1/*-------------------------------------------------------------------------
2 *
3 * controldata_utils.c
4 * Common code for control data file output.
5 *
6 *
7 * Portions Copyright (c) 1996-2019, 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
27#include "access/xlog_internal.h"
28#include "catalog/pg_control.h"
29#include "common/controldata_utils.h"
30#include "common/file_perm.h"
31#ifdef FRONTEND
32#include "common/logging.h"
33#endif
34#include "port/pg_crc32c.h"
35
36#ifndef FRONTEND
37#include "pgstat.h"
38#include "storage/fd.h"
39#endif
40
41/*
42 * get_controlfile()
43 *
44 * Get controlfile values. The result is returned as a palloc'd copy of the
45 * control file data.
46 *
47 * crc_ok_p can be used by the caller to see whether the CRC of the control
48 * file data is correct.
49 */
50ControlFileData *
51get_controlfile(const char *DataDir, bool *crc_ok_p)
52{
53 ControlFileData *ControlFile;
54 int fd;
55 char ControlFilePath[MAXPGPATH];
56 pg_crc32c crc;
57 int r;
58
59 AssertArg(crc_ok_p);
60
61 ControlFile = palloc(sizeof(ControlFileData));
62 snprintf(ControlFilePath, MAXPGPATH, "%s/global/pg_control", DataDir);
63
64#ifndef FRONTEND
65 if ((fd = OpenTransientFile(ControlFilePath, O_RDONLY | PG_BINARY)) == -1)
66 ereport(ERROR,
67 (errcode_for_file_access(),
68 errmsg("could not open file \"%s\" for reading: %m",
69 ControlFilePath)));
70#else
71 if ((fd = open(ControlFilePath, O_RDONLY | PG_BINARY, 0)) == -1)
72 {
73 pg_log_fatal("could not open file \"%s\" for reading: %m",
74 ControlFilePath);
75 exit(EXIT_FAILURE);
76 }
77#endif
78
79 r = read(fd, ControlFile, sizeof(ControlFileData));
80 if (r != sizeof(ControlFileData))
81 {
82 if (r < 0)
83#ifndef FRONTEND
84 ereport(ERROR,
85 (errcode_for_file_access(),
86 errmsg("could not read file \"%s\": %m", ControlFilePath)));
87#else
88 {
89 pg_log_fatal("could not read file \"%s\": %m", ControlFilePath);
90 exit(EXIT_FAILURE);
91 }
92#endif
93 else
94#ifndef FRONTEND
95 ereport(ERROR,
96 (errcode(ERRCODE_DATA_CORRUPTED),
97 errmsg("could not read file \"%s\": read %d of %zu",
98 ControlFilePath, r, sizeof(ControlFileData))));
99#else
100 {
101 pg_log_fatal("could not read file \"%s\": read %d of %zu",
102 ControlFilePath, r, sizeof(ControlFileData));
103 exit(EXIT_FAILURE);
104 }
105#endif
106 }
107
108#ifndef FRONTEND
109 if (CloseTransientFile(fd))
110 ereport(ERROR,
111 (errcode_for_file_access(),
112 errmsg("could not close file \"%s\": %m",
113 ControlFilePath)));
114#else
115 if (close(fd))
116 {
117 pg_log_fatal("could not close file \"%s\": %m", ControlFilePath);
118 exit(EXIT_FAILURE);
119 }
120#endif
121
122 /* Check the CRC. */
123 INIT_CRC32C(crc);
124 COMP_CRC32C(crc,
125 (char *) ControlFile,
126 offsetof(ControlFileData, crc));
127 FIN_CRC32C(crc);
128
129 *crc_ok_p = EQ_CRC32C(crc, ControlFile->crc);
130
131 /* Make sure the control file is valid byte order. */
132 if (ControlFile->pg_control_version % 65536 == 0 &&
133 ControlFile->pg_control_version / 65536 != 0)
134#ifndef FRONTEND
135 elog(ERROR, _("byte ordering mismatch"));
136#else
137 pg_log_warning("possible byte ordering mismatch\n"
138 "The byte ordering used to store the pg_control file might not match the one\n"
139 "used by this program. In that case the results below would be incorrect, and\n"
140 "the PostgreSQL installation would be incompatible with this data directory.");
141#endif
142
143 return ControlFile;
144}
145
146/*
147 * update_controlfile()
148 *
149 * Update controlfile values with the contents given by caller. The
150 * contents to write are included in "ControlFile". "do_sync" can be
151 * optionally used to flush the updated control file. Note that it is up
152 * to the caller to properly lock ControlFileLock when calling this
153 * routine in the backend.
154 */
155void
156update_controlfile(const char *DataDir,
157 ControlFileData *ControlFile, bool do_sync)
158{
159 int fd;
160 char buffer[PG_CONTROL_FILE_SIZE];
161 char ControlFilePath[MAXPGPATH];
162
163 /*
164 * Apply the same static assertions as in backend's WriteControlFile().
165 */
166 StaticAssertStmt(sizeof(ControlFileData) <= PG_CONTROL_MAX_SAFE_SIZE,
167 "pg_control is too large for atomic disk writes");
168 StaticAssertStmt(sizeof(ControlFileData) <= PG_CONTROL_FILE_SIZE,
169 "sizeof(ControlFileData) exceeds PG_CONTROL_FILE_SIZE");
170
171 /* Recalculate CRC of control file */
172 INIT_CRC32C(ControlFile->crc);
173 COMP_CRC32C(ControlFile->crc,
174 (char *) ControlFile,
175 offsetof(ControlFileData, crc));
176 FIN_CRC32C(ControlFile->crc);
177
178 /*
179 * Write out PG_CONTROL_FILE_SIZE bytes into pg_control by zero-padding
180 * the excess over sizeof(ControlFileData), to avoid premature EOF related
181 * errors when reading it.
182 */
183 memset(buffer, 0, PG_CONTROL_FILE_SIZE);
184 memcpy(buffer, ControlFile, sizeof(ControlFileData));
185
186 snprintf(ControlFilePath, sizeof(ControlFilePath), "%s/%s", DataDir, XLOG_CONTROL_FILE);
187
188#ifndef FRONTEND
189
190 /*
191 * All errors issue a PANIC, so no need to use OpenTransientFile() and to
192 * worry about file descriptor leaks.
193 */
194 if ((fd = BasicOpenFile(ControlFilePath, O_RDWR | PG_BINARY)) < 0)
195 ereport(PANIC,
196 (errcode_for_file_access(),
197 errmsg("could not open file \"%s\": %m",
198 ControlFilePath)));
199#else
200 if ((fd = open(ControlFilePath, O_WRONLY | PG_BINARY,
201 pg_file_create_mode)) == -1)
202 {
203 pg_log_fatal("could not open file \"%s\": %m", ControlFilePath);
204 exit(EXIT_FAILURE);
205 }
206#endif
207
208 errno = 0;
209#ifndef FRONTEND
210 pgstat_report_wait_start(WAIT_EVENT_CONTROL_FILE_WRITE_UPDATE);
211#endif
212 if (write(fd, buffer, PG_CONTROL_FILE_SIZE) != PG_CONTROL_FILE_SIZE)
213 {
214 /* if write didn't set errno, assume problem is no disk space */
215 if (errno == 0)
216 errno = ENOSPC;
217
218#ifndef FRONTEND
219 ereport(PANIC,
220 (errcode_for_file_access(),
221 errmsg("could not write file \"%s\": %m",
222 ControlFilePath)));
223#else
224 pg_log_fatal("could not write file \"%s\": %m", ControlFilePath);
225 exit(EXIT_FAILURE);
226#endif
227 }
228#ifndef FRONTEND
229 pgstat_report_wait_end();
230#endif
231
232 if (do_sync)
233 {
234#ifndef FRONTEND
235 pgstat_report_wait_start(WAIT_EVENT_CONTROL_FILE_SYNC_UPDATE);
236 if (pg_fsync(fd) != 0)
237 ereport(PANIC,
238 (errcode_for_file_access(),
239 errmsg("could not fsync file \"%s\": %m",
240 ControlFilePath)));
241 pgstat_report_wait_end();
242#else
243 if (fsync(fd) != 0)
244 {
245 pg_log_fatal("could not fsync file \"%s\": %m", ControlFilePath);
246 exit(EXIT_FAILURE);
247 }
248#endif
249 }
250
251 if (close(fd) < 0)
252 {
253#ifndef FRONTEND
254 ereport(PANIC,
255 (errcode_for_file_access(),
256 errmsg("could not close file \"%s\": %m",
257 ControlFilePath)));
258#else
259 pg_log_fatal("could not close file \"%s\": %m", ControlFilePath);
260 exit(EXIT_FAILURE);
261#endif
262 }
263}
264