diff options
Diffstat (limited to 'contrib/pg_upgrade/exec.c')
-rw-r--r-- | contrib/pg_upgrade/exec.c | 379 |
1 files changed, 0 insertions, 379 deletions
diff --git a/contrib/pg_upgrade/exec.c b/contrib/pg_upgrade/exec.c deleted file mode 100644 index bf87419b187..00000000000 --- a/contrib/pg_upgrade/exec.c +++ /dev/null @@ -1,379 +0,0 @@ -/* - * exec.c - * - * execution functions - * - * Copyright (c) 2010-2015, PostgreSQL Global Development Group - * contrib/pg_upgrade/exec.c - */ - -#include "postgres_fe.h" - -#include "pg_upgrade.h" - -#include <fcntl.h> -#include <sys/types.h> - -static void check_data_dir(const char *pg_data); -static void check_bin_dir(ClusterInfo *cluster); -static void validate_exec(const char *dir, const char *cmdName); - -#ifdef WIN32 -static int win32_check_directory_write_permissions(void); -#endif - - -/* - * exec_prog() - * Execute an external program with stdout/stderr redirected, and report - * errors - * - * Formats a command from the given argument list, logs it to the log file, - * and attempts to execute that command. If the command executes - * successfully, exec_prog() returns true. - * - * If the command fails, an error message is saved to the specified log_file. - * If throw_error is true, this raises a PG_FATAL error and pg_upgrade - * terminates; otherwise it is just reported as PG_REPORT and exec_prog() - * returns false. - * - * The code requires it be called first from the primary thread on Windows. - */ -bool -exec_prog(const char *log_file, const char *opt_log_file, - bool throw_error, const char *fmt,...) -{ - int result = 0; - int written; - -#define MAXCMDLEN (2 * MAXPGPATH) - char cmd[MAXCMDLEN]; - FILE *log; - va_list ap; - -#ifdef WIN32 - static DWORD mainThreadId = 0; - - /* We assume we are called from the primary thread first */ - if (mainThreadId == 0) - mainThreadId = GetCurrentThreadId(); -#endif - - written = 0; - va_start(ap, fmt); - written += vsnprintf(cmd + written, MAXCMDLEN - written, fmt, ap); - va_end(ap); - if (written >= MAXCMDLEN) - pg_fatal("command too long\n"); - written += snprintf(cmd + written, MAXCMDLEN - written, - " >> \"%s\" 2>&1", log_file); - if (written >= MAXCMDLEN) - pg_fatal("command too long\n"); - - pg_log(PG_VERBOSE, "%s\n", cmd); - -#ifdef WIN32 - - /* - * For some reason, Windows issues a file-in-use error if we write data to - * the log file from a non-primary thread just before we create a - * subprocess that also writes to the same log file. One fix is to sleep - * for 100ms. A cleaner fix is to write to the log file _after_ the - * subprocess has completed, so we do this only when writing from a - * non-primary thread. fflush(), running system() twice, and pre-creating - * the file do not see to help. - */ - if (mainThreadId != GetCurrentThreadId()) - result = system(cmd); -#endif - - log = fopen(log_file, "a"); - -#ifdef WIN32 - { - /* - * "pg_ctl -w stop" might have reported that the server has stopped - * because the postmaster.pid file has been removed, but "pg_ctl -w - * start" might still be in the process of closing and might still be - * holding its stdout and -l log file descriptors open. Therefore, - * try to open the log file a few more times. - */ - int iter; - - for (iter = 0; iter < 4 && log == NULL; iter++) - { - pg_usleep(1000000); /* 1 sec */ - log = fopen(log_file, "a"); - } - } -#endif - - if (log == NULL) - pg_fatal("cannot write to log file %s\n", log_file); - -#ifdef WIN32 - /* Are we printing "command:" before its output? */ - if (mainThreadId == GetCurrentThreadId()) - fprintf(log, "\n\n"); -#endif - fprintf(log, "command: %s\n", cmd); -#ifdef WIN32 - /* Are we printing "command:" after its output? */ - if (mainThreadId != GetCurrentThreadId()) - fprintf(log, "\n\n"); -#endif - - /* - * In Windows, we must close the log file at this point so the file is not - * open while the command is running, or we get a share violation. - */ - fclose(log); - -#ifdef WIN32 - /* see comment above */ - if (mainThreadId == GetCurrentThreadId()) -#endif - result = system(cmd); - - if (result != 0) - { - /* we might be in on a progress status line, so go to the next line */ - report_status(PG_REPORT, "\n*failure*"); - fflush(stdout); - - pg_log(PG_VERBOSE, "There were problems executing \"%s\"\n", cmd); - if (opt_log_file) - pg_log(throw_error ? PG_FATAL : PG_REPORT, - "Consult the last few lines of \"%s\" or \"%s\" for\n" - "the probable cause of the failure.\n", - log_file, opt_log_file); - else - pg_log(throw_error ? PG_FATAL : PG_REPORT, - "Consult the last few lines of \"%s\" for\n" - "the probable cause of the failure.\n", - log_file); - } - -#ifndef WIN32 - - /* - * We can't do this on Windows because it will keep the "pg_ctl start" - * output filename open until the server stops, so we do the \n\n above on - * that platform. We use a unique filename for "pg_ctl start" that is - * never reused while the server is running, so it works fine. We could - * log these commands to a third file, but that just adds complexity. - */ - if ((log = fopen(log_file, "a")) == NULL) - pg_fatal("cannot write to log file %s\n", log_file); - fprintf(log, "\n\n"); - fclose(log); -#endif - - return result == 0; -} - - -/* - * pid_lock_file_exists() - * - * Checks whether the postmaster.pid file exists. - */ -bool -pid_lock_file_exists(const char *datadir) -{ - char path[MAXPGPATH]; - int fd; - - snprintf(path, sizeof(path), "%s/postmaster.pid", datadir); - - if ((fd = open(path, O_RDONLY, 0)) < 0) - { - /* ENOTDIR means we will throw a more useful error later */ - if (errno != ENOENT && errno != ENOTDIR) - pg_fatal("could not open file \"%s\" for reading: %s\n", - path, getErrorText(errno)); - - return false; - } - - close(fd); - return true; -} - - -/* - * verify_directories() - * - * does all the hectic work of verifying directories and executables - * of old and new server. - * - * NOTE: May update the values of all parameters - */ -void -verify_directories(void) -{ -#ifndef WIN32 - if (access(".", R_OK | W_OK | X_OK) != 0) -#else - if (win32_check_directory_write_permissions() != 0) -#endif - pg_fatal("You must have read and write access in the current directory.\n"); - - check_bin_dir(&old_cluster); - check_data_dir(old_cluster.pgdata); - check_bin_dir(&new_cluster); - check_data_dir(new_cluster.pgdata); -} - - -#ifdef WIN32 -/* - * win32_check_directory_write_permissions() - * - * access() on WIN32 can't check directory permissions, so we have to - * optionally create, then delete a file to check. - * http://msdn.microsoft.com/en-us/library/1w06ktdy%28v=vs.80%29.aspx - */ -static int -win32_check_directory_write_permissions(void) -{ - int fd; - - /* - * We open a file we would normally create anyway. We do this even in - * 'check' mode, which isn't ideal, but this is the best we can do. - */ - if ((fd = open(GLOBALS_DUMP_FILE, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR)) < 0) - return -1; - close(fd); - - return unlink(GLOBALS_DUMP_FILE); -} -#endif - - -/* - * check_data_dir() - * - * This function validates the given cluster directory - we search for a - * small set of subdirectories that we expect to find in a valid $PGDATA - * directory. If any of the subdirectories are missing (or secured against - * us) we display an error message and exit() - * - */ -static void -check_data_dir(const char *pg_data) -{ - char subDirName[MAXPGPATH]; - int subdirnum; - - /* start check with top-most directory */ - const char *requiredSubdirs[] = {"", "base", "global", "pg_clog", - "pg_multixact", "pg_subtrans", "pg_tblspc", "pg_twophase", - "pg_xlog"}; - - for (subdirnum = 0; - subdirnum < sizeof(requiredSubdirs) / sizeof(requiredSubdirs[0]); - ++subdirnum) - { - struct stat statBuf; - - snprintf(subDirName, sizeof(subDirName), "%s%s%s", pg_data, - /* Win32 can't stat() a directory with a trailing slash. */ - *requiredSubdirs[subdirnum] ? "/" : "", - requiredSubdirs[subdirnum]); - - if (stat(subDirName, &statBuf) != 0) - report_status(PG_FATAL, "check for \"%s\" failed: %s\n", - subDirName, getErrorText(errno)); - else if (!S_ISDIR(statBuf.st_mode)) - report_status(PG_FATAL, "%s is not a directory\n", - subDirName); - } -} - - -/* - * check_bin_dir() - * - * This function searches for the executables that we expect to find - * in the binaries directory. If we find that a required executable - * is missing (or secured against us), we display an error message and - * exit(). - */ -static void -check_bin_dir(ClusterInfo *cluster) -{ - struct stat statBuf; - - /* check bindir */ - if (stat(cluster->bindir, &statBuf) != 0) - report_status(PG_FATAL, "check for \"%s\" failed: %s\n", - cluster->bindir, getErrorText(errno)); - else if (!S_ISDIR(statBuf.st_mode)) - report_status(PG_FATAL, "%s is not a directory\n", - cluster->bindir); - - validate_exec(cluster->bindir, "postgres"); - validate_exec(cluster->bindir, "pg_ctl"); - validate_exec(cluster->bindir, "pg_resetxlog"); - if (cluster == &new_cluster) - { - /* these are only needed in the new cluster */ - validate_exec(cluster->bindir, "psql"); - validate_exec(cluster->bindir, "pg_dump"); - validate_exec(cluster->bindir, "pg_dumpall"); - } -} - - -/* - * validate_exec() - * - * validate "path" as an executable file - */ -static void -validate_exec(const char *dir, const char *cmdName) -{ - char path[MAXPGPATH]; - struct stat buf; - - snprintf(path, sizeof(path), "%s/%s", dir, cmdName); - -#ifdef WIN32 - /* Windows requires a .exe suffix for stat() */ - if (strlen(path) <= strlen(EXE_EXT) || - pg_strcasecmp(path + strlen(path) - strlen(EXE_EXT), EXE_EXT) != 0) - strlcat(path, EXE_EXT, sizeof(path)); -#endif - - /* - * Ensure that the file exists and is a regular file. - */ - if (stat(path, &buf) < 0) - pg_fatal("check for \"%s\" failed: %s\n", - path, getErrorText(errno)); - else if (!S_ISREG(buf.st_mode)) - pg_fatal("check for \"%s\" failed: not an executable file\n", - path); - - /* - * Ensure that the file is both executable and readable (required for - * dynamic loading). - */ -#ifndef WIN32 - if (access(path, R_OK) != 0) -#else - if ((buf.st_mode & S_IRUSR) == 0) -#endif - pg_fatal("check for \"%s\" failed: cannot read file (permission denied)\n", - path); - -#ifndef WIN32 - if (access(path, X_OK) != 0) -#else - if ((buf.st_mode & S_IXUSR) == 0) -#endif - pg_fatal("check for \"%s\" failed: cannot execute (permission denied)\n", - path); -} |