Thread: pg_ctl.c

pg_ctl.c

From
Bruce Momjian
Date:
Here is the C version of pg_ctl.c written by Andrew Dunstan and updated
by me.

You can use it by creating a src/bin/pg_ctl_test directory and putting
the C and Makefile into that directory.  You can then do a make install
and use it for testing.

Unless someone finds a problem, I will apply the change soon.  This
removes our last shell script!

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073
/*-------------------------------------------------------------------------
 *
 * pg_ctl --- start/stops/restarts the PostgreSQL server
 *
 * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
 *
 * $PostgreSQL: pgsql-server/src/bin/initdb/initdb.c,v 1.32 2004/05/18 03:36:36 momjian Exp $
 *
 *-------------------------------------------------------------------------
 */

#include "libpq-fe.h"
#include "postgres_fe.h"
#include <signal.h>
#include <errno.h>
#include "libpq/pqsignal.h"
#include <string.h>

#include <sys/types.h>
#include <sys/stat.h>

#define _(x) gettext((x))

#define WHITESPACE "\f\n\r\t\v"        /* as defined by isspace() */

/* postmaster version ident string */
#define PM_VERSIONSTR "postmaster (PostgreSQL) " PG_VERSION "\n"


typedef enum
{
    SMART_MODE,
    FAST_MODE,
    IMMEDIATE_MODE
}    ShutdownMode;


typedef enum
{
    NO_COMMAND = 0,
    START_COMMAND,
    STOP_COMMAND,
    RESTART_COMMAND,
    RELOAD_COMMAND,
    STATUS_COMMAND,
    KILL_COMMAND
}    CtlCommand;


static bool do_wait = false;
static bool wait_set = false;
static int    wait_seconds = 60;
static bool silence_echo = false;
static ShutdownMode shutdown_mode = SMART_MODE;
static int    sig = SIGTERM;    /* default */
static int    killproc;
static CtlCommand ctl_command = NO_COMMAND;
static char *pg_data_opts = NULL;
static char *pg_data = NULL;
static char *post_opts = NULL;
static const char *progname;
static char *log_file = NULL;
static char *postgres_path = NULL;
static char *argv0 = NULL;

static void *xmalloc(size_t size);
static char *xstrdup(const char *s);
static void do_advice(void);
static void do_help(void);
static void set_mode(char *modeopt);
static void set_sig(char *signame);
static void do_start();
static void do_stop(void);
static void do_restart(void);
static void do_reload(void);
static void do_status(void);
static void do_kill(void);
static long get_pgpid(void);
static char **readfile(char *path);
static void start_postmaster(void);
static bool test_postmaster_connection(void);

static char def_postopts_file[MAXPGPATH];
static char postopts_file[MAXPGPATH];
static char pid_file[MAXPGPATH];
static char conf_file[MAXPGPATH];

/*
 * routines to check memory allocations and fail noisily.
 */

static void *
xmalloc(size_t size)
{
    void       *result;

    result = malloc(size);
    if (!result)
    {
        fprintf(stderr, _("%s: out of memory\n"), progname);
        exit(1);
    }
    return result;
}



static char *
xstrdup(const char *s)
{
    char       *result;

    result = strdup(s);
    if (!result)
    {
        fprintf(stderr, _("%s: out of memory\n"), progname);
        exit(1);
    }
    return result;
}



static long
get_pgpid(void)
{
    FILE       *pidf;
    long        pid;

    pidf = fopen(pid_file, "r");
    if (pidf == NULL)
    {
        /* No pid file, not an error on startup */
        if (errno == ENOENT)
            return 0;
        else
        {
            perror("openning pid file");
            exit(1);
        }
    }
    fscanf(pidf, "%ld", &pid);
    fclose(pidf);
    return pid;
}


/*
 * get the lines from a text file - return NULL if file can't be opened
 */
static char **
readfile(char *path)
{
    FILE       *infile;
    int            maxlength = 0,
                linelen = 0;
    int            nlines = 0;
    char      **result;
    char       *buffer;
    int            c;

    if ((infile = fopen(path, "r")) == NULL)
        return NULL;

    /* pass over the file twice - the first time to size the result */

    while ((c = fgetc(infile)) != EOF)
    {
        linelen++;
        if (c == '\n')
        {
            nlines++;
            if (linelen > maxlength)
                maxlength = linelen;
            linelen = 0;
        }
    }

    /* handle last line without a terminating newline (yuck) */
    if (linelen)
        nlines++;
    if (linelen > maxlength)
        maxlength = linelen;

    /* set up the result and the line buffer */

    result = (char **) xmalloc((nlines + 1) * sizeof(char *));
    buffer = (char *) xmalloc(maxlength + 1);

    /* now reprocess the file and store the lines */
    rewind(infile);
    nlines = 0;
    while (fgets(buffer, maxlength + 1, infile) != NULL)
        result[nlines++] = xstrdup(buffer);

    fclose(infile);
    result[nlines] = NULL;

    return result;
}



/*
 * start/test/stop routines
 */

static void
start_postmaster(void)
{
    /*
     * Since there might be quotes to handle here, it is easier simply
     * to pass everything to a shell to process them.
     */
    char        cmd[MAXPGPATH];

    if (log_file != NULL)
        snprintf(cmd, MAXPGPATH, "\"%s\" %s < %s >>\"%s\" 2>&1 &",
                 postgres_path, post_opts, DEVNULL, log_file);
    else
        snprintf(cmd, MAXPGPATH, "\"%s\" %s < %s 2>&1 &",
                 postgres_path, post_opts, DEVNULL);
    system(cmd);
}



/* Find the pgport and try a connection */
static bool
test_postmaster_connection(void)
{
    PGconn       *conn;
    bool        success = false;
    int            i;
    char        portstr[32];

    *portstr = '\0';

    if (getenv("PGPORT") != NULL)    /* environment */
        snprintf(portstr, sizeof(portstr), "%d", getenv("PGPORT"));
    else    /* post_opts */
    {
        char     *p;

        for (p = post_opts; *p; p++)
        {
            /* advance past whitespace/quoting */
            while (isspace(*p) || *p == '\'' || *p == '"')
                p++;

            if (strncmp(p, "-p", strlen("-p")) == 0)
            {
                /* advance past whitespace/quoting */
                while (isspace(*p) || *p == '\'' || *p == '"')
                    p++;
                StrNCpy(portstr, p, Min(strcspn(p, "\"'"WHITESPACE) + 1,
                                        sizeof(portstr)));
                break;
            }
            /* Advance to next whitespace */
            while (!isspace(*p))
                p++;
        }
    }

    /* config file */
    if (!*portstr)
    {
        char      **optlines;

        optlines = readfile(conf_file);
        if (optlines != NULL)
        {
            for (;*optlines != NULL; optlines++)
            {
                char *p = *optlines;

                while (isspace(*p))
                    p++;
                if (strncmp(p, "port", strlen("port")) != 0)
                    continue;
                while (isspace(*p))
                    p++;
                if (*p != '=')
                    continue;
                p++;
                while (isspace(*p))
                    p++;
                StrNCpy(portstr, p, Min(strcspn(p, "#"WHITESPACE) + 1,
                                        sizeof(portstr)));
                break;
            }
        }
    }

    /* default */
    if (!*portstr)
        snprintf(portstr, sizeof(portstr), "%d", DEF_PGPORT);

    for (i = 0; i < wait_seconds; i++)
    {
        if ((conn = PQsetdbLogin(NULL, portstr, NULL, NULL, "template1", NULL, NULL)) != NULL)
        {
            PQfinish(conn);
            success = true;
            break;
        }
    }

    return success;
}



static void
do_start(void)
{
    long        pid;
    long        old_pid = 0;
    char       *optline = NULL;

    if (ctl_command != RESTART_COMMAND)
    {
        old_pid = get_pgpid();
        if (old_pid != 0)
            fprintf(stderr,
                    "%s: Another postmaster may be running. "
                    "Trying to start postmaster anyway.\n",
                    progname);
    }

    if (post_opts == NULL)
    {
        char      **optlines;
        int            len;

        optlines = readfile(ctl_command == RESTART_COMMAND ?
                            postopts_file : def_postopts_file);
        if (optlines == NULL)
        {
            if (ctl_command == START_COMMAND)
                post_opts = "";
            else
            {
                fprintf(stderr, "%s: cannot read %s\n", progname, postopts_file);
                exit(1);
            }
        }
        else if (optlines[0] == NULL || optlines[1] != NULL)
        {
            fprintf(stderr, "%s: option file %s must have exactly 1 line\n",
                    progname, ctl_command == RESTART_COMMAND ?
                    postopts_file : def_postopts_file);
            exit(1);
        }
        else
        {
            optline = optlines[0];
            len = strcspn(optline, "\r\n");
            optline[len] = '\0';

            if (ctl_command == RESTART_COMMAND)
            {
                char       *arg1;

                arg1 = strchr(optline, '\'');
                if (arg1 == NULL || arg1 == optline)
                    post_opts = "";
                else
                {
                    *(arg1 - 1) = '\0';    /* this should be a space */
                    post_opts = arg1;
                }
                if (postgres_path != NULL)
                    postgres_path = optline;
            }
            else
                post_opts = optline;
        }
    }

    if (postgres_path == NULL)
    {
        char       *postmaster_path;
        int            ret;

        postmaster_path = xmalloc(MAXPGPATH);

        if ((ret = find_other_exec(argv0, "postmaster", PM_VERSIONSTR,
                                   postmaster_path)) < 0)
        {
            if (ret == -1)
                fprintf(stderr,
                        _("The program \"postmaster\" is needed by %s "
                   "but was not found in the same directory as \"%s\".\n"
                          "Check your installation.\n"),
                        progname, progname);
            else
                fprintf(stderr,
                        _("The program \"postmaster\" was found by %s "
                          "but was not the same version as \"%s\".\n"
                          "Check your installation.\n"),
                        progname, progname);
            exit(1);
        }
        postgres_path = postmaster_path;
    }

    start_postmaster();

    if (old_pid != 0)
    {
        pg_usleep(1000000);
        pid = get_pgpid();
        if (pid == old_pid)
        {
            fprintf(stderr,
                    "%s: cannot start postmaster\n"
                    "Examine the log output\n",
                    progname);
            exit(1);
        }
    }

    if (do_wait)
    {
        if (!silence_echo)
        {
            printf("waiting for postmaster to start...");
            fflush(stdout);
        }

        if (test_postmaster_connection() == false)
            printf("could not start postmaster\n");
        else if (!silence_echo)
            printf("done\npostmaster successfully started\n");
    }
    else if (!silence_echo)
        printf("postmaster starting\n");
}



static void
do_stop(void)
{
    int            cnt;
    long        pid;

    pid = get_pgpid();

    if (pid == 0)                /* no pid file */
    {
        fprintf(stderr, "%s: could not find %s\n", progname, pid_file);
        fprintf(stderr, "Is postmaster running?\n");
        exit(1);
    }
    else if (pid < 0)            /* standalone backend, not postmaster */
    {
        pid = -pid;
        fprintf(stderr,
                "%s: cannot stop postmaster; "
                "postgres is running (PID: %ld)\n",
                progname, pid);
        exit(1);
    }

    if (kill((pid_t) pid, sig) != 0)
        fprintf(stderr, "failed\n");

    if (!do_wait)
    {
        if (!silence_echo)
            printf("postmaster shutting down\n");
        return;
    }
    else
    {
        if (!silence_echo)
        {
            printf("waiting for postmaster to shut down...");
            fflush(stdout);
        }

        for (cnt = 0; cnt < wait_seconds; cnt++)
        {
            if ((pid = get_pgpid()) != 0)
            {
                if (!silence_echo)
                {
                    printf(".");
                    fflush(stdout);
                }
                pg_usleep(1000000); /* 1 sec */
            }
            else
                break;
        }

        if (pid != 0)                /* pid file still exists */
        {
            if (!silence_echo)
                printf(" failed\n");

            fprintf(stderr, "%s: postmaster does not shut down\n", progname);
            exit(1);
        }
    }
}


/*
 *    restart/reload routines
 */

static void
do_restart(void)
{
    int            cnt;
    long        pid;

    pid = get_pgpid();

    if (pid == 0)                /* no pid file */
    {
        fprintf(stderr, "%s: could not find %s\n", progname, pid_file);
        fprintf(stderr, "Is postmaster running?\nstarting postmaster anyway\n");
        do_start();
        return;
    }
    else if (pid < 0)            /* standalone backend, not postmaster */
    {
        pid = -pid;
        fprintf(stderr,
                "%s: cannot restart postmaster; "
                "postgres is running (PID: %ld)\n",
                progname, pid);
        fprintf(stderr, "Please terminate postgres and try again.\n");
        exit(1);
    }

    if (kill((pid_t) pid, sig) != 0)
        fprintf(stderr, "failed\n");

    if (!silence_echo)
    {
        printf("waiting for postmaster to shut down...");
        fflush(stdout);
    }

    /* always wait for restart */

    for (cnt = 0; cnt < wait_seconds; cnt++)
    {
        if ((pid = get_pgpid()) != 0)
        {
            if (!silence_echo)
            {
                printf(".");
                fflush(stdout);
            }
            pg_usleep(1000000); /* 1 sec */
        }
        else
            break;
    }

    if (pid != 0)                /* pid file still exists */
    {
        if (!silence_echo)
            printf(" failed\n");

        fprintf(stderr, "%s: postmaster does not shut down\n", progname);
        exit(1);
    }

    do_start();

}


static void
do_reload(void)
{
    long        pid;

    pid = get_pgpid();
    if (pid == 0)                /* no pid file */
    {
        fprintf(stderr, "%s: could not find %s\n", progname, pid_file);
        fprintf(stderr, "Is postmaster running?\n");
        exit(1);
    }
    else if (pid < 0)            /* standalone backend, not postmaster */
    {
        pid = -pid;
        fprintf(stderr,
                "%s: cannot reload postmaster; "
                "postgres is running (PID: %ld)\n",
                progname, pid);
        fprintf(stderr, "Please terminate postgres and try again.\n");
        exit(1);
    }

    if (kill((pid_t) pid, sig) != 0)
        fprintf(stderr, "failed\n");

    if (!silence_echo)
        fprintf(stdout, "postmaster signaled successfully\n");
}

/*
 *    utility routines
 */

static void
do_status(void)
{
    long        pid;

    pid = get_pgpid();
    if (pid == 0)                /* no pid file */
    {
        fprintf(stderr, "%s: postmaster or postgres not running", progname);
        exit(1);
    }
    else if (pid < 0)            /* standalone backend */
    {
        pid = -pid;
        fprintf(stdout, "%s: a standalone backend \"postgres\" is running (PID: %ld)", progname, pid);
    }
    else                        /* postmaster */
    {
        char      **optlines;

        fprintf(stdout, "%s: postmaster is running (PID: %ld)", progname, pid);

        optlines = readfile(postopts_file);
        if (optlines != NULL)
            for (; *optlines != NULL; optlines++)
                fputs(*optlines, stdout);
    }
}



static void
do_kill(void)
{
    if (kill(killproc, sig) != 0)
        fprintf(stderr, "failed\n");
}



static void
do_advice(void)
{
    fprintf(stderr, "\nTry \"%s --help\" for more information.\n", progname);
}



static char *helplines[] =
{
    "%s is a utility to start, stop, restart, reload configuration files,\n",
    "report the status of a PostgreSQL server, or kill a PostgreSQL process\n\n",
    "Usage:\n",
    "  %s start   [-w] [-D DATADIR] [-s] [-l FILENAME] [-o \"OPTIONS\"]\n",
    "  %s stop    [-W] [-D DATADIR] [-s] [-m SHUTDOWN-MODE]\n",
    "  %s restart [-w] [-D DATADIR] [-s] [-m SHUTDOWN-MODE] [-o \"OPTIONS\"]\n",
    "  %s reload  [-D DATADIR] [-s]\n",
    "  %s status  [-D DATADIR]\n",
    "  %s kill    SIGNALNAME PROCESSID\n",
    "Common options:\n",
    "  -D DATADIR   location of the database storage area\n",
    "  -s           only print errors, no informational messages\n",
    "  -w           wait until operation completes\n",
    "  -W           do not wait until operation completes\n",
    "  --help       show this help, then exit\n",
    "  --version    output version information, then exit\n",
    "(The default is to wait for shutdown, but not for start or restart.)\n\n",
    "If the -D option is omitted, the environment variable PGDATA is used.\n\n",
    "Options for start or restart:\n",
    "  -l FILENAME             write (or append) server log to FILENAME.  The\n",
    "                          use of this option is highly recommended.\n",
    "  -o OPTIONS              command line options to pass to the postmaster\n",
    "                          (PostgreSQL server executable)\n",
    "  -p PATH-TO-POSTMASTER   normally not necessary\n\n",
    "Options for stop or restart:\n",
    "  -m SHUTDOWN-MODE   may be 'smart', 'fast', or 'immediate'\n\n",
    "Allowed signal names for kill:\n",
    "  -HUP -INT -QUIT -ABRT -TERM -USR1 -USR2\n\n",
    "Shutdown modes are:\n",
    "  smart       quit after all clients have disconnected\n",
    "  fast        quit directly, with proper shutdown\n",
    "  immediate   quit without complete shutdown; will lead to recovery on restart\n\n",
    "Report bugs to <pgsql-bugs@postgresql.org>.\n",
    NULL
};



static void
do_help(void)
{
    char      **line;

    for (line = helplines; *line; line++)
        /* assuming we can use gettext this way */
        printf(_(*line), progname);
}



