PostgreSQL Source Code  git master
pg_archivecleanup.c File Reference
#include "postgres_fe.h"
#include <ctype.h>
#include <dirent.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/time.h>
#include "pg_getopt.h"
#include "common/logging.h"
#include "access/xlog_internal.h"
Include dependency graph for pg_archivecleanup.c:

Go to the source code of this file.

Functions

static void Initialize (void)
 
static void TrimExtension (char *filename, char *extension)
 
static void CleanupPriorWALFiles (void)
 
static void SetWALFileNameForCleanup (void)
 
static void usage (void)
 
int main (int argc, char **argv)
 

Variables

const char * progname
 
bool dryrun = false
 
char * additional_ext = NULL
 
char * archiveLocation
 
char * restartWALFileName
 
char exclusiveCleanupFileName [MAXFNAMELEN]
 

Function Documentation

◆ CleanupPriorWALFiles()

static void CleanupPriorWALFiles ( void  )
static

Definition at line 91 of file pg_archivecleanup.c.

References additional_ext, archiveLocation, closedir(), dirent::d_name, dryrun, exclusiveCleanupFileName, IsPartialXLogFileName, IsXLogFileName, MAXPGPATH, opendir(), pg_log_debug, pg_log_error, printf, readdir(), snprintf, strlcpy(), TrimExtension(), walfile, and WALFilePath.

Referenced by main().

