]> granicus.if.org Git - postgresql/commitdiff
Change pg_ctl to be in C. This was the final shell script and is
authorBruce Momjian <bruce@momjian.us>
Thu, 27 May 2004 03:37:55 +0000 (03:37 +0000)
committerBruce Momjian <bruce@momjian.us>
Thu, 27 May 2004 03:37:55 +0000 (03:37 +0000)
helpful for the Win32 port.

Andrew Dunstan, with additions by Bruce.

src/bin/pg_ctl/Makefile
src/bin/pg_ctl/pg_ctl.c [new file with mode: 0644]
src/bin/pg_ctl/pg_ctl.sh [deleted file]

index ce541c9d0077b90dcced61ae7f6046f92dda4da3..0d011ed6435df79b723083237d836ac3a9dd35c1 100644 (file)
@@ -2,9 +2,10 @@
 #
 # Makefile for src/bin/pg_ctl
 #
-# Copyright (c) 1999, PostgreSQL Global Development Group
+# Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
+# Portions Copyright (c) 1994, Regents of the University of California
 #
-# $PostgreSQL: pgsql/src/bin/pg_ctl/Makefile,v 1.13 2003/12/23 21:56:21 tgl Exp $
+# $PostgreSQL: pgsql/src/bin/pg_ctl/Makefile,v 1.14 2004/05/27 03:37:55 momjian Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -12,23 +13,30 @@ subdir = src/bin/pg_ctl
 top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
-all: pg_ctl
+override CPPFLAGS := -DFRONTEND -DDEF_PGPORT=$(DEF_PGPORT) -I$(libpq_srcdir) $(CPPFLAGS)
 
-pg_ctl: pg_ctl.sh $(top_builddir)/src/Makefile.global
-       sed -e 's/@VERSION@/$(VERSION)/g' \
-           -e 's,@bindir@,$(bindir),g' \
-           -e 's,@DEF_PGPORT@,$(DEF_PGPORT),g' \
-         $< >$@
-       chmod a+x $@
+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_SCRIPT) pg_ctl $(DESTDIR)$(bindir)/pg_ctl
+       $(INSTALL_PROGRAM) pg_ctl$(X) $(DESTDIR)$(bindir)/pg_ctl$(X)
 
 installdirs:
        $(mkinstalldirs) $(DESTDIR)$(bindir)
 
 uninstall:
-       rm -f $(DESTDIR)$(bindir)/pg_ctl
+       rm -f $(DESTDIR)$(bindir)/pg_ctl$(X)
 
 clean distclean maintainer-clean:
-       rm -f pg_ctl
+       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
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
new file mode 100644 (file)
index 0000000..847bdf9
--- /dev/null
@@ -0,0 +1,1015 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_ctl --- start/stops/restarts the PostgreSQL server
+ *
+ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
+ *
+ * $PostgreSQL: pgsql/src/bin/pg_ctl/pg_ctl.c,v 1.1 2004/05/27 03:37:55 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);
+               }
+               if (!silence_echo)
+                       printf(_("done\n"));
+
+               printf(_("postmaster 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);
+       }
+
+       if (!silence_echo)
+               printf(_("done\n"));
+
+       printf(_("postmaster 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);
+               }
+       }
+
+       /*
+        *      'Action' can be before or after args so loop over both.
+        *      Some getopt_long() implementations will reorder argv[]
+        *      to place all flags first (GNU?), but we don't rely on it.
+        *      Our /port version doesn't do that.
+        */
+       optind = 1;
+       
+       /* process command-line options */
+       while (optind < argc)
+       {
+               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);
+                       }
+               }
+       
+               /* Process an action */
+               if (optind < argc)
+               {
+                       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);
+                       }
+                       optind++;
+               }
+       }
+       
+       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);
+}
diff --git a/src/bin/pg_ctl/pg_ctl.sh b/src/bin/pg_ctl/pg_ctl.sh
deleted file mode 100755 (executable)
index e7a8f8f..0000000
+++ /dev/null
@@ -1,412 +0,0 @@
-#! /bin/sh
-#-------------------------------------------------------------------------
-#
-# pg_ctl.sh--
-#    Start/Stop/Restart/HUP/Report status of postmaster
-#
-# Copyright (c) 2001-2003, PostgreSQL Global Development Group
-#
-#
-# IDENTIFICATION
-#    $PostgreSQL: pgsql/src/bin/pg_ctl/pg_ctl.sh,v 1.38 2004/01/10 02:55:14 momjian Exp $
-#
-#-------------------------------------------------------------------------
-
-CMDNAME=`basename $0`
-
-help="\
-$CMDNAME is a utility to start, stop, restart, reload configuration files,
-or report the status of a PostgreSQL server.
-
-Usage:
-  $CMDNAME start   [-w] [-D DATADIR] [-s] [-l FILENAME] [-o \"OPTIONS\"]
-  $CMDNAME stop    [-W] [-D DATADIR] [-s] [-m SHUTDOWN-MODE]
-  $CMDNAME restart [-w] [-D DATADIR] [-s] [-m SHUTDOWN-MODE] [-o \"OPTIONS\"]
-  $CMDNAME reload  [-D DATADIR] [-s]
-  $CMDNAME status  [-D DATADIR]
-
-Common options:
-  -D DATADIR   location of the database storage area
-  -s           only print errors, no informational messages
-  -w           wait until operation completes
-  -W           do not wait until operation completes
-  --help       show this help, then exit
-  --version    output version information, then exit
-(The default is to wait for shutdown, but not for start or restart.)
-
-If the -D option is omitted, the environment variable PGDATA is used.
-
-Options for start or restart:
-  -l FILENAME             write (or append) server log to FILENAME.  The
-                          use of this option is highly recommended.
-  -o OPTIONS              command line options to pass to the postmaster
-                          (PostgreSQL server executable)
-  -p PATH-TO-POSTMASTER   normally not necessary
-
-Options for stop or restart:
-  -m SHUTDOWN-MODE   may be 'smart', 'fast', or 'immediate'
-
-Shutdown modes are:
-  smart       quit after all clients have disconnected
-  fast        quit directly, with proper shutdown
-  immediate   quit without complete shutdown; will lead to recovery on restart
-
-Report bugs to <pgsql-bugs@postgresql.org>."
-
-advice="\
-Try \"$CMDNAME --help\" for more information."
-
-
-# Placed here during build
-bindir='@bindir@'
-VERSION='@VERSION@'
-DEF_PGPORT='@DEF_PGPORT@'
-
-# protect the log file
-umask 077
-
-# Check for echo -n vs echo \c
-
-if echo '\c' | grep -s c >/dev/null 2>&1
-then
-    ECHO_N="echo -n"
-    ECHO_C=""
-else
-    ECHO_N="echo"
-    ECHO_C='\c'
-fi
-
-#
-# Find out where we're located
-#
-if echo "$0" | grep '/' > /dev/null 2>&1 
-then
-        # explicit dir name given
-        self_path=`echo "$0" | sed 's,/[^/]*$,,'`       # (dirname command is not portable)
-else
-        # look for it in PATH ('which' command is not portable)
-        for dir in `echo "$PATH" | sed 's/:/ /g'`
-       do
-                # empty entry in path means current dir
-                [ -z "$dir" ] && dir='.'
-                if [ -f "$dir/$CMDNAME" ]
-               then
-                        self_path="$dir"
-                        break
-                fi
-        done
-fi
-
-# Check if needed programs actually exist in path
-if [ -x "$self_path/postmaster" ] && [ -x "$self_path/psql" ]; then
-    PGPATH="$self_path"
-elif [ -x "$bindir/postmaster" ] && [ -x "$bindir/psql" ]; then
-    PGPATH="$bindir"
-else
-    echo "The programs \"postmaster\" and \"psql\" are needed by $CMDNAME but" 1>&2
-    echo "were not found in the directory \"$bindir\"." 1>&2
-    echo "Check your installation." 1>&2
-    exit 1
-fi
-
-po_path="$PGPATH/postmaster"
-
-wait=
-wait_seconds=60
-logfile=
-silence_echo=
-shutdown_mode=smart
-PGDATAOPTS=""
-POSTOPTS=""
-
-while [ "$#" -gt 0 ]
-do
-    case "$1" in
-       -h|--help|-\?)
-           echo "$help"
-           exit 0
-           ;;
-        -V|--version)
-           echo "pg_ctl (PostgreSQL) $VERSION"
-           exit 0
-           ;;
-       -D)
-           shift
-           # we need to do this so -D datadir shows in ps display
-           PGDATAOPTS="-D $1"
-           PGDATA="$1"
-           export PGDATA
-           ;;
-       -l)
-           logfile="$2"
-           shift;;
-       -l*)
-           logfile=`echo "$1" | sed 's/^-l//'`
-           ;;
-       -m)
-           shutdown_mode="$2"
-           shift;;
-       -m*)
-           shutdown_mode=`echo "$1" | sed 's/^-m//'`
-           ;;
-       -o)
-           shift
-           POSTOPTS="$1"
-           ;;
-       -p)
-           shift
-           po_path="$1"
-           ;;
-       -s)
-           silence_echo=:
-           ;;
-       -w)
-           wait=yes
-           ;;
-       -W)
-           wait=no
-           ;;
-       -*)
-           echo "$CMDNAME: invalid option: $1" 1>&2
-           echo "$advice" 1>&2
-           exit 1
-           ;;
-       start)
-           op="start"
-           ;;
-       stop)
-           op="stop"
-           ;;
-       restart)
-           op="restart"
-           ;;
-       reload)
-           op="reload"
-           ;;
-       status)
-           op="status"
-           ;;
-       *)
-           echo "$CMDNAME: invalid operation mode: $1" 1>&2
-           echo "$advice" 1>&2
-           exit 1
-           ;;
-    esac
-    shift
-done
-
-if [ x"$op" = x"" ];then
-    echo "$CMDNAME: no operation mode specified" 1>&2
-    echo "$advice" 1>&2
-    exit 1
-fi
-
-if [ -z "$PGDATA" ];then
-    echo "$CMDNAME: no database directory specified and environment variable PGDATA unset" 1>&2
-    echo "$advice" 1>&2
-    exit 1
-fi
-
-if [ -z "$wait" ]; then
-    case "$op" in
-       start)      wait=no;;
-       stop)       wait=yes;;
-       restart)    wait=no;;   # must wait on shutdown anyhow
-    esac
-fi
-
-
-case "$shutdown_mode" in
-    s|smart)
-       sig="-TERM"
-       ;;
-    f|fast)
-       sig="-INT"
-       ;;
-    i|immediate)
-       sig="-QUIT"
-       ;;
-    *)
-       echo "$CMDNAME: invalid shutdown mode: $1" 1>&2
-       echo "$advice" 1>&2
-       exit 1
-       ;;
-esac
-
-if [ "$op" = "reload" ];then
-       sig="-HUP"
-       wait=no
-fi
-
-DEFPOSTOPTS=$PGDATA/postmaster.opts.default
-POSTOPTSFILE=$PGDATA/postmaster.opts
-PIDFILE=$PGDATA/postmaster.pid
-CONFFILE=$PGDATA/postgresql.conf
-
-if [ "$op" = "status" ];then
-    if [ -f "$PIDFILE" ];then
-       PID=`sed -n 1p $PIDFILE`
-       if [ "$PID" -lt 0 ];then
-           PID=`expr 0 - $PID`
-           echo "$CMDNAME: postgres is running (PID: $PID)"
-       else
-           echo "$CMDNAME: postmaster is running (PID: $PID)"
-           echo "Command line was:"
-           cat "$POSTOPTSFILE"
-       fi
-       exit 0
-    else
-       echo "$CMDNAME: postmaster or postgres not running"
-       exit 1
-    fi
-fi
-
-if [ "$op" = "stop" -o "$op" = "restart" -o "$op" = "reload" ];then
-    if [ -f "$PIDFILE" ];then
-       PID=`sed -n 1p $PIDFILE`
-       if [ "$PID" -lt 0 ];then
-           PID=`expr 0 - $PID`
-           echo "$CMDNAME: cannot restart postmaster; postgres is running (PID: $PID)" 1>&2
-           echo "Please terminate postgres and try again." 1>&2
-           exit 1
-       fi
-
-       kill "$sig" $PID
-
-       # wait for postmaster to shut down
-       if [ "$wait" = yes -o "$op" = restart ];then
-           cnt=0
-           $silence_echo $ECHO_N "waiting for postmaster to shut down..."$ECHO_C
-
-           while :
-           do
-               if [ -f "$PIDFILE" ];then
-                   $silence_echo $ECHO_N "."$ECHO_C
-                   cnt=`expr $cnt + 1`
-                   if [ "$cnt" -gt "$wait_seconds" ];then
-                       $silence_echo echo " failed"
-                       echo "$CMDNAME: postmaster does not shut down" 1>&2
-                       exit 1
-                   fi
-               else
-                   break
-               fi
-               sleep 1
-           done
-           $silence_echo echo "done"
-       fi
-
-       if [ "$op" = "reload" ];then
-           $silence_echo echo "postmaster successfully signaled"
-       else
-           if [ "$wait" = yes ];then
-               $silence_echo echo "postmaster successfully shut down"
-           else
-               $silence_echo echo "postmaster shutting down"
-           fi
-       fi
-
-    else # ! -f $PIDFILE
-       echo "$CMDNAME: could not find $PIDFILE" 1>&2
-       echo "Is postmaster running?" 1>&2
-       if [ "$op" = "restart" ];then
-           echo "starting postmaster anyway" 1>&2
-       else
-           exit 1
-       fi
-    fi
-fi # stop, restart, reload
-
-if [ "$op" = "start" -o "$op" = "restart" ];then
-    oldpid=""
-    if [ -f "$PIDFILE" ];then
-       echo "$CMDNAME: Another postmaster may be running.  Trying to start postmaster anyway." 1>&2
-       oldpid=`sed -n 1p $PIDFILE`
-    fi
-
-    # no -o given
-    if [ -z "$POSTOPTS" ];then
-       if [ "$op" = "start" ];then
-           # if we are in start mode, then look for postmaster.opts.default
-           if [ -f "$DEFPOSTOPTS" ]; then
-               eval set X "`cat $DEFPOSTOPTS`"; shift
-           fi
-       else
-           # if we are in restart mode, then look for postmaster.opts
-           eval set X "`cat $POSTOPTSFILE`"; shift
-            po_path="$1"
-            shift
-       fi
-    else # -o given
-        eval set X "$POSTOPTS"; shift
-    fi
-
-    if [ -n "$logfile" ]; then
-        "$po_path" ${1+"$@"} ${PGDATAOPTS+$PGDATAOPTS} </dev/null >>$logfile 2>&1 &
-    else
-        # when starting without log file, redirect stderr to stdout, so
-        # pg_ctl can be invoked with >$logfile and still have pg_ctl's
-        # stderr on the terminal.
-        "$po_path" ${1+"$@"} ${PGDATAOPTS+$PGDATAOPTS} </dev/null 2>&1 &
-    fi
-
-    # if had an old lockfile, check to see if we were able to start
-    if [ -n "$oldpid" ];then
-       sleep 1
-       if [ -f "$PIDFILE" ];then
-           if [ "`sed -n 1p $PIDFILE`" = "$oldpid" ];then
-               echo "$CMDNAME: cannot start postmaster" 1>&2
-               echo "Examine the log output." 1>&2
-               exit 1
-           fi
-        fi
-    fi
-
-# FIXME:  This is horribly misconceived.
-# 1) If password authentication is set up, the connection will fail.
-# 2) If a virtual host is set up, the connection may fail.
-# 3) If network traffic filters are set up tight enough, the connection
-#    may fail.
-# 4) When no Unix domain sockets are available, the connection will
-#    fail.  (Using TCP/IP by default ain't better.)
-# 5) If the dynamic loader is not set up correctly (for this user/at
-#    this time), psql will fail (to find libpq).
-# 6) If psql is misconfigured, this may fail.
-
-    # Attempt to use the right port
-    # Use PGPORT if set, otherwise look in the configuration file
-    if [ -z "$PGPORT" ];then
-        PGPORT=`sed -ne 's/^[  ]*port[^=]*=[   ]\+\([0-9]\+\).*/\1/p' $CONFFILE 2>/dev/null`
-        if [ -z "$PGPORT" ];then
-            PGPORT="$DEF_PGPORT"
-        fi
-    fi
-
-    # wait for postmaster to start
-    if [ "$wait" = yes ];then
-       cnt=0
-       $silence_echo $ECHO_N "waiting for postmaster to start..."$ECHO_C
-       while :
-       do
-           if "$PGPATH/psql" -p $PGPORT -l >/dev/null 2>&1
-           then
-               break;
-           else
-               $silence_echo $ECHO_N "."$ECHO_C
-               cnt=`expr $cnt + 1`
-               if [ "$cnt" -gt "$wait_seconds" ];then
-                   $silence_echo echo "failed"
-                   echo "$CMDNAME: postmaster does not start" 1>&2
-                   exit 1
-               fi
-               sleep 1
-           fi
-       done
-       $silence_echo echo "done"
-       $silence_echo echo "postmaster successfully started"
-    else
-       $silence_echo echo "postmaster starting"
-    fi
-fi # start or restart
-
-exit 0