static void
set_mode(char *modeopt)
{
    if (strcmp(modeopt, "s") == 0 || strcmp(modeopt, "smart") == 0)
    {
        shutdown_mode = SMART_MODE;
        sig = SIGTERM;
    }
    else if (strcmp(modeopt, "f") == 0 || strcmp(modeopt, "fast") == 0)
    {
        shutdown_mode = FAST_MODE;
        sig = SIGINT;
    }
    else if (strcmp(modeopt, "i") == 0 || strcmp(modeopt, "immediate") == 0)
    {
        shutdown_mode = IMMEDIATE_MODE;
        sig = SIGQUIT;
    }
    else
    {
        fprintf(stderr, "%s: invalid shutdown mode %s\n", progname, modeopt);
        do_advice();
        exit(1);
    }
}



static void
set_sig(char *signame)
{
    if (!strcmp(signame, "-HUP"))
        sig = SIGHUP;
    else if (!strcmp(signame, "-INT"))
        sig = SIGINT;
    else if (!strcmp(signame, "-QUIT"))
        sig = SIGQUIT;
    else if (!strcmp(signame, "-ABRT"))
        sig = SIGABRT;

    /*
     * probably should NOT provide SIGKILL
     *
     * else if (!strcmp(signame,"-KILL")) sig = SIGKILL;
     */
    else if (!strcmp(signame, "-TERM"))
        sig = SIGTERM;
    else if (!strcmp(signame, "-USR1"))
        sig = SIGUSR1;
    else if (!strcmp(signame, "-USR2"))
        sig = SIGUSR2;
    else
    {
        fprintf(stderr, "%s: invalid signal \"%s\"\n", progname, signame);
        do_advice();
        exit(1);
    }

}



int
main(int argc, char **argv)
{
    int            i;

#ifdef WIN32
    setvbuf(stderr, NULL, _IONBF, 0);
#endif

    progname = get_progname(argv[0]);

    /*
     * save argv[0] so do_start() can look for the postmaster if
     * necessary. we don't look for postmaster here because in many cases
     * we won't need it.
     */
    argv0 = argv[0];

    umask(077);

    for (i = 0; i < argc; i++)
    {
        char       *arg = argv[i];

        if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0 ||
            strcmp(arg, "-?") == 0)
        {
            do_help();
            exit(0);
        }
        else if (strcmp(arg, "-V") == 0 || strcmp(arg, "--version") == 0)
        {
            printf("pg_ctl (PostgreSQL) %s\n", PG_VERSION);
            exit(0);
        }
        else if (strcmp(arg, "-D") == 0 && i < argc - 1)
        {
            int            len = strlen(arg) + 4;
            char       *env_var;

            i++;
            arg = argv[i];

            pg_data_opts = xmalloc(len);
            snprintf(pg_data_opts, len, "-D %s", arg);
            env_var = xmalloc(len + sizeof("PGDATA="));
            snprintf(env_var, len + sizeof("PGDATA="), "PGDATA=%s", arg);
            putenv(env_var);
        }
        else if (strcmp(arg, "-l") == 0 && i < argc - 1)
        {
            i++;
            arg = argv[i];
            log_file = xstrdup(arg);
        }
        else if (strncmp(arg, "-l", 2) == 0 && strlen(arg) > 2)
            log_file = xstrdup(arg + 2);
        else if (strcmp(arg, "-m") == 0 && i < argc - 1)
        {
            i++;
            arg = argv[i];
            set_mode(arg);
        }
        else if (strncmp(arg, "-m", 2) == 0 && strlen(arg) > 2)
            set_mode(arg + 2);
        else if (strcmp(arg, "-o") == 0 && i < argc - 1)
        {
            i++;
            arg = argv[i];
            post_opts = xstrdup(arg);
        }
        else if (strcmp(arg, "-p") == 0 && i < argc - 1)
        {
            i++;
            arg = argv[i];
            postgres_path = xstrdup(arg);
        }
        else if (strcmp(arg, "-s") == 0)
            silence_echo = true;
        else if (strcmp(arg, "-w") == 0)
        {
            do_wait = true;
            wait_set = true;
        }
        else if (strcmp(arg, "-W") == 0)
        {
            do_wait = false;
            wait_set = true;
        }
        else if (arg[0] == '-')
        {
            fprintf(stderr, "%s: invalid option %s\n", progname, arg);
            do_advice();
            exit(1);
        }
        else if (strcmp(arg, "start") == 0 && ctl_command == NO_COMMAND)
            ctl_command = START_COMMAND;
        else if (strcmp(arg, "stop") == 0 && ctl_command == NO_COMMAND)
            ctl_command = STOP_COMMAND;
        else if (strcmp(arg, "restart") == 0 && ctl_command == NO_COMMAND)
            ctl_command = RESTART_COMMAND;
        else if (strcmp(arg, "reload") == 0 && ctl_command == NO_COMMAND)
            ctl_command = RELOAD_COMMAND;
        else if (strcmp(arg, "status") == 0 && ctl_command == NO_COMMAND)
            ctl_command = STATUS_COMMAND;
        else if (i == 0 && argc >= 3 && strcmp(arg, "kill") == 0)
        {
            /* stricter syntax for kill command */
            ctl_command = KILL_COMMAND;
            set_sig(argv[1]);
            killproc = atol(argv[2]);
            i += 2;
        }
        else if (arg[0] == '-')
        {
            fprintf(stderr, "%s: invalid operation mode %s\n", progname, arg);
            do_advice();
            exit(1);
        }
    }

    if (ctl_command == NO_COMMAND)
    {
        fprintf(stderr, "%s: no operation specified\n", progname);
        do_advice();
        exit(1);
    }

    pg_data = getenv("PGDATA");
    canonicalize_path(pg_data);

    if (pg_data == NULL && ctl_command != KILL_COMMAND)
    {
        fprintf(stderr,
                "%s: no database directory specified "
                "and environment variable PGDATA unset\n",
                progname);
        do_advice();
        exit(1);
    }

    if (!wait_set)
    {
        switch (ctl_command)
        {
            case RESTART_COMMAND:
            case START_COMMAND:
                do_wait = false;
                break;
            case STOP_COMMAND:
                do_wait = true;
                break;
            default:
                break;
        }
    }

    if (ctl_command == RELOAD_COMMAND)
    {
        sig = SIGHUP;
        do_wait = false;
    }

    snprintf(def_postopts_file, MAXPGPATH, "%s/postmaster.opts.default", pg_data);
    snprintf(postopts_file, MAXPGPATH, "%s/postmaster.opts", pg_data);
    snprintf(pid_file, MAXPGPATH, "%s/postmaster.pid", pg_data);
    snprintf(conf_file, MAXPGPATH, "%s/postgresql.conf", pg_data);

    switch (ctl_command)
    {
        case STATUS_COMMAND:
            do_status();
            break;
        case START_COMMAND:
            do_start();
            break;
        case STOP_COMMAND:
            do_stop();
            break;
        case RESTART_COMMAND:
            do_restart();
            break;
        case RELOAD_COMMAND:
            do_reload();
            break;
        case KILL_COMMAND:
            do_kill();
            break;
        default:
            break;
    }

    exit(0);
}
#-------------------------------------------------------------------------
#
# Makefile for src/bin/pg_ctl
#
# Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
# Portions Copyright (c) 1994, Regents of the University of California
#
# $PostgreSQL: pgsql-server/src/bin/pg_ctl/Makefile,v 1.41 2004/05/24 01:01:37 momjian Exp $
#
#-------------------------------------------------------------------------

subdir = src/bin/pg_ctl
top_builddir = ../../..
include $(top_builddir)/src/Makefile.global

override CPPFLAGS := -DFRONTEND -DDEF_PGPORT=$(DEF_PGPORT) -I$(libpq_srcdir) $(CPPFLAGS)

OBJS=    pg_ctl.o exec.o

all: submake-libpq submake-libpgport pg_ctl

pg_ctl: $(OBJS) $(libpq_builddir)/libpq.a
    $(CC) $(CFLAGS) $(OBJS) $(libpq) $(LDFLAGS) $(LIBS) -o $@$(X)

exec.c: % : $(top_srcdir)/src/port/%
    rm -f $@ && $(LN_S) $< .

install: all installdirs
    $(INSTALL_PROGRAM) pg_ctl$(X) $(DESTDIR)$(bindir)/pg_ctl$(X)

installdirs:
    $(mkinstalldirs) $(DESTDIR)$(bindir)

uninstall:
    rm -f $(DESTDIR)$(bindir)/pg_ctl$(X)

clean distclean maintainer-clean:
    rm -f pg_ctl$(X) $(OBJS) exec.c


# ensure that changes in DEF_PGPORT propagate into object file
pg_ctl.o: pg_ctl.c $(top_builddir)/src/Makefile.global

Re: pg_ctl.c

From
Gaetano Mendola
Date:
Bruce Momjian wrote:

> Here is the C version of pg_ctl.c written by Andrew Dunstan and updated
> by me.
>
> You can use it by creating a src/bin/pg_ctl_test directory and putting
> the C and Makefile into that directory.  You can then do a make install
> and use it for testing.
>
> Unless someone finds a problem, I will apply the change soon.  This
> removes our last shell script!

It desn't compile on my platform:

$ gcc -I /usr/include/pgsql/server pg_ctl.c
pg_ctl.c: In function `start_postmaster':
pg_ctl.c:219: error: `DEVNULL' undeclared (first use in this function)
pg_ctl.c:219: error: (Each undeclared identifier is reported only once
pg_ctl.c:219: error: for each function it appears in.)


however below the result of my quich review:

1) exit(1)  => exit(EXIT_FAILURE)
2) xstrdup protected by duplicate NULL string

I seen also that you don't use always the _ macro for error display.


Regards
Gaetano Mendola






*** pg_ctl.c    2004-05-26 02:48:38.000000000 +0200
--- pg_ctl.c.orig    2004-05-26 02:43:32.000000000 +0200
***************
*** 26,33 ****
   /* postmaster version ident string */
   #define PM_VERSIONSTR "postmaster (PostgreSQL) " PG_VERSION "\n"

- #define EXIT_FAILURE 1
-

   typedef enum
   {
--- 26,31 ----
***************
*** 100,106 ****
       if (!result)
       {
           fprintf(stderr, _("%s: out of memory\n"), progname);
!         exit(EXIT_FAILURE);
       }
       return result;
   }
--- 98,104 ----
       if (!result)
       {
           fprintf(stderr, _("%s: out of memory\n"), progname);
!         exit(1);
       }
       return result;
   }
***************
*** 112,130 ****
   {
       char       *result;

-
-     if (!s)
-     {
-         fprintf(stderr, "%s: can not duplicate null pointer", progname);
-         exit(EXIT_FAILURE);
-     }
-
-
       result = strdup(s);
       if (!result)
       {
           fprintf(stderr, _("%s: out of memory\n"), progname);
!         exit(EXIT_FAILURE);
       }
       return result;
   }
--- 110,120 ----
   {
       char       *result;

       result = strdup(s);
       if (!result)
       {
           fprintf(stderr, _("%s: out of memory\n"), progname);
!         exit(1);
       }
       return result;
   }
***************
*** 146,152 ****
           else
           {
               perror("openning pid file");
!             exit(EXIT_FAILURE);
           }
       }
       fscanf(pidf, "%ld", &pid);
--- 136,142 ----
           else
           {
               perror("openning pid file");
!             exit(1);
           }
       }
       fscanf(pidf, "%ld", &pid);
***************
*** 353,359 ****
               else
               {
                   fprintf(stderr, "%s: cannot read %s\n", progname, postopts_file);
!                 exit(EXIT_FAILURE);
               }
           }
           else if (optlines[0] == NULL || optlines[1] != NULL)
--- 343,349 ----
               else
               {
                   fprintf(stderr, "%s: cannot read %s\n", progname, postopts_file);
!                 exit(1);
               }
           }
           else if (optlines[0] == NULL || optlines[1] != NULL)
***************
*** 361,367 ****
               fprintf(stderr, "%s: option file %s must have exactly 1 line\n",
                       progname, ctl_command == RESTART_COMMAND ?
                       postopts_file : def_postopts_file);
!             exit(EXIT_FAILURE);
           }
           else
           {
--- 351,357 ----
               fprintf(stderr, "%s: option file %s must have exactly 1 line\n",
                       progname, ctl_command == RESTART_COMMAND ?
                       postopts_file : def_postopts_file);
!             exit(1);
           }
           else
           {
***************
*** 411,417 ****
                             "but was not the same version as \"%s\".\n"
                             "Check your installation.\n"),
                           progname, progname);
!             exit(EXIT_FAILURE);
           }
           postgres_path = postmaster_path;
       }
--- 401,407 ----
                             "but was not the same version as \"%s\".\n"
                             "Check your installation.\n"),
                           progname, progname);
!             exit(1);
           }
           postgres_path = postmaster_path;
       }
***************
*** 428,434 ****
                       "%s: cannot start postmaster\n"
                       "Examine the log output\n",
                       progname);
!             exit(EXIT_FAILURE);
           }
       }

--- 418,424 ----
                       "%s: cannot start postmaster\n"
                       "Examine the log output\n",
                       progname);
!             exit(1);
           }
       }

***************
*** 463,469 ****
       {
           fprintf(stderr, "%s: could not find %s\n", progname, pid_file);
           fprintf(stderr, "Is postmaster running?\n");
!         exit(EXIT_FAILURE);
       }
       else if (pid < 0)            /* standalone backend, not postmaster */
       {
--- 453,459 ----
       {
           fprintf(stderr, "%s: could not find %s\n", progname, pid_file);
           fprintf(stderr, "Is postmaster running?\n");
!         exit(1);
       }
       else if (pid < 0)            /* standalone backend, not postmaster */
       {
***************
*** 472,478 ****
                   "%s: cannot stop postmaster; "
                   "postgres is running (PID: %ld)\n",
                   progname, pid);
!         exit(EXIT_FAILURE);
       }

       if (kill((pid_t) pid, sig) != 0)
--- 462,468 ----
                   "%s: cannot stop postmaster; "
                   "postgres is running (PID: %ld)\n",
                   progname, pid);
!         exit(1);
       }

       if (kill((pid_t) pid, sig) != 0)
***************
*** 513,519 ****
                   printf(" failed\n");

               fprintf(stderr, "%s: postmaster does not shut down\n", progname);
!             exit(EXIT_FAILURE);
           }
       }
   }
--- 503,509 ----
                   printf(" failed\n");

               fprintf(stderr, "%s: postmaster does not shut down\n", progname);
!             exit(1);
           }
       }
   }
***************
*** 546,552 ****
                   "postgres is running (PID: %ld)\n",
                   progname, pid);
           fprintf(stderr, "Please terminate postgres and try again.\n");
!         exit(EXIT_FAILURE);
       }

       if (kill((pid_t) pid, sig) != 0)
--- 536,542 ----
                   "postgres is running (PID: %ld)\n",
                   progname, pid);
           fprintf(stderr, "Please terminate postgres and try again.\n");
!         exit(1);
       }

       if (kill((pid_t) pid, sig) != 0)
***************
*** 581,587 ****
               printf(" failed\n");

           fprintf(stderr, "%s: postmaster does not shut down\n", progname);
!         exit(EXIT_FAILURE);
       }

       do_start();
--- 571,577 ----
               printf(" failed\n");

           fprintf(stderr, "%s: postmaster does not shut down\n", progname);
!         exit(1);
       }

       do_start();
***************
*** 599,605 ****
       {
           fprintf(stderr, "%s: could not find %s\n", progname, pid_file);
           fprintf(stderr, "Is postmaster running?\n");
!         exit(EXIT_FAILURE);
       }
       else if (pid < 0)            /* standalone backend, not postmaster */
       {
--- 589,595 ----
       {
           fprintf(stderr, "%s: could not find %s\n", progname, pid_file);
           fprintf(stderr, "Is postmaster running?\n");
!         exit(1);
       }
       else if (pid < 0)            /* standalone backend, not postmaster */
       {
***************
*** 609,615 ****
                   "postgres is running (PID: %ld)\n",
                   progname, pid);
           fprintf(stderr, "Please terminate postgres and try again.\n");
!         exit(EXIT_FAILURE);
       }

       if (kill((pid_t) pid, sig) != 0)
--- 599,605 ----
                   "postgres is running (PID: %ld)\n",
                   progname, pid);
           fprintf(stderr, "Please terminate postgres and try again.\n");
!         exit(1);
       }

       if (kill((pid_t) pid, sig) != 0)
***************
*** 632,638 ****
       if (pid == 0)                /* no pid file */
       {
           fprintf(stderr, "%s: postmaster or postgres not running", progname);
!         exit(EXIT_FAILURE);
       }
       else if (pid < 0)            /* standalone backend */
       {
--- 622,628 ----
       if (pid == 0)                /* no pid file */
       {
           fprintf(stderr, "%s: postmaster or postgres not running", progname);
!         exit(1);
       }
       else if (pid < 0)            /* standalone backend */
       {
***************
*** 745,751 ****
       {
           fprintf(stderr, "%s: invalid shutdown mode %s\n", progname, modeopt);
           do_advice();
!         exit(EXIT_FAILURE);
       }
   }

--- 735,741 ----
       {
           fprintf(stderr, "%s: invalid shutdown mode %s\n", progname, modeopt);
           do_advice();
!         exit(1);
       }
   }

***************
*** 778,784 ****
       {
           fprintf(stderr, "%s: invalid signal \"%s\"\n", progname, signame);
           do_advice();
!         exit(EXIT_FAILURE);
       }

   }
--- 768,774 ----
       {
           fprintf(stderr, "%s: invalid signal \"%s\"\n", progname, signame);
           do_advice();
!         exit(1);
       }

   }
***************
*** 878,884 ****
           {
               fprintf(stderr, "%s: invalid option %s\n", progname, arg);
               do_advice();
!             exit(EXIT_FAILURE);
           }
           else if (strcmp(arg, "start") == 0 && ctl_command == NO_COMMAND)
               ctl_command = START_COMMAND;
--- 868,874 ----
           {
               fprintf(stderr, "%s: invalid option %s\n", progname, arg);
               do_advice();
!             exit(1);
           }
           else if (strcmp(arg, "start") == 0 && ctl_command == NO_COMMAND)
               ctl_command = START_COMMAND;