92 {
93  int rc;
94  DIR *xldir;
95  struct dirent *xlde;
96  char walfile[MAXPGPATH];
97 
98  if ((xldir = opendir(archiveLocation)) != NULL)
99  {
100  while (errno = 0, (xlde = readdir(xldir)) != NULL)
101  {
102  /*
103  * Truncation is essentially harmless, because we skip names of
104  * length other than XLOG_FNAME_LEN. (In principle, one could use
105  * a 1000-character additional_ext and get trouble.)
106  */
107  strlcpy(walfile, xlde->d_name, MAXPGPATH);
108  TrimExtension(walfile, additional_ext);
109 
110  /*
111  * We ignore the timeline part of the XLOG segment identifiers in
112  * deciding whether a segment is still needed. This ensures that
113  * we won't prematurely remove a segment from a parent timeline.
114  * We could probably be a little more proactive about removing
115  * segments of non-parent timelines, but that would be a whole lot
116  * more complicated.
117  *
118  * We use the alphanumeric sorting property of the filenames to
119  * decide which ones are earlier than the exclusiveCleanupFileName
120  * file. Note that this means files are not removed in the order
121  * they were originally written, in case this worries you.
122  */
123  if ((IsXLogFileName(walfile) || IsPartialXLogFileName(walfile)) &&
124  strcmp(walfile + 8, exclusiveCleanupFileName + 8) < 0)
125  {
126  char WALFilePath[MAXPGPATH * 2]; /* the file path
127  * including archive */
128 
129  /*
130  * Use the original file name again now, including any
131  * extension that might have been chopped off before testing
132  * the sequence.
133  */
134  snprintf(WALFilePath, sizeof(WALFilePath), "%s/%s",
135  archiveLocation, xlde->d_name);
136 
137  if (dryrun)
138  {
139  /*
140  * Prints the name of the file to be removed and skips the
141  * actual removal. The regular printout is so that the
142  * user can pipe the output into some other program.
143  */
144  printf("%s\n", WALFilePath);
145  pg_log_debug("file \"%s\" would be removed", WALFilePath);
146  continue;
147  }
148 
149  pg_log_debug("removing file \"%s\"", WALFilePath);
150 
151  rc = unlink(WALFilePath);
152  if (rc != 0)
153  {
154  pg_log_error("could not remove file \"%s\": %m",
155  WALFilePath);
156  break;
157  }
158  }
159  }
160 
161  if (errno)
162  pg_log_error("could not read archive location \"%s\": %m",
164  if (closedir(xldir))
165  pg_log_error("could not close archive location \"%s\": %m",
167  }
168  else
169  pg_log_error("could not open archive location \"%s\": %m",
171 }
#define pg_log_error(...)
Definition: logging.h:79
int closedir(DIR *)
Definition: dirent.c:113
#define printf(...)
Definition: port.h:198
char * archiveLocation
Definition: dirent.h:9
static void TrimExtension(char *filename, char *extension)
Definition: dirent.c:25
#define IsXLogFileName(fname)
#define pg_log_debug(...)
Definition: logging.h:91
#define MAXPGPATH
static Walfile * walfile
Definition: receivelog.c:34
DIR * opendir(const char *)
Definition: dirent.c:33
bool dryrun
char exclusiveCleanupFileName[MAXFNAMELEN]
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
char WALFilePath[MAXPGPATH *2]
Definition: pg_standby.c:61
struct dirent * readdir(DIR *)
Definition: dirent.c:77
#define IsPartialXLogFileName(fname)
char d_name[MAX_PATH]
Definition: dirent.h:14
#define snprintf
Definition: port.h:192
char * additional_ext

◆ Initialize()

static void Initialize ( void  )
static

Definition at line 57 of file pg_archivecleanup.c.

References archiveLocation, pg_log_error, S_ISDIR, and stat.

Referenced by main().

58 {
59  /*
60  * This code assumes that archiveLocation is a directory, so we use stat
61  * to test if it's accessible.
62  */
63  struct stat stat_buf;
64 
65  if (stat(archiveLocation, &stat_buf) != 0 ||
66  !S_ISDIR(stat_buf.st_mode))
67  {
68  pg_log_error("archive location \"%s\" does not exist",
70  exit(2);
71  }
72 }
#define pg_log_error(...)
Definition: logging.h:79
char * archiveLocation
struct stat stat_buf
Definition: pg_standby.c:101
#define stat(a, b)
Definition: win32_port.h:255
#define S_ISDIR(m)
Definition: win32_port.h:296

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 279 of file pg_archivecleanup.c.

References _, additional_ext, archiveLocation, CleanupPriorWALFiles(), dryrun, exclusiveCleanupFileName, fprintf, get_progname(), getopt(), Initialize(), optarg, optind, PG_LOG_DEBUG, pg_log_debug, pg_log_error, pg_logging_init(), pg_logging_set_level(), pg_strdup(), PG_TEXTDOMAIN, progname, restartWALFileName, set_pglocale_pgservice(), SetWALFileNameForCleanup(), and usage().

280 {
281  int c;
282 
283  pg_logging_init(argv[0]);
284  set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_archivecleanup"));
285  progname = get_progname(argv[0]);
286 
287  if (argc > 1)
288  {
289  if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
290  {
291  usage();
292  exit(0);
293  }
294  if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
295  {
296  puts("pg_archivecleanup (PostgreSQL) " PG_VERSION);
297  exit(0);
298  }
299  }
300 
301  while ((c = getopt(argc, argv, "x:dn")) != -1)
302  {
303  switch (c)
304  {
305  case 'd': /* Debug mode */
307  break;
308  case 'n': /* Dry-Run mode */
309  dryrun = true;
310  break;
311  case 'x':
312  additional_ext = pg_strdup(optarg); /* Extension to remove
313  * from xlogfile names */
314  break;
315  default:
316  fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
317  exit(2);
318  break;
319  }
320  }
321 
322  /*
323  * We will go to the archiveLocation to check restartWALFileName.
324  * restartWALFileName may not exist anymore, which would not be an error,
325  * so we separate the archiveLocation and restartWALFileName so we can
326  * check separately whether archiveLocation exists, if not that is an
327  * error
328  */
329  if (optind < argc)
330  {
331  archiveLocation = argv[optind];
332  optind++;
333  }
334  else
335  {
336  pg_log_error("must specify archive location");
337  fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
338  exit(2);
339  }
340 
341  if (optind < argc)
342  {
343  restartWALFileName = argv[optind];
344  optind++;
345  }
346  else
347  {
348  pg_log_error("must specify oldest kept WAL file");
349  fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
350  exit(2);
351  }
352 
353  if (optind < argc)
354  {
355  pg_log_error("too many command-line arguments");
356  fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
357  exit(2);
358  }
359 
360  /*
361  * Check archive exists and other initialization if required.
362  */
363  Initialize();
364 
365  /*
366  * Check filename is a valid name, then process to find cut-off
367  */
369 
370  pg_log_debug("keeping WAL file \"%s/%s\" and later",
372 
373  /*
374  * Remove WAL files older than cut-off
375  */
377 
378  exit(0);
379 }
static void CleanupPriorWALFiles(void)
static void SetWALFileNameForCleanup(void)
const char * get_progname(const char *argv0)
Definition: path.c:453
#define pg_log_error(...)
Definition: logging.h:79
void pg_logging_init(const char *argv0)
Definition: logging.c:39
char * archiveLocation
#define fprintf
Definition: port.h:196
int getopt(int nargc, char *const *nargv, const char *ostr)
Definition: getopt.c:71
static void usage(void)
int optind
Definition: getopt.c:50
#define pg_log_debug(...)
Definition: logging.h:91
char * restartWALFileName
char * c
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
const char * progname
bool dryrun
#define PG_TEXTDOMAIN(domain)
Definition: c.h:1135
char exclusiveCleanupFileName[MAXFNAMELEN]
void set_pglocale_pgservice(const char *argv0, const char *app)
Definition: exec.c:565
char * optarg
Definition: getopt.c:52
void pg_logging_set_level(enum pg_log_level new_level)
Definition: logging.c:108
static void Initialize(void)
#define _(x)
Definition: elog.c:84
char * additional_ext

◆ SetWALFileNameForCleanup()

static void SetWALFileNameForCleanup ( void  )
static

Definition at line 180 of file pg_archivecleanup.c.

References _, additional_ext, generate_unaccent_rules::args, exclusiveCleanupFileName, fprintf, IsBackupHistoryFileName, IsPartialXLogFileName, IsXLogFileName, pg_log_error, progname, restartWALFileName, TrimExtension(), and XLogFileNameById.

Referenced by main().

181 {
182  bool fnameOK = false;
183 
185 
186  /*
187  * If restartWALFileName is a WAL file name then just use it directly. If
188  * restartWALFileName is a .partial or .backup filename, make sure we use
189  * the prefix of the filename, otherwise we will remove wrong files since
190  * 000000010000000000000010.partial and
191  * 000000010000000000000010.00000020.backup are after
192  * 000000010000000000000010.
193  */
195  {
197  fnameOK = true;
198  }
200  {
201  int args;
202  uint32 tli = 1,
203  log = 0,
204  seg = 0;
205 
206  args = sscanf(restartWALFileName, "%08X%08X%08X.partial",
207  &tli, &log, &seg);
208  if (args == 3)
209  {
210  fnameOK = true;
211 
212  /*
213  * Use just the prefix of the filename, ignore everything after
214  * first period
215  */
217  }
218  }
220  {
221  int args;
222  uint32 tli = 1,
223  log = 0,
224  seg = 0,
225  offset = 0;
226 
227  args = sscanf(restartWALFileName, "%08X%08X%08X.%08X.backup", &tli, &log, &seg, &offset);
228  if (args == 4)
229  {
230  fnameOK = true;
231 
232  /*
233  * Use just the prefix of the filename, ignore everything after
234  * first period
235  */
237  }
238  }
239 
240  if (!fnameOK)
241  {
242  pg_log_error("invalid file name argument");
243  fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
244  exit(2);
245  }
246 }
#define pg_log_error(...)
Definition: logging.h:79
#define XLogFileNameById(fname, tli, log, seg)
#define fprintf
Definition: port.h:196
static void TrimExtension(char *filename, char *extension)
#define IsXLogFileName(fname)
char * restartWALFileName
unsigned int uint32
Definition: c.h:358
#define IsBackupHistoryFileName(fname)
const char * progname
char exclusiveCleanupFileName[MAXFNAMELEN]
#define IsPartialXLogFileName(fname)
#define _(x)
Definition: elog.c:84
char * additional_ext

◆ TrimExtension()

static void TrimExtension ( char *  filename,
char *  extension 
)
static

Definition at line 75 of file pg_archivecleanup.c.

Referenced by CleanupPriorWALFiles(), and SetWALFileNameForCleanup().

76 {
77  int flen;
78  int elen;
79 
80  if (extension == NULL)
81  return;
82 
83  elen = strlen(extension);
84  flen = strlen(filename);
85 
86  if (flen > elen && strcmp(filename + flen - elen, extension) == 0)
87  filename[flen - elen] = '\0';
88 }
static char * filename
Definition: pg_dumpall.c:91

◆ usage()

static void usage ( void  )
static

Definition at line 254 of file pg_archivecleanup.c.

References _, printf, and progname.

Referenced by main().

255 {
256  printf(_("%s removes older WAL files from PostgreSQL archives.\n\n"), progname);
257  printf(_("Usage:\n"));
258  printf(_(" %s [OPTION]... ARCHIVELOCATION OLDESTKEPTWALFILE\n"), progname);
259  printf(_("\nOptions:\n"));
260  printf(_(" -d generate debug output (verbose mode)\n"));
261  printf(_(" -n dry run, show the names of the files that would be removed\n"));
262  printf(_(" -V, --version output version information, then exit\n"));
263  printf(_(" -x EXT clean up files if they have this extension\n"));
264  printf(_(" -?, --help show this help, then exit\n"));
265  printf(_("\n"
266  "For use as archive_cleanup_command in postgresql.conf:\n"
267  " archive_cleanup_command = 'pg_archivecleanup [OPTION]... ARCHIVELOCATION %%r'\n"
268  "e.g.\n"
269  " archive_cleanup_command = 'pg_archivecleanup /mnt/server/archiverdir %%r'\n"));
270  printf(_("\n"
271  "Or for use as a standalone archive cleaner:\n"
272  "e.g.\n"
273  " pg_archivecleanup /mnt/server/archiverdir 000000010000000000000010.00000020.backup\n"));
274  printf(_("\nReport bugs to <pgsql-bugs@lists.postgresql.org>.\n"));
275 }
#define printf(...)
Definition: port.h:198
const char * progname
#define _(x)
Definition: elog.c:84

Variable Documentation

◆ additional_ext

char* additional_ext = NULL

Definition at line 28 of file pg_archivecleanup.c.

Referenced by CleanupPriorWALFiles(), main(), and SetWALFileNameForCleanup().

◆ archiveLocation

char* archiveLocation

Definition at line 30 of file pg_archivecleanup.c.

Referenced by CleanupPriorWALFiles(), Initialize(), and main().

◆ dryrun

bool dryrun = false

Definition at line 27 of file pg_archivecleanup.c.

Referenced by CleanupPriorWALFiles(), and main().

◆ exclusiveCleanupFileName

char exclusiveCleanupFileName[MAXFNAMELEN]

Definition at line 32 of file pg_archivecleanup.c.

Referenced by CleanupPriorWALFiles(), main(), and SetWALFileNameForCleanup().

◆ progname

const char* progname

Definition at line 24 of file pg_archivecleanup.c.

Referenced by main(), SetWALFileNameForCleanup(), and usage().

◆ restartWALFileName

char* restartWALFileName

Definition at line 31 of file pg_archivecleanup.c.

Referenced by main(), and SetWALFileNameForCleanup().