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
16static void check_data_dir(ClusterInfo *cluster);
17static void check_bin_dir(ClusterInfo *cluster);
18static void get_bin_version(ClusterInfo *cluster);
19static void validate_exec(const char *dir, const char *cmdName);
20
21#ifdef WIN32
22static 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 */
31static void
32get_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 */
79bool
80exec_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 */
218bool
219pid_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 */
249void
250verify_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 */
274static int
275win32_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 */
298static void
299check_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 */
327static void
328check_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 */
365static void
366check_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 */
408static void
409validate_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