***************
*** 902,908 ****
           {
               fprintf(stderr, "%s: invalid operation mode %s\n", progname, arg);
               do_advice();
!             exit(EXIT_FAILURE);
           }
       }

--- 892,898 ----
           {
               fprintf(stderr, "%s: invalid operation mode %s\n", progname, arg);
               do_advice();
!             exit(1);
           }
       }

***************
*** 910,916 ****
       {
           fprintf(stderr, "%s: no operation specified\n", progname);
           do_advice();
!         exit(EXIT_FAILURE);
       }

       pg_data = getenv("PGDATA");
--- 900,906 ----
       {
           fprintf(stderr, "%s: no operation specified\n", progname);
           do_advice();
!         exit(1);
       }

       pg_data = getenv("PGDATA");
***************
*** 923,929 ****
                   "and environment variable PGDATA unset\n",
                   progname);
           do_advice();
!         exit(EXIT_FAILURE);
       }

       if (!wait_set)
--- 913,919 ----
                   "and environment variable PGDATA unset\n",
                   progname);
           do_advice();
!         exit(1);
       }

       if (!wait_set)




Re: pg_ctl.c

From
Andrew Dunstan
Date:
Gaetano Mendola wrote:

> Bruce Momjian wrote:
>
>> Here is the C version of pg_ctl.c written by Andrew Dunstan and updated
>> by me.
>>
>> You can use it by creating a src/bin/pg_ctl_test directory and putting
>> the C and Makefile into that directory.  You can then do a make install
>> and use it for testing.
>>
>> Unless someone finds a problem, I will apply the change soon.  This
>> removes our last shell script!
>
>
> It desn't compile on my platform:
>
> $ gcc -I /usr/include/pgsql/server pg_ctl.c
> pg_ctl.c: In function `start_postmaster':
> pg_ctl.c:219: error: `DEVNULL' undeclared (first use in this function)
> pg_ctl.c:219: error: (Each undeclared identifier is reported only once
> pg_ctl.c:219: error: for each function it appears in.)


It does not appear that you have followed Bruce's instructions above for
testing this. It works just fine for me:

[andrew@marmaduke pg_ctl_x]$ make
make -C ../../../src/interfaces/libpq all
make[1]: Entering directory `/home/andrew/pgwnew/pgsql/src/interfaces/libpq'
make[1]: Nothing to be done for `all'.
make[1]: Leaving directory `/home/andrew/pgwnew/pgsql/src/interfaces/libpq'
make -C ../../../src/port all
make[1]: Entering directory `/home/andrew/pgwnew/pgsql/src/port'
make[1]: Nothing to be done for `all'.
make[1]: Leaving directory `/home/andrew/pgwnew/pgsql/src/port'
gcc -O2 -fno-strict-aliasing -Wall -Wmissing-prototypes
-Wmissing-declarations -DFRONTEND -DDEF_PGPORT=5432
-I../../../src/interfaces/libpq -I../../../src/include -D_GNU_SOURCE
-c -o pg_ctl.o pg_ctl.c
rm -f exec.c && ln -s ../../../src/port/exec.c .
gcc -O2 -fno-strict-aliasing -Wall -Wmissing-prototypes
-Wmissing-declarations -DFRONTEND -DDEF_PGPORT=5432
-I../../../src/interfaces/libpq -I../../../src/include -D_GNU_SOURCE
-c -o exec.o exec.c
gcc -O2 -fno-strict-aliasing -Wall -Wmissing-prototypes
-Wmissing-declarations pg_ctl.o exec.o -L../../../src/interfaces/libpq
-lpq -L../../../src/port  -Wl,-rpath,/usr/local/pgsql/lib -lz -lreadline
-ltermcap -lcrypt -lresolv -lnsl -ldl -lm -lbsd  -lpgport -o pg_ctl
[andrew@marmaduke pg_ctl_x]$


What version of the pg include files is in /usr/include/pgsql/server ?
If <= 7.4 then of course DEVNULL will not be defined.

>
>
> however below the result of my quich review:
>
> 1) exit(1)  => exit(EXIT_FAILURE)


If we used a number of different error codes I might agree. But it seems
pointless here, and the style is widely used in our code base (I just
counted 201 other occurrrences, not including cases of exit(0) ).

> 2) xstrdup protected by duplicate NULL string


I don't object, but it is redundant - in every case where it is called
the argument is demonstrably not NULL.

>
> I seen also that you don't use always the _ macro for error display.
>

True - that's part of the polish needed.

BTW, please don't send reverse diffs, they are a pain to read, IMNSHO
(i.e. you should do diff -c file.c.orig file.c instead of having the
files the other way around).

There is one small thing that is wrong with it - an incorrect format
argument. see patch below.

cheers

andrew

*** pg_ctl.c.orig       2004-05-26 10:27:20.000000000 -0400
--- pg_ctl.c    2004-05-26 10:28:34.000000000 -0400
***************
*** 237,243 ****
        *portstr = '\0';

        if (getenv("PGPORT") != NULL)   /* environment */
