PostgreSQL Source Code  git master
shell_archive.c
Go to the documentation of this file.
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, PostgreSQL Global Development Group
10  *
11  * IDENTIFICATION
12  * src/backend/postmaster/shell_archive.c
13  *
14  *-------------------------------------------------------------------------
15  */
16 #include "postgres.h"
17 
18 #include <sys/wait.h>
19 
20 #include "access/xlog.h"
21 #include "pgstat.h"
22 #include "postmaster/pgarch.h"
23 
24 static bool shell_archive_configured(void);
25 static bool shell_archive_file(const char *file, const char *path);
26 static void shell_archive_shutdown(void);
27 
28 void
30 {
32 
36 }
37 
38 static bool
40 {
41  return XLogArchiveCommand[0] != '\0';
42 }
43 
44 static bool
45 shell_archive_file(const char *file, const char *path)
46 {
47  char xlogarchcmd[MAXPGPATH];
48  char *dp;
49  char *endp;
50  const char *sp;
51  int rc;
52 
53  /*
54  * construct the command to be executed
55  */
56  dp = xlogarchcmd;
57  endp = xlogarchcmd + MAXPGPATH - 1;
58  *endp = '\0';
59 
60  for (sp = XLogArchiveCommand; *sp; sp++)
61  {
62  if (*sp == '%')
63  {
64  switch (sp[1])
65  {
66  case 'p':
67  /* %p: relative path of source file */
68  sp++;
69  strlcpy(dp, path, endp - dp);
70  make_native_path(dp);
71  dp += strlen(dp);
72  break;
73  case 'f':
74  /* %f: filename of source file */
75  sp++;
76  strlcpy(dp, file, endp - dp);
77  dp += strlen(dp);
78  break;
79  case '%':
80  /* convert %% to a single % */
81  sp++;
82  if (dp < endp)
83  *dp++ = *sp;
84  break;
85  default:
86  /* otherwise treat the % as not special */
87  if (dp < endp)
88  *dp++ = *sp;
89  break;
90  }
91  }
92  else
93  {
94  if (dp < endp)
95  *dp++ = *sp;
96  }
97  }
98  *dp = '\0';
99 
100  ereport(DEBUG3,
101  (errmsg_internal("executing archive command \"%s\"",
102  xlogarchcmd)));
103 
104  fflush(NULL);
106  rc = system(xlogarchcmd);
108 
109  if (rc != 0)
110  {
111  /*
112  * If either the shell itself, or a called command, died on a signal,
113  * abort the archiver. We do this because system() ignores SIGINT and
114  * SIGQUIT while waiting; so a signal is very likely something that
115  * should have interrupted us too. Also die if the shell got a hard
116  * "command not found" type of error. If we overreact it's no big
117  * deal, the postmaster will just start the archiver again.
118  */
119  int lev = wait_result_is_any_signal(rc, true) ? FATAL : LOG;
120 
121  if (WIFEXITED(rc))
122  {
123  ereport(lev,
124  (errmsg("archive command failed with exit code %d",
125  WEXITSTATUS(rc)),
126  errdetail("The failed archive command was: %s",
127  xlogarchcmd)));
128  }
129  else if (WIFSIGNALED(rc))
130  {
131 #if defined(WIN32)
132  ereport(lev,
133  (errmsg("archive command was terminated by exception 0x%X",
134  WTERMSIG(rc)),
135  errhint("See C include file \"ntstatus.h\" for a description of the hexadecimal value."),
136  errdetail("The failed archive command was: %s",
137  xlogarchcmd)));
138 #else
139  ereport(lev,
140  (errmsg("archive command was terminated by signal %d: %s",
141  WTERMSIG(rc), pg_strsignal(WTERMSIG(rc))),
142  errdetail("The failed archive command was: %s",
143  xlogarchcmd)));
144 #endif
145  }
146  else
147  {
148  ereport(lev,
149  (errmsg("archive command exited with unrecognized status %d",
150  rc),
151  errdetail("The failed archive command was: %s",
152  xlogarchcmd)));
153  }
154 
155  return false;
156  }
157 
158  elog(DEBUG1, "archived write-ahead log file \"%s\"", file);
159  return true;
160 }
161 
162 static void
164 {
165  elog(DEBUG1, "archiver process shutting down");
166 }
#define AssertVariableIsOfType(varname, typename)
Definition: c.h:914
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1033
int errdetail(const char *fmt,...)
Definition: elog.c:1079
int errhint(const char *fmt,...)
Definition: elog.c:1193
int errmsg(const char *fmt,...)
Definition: elog.c:946
#define LOG
Definition: elog.h:27
#define DEBUG3
Definition: elog.h:24
#define FATAL
Definition: elog.h:37
#define DEBUG1
Definition: elog.h:26
#define ereport(elevel,...)
Definition: elog.h:145
static void const char fflush(stdout)
#define MAXPGPATH
void(* ArchiveModuleInit)(ArchiveModuleCallbacks *cb)
Definition: pgarch.h:64
const char * pg_strsignal(int signum)
Definition: pgstrsignal.c:42
void make_native_path(char *filename)
Definition: path.c:167
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
static void shell_archive_shutdown(void)
static bool shell_archive_file(const char *file, const char *path)
Definition: shell_archive.c:45
static bool shell_archive_configured(void)
Definition: shell_archive.c:39
void shell_archive_init(ArchiveModuleCallbacks *cb)
Definition: shell_archive.c:29
ArchiveFileCB archive_file_cb
Definition: pgarch.h:56
ArchiveShutdownCB shutdown_cb
Definition: pgarch.h:57
ArchiveCheckConfiguredCB check_configured_cb
Definition: pgarch.h:55
bool wait_result_is_any_signal(int exit_status, bool include_command_not_found)
Definition: wait_error.c:121
@ WAIT_EVENT_ARCHIVE_COMMAND
Definition: wait_event.h:83
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition: wait_event.h:268
static void pgstat_report_wait_end(void)
Definition: wait_event.h:284
#define WIFEXITED(w)
Definition: win32_port.h:160
#define WIFSIGNALED(w)
Definition: win32_port.h:161
#define WTERMSIG(w)
Definition: win32_port.h:163
#define WEXITSTATUS(w)
Definition: win32_port.h:162
char * XLogArchiveCommand
Definition: xlog.c:123