Header And Logo

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

pg_ctl.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * pg_ctl --- start/stops/restarts the PostgreSQL server
00004  *
00005  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00006  *
00007  * src/bin/pg_ctl/pg_ctl.c
00008  *
00009  *-------------------------------------------------------------------------
00010  */
00011 
00012 #ifdef WIN32
00013 /*
00014  * Need this to get defines for restricted tokens and jobs. And it
00015  * has to be set before any header from the Win32 API is loaded.
00016  */
00017 #define _WIN32_WINNT 0x0501
00018 #endif
00019 
00020 #include "postgres_fe.h"
00021 #include "libpq-fe.h"
00022 
00023 #include <fcntl.h>
00024 #include <locale.h>
00025 #include <signal.h>
00026 #include <time.h>
00027 #include <sys/types.h>
00028 #include <sys/stat.h>
00029 #include <unistd.h>
00030 
00031 #ifdef HAVE_SYS_RESOURCE_H
00032 #include <sys/time.h>
00033 #include <sys/resource.h>
00034 #endif
00035 
00036 #include "getopt_long.h"
00037 #include "miscadmin.h"
00038 
00039 #if defined(__CYGWIN__)
00040 #include <sys/cygwin.h>
00041 #include <windows.h>
00042 /* Cygwin defines WIN32 in windows.h, but we don't want it. */
00043 #undef WIN32
00044 #endif
00045 
00046 /* PID can be negative for standalone backend */
00047 typedef long pgpid_t;
00048 
00049 
00050 typedef enum
00051 {
00052     SMART_MODE,
00053     FAST_MODE,
00054     IMMEDIATE_MODE
00055 } ShutdownMode;
00056 
00057 
00058 typedef enum
00059 {
00060     NO_COMMAND = 0,
00061     INIT_COMMAND,
00062     START_COMMAND,
00063     STOP_COMMAND,
00064     RESTART_COMMAND,
00065     RELOAD_COMMAND,
00066     STATUS_COMMAND,
00067     PROMOTE_COMMAND,
00068     KILL_COMMAND,
00069     REGISTER_COMMAND,
00070     UNREGISTER_COMMAND,
00071     RUN_AS_SERVICE_COMMAND
00072 } CtlCommand;
00073 
00074 #define DEFAULT_WAIT    60
00075 
00076 static bool do_wait = false;
00077 static bool wait_set = false;
00078 static int  wait_seconds = DEFAULT_WAIT;
00079 static bool silent_mode = false;
00080 static ShutdownMode shutdown_mode = SMART_MODE;
00081 static int  sig = SIGTERM;      /* default */
00082 static CtlCommand ctl_command = NO_COMMAND;
00083 static char *pg_data = NULL;
00084 static char *pg_config = NULL;
00085 static char *pgdata_opt = NULL;
00086 static char *post_opts = NULL;
00087 static const char *progname;
00088 static char *log_file = NULL;
00089 static char *exec_path = NULL;
00090 static char *register_servicename = "PostgreSQL";       /* FIXME: + version ID? */
00091 static char *register_username = NULL;
00092 static char *register_password = NULL;
00093 static char *argv0 = NULL;
00094 static bool allow_core_files = false;
00095 static time_t start_time;
00096 
00097 static char postopts_file[MAXPGPATH];
00098 static char pid_file[MAXPGPATH];
00099 static char backup_file[MAXPGPATH];
00100 static char recovery_file[MAXPGPATH];
00101 static char promote_file[MAXPGPATH];
00102 
00103 #if defined(WIN32) || defined(__CYGWIN__)
00104 static DWORD pgctl_start_type = SERVICE_AUTO_START;
00105 static SERVICE_STATUS status;
00106 static SERVICE_STATUS_HANDLE hStatus = (SERVICE_STATUS_HANDLE) 0;
00107 static HANDLE shutdownHandles[2];
00108 static pid_t postmasterPID = -1;
00109 
00110 #define shutdownEvent     shutdownHandles[0]
00111 #define postmasterProcess shutdownHandles[1]
00112 #endif
00113 
00114 
00115 static void
00116 write_stderr(const char *fmt,...)
00117 /* This extension allows gcc to check the format string for consistency with
00118    the supplied arguments. */
00119 __attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
00120 static void do_advice(void);
00121 static void do_help(void);
00122 static void set_mode(char *modeopt);
00123 static void set_sig(char *signame);
00124 static void do_init(void);
00125 static void do_start(void);
00126 static void do_stop(void);
00127 static void do_restart(void);
00128 static void do_reload(void);
00129 static void do_status(void);
00130 static void do_promote(void);
00131 static void do_kill(pgpid_t pid);
00132 static void print_msg(const char *msg);
00133 static void adjust_data_dir(void);
00134 
00135 #if defined(WIN32) || defined(__CYGWIN__)
00136 static bool pgwin32_IsInstalled(SC_HANDLE);
00137 static char *pgwin32_CommandLine(bool);
00138 static void pgwin32_doRegister(void);
00139 static void pgwin32_doUnregister(void);
00140 static void pgwin32_SetServiceStatus(DWORD);
00141 static void WINAPI pgwin32_ServiceHandler(DWORD);
00142 static void WINAPI pgwin32_ServiceMain(DWORD, LPTSTR *);
00143 static void pgwin32_doRunAsService(void);
00144 static int  CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, bool as_service);
00145 #endif
00146 
00147 static pgpid_t get_pgpid(void);
00148 static char **readfile(const char *path);
00149 static int  start_postmaster(void);
00150 static void read_post_opts(void);
00151 
00152 static PGPing test_postmaster_connection(bool);
00153 static bool postmaster_is_alive(pid_t pid);
00154 
00155 #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
00156 static void unlimit_core_size(void);
00157 #endif
00158 
00159 
00160 #if defined(WIN32) || defined(__CYGWIN__)
00161 static void
00162 write_eventlog(int level, const char *line)
00163 {
00164     static HANDLE evtHandle = INVALID_HANDLE_VALUE;
00165 
00166     if (silent_mode && level == EVENTLOG_INFORMATION_TYPE)
00167         return;
00168 
00169     if (evtHandle == INVALID_HANDLE_VALUE)
00170     {
00171         evtHandle = RegisterEventSource(NULL, "PostgreSQL");
00172         if (evtHandle == NULL)
00173         {
00174             evtHandle = INVALID_HANDLE_VALUE;
00175             return;
00176         }
00177     }
00178 
00179     ReportEvent(evtHandle,
00180                 level,
00181                 0,
00182                 0,              /* All events are Id 0 */
00183                 NULL,
00184                 1,
00185                 0,
00186                 &line,
00187                 NULL);
00188 }
00189 #endif
00190 
00191 /*
00192  * Write errors to stderr (or by equal means when stderr is
00193  * not available).
00194  */
00195 static void
00196 write_stderr(const char *fmt,...)
00197 {
00198     va_list     ap;
00199 
00200     va_start(ap, fmt);
00201 #if !defined(WIN32) && !defined(__CYGWIN__)
00202     /* On Unix, we just fprintf to stderr */
00203     vfprintf(stderr, fmt, ap);
00204 #else
00205 
00206     /*
00207      * On Win32, we print to stderr if running on a console, or write to
00208      * eventlog if running as a service
00209      */
00210     if (!isatty(fileno(stderr)))    /* Running as a service */
00211     {
00212         char        errbuf[2048];       /* Arbitrary size? */
00213 
00214         vsnprintf(errbuf, sizeof(errbuf), fmt, ap);
00215 
00216         write_eventlog(EVENTLOG_ERROR_TYPE, errbuf);
00217     }
00218     else
00219         /* Not running as service, write to stderr */
00220         vfprintf(stderr, fmt, ap);
00221 #endif
00222     va_end(ap);
00223 }
00224 
00225 /*
00226  * Given an already-localized string, print it to stdout unless the
00227  * user has specified that no messages should be printed.
00228  */
00229 static void
00230 print_msg(const char *msg)
00231 {
00232     if (!silent_mode)
00233     {
00234         fputs(msg, stdout);
00235         fflush(stdout);
00236     }
00237 }
00238 
00239 static pgpid_t
00240 get_pgpid(void)
00241 {
00242     FILE       *pidf;
00243     long        pid;
00244 
00245     pidf = fopen(pid_file, "r");
00246     if (pidf == NULL)
00247     {
00248         /* No pid file, not an error on startup */
00249         if (errno == ENOENT)
00250             return 0;
00251         else
00252         {
00253             write_stderr(_("%s: could not open PID file \"%s\": %s\n"),
00254                          progname, pid_file, strerror(errno));
00255             exit(1);
00256         }
00257     }
00258     if (fscanf(pidf, "%ld", &pid) != 1)
00259     {
00260         /* Is the file empty? */
00261         if (ftell(pidf) == 0 && feof(pidf))
00262             write_stderr(_("%s: the PID file \"%s\" is empty\n"),
00263                          progname, pid_file);
00264         else
00265             write_stderr(_("%s: invalid data in PID file \"%s\"\n"),
00266                          progname, pid_file);
00267         exit(1);
00268     }
00269     fclose(pidf);
00270     return (pgpid_t) pid;
00271 }
00272 
00273 
00274 /*
00275  * get the lines from a text file - return NULL if file can't be opened
00276  */
00277 static char **
00278 readfile(const char *path)
00279 {
00280     int         fd;
00281     int         nlines;
00282     char      **result;
00283     char       *buffer;
00284     char       *linebegin;
00285     int         i;
00286     int         n;
00287     int         len;
00288     struct stat statbuf;
00289 
00290     /*
00291      * Slurp the file into memory.
00292      *
00293      * The file can change concurrently, so we read the whole file into memory
00294      * with a single read() call. That's not guaranteed to get an atomic
00295      * snapshot, but in practice, for a small file, it's close enough for the
00296      * current use.
00297      */
00298     fd = open(path, O_RDONLY | PG_BINARY, 0);
00299     if (fd < 0)
00300         return NULL;
00301     if (fstat(fd, &statbuf) < 0)
00302     {
00303         close(fd);
00304         return NULL;
00305     }
00306     if (statbuf.st_size == 0)
00307     {
00308         /* empty file */
00309         close(fd);
00310         result = (char **) pg_malloc(sizeof(char *));
00311         *result = NULL;
00312         return result;
00313     }
00314     buffer = pg_malloc(statbuf.st_size + 1);
00315 
00316     len = read(fd, buffer, statbuf.st_size + 1);
00317     close(fd);
00318     if (len != statbuf.st_size)
00319     {
00320         /* oops, the file size changed between fstat and read */
00321         free(buffer);
00322         return NULL;
00323     }
00324 
00325     /*
00326      * Count newlines. We expect there to be a newline after each full line,
00327      * including one at the end of file. If there isn't a newline at the end,
00328      * any characters after the last newline will be ignored.
00329      */
00330     nlines = 0;
00331     for (i = 0; i < len; i++)
00332     {
00333         if (buffer[i] == '\n')
00334             nlines++;
00335     }
00336 
00337     /* set up the result buffer */
00338     result = (char **) pg_malloc((nlines + 1) * sizeof(char *));
00339 
00340     /* now split the buffer into lines */
00341     linebegin = buffer;
00342     n = 0;
00343     for (i = 0; i < len; i++)
00344     {
00345         if (buffer[i] == '\n')
00346         {
00347             int     slen = &buffer[i] - linebegin + 1;
00348             char   *linebuf = pg_malloc(slen + 1);
00349             memcpy(linebuf, linebegin, slen);
00350             linebuf[slen] = '\0';
00351             result[n++] = linebuf;
00352             linebegin = &buffer[i + 1];
00353         }
00354     }
00355     result[n] = NULL;
00356 
00357     free(buffer);
00358 
00359     return result;
00360 }
00361 
00362 
00363 
00364 /*
00365  * start/test/stop routines
00366  */
00367 
00368 static int
00369 start_postmaster(void)
00370 {
00371     char        cmd[MAXPGPATH];
00372 
00373 #ifndef WIN32
00374 
00375     /*
00376      * Since there might be quotes to handle here, it is easier simply to pass
00377      * everything to a shell to process them.
00378      *
00379      * XXX it would be better to fork and exec so that we would know the child
00380      * postmaster's PID directly; then test_postmaster_connection could use
00381      * the PID without having to rely on reading it back from the pidfile.
00382      */
00383     if (log_file != NULL)
00384         snprintf(cmd, MAXPGPATH, SYSTEMQUOTE "\"%s\" %s%s < \"%s\" >> \"%s\" 2>&1 &" SYSTEMQUOTE,
00385                  exec_path, pgdata_opt, post_opts,
00386                  DEVNULL, log_file);
00387     else
00388         snprintf(cmd, MAXPGPATH, SYSTEMQUOTE "\"%s\" %s%s < \"%s\" 2>&1 &" SYSTEMQUOTE,
00389                  exec_path, pgdata_opt, post_opts, DEVNULL);
00390 
00391     return system(cmd);
00392 #else                           /* WIN32 */
00393 
00394     /*
00395      * On win32 we don't use system(). So we don't need to use & (which would
00396      * be START /B on win32). However, we still call the shell (CMD.EXE) with
00397      * it to handle redirection etc.
00398      */
00399     PROCESS_INFORMATION pi;
00400 
00401     if (log_file != NULL)
00402         snprintf(cmd, MAXPGPATH, "CMD /C " SYSTEMQUOTE "\"%s\" %s%s < \"%s\" >> \"%s\" 2>&1" SYSTEMQUOTE,
00403                  exec_path, pgdata_opt, post_opts, DEVNULL, log_file);
00404     else
00405         snprintf(cmd, MAXPGPATH, "CMD /C " SYSTEMQUOTE "\"%s\" %s%s < \"%s\" 2>&1" SYSTEMQUOTE,
00406                  exec_path, pgdata_opt, post_opts, DEVNULL);
00407 
00408     if (!CreateRestrictedProcess(cmd, &pi, false))
00409         return GetLastError();
00410     CloseHandle(pi.hProcess);
00411     CloseHandle(pi.hThread);
00412     return 0;
00413 #endif   /* WIN32 */
00414 }
00415 
00416 
00417 
00418 /*
00419  * Find the pgport and try a connection
00420  *
00421  * Note that the checkpoint parameter enables a Windows service control
00422  * manager checkpoint, it's got nothing to do with database checkpoints!!
00423  */
00424 static PGPing
00425 test_postmaster_connection(bool do_checkpoint)
00426 {
00427     PGPing      ret = PQPING_NO_RESPONSE;
00428     bool        found_stale_pidfile = false;
00429     pgpid_t     pm_pid = 0;
00430     char        connstr[MAXPGPATH * 2 + 256];
00431     int         i;
00432 
00433     /* if requested wait time is zero, return "still starting up" code */
00434     if (wait_seconds <= 0)
00435         return PQPING_REJECT;
00436 
00437     connstr[0] = '\0';
00438 
00439     for (i = 0; i < wait_seconds; i++)
00440     {
00441         /* Do we need a connection string? */
00442         if (connstr[0] == '\0')
00443         {
00444             /*----------
00445              * The number of lines in postmaster.pid tells us several things:
00446              *
00447              * # of lines
00448              *      0   lock file created but status not written
00449              *      2   pre-9.1 server, shared memory not created
00450              *      3   pre-9.1 server, shared memory created
00451              *      5   9.1+ server, ports not opened
00452              *      6   9.1+ server, shared memory not created
00453              *      7   9.1+ server, shared memory created
00454              *
00455              * This code does not support pre-9.1 servers.  On Unix machines
00456              * we could consider extracting the port number from the shmem
00457              * key, but that (a) is not robust, and (b) doesn't help with
00458              * finding out the socket directory.  And it wouldn't work anyway
00459              * on Windows.
00460              *
00461              * If we see less than 6 lines in postmaster.pid, just keep
00462              * waiting.
00463              *----------
00464              */
00465             char      **optlines;
00466 
00467             /* Try to read the postmaster.pid file */
00468             if ((optlines = readfile(pid_file)) != NULL &&
00469                 optlines[0] != NULL &&
00470                 optlines[1] != NULL &&
00471                 optlines[2] != NULL)
00472             {
00473                 if (optlines[3] == NULL)
00474                 {
00475                     /* File is exactly three lines, must be pre-9.1 */
00476                     write_stderr(_("\n%s: -w option is not supported when starting a pre-9.1 server\n"),
00477                                  progname);
00478                     return PQPING_NO_ATTEMPT;
00479                 }
00480                 else if (optlines[4] != NULL &&
00481                          optlines[5] != NULL)
00482                 {
00483                     /* File is complete enough for us, parse it */
00484                     long        pmpid;
00485                     time_t      pmstart;
00486 
00487                     /*
00488                      * Make sanity checks.  If it's for a standalone backend
00489                      * (negative PID), or the recorded start time is before
00490                      * pg_ctl started, then either we are looking at the wrong
00491                      * data directory, or this is a pre-existing pidfile that
00492                      * hasn't (yet?) been overwritten by our child postmaster.
00493                      * Allow 2 seconds slop for possible cross-process clock
00494                      * skew.
00495                      */
00496                     pmpid = atol(optlines[LOCK_FILE_LINE_PID - 1]);
00497                     pmstart = atol(optlines[LOCK_FILE_LINE_START_TIME - 1]);
00498                     if (pmpid <= 0 || pmstart < start_time - 2)
00499                     {
00500                         /*
00501                          * Set flag to report stale pidfile if it doesn't get
00502                          * overwritten before we give up waiting.
00503                          */
00504                         found_stale_pidfile = true;
00505                     }
00506                     else
00507                     {
00508                         /*
00509                          * OK, seems to be a valid pidfile from our child.
00510                          */
00511                         int         portnum;
00512                         char       *sockdir;
00513                         char       *hostaddr;
00514                         char        host_str[MAXPGPATH];
00515 
00516                         found_stale_pidfile = false;
00517                         pm_pid = (pgpid_t) pmpid;
00518 
00519                         /*
00520                          * Extract port number and host string to use. Prefer
00521                          * using Unix socket if available.
00522                          */
00523                         portnum = atoi(optlines[LOCK_FILE_LINE_PORT - 1]);
00524                         sockdir = optlines[LOCK_FILE_LINE_SOCKET_DIR - 1];
00525                         hostaddr = optlines[LOCK_FILE_LINE_LISTEN_ADDR - 1];
00526 
00527                         /*
00528                          * While unix_socket_directories can accept relative
00529                          * directories, libpq's host parameter must have a
00530                          * leading slash to indicate a socket directory.  So,
00531                          * ignore sockdir if it's relative, and try to use TCP
00532                          * instead.
00533                          */
00534                         if (sockdir[0] == '/')
00535                             strlcpy(host_str, sockdir, sizeof(host_str));
00536                         else
00537                             strlcpy(host_str, hostaddr, sizeof(host_str));
00538 
00539                         /* remove trailing newline */
00540                         if (strchr(host_str, '\n') != NULL)
00541                             *strchr(host_str, '\n') = '\0';
00542 
00543                         /* Fail if couldn't get either sockdir or host addr */
00544                         if (host_str[0] == '\0')
00545                         {
00546                             write_stderr(_("\n%s: -w option cannot use a relative socket directory specification\n"),
00547                                          progname);
00548                             return PQPING_NO_ATTEMPT;
00549                         }
00550 
00551                         /* If postmaster is listening on "*", use localhost */
00552                         if (strcmp(host_str, "*") == 0)
00553                             strcpy(host_str, "localhost");
00554 
00555                         /*
00556                          * We need to set connect_timeout otherwise on Windows
00557                          * the Service Control Manager (SCM) will probably
00558                          * timeout first.
00559                          */
00560                         snprintf(connstr, sizeof(connstr),
00561                         "dbname=postgres port=%d host='%s' connect_timeout=5",
00562                                  portnum, host_str);
00563                     }
00564                 }
00565             }
00566         }
00567 
00568         /* If we have a connection string, ping the server */
00569         if (connstr[0] != '\0')
00570         {
00571             ret = PQping(connstr);
00572             if (ret == PQPING_OK || ret == PQPING_NO_ATTEMPT)
00573                 break;
00574         }
00575 
00576         /*
00577          * The postmaster should create postmaster.pid very soon after being
00578          * started.  If it's not there after we've waited 5 or more seconds,
00579          * assume startup failed and give up waiting.  (Note this covers both
00580          * cases where the pidfile was never created, and where it was created
00581          * and then removed during postmaster exit.)  Also, if there *is* a
00582          * file there but it appears stale, issue a suitable warning and give
00583          * up waiting.
00584          */
00585         if (i >= 5)
00586         {
00587             struct stat statbuf;
00588 
00589             if (stat(pid_file, &statbuf) != 0)
00590                 return PQPING_NO_RESPONSE;
00591 
00592             if (found_stale_pidfile)
00593             {
00594                 write_stderr(_("\n%s: this data directory appears to be running a pre-existing postmaster\n"),
00595                              progname);
00596                 return PQPING_NO_RESPONSE;
00597             }
00598         }
00599 
00600         /*
00601          * If we've been able to identify the child postmaster's PID, check
00602          * the process is still alive.  This covers cases where the postmaster
00603          * successfully created the pidfile but then crashed without removing
00604          * it.
00605          */
00606         if (pm_pid > 0 && !postmaster_is_alive((pid_t) pm_pid))
00607             return PQPING_NO_RESPONSE;
00608 
00609         /* No response, or startup still in process; wait */
00610 #if defined(WIN32)
00611         if (do_checkpoint)
00612         {
00613             /*
00614              * Increment the wait hint by 6 secs (connection timeout + sleep)
00615              * We must do this to indicate to the SCM that our startup time is
00616              * changing, otherwise it'll usually send a stop signal after 20
00617              * seconds, despite incrementing the checkpoint counter.
00618              */
00619             status.dwWaitHint += 6000;
00620             status.dwCheckPoint++;
00621             SetServiceStatus(hStatus, (LPSERVICE_STATUS) &status);
00622         }
00623         else
00624 #endif
00625             print_msg(".");
00626 
00627         pg_usleep(1000000);     /* 1 sec */
00628     }
00629 
00630     /* return result of last call to PQping */
00631     return ret;
00632 }
00633 
00634 
00635 #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
00636 static void
00637 unlimit_core_size(void)
00638 {
00639     struct rlimit lim;
00640 
00641     getrlimit(RLIMIT_CORE, &lim);
00642     if (lim.rlim_max == 0)
00643     {
00644         write_stderr(_("%s: cannot set core file size limit; disallowed by hard limit\n"),
00645                      progname);
00646         return;
00647     }
00648     else if (lim.rlim_max == RLIM_INFINITY || lim.rlim_cur < lim.rlim_max)
00649     {
00650         lim.rlim_cur = lim.rlim_max;
00651         setrlimit(RLIMIT_CORE, &lim);
00652     }
00653 }
00654 #endif
00655 
00656 static void
00657 read_post_opts(void)
00658 {
00659     if (post_opts == NULL)
00660     {
00661         post_opts = "";         /* default */
00662         if (ctl_command == RESTART_COMMAND)
00663         {
00664             char      **optlines;
00665 
00666             optlines = readfile(postopts_file);
00667             if (optlines == NULL)
00668             {
00669                 write_stderr(_("%s: could not read file \"%s\"\n"), progname, postopts_file);
00670                 exit(1);
00671             }
00672             else if (optlines[0] == NULL || optlines[1] != NULL)
00673             {
00674                 write_stderr(_("%s: option file \"%s\" must have exactly one line\n"),
00675                              progname, postopts_file);
00676                 exit(1);
00677             }
00678             else
00679             {
00680                 int         len;
00681                 char       *optline;
00682                 char       *arg1;
00683 
00684                 optline = optlines[0];
00685                 /* trim off line endings */
00686                 len = strcspn(optline, "\r\n");
00687                 optline[len] = '\0';
00688 
00689                 /*
00690                  * Are we at the first option, as defined by space and
00691                  * double-quote?
00692                  */
00693                 if ((arg1 = strstr(optline, " \"")) != NULL)
00694                 {
00695                     *arg1 = '\0';       /* terminate so we get only program
00696                                          * name */
00697                     post_opts = arg1 + 1;       /* point past whitespace */
00698                 }
00699                 if (exec_path == NULL)
00700                     exec_path = optline;
00701             }
00702         }
00703     }
00704 }
00705 
00706 static char *
00707 find_other_exec_or_die(const char *argv0, const char *target, const char *versionstr)
00708 {
00709     int         ret;
00710     char       *found_path;
00711 
00712     found_path = pg_malloc(MAXPGPATH);
00713 
00714     if ((ret = find_other_exec(argv0, target, versionstr, found_path)) < 0)
00715     {
00716         char        full_path[MAXPGPATH];
00717 
00718         if (find_my_exec(argv0, full_path) < 0)
00719             strlcpy(full_path, progname, sizeof(full_path));
00720 
00721         if (ret == -1)
00722             write_stderr(_("The program \"%s\" is needed by %s "
00723                            "but was not found in the\n"
00724                            "same directory as \"%s\".\n"
00725                            "Check your installation.\n"),
00726                          target, progname, full_path);
00727         else
00728             write_stderr(_("The program \"%s\" was found by \"%s\"\n"
00729                            "but was not the same version as %s.\n"
00730                            "Check your installation.\n"),
00731                          target, full_path, progname);
00732         exit(1);
00733     }
00734 
00735     return found_path;
00736 }
00737 
00738 static void
00739 do_init(void)
00740 {
00741     char        cmd[MAXPGPATH];
00742 
00743     if (exec_path == NULL)
00744         exec_path = find_other_exec_or_die(argv0, "initdb", "initdb (PostgreSQL) " PG_VERSION "\n");
00745 
00746     if (pgdata_opt == NULL)
00747         pgdata_opt = "";
00748 
00749     if (post_opts == NULL)
00750         post_opts = "";
00751 
00752     if (!silent_mode)
00753         snprintf(cmd, MAXPGPATH, SYSTEMQUOTE "\"%s\" %s%s" SYSTEMQUOTE,
00754                  exec_path, pgdata_opt, post_opts);
00755     else
00756         snprintf(cmd, MAXPGPATH, SYSTEMQUOTE "\"%s\" %s%s > \"%s\"" SYSTEMQUOTE,
00757                  exec_path, pgdata_opt, post_opts, DEVNULL);
00758 
00759     if (system(cmd) != 0)
00760     {
00761         write_stderr(_("%s: database system initialization failed\n"), progname);
00762         exit(1);
00763     }
00764 }
00765 
00766 static void
00767 do_start(void)
00768 {
00769     pgpid_t     old_pid = 0;
00770     int         exitcode;
00771 
00772     if (ctl_command != RESTART_COMMAND)
00773     {
00774         old_pid = get_pgpid();
00775         if (old_pid != 0)
00776             write_stderr(_("%s: another server might be running; "
00777                            "trying to start server anyway\n"),
00778                          progname);
00779     }
00780 
00781     read_post_opts();
00782 
00783     /* No -D or -D already added during server start */
00784     if (ctl_command == RESTART_COMMAND || pgdata_opt == NULL)
00785         pgdata_opt = "";
00786 
00787     if (exec_path == NULL)
00788         exec_path = find_other_exec_or_die(argv0, "postgres", PG_BACKEND_VERSIONSTR);
00789 
00790 #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
00791     if (allow_core_files)
00792         unlimit_core_size();
00793 #endif
00794 
00795     /*
00796      * If possible, tell the postmaster our parent shell's PID (see the
00797      * comments in CreateLockFile() for motivation).  Windows hasn't got
00798      * getppid() unfortunately.
00799      */
00800 #ifndef WIN32
00801     {
00802         static char env_var[32];
00803 
00804         snprintf(env_var, sizeof(env_var), "PG_GRANDPARENT_PID=%d",
00805                  (int) getppid());
00806         putenv(env_var);
00807     }
00808 #endif
00809 
00810     exitcode = start_postmaster();
00811     if (exitcode != 0)
00812     {
00813         write_stderr(_("%s: could not start server: exit code was %d\n"),
00814                      progname, exitcode);
00815         exit(1);
00816     }
00817 
00818     if (do_wait)
00819     {
00820         print_msg(_("waiting for server to start..."));
00821 
00822         switch (test_postmaster_connection(false))
00823         {
00824             case PQPING_OK:
00825                 print_msg(_(" done\n"));
00826                 print_msg(_("server started\n"));
00827                 break;
00828             case PQPING_REJECT:
00829                 print_msg(_(" stopped waiting\n"));
00830                 print_msg(_("server is still starting up\n"));
00831                 break;
00832             case PQPING_NO_RESPONSE:
00833                 print_msg(_(" stopped waiting\n"));
00834                 write_stderr(_("%s: could not start server\n"
00835                                "Examine the log output.\n"),
00836                              progname);
00837                 exit(1);
00838                 break;
00839             case PQPING_NO_ATTEMPT:
00840                 print_msg(_(" failed\n"));
00841                 write_stderr(_("%s: could not wait for server because of misconfiguration\n"),
00842                              progname);
00843                 exit(1);
00844         }
00845     }
00846     else
00847         print_msg(_("server starting\n"));
00848 }
00849 
00850 
00851 static void
00852 do_stop(void)
00853 {
00854     int         cnt;
00855     pgpid_t     pid;
00856     struct stat statbuf;
00857 
00858     pid = get_pgpid();
00859 
00860     if (pid == 0)               /* no pid file */
00861     {
00862         write_stderr(_("%s: PID file \"%s\" does not exist\n"), progname, pid_file);
00863         write_stderr(_("Is server running?\n"));
00864         exit(1);
00865     }
00866     else if (pid < 0)           /* standalone backend, not postmaster */
00867     {
00868         pid = -pid;
00869         write_stderr(_("%s: cannot stop server; "
00870                        "single-user server is running (PID: %ld)\n"),
00871                      progname, pid);
00872         exit(1);
00873     }
00874 
00875     if (kill((pid_t) pid, sig) != 0)
00876     {
00877         write_stderr(_("%s: could not send stop signal (PID: %ld): %s\n"), progname, pid,
00878                      strerror(errno));
00879         exit(1);
00880     }
00881 
00882     if (!do_wait)
00883     {
00884         print_msg(_("server shutting down\n"));
00885         return;
00886     }
00887     else
00888     {
00889         /*
00890          * If backup_label exists, an online backup is running. Warn the user
00891          * that smart shutdown will wait for it to finish. However, if
00892          * recovery.conf is also present, we're recovering from an online
00893          * backup instead of performing one.
00894          */
00895         if (shutdown_mode == SMART_MODE &&
00896             stat(backup_file, &statbuf) == 0 &&
00897             stat(recovery_file, &statbuf) != 0)
00898         {
00899             print_msg(_("WARNING: online backup mode is active\n"
00900                         "Shutdown will not complete until pg_stop_backup() is called.\n\n"));
00901         }
00902 
00903         print_msg(_("waiting for server to shut down..."));
00904 
00905         for (cnt = 0; cnt < wait_seconds; cnt++)
00906         {
00907             if ((pid = get_pgpid()) != 0)
00908             {
00909                 print_msg(".");
00910                 pg_usleep(1000000);     /* 1 sec */
00911             }
00912             else
00913                 break;
00914         }
00915 
00916         if (pid != 0)           /* pid file still exists */
00917         {
00918             print_msg(_(" failed\n"));
00919 
00920             write_stderr(_("%s: server does not shut down\n"), progname);
00921             if (shutdown_mode == SMART_MODE)
00922                 write_stderr(_("HINT: The \"-m fast\" option immediately disconnects sessions rather than\n"
00923                           "waiting for session-initiated disconnection.\n"));
00924             exit(1);
00925         }
00926         print_msg(_(" done\n"));
00927 
00928         print_msg(_("server stopped\n"));
00929     }
00930 }
00931 
00932 
00933 /*
00934  *  restart/reload routines
00935  */
00936 
00937 static void
00938 do_restart(void)
00939 {
00940     int         cnt;
00941     pgpid_t     pid;
00942     struct stat statbuf;
00943 
00944     pid = get_pgpid();
00945 
00946     if (pid == 0)               /* no pid file */
00947     {
00948         write_stderr(_("%s: PID file \"%s\" does not exist\n"),
00949                      progname, pid_file);
00950         write_stderr(_("Is server running?\n"));
00951         write_stderr(_("starting server anyway\n"));
00952         do_start();
00953         return;
00954     }
00955     else if (pid < 0)           /* standalone backend, not postmaster */
00956     {
00957         pid = -pid;
00958         if (postmaster_is_alive((pid_t) pid))
00959         {
00960             write_stderr(_("%s: cannot restart server; "
00961                            "single-user server is running (PID: %ld)\n"),
00962                          progname, pid);
00963             write_stderr(_("Please terminate the single-user server and try again.\n"));
00964             exit(1);
00965         }
00966     }
00967 
00968     if (postmaster_is_alive((pid_t) pid))
00969     {
00970         if (kill((pid_t) pid, sig) != 0)
00971         {
00972             write_stderr(_("%s: could not send stop signal (PID: %ld): %s\n"), progname, pid,
00973                          strerror(errno));
00974             exit(1);
00975         }
00976 
00977         /*
00978          * If backup_label exists, an online backup is running. Warn the user
00979          * that smart shutdown will wait for it to finish. However, if
00980          * recovery.conf is also present, we're recovering from an online
00981          * backup instead of performing one.
00982          */
00983         if (shutdown_mode == SMART_MODE &&
00984             stat(backup_file, &statbuf) == 0 &&
00985             stat(recovery_file, &statbuf) != 0)
00986         {
00987             print_msg(_("WARNING: online backup mode is active\n"
00988                         "Shutdown will not complete until pg_stop_backup() is called.\n\n"));
00989         }
00990 
00991         print_msg(_("waiting for server to shut down..."));
00992 
00993         /* always wait for restart */
00994 
00995         for (cnt = 0; cnt < wait_seconds; cnt++)
00996         {
00997             if ((pid = get_pgpid()) != 0)
00998             {
00999                 print_msg(".");
01000                 pg_usleep(1000000);     /* 1 sec */
01001             }
01002             else
01003                 break;
01004         }
01005 
01006         if (pid != 0)           /* pid file still exists */
01007         {
01008             print_msg(_(" failed\n"));
01009 
01010             write_stderr(_("%s: server does not shut down\n"), progname);
01011             if (shutdown_mode == SMART_MODE)
01012                 write_stderr(_("HINT: The \"-m fast\" option immediately disconnects sessions rather than\n"
01013                           "waiting for session-initiated disconnection.\n"));
01014             exit(1);
01015         }
01016 
01017         print_msg(_(" done\n"));
01018         print_msg(_("server stopped\n"));
01019     }
01020     else
01021     {
01022         write_stderr(_("%s: old server process (PID: %ld) seems to be gone\n"),
01023                      progname, pid);
01024         write_stderr(_("starting server anyway\n"));
01025     }
01026 
01027     do_start();
01028 }
01029 
01030 static void
01031 do_reload(void)
01032 {
01033     pgpid_t     pid;
01034 
01035     pid = get_pgpid();
01036     if (pid == 0)               /* no pid file */
01037     {
01038         write_stderr(_("%s: PID file \"%s\" does not exist\n"), progname, pid_file);
01039         write_stderr(_("Is server running?\n"));
01040         exit(1);
01041     }
01042     else if (pid < 0)           /* standalone backend, not postmaster */
01043     {
01044         pid = -pid;
01045         write_stderr(_("%s: cannot reload server; "
01046                        "single-user server is running (PID: %ld)\n"),
01047                      progname, pid);
01048         write_stderr(_("Please terminate the single-user server and try again.\n"));
01049         exit(1);
01050     }
01051 
01052     if (kill((pid_t) pid, sig) != 0)
01053     {
01054         write_stderr(_("%s: could not send reload signal (PID: %ld): %s\n"),
01055                      progname, pid, strerror(errno));
01056         exit(1);
01057     }
01058 
01059     print_msg(_("server signaled\n"));
01060 }
01061 
01062 
01063 /*
01064  * promote
01065  */
01066 
01067 static void
01068 do_promote(void)
01069 {
01070     FILE       *prmfile;
01071     pgpid_t     pid;
01072     struct stat statbuf;
01073 
01074     pid = get_pgpid();
01075 
01076     if (pid == 0)               /* no pid file */
01077     {
01078         write_stderr(_("%s: PID file \"%s\" does not exist\n"), progname, pid_file);
01079         write_stderr(_("Is server running?\n"));
01080         exit(1);
01081     }
01082     else if (pid < 0)           /* standalone backend, not postmaster */
01083     {
01084         pid = -pid;
01085         write_stderr(_("%s: cannot promote server; "
01086                        "single-user server is running (PID: %ld)\n"),
01087                      progname, pid);
01088         exit(1);
01089     }
01090 
01091     /* If recovery.conf doesn't exist, the server is not in standby mode */
01092     if (stat(recovery_file, &statbuf) != 0)
01093     {
01094         write_stderr(_("%s: cannot promote server; "
01095                        "server is not in standby mode\n"),
01096                      progname);
01097         exit(1);
01098     }
01099 
01100     /*
01101      * For 9.3 onwards, use fast promotion as the default option.
01102      * Promotion with a full checkpoint is still possible by writing
01103      * a file called "promote", e.g.
01104      *   snprintf(promote_file, MAXPGPATH, "%s/promote", pg_data);
01105      */
01106     snprintf(promote_file, MAXPGPATH, "%s/fast_promote", pg_data);
01107 
01108     if ((prmfile = fopen(promote_file, "w")) == NULL)
01109     {
01110         write_stderr(_("%s: could not create promote signal file \"%s\": %s\n"),
01111                      progname, promote_file, strerror(errno));
01112         exit(1);
01113     }
01114     if (fclose(prmfile))
01115     {
01116         write_stderr(_("%s: could not write promote signal file \"%s\": %s\n"),
01117                      progname, promote_file, strerror(errno));
01118         exit(1);
01119     }
01120 
01121     sig = SIGUSR1;
01122     if (kill((pid_t) pid, sig) != 0)
01123     {
01124         write_stderr(_("%s: could not send promote signal (PID: %ld): %s\n"),
01125                      progname, pid, strerror(errno));
01126         if (unlink(promote_file) != 0)
01127             write_stderr(_("%s: could not remove promote signal file \"%s\": %s\n"),
01128                          progname, promote_file, strerror(errno));
01129         exit(1);
01130     }
01131 
01132     print_msg(_("server promoting\n"));
01133 }
01134 
01135 
01136 /*
01137  *  utility routines
01138  */
01139 
01140 static bool
01141 postmaster_is_alive(pid_t pid)
01142 {
01143     /*
01144      * Test to see if the process is still there.  Note that we do not
01145      * consider an EPERM failure to mean that the process is still there;
01146      * EPERM must mean that the given PID belongs to some other userid, and
01147      * considering the permissions on $PGDATA, that means it's not the
01148      * postmaster we are after.
01149      *
01150      * Don't believe that our own PID or parent shell's PID is the postmaster,
01151      * either.  (Windows hasn't got getppid(), though.)
01152      */
01153     if (pid == getpid())
01154         return false;
01155 #ifndef WIN32
01156     if (pid == getppid())
01157         return false;
01158 #endif
01159     if (kill(pid, 0) == 0)
01160         return true;
01161     return false;
01162 }
01163 
01164 static void
01165 do_status(void)
01166 {
01167     pgpid_t     pid;
01168 
01169     pid = get_pgpid();
01170     /* Is there a pid file? */
01171     if (pid != 0)
01172     {
01173         /* standalone backend? */
01174         if (pid < 0)
01175         {
01176             pid = -pid;
01177             if (postmaster_is_alive((pid_t) pid))
01178             {
01179                 printf(_("%s: single-user server is running (PID: %ld)\n"),
01180                        progname, pid);
01181                 return;
01182             }
01183         }
01184         else
01185             /* must be a postmaster */
01186         {
01187             if (postmaster_is_alive((pid_t) pid))
01188             {
01189                 char      **optlines;
01190 
01191                 printf(_("%s: server is running (PID: %ld)\n"),
01192                        progname, pid);
01193 
01194                 optlines = readfile(postopts_file);
01195                 if (optlines != NULL)
01196                     for (; *optlines != NULL; optlines++)
01197                         fputs(*optlines, stdout);
01198                 return;
01199             }
01200         }
01201     }
01202     printf(_("%s: no server running\n"), progname);
01203 
01204     /*
01205      * The Linux Standard Base Core Specification 3.1 says this should return
01206      * '3'
01207      * http://refspecs.freestandards.org/LSB_3.1.1/LSB-Core-generic/LSB-Core-ge
01208      * neric/iniscrptact.html
01209      */
01210     exit(3);
01211 }
01212 
01213 
01214 
01215 static void
01216 do_kill(pgpid_t pid)
01217 {
01218     if (kill((pid_t) pid, sig) != 0)
01219     {
01220         write_stderr(_("%s: could not send signal %d (PID: %ld): %s\n"),
01221                      progname, sig, pid, strerror(errno));
01222         exit(1);
01223     }
01224 }
01225 
01226 #if defined(WIN32) || defined(__CYGWIN__)
01227 
01228 static bool
01229 pgwin32_IsInstalled(SC_HANDLE hSCM)
01230 {
01231     SC_HANDLE   hService = OpenService(hSCM, register_servicename, SERVICE_QUERY_CONFIG);
01232     bool        bResult = (hService != NULL);
01233 
01234     if (bResult)
01235         CloseServiceHandle(hService);
01236     return bResult;
01237 }
01238 
01239 static char *
01240 pgwin32_CommandLine(bool registration)
01241 {
01242     static char cmdLine[MAXPGPATH];
01243     int         ret;
01244 
01245 #ifdef __CYGWIN__
01246     char        buf[MAXPGPATH];
01247 #endif
01248 
01249     if (registration)
01250     {
01251         ret = find_my_exec(argv0, cmdLine);
01252         if (ret != 0)
01253         {
01254             write_stderr(_("%s: could not find own program executable\n"), progname);
01255             exit(1);
01256         }
01257     }
01258     else
01259     {
01260         ret = find_other_exec(argv0, "postgres", PG_BACKEND_VERSIONSTR,
01261                               cmdLine);
01262         if (ret != 0)
01263         {
01264             write_stderr(_("%s: could not find postgres program executable\n"), progname);
01265             exit(1);
01266         }
01267     }
01268 
01269 #ifdef __CYGWIN__
01270     /* need to convert to windows path */
01271 #if CYGWIN_VERSION_DLL_MAJOR >= 1007
01272     cygwin_conv_path(CCP_POSIX_TO_WIN_A, cmdLine, buf, sizeof(buf));
01273 #else
01274     cygwin_conv_to_full_win32_path(cmdLine, buf);
01275 #endif
01276     strcpy(cmdLine, buf);
01277 #endif
01278 
01279     if (registration)
01280     {
01281         if (pg_strcasecmp(cmdLine + strlen(cmdLine) - 4, ".exe") != 0)
01282         {
01283             /* If commandline does not end in .exe, append it */
01284             strcat(cmdLine, ".exe");
01285         }
01286         strcat(cmdLine, " runservice -N \"");
01287         strcat(cmdLine, register_servicename);
01288         strcat(cmdLine, "\"");
01289     }
01290 
01291     if (pg_config)
01292     {
01293         strcat(cmdLine, " -D \"");
01294         strcat(cmdLine, pg_config);
01295         strcat(cmdLine, "\"");
01296     }
01297 
01298     if (registration && do_wait)
01299         strcat(cmdLine, " -w");
01300 
01301     if (registration && wait_seconds != DEFAULT_WAIT)
01302         /* concatenate */
01303         sprintf(cmdLine + strlen(cmdLine), " -t %d", wait_seconds);
01304 
01305     if (registration && silent_mode)
01306         strcat(cmdLine, " -s");
01307 
01308     if (post_opts)
01309     {
01310         strcat(cmdLine, " ");
01311         if (registration)
01312             strcat(cmdLine, " -o \"");
01313         strcat(cmdLine, post_opts);
01314         if (registration)
01315             strcat(cmdLine, "\"");
01316     }
01317 
01318     return cmdLine;
01319 }
01320 
01321 static void
01322 pgwin32_doRegister(void)
01323 {
01324     SC_HANDLE   hService;
01325     SC_HANDLE   hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
01326 
01327     if (hSCM == NULL)
01328     {
01329         write_stderr(_("%s: could not open service manager\n"), progname);
01330         exit(1);
01331     }
01332     if (pgwin32_IsInstalled(hSCM))
01333     {
01334         CloseServiceHandle(hSCM);
01335         write_stderr(_("%s: service \"%s\" already registered\n"), progname, register_servicename);
01336         exit(1);
01337     }
01338 
01339     if ((hService = CreateService(hSCM, register_servicename, register_servicename,
01340                                SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
01341                                   pgctl_start_type, SERVICE_ERROR_NORMAL,
01342                                   pgwin32_CommandLine(true),
01343        NULL, NULL, "RPCSS\0", register_username, register_password)) == NULL)
01344     {
01345         CloseServiceHandle(hSCM);
01346         write_stderr(_("%s: could not register service \"%s\": error code %lu\n"), progname, register_servicename, GetLastError());
01347         exit(1);
01348     }
01349     CloseServiceHandle(hService);
01350     CloseServiceHandle(hSCM);
01351 }
01352 
01353 static void
01354 pgwin32_doUnregister(void)
01355 {
01356     SC_HANDLE   hService;
01357     SC_HANDLE   hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
01358 
01359     if (hSCM == NULL)
01360     {
01361         write_stderr(_("%s: could not open service manager\n"), progname);
01362         exit(1);
01363     }
01364     if (!pgwin32_IsInstalled(hSCM))
01365     {
01366         CloseServiceHandle(hSCM);
01367         write_stderr(_("%s: service \"%s\" not registered\n"), progname, register_servicename);
01368         exit(1);
01369     }
01370 
01371     if ((hService = OpenService(hSCM, register_servicename, DELETE)) == NULL)
01372     {
01373         CloseServiceHandle(hSCM);
01374         write_stderr(_("%s: could not open service \"%s\": error code %lu\n"), progname, register_servicename, GetLastError());
01375         exit(1);
01376     }
01377     if (!DeleteService(hService))
01378     {
01379         CloseServiceHandle(hService);
01380         CloseServiceHandle(hSCM);
01381         write_stderr(_("%s: could not unregister service \"%s\": error code %lu\n"), progname, register_servicename, GetLastError());
01382         exit(1);
01383     }
01384     CloseServiceHandle(hService);
01385     CloseServiceHandle(hSCM);
01386 }
01387 
01388 static void
01389 pgwin32_SetServiceStatus(DWORD currentState)
01390 {
01391     status.dwCurrentState = currentState;
01392     SetServiceStatus(hStatus, (LPSERVICE_STATUS) &status);
01393 }
01394 
01395 static void WINAPI
01396 pgwin32_ServiceHandler(DWORD request)
01397 {
01398     switch (request)
01399     {
01400         case SERVICE_CONTROL_STOP:
01401         case SERVICE_CONTROL_SHUTDOWN:
01402 
01403             /*
01404              * We only need a short wait hint here as it just needs to wait
01405              * for the next checkpoint. They occur every 5 seconds during
01406              * shutdown
01407              */
01408             status.dwWaitHint = 10000;
01409             pgwin32_SetServiceStatus(SERVICE_STOP_PENDING);
01410             SetEvent(shutdownEvent);
01411             return;
01412 
01413         case SERVICE_CONTROL_PAUSE:
01414             /* Win32 config reloading */
01415             status.dwWaitHint = 5000;
01416             kill(postmasterPID, SIGHUP);
01417             return;
01418 
01419             /* FIXME: These could be used to replace other signals etc */
01420         case SERVICE_CONTROL_CONTINUE:
01421         case SERVICE_CONTROL_INTERROGATE:
01422         default:
01423             break;
01424     }
01425 }
01426 
01427 static void WINAPI
01428 pgwin32_ServiceMain(DWORD argc, LPTSTR *argv)
01429 {
01430     PROCESS_INFORMATION pi;
01431     DWORD       ret;
01432 
01433     /* Initialize variables */
01434     status.dwWin32ExitCode = S_OK;
01435     status.dwCheckPoint = 0;
01436     status.dwWaitHint = 60000;
01437     status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
01438     status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_PAUSE_CONTINUE;
01439     status.dwServiceSpecificExitCode = 0;
01440     status.dwCurrentState = SERVICE_START_PENDING;
01441 
01442     memset(&pi, 0, sizeof(pi));
01443 
01444     read_post_opts();
01445 
01446     /* Register the control request handler */
01447     if ((hStatus = RegisterServiceCtrlHandler(register_servicename, pgwin32_ServiceHandler)) == (SERVICE_STATUS_HANDLE) 0)
01448         return;
01449 
01450     if ((shutdownEvent = CreateEvent(NULL, true, false, NULL)) == NULL)
01451         return;
01452 
01453     /* Start the postmaster */
01454     pgwin32_SetServiceStatus(SERVICE_START_PENDING);
01455     if (!CreateRestrictedProcess(pgwin32_CommandLine(false), &pi, true))
01456     {
01457         pgwin32_SetServiceStatus(SERVICE_STOPPED);
01458         return;
01459     }
01460     postmasterPID = pi.dwProcessId;
01461     postmasterProcess = pi.hProcess;
01462     CloseHandle(pi.hThread);
01463 
01464     if (do_wait)
01465     {
01466         write_eventlog(EVENTLOG_INFORMATION_TYPE, _("Waiting for server startup...\n"));
01467         if (test_postmaster_connection(true) != PQPING_OK)
01468         {
01469             write_eventlog(EVENTLOG_ERROR_TYPE, _("Timed out waiting for server startup\n"));
01470             pgwin32_SetServiceStatus(SERVICE_STOPPED);
01471             return;
01472         }
01473         write_eventlog(EVENTLOG_INFORMATION_TYPE, _("Server started and accepting connections\n"));
01474     }
01475 
01476     pgwin32_SetServiceStatus(SERVICE_RUNNING);
01477 
01478     /* Wait for quit... */
01479     ret = WaitForMultipleObjects(2, shutdownHandles, FALSE, INFINITE);
01480 
01481     pgwin32_SetServiceStatus(SERVICE_STOP_PENDING);
01482     switch (ret)
01483     {
01484         case WAIT_OBJECT_0:     /* shutdown event */
01485             kill(postmasterPID, SIGINT);
01486 
01487             /*
01488              * Increment the checkpoint and try again Abort after 12
01489              * checkpoints as the postmaster has probably hung
01490              */
01491             while (WaitForSingleObject(postmasterProcess, 5000) == WAIT_TIMEOUT && status.dwCheckPoint < 12)
01492                 status.dwCheckPoint++;
01493             break;
01494 
01495         case (WAIT_OBJECT_0 + 1):       /* postmaster went down */
01496             break;
01497 
01498         default:
01499             /* shouldn't get here? */
01500             break;
01501     }
01502 
01503     CloseHandle(shutdownEvent);
01504     CloseHandle(postmasterProcess);
01505 
01506     pgwin32_SetServiceStatus(SERVICE_STOPPED);
01507 }
01508 
01509 static void
01510 pgwin32_doRunAsService(void)
01511 {
01512     SERVICE_TABLE_ENTRY st[] = {{register_servicename, pgwin32_ServiceMain},
01513     {NULL, NULL}};
01514 
01515     if (StartServiceCtrlDispatcher(st) == 0)
01516     {
01517         write_stderr(_("%s: could not start service \"%s\": error code %lu\n"), progname, register_servicename, GetLastError());
01518         exit(1);
01519     }
01520 }
01521 
01522 
01523 /*
01524  * Mingw headers are incomplete, and so are the libraries. So we have to load
01525  * a whole lot of API functions dynamically. Since we have to do this anyway,
01526  * also load the couple of functions that *do* exist in minwg headers but not
01527  * on NT4. That way, we don't break on NT4.
01528  */
01529 typedef BOOL (WINAPI * __CreateRestrictedToken) (HANDLE, DWORD, DWORD, PSID_AND_ATTRIBUTES, DWORD, PLUID_AND_ATTRIBUTES, DWORD, PSID_AND_ATTRIBUTES, PHANDLE);
01530 typedef BOOL (WINAPI * __IsProcessInJob) (HANDLE, HANDLE, PBOOL);
01531 typedef HANDLE (WINAPI * __CreateJobObject) (LPSECURITY_ATTRIBUTES, LPCTSTR);
01532 typedef BOOL (WINAPI * __SetInformationJobObject) (HANDLE, JOBOBJECTINFOCLASS, LPVOID, DWORD);
01533 typedef BOOL (WINAPI * __AssignProcessToJobObject) (HANDLE, HANDLE);
01534 typedef BOOL (WINAPI * __QueryInformationJobObject) (HANDLE, JOBOBJECTINFOCLASS, LPVOID, DWORD, LPDWORD);
01535 
01536 /* Windows API define missing from some versions of MingW headers */
01537 #ifndef  DISABLE_MAX_PRIVILEGE
01538 #define DISABLE_MAX_PRIVILEGE   0x1
01539 #endif
01540 
01541 /*
01542  * Create a restricted token, a job object sandbox, and execute the specified
01543  * process with it.
01544  *
01545  * Returns 0 on success, non-zero on failure, same as CreateProcess().
01546  *
01547  * On NT4, or any other system not containing the required functions, will
01548  * launch the process under the current token without doing any modifications.
01549  *
01550  * NOTE! Job object will only work when running as a service, because it's
01551  * automatically destroyed when pg_ctl exits.
01552  */
01553 static int
01554 CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, bool as_service)
01555 {
01556     int         r;
01557     BOOL        b;
01558     STARTUPINFO si;
01559     HANDLE      origToken;
01560     HANDLE      restrictedToken;
01561     SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
01562     SID_AND_ATTRIBUTES dropSids[2];
01563 
01564     /* Functions loaded dynamically */
01565     __CreateRestrictedToken _CreateRestrictedToken = NULL;
01566     __IsProcessInJob _IsProcessInJob = NULL;
01567     __CreateJobObject _CreateJobObject = NULL;
01568     __SetInformationJobObject _SetInformationJobObject = NULL;
01569     __AssignProcessToJobObject _AssignProcessToJobObject = NULL;
01570     __QueryInformationJobObject _QueryInformationJobObject = NULL;
01571     HANDLE      Kernel32Handle;
01572     HANDLE      Advapi32Handle;
01573 
01574     ZeroMemory(&si, sizeof(si));
01575     si.cb = sizeof(si);
01576 
01577     Advapi32Handle = LoadLibrary("ADVAPI32.DLL");
01578     if (Advapi32Handle != NULL)
01579     {
01580         _CreateRestrictedToken = (__CreateRestrictedToken) GetProcAddress(Advapi32Handle, "CreateRestrictedToken");
01581     }
01582 
01583     if (_CreateRestrictedToken == NULL)
01584     {
01585         /*
01586          * NT4 doesn't have CreateRestrictedToken, so just call ordinary
01587          * CreateProcess
01588          */
01589         write_stderr(_("%s: WARNING: cannot create restricted tokens on this platform\n"), progname);
01590         if (Advapi32Handle != NULL)
01591             FreeLibrary(Advapi32Handle);
01592         return CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, processInfo);
01593     }
01594 
01595     /* Open the current token to use as a base for the restricted one */
01596     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &origToken))
01597     {
01598         write_stderr(_("%s: could not open process token: error code %lu\n"), progname, GetLastError());
01599         return 0;
01600     }
01601 
01602     /* Allocate list of SIDs to remove */
01603     ZeroMemory(&dropSids, sizeof(dropSids));
01604     if (!AllocateAndInitializeSid(&NtAuthority, 2,
01605          SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,
01606                                   0, &dropSids[0].Sid) ||
01607         !AllocateAndInitializeSid(&NtAuthority, 2,
01608     SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0,
01609                                   0, &dropSids[1].Sid))
01610     {
01611         write_stderr(_("%s: could not allocate SIDs: error code %lu\n"), progname, GetLastError());
01612         return 0;
01613     }
01614 
01615     b = _CreateRestrictedToken(origToken,
01616                                DISABLE_MAX_PRIVILEGE,
01617                                sizeof(dropSids) / sizeof(dropSids[0]),
01618                                dropSids,
01619                                0, NULL,
01620                                0, NULL,
01621                                &restrictedToken);
01622 
01623     FreeSid(dropSids[1].Sid);
01624     FreeSid(dropSids[0].Sid);
01625     CloseHandle(origToken);
01626     FreeLibrary(Advapi32Handle);
01627 
01628     if (!b)
01629     {
01630         write_stderr(_("%s: could not create restricted token: error code %lu\n"), progname, GetLastError());
01631         return 0;
01632     }
01633 
01634 #ifndef __CYGWIN__
01635     AddUserToTokenDacl(restrictedToken);
01636 #endif
01637 
01638     r = CreateProcessAsUser(restrictedToken, NULL, cmd, NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, NULL, &si, processInfo);
01639 
01640     Kernel32Handle = LoadLibrary("KERNEL32.DLL");
01641     if (Kernel32Handle != NULL)
01642     {
01643         _IsProcessInJob = (__IsProcessInJob) GetProcAddress(Kernel32Handle, "IsProcessInJob");
01644         _CreateJobObject = (__CreateJobObject) GetProcAddress(Kernel32Handle, "CreateJobObjectA");
01645         _SetInformationJobObject = (__SetInformationJobObject) GetProcAddress(Kernel32Handle, "SetInformationJobObject");
01646         _AssignProcessToJobObject = (__AssignProcessToJobObject) GetProcAddress(Kernel32Handle, "AssignProcessToJobObject");
01647         _QueryInformationJobObject = (__QueryInformationJobObject) GetProcAddress(Kernel32Handle, "QueryInformationJobObject");
01648     }
01649 
01650     /* Verify that we found all functions */
01651     if (_IsProcessInJob == NULL || _CreateJobObject == NULL || _SetInformationJobObject == NULL || _AssignProcessToJobObject == NULL || _QueryInformationJobObject == NULL)
01652     {
01653         /*
01654          * IsProcessInJob() is not available on < WinXP, so there is no need
01655          * to log the error every time in that case
01656          */
01657         OSVERSIONINFO osv;
01658 
01659         osv.dwOSVersionInfoSize = sizeof(osv);
01660         if (!GetVersionEx(&osv) ||      /* could not get version */
01661             (osv.dwMajorVersion == 5 && osv.dwMinorVersion > 0) ||      /* 5.1=xp, 5.2=2003, etc */
01662             osv.dwMajorVersion > 5)     /* anything newer should have the API */
01663 
01664             /*
01665              * Log error if we can't get version, or if we're on WinXP/2003 or
01666              * newer
01667              */
01668             write_stderr(_("%s: WARNING: could not locate all job object functions in system API\n"), progname);
01669     }
01670     else
01671     {
01672         BOOL        inJob;
01673 
01674         if (_IsProcessInJob(processInfo->hProcess, NULL, &inJob))
01675         {
01676             if (!inJob)
01677             {
01678                 /*
01679                  * Job objects are working, and the new process isn't in one,
01680                  * so we can create one safely. If any problems show up when
01681                  * setting it, we're going to ignore them.
01682                  */
01683                 HANDLE      job;
01684                 char        jobname[128];
01685 
01686                 sprintf(jobname, "PostgreSQL_%lu", processInfo->dwProcessId);
01687 
01688                 job = _CreateJobObject(NULL, jobname);
01689                 if (job)
01690                 {
01691                     JOBOBJECT_BASIC_LIMIT_INFORMATION basicLimit;
01692                     JOBOBJECT_BASIC_UI_RESTRICTIONS uiRestrictions;
01693                     JOBOBJECT_SECURITY_LIMIT_INFORMATION securityLimit;
01694                     OSVERSIONINFO osv;
01695 
01696                     ZeroMemory(&basicLimit, sizeof(basicLimit));
01697                     ZeroMemory(&uiRestrictions, sizeof(uiRestrictions));
01698                     ZeroMemory(&securityLimit, sizeof(securityLimit));
01699 
01700                     basicLimit.LimitFlags = JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION | JOB_OBJECT_LIMIT_PRIORITY_CLASS;
01701                     basicLimit.PriorityClass = NORMAL_PRIORITY_CLASS;
01702                     _SetInformationJobObject(job, JobObjectBasicLimitInformation, &basicLimit, sizeof(basicLimit));
01703 
01704                     uiRestrictions.UIRestrictionsClass = JOB_OBJECT_UILIMIT_DESKTOP | JOB_OBJECT_UILIMIT_DISPLAYSETTINGS |
01705                         JOB_OBJECT_UILIMIT_EXITWINDOWS | JOB_OBJECT_UILIMIT_READCLIPBOARD |
01706                         JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS | JOB_OBJECT_UILIMIT_WRITECLIPBOARD;
01707 
01708                     if (as_service)
01709                     {
01710                         osv.dwOSVersionInfoSize = sizeof(osv);
01711                         if (!GetVersionEx(&osv) ||
01712                             osv.dwMajorVersion < 6 ||
01713                         (osv.dwMajorVersion == 6 && osv.dwMinorVersion == 0))
01714                         {
01715                             /*
01716                              * On Windows 7 (and presumably later),
01717                              * JOB_OBJECT_UILIMIT_HANDLES prevents us from
01718                              * starting as a service. So we only enable it on
01719                              * Vista and earlier (version <= 6.0)
01720                              */
01721                             uiRestrictions.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_HANDLES;
01722                         }
01723                     }
01724                     _SetInformationJobObject(job, JobObjectBasicUIRestrictions, &uiRestrictions, sizeof(uiRestrictions));
01725 
01726                     securityLimit.SecurityLimitFlags = JOB_OBJECT_SECURITY_NO_ADMIN | JOB_OBJECT_SECURITY_ONLY_TOKEN;
01727                     securityLimit.JobToken = restrictedToken;
01728                     _SetInformationJobObject(job, JobObjectSecurityLimitInformation, &securityLimit, sizeof(securityLimit));
01729 
01730                     _AssignProcessToJobObject(job, processInfo->hProcess);
01731                 }
01732             }
01733         }
01734     }
01735 
01736 
01737     CloseHandle(restrictedToken);
01738 
01739     ResumeThread(processInfo->hThread);
01740 
01741     FreeLibrary(Kernel32Handle);
01742 
01743     /*
01744      * We intentionally don't close the job object handle, because we want the
01745      * object to live on until pg_ctl shuts down.
01746      */
01747     return r;
01748 }
01749 #endif
01750 
01751 static void
01752 do_advice(void)
01753 {
01754     write_stderr(_("Try \"%s --help\" for more information.\n"), progname);
01755 }
01756 
01757 
01758 
01759 static void
01760 do_help(void)
01761 {
01762     printf(_("%s is a utility to initialize, start, stop, or control a PostgreSQL server.\n\n"), progname);
01763     printf(_("Usage:\n"));
01764     printf(_("  %s init[db]               [-D DATADIR] [-s] [-o \"OPTIONS\"]\n"), progname);
01765     printf(_("  %s start   [-w] [-t SECS] [-D DATADIR] [-s] [-l FILENAME] [-o \"OPTIONS\"]\n"), progname);
01766     printf(_("  %s stop    [-W] [-t SECS] [-D DATADIR] [-s] [-m SHUTDOWN-MODE]\n"), progname);
01767     printf(_("  %s restart [-w] [-t SECS] [-D DATADIR] [-s] [-m SHUTDOWN-MODE]\n"
01768              "                 [-o \"OPTIONS\"]\n"), progname);
01769     printf(_("  %s reload  [-D DATADIR] [-s]\n"), progname);
01770     printf(_("  %s status  [-D DATADIR]\n"), progname);
01771     printf(_("  %s promote [-D DATADIR] [-s]\n"), progname);
01772     printf(_("  %s kill    SIGNALNAME PID\n"), progname);
01773 #if defined(WIN32) || defined(__CYGWIN__)
01774     printf(_("  %s register   [-N SERVICENAME] [-U USERNAME] [-P PASSWORD] [-D DATADIR]\n"
01775              "                    [-S START-TYPE] [-w] [-t SECS] [-o \"OPTIONS\"]\n"), progname);
01776     printf(_("  %s unregister [-N SERVICENAME]\n"), progname);
01777 #endif
01778 
01779     printf(_("\nCommon options:\n"));
01780     printf(_("  -D, --pgdata=DATADIR   location of the database storage area\n"));
01781     printf(_("  -s, --silent           only print errors, no informational messages\n"));
01782     printf(_("  -t, --timeout=SECS     seconds to wait when using -w option\n"));
01783     printf(_("  -V, --version          output version information, then exit\n"));
01784     printf(_("  -w                     wait until operation completes\n"));
01785     printf(_("  -W                     do not wait until operation completes\n"));
01786     printf(_("  -?, --help             show this help, then exit\n"));
01787     printf(_("(The default is to wait for shutdown, but not for start or restart.)\n\n"));
01788     printf(_("If the -D option is omitted, the environment variable PGDATA is used.\n"));
01789 
01790     printf(_("\nOptions for start or restart:\n"));
01791 #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
01792     printf(_("  -c, --core-files       allow postgres to produce core files\n"));
01793 #else
01794     printf(_("  -c, --core-files       not applicable on this platform\n"));
01795 #endif
01796     printf(_("  -l, --log=FILENAME     write (or append) server log to FILENAME\n"));
01797     printf(_("  -o OPTIONS             command line options to pass to postgres\n"
01798      "                         (PostgreSQL server executable) or initdb\n"));
01799     printf(_("  -p PATH-TO-POSTGRES    normally not necessary\n"));
01800     printf(_("\nOptions for stop, restart, or promote:\n"));
01801     printf(_("  -m, --mode=MODE        MODE can be \"smart\", \"fast\", or \"immediate\"\n"));
01802 
01803     printf(_("\nShutdown modes are:\n"));
01804     printf(_("  smart       quit after all clients have disconnected\n"));
01805     printf(_("  fast        quit directly, with proper shutdown\n"));
01806     printf(_("  immediate   quit without complete shutdown; will lead to recovery on restart\n"));
01807 
01808     printf(_("\nAllowed signal names for kill:\n"));
01809     printf("  ABRT HUP INT QUIT TERM USR1 USR2\n");
01810 
01811 #if defined(WIN32) || defined(__CYGWIN__)
01812     printf(_("\nOptions for register and unregister:\n"));
01813     printf(_("  -N SERVICENAME  service name with which to register PostgreSQL server\n"));
01814     printf(_("  -P PASSWORD     password of account to register PostgreSQL server\n"));
01815     printf(_("  -U USERNAME     user name of account to register PostgreSQL server\n"));
01816     printf(_("  -S START-TYPE   service start type to register PostgreSQL server\n"));
01817 
01818     printf(_("\nStart types are:\n"));
01819     printf(_("  auto       start service automatically during system startup (default)\n"));
01820     printf(_("  demand     start service on demand\n"));
01821 #endif
01822 
01823     printf(_("\nReport bugs to <[email protected]>.\n"));
01824 }
01825 
01826 
01827 
01828 static void
01829 set_mode(char *modeopt)
01830 {
01831     if (strcmp(modeopt, "s") == 0 || strcmp(modeopt, "smart") == 0)
01832     {
01833         shutdown_mode = SMART_MODE;
01834         sig = SIGTERM;
01835     }
01836     else if (strcmp(modeopt, "f") == 0 || strcmp(modeopt, "fast") == 0)
01837     {
01838         shutdown_mode = FAST_MODE;
01839         sig = SIGINT;
01840     }
01841     else if (strcmp(modeopt, "i") == 0 || strcmp(modeopt, "immediate") == 0)
01842     {
01843         shutdown_mode = IMMEDIATE_MODE;
01844         sig = SIGQUIT;
01845     }
01846     else
01847     {
01848         write_stderr(_("%s: unrecognized shutdown mode \"%s\"\n"), progname, modeopt);
01849         do_advice();
01850         exit(1);
01851     }
01852 }
01853 
01854 
01855 
01856 static void
01857 set_sig(char *signame)
01858 {
01859     if (strcmp(signame, "HUP") == 0)
01860         sig = SIGHUP;
01861     else if (strcmp(signame, "INT") == 0)
01862         sig = SIGINT;
01863     else if (strcmp(signame, "QUIT") == 0)
01864         sig = SIGQUIT;
01865     else if (strcmp(signame, "ABRT") == 0)
01866         sig = SIGABRT;
01867 #if 0
01868     /* probably should NOT provide SIGKILL */
01869     else if (strcmp(signame, "KILL") == 0)
01870         sig = SIGKILL;
01871 #endif
01872     else if (strcmp(signame, "TERM") == 0)
01873         sig = SIGTERM;
01874     else if (strcmp(signame, "USR1") == 0)
01875         sig = SIGUSR1;
01876     else if (strcmp(signame, "USR2") == 0)
01877         sig = SIGUSR2;
01878     else
01879     {
01880         write_stderr(_("%s: unrecognized signal name \"%s\"\n"), progname, signame);
01881         do_advice();
01882         exit(1);
01883     }
01884 }
01885 
01886 
01887 #if defined(WIN32) || defined(__CYGWIN__)
01888 static void
01889 set_starttype(char *starttypeopt)
01890 {
01891     if (strcmp(starttypeopt, "a") == 0 || strcmp(starttypeopt, "auto") == 0)
01892         pgctl_start_type = SERVICE_AUTO_START;
01893     else if (strcmp(starttypeopt, "d") == 0 || strcmp(starttypeopt, "demand") == 0)
01894         pgctl_start_type = SERVICE_DEMAND_START;
01895     else
01896     {
01897         write_stderr(_("%s: unrecognized start type \"%s\"\n"), progname, starttypeopt);
01898         do_advice();
01899         exit(1);
01900     }
01901 }
01902 #endif
01903 
01904 /*
01905  * adjust_data_dir
01906  *
01907  * If a configuration-only directory was specified, find the real data dir.
01908  */
01909 static void
01910 adjust_data_dir(void)
01911 {
01912     char        cmd[MAXPGPATH],
01913                 filename[MAXPGPATH],
01914                *my_exec_path;
01915     FILE       *fd;
01916 
01917     /* do nothing if we're working without knowledge of data dir */
01918     if (pg_config == NULL)
01919         return;
01920 
01921     /* If there is no postgresql.conf, it can't be a config-only dir */
01922     snprintf(filename, sizeof(filename), "%s/postgresql.conf", pg_config);
01923     if ((fd = fopen(filename, "r")) == NULL)
01924         return;
01925     fclose(fd);
01926 
01927     /* If PG_VERSION exists, it can't be a config-only dir */
01928     snprintf(filename, sizeof(filename), "%s/PG_VERSION", pg_config);
01929     if ((fd = fopen(filename, "r")) != NULL)
01930     {
01931         fclose(fd);
01932         return;
01933     }
01934 
01935     /* Must be a configuration directory, so find the data directory */
01936 
01937     /* we use a private my_exec_path to avoid interfering with later uses */
01938     if (exec_path == NULL)
01939         my_exec_path = find_other_exec_or_die(argv0, "postgres", PG_BACKEND_VERSIONSTR);
01940     else
01941         my_exec_path = pg_strdup(exec_path);
01942 
01943     snprintf(cmd, MAXPGPATH, SYSTEMQUOTE "\"%s\" %s%s -C data_directory" SYSTEMQUOTE,
01944              my_exec_path, pgdata_opt ? pgdata_opt : "", post_opts ?
01945              post_opts : "");
01946 
01947     fd = popen(cmd, "r");
01948     if (fd == NULL || fgets(filename, sizeof(filename), fd) == NULL)
01949     {
01950         write_stderr(_("%s: could not determine the data directory using command \"%s\"\n"), progname, cmd);
01951         exit(1);
01952     }
01953     pclose(fd);
01954     free(my_exec_path);
01955 
01956     /* Remove trailing newline */
01957     if (strchr(filename, '\n') != NULL)
01958         *strchr(filename, '\n') = '\0';
01959 
01960     free(pg_data);
01961     pg_data = pg_strdup(filename);
01962     canonicalize_path(pg_data);
01963 }
01964 
01965 
01966 int
01967 main(int argc, char **argv)
01968 {
01969     static struct option long_options[] = {
01970         {"help", no_argument, NULL, '?'},
01971         {"version", no_argument, NULL, 'V'},
01972         {"log", required_argument, NULL, 'l'},
01973         {"mode", required_argument, NULL, 'm'},
01974         {"pgdata", required_argument, NULL, 'D'},
01975         {"silent", no_argument, NULL, 's'},
01976         {"timeout", required_argument, NULL, 't'},
01977         {"core-files", no_argument, NULL, 'c'},
01978         {NULL, 0, NULL, 0}
01979     };
01980 
01981     int         option_index;
01982     int         c;
01983     pgpid_t     killproc = 0;
01984 
01985 #if defined(WIN32) || defined(__CYGWIN__)
01986     setvbuf(stderr, NULL, _IONBF, 0);
01987 #endif
01988 
01989     progname = get_progname(argv[0]);
01990     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_ctl"));
01991     start_time = time(NULL);
01992 
01993     /*
01994      * save argv[0] so do_start() can look for the postmaster if necessary. we
01995      * don't look for postmaster here because in many cases we won't need it.
01996      */
01997     argv0 = argv[0];
01998 
01999     umask(S_IRWXG | S_IRWXO);
02000 
02001     /* support --help and --version even if invoked as root */
02002     if (argc > 1)
02003     {
02004         if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 ||
02005             strcmp(argv[1], "-?") == 0)
02006         {
02007             do_help();
02008             exit(0);
02009         }
02010         else if (strcmp(argv[1], "-V") == 0 || strcmp(argv[1], "--version") == 0)
02011         {
02012             puts("pg_ctl (PostgreSQL) " PG_VERSION);
02013             exit(0);
02014         }
02015     }
02016 
02017     /*
02018      * Disallow running as root, to forestall any possible security holes.
02019      */
02020 #ifndef WIN32
02021     if (geteuid() == 0)
02022     {
02023         write_stderr(_("%s: cannot be run as root\n"
02024                        "Please log in (using, e.g., \"su\") as the "
02025                        "(unprivileged) user that will\n"
02026                        "own the server process.\n"),
02027                      progname);
02028         exit(1);
02029     }
02030 #endif
02031 
02032     /*
02033      * 'Action' can be before or after args so loop over both. Some
02034      * getopt_long() implementations will reorder argv[] to place all flags
02035      * first (GNU?), but we don't rely on it. Our /port version doesn't do
02036      * that.
02037      */
02038     optind = 1;
02039 
02040     /* process command-line options */
02041     while (optind < argc)
02042     {
02043         while ((c = getopt_long(argc, argv, "cD:l:m:N:o:p:P:sS:t:U:wW", long_options, &option_index)) != -1)
02044         {
02045             switch (c)
02046             {
02047                 case 'D':
02048                     {
02049                         char       *pgdata_D;
02050                         char       *env_var = pg_malloc(strlen(optarg) + 8);
02051 
02052                         pgdata_D = pg_strdup(optarg);
02053                         canonicalize_path(pgdata_D);
02054                         snprintf(env_var, strlen(optarg) + 8, "PGDATA=%s",
02055                                  pgdata_D);
02056                         putenv(env_var);
02057 
02058                         /*
02059                          * We could pass PGDATA just in an environment
02060                          * variable but we do -D too for clearer postmaster
02061                          * 'ps' display
02062                          */
02063                         pgdata_opt = pg_malloc(strlen(pgdata_D) + 7);
02064                         snprintf(pgdata_opt, strlen(pgdata_D) + 7,
02065                                  "-D \"%s\" ",
02066                                  pgdata_D);
02067                         break;
02068                     }
02069                 case 'l':
02070                     log_file = pg_strdup(optarg);
02071                     break;
02072                 case 'm':
02073                     set_mode(optarg);
02074                     break;
02075                 case 'N':
02076                     register_servicename = pg_strdup(optarg);
02077                     break;
02078                 case 'o':
02079                     post_opts = pg_strdup(optarg);
02080                     break;
02081                 case 'p':
02082                     exec_path = pg_strdup(optarg);
02083                     break;
02084                 case 'P':
02085                     register_password = pg_strdup(optarg);
02086                     break;
02087                 case 's':
02088                     silent_mode = true;
02089                     break;
02090                 case 'S':
02091 #if defined(WIN32) || defined(__CYGWIN__)
02092                     set_starttype(optarg);
02093 #else
02094                     write_stderr(_("%s: -S option not supported on this platform\n"),
02095                                  progname);
02096                     exit(1);
02097 #endif
02098                     break;
02099                 case 't':
02100                     wait_seconds = atoi(optarg);
02101                     break;
02102                 case 'U':
02103                     if (strchr(optarg, '\\'))
02104                         register_username = pg_strdup(optarg);
02105                     else
02106                         /* Prepend .\ for local accounts */
02107                     {
02108                         register_username = pg_malloc(strlen(optarg) + 3);
02109                         strcpy(register_username, ".\\");
02110                         strcat(register_username, optarg);
02111                     }
02112                     break;
02113                 case 'w':
02114                     do_wait = true;
02115                     wait_set = true;
02116                     break;
02117                 case 'W':
02118                     do_wait = false;
02119                     wait_set = true;
02120                     break;
02121                 case 'c':
02122                     allow_core_files = true;
02123                     break;
02124                 default:
02125                     /* getopt_long already issued a suitable error message */
02126                     do_advice();
02127                     exit(1);
02128             }
02129         }
02130 
02131         /* Process an action */
02132         if (optind < argc)
02133         {
02134             if (ctl_command != NO_COMMAND)
02135             {
02136                 write_stderr(_("%s: too many command-line arguments (first is \"%s\")\n"), progname, argv[optind]);
02137                 do_advice();
02138                 exit(1);
02139             }
02140 
02141             if (strcmp(argv[optind], "init") == 0
02142                 || strcmp(argv[optind], "initdb") == 0)
02143                 ctl_command = INIT_COMMAND;
02144             else if (strcmp(argv[optind], "start") == 0)
02145                 ctl_command = START_COMMAND;
02146             else if (strcmp(argv[optind], "stop") == 0)
02147                 ctl_command = STOP_COMMAND;
02148             else if (strcmp(argv[optind], "restart") == 0)
02149                 ctl_command = RESTART_COMMAND;
02150             else if (strcmp(argv[optind], "reload") == 0)
02151                 ctl_command = RELOAD_COMMAND;
02152             else if (strcmp(argv[optind], "status") == 0)
02153                 ctl_command = STATUS_COMMAND;
02154             else if (strcmp(argv[optind], "promote") == 0)
02155                 ctl_command = PROMOTE_COMMAND;
02156             else if (strcmp(argv[optind], "kill") == 0)
02157             {
02158                 if (argc - optind < 3)
02159                 {
02160                     write_stderr(_("%s: missing arguments for kill mode\n"), progname);
02161                     do_advice();
02162                     exit(1);
02163                 }
02164                 ctl_command = KILL_COMMAND;
02165                 set_sig(argv[++optind]);
02166                 killproc = atol(argv[++optind]);
02167             }
02168 #if defined(WIN32) || defined(__CYGWIN__)
02169             else if (strcmp(argv[optind], "register") == 0)
02170                 ctl_command = REGISTER_COMMAND;
02171             else if (strcmp(argv[optind], "unregister") == 0)
02172                 ctl_command = UNREGISTER_COMMAND;
02173             else if (strcmp(argv[optind], "runservice") == 0)
02174                 ctl_command = RUN_AS_SERVICE_COMMAND;
02175 #endif
02176             else
02177             {
02178                 write_stderr(_("%s: unrecognized operation mode \"%s\"\n"), progname, argv[optind]);
02179                 do_advice();
02180                 exit(1);
02181             }
02182             optind++;
02183         }
02184     }
02185 
02186     if (ctl_command == NO_COMMAND)
02187     {
02188         write_stderr(_("%s: no operation specified\n"), progname);
02189         do_advice();
02190         exit(1);
02191     }
02192 
02193     /* Note we put any -D switch into the env var above */
02194     pg_config = getenv("PGDATA");
02195     if (pg_config)
02196     {
02197         pg_config = pg_strdup(pg_config);
02198         canonicalize_path(pg_config);
02199         pg_data = pg_strdup(pg_config);
02200     }
02201 
02202     /* -D might point at config-only directory; if so find the real PGDATA */
02203     adjust_data_dir();
02204 
02205     /* Complain if -D needed and not provided */
02206     if (pg_config == NULL &&
02207         ctl_command != KILL_COMMAND && ctl_command != UNREGISTER_COMMAND)
02208     {
02209         write_stderr(_("%s: no database directory specified and environment variable PGDATA unset\n"),
02210                      progname);
02211         do_advice();
02212         exit(1);
02213     }
02214 
02215     if (!wait_set)
02216     {
02217         switch (ctl_command)
02218         {
02219             case RESTART_COMMAND:
02220             case START_COMMAND:
02221                 do_wait = false;
02222                 break;
02223             case STOP_COMMAND:
02224                 do_wait = true;
02225                 break;
02226             default:
02227                 break;
02228         }
02229     }
02230 
02231     if (ctl_command == RELOAD_COMMAND)
02232     {
02233         sig = SIGHUP;
02234         do_wait = false;
02235     }
02236 
02237     if (pg_data)
02238     {
02239         snprintf(postopts_file, MAXPGPATH, "%s/postmaster.opts", pg_data);
02240         snprintf(pid_file, MAXPGPATH, "%s/postmaster.pid", pg_data);
02241         snprintf(backup_file, MAXPGPATH, "%s/backup_label", pg_data);
02242         snprintf(recovery_file, MAXPGPATH, "%s/recovery.conf", pg_data);
02243     }
02244 
02245     switch (ctl_command)
02246     {
02247         case INIT_COMMAND:
02248             do_init();
02249             break;
02250         case STATUS_COMMAND:
02251             do_status();
02252             break;
02253         case START_COMMAND:
02254             do_start();
02255             break;
02256         case STOP_COMMAND:
02257             do_stop();
02258             break;
02259         case RESTART_COMMAND:
02260             do_restart();
02261             break;
02262         case RELOAD_COMMAND:
02263             do_reload();
02264             break;
02265         case PROMOTE_COMMAND:
02266             do_promote();
02267             break;
02268         case KILL_COMMAND:
02269             do_kill(killproc);
02270             break;
02271 #if defined(WIN32) || defined(__CYGWIN__)
02272         case REGISTER_COMMAND:
02273             pgwin32_doRegister();
02274             break;
02275         case UNREGISTER_COMMAND:
02276             pgwin32_doUnregister();
02277             break;
02278         case RUN_AS_SERVICE_COMMAND:
02279             pgwin32_doRunAsService();
02280             break;
02281 #endif
02282         default:
02283             break;
02284     }
02285 
02286     exit(0);
02287 }