1 /*-------------------------------------------------------------------------
2  *
3  * controldata_utils.c
4  *		Common code for control data file output.
5  *
6  *
7  * Portions Copyright (c) 1996-2020, 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  */
50 ControlFileData *
get_controlfile(const char * DataDir,bool * crc_ok_p)51 get_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) != 0)
110 		ereport(ERROR,
111 				(errcode_for_file_access(),
112 				 errmsg("could not close file \"%s\": %m",
113 						ControlFilePath)));
114 #else
115 	if (close(fd) != 0)
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  */
155 void
update_controlfile(const char * DataDir,ControlFileData * ControlFile,bool do_sync)156 update_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