summaryrefslogtreecommitdiff
path: root/contrib/pg_upgrade/exec.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/pg_upgrade/exec.c')
-rw-r--r--contrib/pg_upgrade/exec.c379
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);
-}