Header And Logo

PostgreSQL
| The world's most advanced open source database.

Defines | Functions

exec.c File Reference

#include "postgres_fe.h"
#include "pg_upgrade.h"
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
Include dependency graph for exec.c:

Go to the source code of this file.

Defines

#define MAXCMDLEN   (2 * MAXPGPATH)

Functions

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)
bool exec_prog (const char *log_file, const char *opt_log_file, bool throw_error, const char *fmt,...)
bool pid_lock_file_exists (const char *datadir)
void verify_directories (void)

Define Documentation

#define MAXCMDLEN   (2 * MAXPGPATH)

Referenced by exec_prog().


Function Documentation

static void check_bin_dir ( ClusterInfo cluster  )  [static]

Definition at line 273 of file exec.c.

References ClusterInfo::bindir, getErrorText(), new_cluster, PG_FATAL, report_status(), and validate_exec().

Referenced by verify_directories().

{
    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_dumpall");
    }
}

static void check_data_dir ( const char *  pg_data  )  [static]

Definition at line 233 of file exec.c.

References getErrorText(), PG_FATAL, report_status(), and snprintf().

Referenced by verify_directories().

{
    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);
    }
}

bool exec_prog ( const char *  log_file,
const char *  opt_log_file,
bool  throw_error,
const char *  fmt,
  ... 
)

Definition at line 42 of file exec.c.

References fopen_priv(), MAXCMDLEN, NULL, PG_FATAL, pg_log(), PG_REPORT, PG_VERBOSE, report_status(), S_IRWXG, S_IRWXO, snprintf(), strlcpy(), system(), SYSTEMQUOTE, and vsnprintf().

Referenced by copy_clog_xlog_xid(), copy_subdir_files(), generate_old_dump(), issue_warnings(), main(), parallel_exec_prog(), prepare_new_cluster(), prepare_new_databases(), start_postmaster(), and stop_postmaster().

{
    int         result;
    int         written;
#define MAXCMDLEN (2 * MAXPGPATH)
    char        cmd[MAXCMDLEN];
    mode_t      old_umask = 0;
    FILE       *log;
    va_list     ap;

    old_umask = umask(S_IRWXG | S_IRWXO);

    written = strlcpy(cmd, SYSTEMQUOTE, sizeof(cmd));
    va_start(ap, fmt);
    written += vsnprintf(cmd + written, MAXCMDLEN - written, fmt, ap);
    va_end(ap);
    if (written >= MAXCMDLEN)
        pg_log(PG_FATAL, "command too long\n");
    written += snprintf(cmd + written, MAXCMDLEN - written,
                        " >> \"%s\" 2>&1" SYSTEMQUOTE, log_file);
    if (written >= MAXCMDLEN)
        pg_log(PG_FATAL, "command too long\n");

    log = fopen_priv(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++)
        {
            sleep(1);
            log = fopen_priv(log_file, "a");
        }
    }
#endif

    if (log == NULL)
        pg_log(PG_FATAL, "cannot write to log file %s\n", log_file);
#ifdef WIN32
    fprintf(log, "\n\n");
#endif
    pg_log(PG_VERBOSE, "%s\n", cmd);
    fprintf(log, "command: %s\n", cmd);

    /*
     * 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);

    result = system(cmd);

    umask(old_umask);

    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_priv(log_file, "a")) == NULL)
        pg_log(PG_FATAL, "cannot write to log file %s\n", log_file);
    fprintf(log, "\n\n");
    fclose(log);
#endif

    return result == 0;
}

bool pid_lock_file_exists ( const char *  datadir  ) 

Definition at line 148 of file exec.c.

References close, getErrorText(), PG_FATAL, pg_log(), and snprintf().

Referenced by setup().

{
    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_log(PG_FATAL, "could not open file \"%s\" for reading: %s\n",
                   path, getErrorText(errno));

        return false;
    }

    close(fd);
    return true;
}

static void validate_exec ( const char *  dir,
const char *  cmdName 
) [static]

Definition at line 303 of file exec.c.

References getErrorText(), PG_FATAL, pg_log(), pg_strcasecmp(), snprintf(), and strlcat().

Referenced by check_bin_dir().

{
    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_log(PG_FATAL, "check for \"%s\" failed: %s\n",
               path, getErrorText(errno));
    else if (!S_ISREG(buf.st_mode))
        pg_log(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_log(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_log(PG_FATAL, "check for \"%s\" failed: cannot execute (permission denied)\n",
               path);
}

void verify_directories ( void   ) 

Definition at line 179 of file exec.c.

References check_bin_dir(), check_data_dir(), new_cluster, old_cluster, PG_FATAL, pg_log(), and ClusterInfo::pgdata.

Referenced by setup().

{

#ifndef WIN32
    if (access(".", R_OK | W_OK | X_OK) != 0)
#else
    if (win32_check_directory_write_permissions() != 0)
#endif
        pg_log(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);
}