Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * archive.c
4 : * Routines to access WAL archives from frontend
5 : *
6 : * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : *
10 : * IDENTIFICATION
11 : * src/fe_utils/archive.c
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 :
16 : #include "postgres_fe.h"
17 :
18 : #include <unistd.h>
19 : #include <sys/stat.h>
20 :
21 : #include "access/xlog_internal.h"
22 : #include "common/archive.h"
23 : #include "common/logging.h"
24 : #include "fe_utils/archive.h"
25 :
26 :
27 : /*
28 : * RestoreArchivedFile
29 : *
30 : * Attempt to retrieve the specified file from off-line archival storage.
31 : * If successful, return a file descriptor of the restored file, else
32 : * return -1.
33 : *
34 : * For fixed-size files, the caller may pass the expected size as an
35 : * additional crosscheck on successful recovery. If the file size is not
36 : * known, set expectedSize = 0.
37 : */
38 : int
1103 michael 39 CBC 1 : RestoreArchivedFile(const char *path, const char *xlogfname,
40 : off_t expectedSize, const char *restoreCommand)
41 : {
42 : char xlogpath[MAXPGPATH];
43 : char *xlogRestoreCmd;
44 : int rc;
45 : struct stat stat_buf;
46 :
47 1 : snprintf(xlogpath, MAXPGPATH, "%s/" XLOGDIR "/%s", path, xlogfname);
48 :
62 49 1 : xlogRestoreCmd = BuildRestoreCommand(restoreCommand, xlogpath,
50 : xlogfname, NULL);
51 :
52 : /*
53 : * Execute restore_command, which should copy the missing file from
1103 michael 54 ECB : * archival storage.
55 : */
223 tgl 56 GNC 1 : fflush(NULL);
1103 michael 57 CBC 1 : rc = system(xlogRestoreCmd);
1103 michael 58 GIC 1 : pfree(xlogRestoreCmd);
1103 michael 59 ECB :
1103 michael 60 GIC 1 : if (rc == 0)
61 : {
62 : /*
63 : * Command apparently succeeded, but let's make sure the file is
64 : * really there now and has the correct size.
1103 michael 65 ECB : */
1103 michael 66 GIC 1 : if (stat(xlogpath, &stat_buf) == 0)
1103 michael 67 ECB : {
1103 michael 68 GBC 1 : if (expectedSize > 0 && stat_buf.st_size != expectedSize)
366 tgl 69 UIC 0 : pg_fatal("unexpected file size for \"%s\": %lld instead of %lld",
70 : xlogfname, (long long int) stat_buf.st_size,
71 : (long long int) expectedSize);
72 : else
1103 michael 73 ECB : {
1103 michael 74 GIC 1 : int xlogfd = open(xlogpath, O_RDONLY | PG_BINARY, 0);
1103 michael 75 ECB :
1103 michael 76 GBC 1 : if (xlogfd < 0)
366 tgl 77 UIC 0 : pg_fatal("could not open file \"%s\" restored from archive: %m",
78 : xlogpath);
1103 michael 79 ECB : else
1103 michael 80 GIC 1 : return xlogfd;
81 : }
82 : }
83 : else
1103 michael 84 EUB : {
1103 michael 85 UBC 0 : if (errno != ENOENT)
366 tgl 86 UIC 0 : pg_fatal("could not stat file \"%s\": %m",
87 : xlogpath);
88 : }
89 : }
90 :
91 : /*
92 : * If the failure was due to a signal, then it would be misleading to
93 : * return with a failure at restoring the file. So just bail out and
94 : * exit. Hard shell errors such as "command not found" are treated as
95 : * fatal too.
1103 michael 96 EUB : */
1103 michael 97 UBC 0 : if (wait_result_is_any_signal(rc, true))
366 tgl 98 UIC 0 : pg_fatal("restore_command failed: %s",
99 : wait_result_to_str(rc));
100 :
101 : /*
102 : * The file is not available, so just let the caller decide what to do
103 : * next.
1103 michael 104 EUB : */
1103 michael 105 UIC 0 : pg_log_error("could not restore file \"%s\" from archive",
1103 michael 106 EUB : xlogfname);
1103 michael 107 UIC 0 : return -1;
108 : }
|