Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * shell_archive.c
4 : *
5 : * This archiving function uses a user-specified shell command (the
6 : * archive_command GUC) to copy write-ahead log files. It is used as the
7 : * default, but other modules may define their own custom archiving logic.
8 : *
9 : * Copyright (c) 2022-2023, PostgreSQL Global Development Group
10 : *
11 : * IDENTIFICATION
12 : * src/backend/archive/shell_archive.c
13 : *
14 : *-------------------------------------------------------------------------
15 : */
16 : #include "postgres.h"
17 :
18 : #include <sys/wait.h>
19 :
20 : #include "access/xlog.h"
21 : #include "archive/archive_module.h"
22 : #include "archive/shell_archive.h"
23 : #include "common/percentrepl.h"
24 : #include "pgstat.h"
25 :
26 : static bool shell_archive_configured(ArchiveModuleState *state);
27 : static bool shell_archive_file(ArchiveModuleState *state,
28 : const char *file,
29 : const char *path);
30 : static void shell_archive_shutdown(ArchiveModuleState *state);
31 :
32 : static const ArchiveModuleCallbacks shell_archive_callbacks = {
33 : .startup_cb = NULL,
34 : .check_configured_cb = shell_archive_configured,
35 : .archive_file_cb = shell_archive_file,
36 : .shutdown_cb = shell_archive_shutdown
37 : };
38 :
39 : const ArchiveModuleCallbacks *
51 michael 40 GNC 9 : shell_archive_init(void)
41 : {
42 9 : return &shell_archive_callbacks;
43 : }
44 :
45 : static bool
46 23 : shell_archive_configured(ArchiveModuleState *state)
430 rhaas 47 ECB : {
430 rhaas 48 GIC 23 : return XLogArchiveCommand[0] != '\0';
430 rhaas 49 ECB : }
50 :
51 : static bool
51 michael 52 GNC 23 : shell_archive_file(ArchiveModuleState *state, const char *file,
53 : const char *path)
436 rhaas 54 ECB : {
55 : char *xlogarchcmd;
88 peter 56 GNC 23 : char *nativePath = NULL;
57 : int rc;
436 rhaas 58 ECB :
88 peter 59 GNC 23 : if (path)
436 rhaas 60 ECB : {
88 peter 61 GNC 23 : nativePath = pstrdup(path);
62 23 : make_native_path(nativePath);
63 : }
64 :
51 michael 65 23 : xlogarchcmd = replace_percent_placeholders(XLogArchiveCommand,
66 : "archive_command", "fp",
67 : file, nativePath);
68 :
88 peter 69 23 : if (nativePath)
70 23 : pfree(nativePath);
71 :
436 rhaas 72 GIC 23 : ereport(DEBUG3,
436 rhaas 73 EUB : (errmsg_internal("executing archive command \"%s\"",
74 : xlogarchcmd)));
75 :
223 tgl 76 GNC 23 : fflush(NULL);
436 rhaas 77 GIC 23 : pgstat_report_wait_start(WAIT_EVENT_ARCHIVE_COMMAND);
78 23 : rc = system(xlogarchcmd);
79 23 : pgstat_report_wait_end();
80 :
81 23 : if (rc != 0)
82 : {
83 : /*
436 rhaas 84 EUB : * If either the shell itself, or a called command, died on a signal,
85 : * abort the archiver. We do this because system() ignores SIGINT and
86 : * SIGQUIT while waiting; so a signal is very likely something that
87 : * should have interrupted us too. Also die if the shell got a hard
88 : * "command not found" type of error. If we overreact it's no big
89 : * deal, the postmaster will just start the archiver again.
90 : */
436 rhaas 91 GIC 1 : int lev = wait_result_is_any_signal(rc, true) ? FATAL : LOG;
92 :
436 rhaas 93 GBC 1 : if (WIFEXITED(rc))
94 : {
436 rhaas 95 GIC 1 : ereport(lev,
96 : (errmsg("archive command failed with exit code %d",
97 : WEXITSTATUS(rc)),
98 : errdetail("The failed archive command was: %s",
99 : xlogarchcmd)));
436 rhaas 100 ECB : }
436 rhaas 101 UIC 0 : else if (WIFSIGNALED(rc))
102 : {
436 rhaas 103 ECB : #if defined(WIN32)
104 : ereport(lev,
105 : (errmsg("archive command was terminated by exception 0x%X",
106 : WTERMSIG(rc)),
107 : errhint("See C include file \"ntstatus.h\" for a description of the hexadecimal value."),
108 : errdetail("The failed archive command was: %s",
109 : xlogarchcmd)));
110 : #else
436 rhaas 111 UIC 0 : ereport(lev,
436 rhaas 112 ECB : (errmsg("archive command was terminated by signal %d: %s",
113 : WTERMSIG(rc), pg_strsignal(WTERMSIG(rc))),
114 : errdetail("The failed archive command was: %s",
115 : xlogarchcmd)));
116 : #endif
117 : }
118 : else
119 : {
436 rhaas 120 UIC 0 : ereport(lev,
121 : (errmsg("archive command exited with unrecognized status %d",
122 : rc),
123 : errdetail("The failed archive command was: %s",
124 : xlogarchcmd)));
125 : }
126 :
436 rhaas 127 GIC 1 : return false;
128 : }
129 :
88 peter 130 GNC 22 : pfree(xlogarchcmd);
131 :
436 rhaas 132 GIC 22 : elog(DEBUG1, "archived write-ahead log file \"%s\"", file);
133 22 : return true;
134 : }
135 :
136 : static void
51 michael 137 GNC 9 : shell_archive_shutdown(ArchiveModuleState *state)
138 : {
172 michael 139 GIC 9 : elog(DEBUG1, "archiver process shutting down");
140 9 : }
|