!               snprintf(portstr, sizeof(portstr), "%d", getenv("PGPORT"));
        else    /* post_opts */
        {
                char    *p;
--- 237,243 ----
        *portstr = '\0';

        if (getenv("PGPORT") != NULL)   /* environment */
!               snprintf(portstr, sizeof(portstr), "%s", getenv("PGPORT"));
        else    /* post_opts */
        {
                char    *p;


Re: pg_ctl.c

From
Bruce Momjian
Date:
OK, here is a new version with lots of fixes.

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073
/*-------------------------------------------------------------------------
 *
 * pg_ctl --- start/stops/restarts the PostgreSQL server
 *
 * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
 *
 * $PostgreSQL: pgsql-server/src/bin/initdb/initdb.c,v 1.32 2004/05/18 03:36:36 momjian Exp $
 *
 *-------------------------------------------------------------------------
 */

#include "postgres_fe.h"
#include "libpq-fe.h"

#include <signal.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>

#include "libpq/pqsignal.h"
#include "getopt_long.h"

#ifndef HAVE_OPTRESET
int            optreset;
#endif


#define _(x) gettext((x))

#define WHITESPACE "\f\n\r\t\v"        /* as defined by isspace() */

/* postmaster version ident string */
#define PM_VERSIONSTR "postmaster (PostgreSQL) " PG_VERSION "\n"


typedef enum
{
    SMART_MODE,
    FAST_MODE,
    IMMEDIATE_MODE
}    ShutdownMode;


typedef enum
{
    NO_COMMAND = 0,
    START_COMMAND,
    STOP_COMMAND,
    RESTART_COMMAND,
    RELOAD_COMMAND,
    STATUS_COMMAND,
    KILL_COMMAND
}    CtlCommand;


static bool do_wait = false;
static bool wait_set = false;
static int    wait_seconds = 60;
static bool silence_echo = false;
static ShutdownMode shutdown_mode = SMART_MODE;
static int    sig = SIGTERM;    /* default */
static int    killproc;
static CtlCommand ctl_command = NO_COMMAND;
static char *pg_data_opts = NULL;
static char *pg_data = NULL;
static char *post_opts = NULL;
static const char *progname;
static char *log_file = NULL;
static char *postgres_path = NULL;
static char *argv0 = NULL;

static void *xmalloc(size_t size);
static char *xstrdup(const char *s);
static void do_advice(void);
static void do_help(void);
static void set_mode(char *modeopt);
static void set_sig(char *signame);
static void do_start();
static void do_stop(void);
static void do_restart(void);
static void do_reload(void);
static void do_status(void);
static void do_kill(void);
static long get_pgpid(void);
static char **readfile(char *path);
static int start_postmaster(void);
static bool test_postmaster_connection(void);

static char def_postopts_file[MAXPGPATH];
static char postopts_file[MAXPGPATH];
static char pid_file[MAXPGPATH];
static char conf_file[MAXPGPATH];

/*
 * routines to check memory allocations and fail noisily.
 */

static void *
xmalloc(size_t size)
{
    void       *result;

    result = malloc(size);
    if (!result)
    {
        fprintf(stderr, _("%s: out of memory\n"), progname);
        exit(1);
    }
    return result;
}



static char *
xstrdup(const char *s)
{
    char       *result;

    result = strdup(s);
    if (!result)
    {
        fprintf(stderr, _("%s: out of memory\n"), progname);
        exit(1);
    }
    return result;
}



static long
get_pgpid(void)
{
    FILE       *pidf;
    long        pid;

    pidf = fopen(pid_file, "r");
    if (pidf == NULL)
    {
        /* No pid file, not an error on startup */
        if (errno == ENOENT)
            return 0;
        else
        {
            perror("openning pid file");
            exit(1);
        }
    }
    fscanf(pidf, "%ld", &pid);
    fclose(pidf);
    return pid;
}


/*
 * get the lines from a text file - return NULL if file can't be opened
 */
static char **
readfile(char *path)
{
    FILE       *infile;
    int            maxlength = 0,
                linelen = 0;
    int            nlines = 0;
    char      **result;
    char       *buffer;
    int            c;

    if ((infile = fopen(path, "r")) == NULL)
        return NULL;

    /* pass over the file twice - the first time to size the result */

    while ((c = fgetc(infile)) != EOF)
    {
        linelen++;
        if (c == '\n')
        {
            nlines++;
            if (linelen > maxlength)
                maxlength = linelen;
            linelen = 0;
        }
    }

    /* handle last line without a terminating newline (yuck) */
    if (linelen)
        nlines++;
    if (linelen > maxlength)
        maxlength = linelen;

    /* set up the result and the line buffer */

    result = (char **) xmalloc((nlines + 1) * sizeof(char *));
    buffer = (char *) xmalloc(maxlength + 1);

    /* now reprocess the file and store the lines */
    rewind(infile);
    nlines = 0;
    while (fgets(buffer, maxlength + 1, infile) != NULL)
        result[nlines++] = xstrdup(buffer);

    fclose(infile);
    result[nlines] = NULL;

    return result;
}



/*
 * start/test/stop routines
 */

static int
start_postmaster(void)
{
    /*
     * Since there might be quotes to handle here, it is easier simply
     * to pass everything to a shell to process them.
     */
    char        cmd[MAXPGPATH];

    /* Does '&' work on Win32? */
    if (log_file != NULL)
        snprintf(cmd, MAXPGPATH, "\"%s\" %s < %s >>\"%s\" 2>&1 &",
                 postgres_path, post_opts, DEVNULL, log_file);
    else
        snprintf(cmd, MAXPGPATH, "\"%s\" %s < %s 2>&1 &",
                 postgres_path, post_opts, DEVNULL);
    return system(cmd);
}



/* Find the pgport and try a connection */
static bool
test_postmaster_connection(void)
{
    PGconn       *conn;
    bool        success = false;
    int            i;
    char        portstr[32];
    char         *p;


    *portstr = '\0';

    /* post_opts */
    for (p = post_opts; *p;)
    {
        /* advance past whitespace/quoting */
        while (isspace(*p) || *p == '\'' || *p == '"')
            p++;

        if (strncmp(p, "-p", strlen("-p")) == 0)
        {
            p += strlen("-p");
            /* advance past whitespace/quoting */
            while (isspace(*p) || *p == '\'' || *p == '"')
                p++;
            StrNCpy(portstr, p, Min(strcspn(p, "\"'"WHITESPACE) + 1,
                                    sizeof(portstr)));
            /* keep looking, maybe there is another -p */
        }
        /* Advance to next whitespace */
        while (!isspace(*p))
            p++;
    }

    /* config file */
    if (!*portstr)
    {
        char      **optlines;

        optlines = readfile(conf_file);
        if (optlines != NULL)
        {
            for (;*optlines != NULL; optlines++)
            {
                p = *optlines;

                while (isspace(*p))
                    p++;
                if (strncmp(p, "port", strlen("port")) != 0)
                    continue;
                p += strlen("port");
                while (isspace(*p))
                    p++;
                if (*p != '=')
                    continue;
                p++;
                while (isspace(*p))
                    p++;
                StrNCpy(portstr, p, Min(strcspn(p, "#"WHITESPACE) + 1,
                                        sizeof(portstr)));
                /* keep looking, maybe there is another */
            }
        }
    }

    /* environment */
    if (!*portstr && getenv("PGPORT") != NULL)
        StrNCpy(portstr, getenv("PGPORT"), sizeof(portstr));

    /* default */
    if (!*portstr)
        snprintf(portstr, sizeof(portstr), "%d", DEF_PGPORT);

    for (i = 0; i < wait_seconds; i++)
    {
        if ((conn = PQsetdbLogin(NULL, portstr, NULL, NULL, "template1", NULL, NULL)) != NULL)
        {
            PQfinish(conn);
            success = true;
            break;
        }
    }

    return success;
}



static void
do_start(void)
{
    long        pid;
    long        old_pid = 0;
    char       *optline = NULL;

    if (ctl_command != RESTART_COMMAND)
    {
        old_pid = get_pgpid();
        if (old_pid != 0)
            fprintf(stderr,
                    _("%s: Another postmaster may be running. "
                    "Trying to start postmaster anyway.\n"),
                    progname);
    }

    if (post_opts == NULL)
    {
        char      **optlines;
        int            len;

        optlines = readfile(ctl_command == RESTART_COMMAND ?
                            postopts_file : def_postopts_file);
        if (optlines == NULL)
        {
            if (ctl_command == START_COMMAND)
                post_opts = "";
            else
            {
                fprintf(stderr, _("%s: cannot read %s\n"), progname, postopts_file);
                exit(1);
            }
        }
        else if (optlines[0] == NULL || optlines[1] != NULL)
        {
            fprintf(stderr, _("%s: option file %s must have exactly 1 line\n"),
                    progname, ctl_command == RESTART_COMMAND ?
                    postopts_file : def_postopts_file);
            exit(1);
        }
        else
        {
            optline = optlines[0];
            len = strcspn(optline, "\r\n");
            optline[len] = '\0';

            if (ctl_command == RESTART_COMMAND)
            {
                char       *arg1;

                arg1 = strchr(optline, '\'');
                if (arg1 == NULL || arg1 == optline)
                    post_opts = "";
                else
                {
                    *(arg1 - 1) = '\0';    /* this should be a space */
                    post_opts = arg1;
                }
                if (postgres_path != NULL)
                    postgres_path = optline;
            }
            else
                post_opts = optline;
        }
    }

    if (postgres_path == NULL)
    {
        char       *postmaster_path;
        int            ret;

        postmaster_path = xmalloc(MAXPGPATH);

        if ((ret = find_other_exec(argv0, "postmaster", PM_VERSIONSTR,
                                   postmaster_path)) < 0)
        {
            if (ret == -1)
                fprintf(stderr,
                        _("The program \"postmaster\" is needed by %s "
                   "but was not found in the same directory as \"%s\".\n"
                          "Check your installation.\n"),
                        progname, progname);
            else
                fprintf(stderr,
                        _("The program \"postmaster\" was found by %s "
                          "but was not the same version as \"%s\".\n"
                          "Check your installation.\n"),
                        progname, progname);
            exit(1);
        }
        postgres_path = postmaster_path;
    }

    if (start_postmaster() != 0)
    {
        fprintf(stderr, _("Unable to run the postmaster binary\n"));
        exit(1);
    }

    if (old_pid != 0)
    {
        pg_usleep(1000000);
        pid = get_pgpid();
        if (pid == old_pid)
        {
            fprintf(stderr,
                    _("%s: cannot start postmaster\n"
                    "Examine the log output\n"),
                    progname);
            exit(1);
        }
    }

    if (do_wait)
    {
        if (!silence_echo)
        {
            printf(_("waiting for postmaster to start..."));
            fflush(stdout);
        }

        if (test_postmaster_connection() == false)
            printf(_("could not start postmaster\n"));
        else if (!silence_echo)
            printf(_("done\npostmaster started\n"));
    }
    else if (!silence_echo)
        printf(_("postmaster starting\n"));
}



static void
do_stop(void)
{
    int            cnt;
    long        pid;

    pid = get_pgpid();

    if (pid == 0)                /* no pid file */
    {
        fprintf(stderr, _("%s: could not find %s\n"), progname, pid_file);
        fprintf(stderr, _("Is postmaster running?\n"));
        exit(1);
    }
    else if (pid < 0)            /* standalone backend, not postmaster */
    {
        pid = -pid;
        fprintf(stderr,
                _("%s: cannot stop postmaster; "
                "postgres is running (PID: %ld)\n"),
                progname, pid);
        exit(1);
    }

    if (kill((pid_t) pid, sig) != 0)
    {
        fprintf(stderr, _("stop signal failed\n"));
        exit(1);
    }

    if (!do_wait)
    {
        if (!silence_echo)
            printf(_("postmaster shutting down\n"));
        return;
    }
    else
    {
        if (!silence_echo)
        {
            printf(_("waiting for postmaster to shut down..."));
            fflush(stdout);
        }

        for (cnt = 0; cnt < wait_seconds; cnt++)
        {
            if ((pid = get_pgpid()) != 0)
            {
                if (!silence_echo)
                {
                    printf(".");
                    fflush(stdout);
                }
                pg_usleep(1000000); /* 1 sec */
            }
            else
                break;
        }

        if (pid != 0)                /* pid file still exists */
        {
            if (!silence_echo)
                printf(_(" failed\n"));

            fprintf(stderr, _("%s: postmaster does not shut down\n"), progname);
            exit(1);
        }
        printf(_("done\npostmaster stopped\n"));
    }
}


/*
 *    restart/reload routines
 */

static void
do_restart(void)
{
    int            cnt;
    long        pid;

    pid = get_pgpid();

    if (pid == 0)                /* no pid file */
    {
        fprintf(stderr, _("%s: could not find %s\n"), progname, pid_file);
        fprintf(stderr, _("Is postmaster running?\nstarting postmaster anyway\n"));
        do_start();
        return;
    }
    else if (pid < 0)            /* standalone backend, not postmaster */
    {
        pid = -pid;
        fprintf(stderr,
                _("%s: cannot restart postmaster; "
                "postgres is running (PID: %ld)\n"),
                progname, pid);
        fprintf(stderr, _("Please terminate postgres and try again.\n"));
        exit(1);
    }

    if (kill((pid_t) pid, sig) != 0)
    {
        fprintf(stderr, _("stop signal failed\n"));
        exit(1);
    }

    if (!silence_echo)
    {
        printf(_("waiting for postmaster to shut down..."));
        fflush(stdout);
    }

    /* always wait for restart */

    for (cnt = 0; cnt < wait_seconds; cnt++)
    {
        if ((pid = get_pgpid()) != 0)
        {
            if (!silence_echo)
            {
                printf(".");
                fflush(stdout);
            }
            pg_usleep(1000000); /* 1 sec */
        }
        else
            break;
    }

    if (pid != 0)                /* pid file still exists */
    {
        if (!silence_echo)
            printf(_(" failed\n"));

        fprintf(stderr, _("%s: postmaster does not shut down\n"), progname);
        exit(1);
    }

    printf(_("done\npostmaster stopped\n"));
    do_start();
}


static void
do_reload(void)
{
    long        pid;

    pid = get_pgpid();
    if (pid == 0)                /* no pid file */
    {
        fprintf(stderr, _("%s: could not find %s\n"), progname, pid_file);
        fprintf(stderr, _("Is postmaster running?\n"));
        exit(1);
    }
    else if (pid < 0)            /* standalone backend, not postmaster */
    {
        pid = -pid;
        fprintf(stderr,
                _("%s: cannot reload postmaster; "
                "postgres is running (PID: %ld)\n"),
                progname, pid);
        fprintf(stderr, _("Please terminate postgres and try again.\n"));
        exit(1);
    }

    if (kill((pid_t) pid, sig) != 0)
    {
        fprintf(stderr, _("reload signal failed\n"));
        exit(1);
    }

    if (!silence_echo)
        fprintf(stdout, _("postmaster signaled\n"));
}

/*
 *    utility routines
 */

static void
do_status(void)
{
    long        pid;

    pid = get_pgpid();
    if (pid == 0)                /* no pid file */
    {
        fprintf(stderr, _("%s: postmaster or postgres not running\n"), progname);
        exit(1);
    }
    else if (pid < 0)            /* standalone backend */
    {
        pid = -pid;
        fprintf(stdout, _("%s: a standalone backend \"postgres\" is running (PID: %ld)\n"), progname, pid);
    }
    else                        /* postmaster */
    {
        char      **optlines;

        fprintf(stdout, _("%s: postmaster is running (PID: %ld)\n"), progname, pid);

        optlines = readfile(postopts_file);
        if (optlines != NULL)
            for (; *optlines != NULL; optlines++)
                fputs(*optlines, stdout);
    }
}



static void
do_kill(void)
{
    if (kill(killproc, sig) != 0)
    {
        fprintf(stderr, _("signal %d failed\n"), sig);
        exit(1);
    }
}



static void
do_advice(void)
{
    fprintf(stderr, _("\nTry \"%s --help\" for more information.\n"), progname);
}



static void
do_help(void)
{
    printf(_("%s is a utility to start, stop, restart, reload configuration files,\n"), progname);
    printf(_("report the status of a PostgreSQL server, or kill a PostgreSQL process\n\n"));
    printf(_("Usage:\n"));
    printf(_("  %s start   [-w] [-D DATADIR] [-s] [-l FILENAME] [-o \"OPTIONS\"]\n"), progname);
    printf(_("  %s stop    [-W] [-D DATADIR] [-s] [-m SHUTDOWN-MODE]\n"), progname);
    printf(_("  %s restart [-w] [-D DATADIR] [-s] [-m SHUTDOWN-MODE] [-o \"OPTIONS\"]\n"), progname);
    printf(_("  %s reload  [-D DATADIR] [-s]\n"), progname);
    printf(_("  %s status  [-D DATADIR]\n"), progname);
    printf(_("  %s kill    SIGNALNAME PROCESSID\n"), progname);
    printf(_("Common options:\n"));
    printf(_("  -D, --pgdata DATADIR   location of the database storage area\n"));
    printf(_("  -s, --silent only print errors, no informational messages\n"));
    printf(_("  -w           wait until operation completes\n"));
    printf(_("  -W           do not wait until operation completes\n"));
    printf(_("  --help       show this help, then exit\n"));
    printf(_("  --version    output version information, then exit\n"));
    printf(_("(The default is to wait for shutdown, but not for start or restart.)\n\n"));
    printf(_("If the -D option is omitted, the environment variable PGDATA is used.\n\n"));
    printf(_("Options for start or restart:\n"));
    printf(_("  -l, --log FILENAME      write (or append) server log to FILENAME.  The\n"));
    printf(_("                          use of this option is highly recommended.\n"));
    printf(_("  -o OPTIONS              command line options to pass to the postmaster\n"));
    printf(_("                          (PostgreSQL server executable)\n"));
    printf(_("  -p PATH-TO-POSTMASTER   normally not necessary\n\n"));
    printf(_("Options for stop or restart:\n"));
    printf(_("  -m SHUTDOWN-MODE   may be 'smart', 'fast', or 'immediate'\n\n"));
    printf(_("Allowed signal names for kill:\n"));
    printf(_("  -HUP -INT -QUIT -ABRT -TERM -USR1 -USR2\n\n"));
    printf(_("Shutdown modes are:\n"));
    printf(_("  smart       quit after all clients have disconnected\n"));
    printf(_("  fast        quit directly, with proper shutdown\n"));
    printf(_("  immediate   quit without complete shutdown; will lead to recovery on restart\n\n"));
    printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
}



static void
set_mode(char *modeopt)
{
    if (strcmp(modeopt, "s") == 0 || strcmp(modeopt, "smart") == 0)
    {
        shutdown_mode = SMART_MODE;
        sig = SIGTERM;
    }
    else if (strcmp(modeopt, "f") == 0 || strcmp(modeopt, "fast") == 0)
    {
        shutdown_mode = FAST_MODE;
        sig = SIGINT;
    }
    else if (strcmp(modeopt, "i") == 0 || strcmp(modeopt, "immediate") == 0)
    {
        shutdown_mode = IMMEDIATE_MODE;
        sig = SIGQUIT;
    }
    else
    {
        fprintf(stderr, _("%s: invalid shutdown mode %s\n"), progname, modeopt);
        do_advice();
        exit(1);
    }
}



static void
set_sig(char *signame)
{
    if (!strcmp(signame, "-HUP"))
        sig = SIGHUP;
    else if (!strcmp(signame, "-INT"))
        sig = SIGINT;
    else if (!strcmp(signame, "-QUIT"))
        sig = SIGQUIT;
    else if (!strcmp(signame, "-ABRT"))
        sig = SIGABRT;

    /*
     * probably should NOT provide SIGKILL
     *
     * else if (!strcmp(signame,"-KILL")) sig = SIGKILL;
     */
    else if (!strcmp(signame, "-TERM"))
        sig = SIGTERM;
    else if (!strcmp(signame, "-USR1"))
        sig = SIGUSR1;
    else if (!strcmp(signame, "-USR2"))
        sig = SIGUSR2;
    else
    {
        fprintf(stderr, _("%s: invalid signal \"%s\"\n"), progname, signame);
        do_advice();
        exit(1);
    }

}



int
main(int argc, char **argv)
{
    static struct option long_options[] = {
        {"help", no_argument, NULL, '?'},
        {"version", no_argument, NULL, 'V'},
        {"log", required_argument, NULL, 'l'},
        {"mode", required_argument, NULL, 'm'},
        {"pgdata", required_argument, NULL, 'D'},
        {"silent", no_argument, NULL, 's'},
        {0, 0, 0, 0}
    };

    int            option_index;
    int            c;

#ifdef WIN32
    setvbuf(stderr, NULL, _IONBF, 0);
#endif

    progname = get_progname(argv[0]);

    /*
     * save argv[0] so do_start() can look for the postmaster if
     * necessary. we don't look for postmaster here because in many cases
     * we won't need it.
     */
    argv0 = argv[0];

    umask(077);

    if (argc > 1)
    {
        if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 ||
            strcmp(argv[1], "-?") == 0)
        {
            do_help();
            exit(0);
        }
        else if (strcmp(argv[1], "-V") == 0 || strcmp(argv[1], "--version") == 0)
        {
            printf("%s (PostgreSQL) %s\n", progname, PG_VERSION);
            exit(0);
        }
    }

    /* process command-line options */

    while ((c = getopt_long(argc, argv, "D:l:m:o:p:swW", long_options, &option_index)) != -1)
    {
        switch (c)
        {
            case 'D':
            {
                int            len = strlen(optarg) + 4;
                char       *env_var;

                pg_data_opts = xmalloc(len);
                snprintf(pg_data_opts, len, "-D %s", optarg);
                env_var = xmalloc(len + sizeof("PGDATA="));
                snprintf(env_var, len + sizeof("PGDATA="), "PGDATA=%s", optarg);
                putenv(env_var);
                break;
            }
            case 'l':
                log_file = xstrdup(optarg);
                break;
            case 'm':
                set_mode(optarg);
                break;
            case 'o':
                post_opts = xstrdup(optarg);
                break;
            case 'p':
                postgres_path = xstrdup(optarg);
                break;
            case 's':
                silence_echo = true;
                break;
            case 'w':
                do_wait = true;
                wait_set = true;
                break;
            case 'W':
                do_wait = false;
                wait_set = true;
                break;
            default:
                fprintf(stderr, _("%s: invalid option %s\n"), progname, optarg);
                do_advice();
                exit(1);
        }
    }

    for (; optind < argc; optind++)
    {
        if (ctl_command != NO_COMMAND)
        {
            fprintf(stderr, _("%s: extra operation mode %s\n"), progname, argv[optind]);
            do_advice();
            exit(1);
        }

        if (strcmp(argv[optind], "start") == 0)
            ctl_command = START_COMMAND;
        else if (strcmp(argv[optind], "stop") == 0)
            ctl_command = STOP_COMMAND;
        else if (strcmp(argv[optind], "restart") == 0)
            ctl_command = RESTART_COMMAND;
        else if (strcmp(argv[optind], "reload") == 0)
            ctl_command = RELOAD_COMMAND;
        else if (strcmp(argv[optind], "status") == 0)
            ctl_command = STATUS_COMMAND;
        else if (strcmp(argv[optind], "kill") == 0)
        {
            if (argc - optind < 3)
            {
                fprintf(stderr, _("%s: invalid kill syntax\n"), progname);
                do_advice();
                exit(1);
            }
            ctl_command = KILL_COMMAND;
            set_sig(argv[optind + 1]);
            killproc = atol(argv[optind + 2]);
        }
        else
        {
            fprintf(stderr, _("%s: invalid operation mode %s\n"), progname, argv[optind]);
            do_advice();
            exit(1);
        }
    }

    if (ctl_command == NO_COMMAND)
    {
        fprintf(stderr, _("%s: no operation specified\n"), progname);
        do_advice();
        exit(1);
    }

    pg_data = getenv("PGDATA");
    canonicalize_path(pg_data);

    if (pg_data == NULL && ctl_command != KILL_COMMAND)
    {
        fprintf(stderr,
                _("%s: no database directory specified "
                "and environment variable PGDATA unset\n"),
                progname);
        do_advice();
        exit(1);
    }

    if (!wait_set)
    {
        switch (ctl_command)
        {
            case RESTART_COMMAND:
            case START_COMMAND:
                do_wait = false;
                break;
            case STOP_COMMAND:
                do_wait = true;
                break;
            default:
                break;
        }
    }

    if (ctl_command == RELOAD_COMMAND)
    {
        sig = SIGHUP;
        do_wait = false;
    }

    snprintf(def_postopts_file, MAXPGPATH, "%s/postmaster.opts.default", pg_data);
    snprintf(postopts_file, MAXPGPATH, "%s/postmaster.opts", pg_data);
    snprintf(pid_file, MAXPGPATH, "%s/postmaster.pid", pg_data);
    snprintf(conf_file, MAXPGPATH, "%s/postgresql.conf", pg_data);

    switch (ctl_command)
    {
        case STATUS_COMMAND:
            do_status();
            break;
        case START_COMMAND:
            do_start();
            break;
        case STOP_COMMAND:
            do_stop();
            break;
        case RESTART_COMMAND:
            do_restart();
            break;
        case RELOAD_COMMAND:
            do_reload();
            break;
        case KILL_COMMAND:
            do_kill();
            break;
        default:
            break;
    }

    exit(0);
}
#-------------------------------------------------------------------------
#
# Makefile for src/bin/pg_ctl
#
# Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
# Portions Copyright (c) 1994, Regents of the University of California
#
# $PostgreSQL: pgsql-server/src/bin/pg_ctl/Makefile,v 1.41 2004/05/24 01:01:37 momjian Exp $
#
#-------------------------------------------------------------------------

subdir = src/bin/pg_ctl
top_builddir = ../../..
include $(top_builddir)/src/Makefile.global

override CPPFLAGS := -DFRONTEND -DDEF_PGPORT=$(DEF_PGPORT) -I$(libpq_srcdir) $(CPPFLAGS)

OBJS=    pg_ctl.o exec.o

all: submake-libpq submake-libpgport pg_ctl

pg_ctl: $(OBJS) $(libpq_builddir)/libpq.a
    $(CC) $(CFLAGS) $(OBJS) $(libpq) $(LDFLAGS) $(LIBS) -o $@$(X)

exec.c: % : $(top_srcdir)/src/port/%
    rm -f $@ && $(LN_S) $< .

install: all installdirs
    $(INSTALL_PROGRAM) pg_ctl$(X) $(DESTDIR)$(bindir)/pg_ctl$(X)

installdirs:
    $(mkinstalldirs) $(DESTDIR)$(bindir)

uninstall:
    rm -f $(DESTDIR)$(bindir)/pg_ctl$(X)

clean distclean maintainer-clean:
    rm -f pg_ctl$(X) $(OBJS) exec.c


# ensure that changes in DEF_PGPORT propagate into object file
pg_ctl.o: pg_ctl.c $(top_builddir)/src/Makefile.global

Re: pg_ctl.c

From
Gaetano Mendola
Date:
Andrew Dunstan wrote:

> Gaetano Mendola wrote:
>
>> Bruce Momjian wrote:
>>
>> however below the result of my quich review:
>>
>> 1) exit(1)  => exit(EXIT_FAILURE)
>
>
>
> If we used a number of different error codes I might agree. But it seems
> pointless here, and the style is widely used in our code base (I just
> counted 201 other occurrrences, not including cases of exit(0) ).

This doesn't mean that we don't have to.


>> 2) xstrdup protected by duplicate NULL string
> I don't object, but it is redundant - in every case where it is called
> the argument is demonstrably not NULL.

Now it's true, and in the future ? Bruce was arguing about that check
that if the string is null the program simply will exit crashing!
I really appreciate the quality software of Postgres but some time
I don't understand why test "NULL" pointer is an overkill for you.
I mean xstrdup is supposed to be the strdup safe version, and without
that control is not safe, why don't use directly the strdup then ?
If there is no memory available before postgresql start go figure after!



Regards
Gaetano Mendola













Re: pg_ctl.c

From
Andrew Dunstan
Date:
Gaetano Mendola wrote:

> Andrew Dunstan wrote:
>
>> Gaetano Mendola wrote:
>>
>>> Bruce Momjian wrote:
>>>
>>> however below the result of my quich review:
>>>
>>> 1) exit(1)  => exit(EXIT_FAILURE)
>>
>>
>>
>>
>> If we used a number of different error codes I might agree. But it
>> seems pointless here, and the style is widely used in our code base
>> (I just counted 201 other occurrrences, not including cases of
>> exit(0) ).
>
>
> This doesn't mean that we don't have to.


We should be consistent. If you want to prepare a global patch that
replaces every instance of exit(n) with exit(SOME_CONSTANT) then be my
guest.

>
>
>>> 2) xstrdup protected by duplicate NULL string
>>
>> I don't object, but it is redundant - in every case where it is
>> called the argument is demonstrably not NULL.
>
>
> Now it's true, and in the future ? Bruce was arguing about that check
> that if the string is null the program simply will exit crashing!
> I really appreciate the quality software of Postgres but some time
> I don't understand why test "NULL" pointer is an overkill for you.
> I mean xstrdup is supposed to be the strdup safe version, and without
> that control is not safe, why don't use directly the strdup then ?
> If there is no memory available before postgresql start go figure after!
>

I am not arguing that we should crash. I am arguing that we will not
crash in this case, and the test is therefore redundant.

I already said I don't object to the change, if that's the consensus,
just that it is unnecessary. BTW, this code was lifted directly from
initdb.c.

I'd far rather you found real bugs than the ghosts of imaginary bugs,
though.

cheers

andrew



Re: pg_ctl.c

From
Gaetano Mendola
Date:
Andrew Dunstan wrote:

> Gaetano Mendola wrote:
>
>> Andrew Dunstan wrote:
>>
>>> Gaetano Mendola wrote:
>>>
>>>> Bruce Momjian wrote:
>>>>
>>>> however below the result of my quich review:
>>>>
>>>> 1) exit(1)  => exit(EXIT_FAILURE)
>>>
>>>
>>>
>>>
>>>
>>> If we used a number of different error codes I might agree. But it
>>> seems pointless here, and the style is widely used in our code base
>>> (I just counted 201 other occurrrences, not including cases of
>>> exit(0) ).
>>
>>
>>
>> This doesn't mean that we don't have to.
>
>
>
> We should be consistent. If you want to prepare a global patch that
> replaces every instance of exit(n) with exit(SOME_CONSTANT) then be my
> guest.

I'd like to do it, partecipate more on postgres coding but in this
period I really don't have time, this doesn't mean that we have to
wrote exit(1) instead of exit(EXIT_FAILURE) and change these
exit in the future. BTW the next patch will write again: exit(1).

