Improve comment about GetWALAvailability's WALAVAIL_REMOVED code.
[pgsql.git] / src / backend / access / transam / shell_restore.c
blob8458209f490ba374d3a3be6662a38ba3ebee46ea
1 /*-------------------------------------------------------------------------
3 * shell_restore.c
4 * Recovery functions for a user-specified shell command.
6 * These recovery functions use a user-specified shell command (e.g. based
7 * on the GUC restore_command).
9 * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
10 * Portions Copyright (c) 1994, Regents of the University of California
12 * src/backend/access/transam/shell_restore.c
14 *-------------------------------------------------------------------------
17 #include "postgres.h"
19 #include <signal.h>
21 #include "access/xlogarchive.h"
22 #include "access/xlogrecovery.h"
23 #include "common/percentrepl.h"
24 #include "storage/ipc.h"
25 #include "utils/wait_event.h"
27 static bool ExecuteRecoveryCommand(const char *command,
28 const char *commandName,
29 bool failOnSignal,
30 bool exitOnSigterm,
31 uint32 wait_event_info,
32 int fail_elevel);
35 * Attempt to execute a shell-based restore command.
37 * Returns true if the command has succeeded, false otherwise.
39 bool
40 shell_restore(const char *file, const char *path,
41 const char *lastRestartPointFileName)
43 char *nativePath = pstrdup(path);
44 char *cmd;
45 bool ret;
47 /* Build the restore command to execute */
48 make_native_path(nativePath);
49 cmd = replace_percent_placeholders(recoveryRestoreCommand,
50 "restore_command", "frp", file,
51 lastRestartPointFileName,
52 nativePath);
53 pfree(nativePath);
56 * Remember, we rollforward UNTIL the restore fails so failure here is
57 * just part of the process... that makes it difficult to determine
58 * whether the restore failed because there isn't an archive to restore,
59 * or because the administrator has specified the restore program
60 * incorrectly. We have to assume the former.
62 * However, if the failure was due to any sort of signal, it's best to
63 * punt and abort recovery. (If we "return false" here, upper levels will
64 * assume that recovery is complete and start up the database!) It's
65 * essential to abort on child SIGINT and SIGQUIT, because per spec
66 * system() ignores SIGINT and SIGQUIT while waiting; if we see one of
67 * those it's a good bet we should have gotten it too.
69 * On SIGTERM, assume we have received a fast shutdown request, and exit
70 * cleanly. It's pure chance whether we receive the SIGTERM first, or the
71 * child process. If we receive it first, the signal handler will call
72 * proc_exit, otherwise we do it here. If we or the child process received
73 * SIGTERM for any other reason than a fast shutdown request, postmaster
74 * will perform an immediate shutdown when it sees us exiting
75 * unexpectedly.
77 * We treat hard shell errors such as "command not found" as fatal, too.
79 ret = ExecuteRecoveryCommand(cmd, "restore_command",
80 true, /* failOnSignal */
81 true, /* exitOnSigterm */
82 WAIT_EVENT_RESTORE_COMMAND, DEBUG2);
83 pfree(cmd);
85 return ret;
89 * Attempt to execute a shell-based archive cleanup command.
91 void
92 shell_archive_cleanup(const char *lastRestartPointFileName)
94 char *cmd;
96 cmd = replace_percent_placeholders(archiveCleanupCommand,
97 "archive_cleanup_command",
98 "r", lastRestartPointFileName);
99 (void) ExecuteRecoveryCommand(cmd, "archive_cleanup_command", false, false,
100 WAIT_EVENT_ARCHIVE_CLEANUP_COMMAND, WARNING);
101 pfree(cmd);
105 * Attempt to execute a shell-based end-of-recovery command.
107 void
108 shell_recovery_end(const char *lastRestartPointFileName)
110 char *cmd;
112 cmd = replace_percent_placeholders(recoveryEndCommand,
113 "recovery_end_command",
114 "r", lastRestartPointFileName);
115 (void) ExecuteRecoveryCommand(cmd, "recovery_end_command", true, false,
116 WAIT_EVENT_RECOVERY_END_COMMAND, WARNING);
117 pfree(cmd);
121 * Attempt to execute an external shell command during recovery.
123 * 'command' is the shell command to be executed, 'commandName' is a
124 * human-readable name describing the command emitted in the logs. If
125 * 'failOnSignal' is true and the command is killed by a signal, a FATAL
126 * error is thrown. Otherwise, 'fail_elevel' is used for the log message.
127 * If 'exitOnSigterm' is true and the command is killed by SIGTERM, we exit
128 * immediately.
130 * Returns whether the command succeeded.
132 static bool
133 ExecuteRecoveryCommand(const char *command, const char *commandName,
134 bool failOnSignal, bool exitOnSigterm,
135 uint32 wait_event_info, int fail_elevel)
137 int rc;
139 Assert(command && commandName);
141 ereport(DEBUG3,
142 (errmsg_internal("executing %s \"%s\"", commandName, command)));
145 * execute the constructed command
147 fflush(NULL);
148 pgstat_report_wait_start(wait_event_info);
149 rc = system(command);
150 pgstat_report_wait_end();
152 if (rc != 0)
154 if (exitOnSigterm && wait_result_is_signal(rc, SIGTERM))
155 proc_exit(1);
158 * If the failure was due to any sort of signal, it's best to punt and
159 * abort recovery. See comments in shell_restore().
161 ereport((failOnSignal && wait_result_is_any_signal(rc, true)) ? FATAL : fail_elevel,
162 /*------
163 translator: First %s represents a postgresql.conf parameter name like
164 "recovery_end_command", the 2nd is the value of that parameter, the
165 third an already translated error message. */
166 (errmsg("%s \"%s\": %s", commandName,
167 command, wait_result_to_str(rc))));
170 return (rc == 0);