1 | /* |
2 | * exec.c |
3 | * |
4 | * execution functions |
5 | * |
6 | * Copyright (c) 2010-2019, PostgreSQL Global Development Group |
7 | * src/bin/pg_upgrade/exec.c |
8 | */ |
9 | |
10 | #include "postgres_fe.h" |
11 | |
12 | #include <fcntl.h> |
13 | |
14 | #include "pg_upgrade.h" |
15 | |
16 | static void check_data_dir(ClusterInfo *cluster); |
17 | static void check_bin_dir(ClusterInfo *cluster); |
18 | static void get_bin_version(ClusterInfo *cluster); |
19 | static void validate_exec(const char *dir, const char *cmdName); |
20 | |
21 | #ifdef WIN32 |
22 | static int win32_check_directory_write_permissions(void); |
23 | #endif |
24 | |
25 | |
26 | /* |
27 | * get_bin_version |
28 | * |
29 | * Fetch major version of binaries for cluster. |
30 | */ |
31 | static void |
32 | get_bin_version(ClusterInfo *cluster) |
33 | { |
34 | char cmd[MAXPGPATH], |
35 | cmd_output[MAX_STRING]; |
36 | FILE *output; |
37 | int v1 = 0, |
38 | v2 = 0; |
39 | |
40 | snprintf(cmd, sizeof(cmd), "\"%s/pg_ctl\" --version" , cluster->bindir); |
41 | |
42 | if ((output = popen(cmd, "r" )) == NULL || |
43 | fgets(cmd_output, sizeof(cmd_output), output) == NULL) |
44 | pg_fatal("could not get pg_ctl version data using %s: %s\n" , |
45 | cmd, strerror(errno)); |
46 | |
47 | pclose(output); |
48 | |
49 | if (sscanf(cmd_output, "%*s %*s %d.%d" , &v1, &v2) < 1) |
50 | pg_fatal("could not get pg_ctl version output from %s\n" , cmd); |
51 | |
52 | if (v1 < 10) |
53 | { |
54 | /* old style, e.g. 9.6.1 */ |
55 | cluster->bin_version = v1 * 10000 + v2 * 100; |
56 | } |
57 | else |
58 | { |
59 | /* new style, e.g. 10.1 */ |
60 | cluster->bin_version = v1 * 10000; |
61 | } |
62 | } |
63 | |
64 | |
65 | /* |
66 | * exec_prog() |
67 | * Execute an external program with stdout/stderr redirected, and report |
68 | * errors |
69 | * |
70 | * Formats a command from the given argument list, logs it to the log file, |
71 | * and attempts to execute that command. If the command executes |
72 | * successfully, exec_prog() returns true. |
73 | * |
74 | * If the command fails, an error message is optionally written to the specified |
75 | * log_file, and the program optionally exits. |
76 | * |
77 | * The code requires it be called first from the primary thread on Windows. |
78 | */ |
79 | bool |
80 | exec_prog(const char *log_file, const char *opt_log_file, |
81 | bool report_error, bool exit_on_error, const char *fmt,...) |
82 | { |
83 | int result = 0; |
84 | int written; |
85 | |
86 | #define MAXCMDLEN (2 * MAXPGPATH) |
87 | char cmd[MAXCMDLEN]; |
88 | FILE *log; |
89 | va_list ap; |
90 | |
91 | #ifdef WIN32 |
92 | static DWORD mainThreadId = 0; |
93 | |
94 | /* We assume we are called from the primary thread first */ |
95 | if (mainThreadId == 0) |
96 | mainThreadId = GetCurrentThreadId(); |
97 | #endif |
98 | |
99 | written = 0; |
100 | va_start(ap, fmt); |
101 | written += vsnprintf(cmd + written, MAXCMDLEN - written, fmt, ap); |
102 | va_end(ap); |
103 | if (written >= MAXCMDLEN) |
104 | pg_fatal("command too long\n" ); |
105 | written += snprintf(cmd + written, MAXCMDLEN - written, |
106 | " >> \"%s\" 2>&1" , log_file); |
107 | if (written >= MAXCMDLEN) |
108 | pg_fatal("command too long\n" ); |
109 | |
110 | pg_log(PG_VERBOSE, "%s\n" , cmd); |
111 | |
112 | #ifdef WIN32 |
113 | |
114 | /* |
115 | * For some reason, Windows issues a file-in-use error if we write data to |
116 | * the log file from a non-primary thread just before we create a |
117 | * subprocess that also writes to the same log file. One fix is to sleep |
118 | * for 100ms. A cleaner fix is to write to the log file _after_ the |
119 | * subprocess has completed, so we do this only when writing from a |
120 | * non-primary thread. fflush(), running system() twice, and pre-creating |
121 | * the file do not see to help. |
122 | */ |
123 | if (mainThreadId != GetCurrentThreadId()) |
124 | result = system(cmd); |
125 | #endif |
126 | |
127 | log = fopen(log_file, "a" ); |
128 | |
129 | #ifdef WIN32 |
130 | { |
131 | /* |
132 | * "pg_ctl -w stop" might have reported that the server has stopped |
133 | * because the postmaster.pid file has been removed, but "pg_ctl -w |
134 | * start" might still be in the process of closing and might still be |
135 | * holding its stdout and -l log file descriptors open. Therefore, |
136 | * try to open the log file a few more times. |
137 | */ |
138 | int iter; |
139 | |
140 | for (iter = 0; iter < 4 && log == NULL; iter++) |
141 | { |
142 | pg_usleep(1000000); /* 1 sec */ |
143 | log = fopen(log_file, "a" ); |
144 | } |
145 | } |
146 | #endif |
147 | |
148 | if (log == NULL) |
149 | pg_fatal("could not open log file \"%s\": %m\n" , log_file); |
150 | |
151 | #ifdef WIN32 |
152 | /* Are we printing "command:" before its output? */ |
153 | if (mainThreadId == GetCurrentThreadId()) |
154 | fprintf(log, "\n\n" ); |
155 | #endif |
156 | fprintf(log, "command: %s\n" , cmd); |
157 | #ifdef WIN32 |
158 | /* Are we printing "command:" after its output? */ |
159 | if (mainThreadId != GetCurrentThreadId()) |
160 | fprintf(log, "\n\n" ); |
161 | #endif |
162 | |
163 | /* |
164 | * In Windows, we must close the log file at this point so the file is not |
165 | * open while the command is running, or we get a share violation. |
166 | */ |
167 | fclose(log); |
168 | |
169 | #ifdef WIN32 |
170 | /* see comment above */ |
171 | if (mainThreadId == GetCurrentThreadId()) |
172 | #endif |
173 | result = system(cmd); |
174 | |
175 | if (result != 0 && report_error) |
176 | { |
177 | /* we might be in on a progress status line, so go to the next line */ |
178 | report_status(PG_REPORT, "\n*failure*" ); |
179 | fflush(stdout); |
180 | |
181 | pg_log(PG_VERBOSE, "There were problems executing \"%s\"\n" , cmd); |
182 | if (opt_log_file) |
183 | pg_log(exit_on_error ? PG_FATAL : PG_REPORT, |
184 | "Consult the last few lines of \"%s\" or \"%s\" for\n" |
185 | "the probable cause of the failure.\n" , |
186 | log_file, opt_log_file); |
187 | else |
188 | pg_log(exit_on_error ? PG_FATAL : PG_REPORT, |
189 | "Consult the last few lines of \"%s\" for\n" |
190 | "the probable cause of the failure.\n" , |
191 | log_file); |
192 | } |
193 | |
194 | #ifndef WIN32 |
195 | |
196 | /* |
197 | * We can't do this on Windows because it will keep the "pg_ctl start" |
198 | * output filename open until the server stops, so we do the \n\n above on |
199 | * that platform. We use a unique filename for "pg_ctl start" that is |
200 | * never reused while the server is running, so it works fine. We could |
201 | * log these commands to a third file, but that just adds complexity. |
202 | */ |
203 | if ((log = fopen(log_file, "a" )) == NULL) |
204 | pg_fatal("could not write to log file \"%s\": %m\n" , log_file); |
205 | fprintf(log, "\n\n" ); |
206 | fclose(log); |
207 | #endif |
208 | |
209 | return result == 0; |
210 | } |
211 | |
212 | |
213 | /* |
214 | * pid_lock_file_exists() |
215 | * |
216 | * Checks whether the postmaster.pid file exists. |
217 | */ |
218 | bool |
219 | pid_lock_file_exists(const char *datadir) |
220 | { |
221 | char path[MAXPGPATH]; |
222 | int fd; |
223 | |
224 | snprintf(path, sizeof(path), "%s/postmaster.pid" , datadir); |
225 | |
226 | if ((fd = open(path, O_RDONLY, 0)) < 0) |
227 | { |
228 | /* ENOTDIR means we will throw a more useful error later */ |
229 | if (errno != ENOENT && errno != ENOTDIR) |
230 | pg_fatal("could not open file \"%s\" for reading: %s\n" , |
231 | path, strerror(errno)); |
232 | |
233 | return false; |
234 | } |
235 | |
236 | close(fd); |
237 | return true; |
238 | } |
239 | |
240 | |
241 | /* |
242 | * verify_directories() |
243 | * |
244 | * does all the hectic work of verifying directories and executables |
245 | * of old and new server. |
246 | * |
247 | * NOTE: May update the values of all parameters |
248 | */ |
249 | void |
250 | verify_directories(void) |
251 | { |
252 | #ifndef WIN32 |
253 | if (access("." , R_OK | W_OK | X_OK) != 0) |
254 | #else |
255 | if (win32_check_directory_write_permissions() != 0) |
256 | #endif |
257 | pg_fatal("You must have read and write access in the current directory.\n" ); |
258 | |
259 | check_bin_dir(&old_cluster); |
260 | check_data_dir(&old_cluster); |
261 | check_bin_dir(&new_cluster); |
262 | check_data_dir(&new_cluster); |
263 | } |
264 | |
265 | |
266 | #ifdef WIN32 |
267 | /* |
268 | * win32_check_directory_write_permissions() |
269 | * |
270 | * access() on WIN32 can't check directory permissions, so we have to |
271 | * optionally create, then delete a file to check. |
272 | * http://msdn.microsoft.com/en-us/library/1w06ktdy%28v=vs.80%29.aspx |
273 | */ |
274 | static int |
275 | win32_check_directory_write_permissions(void) |
276 | { |
277 | int fd; |
278 | |
279 | /* |
280 | * We open a file we would normally create anyway. We do this even in |
281 | * 'check' mode, which isn't ideal, but this is the best we can do. |
282 | */ |
283 | if ((fd = open(GLOBALS_DUMP_FILE, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR)) < 0) |
284 | return -1; |
285 | close(fd); |
286 | |
287 | return unlink(GLOBALS_DUMP_FILE); |
288 | } |
289 | #endif |
290 | |
291 | |
292 | /* |
293 | * check_single_dir() |
294 | * |
295 | * Check for the presence of a single directory in PGDATA, and fail if |
296 | * is it missing or not accessible. |
297 | */ |
298 | static void |
299 | check_single_dir(const char *pg_data, const char *subdir) |
300 | { |
301 | struct stat statBuf; |
302 | char subDirName[MAXPGPATH]; |
303 | |
304 | snprintf(subDirName, sizeof(subDirName), "%s%s%s" , pg_data, |
305 | /* Win32 can't stat() a directory with a trailing slash. */ |
306 | *subdir ? "/" : "" , |
307 | subdir); |
308 | |
309 | if (stat(subDirName, &statBuf) != 0) |
310 | report_status(PG_FATAL, "check for \"%s\" failed: %s\n" , |
311 | subDirName, strerror(errno)); |
312 | else if (!S_ISDIR(statBuf.st_mode)) |
313 | report_status(PG_FATAL, "\"%s\" is not a directory\n" , |
314 | subDirName); |
315 | } |
316 | |
317 | |
318 | /* |
319 | * check_data_dir() |
320 | * |
321 | * This function validates the given cluster directory - we search for a |
322 | * small set of subdirectories that we expect to find in a valid $PGDATA |
323 | * directory. If any of the subdirectories are missing (or secured against |
324 | * us) we display an error message and exit() |
325 | * |
326 | */ |
327 | static void |
328 | check_data_dir(ClusterInfo *cluster) |
329 | { |
330 | const char *pg_data = cluster->pgdata; |
331 | |
332 | /* get the cluster version */ |
333 | cluster->major_version = get_major_server_version(cluster); |
334 | |
335 | check_single_dir(pg_data, "" ); |
336 | check_single_dir(pg_data, "base" ); |
337 | check_single_dir(pg_data, "global" ); |
338 | check_single_dir(pg_data, "pg_multixact" ); |
339 | check_single_dir(pg_data, "pg_subtrans" ); |
340 | check_single_dir(pg_data, "pg_tblspc" ); |
341 | check_single_dir(pg_data, "pg_twophase" ); |
342 | |
343 | /* pg_xlog has been renamed to pg_wal in v10 */ |
344 | if (GET_MAJOR_VERSION(cluster->major_version) < 1000) |
345 | check_single_dir(pg_data, "pg_xlog" ); |
346 | else |
347 | check_single_dir(pg_data, "pg_wal" ); |
348 | |
349 | /* pg_clog has been renamed to pg_xact in v10 */ |
350 | if (GET_MAJOR_VERSION(cluster->major_version) < 1000) |
351 | check_single_dir(pg_data, "pg_clog" ); |
352 | else |
353 | check_single_dir(pg_data, "pg_xact" ); |
354 | } |
355 | |
356 | |
357 | /* |
358 | * check_bin_dir() |
359 | * |
360 | * This function searches for the executables that we expect to find |
361 | * in the binaries directory. If we find that a required executable |
362 | * is missing (or secured against us), we display an error message and |
363 | * exit(). |
364 | */ |
365 | static void |
366 | check_bin_dir(ClusterInfo *cluster) |
367 | { |
368 | struct stat statBuf; |
369 | |
370 | /* check bindir */ |
371 | if (stat(cluster->bindir, &statBuf) != 0) |
372 | report_status(PG_FATAL, "check for \"%s\" failed: %s\n" , |
373 | cluster->bindir, strerror(errno)); |
374 | else if (!S_ISDIR(statBuf.st_mode)) |
375 | report_status(PG_FATAL, "\"%s\" is not a directory\n" , |
376 | cluster->bindir); |
377 | |
378 | validate_exec(cluster->bindir, "postgres" ); |
379 | validate_exec(cluster->bindir, "pg_ctl" ); |
380 | |
381 | /* |
382 | * Fetch the binary version after checking for the existence of pg_ctl. |
383 | * This way we report a useful error if the pg_ctl binary used for version |
384 | * fetching is missing/broken. |
385 | */ |
386 | get_bin_version(cluster); |
387 | |
388 | /* pg_resetxlog has been renamed to pg_resetwal in version 10 */ |
389 | if (GET_MAJOR_VERSION(cluster->bin_version) < 1000) |
390 | validate_exec(cluster->bindir, "pg_resetxlog" ); |
391 | else |
392 | validate_exec(cluster->bindir, "pg_resetwal" ); |
393 | if (cluster == &new_cluster) |
394 | { |
395 | /* these are only needed in the new cluster */ |
396 | validate_exec(cluster->bindir, "psql" ); |
397 | validate_exec(cluster->bindir, "pg_dump" ); |
398 | validate_exec(cluster->bindir, "pg_dumpall" ); |
399 | } |
400 | } |
401 | |
402 | |
403 | /* |
404 | * validate_exec() |
405 | * |
406 | * validate "path" as an executable file |
407 | */ |
408 | static void |
409 | validate_exec(const char *dir, const char *cmdName) |
410 | { |
411 | char path[MAXPGPATH]; |
412 | struct stat buf; |
413 | |
414 | snprintf(path, sizeof(path), "%s/%s" , dir, cmdName); |
415 | |
416 | #ifdef WIN32 |
417 | /* Windows requires a .exe suffix for stat() */ |
418 | if (strlen(path) <= strlen(EXE_EXT) || |
419 | pg_strcasecmp(path + strlen(path) - strlen(EXE_EXT), EXE_EXT) != 0) |
420 | strlcat(path, EXE_EXT, sizeof(path)); |
421 | #endif |
422 | |
423 | /* |
424 | * Ensure that the file exists and is a regular file. |
425 | */ |
426 | if (stat(path, &buf) < 0) |
427 | pg_fatal("check for \"%s\" failed: %s\n" , |
428 | path, strerror(errno)); |
429 | else if (!S_ISREG(buf.st_mode)) |
430 | pg_fatal("check for \"%s\" failed: not a regular file\n" , |
431 | path); |
432 | |
433 | /* |
434 | * Ensure that the file is both executable and readable (required for |
435 | * dynamic loading). |
436 | */ |
437 | #ifndef WIN32 |
438 | if (access(path, R_OK) != 0) |
439 | #else |
440 | if ((buf.st_mode & S_IRUSR) == 0) |
441 | #endif |
442 | pg_fatal("check for \"%s\" failed: cannot read file (permission denied)\n" , |
443 | path); |
444 | |
445 | #ifndef WIN32 |
446 | if (access(path, X_OK) != 0) |
447 | #else |
448 | if ((buf.st_mode & S_IXUSR) == 0) |
449 | #endif |
450 | pg_fatal("check for \"%s\" failed: cannot execute (permission denied)\n" , |
451 | path); |
452 | } |
453 | |