>>>> 2) xstrdup protected by duplicate NULL string
>>>
>>>
>>> I don't object, but it is redundant - in every case where it is
>>> called the argument is demonstrably not NULL.
>>
>>
>>
>> Now it's true, and in the future ? Bruce was arguing about that check
>> that if the string is null the program simply will exit crashing!
>> I really appreciate the quality software of Postgres but some time
>> I don't understand why test "NULL" pointer is an overkill for you.
>> I mean xstrdup is supposed to be the strdup safe version, and without
>> that control is not safe, why don't use directly the strdup then ?
>> If there is no memory available before postgresql start go figure after!
>>
>
> I am not arguing that we should crash. I am arguing that we will not
> crash in this case, and the test is therefore redundant.
>
> I already said I don't object to the change, if that's the consensus,
> just that it is unnecessary. BTW, this code was lifted directly from
> initdb.c.
>
> I'd far rather you found real bugs than the ghosts of imaginary bugs,
> though.

I was not looking for bugs or ghost, I repeat the test may be redundant
now with the current version of pg_ctl.c, do you write free function
trusting in the caller ( as Bruce do ) or watching were and how it's called?

I write free function without trust the caller and without see where and
how is called, different point of view.


Regards
Gaetano Mendola













Re: pg_ctl.c

From
"Thomas Hallgren"
Date:
Neither the version in CVS head nor the version you attached here links on
win32 (msys/mingw). I get the following:

gcc -O2 -fno-strict-aliasing -Wall -Wmissing-prototypes -Wmissing-declaratio
ns pg_ctl.o
ec.o -L../../../src/interfaces/libpq -lpq -L../../../src/port   -lz -lreadli
ne -lwsock32 -lm  -lpgport -lws2_32 -o pg_ctl.exe
pg_ctl.o(.text+0xa3c):pg_ctl.c: undefined reference to `kill'
pg_ctl.o(.text+0xc4c):pg_ctl.c: undefined reference to `kill'
pg_ctl.o(.text+0xe5a):pg_ctl.c: undefined reference to `kill'
pg_ctl.o(.text+0x1058):pg_ctl.c: undefined reference to `kill'

Regards,

Thomas Hallgren

"Bruce Momjian" <pgman@candle.pha.pa.us> wrote in message
news:200405261459.i4QExWT28671@candle.pha.pa.us...
> OK, here is a new version with lots of fixes.
>
> --
>   Bruce Momjian                        |  http://candle.pha.pa.us
>   pgman@candle.pha.pa.us               |  (610) 359-1001
>   +  If your life is a hard drive,     |  13 Roberts Road
>   +  Christ can be your backup.        |  Newtown Square, Pennsylvania
19073
>


----------------------------------------------------------------------------
----


