Line data Source code
1 : /*------------------------------------------------------------------------- 2 : * 3 : * archive.c 4 : * Routines to access WAL archives from frontend 5 : * 6 : * Portions Copyright (c) 1996-2024, 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 39 2 : 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 2 : snprintf(xlogpath, MAXPGPATH, "%s/" XLOGDIR "/%s", path, xlogfname); 48 : 49 2 : xlogRestoreCmd = BuildRestoreCommand(restoreCommand, xlogpath, 50 : xlogfname, NULL); 51 : 52 : /* 53 : * Execute restore_command, which should copy the missing file from 54 : * archival storage. 55 : */ 56 2 : fflush(NULL); 57 2 : rc = system(xlogRestoreCmd); 58 2 : pfree(xlogRestoreCmd); 59 : 60 2 : 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. 65 : */ 66 2 : if (stat(xlogpath, &stat_buf) == 0) 67 : { 68 2 : if (expectedSize > 0 && stat_buf.st_size != expectedSize) 69 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 73 : { 74 2 : int xlogfd = open(xlogpath, O_RDONLY | PG_BINARY, 0); 75 : 76 2 : if (xlogfd < 0) 77 0 : pg_fatal("could not open file \"%s\" restored from archive: %m", 78 : xlogpath); 79 : else 80 2 : return xlogfd; 81 : } 82 : } 83 : else 84 : { 85 0 : if (errno != ENOENT) 86 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. 96 : */ 97 0 : if (wait_result_is_any_signal(rc, true)) 98 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. 104 : */ 105 0 : pg_log_error("could not restore file \"%s\" from archive", 106 : xlogfname); 107 0 : return -1; 108 : }