Suppress "variable may be used uninitialized" warning.
[pgsql.git] / src / common / controldata_utils.c
blob82309b25107716db8d7b0fbb966f493b27fdf020
1 /*-------------------------------------------------------------------------
3 * controldata_utils.c
4 * Common code for control data file output.
7 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
11 * IDENTIFICATION
12 * src/common/controldata_utils.c
14 *-------------------------------------------------------------------------
17 #ifndef FRONTEND
18 #include "postgres.h"
19 #else
20 #include "postgres_fe.h"
21 #endif
23 #include <unistd.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <time.h>
28 #include "access/xlog_internal.h"
29 #include "catalog/pg_control.h"
30 #include "common/controldata_utils.h"
31 #include "common/file_perm.h"
32 #ifdef FRONTEND
33 #include "common/logging.h"
34 #endif
35 #include "port/pg_crc32c.h"
37 #ifndef FRONTEND
38 #include "pgstat.h"
39 #include "storage/fd.h"
40 #endif
43 * get_controlfile()
45 * Get controlfile values. The result is returned as a palloc'd copy of the
46 * control file data.
48 * crc_ok_p can be used by the caller to see whether the CRC of the control
49 * file data is correct.
51 ControlFileData *
52 get_controlfile(const char *DataDir, bool *crc_ok_p)
54 char ControlFilePath[MAXPGPATH];
56 snprintf(ControlFilePath, MAXPGPATH, "%s/global/pg_control", DataDir);
58 return get_controlfile_by_exact_path(ControlFilePath, crc_ok_p);
62 * get_controlfile_by_exact_path()
64 * As above, but the caller specifies the path to the control file itself,
65 * rather than the path to the data directory.
67 ControlFileData *
68 get_controlfile_by_exact_path(const char *ControlFilePath, bool *crc_ok_p)
70 ControlFileData *ControlFile;
71 int fd;
72 pg_crc32c crc;
73 int r;
74 #ifdef FRONTEND
75 pg_crc32c last_crc;
76 int retries = 0;
77 #endif
79 Assert(crc_ok_p);
81 ControlFile = palloc_object(ControlFileData);
83 #ifdef FRONTEND
84 INIT_CRC32C(last_crc);
86 retry:
87 #endif
89 #ifndef FRONTEND
90 if ((fd = OpenTransientFile(ControlFilePath, O_RDONLY | PG_BINARY)) == -1)
91 ereport(ERROR,
92 (errcode_for_file_access(),
93 errmsg("could not open file \"%s\" for reading: %m",
94 ControlFilePath)));
95 #else
96 if ((fd = open(ControlFilePath, O_RDONLY | PG_BINARY, 0)) == -1)
97 pg_fatal("could not open file \"%s\" for reading: %m",
98 ControlFilePath);
99 #endif
101 r = read(fd, ControlFile, sizeof(ControlFileData));
102 if (r != sizeof(ControlFileData))
104 if (r < 0)
105 #ifndef FRONTEND
106 ereport(ERROR,
107 (errcode_for_file_access(),
108 errmsg("could not read file \"%s\": %m", ControlFilePath)));
109 #else
110 pg_fatal("could not read file \"%s\": %m", ControlFilePath);
111 #endif
112 else
113 #ifndef FRONTEND
114 ereport(ERROR,
115 (errcode(ERRCODE_DATA_CORRUPTED),
116 errmsg("could not read file \"%s\": read %d of %zu",
117 ControlFilePath, r, sizeof(ControlFileData))));
118 #else
119 pg_fatal("could not read file \"%s\": read %d of %zu",
120 ControlFilePath, r, sizeof(ControlFileData));
121 #endif
124 #ifndef FRONTEND
125 if (CloseTransientFile(fd) != 0)
126 ereport(ERROR,
127 (errcode_for_file_access(),
128 errmsg("could not close file \"%s\": %m",
129 ControlFilePath)));
130 #else
131 if (close(fd) != 0)
132 pg_fatal("could not close file \"%s\": %m", ControlFilePath);
133 #endif
135 /* Check the CRC. */
136 INIT_CRC32C(crc);
137 COMP_CRC32C(crc,
138 (char *) ControlFile,
139 offsetof(ControlFileData, crc));
140 FIN_CRC32C(crc);
142 *crc_ok_p = EQ_CRC32C(crc, ControlFile->crc);
144 #ifdef FRONTEND
147 * If the server was writing at the same time, it is possible that we read
148 * partially updated contents on some systems. If the CRC doesn't match,
149 * retry a limited number of times until we compute the same bad CRC twice
150 * in a row with a short sleep in between. Then the failure is unlikely
151 * to be due to a concurrent write.
153 if (!*crc_ok_p &&
154 (retries == 0 || !EQ_CRC32C(crc, last_crc)) &&
155 retries < 10)
157 retries++;
158 last_crc = crc;
159 pg_usleep(10000);
160 goto retry;
162 #endif
164 /* Make sure the control file is valid byte order. */
165 if (ControlFile->pg_control_version % 65536 == 0 &&
166 ControlFile->pg_control_version / 65536 != 0)
167 #ifndef FRONTEND
168 elog(ERROR, _("byte ordering mismatch"));
169 #else
170 pg_log_warning("possible byte ordering mismatch\n"
171 "The byte ordering used to store the pg_control file might not match the one\n"
172 "used by this program. In that case the results below would be incorrect, and\n"
173 "the PostgreSQL installation would be incompatible with this data directory.");
174 #endif
176 return ControlFile;
180 * update_controlfile()
182 * Update controlfile values with the contents given by caller. The
183 * contents to write are included in "ControlFile". "do_sync" can be
184 * optionally used to flush the updated control file. Note that it is up
185 * to the caller to properly lock ControlFileLock when calling this
186 * routine in the backend.
188 void
189 update_controlfile(const char *DataDir,
190 ControlFileData *ControlFile, bool do_sync)
192 int fd;
193 char buffer[PG_CONTROL_FILE_SIZE];
194 char ControlFilePath[MAXPGPATH];
196 /* Update timestamp */
197 ControlFile->time = (pg_time_t) time(NULL);
199 /* Recalculate CRC of control file */
200 INIT_CRC32C(ControlFile->crc);
201 COMP_CRC32C(ControlFile->crc,
202 (char *) ControlFile,
203 offsetof(ControlFileData, crc));
204 FIN_CRC32C(ControlFile->crc);
207 * Write out PG_CONTROL_FILE_SIZE bytes into pg_control by zero-padding
208 * the excess over sizeof(ControlFileData), to avoid premature EOF related
209 * errors when reading it.
211 memset(buffer, 0, PG_CONTROL_FILE_SIZE);
212 memcpy(buffer, ControlFile, sizeof(ControlFileData));
214 snprintf(ControlFilePath, sizeof(ControlFilePath), "%s/%s", DataDir, XLOG_CONTROL_FILE);
216 #ifndef FRONTEND
219 * All errors issue a PANIC, so no need to use OpenTransientFile() and to
220 * worry about file descriptor leaks.
222 if ((fd = BasicOpenFile(ControlFilePath, O_RDWR | PG_BINARY)) < 0)
223 ereport(PANIC,
224 (errcode_for_file_access(),
225 errmsg("could not open file \"%s\": %m",
226 ControlFilePath)));
227 #else
228 if ((fd = open(ControlFilePath, O_WRONLY | PG_BINARY,
229 pg_file_create_mode)) == -1)
230 pg_fatal("could not open file \"%s\": %m", ControlFilePath);
231 #endif
233 errno = 0;
234 #ifndef FRONTEND
235 pgstat_report_wait_start(WAIT_EVENT_CONTROL_FILE_WRITE_UPDATE);
236 #endif
237 if (write(fd, buffer, PG_CONTROL_FILE_SIZE) != PG_CONTROL_FILE_SIZE)
239 /* if write didn't set errno, assume problem is no disk space */
240 if (errno == 0)
241 errno = ENOSPC;
243 #ifndef FRONTEND
244 ereport(PANIC,
245 (errcode_for_file_access(),
246 errmsg("could not write file \"%s\": %m",
247 ControlFilePath)));
248 #else
249 pg_fatal("could not write file \"%s\": %m", ControlFilePath);
250 #endif
252 #ifndef FRONTEND
253 pgstat_report_wait_end();
254 #endif
256 if (do_sync)
258 #ifndef FRONTEND
259 pgstat_report_wait_start(WAIT_EVENT_CONTROL_FILE_SYNC_UPDATE);
260 if (pg_fsync(fd) != 0)
261 ereport(PANIC,
262 (errcode_for_file_access(),
263 errmsg("could not fsync file \"%s\": %m",
264 ControlFilePath)));
265 pgstat_report_wait_end();
266 #else
267 if (fsync(fd) != 0)
268 pg_fatal("could not fsync file \"%s\": %m", ControlFilePath);
269 #endif
272 if (close(fd) != 0)
274 #ifndef FRONTEND
275 ereport(PANIC,
276 (errcode_for_file_access(),
277 errmsg("could not close file \"%s\": %m",
278 ControlFilePath)));
279 #else
280 pg_fatal("could not close file \"%s\": %m", ControlFilePath);
281 #endif