Thread: pg_ctl.c
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
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)
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;
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
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
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
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
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 >
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 > >
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
-----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-----