From f3d6d948c7b4ef199452c33db3e8fdbb9ccacd17 Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Thu, 27 May 2004 03:37:55 +0000 Subject: [PATCH] Change pg_ctl to be in C. This was the final shell script and is helpful for the Win32 port. Andrew Dunstan, with additions by Bruce. --- src/bin/pg_ctl/Makefile | 32 +- src/bin/pg_ctl/pg_ctl.c | 1015 ++++++++++++++++++++++++++++++++++++++ src/bin/pg_ctl/pg_ctl.sh | 412 ---------------- 3 files changed, 1035 insertions(+), 424 deletions(-) create mode 100644 src/bin/pg_ctl/pg_ctl.c delete mode 100755 src/bin/pg_ctl/pg_ctl.sh diff --git a/src/bin/pg_ctl/Makefile b/src/bin/pg_ctl/Makefile index ce541c9d00..0d011ed643 100644 --- a/src/bin/pg_ctl/Makefile +++ b/src/bin/pg_ctl/Makefile @@ -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 index 0000000000..847bdf9332 --- /dev/null +++ b/src/bin/pg_ctl/pg_ctl.c @@ -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 +#include +#include +#include + +#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 .\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 index e7a8f8f297..0000000000 --- a/src/bin/pg_ctl/pg_ctl.sh +++ /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 ." - -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} >$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} &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 -- GitLab