>
/*-------------------------------------------------------------------------
>  *
>  * pg_ctl --- start/stops/restarts the PostgreSQL server
>  *
>  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
>  *
>  * $PostgreSQL: pgsql-server/src/bin/initdb/initdb.c,v 1.32 2004/05/18
03:36:36 momjian Exp $
>  *
>
*-------------------------------------------------------------------------
>  */
>
> #include "postgres_fe.h"
> #include "libpq-fe.h"
>
> #include <signal.h>
> #include <errno.h>
> #include <sys/types.h>
> #include <sys/stat.h>
>
> #include "libpq/pqsignal.h"
> #include "getopt_long.h"
>
> #ifndef HAVE_OPTRESET
> int optreset;
> #endif
>
>
> #define _(x) gettext((x))
>
> #define WHITESPACE "\f\n\r\t\v" /* as defined by isspace() */
>
> /* postmaster version ident string */
> #define PM_VERSIONSTR "postmaster (PostgreSQL) " PG_VERSION "\n"
>
>
> typedef enum
> {
> SMART_MODE,
> FAST_MODE,
> IMMEDIATE_MODE
> } ShutdownMode;
>
>
> typedef enum
> {
> NO_COMMAND = 0,
> START_COMMAND,
> STOP_COMMAND,
> RESTART_COMMAND,
> RELOAD_COMMAND,
> STATUS_COMMAND,
> KILL_COMMAND
> } CtlCommand;
>
>
> static bool do_wait = false;
> static bool wait_set = false;
> static int wait_seconds = 60;
> static bool silence_echo = false;
> static ShutdownMode shutdown_mode = SMART_MODE;
> static int sig = SIGTERM; /* default */
> static int killproc;
> static CtlCommand ctl_command = NO_COMMAND;
> static char *pg_data_opts = NULL;
> static char *pg_data = NULL;
> static char *post_opts = NULL;
> static const char *progname;
> static char *log_file = NULL;
> static char *postgres_path = NULL;
> static char *argv0 = NULL;
>
> static void *xmalloc(size_t size);
> static char *xstrdup(const char *s);
> static void do_advice(void);
> static void do_help(void);
> static void set_mode(char *modeopt);
> static void set_sig(char *signame);
> static void do_start();
> static void do_stop(void);
> static void do_restart(void);
> static void do_reload(void);
> static void do_status(void);
> static void do_kill(void);
> static long get_pgpid(void);
> static char **readfile(char *path);
> static int start_postmaster(void);
> static bool test_postmaster_connection(void);
>
> static char def_postopts_file[MAXPGPATH];
> static char postopts_file[MAXPGPATH];
> static char pid_file[MAXPGPATH];
> static char conf_file[MAXPGPATH];
>
> /*
>  * routines to check memory allocations and fail noisily.
>  */
>
> static void *
> xmalloc(size_t size)
> {
> void    *result;
>
> result = malloc(size);
> if (!result)
> {
> fprintf(stderr, _("%s: out of memory\n"), progname);
> exit(1);
> }
> return result;
> }
>
>
>
> static char *
> xstrdup(const char *s)
> {
> char    *result;
>
> result = strdup(s);
> if (!result)
> {
> fprintf(stderr, _("%s: out of memory\n"), progname);
> exit(1);
> }
> return result;
> }
>
>
>
> static long
> get_pgpid(void)
> {
> FILE    *pidf;
> long pid;
>
> pidf = fopen(pid_file, "r");
> if (pidf == NULL)
> {
> /* No pid file, not an error on startup */
> if (errno == ENOENT)
> return 0;
> else
> {
> perror("openning pid file");
> exit(1);
> }
> }
> fscanf(pidf, "%ld", &pid);
> fclose(pidf);
> return pid;
> }
>
>
> /*
>  * get the lines from a text file - return NULL if file can't be opened
>  */
> static char **
> readfile(char *path)
> {
> FILE    *infile;
> int maxlength = 0,
> linelen = 0;
> int nlines = 0;
> char   **result;
> char    *buffer;
> int c;
>
> if ((infile = fopen(path, "r")) == NULL)
> return NULL;
>
> /* pass over the file twice - the first time to size the result */
>
> while ((c = fgetc(infile)) != EOF)
> {
> linelen++;
> if (c == '\n')
> {
> nlines++;
> if (linelen > maxlength)
> maxlength = linelen;
> linelen = 0;
> }
> }
>
> /* handle last line without a terminating newline (yuck) */
> if (linelen)
> nlines++;
> if (linelen > maxlength)
> maxlength = linelen;
>
> /* set up the result and the line buffer */
>
> result = (char **) xmalloc((nlines + 1) * sizeof(char *));
> buffer = (char *) xmalloc(maxlength + 1);
>
> /* now reprocess the file and store the lines */
> rewind(infile);
> nlines = 0;
> while (fgets(buffer, maxlength + 1, infile) != NULL)
> result[nlines++] = xstrdup(buffer);
>
> fclose(infile);
> result[nlines] = NULL;
>
> return result;
> }
>
>
>
> /*
>  * start/test/stop routines
>  */
>
> static int
> start_postmaster(void)
> {
> /*
> * Since there might be quotes to handle here, it is easier simply
> * to pass everything to a shell to process them.
> */
> char cmd[MAXPGPATH];
>
> /* Does '&' work on Win32? */
> if (log_file != NULL)
> snprintf(cmd, MAXPGPATH, "\"%s\" %s < %s >>\"%s\" 2>&1 &",
> postgres_path, post_opts, DEVNULL, log_file);
> else
> snprintf(cmd, MAXPGPATH, "\"%s\" %s < %s 2>&1 &",
> postgres_path, post_opts, DEVNULL);
> return system(cmd);
> }
>
>
>
> /* Find the pgport and try a connection */
> static bool
> test_postmaster_connection(void)
> {
> PGconn    *conn;
> bool success = false;
> int i;
> char portstr[32];
> char *p;
>
>
> *portstr = '\0';
>
> /* post_opts */
> for (p = post_opts; *p;)
> {
> /* advance past whitespace/quoting */
> while (isspace(*p) || *p == '\'' || *p == '"')
> p++;
>
> if (strncmp(p, "-p", strlen("-p")) == 0)
> {
> p += strlen("-p");
> /* advance past whitespace/quoting */
> while (isspace(*p) || *p == '\'' || *p == '"')
> p++;
> StrNCpy(portstr, p, Min(strcspn(p, "\"'"WHITESPACE) + 1,
> sizeof(portstr)));
> /* keep looking, maybe there is another -p */
> }
> /* Advance to next whitespace */
> while (!isspace(*p))
> p++;
> }
>
> /* config file */
> if (!*portstr)
> {
> char   **optlines;
>
> optlines = readfile(conf_file);
> if (optlines != NULL)
> {
> for (;*optlines != NULL; optlines++)
> {
> p = *optlines;
>
> while (isspace(*p))
> p++;
> if (strncmp(p, "port", strlen("port")) != 0)
> continue;
> p += strlen("port");
> while (isspace(*p))
> p++;
> if (*p != '=')
> continue;
> p++;
> while (isspace(*p))
> p++;
> StrNCpy(portstr, p, Min(strcspn(p, "#"WHITESPACE) + 1,
> sizeof(portstr)));
> /* keep looking, maybe there is another */
> }
> }
> }
>
> /* environment */
> if (!*portstr && getenv("PGPORT") != NULL)
> StrNCpy(portstr, getenv("PGPORT"), sizeof(portstr));
>
> /* default */
> if (!*portstr)
> snprintf(portstr, sizeof(portstr), "%d", DEF_PGPORT);
>
> for (i = 0; i < wait_seconds; i++)
> {
> if ((conn = PQsetdbLogin(NULL, portstr, NULL, NULL, "template1", NULL,
NULL)) != NULL)
> {
> PQfinish(conn);
> success = true;
> break;
> }
> }
>
> return success;
> }
>
>
>
> static void
> do_start(void)
> {
> long pid;
> long old_pid = 0;
> char    *optline = NULL;
>
> if (ctl_command != RESTART_COMMAND)
> {
> old_pid = get_pgpid();
> if (old_pid != 0)
> fprintf(stderr,
> _("%s: Another postmaster may be running. "
> "Trying to start postmaster anyway.\n"),
> progname);
> }
>
> if (post_opts == NULL)
> {
> char   **optlines;
> int len;
>
> optlines = readfile(ctl_command == RESTART_COMMAND ?
> postopts_file : def_postopts_file);
> if (optlines == NULL)
> {
> if (ctl_command == START_COMMAND)
> post_opts = "";
> else
> {
> fprintf(stderr, _("%s: cannot read %s\n"), progname, postopts_file);
> exit(1);
> }
> }
> else if (optlines[0] == NULL || optlines[1] != NULL)
> {
> fprintf(stderr, _("%s: option file %s must have exactly 1 line\n"),
> progname, ctl_command == RESTART_COMMAND ?
> postopts_file : def_postopts_file);
> exit(1);
> }
> else
> {
> optline = optlines[0];
> len = strcspn(optline, "\r\n");
> optline[len] = '\0';
>
> if (ctl_command == RESTART_COMMAND)
> {
> char    *arg1;
>
> arg1 = strchr(optline, '\'');
> if (arg1 == NULL || arg1 == optline)
> post_opts = "";
> else
> {
> *(arg1 - 1) = '\0'; /* this should be a space */
> post_opts = arg1;
> }
> if (postgres_path != NULL)
> postgres_path = optline;
> }
> else
> post_opts = optline;
> }
> }
>
> if (postgres_path == NULL)
> {
> char    *postmaster_path;
> int ret;
>
> postmaster_path = xmalloc(MAXPGPATH);
>
> if ((ret = find_other_exec(argv0, "postmaster", PM_VERSIONSTR,
>    postmaster_path)) < 0)
> {
> if (ret == -1)
> fprintf(stderr,
> _("The program \"postmaster\" is needed by %s "
>    "but was not found in the same directory as \"%s\".\n"
>   "Check your installation.\n"),
> progname, progname);
> else
> fprintf(stderr,
> _("The program \"postmaster\" was found by %s "
>   "but was not the same version as \"%s\".\n"
>   "Check your installation.\n"),
> progname, progname);
> exit(1);
> }
> postgres_path = postmaster_path;
> }
>
> if (start_postmaster() != 0)
> {
> fprintf(stderr, _("Unable to run the postmaster binary\n"));
> exit(1);
> }
>
> if (old_pid != 0)
> {
> pg_usleep(1000000);
> pid = get_pgpid();
> if (pid == old_pid)
> {
> fprintf(stderr,
> _("%s: cannot start postmaster\n"
> "Examine the log output\n"),
> progname);
> exit(1);
> }
> }
>
> if (do_wait)
> {
> if (!silence_echo)
> {
> printf(_("waiting for postmaster to start..."));
> fflush(stdout);
> }
>
> if (test_postmaster_connection() == false)
> printf(_("could not start postmaster\n"));
> else if (!silence_echo)
> printf(_("done\npostmaster started\n"));
> }
> else if (!silence_echo)
> printf(_("postmaster starting\n"));
> }
>
>
>
> static void
> do_stop(void)
> {
> int cnt;
> long pid;
>
> pid = get_pgpid();
>
> if (pid == 0) /* no pid file */
> {
> fprintf(stderr, _("%s: could not find %s\n"), progname, pid_file);
> fprintf(stderr, _("Is postmaster running?\n"));
> exit(1);
> }
> else if (pid < 0) /* standalone backend, not postmaster */
> {
> pid = -pid;
> fprintf(stderr,
> _("%s: cannot stop postmaster; "
> "postgres is running (PID: %ld)\n"),
> progname, pid);
> exit(1);
> }
>
> if (kill((pid_t) pid, sig) != 0)
> {
> fprintf(stderr, _("stop signal failed\n"));
> exit(1);
> }
>
> if (!do_wait)
> {
> if (!silence_echo)
> printf(_("postmaster shutting down\n"));
> return;
> }
> else
> {
> if (!silence_echo)
> {
> printf(_("waiting for postmaster to shut down..."));
> fflush(stdout);
> }
>
> for (cnt = 0; cnt < wait_seconds; cnt++)
> {
> if ((pid = get_pgpid()) != 0)
> {
> if (!silence_echo)
> {
> printf(".");
> fflush(stdout);
> }
> pg_usleep(1000000); /* 1 sec */
> }
> else
> break;
> }
>
> if (pid != 0) /* pid file still exists */
> {
> if (!silence_echo)
> printf(_(" failed\n"));
>
> fprintf(stderr, _("%s: postmaster does not shut down\n"), progname);
> exit(1);
> }
> printf(_("done\npostmaster stopped\n"));
> }
> }
>
>
> /*
>  * restart/reload routines
>  */
>
> static void
> do_restart(void)
> {
> int cnt;
> long pid;
>
> pid = get_pgpid();
>
> if (pid == 0) /* no pid file */
> {
> fprintf(stderr, _("%s: could not find %s\n"), progname, pid_file);
> fprintf(stderr, _("Is postmaster running?\nstarting postmaster
anyway\n"));
> do_start();
> return;
> }
> else if (pid < 0) /* standalone backend, not postmaster */
> {
> pid = -pid;
> fprintf(stderr,
> _("%s: cannot restart postmaster; "
> "postgres is running (PID: %ld)\n"),
> progname, pid);
> fprintf(stderr, _("Please terminate postgres and try again.\n"));
> exit(1);
> }
>
> if (kill((pid_t) pid, sig) != 0)
> {
> fprintf(stderr, _("stop signal failed\n"));
> exit(1);
> }
>
> if (!silence_echo)
> {
> printf(_("waiting for postmaster to shut down..."));
> fflush(stdout);
> }
>
> /* always wait for restart */
>
> for (cnt = 0; cnt < wait_seconds; cnt++)
> {
> if ((pid = get_pgpid()) != 0)
> {
> if (!silence_echo)
> {
> printf(".");
> fflush(stdout);
> }
> pg_usleep(1000000); /* 1 sec */
> }
> else
> break;
> }
>
> if (pid != 0) /* pid file still exists */
> {
> if (!silence_echo)
> printf(_(" failed\n"));
>
> fprintf(stderr, _("%s: postmaster does not shut down\n"), progname);
> exit(1);
> }
>
> printf(_("done\npostmaster stopped\n"));
> do_start();
> }
>
>
> static void
> do_reload(void)
> {
> long pid;
>
> pid = get_pgpid();
> if (pid == 0) /* no pid file */
> {
> fprintf(stderr, _("%s: could not find %s\n"), progname, pid_file);
> fprintf(stderr, _("Is postmaster running?\n"));
> exit(1);
> }
> else if (pid < 0) /* standalone backend, not postmaster */
> {
> pid = -pid;
> fprintf(stderr,
> _("%s: cannot reload postmaster; "
> "postgres is running (PID: %ld)\n"),
> progname, pid);
> fprintf(stderr, _("Please terminate postgres and try again.\n"));
> exit(1);
> }
>
> if (kill((pid_t) pid, sig) != 0)
> {
> fprintf(stderr, _("reload signal failed\n"));
> exit(1);
> }
>
> if (!silence_echo)
> fprintf(stdout, _("postmaster signaled\n"));
> }
>
> /*
>  * utility routines
>  */
>
> static void
> do_status(void)
> {
> long pid;
>
> pid = get_pgpid();
> if (pid == 0) /* no pid file */
> {
> fprintf(stderr, _("%s: postmaster or postgres not running\n"), progname);
> exit(1);
> }
> else if (pid < 0) /* standalone backend */
> {
> pid = -pid;
> fprintf(stdout, _("%s: a standalone backend \"postgres\" is running (PID:
%ld)\n"), progname, pid);
> }
> else /* postmaster */
> {
> char   **optlines;
>
> fprintf(stdout, _("%s: postmaster is running (PID: %ld)\n"), progname,
pid);
>
> optlines = readfile(postopts_file);
> if (optlines != NULL)
> for (; *optlines != NULL; optlines++)
> fputs(*optlines, stdout);
> }
> }
>
>
>
> static void
> do_kill(void)
> {
> if (kill(killproc, sig) != 0)
> {
> fprintf(stderr, _("signal %d failed\n"), sig);
> exit(1);
> }
> }
>
>
>
> static void
> do_advice(void)
> {
> fprintf(stderr, _("\nTry \"%s --help\" for more information.\n"),
progname);
> }
>
>
>
> static void
> do_help(void)
> {
> printf(_("%s is a utility to start, stop, restart, reload configuration
files,\n"), progname);
> printf(_("report the status of a PostgreSQL server, or kill a PostgreSQL
process\n\n"));
> printf(_("Usage:\n"));
> printf(_("  %s start   [-w] [-D DATADIR] [-s] [-l FILENAME] [-o
\"OPTIONS\"]\n"), progname);
> printf(_("  %s stop    [-W] [-D DATADIR] [-s] [-m SHUTDOWN-MODE]\n"),
progname);
> printf(_("  %s restart [-w] [-D DATADIR] [-s] [-m SHUTDOWN-MODE] [-o
\"OPTIONS\"]\n"), progname);
> printf(_("  %s reload  [-D DATADIR] [-s]\n"), progname);
> printf(_("  %s status  [-D DATADIR]\n"), progname);
> printf(_("  %s kill    SIGNALNAME PROCESSID\n"), progname);
> printf(_("Common options:\n"));
> printf(_("  -D, --pgdata DATADIR   location of the database storage
area\n"));
> printf(_("  -s, --silent only print errors, no informational
messages\n"));
> printf(_("  -w           wait until operation completes\n"));
> printf(_("  -W           do not wait until operation completes\n"));
> printf(_("  --help       show this help, then exit\n"));
> printf(_("  --version    output version information, then exit\n"));
> printf(_("(The default is to wait for shutdown, but not for start or
restart.)\n\n"));
> printf(_("If the -D option is omitted, the environment variable PGDATA is
used.\n\n"));
> printf(_("Options for start or restart:\n"));
> printf(_("  -l, --log FILENAME      write (or append) server log to
FILENAME.  The\n"));
> printf(_("                          use of this option is highly
recommended.\n"));
> printf(_("  -o OPTIONS              command line options to pass to the
postmaster\n"));
> printf(_("                          (PostgreSQL server executable)\n"));
> printf(_("  -p PATH-TO-POSTMASTER   normally not necessary\n\n"));
> printf(_("Options for stop or restart:\n"));
> printf(_("  -m SHUTDOWN-MODE   may be 'smart', 'fast', or
'immediate'\n\n"));
> printf(_("Allowed signal names for kill:\n"));
> printf(_("  -HUP -INT -QUIT -ABRT -TERM -USR1 -USR2\n\n"));
> printf(_("Shutdown modes are:\n"));
> printf(_("  smart       quit after all clients have disconnected\n"));
> printf(_("  fast        quit directly, with proper shutdown\n"));
> printf(_("  immediate   quit without complete shutdown; will lead to
recovery on restart\n\n"));
> printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
> }
>
>
>
> static void
> set_mode(char *modeopt)
> {
> if (strcmp(modeopt, "s") == 0 || strcmp(modeopt, "smart") == 0)
> {
> shutdown_mode = SMART_MODE;
> sig = SIGTERM;
> }
> else if (strcmp(modeopt, "f") == 0 || strcmp(modeopt, "fast") == 0)
> {
> shutdown_mode = FAST_MODE;
> sig = SIGINT;
> }
> else if (strcmp(modeopt, "i") == 0 || strcmp(modeopt, "immediate") == 0)
> {
> shutdown_mode = IMMEDIATE_MODE;
> sig = SIGQUIT;
> }
> else
> {
> fprintf(stderr, _("%s: invalid shutdown mode %s\n"), progname, modeopt);
> do_advice();
> exit(1);
> }
> }
>
>
>
> static void
> set_sig(char *signame)
> {
> if (!strcmp(signame, "-HUP"))
> sig = SIGHUP;
> else if (!strcmp(signame, "-INT"))
> sig = SIGINT;
> else if (!strcmp(signame, "-QUIT"))
> sig = SIGQUIT;
> else if (!strcmp(signame, "-ABRT"))
> sig = SIGABRT;
>
> /*
> * probably should NOT provide SIGKILL
> *
> * else if (!strcmp(signame,"-KILL")) sig = SIGKILL;
> */
> else if (!strcmp(signame, "-TERM"))
> sig = SIGTERM;
> else if (!strcmp(signame, "-USR1"))
> sig = SIGUSR1;
> else if (!strcmp(signame, "-USR2"))
> sig = SIGUSR2;
> else
> {
> fprintf(stderr, _("%s: invalid signal \"%s\"\n"), progname, signame);
> do_advice();
> exit(1);
> }
>
> }
>
>
>
> int
> main(int argc, char **argv)
> {
> static struct option long_options[] = {
> {"help", no_argument, NULL, '?'},
> {"version", no_argument, NULL, 'V'},
> {"log", required_argument, NULL, 'l'},
> {"mode", required_argument, NULL, 'm'},
> {"pgdata", required_argument, NULL, 'D'},
> {"silent", no_argument, NULL, 's'},
> {0, 0, 0, 0}
> };
>
> int option_index;
> int c;
>
> #ifdef WIN32
> setvbuf(stderr, NULL, _IONBF, 0);
> #endif
>
> progname = get_progname(argv[0]);
>
> /*
> * save argv[0] so do_start() can look for the postmaster if
> * necessary. we don't look for postmaster here because in many cases
> * we won't need it.
> */
> argv0 = argv[0];
>
> umask(077);
>
>     if (argc > 1)
>     {
> if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 ||
> strcmp(argv[1], "-?") == 0)
> {
> do_help();
> exit(0);
> }
> else if (strcmp(argv[1], "-V") == 0 || strcmp(argv[1], "--version") == 0)
> {
> printf("%s (PostgreSQL) %s\n", progname, PG_VERSION);
> exit(0);
> }
> }
>
> /* process command-line options */
>
> while ((c = getopt_long(argc, argv, "D:l:m:o:p:swW", long_options,
&option_index)) != -1)
> {
> switch (c)
> {
> case 'D':
> {
> int len = strlen(optarg) + 4;
> char    *env_var;
>
> pg_data_opts = xmalloc(len);
> snprintf(pg_data_opts, len, "-D %s", optarg);
> env_var = xmalloc(len + sizeof("PGDATA="));
> snprintf(env_var, len + sizeof("PGDATA="), "PGDATA=%s", optarg);
> putenv(env_var);
> break;
> }
> case 'l':
> log_file = xstrdup(optarg);
> break;
> case 'm':
> set_mode(optarg);
> break;
> case 'o':
> post_opts = xstrdup(optarg);
> break;
> case 'p':
> postgres_path = xstrdup(optarg);
> break;
> case 's':
> silence_echo = true;
> break;
> case 'w':
> do_wait = true;
> wait_set = true;
> break;
> case 'W':
> do_wait = false;
> wait_set = true;
> break;
> default:
> fprintf(stderr, _("%s: invalid option %s\n"), progname, optarg);
> do_advice();
> exit(1);
> }
> }
>
> for (; optind < argc; optind++)
> {
> if (ctl_command != NO_COMMAND)
> {
> fprintf(stderr, _("%s: extra operation mode %s\n"), progname,
argv[optind]);
> do_advice();
> exit(1);
> }
>
> if (strcmp(argv[optind], "start") == 0)
> ctl_command = START_COMMAND;
> else if (strcmp(argv[optind], "stop") == 0)
> ctl_command = STOP_COMMAND;
> else if (strcmp(argv[optind], "restart") == 0)
> ctl_command = RESTART_COMMAND;
> else if (strcmp(argv[optind], "reload") == 0)
> ctl_command = RELOAD_COMMAND;
> else if (strcmp(argv[optind], "status") == 0)
> ctl_command = STATUS_COMMAND;
> else if (strcmp(argv[optind], "kill") == 0)
> {
> if (argc - optind < 3)
> {
> fprintf(stderr, _("%s: invalid kill syntax\n"), progname);
> do_advice();
> exit(1);
> }
> ctl_command = KILL_COMMAND;
> set_sig(argv[optind + 1]);
> killproc = atol(argv[optind + 2]);
> }
> else
> {
> fprintf(stderr, _("%s: invalid operation mode %s\n"), progname,
argv[optind]);
> do_advice();
> exit(1);
> }
> }
>
> if (ctl_command == NO_COMMAND)
> {
> fprintf(stderr, _("%s: no operation specified\n"), progname);
> do_advice();
> exit(1);
> }
>
> pg_data = getenv("PGDATA");
> canonicalize_path(pg_data);
>
> if (pg_data == NULL && ctl_command != KILL_COMMAND)
> {
> fprintf(stderr,
> _("%s: no database directory specified "
> "and environment variable PGDATA unset\n"),
> progname);
> do_advice();
> exit(1);
> }
>
> if (!wait_set)
> {
> switch (ctl_command)
> {
> case RESTART_COMMAND:
> case START_COMMAND:
> do_wait = false;
> break;
> case STOP_COMMAND:
> do_wait = true;
> break;
> default:
> break;
> }
> }
>
> if (ctl_command == RELOAD_COMMAND)
> {
> sig = SIGHUP;
> do_wait = false;
> }
>
> snprintf(def_postopts_file, MAXPGPATH, "%s/postmaster.opts.default",
pg_data);
> snprintf(postopts_file, MAXPGPATH, "%s/postmaster.opts", pg_data);
> snprintf(pid_file, MAXPGPATH, "%s/postmaster.pid", pg_data);
> snprintf(conf_file, MAXPGPATH, "%s/postgresql.conf", pg_data);
>
> switch (ctl_command)
> {
> case STATUS_COMMAND:
> do_status();
> break;
> case START_COMMAND:
> do_start();
> break;
> case STOP_COMMAND:
> do_stop();
> break;
> case RESTART_COMMAND:
> do_restart();
> break;
> case RELOAD_COMMAND:
> do_reload();
> break;
> case KILL_COMMAND:
> do_kill();
> break;
> default:
> break;
> }
>
> exit(0);
> }
>


----------------------------------------------------------------------------
----


> #-------------------------------------------------------------------------
> #
> # Makefile for src/bin/pg_ctl
> #
> # Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
> # Portions Copyright (c) 1994, Regents of the University of California
> #
> # $PostgreSQL: pgsql-server/src/bin/pg_ctl/Makefile,v 1.41 2004/05/24
01:01:37 momjian Exp $
> #
> #-------------------------------------------------------------------------
>
> subdir = src/bin/pg_ctl
> top_builddir = ../../..
> include $(top_builddir)/src/Makefile.global
>
> override CPPFLAGS
:= -DFRONTEND -DDEF_PGPORT=$(DEF_PGPORT) -I$(libpq_srcdir) $(CPPFLAGS)
>
> OBJS= pg_ctl.o exec.o
>
> all: submake-libpq submake-libpgport pg_ctl
>
> pg_ctl: $(OBJS) $(libpq_builddir)/libpq.a
> $(CC) $(CFLAGS) $(OBJS) $(libpq) $(LDFLAGS) $(LIBS) -o $@$(X)
>
> exec.c: % : $(top_srcdir)/src/port/%
> rm -f $@ && $(LN_S) $< .
>
> install: all installdirs
> $(INSTALL_PROGRAM) pg_ctl$(X) $(DESTDIR)$(bindir)/pg_ctl$(X)
>
> installdirs:
> $(mkinstalldirs) $(DESTDIR)$(bindir)
>
> uninstall:
> rm -f $(DESTDIR)$(bindir)/pg_ctl$(X)
>
> clean distclean maintainer-clean:
> rm -f pg_ctl$(X) $(OBJS) exec.c
>
>
> # ensure that changes in DEF_PGPORT propagate into object file
> pg_ctl.o: pg_ctl.c $(top_builddir)/src/Makefile.global
>


----------------------------------------------------------------------------
----


>
> ---------------------------(end of broadcast)---------------------------
> TIP 1: subscribe and unsubscribe commands go to majordomo@postgresql.org
>


Re: pg_ctl.c

From
"Magnus Hagander"
Date:
Seems it needs an implementation of the "pgwin32 special kill". Try
stealing the one from  backend/port/win32/signal.c (look for pqkill).

Perhaps this function (not the rest of signal.c!) should be moved into
port/, instead of backend/port. IIRC it depends on no other backend
code.

//Magnus

> -----Original Message-----
> From: Thomas Hallgren [mailto:thhal@mailblocks.com]
> Sent: Thursday, May 27, 2004 10:53 AM
> To: pgsql-patches@postgresql.org
> Subject: Re: [PATCHES] pg_ctl.c
>
> Neither the version in CVS head nor the version you attached
> here links on
> win32 (msys/mingw). I get the following:
>
> gcc -O2 -fno-strict-aliasing -Wall -Wmissing-prototypes
> -Wmissing-declaratio ns pg_ctl.o
> ec.o -L../../../src/interfaces/libpq -lpq -L../../../src/port
>   -lz -lreadli
> ne -lwsock32 -lm  -lpgport -lws2_32 -o pg_ctl.exe
> pg_ctl.o(.text+0xa3c):pg_ctl.c: undefined reference to `kill'
> pg_ctl.o(.text+0xc4c):pg_ctl.c: undefined reference to `kill'
> pg_ctl.o(.text+0xe5a):pg_ctl.c: undefined reference to `kill'
> pg_ctl.o(.text+0x1058):pg_ctl.c: undefined reference to `kill'
>
> Regards,
>
> Thomas Hallgren
>
> "Bruce Momjian" <pgman@candle.pha.pa.us> wrote in message
> news:200405261459.i4QExWT28671@candle.pha.pa.us...
> > OK, here is a new version with lots of fixes.
> >
> > --
> >   Bruce Momjian                        |  http://candle.pha.pa.us
> >   pgman@candle.pha.pa.us               |  (610) 359-1001
> >   +  If your life is a hard drive,     |  13 Roberts Road
> >   +  Christ can be your backup.        |  Newtown Square,
> Pennsylvania
> 19073
> >
>
>
> --------------------------------------------------------------
> --------------
> ----
>
>
> >
> /*------------------------------------------------------------
> -------------
> >  *
> >  * pg_ctl --- start/stops/restarts the PostgreSQL server
> >  *
> >  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development
> > Group
> >  *
> >  * $PostgreSQL: pgsql-server/src/bin/initdb/initdb.c,v 1.32
> 2004/05/18
> 03:36:36 momjian Exp $
> >  *
> >
> *-------------------------------------------------------------
> ------------
> >  */
> >
> > #include "postgres_fe.h"
> > #include "libpq-fe.h"
> >
> > #include <signal.h>
> > #include <errno.h>
> > #include <sys/types.h>
> > #include <sys/stat.h>
> >
> > #include "libpq/pqsignal.h"
> > #include "getopt_long.h"
> >
> > #ifndef HAVE_OPTRESET
> > int optreset;
> > #endif
> >
> >
> > #define _(x) gettext((x))
> >
> > #define WHITESPACE "\f\n\r\t\v" /* as defined by isspace() */
> >
> > /* postmaster version ident string */
> > #define PM_VERSIONSTR "postmaster (PostgreSQL) " PG_VERSION "\n"
> >
> >
> > typedef enum
> > {
> > SMART_MODE,
> > FAST_MODE,
> > IMMEDIATE_MODE
> > } ShutdownMode;
> >
> >
> > typedef enum
> > {
> > NO_COMMAND = 0,
> > START_COMMAND,
> > STOP_COMMAND,
> > RESTART_COMMAND,
> > RELOAD_COMMAND,
> > STATUS_COMMAND,
> > KILL_COMMAND
> > } CtlCommand;
> >
> >
> > static bool do_wait = false;
> > static bool wait_set = false;
> > static int wait_seconds = 60;
> > static bool silence_echo = false;
> > static ShutdownMode shutdown_mode = SMART_MODE; static int sig =
> > SIGTERM; /* default */ static int killproc; static CtlCommand
> > ctl_command = NO_COMMAND; static char *pg_data_opts = NULL; static
> > char *pg_data = NULL; static char *post_opts = NULL; static
> const char
> > *progname; static char *log_file = NULL; static char
> *postgres_path =
> > NULL; static char *argv0 = NULL;
> >
> > static void *xmalloc(size_t size);
> > static char *xstrdup(const char *s);
> > static void do_advice(void);
> > static void do_help(void);
> > static void set_mode(char *modeopt);
> > static void set_sig(char *signame);
> > static void do_start();
> > static void do_stop(void);
> > static void do_restart(void);
> > static void do_reload(void);
> > static void do_status(void);
> > static void do_kill(void);
> > static long get_pgpid(void);
> > static char **readfile(char *path);
> > static int start_postmaster(void);
> > static bool test_postmaster_connection(void);
> >
> > static char def_postopts_file[MAXPGPATH]; static char
> > postopts_file[MAXPGPATH]; static char pid_file[MAXPGPATH];
> static char
> > conf_file[MAXPGPATH];
> >
> > /*
> >  * routines to check memory allocations and fail noisily.
> >  */
> >
> > static void *
> > xmalloc(size_t size)
> > {
> > void    *result;
> >
> > result = malloc(size);
> > if (!result)
> > {
> > fprintf(stderr, _("%s: out of memory\n"), progname);
> exit(1); } return
> > result; }
> >
> >
> >
> > static char *
> > xstrdup(const char *s)
> > {
> > char    *result;
> >
> > result = strdup(s);
> > if (!result)
> > {
> > fprintf(stderr, _("%s: out of memory\n"), progname);
> exit(1); } return
> > result; }
> >
> >
> >
> > static long
> > get_pgpid(void)
> > {
> > FILE    *pidf;
> > long pid;
> >
> > pidf = fopen(pid_file, "r");
> > if (pidf == NULL)
> > {
> > /* No pid file, not an error on startup */ if (errno ==
> ENOENT) return
> > 0; else { perror("openning pid file"); exit(1); } } fscanf(pidf,
> > "%ld", &pid); fclose(pidf); return pid; }
> >
> >
> > /*
> >  * get the lines from a text file - return NULL if file can't be
> > opened  */ static char ** readfile(char *path) {
> > FILE    *infile;
> > int maxlength = 0,
> > linelen = 0;
> > int nlines = 0;
> > char   **result;
> > char    *buffer;
> > int c;
> >
> > if ((infile = fopen(path, "r")) == NULL) return NULL;
> >
> > /* pass over the file twice - the first time to size the result */
> >
> > while ((c = fgetc(infile)) != EOF)
> > {
> > linelen++;
> > if (c == '\n')
> > {
> > nlines++;
> > if (linelen > maxlength)
> > maxlength = linelen;
> > linelen = 0;
> > }
> > }
> >
> > /* handle last line without a terminating newline (yuck) */ if
> > (linelen)
> > nlines++;
> > if (linelen > maxlength)
> > maxlength = linelen;
> >
> > /* set up the result and the line buffer */
> >
> > result = (char **) xmalloc((nlines + 1) * sizeof(char *)); buffer =
> > (char *) xmalloc(maxlength + 1);
> >
> > /* now reprocess the file and store the lines */ rewind(infile);
> > nlines = 0; while (fgets(buffer, maxlength + 1, infile) != NULL)
> > result[nlines++] = xstrdup(buffer);
> >
> > fclose(infile);
> > result[nlines] = NULL;
> >
> > return result;
> > }
> >
> >
> >
> > /*
> >  * start/test/stop routines
> >  */
> >
> > static int
> > start_postmaster(void)
> > {
> > /*
> > * Since there might be quotes to handle here, it is easier simply
> > * to pass everything to a shell to process them.
> > */
> > char cmd[MAXPGPATH];
> >
> > /* Does '&' work on Win32? */
> > if (log_file != NULL)
> > snprintf(cmd, MAXPGPATH, "\"%s\" %s < %s >>\"%s\" 2>&1 &",
> > postgres_path, post_opts, DEVNULL, log_file); else snprintf(cmd,
> > MAXPGPATH, "\"%s\" %s < %s 2>&1 &", postgres_path, post_opts,
> > DEVNULL); return system(cmd); }
> >
> >
> >
> > /* Find the pgport and try a connection */ static bool
> > test_postmaster_connection(void)
> > {
> > PGconn    *conn;
> > bool success = false;
> > int i;
> > char portstr[32];
> > char *p;
> >
> >
> > *portstr = '\0';
> >
> > /* post_opts */
> > for (p = post_opts; *p;)
> > {
> > /* advance past whitespace/quoting */
> > while (isspace(*p) || *p == '\'' || *p == '"')
> > p++;
> >
> > if (strncmp(p, "-p", strlen("-p")) == 0)
> > {
> > p += strlen("-p");
> > /* advance past whitespace/quoting */
> > while (isspace(*p) || *p == '\'' || *p == '"')
> > p++;
> > StrNCpy(portstr, p, Min(strcspn(p, "\"'"WHITESPACE) + 1,
> > sizeof(portstr)));
> > /* keep looking, maybe there is another -p */
> > }
> > /* Advance to next whitespace */
> > while (!isspace(*p))
> > p++;
> > }
> >
> > /* config file */
> > if (!*portstr)
> > {
> > char   **optlines;
> >
> > optlines = readfile(conf_file);
> > if (optlines != NULL)
> > {
> > for (;*optlines != NULL; optlines++)
> > {
> > p = *optlines;
> >
> > while (isspace(*p))
> > p++;
> > if (strncmp(p, "port", strlen("port")) != 0)
> > continue;
> > p += strlen("port");
> > while (isspace(*p))
> > p++;
> > if (*p != '=')
> > continue;
> > p++;
> > while (isspace(*p))
> > p++;
> > StrNCpy(portstr, p, Min(strcspn(p, "#"WHITESPACE) + 1,
> > sizeof(portstr)));
> > /* keep looking, maybe there is another */
> > }
> > }
> > }
> >
> > /* environment */
> > if (!*portstr && getenv("PGPORT") != NULL)
> > StrNCpy(portstr, getenv("PGPORT"), sizeof(portstr));
> >
> > /* default */
> > if (!*portstr)
> > snprintf(portstr, sizeof(portstr), "%d", DEF_PGPORT);
> >
> > for (i = 0; i < wait_seconds; i++)
> > {
> > if ((conn = PQsetdbLogin(NULL, portstr, NULL, NULL,
> "template1", NULL,
> NULL)) != NULL)
> > {
> > PQfinish(conn);
> > success = true;
> > break;
> > }
> > }
> >
> > return success;
> > }
> >
> >
> >
> > static void
> > do_start(void)
> > {
> > long pid;
> > long old_pid = 0;
> > char    *optline = NULL;
> >
> > if (ctl_command != RESTART_COMMAND)
> > {
> > old_pid = get_pgpid();
> > if (old_pid != 0)
> > fprintf(stderr,
> > _("%s: Another postmaster may be running. "
> > "Trying to start postmaster anyway.\n"),
> > progname);
> > }
> >
> > if (post_opts == NULL)
> > {
> > char   **optlines;
> > int len;
> >
> > optlines = readfile(ctl_command == RESTART_COMMAND ?
> > postopts_file : def_postopts_file);
> > if (optlines == NULL)
> > {
> > if (ctl_command == START_COMMAND)
> > post_opts = "";
> > else
> > {
> > fprintf(stderr, _("%s: cannot read %s\n"), progname, postopts_file);
> > exit(1);
> > }
> > }
> > else if (optlines[0] == NULL || optlines[1] != NULL)
> > {
> > fprintf(stderr, _("%s: option file %s must have exactly 1 line\n"),
> > progname, ctl_command == RESTART_COMMAND ?
> > postopts_file : def_postopts_file);
> > exit(1);
> > }
> > else
> > {
> > optline = optlines[0];
> > len = strcspn(optline, "\r\n");
> > optline[len] = '\0';
> >
> > if (ctl_command == RESTART_COMMAND)
> > {
> > char    *arg1;
> >
> > arg1 = strchr(optline, '\'');
> > if (arg1 == NULL || arg1 == optline)
> > post_opts = "";
> > else
> > {
> > *(arg1 - 1) = '\0'; /* this should be a space */
> > post_opts = arg1;
> > }
> > if (postgres_path != NULL)
> > postgres_path = optline;
> > }
> > else
> > post_opts = optline;
> > }
> > }
> >
> > if (postgres_path == NULL)
> > {
> > char    *postmaster_path;
> > int ret;
> >
> > postmaster_path = xmalloc(MAXPGPATH);
> >
> > if ((ret = find_other_exec(argv0, "postmaster", PM_VERSIONSTR,
> >    postmaster_path)) < 0)
> > {
> > if (ret == -1)
> > fprintf(stderr,
> > _("The program \"postmaster\" is needed by %s "
> >    "but was not found in the same directory as \"%s\".\n"
> >   "Check your installation.\n"),
> > progname, progname);
> > else
> > fprintf(stderr,
> > _("The program \"postmaster\" was found by %s "
> >   "but was not the same version as \"%s\".\n"
> >   "Check your installation.\n"),
> > progname, progname);
> > exit(1);
> > }
> > postgres_path = postmaster_path;
> > }
> >
> > if (start_postmaster() != 0)
> > {
> > fprintf(stderr, _("Unable to run the postmaster binary\n"));
> > exit(1);
> > }
> >
> > if (old_pid != 0)
> > {
> > pg_usleep(1000000);
> > pid = get_pgpid();
> > if (pid == old_pid)
> > {
> > fprintf(stderr,
> > _("%s: cannot start postmaster\n"
> > "Examine the log output\n"),
> > progname);
> > exit(1);
> > }
> > }
> >
> > if (do_wait)
> > {
> > if (!silence_echo)
> > {
> > printf(_("waiting for postmaster to start..."));
> > fflush(stdout);
> > }
> >
> > if (test_postmaster_connection() == false)
> > printf(_("could not start postmaster\n"));
> > else if (!silence_echo)
> > printf(_("done\npostmaster started\n"));
> > }
> > else if (!silence_echo)
> > printf(_("postmaster starting\n"));
> > }
> >
> >
> >
> > static void
> > do_stop(void)
> > {
> > int cnt;
> > long pid;
> >
> > pid = get_pgpid();
> >
> > if (pid == 0) /* no pid file */
> > {
> > fprintf(stderr, _("%s: could not find %s\n"), progname, pid_file);
> > fprintf(stderr, _("Is postmaster running?\n"));
> > exit(1);
> > }
> > else if (pid < 0) /* standalone backend, not postmaster */
> > {
> > pid = -pid;
> > fprintf(stderr,
> > _("%s: cannot stop postmaster; "
> > "postgres is running (PID: %ld)\n"),
> > progname, pid);
> > exit(1);
> > }
> >
> > if (kill((pid_t) pid, sig) != 0)
> > {
> > fprintf(stderr, _("stop signal failed\n"));
> > exit(1);
> > }
> >
> > if (!do_wait)
> > {
> > if (!silence_echo)
> > printf(_("postmaster shutting down\n"));
> > return;
> > }
> > else
> > {
> > if (!silence_echo)
> > {
> > printf(_("waiting for postmaster to shut down..."));
> > fflush(stdout);
> > }
> >
> > for (cnt = 0; cnt < wait_seconds; cnt++)
> > {
> > if ((pid = get_pgpid()) != 0)
> > {
> > if (!silence_echo)
> > {
> > printf(".");
> > fflush(stdout);
> > }
> > pg_usleep(1000000); /* 1 sec */
> > }
> > else
> > break;
> > }
> >
> > if (pid != 0) /* pid file still exists */
> > {
> > if (!silence_echo)
> > printf(_(" failed\n"));
> >
> > fprintf(stderr, _("%s: postmaster does not shut down\n"), progname);
> > exit(1);
> > }
> > printf(_("done\npostmaster stopped\n"));
> > }
> > }
> >
> >
> > /*
> >  * restart/reload routines
> >  */
> >
> > static void
> > do_restart(void)
> > {
> > int cnt;
> > long pid;
> >
> > pid = get_pgpid();
> >
> > if (pid == 0) /* no pid file */
> > {
> > fprintf(stderr, _("%s: could not find %s\n"), progname, pid_file);
> > fprintf(stderr, _("Is postmaster running?\nstarting postmaster
> anyway\n"));
> > do_start();
> > return;
> > }
> > else if (pid < 0) /* standalone backend, not postmaster */
> > {
> > pid = -pid;
> > fprintf(stderr,
> > _("%s: cannot restart postmaster; "
> > "postgres is running (PID: %ld)\n"),
> > progname, pid);
> > fprintf(stderr, _("Please terminate postgres and try again.\n"));
> > exit(1);
> > }
> >
> > if (kill((pid_t) pid, sig) != 0)
> > {
> > fprintf(stderr, _("stop signal failed\n"));
> > exit(1);
> > }
> >
> > if (!silence_echo)
> > {
> > printf(_("waiting for postmaster to shut down..."));
> > fflush(stdout);
> > }
> >
> > /* always wait for restart */
> >
> > for (cnt = 0; cnt < wait_seconds; cnt++)
> > {
> > if ((pid = get_pgpid()) != 0)
> > {
> > if (!silence_echo)
> > {
> > printf(".");
> > fflush(stdout);
> > }
> > pg_usleep(1000000); /* 1 sec */
> > }
> > else
> > break;
> > }
> >
> > if (pid != 0) /* pid file still exists */
> > {
> > if (!silence_echo)
> > printf(_(" failed\n"));
> >
> > fprintf(stderr, _("%s: postmaster does not shut down\n"), progname);
> > exit(1);
> > }
> >
> > printf(_("done\npostmaster stopped\n"));
> > do_start();
> > }
> >
> >
> > static void
> > do_reload(void)
> > {
> > long pid;
> >
> > pid = get_pgpid();
> > if (pid == 0) /* no pid file */
> > {
> > fprintf(stderr, _("%s: could not find %s\n"), progname, pid_file);
> > fprintf(stderr, _("Is postmaster running?\n"));
> > exit(1);
> > }
> > else if (pid < 0) /* standalone backend, not postmaster */
> > {
> > pid = -pid;
> > fprintf(stderr,
> > _("%s: cannot reload postmaster; "
> > "postgres is running (PID: %ld)\n"),
> > progname, pid);
> > fprintf(stderr, _("Please terminate postgres and try again.\n"));
> > exit(1);
> > }
> >
> > if (kill((pid_t) pid, sig) != 0)
> > {
> > fprintf(stderr, _("reload signal failed\n"));
> > exit(1);
> > }
> >
> > if (!silence_echo)
> > fprintf(stdout, _("postmaster signaled\n"));
> > }
> >
> > /*
> >  * utility routines
> >  */
> >
> > static void
> > do_status(void)
> > {
> > long pid;
> >
> > pid = get_pgpid();
> > if (pid == 0) /* no pid file */
> > {
> > fprintf(stderr, _("%s: postmaster or postgres not
> running\n"), progname);
> > exit(1);
> > }
> > else if (pid < 0) /* standalone backend */
> > {
> > pid = -pid;
> > fprintf(stdout, _("%s: a standalone backend \"postgres\" is
> running (PID:
> %ld)\n"), progname, pid);
> > }
> > else /* postmaster */
> > {
> > char   **optlines;
> >
> > fprintf(stdout, _("%s: postmaster is running (PID:
> %ld)\n"), progname,
> pid);
> >
> > optlines = readfile(postopts_file);
> > if (optlines != NULL)
> > for (; *optlines != NULL; optlines++)
> > fputs(*optlines, stdout);
> > }
> > }
> >
> >
> >
> > static void
> > do_kill(void)
> > {
> > if (kill(killproc, sig) != 0)
> > {
> > fprintf(stderr, _("signal %d failed\n"), sig);
> > exit(1);
> > }
> > }
> >
> >
> >
> > static void
> > do_advice(void)
> > {
> > fprintf(stderr, _("\nTry \"%s --help\" for more information.\n"),
> progname);
> > }
> >
> >
> >
> > static void
> > do_help(void)
> > {
> > printf(_("%s is a utility to start, stop, restart, reload
> configuration
> files,\n"), progname);
> > printf(_("report the status of a PostgreSQL server, or kill
> a PostgreSQL
> process\n\n"));
> > printf(_("Usage:\n"));
> > printf(_("  %s start   [-w] [-D DATADIR] [-s] [-l FILENAME] [-o
> \"OPTIONS\"]\n"), progname);
> > printf(_("  %s stop    [-W] [-D DATADIR] [-s] [-m
> SHUTDOWN-MODE]\n"),
> progname);
> > printf(_("  %s restart [-w] [-D DATADIR] [-s] [-m SHUTDOWN-MODE] [-o
> \"OPTIONS\"]\n"), progname);
> > printf(_("  %s reload  [-D DATADIR] [-s]\n"), progname);
> > printf(_("  %s status  [-D DATADIR]\n"), progname);
> > printf(_("  %s kill    SIGNALNAME PROCESSID\n"), progname);
> > printf(_("Common options:\n"));
> > printf(_("  -D, --pgdata DATADIR   location of the database storage
> area\n"));
> > printf(_("  -s, --silent only print errors, no informational
> messages\n"));
> > printf(_("  -w           wait until operation completes\n"));
> > printf(_("  -W           do not wait until operation completes\n"));
> > printf(_("  --help       show this help, then exit\n"));
> > printf(_("  --version    output version information, then exit\n"));
> > printf(_("(The default is to wait for shutdown, but not for start or
> restart.)\n\n"));
> > printf(_("If the -D option is omitted, the environment
> variable PGDATA is
> used.\n\n"));
> > printf(_("Options for start or restart:\n"));
> > printf(_("  -l, --log FILENAME      write (or append) server log to
> FILENAME.  The\n"));
> > printf(_("                          use of this option is highly
> recommended.\n"));
> > printf(_("  -o OPTIONS              command line options to
> pass to the
> postmaster\n"));
> > printf(_("                          (PostgreSQL server
> executable)\n"));
> > printf(_("  -p PATH-TO-POSTMASTER   normally not necessary\n\n"));
> > printf(_("Options for stop or restart:\n"));
> > printf(_("  -m SHUTDOWN-MODE   may be 'smart', 'fast', or
> 'immediate'\n\n"));
> > printf(_("Allowed signal names for kill:\n"));
> > printf(_("  -HUP -INT -QUIT -ABRT -TERM -USR1 -USR2\n\n"));
> > printf(_("Shutdown modes are:\n"));
> > printf(_("  smart       quit after all clients have
> disconnected\n"));
> > printf(_("  fast        quit directly, with proper shutdown\n"));
> > printf(_("  immediate   quit without complete shutdown; will lead to
> recovery on restart\n\n"));
> > printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
> > }
> >
> >
> >
> > static void
> > set_mode(char *modeopt)
> > {
> > if (strcmp(modeopt, "s") == 0 || strcmp(modeopt, "smart") == 0)
> > {
> > shutdown_mode = SMART_MODE;
> > sig = SIGTERM;
> > }
> > else if (strcmp(modeopt, "f") == 0 || strcmp(modeopt, "fast") == 0)
> > {
> > shutdown_mode = FAST_MODE;
> > sig = SIGINT;
> > }
> > else if (strcmp(modeopt, "i") == 0 || strcmp(modeopt,
> "immediate") == 0)
> > {
> > shutdown_mode = IMMEDIATE_MODE;
> > sig = SIGQUIT;
> > }
> > else
> > {
> > fprintf(stderr, _("%s: invalid shutdown mode %s\n"),
> progname, modeopt);
> > do_advice();
> > exit(1);
> > }
> > }
> >
> >
> >
> > static void
> > set_sig(char *signame)
> > {
> > if (!strcmp(signame, "-HUP"))
> > sig = SIGHUP;
> > else if (!strcmp(signame, "-INT"))
> > sig = SIGINT;
> > else if (!strcmp(signame, "-QUIT"))
> > sig = SIGQUIT;
> > else if (!strcmp(signame, "-ABRT"))
> > sig = SIGABRT;
> >
> > /*
> > * probably should NOT provide SIGKILL
> > *
> > * else if (!strcmp(signame,"-KILL")) sig = SIGKILL;
> > */
> > else if (!strcmp(signame, "-TERM"))
> > sig = SIGTERM;
> > else if (!strcmp(signame, "-USR1"))
> > sig = SIGUSR1;
> > else if (!strcmp(signame, "-USR2"))
> > sig = SIGUSR2;
> > else
> > {
> > fprintf(stderr, _("%s: invalid signal \"%s\"\n"), progname,
> signame);
> > do_advice();
> > exit(1);
> > }
> >
> > }
> >
> >
> >
> > int
> > main(int argc, char **argv)
> > {
> > static struct option long_options[] = {
> > {"help", no_argument, NULL, '?'},
> > {"version", no_argument, NULL, 'V'},
> > {"log", required_argument, NULL, 'l'},
> > {"mode", required_argument, NULL, 'm'},
> > {"pgdata", required_argument, NULL, 'D'},
> > {"silent", no_argument, NULL, 's'},
> > {0, 0, 0, 0}
> > };
> >
> > int option_index;
> > int c;
> >
> > #ifdef WIN32
> > setvbuf(stderr, NULL, _IONBF, 0);
> > #endif
> >
> > progname = get_progname(argv[0]);
> >
> > /*
> > * save argv[0] so do_start() can look for the postmaster if
> > * necessary. we don't look for postmaster here because in many cases
> > * we won't need it.
> > */
> > argv0 = argv[0];
> >
> > umask(077);
> >
> >     if (argc > 1)
> >     {
> > if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 ||
> > strcmp(argv[1], "-?") == 0)
> > {
> > do_help();
> > exit(0);
> > }
> > else if (strcmp(argv[1], "-V") == 0 || strcmp(argv[1],
> "--version") == 0)
> > {
> > printf("%s (PostgreSQL) %s\n", progname, PG_VERSION);
> > exit(0);
> > }
> > }
> >
> > /* process command-line options */
> >
> > while ((c = getopt_long(argc, argv, "D:l:m:o:p:swW", long_options,
> &option_index)) != -1)
> > {
> > switch (c)
> > {
> > case 'D':
> > {
> > int len = strlen(optarg) + 4;
> > char    *env_var;
> >
> > pg_data_opts = xmalloc(len);
> > snprintf(pg_data_opts, len, "-D %s", optarg);
> > env_var = xmalloc(len + sizeof("PGDATA="));
> > snprintf(env_var, len + sizeof("PGDATA="), "PGDATA=%s", optarg);
> > putenv(env_var);
> > break;
> > }
> > case 'l':
> > log_file = xstrdup(optarg);
> > break;
> > case 'm':
> > set_mode(optarg);
> > break;
> > case 'o':
> > post_opts = xstrdup(optarg);
> > break;
> > case 'p':
> > postgres_path = xstrdup(optarg);
> > break;
> > case 's':
> > silence_echo = true;
> > break;
> > case 'w':
> > do_wait = true;
> > wait_set = true;
> > break;
> > case 'W':
> > do_wait = false;
> > wait_set = true;
> > break;
> > default:
> > fprintf(stderr, _("%s: invalid option %s\n"), progname, optarg);
> > do_advice();
> > exit(1);
> > }
> > }
> >
> > for (; optind < argc; optind++)
> > {
> > if (ctl_command != NO_COMMAND)
> > {
> > fprintf(stderr, _("%s: extra operation mode %s\n"), progname,
> argv[optind]);
> > do_advice();
> > exit(1);
> > }
> >
> > if (strcmp(argv[optind], "start") == 0)
> > ctl_command = START_COMMAND;
> > else if (strcmp(argv[optind], "stop") == 0)
> > ctl_command = STOP_COMMAND;
> > else if (strcmp(argv[optind], "restart") == 0)
> > ctl_command = RESTART_COMMAND;
> > else if (strcmp(argv[optind], "reload") == 0)
> > ctl_command = RELOAD_COMMAND;
> > else if (strcmp(argv[optind], "status") == 0)
> > ctl_command = STATUS_COMMAND;
> > else if (strcmp(argv[optind], "kill") == 0)
> > {
> > if (argc - optind < 3)
> > {
> > fprintf(stderr, _("%s: invalid kill syntax\n"), progname);
> > do_advice();
> > exit(1);
> > }
> > ctl_command = KILL_COMMAND;
> > set_sig(argv[optind + 1]);
> > killproc = atol(argv[optind + 2]);
> > }
> > else
> > {
> > fprintf(stderr, _("%s: invalid operation mode %s\n"), progname,
> argv[optind]);
> > do_advice();
> > exit(1);
> > }
> > }
> >
> > if (ctl_command == NO_COMMAND)
> > {
> > fprintf(stderr, _("%s: no operation specified\n"), progname);
> > do_advice();
> > exit(1);
> > }
> >
> > pg_data = getenv("PGDATA");
> > canonicalize_path(pg_data);
> >
> > if (pg_data == NULL && ctl_command != KILL_COMMAND)
> > {
> > fprintf(stderr,
> > _("%s: no database directory specified "
> > "and environment variable PGDATA unset\n"),
> > progname);
> > do_advice();
> > exit(1);
> > }
> >
> > if (!wait_set)
> > {
> > switch (ctl_command)
> > {
> > case RESTART_COMMAND:
> > case START_COMMAND:
> > do_wait = false;
> > break;
> > case STOP_COMMAND:
> > do_wait = true;
> > break;
> > default:
> > break;
> > }
> > }
> >
> > if (ctl_command == RELOAD_COMMAND)
> > {
> > sig = SIGHUP;
> > do_wait = false;
> > }
> >
> > snprintf(def_postopts_file, MAXPGPATH, "%s/postmaster.opts.default",
> pg_data);
> > snprintf(postopts_file, MAXPGPATH, "%s/postmaster.opts", pg_data);
> > snprintf(pid_file, MAXPGPATH, "%s/postmaster.pid", pg_data);
> > snprintf(conf_file, MAXPGPATH, "%s/postgresql.conf", pg_data);
> >
> > switch (ctl_command)
> > {
> > case STATUS_COMMAND:
> > do_status();
> > break;
> > case START_COMMAND:
> > do_start();
> > break;
> > case STOP_COMMAND:
> > do_stop();
> > break;
> > case RESTART_COMMAND:
> > do_restart();
> > break;
> > case RELOAD_COMMAND:
> > do_reload();
> > break;
> > case KILL_COMMAND:
> > do_kill();
> > break;
> > default:
> > break;
> > }
> >
> > exit(0);
> > }
> >
>
>
> --------------------------------------------------------------
> --------------
> ----
>
>
> >
> #-------------------------------------------------------------
> ------------
> > #
> > # Makefile for src/bin/pg_ctl
> > #
> > # Portions Copyright (c) 1996-2003, PostgreSQL Global
> Development Group
> > # Portions Copyright (c) 1994, Regents of the University of
> California
> > #
> > # $PostgreSQL: pgsql-server/src/bin/pg_ctl/Makefile,v 1.41
> 2004/05/24
> 01:01:37 momjian Exp $
> > #
> >
> #-------------------------------------------------------------
> ------------
> >
> > subdir = src/bin/pg_ctl
> > top_builddir = ../../..
> > include $(top_builddir)/src/Makefile.global
> >
> > override CPPFLAGS
> := -DFRONTEND -DDEF_PGPORT=$(DEF_PGPORT) -I$(libpq_srcdir) $(CPPFLAGS)
> >
> > OBJS= pg_ctl.o exec.o
> >
> > all: submake-libpq submake-libpgport pg_ctl
> >
> > pg_ctl: $(OBJS) $(libpq_builddir)/libpq.a
> > $(CC) $(CFLAGS) $(OBJS) $(libpq) $(LDFLAGS) $(LIBS) -o $@$(X)
> >
> > exec.c: % : $(top_srcdir)/src/port/%
> > rm -f $@ && $(LN_S) $< .
> >
> > install: all installdirs
> > $(INSTALL_PROGRAM) pg_ctl$(X) $(DESTDIR)$(bindir)/pg_ctl$(X)
> >
> > installdirs:
> > $(mkinstalldirs) $(DESTDIR)$(bindir)
> >
> > uninstall:
> > rm -f $(DESTDIR)$(bindir)/pg_ctl$(X)
> >
> > clean distclean maintainer-clean:
> > rm -f pg_ctl$(X) $(OBJS) exec.c
> >
> >
> > # ensure that changes in DEF_PGPORT propagate into object file
> > pg_ctl.o: pg_ctl.c $(top_builddir)/src/Makefile.global
> >
>
>
> --------------------------------------------------------------
> --------------
> ----
>
>
> >
> > ---------------------------(end of
> broadcast)---------------------------
> > TIP 1: subscribe and unsubscribe commands go to
> majordomo@postgresql.org
> >
>
>
> ---------------------------(end of
> broadcast)---------------------------
> TIP 8: explain analyze is your friend
>
>

Re: pg_ctl.c

From
Bruce Momjian
Date:
Magnus Hagander wrote:
> Seems it needs an implementation of the "pgwin32 special kill". Try
> stealing the one from  backend/port/win32/signal.c (look for pqkill).
>
> Perhaps this function (not the rest of signal.c!) should be moved into
> port/, instead of backend/port. IIRC it depends on no other backend
> code.

OK, patch attached and applied, and new kill.c file that goes into
/port.

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073
Index: configure
===================================================================
RCS file: /cvsroot/pgsql-server/configure,v
retrieving revision 1.369
diff -c -c -r1.369 configure
*** configure    22 May 2004 00:34:49 -0000    1.369
--- configure    27 May 2004 13:05:41 -0000
***************
*** 12014,12019 ****
--- 12014,12020 ----
  case $host_os in mingw*)
  LIBOBJS="$LIBOBJS copydir.$ac_objext"
  LIBOBJS="$LIBOBJS gettimeofday.$ac_objext"
+ LIBOBJS="$LIBOBJS kill.$ac_objext"
  LIBOBJS="$LIBOBJS open.$ac_objext"
  LIBOBJS="$LIBOBJS rand.$ac_objext" ;;
  esac
Index: configure.in
===================================================================
RCS file: /cvsroot/pgsql-server/configure.in,v
retrieving revision 1.358
diff -c -c -r1.358 configure.in
*** configure.in    22 May 2004 00:34:49 -0000    1.358
--- configure.in    27 May 2004 13:05:43 -0000
***************
*** 891,896 ****
--- 891,897 ----
  case $host_os in mingw*)
  AC_LIBOBJ(copydir)
  AC_LIBOBJ(gettimeofday)
+ AC_LIBOBJ(kill)
  AC_LIBOBJ(open)
  AC_LIBOBJ(rand) ;;
  esac
Index: src/backend/port/win32/signal.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/backend/port/win32/signal.c,v
retrieving revision 1.1
diff -c -c -r1.1 signal.c
*** src/backend/port/win32/signal.c    12 Apr 2004 16:19:18 -0000    1.1
--- src/backend/port/win32/signal.c    27 May 2004 13:05:48 -0000
***************
*** 152,197 ****
      return prevfunc;
  }

- /* signal sending */
- int
- pqkill(int pid, int sig)
- {
-     char        pipename[128];
-     BYTE        sigData = sig;
-     BYTE        sigRet = 0;
-     DWORD        bytes;
-
-     if (sig >= PG_SIGNAL_COUNT || sig <= 0)
-     {
-         errno = EINVAL;
-         return -1;
-     }
-     if (pid <= 0)
-     {
-         /* No support for process groups */
-         errno = EINVAL;
-         return -1;
-     }
-     wsprintf(pipename, "\\\\.\\pipe\\pgsignal_%i", pid);
-     if (!CallNamedPipe(pipename, &sigData, 1, &sigRet, 1, &bytes, 1000))
-     {
-         if (GetLastError() == ERROR_FILE_NOT_FOUND)
-             errno = ESRCH;
-         else if (GetLastError() == ERROR_ACCESS_DENIED)
-             errno = EPERM;
-         else
-             errno = EINVAL;
-         return -1;
-     }
-     if (bytes != 1 || sigRet != sig)
-     {
-         errno = ESRCH;
-         return -1;
-     }
-
-     return 0;
- }
-
  /*
   * All functions below execute on the signal handler thread
   * and must be synchronized as such!
--- 152,157 ----
Index: src/include/port/win32.h
===================================================================
RCS file: /cvsroot/pgsql-server/src/include/port/win32.h,v
retrieving revision 1.23
diff -c -c -r1.23 win32.h
*** src/include/port/win32.h    22 Apr 2004 03:51:24 -0000    1.23
--- src/include/port/win32.h    27 May 2004 13:06:03 -0000
***************
*** 116,125 ****
  #define SIG_ERR ((pqsigfunc)-1)
  #define SIG_IGN ((pqsigfunc)1)

! #ifndef FRONTEND
! #define kill(pid,sig)   pqkill(pid,sig)
! extern int pqkill(int pid, int sig);

  #define pg_usleep(t) pgwin32_backend_usleep(t)
  void pgwin32_backend_usleep(long microsec);
  #endif
--- 116,125 ----
  #define SIG_ERR ((pqsigfunc)-1)
  #define SIG_IGN ((pqsigfunc)1)

! #define kill(pid,sig)   pgkill(pid,sig)
! extern int pgkill(int pid, int sig);

+ #ifndef FRONTEND
  #define pg_usleep(t) pgwin32_backend_usleep(t)
  void pgwin32_backend_usleep(long microsec);
  #endif
/*-------------------------------------------------------------------------
 *
 * kill.c
 *      kill()
 *
 * Copyright (c) 1996-2003, PostgreSQL Global Development Group
 *
 *    This is a replacement version of kill for Win32 which sends
 *    signals that the backend can recognize.
 *
 * IDENTIFICATION
 *      $PostgreSQL: pgsql-server/src/port/pipe.c,v 1.4 2004/05/18 20:18:59 momjian Exp $
 *
 *-------------------------------------------------------------------------
 */

#include "postgres.h"

#ifdef WIN32
/* signal sending */
int
pgkill(int pid, int sig)
{
    char        pipename[128];
    BYTE        sigData = sig;
    BYTE        sigRet = 0;
    DWORD        bytes;

    if (sig >= PG_SIGNAL_COUNT || sig <= 0)
    {
        errno = EINVAL;
        return -1;
    }
    if (pid <= 0)
    {
        /* No support for process groups */
        errno = EINVAL;
        return -1;
    }
    wsprintf(pipename, "\\\\.\\pipe\\pgsignal_%i", pid);
    if (!CallNamedPipe(pipename, &sigData, 1, &sigRet, 1, &bytes, 1000))
    {
        if (GetLastError() == ERROR_FILE_NOT_FOUND)
            errno = ESRCH;
        else if (GetLastError() == ERROR_ACCESS_DENIED)
            errno = EPERM;
        else
            errno = EINVAL;
        return -1;
    }
    if (bytes != 1 || sigRet != sig)
    {
        errno = ESRCH;
        return -1;
    }

    return 0;
}
#endif

Re: pg_ctl.c

From
Gaetano Mendola
Date:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Bruce Momjian wrote:

| Gaetano Mendola wrote:
|
|>Bruce Momjian wrote:
|>
|>
|>>Here is the C version of pg_ctl.c written by Andrew Dunstan and updated
|>>by me.
|>>
|>>You can use it by creating a src/bin/pg_ctl_test directory and putting
|>>the C and Makefile into that directory.  You can then do a make install
|>>and use it for testing.
|>>
|>>Unless someone finds a problem, I will apply the change soon.  This
|>>removes our last shell script!
|>
|>It desn't compile on my platform:
|>
|>$ gcc -I /usr/include/pgsql/server pg_ctl.c
|>pg_ctl.c: In function `start_postmaster':
|>pg_ctl.c:219: error: `DEVNULL' undeclared (first use in this function)
|>pg_ctl.c:219: error: (Each undeclared identifier is reported only once
|>pg_ctl.c:219: error: for each function it appears in.)
|
|
| DEVNULL is in CVS port.h.  Are you running against CVS?

No. Against 7.4.1


|>2) xstrdup protected by duplicate NULL string
|
|
| You mean that you can't pass NULL to xstrdup?  Yea, but if we do, it
| will crash and we will hear about it right away.

Yea u'r right, it will crash without know why, for the same reason you can
avoid to use the xstrdup then.



Regards
Gaetano Mendola




-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (MingW32)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org

iD8DBQFAtE3h7UpzwH2SGd4RAjDhAKDV8lRn7XEAGqHLBJzQTvrBlyJsXgCgrw5c
CljcRIysGU3+IGoVbHU9vYg=
=9jrs
-----END PGP SIGNATURE-----