PostgreSQL Source Code  git master
controldata_utils.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * controldata_utils.c
4  * Common code for control data file output.
5  *
6  *
7  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  *
11  * IDENTIFICATION
12  * src/common/controldata_utils.c
13  *
14  *-------------------------------------------------------------------------
15  */
16 
17 #ifndef FRONTEND
18 #include "postgres.h"
19 #else
20 #include "postgres_fe.h"
21 #endif
22 
23 #include <unistd.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <time.h>
27 
28 #include "access/xlog_internal.h"
29 #include "catalog/pg_control.h"
31 #include "common/file_perm.h"
32 #ifdef FRONTEND
33 #include "common/logging.h"
34 #endif
35 #include "port/pg_crc32c.h"
36 
37 #ifndef FRONTEND
38 #include "pgstat.h"
39 #include "storage/fd.h"
40 #endif
41 
42 /*
43  * get_controlfile()
44  *
45  * Get controlfile values. The result is returned as a palloc'd copy of the
46  * control file data.
47  *
48  * crc_ok_p can be used by the caller to see whether the CRC of the control
49  * file data is correct.
50  */
52 get_controlfile(const char *DataDir, bool *crc_ok_p)
53 {
55  int fd;
56  char ControlFilePath[MAXPGPATH];
57  pg_crc32c crc;
58  int r;
59 
60  Assert(crc_ok_p);
61 
63  snprintf(ControlFilePath, MAXPGPATH, "%s/global/pg_control", DataDir);
64 
65 #ifndef FRONTEND
66  if ((fd = OpenTransientFile(ControlFilePath, O_RDONLY | PG_BINARY)) == -1)
67  ereport(ERROR,
69  errmsg("could not open file \"%s\" for reading: %m",
70  ControlFilePath)));
71 #else
72  if ((fd = open(ControlFilePath, O_RDONLY | PG_BINARY, 0)) == -1)
73  pg_fatal("could not open file \"%s\" for reading: %m",
74  ControlFilePath);
75 #endif
76 
77  r = read(fd, ControlFile, sizeof(ControlFileData));
78  if (r != sizeof(ControlFileData))
79  {
80  if (r < 0)
81 #ifndef FRONTEND
82  ereport(ERROR,
84  errmsg("could not read file \"%s\": %m", ControlFilePath)));
85 #else
86  pg_fatal("could not read file \"%s\": %m", ControlFilePath);
87 #endif
88  else
89 #ifndef FRONTEND
90  ereport(ERROR,
92  errmsg("could not read file \"%s\": read %d of %zu",
93  ControlFilePath, r, sizeof(ControlFileData))));
94 #else
95  pg_fatal("could not read file \"%s\": read %d of %zu",
96  ControlFilePath, r, sizeof(ControlFileData));
97 #endif
98  }
99 
100 #ifndef FRONTEND
101  if (CloseTransientFile(fd) != 0)
102  ereport(ERROR,
104  errmsg("could not close file \"%s\": %m",
105  ControlFilePath)));
106 #else
107  if (close(fd) != 0)
108  pg_fatal("could not close file \"%s\": %m", ControlFilePath);
109 #endif
110 
111  /* Check the CRC. */
112  INIT_CRC32C(crc);
114  (char *) ControlFile,
115  offsetof(ControlFileData, crc));
116  FIN_CRC32C(crc);
117 
118  *crc_ok_p = EQ_CRC32C(crc, ControlFile->crc);
119 
120  /* Make sure the control file is valid byte order. */
121  if (ControlFile->pg_control_version % 65536 == 0 &&
122  ControlFile->pg_control_version / 65536 != 0)
123 #ifndef FRONTEND
124  elog(ERROR, _("byte ordering mismatch"));
125 #else
126  pg_log_warning("possible byte ordering mismatch\n"
127  "The byte ordering used to store the pg_control file might not match the one\n"
128  "used by this program. In that case the results below would be incorrect, and\n"
129  "the PostgreSQL installation would be incompatible with this data directory.");
130 #endif
131 
132  return ControlFile;
133 }
134 
135 /*
136  * update_controlfile()
137  *
138  * Update controlfile values with the contents given by caller. The
139  * contents to write are included in "ControlFile". "do_sync" can be
140  * optionally used to flush the updated control file. Note that it is up
141  * to the caller to properly lock ControlFileLock when calling this
142  * routine in the backend.
143  */
144 void
147 {
148  int fd;
149  char buffer[PG_CONTROL_FILE_SIZE];
150  char ControlFilePath[MAXPGPATH];
151 
152  /* Update timestamp */
153  ControlFile->time = (pg_time_t) time(NULL);
154 
155  /* Recalculate CRC of control file */
158  (char *) ControlFile,
159  offsetof(ControlFileData, crc));
161 
162  /*
163  * Write out PG_CONTROL_FILE_SIZE bytes into pg_control by zero-padding
164  * the excess over sizeof(ControlFileData), to avoid premature EOF related
165  * errors when reading it.
166  */
167  memset(buffer, 0, PG_CONTROL_FILE_SIZE);
168  memcpy(buffer, ControlFile, sizeof(ControlFileData));
169 
170  snprintf(ControlFilePath, sizeof(ControlFilePath), "%s/%s", DataDir, XLOG_CONTROL_FILE);
171 
172 #ifndef FRONTEND
173 
174  /*
175  * All errors issue a PANIC, so no need to use OpenTransientFile() and to
176  * worry about file descriptor leaks.
177  */
178  if ((fd = BasicOpenFile(ControlFilePath, O_RDWR | PG_BINARY)) < 0)
179  ereport(PANIC,
181  errmsg("could not open file \"%s\": %m",
182  ControlFilePath)));
183 #else
184  if ((fd = open(ControlFilePath, O_WRONLY | PG_BINARY,
185  pg_file_create_mode)) == -1)
186  pg_fatal("could not open file \"%s\": %m", ControlFilePath);
187 #endif
188 
189  errno = 0;
190 #ifndef FRONTEND
192 #endif
194  {
195  /* if write didn't set errno, assume problem is no disk space */
196  if (errno == 0)
197  errno = ENOSPC;
198 
199 #ifndef FRONTEND
200  ereport(PANIC,
202  errmsg("could not write file \"%s\": %m",
203  ControlFilePath)));
204 #else
205  pg_fatal("could not write file \"%s\": %m", ControlFilePath);
206 #endif
207  }
208 #ifndef FRONTEND
210 #endif
211 
212  if (do_sync)
213  {
214 #ifndef FRONTEND
216  if (pg_fsync(fd) != 0)
217  ereport(PANIC,
219  errmsg("could not fsync file \"%s\": %m",
220  ControlFilePath)));
222 #else
223  if (fsync(fd) != 0)
224  pg_fatal("could not fsync file \"%s\": %m", ControlFilePath);
225 #endif
226  }
227 
228  if (close(fd) != 0)
229  {
230 #ifndef FRONTEND
231  ereport(PANIC,
233  errmsg("could not close file \"%s\": %m",
234  ControlFilePath)));
235 #else
236  pg_fatal("could not close file \"%s\": %m", ControlFilePath);
237 #endif
238  }
239 }
#define PG_BINARY
Definition: c.h:1278
void update_controlfile(const char *DataDir, ControlFileData *ControlFile, bool do_sync)
ControlFileData * get_controlfile(const char *DataDir, bool *crc_ok_p)
int errcode_for_file_access(void)
Definition: elog.c:881
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define _(x)
Definition: elog.c:91
#define PANIC
Definition: elog.h:42
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
int CloseTransientFile(int fd)
Definition: fd.c:2706
int BasicOpenFile(const char *fileName, int fileFlags)
Definition: fd.c:998
int pg_fsync(int fd)
Definition: fd.c:361
int OpenTransientFile(const char *fileName, int fileFlags)
Definition: fd.c:2530
#define palloc_object(type)
Definition: fe_memutils.h:62
int pg_file_create_mode
Definition: file_perm.c:19
char * DataDir
Definition: globals.c:66
static bool do_sync
Definition: initdb.c:165
#define close(a)
Definition: win32.h:12
#define write(a, b, c)
Definition: win32.h:14
#define read(a, b, c)
Definition: win32.h:13
Assert(fmt[strlen(fmt) - 1] !='\n')
#define pg_fatal(...)
#define ERRCODE_DATA_CORRUPTED
Definition: pg_basebackup.c:41
#define MAXPGPATH
#define PG_CONTROL_FILE_SIZE
Definition: pg_control.h:248
uint32 pg_crc32c
Definition: pg_crc32c.h:38
#define COMP_CRC32C(crc, data, len)
Definition: pg_crc32c.h:89
#define EQ_CRC32C(c1, c2)
Definition: pg_crc32c.h:42
#define INIT_CRC32C(crc)
Definition: pg_crc32c.h:41
#define FIN_CRC32C(crc)
Definition: pg_crc32c.h:94
return crc
#define pg_log_warning(...)
Definition: pgfnames.c:24
int64 pg_time_t
Definition: pgtime.h:23
#define snprintf
Definition: port.h:238
static int fd(const char *x, int i)
Definition: preproc-init.c:105
uint32 pg_control_version
Definition: pg_control.h:123
pg_time_t time
Definition: pg_control.h:130
pg_crc32c crc
Definition: pg_control.h:230
@ WAIT_EVENT_CONTROL_FILE_WRITE_UPDATE
Definition: wait_event.h:174
@ WAIT_EVENT_CONTROL_FILE_SYNC_UPDATE
Definition: wait_event.h:172
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition: wait_event.h:271
static void pgstat_report_wait_end(void)
Definition: wait_event.h:287
#define fsync(fd)
Definition: win32_port.h:85
static ControlFileData * ControlFile
Definition: xlog.c:570
#define XLOG_CONTROL_FILE