LCOV - code coverage report
Current view: top level - src/bin/pg_ctl - pg_ctl.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13beta1 Lines: 467 705 66.2 %
Date: 2020-06-01 08:06:25 Functions: 26 28 92.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * pg_ctl --- start/stops/restarts the PostgreSQL server
       4             :  *
       5             :  * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
       6             :  *
       7             :  * src/bin/pg_ctl/pg_ctl.c
       8             :  *
       9             :  *-------------------------------------------------------------------------
      10             :  */
      11             : 
      12             : #include "postgres_fe.h"
      13             : 
      14             : #include <fcntl.h>
      15             : #include <signal.h>
      16             : #include <time.h>
      17             : #include <sys/stat.h>
      18             : #include <sys/wait.h>
      19             : #include <unistd.h>
      20             : 
      21             : #ifdef HAVE_SYS_RESOURCE_H
      22             : #include <sys/time.h>
      23             : #include <sys/resource.h>
      24             : #endif
      25             : 
      26             : #include "catalog/pg_control.h"
      27             : #include "common/controldata_utils.h"
      28             : #include "common/file_perm.h"
      29             : #include "common/logging.h"
      30             : #include "common/string.h"
      31             : #include "getopt_long.h"
      32             : #include "utils/pidfile.h"
      33             : 
      34             : #ifdef WIN32                    /* on Unix, we don't need libpq */
      35             : #include "pqexpbuffer.h"
      36             : #endif
      37             : 
      38             : /* PID can be negative for standalone backend */
      39             : typedef long pgpid_t;
      40             : 
      41             : 
      42             : typedef enum
      43             : {
      44             :     SMART_MODE,
      45             :     FAST_MODE,
      46             :     IMMEDIATE_MODE
      47             : } ShutdownMode;
      48             : 
      49             : typedef enum
      50             : {
      51             :     POSTMASTER_READY,
      52             :     POSTMASTER_STILL_STARTING,
      53             :     POSTMASTER_FAILED
      54             : } WaitPMResult;
      55             : 
      56             : typedef enum
      57             : {
      58             :     NO_COMMAND = 0,
      59             :     INIT_COMMAND,
      60             :     START_COMMAND,
      61             :     STOP_COMMAND,
      62             :     RESTART_COMMAND,
      63             :     RELOAD_COMMAND,
      64             :     STATUS_COMMAND,
      65             :     PROMOTE_COMMAND,
      66             :     LOGROTATE_COMMAND,
      67             :     KILL_COMMAND,
      68             :     REGISTER_COMMAND,
      69             :     UNREGISTER_COMMAND,
      70             :     RUN_AS_SERVICE_COMMAND
      71             : } CtlCommand;
      72             : 
      73             : #define DEFAULT_WAIT    60
      74             : 
      75             : #define USEC_PER_SEC    1000000
      76             : 
      77             : #define WAITS_PER_SEC   10      /* should divide USEC_PER_SEC evenly */
      78             : 
      79             : static bool do_wait = true;
      80             : static int  wait_seconds = DEFAULT_WAIT;
      81             : static bool wait_seconds_arg = false;
      82             : static bool silent_mode = false;
      83             : static ShutdownMode shutdown_mode = FAST_MODE;
      84             : static int  sig = SIGINT;       /* default */
      85             : static CtlCommand ctl_command = NO_COMMAND;
      86             : static char *pg_data = NULL;
      87             : static char *pg_config = NULL;
      88             : static char *pgdata_opt = NULL;
      89             : static char *post_opts = NULL;
      90             : static const char *progname;
      91             : static char *log_file = NULL;
      92             : static char *exec_path = NULL;
      93             : static char *event_source = NULL;
      94             : static char *register_servicename = "PostgreSQL"; /* FIXME: + version ID? */
      95             : static char *register_username = NULL;
      96             : static char *register_password = NULL;
      97             : static char *argv0 = NULL;
      98             : static bool allow_core_files = false;
      99             : static time_t start_time;
     100             : 
     101             : static char postopts_file[MAXPGPATH];
     102             : static char version_file[MAXPGPATH];
     103             : static char pid_file[MAXPGPATH];
     104             : static char backup_file[MAXPGPATH];
     105             : static char promote_file[MAXPGPATH];
     106             : static char logrotate_file[MAXPGPATH];
     107             : 
     108             : static volatile pgpid_t postmasterPID = -1;
     109             : 
     110             : #ifdef WIN32
     111             : static DWORD pgctl_start_type = SERVICE_AUTO_START;
     112             : static SERVICE_STATUS status;
     113             : static SERVICE_STATUS_HANDLE hStatus = (SERVICE_STATUS_HANDLE) 0;
     114             : static HANDLE shutdownHandles[2];
     115             : 
     116             : #define shutdownEvent     shutdownHandles[0]
     117             : #define postmasterProcess shutdownHandles[1]
     118             : #endif
     119             : 
     120             : 
     121             : static void write_stderr(const char *fmt,...) pg_attribute_printf(1, 2);
     122             : static void do_advice(void);
     123             : static void do_help(void);
     124             : static void set_mode(char *modeopt);
     125             : static void set_sig(char *signame);
     126             : static void do_init(void);
     127             : static void do_start(void);
     128             : static void do_stop(void);
     129             : static void do_restart(void);
     130             : static void do_reload(void);
     131             : static void do_status(void);
     132             : static void do_promote(void);
     133             : static void do_logrotate(void);
     134             : static void do_kill(pgpid_t pid);
     135             : static void print_msg(const char *msg);
     136             : static void adjust_data_dir(void);
     137             : 
     138             : #ifdef WIN32
     139             : #include <versionhelpers.h>
     140             : static bool pgwin32_IsInstalled(SC_HANDLE);
     141             : static char *pgwin32_CommandLine(bool);
     142             : static void pgwin32_doRegister(void);
     143             : static void pgwin32_doUnregister(void);
     144             : static void pgwin32_SetServiceStatus(DWORD);
     145             : static void WINAPI pgwin32_ServiceHandler(DWORD);
     146             : static void WINAPI pgwin32_ServiceMain(DWORD, LPTSTR *);
     147             : static void pgwin32_doRunAsService(void);
     148             : static int  CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, bool as_service);
     149             : static PTOKEN_PRIVILEGES GetPrivilegesToDelete(HANDLE hToken);
     150             : #endif
     151             : 
     152             : static pgpid_t get_pgpid(bool is_status_request);
     153             : static char **readfile(const char *path, int *numlines);
     154             : static void free_readfile(char **optlines);
     155             : static pgpid_t start_postmaster(void);
     156             : static void read_post_opts(void);
     157             : 
     158             : static WaitPMResult wait_for_postmaster(pgpid_t pm_pid, bool do_checkpoint);
     159             : static bool postmaster_is_alive(pid_t pid);
     160             : 
     161             : #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
     162             : static void unlimit_core_size(void);
     163             : #endif
     164             : 
     165             : static DBState get_control_dbstate(void);
     166             : 
     167             : 
     168             : #ifdef WIN32
     169             : static void
     170             : write_eventlog(int level, const char *line)
     171             : {
     172             :     static HANDLE evtHandle = INVALID_HANDLE_VALUE;
     173             : 
     174             :     if (silent_mode && level == EVENTLOG_INFORMATION_TYPE)
     175             :         return;
     176             : 
     177             :     if (evtHandle == INVALID_HANDLE_VALUE)
     178             :     {
     179             :         evtHandle = RegisterEventSource(NULL,
     180             :                                         event_source ? event_source : DEFAULT_EVENT_SOURCE);
     181             :         if (evtHandle == NULL)
     182             :         {
     183             :             evtHandle = INVALID_HANDLE_VALUE;
     184             :             return;
     185             :         }
     186             :     }
     187             : 
     188             :     ReportEvent(evtHandle,
     189             :                 level,
     190             :                 0,
     191             :                 0,              /* All events are Id 0 */
     192             :                 NULL,
     193             :                 1,
     194             :                 0,
     195             :                 &line,
     196             :                 NULL);
     197             : }
     198             : #endif
     199             : 
     200             : /*
     201             :  * Write errors to stderr (or by equal means when stderr is
     202             :  * not available).
     203             :  */
     204             : static void
     205          56 : write_stderr(const char *fmt,...)
     206             : {
     207             :     va_list     ap;
     208             : 
     209          56 :     va_start(ap, fmt);
     210             : #ifndef WIN32
     211             :     /* On Unix, we just fprintf to stderr */
     212          56 :     vfprintf(stderr, fmt, ap);
     213             : #else
     214             : 
     215             :     /*
     216             :      * On Win32, we print to stderr if running on a console, or write to
     217             :      * eventlog if running as a service
     218             :      */
     219             :     if (pgwin32_is_service())   /* Running as a service */
     220             :     {
     221             :         char        errbuf[2048];   /* Arbitrary size? */
     222             : 
     223             :         vsnprintf(errbuf, sizeof(errbuf), fmt, ap);
     224             : 
     225             :         write_eventlog(EVENTLOG_ERROR_TYPE, errbuf);
     226             :     }
     227             :     else
     228             :         /* Not running as service, write to stderr */
     229             :         vfprintf(stderr, fmt, ap);
     230             : #endif
     231          56 :     va_end(ap);
     232          56 : }
     233             : 
     234             : /*
     235             :  * Given an already-localized string, print it to stdout unless the
     236             :  * user has specified that no messages should be printed.
     237             :  */
     238             : static void
     239        5440 : print_msg(const char *msg)
     240             : {
     241        5440 :     if (!silent_mode)
     242             :     {
     243        4912 :         fputs(msg, stdout);
     244        4912 :         fflush(stdout);
     245             :     }
     246        5440 : }
     247             : 
     248             : static pgpid_t
     249        3238 : get_pgpid(bool is_status_request)
     250             : {
     251             :     FILE       *pidf;
     252             :     long        pid;
     253             :     struct stat statbuf;
     254             : 
     255        3238 :     if (stat(pg_data, &statbuf) != 0)
     256             :     {
     257           6 :         if (errno == ENOENT)
     258           6 :             write_stderr(_("%s: directory \"%s\" does not exist\n"), progname,
     259             :                          pg_data);
     260             :         else
     261           0 :             write_stderr(_("%s: could not access directory \"%s\": %s\n"), progname,
     262           0 :                          pg_data, strerror(errno));
     263             : 
     264             :         /*
     265             :          * The Linux Standard Base Core Specification 3.1 says this should
     266             :          * return '4, program or service status is unknown'
     267             :          * https://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html
     268             :          */
     269           6 :         exit(is_status_request ? 4 : 1);
     270             :     }
     271             : 
     272        3232 :     if (stat(version_file, &statbuf) != 0 && errno == ENOENT)
     273             :     {
     274           0 :         write_stderr(_("%s: directory \"%s\" is not a database cluster directory\n"),
     275             :                      progname, pg_data);
     276           0 :         exit(is_status_request ? 4 : 1);
     277             :     }
     278             : 
     279        3232 :     pidf = fopen(pid_file, "r");
     280        3232 :     if (pidf == NULL)
     281             :     {
     282             :         /* No pid file, not an error on startup */
     283        1220 :         if (errno == ENOENT)
     284        1220 :             return 0;
     285             :         else
     286             :         {
     287           0 :             write_stderr(_("%s: could not open PID file \"%s\": %s\n"),
     288           0 :                          progname, pid_file, strerror(errno));
     289           0 :             exit(1);
     290             :         }
     291             :     }
     292        2012 :     if (fscanf(pidf, "%ld", &pid) != 1)
     293             :     {
     294             :         /* Is the file empty? */
     295           0 :         if (ftell(pidf) == 0 && feof(pidf))
     296           0 :             write_stderr(_("%s: the PID file \"%s\" is empty\n"),
     297             :                          progname, pid_file);
     298             :         else
     299           0 :             write_stderr(_("%s: invalid data in PID file \"%s\"\n"),
     300             :                          progname, pid_file);
     301           0 :         exit(1);
     302             :     }
     303        2012 :     fclose(pidf);
     304        2012 :     return (pgpid_t) pid;
     305             : }
     306             : 
     307             : 
     308             : /*
     309             :  * get the lines from a text file - return NULL if file can't be opened
     310             :  *
     311             :  * Trailing newlines are deleted from the lines (this is a change from pre-v10)
     312             :  *
     313             :  * *numlines is set to the number of line pointers returned; there is
     314             :  * also an additional NULL pointer after the last real line.
     315             :  */
     316             : static char **
     317        2820 : readfile(const char *path, int *numlines)
     318             : {
     319             :     int         fd;
     320             :     int         nlines;
     321             :     char      **result;
     322             :     char       *buffer;
     323             :     char       *linebegin;
     324             :     int         i;
     325             :     int         n;
     326             :     int         len;
     327             :     struct stat statbuf;
     328             : 
     329        2820 :     *numlines = 0;              /* in case of failure or empty file */
     330             : 
     331             :     /*
     332             :      * Slurp the file into memory.
     333             :      *
     334             :      * The file can change concurrently, so we read the whole file into memory
     335             :      * with a single read() call. That's not guaranteed to get an atomic
     336             :      * snapshot, but in practice, for a small file, it's close enough for the
     337             :      * current use.
     338             :      */
     339        2820 :     fd = open(path, O_RDONLY | PG_BINARY, 0);
     340        2820 :     if (fd < 0)
     341         604 :         return NULL;
     342        2216 :     if (fstat(fd, &statbuf) < 0)
     343             :     {
     344           0 :         close(fd);
     345           0 :         return NULL;
     346             :     }
     347        2216 :     if (statbuf.st_size == 0)
     348             :     {
     349             :         /* empty file */
     350           0 :         close(fd);
     351           0 :         result = (char **) pg_malloc(sizeof(char *));
     352           0 :         *result = NULL;
     353           0 :         return result;
     354             :     }
     355        2216 :     buffer = pg_malloc(statbuf.st_size + 1);
     356             : 
     357        2216 :     len = read(fd, buffer, statbuf.st_size + 1);
     358        2216 :     close(fd);
     359        2216 :     if (len != statbuf.st_size)
     360             :     {
     361             :         /* oops, the file size changed between fstat and read */
     362           0 :         free(buffer);
     363           0 :         return NULL;
     364             :     }
     365             : 
     366             :     /*
     367             :      * Count newlines. We expect there to be a newline after each full line,
     368             :      * including one at the end of file. If there isn't a newline at the end,
     369             :      * any characters after the last newline will be ignored.
     370             :      */
     371        2216 :     nlines = 0;
     372      363610 :     for (i = 0; i < len; i++)
     373             :     {
     374      361394 :         if (buffer[i] == '\n')
     375       17080 :             nlines++;
     376             :     }
     377             : 
     378             :     /* set up the result buffer */
     379        2216 :     result = (char **) pg_malloc((nlines + 1) * sizeof(char *));
     380        2216 :     *numlines = nlines;
     381             : 
     382             :     /* now split the buffer into lines */
     383        2216 :     linebegin = buffer;
     384        2216 :     n = 0;
     385      363610 :     for (i = 0; i < len; i++)
     386             :     {
     387      361394 :         if (buffer[i] == '\n')
     388             :         {
     389       17080 :             int         slen = &buffer[i] - linebegin;
     390       17080 :             char       *linebuf = pg_malloc(slen + 1);
     391             : 
     392       17080 :             memcpy(linebuf, linebegin, slen);
     393             :             /* we already dropped the \n, but get rid of any \r too */
     394       17080 :             if (slen > 0 && linebuf[slen - 1] == '\r')
     395           0 :                 slen--;
     396       17080 :             linebuf[slen] = '\0';
     397       17080 :             result[n++] = linebuf;
     398       17080 :             linebegin = &buffer[i + 1];
     399             :         }
     400             :     }
     401        2216 :     result[n] = NULL;
     402             : 
     403        2216 :     free(buffer);
     404             : 
     405        2216 :     return result;
     406             : }
     407             : 
     408             : 
     409             : /*
     410             :  * Free memory allocated for optlines through readfile()
     411             :  */
     412             : static void
     413        2820 : free_readfile(char **optlines)
     414             : {
     415        2820 :     char       *curr_line = NULL;
     416        2820 :     int         i = 0;
     417             : 
     418        2820 :     if (!optlines)
     419         604 :         return;
     420             : 
     421       19296 :     while ((curr_line = optlines[i++]))
     422       17080 :         free(curr_line);
     423             : 
     424        2216 :     free(optlines);
     425             : }
     426             : 
     427             : /*
     428             :  * start/test/stop routines
     429             :  */
     430             : 
     431             : /*
     432             :  * Start the postmaster and return its PID.
     433             :  *
     434             :  * Currently, on Windows what we return is the PID of the shell process
     435             :  * that launched the postmaster (and, we trust, is waiting for it to exit).
     436             :  * So the PID is usable for "is the postmaster still running" checks,
     437             :  * but cannot be compared directly to postmaster.pid.
     438             :  *
     439             :  * On Windows, we also save aside a handle to the shell process in
     440             :  * "postmasterProcess", which the caller should close when done with it.
     441             :  */
     442             : static pgpid_t
     443         596 : start_postmaster(void)
     444             : {
     445             :     char        cmd[MAXPGPATH];
     446             : 
     447             : #ifndef WIN32
     448             :     pgpid_t     pm_pid;
     449             : 
     450             :     /* Flush stdio channels just before fork, to avoid double-output problems */
     451         596 :     fflush(stdout);
     452         596 :     fflush(stderr);
     453             : 
     454         596 :     pm_pid = fork();
     455        1192 :     if (pm_pid < 0)
     456             :     {
     457             :         /* fork failed */
     458           0 :         write_stderr(_("%s: could not start server: %s\n"),
     459           0 :                      progname, strerror(errno));
     460           0 :         exit(1);
     461             :     }
     462        1192 :     if (pm_pid > 0)
     463             :     {
     464             :         /* fork succeeded, in parent */
     465         596 :         return pm_pid;
     466             :     }
     467             : 
     468             :     /* fork succeeded, in child */
     469             : 
     470             :     /*
     471             :      * If possible, detach the postmaster process from the launching process
     472             :      * group and make it a group leader, so that it doesn't get signaled along
     473             :      * with the current group that launched it.
     474             :      */
     475             : #ifdef HAVE_SETSID
     476         596 :     if (setsid() < 0)
     477             :     {
     478           0 :         write_stderr(_("%s: could not start server due to setsid() failure: %s\n"),
     479           0 :                      progname, strerror(errno));
     480           0 :         exit(1);
     481             :     }
     482             : #endif
     483             : 
     484             :     /*
     485             :      * Since there might be quotes to handle here, it is easier simply to pass
     486             :      * everything to a shell to process them.  Use exec so that the postmaster
     487             :      * has the same PID as the current child process.
     488             :      */
     489         596 :     if (log_file != NULL)
     490         586 :         snprintf(cmd, MAXPGPATH, "exec \"%s\" %s%s < \"%s\" >> \"%s\" 2>&1",
     491             :                  exec_path, pgdata_opt, post_opts,
     492             :                  DEVNULL, log_file);
     493             :     else
     494          10 :         snprintf(cmd, MAXPGPATH, "exec \"%s\" %s%s < \"%s\" 2>&1",
     495             :                  exec_path, pgdata_opt, post_opts, DEVNULL);
     496             : 
     497         596 :     (void) execl("/bin/sh", "/bin/sh", "-c", cmd, (char *) NULL);
     498             : 
     499             :     /* exec failed */
     500           0 :     write_stderr(_("%s: could not start server: %s\n"),
     501         596 :                  progname, strerror(errno));
     502           0 :     exit(1);
     503             : 
     504             :     return 0;                   /* keep dumb compilers quiet */
     505             : 
     506             : #else                           /* WIN32 */
     507             : 
     508             :     /*
     509             :      * As with the Unix case, it's easiest to use the shell (CMD.EXE) to
     510             :      * handle redirection etc.  Unfortunately CMD.EXE lacks any equivalent of
     511             :      * "exec", so we don't get to find out the postmaster's PID immediately.
     512             :      */
     513             :     PROCESS_INFORMATION pi;
     514             :     const char *comspec;
     515             : 
     516             :     /* Find CMD.EXE location using COMSPEC, if it's set */
     517             :     comspec = getenv("COMSPEC");
     518             :     if (comspec == NULL)
     519             :         comspec = "CMD";
     520             : 
     521             :     if (log_file != NULL)
     522             :     {
     523             :         /*
     524             :          * First, open the log file if it exists.  The idea is that if the
     525             :          * file is still locked by a previous postmaster run, we'll wait until
     526             :          * it comes free, instead of failing with ERROR_SHARING_VIOLATION.
     527             :          * (It'd be better to open the file in a sharing-friendly mode, but we
     528             :          * can't use CMD.EXE to do that, so work around it.  Note that the
     529             :          * previous postmaster will still have the file open for a short time
     530             :          * after removing postmaster.pid.)
     531             :          *
     532             :          * If the log file doesn't exist, we *must not* create it here.  If we
     533             :          * were launched with higher privileges than the restricted process
     534             :          * will have, the log file might end up with permissions settings that
     535             :          * prevent the postmaster from writing on it.
     536             :          */
     537             :         int         fd = open(log_file, O_RDWR, 0);
     538             : 
     539             :         if (fd == -1)
     540             :         {
     541             :             /*
     542             :              * ENOENT is expectable since we didn't use O_CREAT.  Otherwise
     543             :              * complain.  We could just fall through and let CMD.EXE report
     544             :              * the problem, but its error reporting is pretty miserable.
     545             :              */
     546             :             if (errno != ENOENT)
     547             :             {
     548             :                 write_stderr(_("%s: could not open log file \"%s\": %s\n"),
     549             :                              progname, log_file, strerror(errno));
     550             :                 exit(1);
     551             :             }
     552             :         }
     553             :         else
     554             :             close(fd);
     555             : 
     556             :         snprintf(cmd, MAXPGPATH, "\"%s\" /C \"\"%s\" %s%s < \"%s\" >> \"%s\" 2>&1\"",
     557             :                  comspec, exec_path, pgdata_opt, post_opts, DEVNULL, log_file);
     558             :     }
     559             :     else
     560             :         snprintf(cmd, MAXPGPATH, "\"%s\" /C \"\"%s\" %s%s < \"%s\" 2>&1\"",
     561             :                  comspec, exec_path, pgdata_opt, post_opts, DEVNULL);
     562             : 
     563             :     if (!CreateRestrictedProcess(cmd, &pi, false))
     564             :     {
     565             :         write_stderr(_("%s: could not start server: error code %lu\n"),
     566             :                      progname, (unsigned long) GetLastError());
     567             :         exit(1);
     568             :     }
     569             :     /* Don't close command process handle here; caller must do so */
     570             :     postmasterProcess = pi.hProcess;
     571             :     CloseHandle(pi.hThread);
     572             :     return pi.dwProcessId;      /* Shell's PID, not postmaster's! */
     573             : #endif                          /* WIN32 */
     574             : }
     575             : 
     576             : 
     577             : 
     578             : /*
     579             :  * Wait for the postmaster to become ready.
     580             :  *
     581             :  * On Unix, pm_pid is the PID of the just-launched postmaster.  On Windows,
     582             :  * it may be the PID of an ancestor shell process, so we can't check the
     583             :  * contents of postmaster.pid quite as carefully.
     584             :  *
     585             :  * On Windows, the static variable postmasterProcess is an implicit argument
     586             :  * to this routine; it contains a handle to the postmaster process or an
     587             :  * ancestor shell process thereof.
     588             :  *
     589             :  * Note that the checkpoint parameter enables a Windows service control
     590             :  * manager checkpoint, it's got nothing to do with database checkpoints!!
     591             :  */
     592             : static WaitPMResult
     593         596 : wait_for_postmaster(pgpid_t pm_pid, bool do_checkpoint)
     594             : {
     595             :     int         i;
     596             : 
     597        2728 :     for (i = 0; i < wait_seconds * WAITS_PER_SEC; i++)
     598             :     {
     599             :         char      **optlines;
     600             :         int         numlines;
     601             : 
     602             :         /*
     603             :          * Try to read the postmaster.pid file.  If it's not valid, or if the
     604             :          * status line isn't there yet, just keep waiting.
     605             :          */
     606        2728 :         if ((optlines = readfile(pid_file, &numlines)) != NULL &&
     607        2124 :             numlines >= LOCK_FILE_LINE_PM_STATUS)
     608             :         {
     609             :             /* File is complete enough for us, parse it */
     610             :             pgpid_t     pmpid;
     611             :             time_t      pmstart;
     612             : 
     613             :             /*
     614             :              * Make sanity checks.  If it's for the wrong PID, or the recorded
     615             :              * start time is before pg_ctl started, then either we are looking
     616             :              * at the wrong data directory, or this is a pre-existing pidfile
     617             :              * that hasn't (yet?) been overwritten by our child postmaster.
     618             :              * Allow 2 seconds slop for possible cross-process clock skew.
     619             :              */
     620        2120 :             pmpid = atol(optlines[LOCK_FILE_LINE_PID - 1]);
     621        2120 :             pmstart = atol(optlines[LOCK_FILE_LINE_START_TIME - 1]);
     622        2120 :             if (pmstart >= start_time - 2 &&
     623             : #ifndef WIN32
     624             :                 pmpid == pm_pid
     625             : #else
     626             :             /* Windows can only reject standalone-backend PIDs */
     627             :                 pmpid > 0
     628             : #endif
     629             :                 )
     630             :             {
     631             :                 /*
     632             :                  * OK, seems to be a valid pidfile from our child.  Check the
     633             :                  * status line (this assumes a v10 or later server).
     634             :                  */
     635        2112 :                 char       *pmstatus = optlines[LOCK_FILE_LINE_PM_STATUS - 1];
     636             : 
     637        2112 :                 if (strcmp(pmstatus, PM_STATUS_READY) == 0 ||
     638        1530 :                     strcmp(pmstatus, PM_STATUS_STANDBY) == 0)
     639             :                 {
     640             :                     /* postmaster is done starting up */
     641         582 :                     free_readfile(optlines);
     642         596 :                     return POSTMASTER_READY;
     643             :                 }
     644             :             }
     645             :         }
     646             : 
     647             :         /*
     648             :          * Free the results of readfile.
     649             :          *
     650             :          * This is safe to call even if optlines is NULL.
     651             :          */
     652        2146 :         free_readfile(optlines);
     653             : 
     654             :         /*
     655             :          * Check whether the child postmaster process is still alive.  This
     656             :          * lets us exit early if the postmaster fails during startup.
     657             :          *
     658             :          * On Windows, we may be checking the postmaster's parent shell, but
     659             :          * that's fine for this purpose.
     660             :          */
     661             : #ifndef WIN32
     662             :         {
     663             :             int         exitstatus;
     664             : 
     665        2146 :             if (waitpid((pid_t) pm_pid, &exitstatus, WNOHANG) == (pid_t) pm_pid)
     666          14 :                 return POSTMASTER_FAILED;
     667             :         }
     668             : #else
     669             :         if (WaitForSingleObject(postmasterProcess, 0) == WAIT_OBJECT_0)
     670             :             return POSTMASTER_FAILED;
     671             : #endif
     672             : 
     673             :         /* Startup still in process; wait, printing a dot once per second */
     674        2132 :         if (i % WAITS_PER_SEC == 0)
     675             :         {
     676             : #ifdef WIN32
     677             :             if (do_checkpoint)
     678             :             {
     679             :                 /*
     680             :                  * Increment the wait hint by 6 secs (connection timeout +
     681             :                  * sleep).  We must do this to indicate to the SCM that our
     682             :                  * startup time is changing, otherwise it'll usually send a
     683             :                  * stop signal after 20 seconds, despite incrementing the
     684             :                  * checkpoint counter.
     685             :                  */
     686             :                 status.dwWaitHint += 6000;
     687             :                 status.dwCheckPoint++;
     688             :                 SetServiceStatus(hStatus, (LPSERVICE_STATUS) &status);
     689             :             }
     690             :             else
     691             : #endif
     692         596 :                 print_msg(".");
     693             :         }
     694             : 
     695        2132 :         pg_usleep(USEC_PER_SEC / WAITS_PER_SEC);
     696             :     }
     697             : 
     698             :     /* out of patience; report that postmaster is still starting up */
     699           0 :     return POSTMASTER_STILL_STARTING;
     700             : }
     701             : 
     702             : 
     703             : #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
     704             : static void
     705           0 : unlimit_core_size(void)
     706             : {
     707             :     struct rlimit lim;
     708             : 
     709           0 :     getrlimit(RLIMIT_CORE, &lim);
     710           0 :     if (lim.rlim_max == 0)
     711             :     {
     712           0 :         write_stderr(_("%s: cannot set core file size limit; disallowed by hard limit\n"),
     713             :                      progname);
     714           0 :         return;
     715             :     }
     716           0 :     else if (lim.rlim_max == RLIM_INFINITY || lim.rlim_cur < lim.rlim_max)
     717             :     {
     718           0 :         lim.rlim_cur = lim.rlim_max;
     719           0 :         setrlimit(RLIMIT_CORE, &lim);
     720             :     }
     721             : }
     722             : #endif
     723             : 
     724             : static void
     725         596 : read_post_opts(void)
     726             : {
     727         596 :     if (post_opts == NULL)
     728             :     {
     729         110 :         post_opts = "";           /* default */
     730         110 :         if (ctl_command == RESTART_COMMAND)
     731             :         {
     732             :             char      **optlines;
     733             :             int         numlines;
     734             : 
     735          90 :             optlines = readfile(postopts_file, &numlines);
     736          90 :             if (optlines == NULL)
     737             :             {
     738           0 :                 write_stderr(_("%s: could not read file \"%s\"\n"), progname, postopts_file);
     739           0 :                 exit(1);
     740             :             }
     741          90 :             else if (numlines != 1)
     742             :             {
     743           0 :                 write_stderr(_("%s: option file \"%s\" must have exactly one line\n"),
     744             :                              progname, postopts_file);
     745           0 :                 exit(1);
     746             :             }
     747             :             else
     748             :             {
     749             :                 char       *optline;
     750             :                 char       *arg1;
     751             : 
     752          90 :                 optline = optlines[0];
     753             : 
     754             :                 /*
     755             :                  * Are we at the first option, as defined by space and
     756             :                  * double-quote?
     757             :                  */
     758          90 :                 if ((arg1 = strstr(optline, " \"")) != NULL)
     759             :                 {
     760          90 :                     *arg1 = '\0';   /* terminate so we get only program name */
     761          90 :                     post_opts = pg_strdup(arg1 + 1);    /* point past whitespace */
     762             :                 }
     763          90 :                 if (exec_path == NULL)
     764          90 :                     exec_path = pg_strdup(optline);
     765             :             }
     766             : 
     767             :             /* Free the results of readfile. */
     768          90 :             free_readfile(optlines);
     769             :         }
     770             :     }
     771         596 : }
     772             : 
     773             : /*
     774             :  * SIGINT signal handler used while waiting for postmaster to start up.
     775             :  * Forwards the SIGINT to the postmaster process, asking it to shut down,
     776             :  * before terminating pg_ctl itself. This way, if the user hits CTRL-C while
     777             :  * waiting for the server to start up, the server launch is aborted.
     778             :  */
     779             : static void
     780           0 : trap_sigint_during_startup(int sig)
     781             : {
     782           0 :     if (postmasterPID != -1)
     783             :     {
     784           0 :         if (kill(postmasterPID, SIGINT) != 0)
     785           0 :             write_stderr(_("%s: could not send stop signal (PID: %ld): %s\n"),
     786           0 :                          progname, (pgpid_t) postmasterPID, strerror(errno));
     787             :     }
     788             : 
     789             :     /*
     790             :      * Clear the signal handler, and send the signal again, to terminate the
     791             :      * process as normal.
     792             :      */
     793           0 :     pqsignal(SIGINT, SIG_DFL);
     794           0 :     raise(SIGINT);
     795           0 : }
     796             : 
     797             : static char *
     798         508 : find_other_exec_or_die(const char *argv0, const char *target, const char *versionstr)
     799             : {
     800             :     int         ret;
     801             :     char       *found_path;
     802             : 
     803         508 :     found_path = pg_malloc(MAXPGPATH);
     804             : 
     805         508 :     if ((ret = find_other_exec(argv0, target, versionstr, found_path)) < 0)
     806             :     {
     807             :         char        full_path[MAXPGPATH];
     808             : 
     809           0 :         if (find_my_exec(argv0, full_path) < 0)
     810           0 :             strlcpy(full_path, progname, sizeof(full_path));
     811             : 
     812           0 :         if (ret == -1)
     813           0 :             write_stderr(_("The program \"%s\" is needed by %s but was not found in the\n"
     814             :                            "same directory as \"%s\".\n"
     815             :                            "Check your installation.\n"),
     816             :                          target, progname, full_path);
     817             :         else
     818           0 :             write_stderr(_("The program \"%s\" was found by \"%s\"\n"
     819             :                            "but was not the same version as %s.\n"
     820             :                            "Check your installation.\n"),
     821             :                          target, full_path, progname);
     822           0 :         exit(1);
     823             :     }
     824             : 
     825         508 :     return found_path;
     826             : }
     827             : 
     828             : static void
     829           2 : do_init(void)
     830             : {
     831             :     char        cmd[MAXPGPATH];
     832             : 
     833           2 :     if (exec_path == NULL)
     834           2 :         exec_path = find_other_exec_or_die(argv0, "initdb", "initdb (PostgreSQL) " PG_VERSION "\n");
     835             : 
     836           2 :     if (pgdata_opt == NULL)
     837           0 :         pgdata_opt = "";
     838             : 
     839           2 :     if (post_opts == NULL)
     840           0 :         post_opts = "";
     841             : 
     842           2 :     if (!silent_mode)
     843           2 :         snprintf(cmd, MAXPGPATH, "\"%s\" %s%s",
     844             :                  exec_path, pgdata_opt, post_opts);
     845             :     else
     846           0 :         snprintf(cmd, MAXPGPATH, "\"%s\" %s%s > \"%s\"",
     847             :                  exec_path, pgdata_opt, post_opts, DEVNULL);
     848             : 
     849           2 :     if (system(cmd) != 0)
     850             :     {
     851           0 :         write_stderr(_("%s: database system initialization failed\n"), progname);
     852           0 :         exit(1);
     853             :     }
     854           2 : }
     855             : 
     856             : static void
     857         598 : do_start(void)
     858             : {
     859         598 :     pgpid_t     old_pid = 0;
     860             :     pgpid_t     pm_pid;
     861             : 
     862         598 :     if (ctl_command != RESTART_COMMAND)
     863             :     {
     864         508 :         old_pid = get_pgpid(false);
     865         506 :         if (old_pid != 0)
     866           6 :             write_stderr(_("%s: another server might be running; "
     867             :                            "trying to start server anyway\n"),
     868             :                          progname);
     869             :     }
     870             : 
     871         596 :     read_post_opts();
     872             : 
     873             :     /* No -D or -D already added during server start */
     874         596 :     if (ctl_command == RESTART_COMMAND || pgdata_opt == NULL)
     875          94 :         pgdata_opt = "";
     876             : 
     877         596 :     if (exec_path == NULL)
     878         506 :         exec_path = find_other_exec_or_die(argv0, "postgres", PG_BACKEND_VERSIONSTR);
     879             : 
     880             : #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
     881         596 :     if (allow_core_files)
     882           0 :         unlimit_core_size();
     883             : #endif
     884             : 
     885             :     /*
     886             :      * If possible, tell the postmaster our parent shell's PID (see the
     887             :      * comments in CreateLockFile() for motivation).  Windows hasn't got
     888             :      * getppid() unfortunately.
     889             :      */
     890             : #ifndef WIN32
     891             :     {
     892             :         static char env_var[32];
     893             : 
     894         596 :         snprintf(env_var, sizeof(env_var), "PG_GRANDPARENT_PID=%d",
     895         596 :                  (int) getppid());
     896         596 :         putenv(env_var);
     897             :     }
     898             : #endif
     899             : 
     900         596 :     pm_pid = start_postmaster();
     901             : 
     902         596 :     if (do_wait)
     903             :     {
     904             :         /*
     905             :          * If the user interrupts the startup (e.g. with CTRL-C), we'd like to
     906             :          * abort the server launch.  Install a signal handler that will
     907             :          * forward SIGINT to the postmaster process, while we wait.
     908             :          *
     909             :          * (We don't bother to reset the signal handler after the launch, as
     910             :          * we're about to exit, anyway.)
     911             :          */
     912         596 :         postmasterPID = pm_pid;
     913         596 :         pqsignal(SIGINT, trap_sigint_during_startup);
     914             : 
     915         596 :         print_msg(_("waiting for server to start..."));
     916             : 
     917         596 :         switch (wait_for_postmaster(pm_pid, false))
     918             :         {
     919         582 :             case POSTMASTER_READY:
     920         582 :                 print_msg(_(" done\n"));
     921         582 :                 print_msg(_("server started\n"));
     922         582 :                 break;
     923           0 :             case POSTMASTER_STILL_STARTING:
     924           0 :                 print_msg(_(" stopped waiting\n"));
     925           0 :                 write_stderr(_("%s: server did not start in time\n"),
     926             :                              progname);
     927           0 :                 exit(1);
     928             :                 break;
     929          14 :             case POSTMASTER_FAILED:
     930          14 :                 print_msg(_(" stopped waiting\n"));
     931          14 :                 write_stderr(_("%s: could not start server\n"
     932             :                                "Examine the log output.\n"),
     933             :                              progname);
     934          14 :                 exit(1);
     935             :                 break;
     936             :         }
     937         582 :     }
     938             :     else
     939           0 :         print_msg(_("server starting\n"));
     940             : 
     941             : #ifdef WIN32
     942             :     /* Now we don't need the handle to the shell process anymore */
     943             :     CloseHandle(postmasterProcess);
     944             :     postmasterProcess = INVALID_HANDLE_VALUE;
     945             : #endif
     946         582 : }
     947             : 
     948             : 
     949             : static void
     950         626 : do_stop(void)
     951             : {
     952             :     int         cnt;
     953             :     pgpid_t     pid;
     954             :     struct stat statbuf;
     955             : 
     956         626 :     pid = get_pgpid(false);
     957             : 
     958         626 :     if (pid == 0)               /* no pid file */
     959             :     {
     960           2 :         write_stderr(_("%s: PID file \"%s\" does not exist\n"), progname, pid_file);
     961           2 :         write_stderr(_("Is server running?\n"));
     962           2 :         exit(1);
     963             :     }
     964         624 :     else if (pid < 0)            /* standalone backend, not postmaster */
     965             :     {
     966           0 :         pid = -pid;
     967           0 :         write_stderr(_("%s: cannot stop server; "
     968             :                        "single-user server is running (PID: %ld)\n"),
     969             :                      progname, pid);
     970           0 :         exit(1);
     971             :     }
     972             : 
     973         624 :     if (kill((pid_t) pid, sig) != 0)
     974             :     {
     975           0 :         write_stderr(_("%s: could not send stop signal (PID: %ld): %s\n"), progname, pid,
     976           0 :                      strerror(errno));
     977           0 :         exit(1);
     978             :     }
     979             : 
     980         624 :     if (!do_wait)
     981             :     {
     982           0 :         print_msg(_("server shutting down\n"));
     983           0 :         return;
     984             :     }
     985             :     else
     986             :     {
     987             :         /*
     988             :          * If backup_label exists, an online backup is running. Warn the user
     989             :          * that smart shutdown will wait for it to finish. However, if the
     990             :          * server is in archive recovery, we're recovering from an online
     991             :          * backup instead of performing one.
     992             :          */
     993         632 :         if (shutdown_mode == SMART_MODE &&
     994           8 :             stat(backup_file, &statbuf) == 0 &&
     995           0 :             get_control_dbstate() != DB_IN_ARCHIVE_RECOVERY)
     996             :         {
     997           0 :             print_msg(_("WARNING: online backup mode is active\n"
     998             :                         "Shutdown will not complete until pg_stop_backup() is called.\n\n"));
     999             :         }
    1000             : 
    1001         624 :         print_msg(_("waiting for server to shut down..."));
    1002             : 
    1003        1612 :         for (cnt = 0; cnt < wait_seconds * WAITS_PER_SEC; cnt++)
    1004             :         {
    1005        1612 :             if ((pid = get_pgpid(false)) != 0)
    1006             :             {
    1007         988 :                 if (cnt % WAITS_PER_SEC == 0)
    1008         624 :                     print_msg(".");
    1009         988 :                 pg_usleep(USEC_PER_SEC / WAITS_PER_SEC);
    1010             :             }
    1011             :             else
    1012         624 :                 break;
    1013             :         }
    1014             : 
    1015         624 :         if (pid != 0)           /* pid file still exists */
    1016             :         {
    1017           0 :             print_msg(_(" failed\n"));
    1018             : 
    1019           0 :             write_stderr(_("%s: server does not shut down\n"), progname);
    1020           0 :             if (shutdown_mode == SMART_MODE)
    1021           0 :                 write_stderr(_("HINT: The \"-m fast\" option immediately disconnects sessions rather than\n"
    1022             :                                "waiting for session-initiated disconnection.\n"));
    1023           0 :             exit(1);
    1024             :         }
    1025         624 :         print_msg(_(" done\n"));
    1026             : 
    1027         624 :         print_msg(_("server stopped\n"));
    1028             :     }
    1029             : }
    1030             : 
    1031             : 
    1032             : /*
    1033             :  *  restart/reload routines
    1034             :  */
    1035             : 
    1036             : static void
    1037          90 : do_restart(void)
    1038             : {
    1039             :     int         cnt;
    1040             :     pgpid_t     pid;
    1041             :     struct stat statbuf;
    1042             : 
    1043          90 :     pid = get_pgpid(false);
    1044             : 
    1045          90 :     if (pid == 0)               /* no pid file */
    1046             :     {
    1047           6 :         write_stderr(_("%s: PID file \"%s\" does not exist\n"),
    1048             :                      progname, pid_file);
    1049           6 :         write_stderr(_("Is server running?\n"));
    1050           6 :         write_stderr(_("trying to start server anyway\n"));
    1051           6 :         do_start();
    1052           6 :         return;
    1053             :     }
    1054          84 :     else if (pid < 0)            /* standalone backend, not postmaster */
    1055             :     {
    1056           0 :         pid = -pid;
    1057           0 :         if (postmaster_is_alive((pid_t) pid))
    1058             :         {
    1059           0 :             write_stderr(_("%s: cannot restart server; "
    1060             :                            "single-user server is running (PID: %ld)\n"),
    1061             :                          progname, pid);
    1062           0 :             write_stderr(_("Please terminate the single-user server and try again.\n"));
    1063           0 :             exit(1);
    1064             :         }
    1065             :     }
    1066             : 
    1067          84 :     if (postmaster_is_alive((pid_t) pid))
    1068             :     {
    1069          84 :         if (kill((pid_t) pid, sig) != 0)
    1070             :         {
    1071           0 :             write_stderr(_("%s: could not send stop signal (PID: %ld): %s\n"), progname, pid,
    1072           0 :                          strerror(errno));
    1073           0 :             exit(1);
    1074             :         }
    1075             : 
    1076             :         /*
    1077             :          * If backup_label exists, an online backup is running. Warn the user
    1078             :          * that smart shutdown will wait for it to finish. However, if the
    1079             :          * server is in archive recovery, we're recovering from an online
    1080             :          * backup instead of performing one.
    1081             :          */
    1082          84 :         if (shutdown_mode == SMART_MODE &&
    1083           0 :             stat(backup_file, &statbuf) == 0 &&
    1084           0 :             get_control_dbstate() != DB_IN_ARCHIVE_RECOVERY)
    1085             :         {
    1086           0 :             print_msg(_("WARNING: online backup mode is active\n"
    1087             :                         "Shutdown will not complete until pg_stop_backup() is called.\n\n"));
    1088             :         }
    1089             : 
    1090          84 :         print_msg(_("waiting for server to shut down..."));
    1091             : 
    1092             :         /* always wait for restart */
    1093             : 
    1094         284 :         for (cnt = 0; cnt < wait_seconds * WAITS_PER_SEC; cnt++)
    1095             :         {
    1096         284 :             if ((pid = get_pgpid(false)) != 0)
    1097             :             {
    1098         200 :                 if (cnt % WAITS_PER_SEC == 0)
    1099          84 :                     print_msg(".");
    1100         200 :                 pg_usleep(USEC_PER_SEC / WAITS_PER_SEC);
    1101             :             }
    1102             :             else
    1103          84 :                 break;
    1104             :         }
    1105             : 
    1106          84 :         if (pid != 0)           /* pid file still exists */
    1107             :         {
    1108           0 :             print_msg(_(" failed\n"));
    1109             : 
    1110           0 :             write_stderr(_("%s: server does not shut down\n"), progname);
    1111           0 :             if (shutdown_mode == SMART_MODE)
    1112           0 :                 write_stderr(_("HINT: The \"-m fast\" option immediately disconnects sessions rather than\n"
    1113             :                                "waiting for session-initiated disconnection.\n"));
    1114           0 :             exit(1);
    1115             :         }
    1116             : 
    1117          84 :         print_msg(_(" done\n"));
    1118          84 :         print_msg(_("server stopped\n"));
    1119             :     }
    1120             :     else
    1121             :     {
    1122           0 :         write_stderr(_("%s: old server process (PID: %ld) seems to be gone\n"),
    1123             :                      progname, pid);
    1124           0 :         write_stderr(_("starting server anyway\n"));
    1125             :     }
    1126             : 
    1127          84 :     do_start();
    1128             : }
    1129             : 
    1130             : static void
    1131          58 : do_reload(void)
    1132             : {
    1133             :     pgpid_t     pid;
    1134             : 
    1135          58 :     pid = get_pgpid(false);
    1136          58 :     if (pid == 0)               /* no pid file */
    1137             :     {
    1138           0 :         write_stderr(_("%s: PID file \"%s\" does not exist\n"), progname, pid_file);
    1139           0 :         write_stderr(_("Is server running?\n"));
    1140           0 :         exit(1);
    1141             :     }
    1142          58 :     else if (pid < 0)            /* standalone backend, not postmaster */
    1143             :     {
    1144           0 :         pid = -pid;
    1145           0 :         write_stderr(_("%s: cannot reload server; "
    1146             :                        "single-user server is running (PID: %ld)\n"),
    1147             :                      progname, pid);
    1148           0 :         write_stderr(_("Please terminate the single-user server and try again.\n"));
    1149           0 :         exit(1);
    1150             :     }
    1151             : 
    1152          58 :     if (kill((pid_t) pid, sig) != 0)
    1153             :     {
    1154           0 :         write_stderr(_("%s: could not send reload signal (PID: %ld): %s\n"),
    1155           0 :                      progname, pid, strerror(errno));
    1156           0 :         exit(1);
    1157             :     }
    1158             : 
    1159          58 :     print_msg(_("server signaled\n"));
    1160          58 : }
    1161             : 
    1162             : 
    1163             : /*
    1164             :  * promote
    1165             :  */
    1166             : 
    1167             : static void
    1168          52 : do_promote(void)
    1169             : {
    1170             :     FILE       *prmfile;
    1171             :     pgpid_t     pid;
    1172             : 
    1173          52 :     pid = get_pgpid(false);
    1174             : 
    1175          50 :     if (pid == 0)               /* no pid file */
    1176             :     {
    1177           2 :         write_stderr(_("%s: PID file \"%s\" does not exist\n"), progname, pid_file);
    1178           2 :         write_stderr(_("Is server running?\n"));
    1179           2 :         exit(1);
    1180             :     }
    1181          48 :     else if (pid < 0)            /* standalone backend, not postmaster */
    1182             :     {
    1183           0 :         pid = -pid;
    1184           0 :         write_stderr(_("%s: cannot promote server; "
    1185             :                        "single-user server is running (PID: %ld)\n"),
    1186             :                      progname, pid);
    1187           0 :         exit(1);
    1188             :     }
    1189             : 
    1190          48 :     if (get_control_dbstate() != DB_IN_ARCHIVE_RECOVERY)
    1191             :     {
    1192           2 :         write_stderr(_("%s: cannot promote server; "
    1193             :                        "server is not in standby mode\n"),
    1194             :                      progname);
    1195           2 :         exit(1);
    1196             :     }
    1197             : 
    1198             :     /*
    1199             :      * For 9.3 onwards, "fast" promotion is performed. Promotion with a full
    1200             :      * checkpoint is still possible by writing a file called
    1201             :      * "fallback_promote" instead of "promote"
    1202             :      */
    1203          46 :     snprintf(promote_file, MAXPGPATH, "%s/promote", pg_data);
    1204             : 
    1205          46 :     if ((prmfile = fopen(promote_file, "w")) == NULL)
    1206             :     {
    1207           0 :         write_stderr(_("%s: could not create promote signal file \"%s\": %s\n"),
    1208           0 :                      progname, promote_file, strerror(errno));
    1209           0 :         exit(1);
    1210             :     }
    1211          46 :     if (fclose(prmfile))
    1212             :     {
    1213           0 :         write_stderr(_("%s: could not write promote signal file \"%s\": %s\n"),
    1214           0 :                      progname, promote_file, strerror(errno));
    1215           0 :         exit(1);
    1216             :     }
    1217             : 
    1218          46 :     sig = SIGUSR1;
    1219          46 :     if (kill((pid_t) pid, sig) != 0)
    1220             :     {
    1221           0 :         write_stderr(_("%s: could not send promote signal (PID: %ld): %s\n"),
    1222           0 :                      progname, pid, strerror(errno));
    1223           0 :         if (unlink(promote_file) != 0)
    1224           0 :             write_stderr(_("%s: could not remove promote signal file \"%s\": %s\n"),
    1225           0 :                          progname, promote_file, strerror(errno));
    1226           0 :         exit(1);
    1227             :     }
    1228             : 
    1229          46 :     if (do_wait)
    1230             :     {
    1231          44 :         DBState     state = DB_STARTUP;
    1232             :         int         cnt;
    1233             : 
    1234          44 :         print_msg(_("waiting for server to promote..."));
    1235         116 :         for (cnt = 0; cnt < wait_seconds * WAITS_PER_SEC; cnt++)
    1236             :         {
    1237         116 :             state = get_control_dbstate();
    1238         116 :             if (state == DB_IN_PRODUCTION)
    1239          44 :                 break;
    1240             : 
    1241          72 :             if (cnt % WAITS_PER_SEC == 0)
    1242          44 :                 print_msg(".");
    1243          72 :             pg_usleep(USEC_PER_SEC / WAITS_PER_SEC);
    1244             :         }
    1245          44 :         if (state == DB_IN_PRODUCTION)
    1246             :         {
    1247          44 :             print_msg(_(" done\n"));
    1248          44 :             print_msg(_("server promoted\n"));
    1249             :         }
    1250             :         else
    1251             :         {
    1252           0 :             print_msg(_(" stopped waiting\n"));
    1253           0 :             write_stderr(_("%s: server did not promote in time\n"),
    1254             :                          progname);
    1255           0 :             exit(1);
    1256             :         }
    1257             :     }
    1258             :     else
    1259           2 :         print_msg(_("server promoting\n"));
    1260          46 : }
    1261             : 
    1262             : /*
    1263             :  * log rotate
    1264             :  */
    1265             : 
    1266             : static void
    1267           2 : do_logrotate(void)
    1268             : {
    1269             :     FILE       *logrotatefile;
    1270             :     pgpid_t     pid;
    1271             : 
    1272           2 :     pid = get_pgpid(false);
    1273             : 
    1274           2 :     if (pid == 0)               /* no pid file */
    1275             :     {
    1276           0 :         write_stderr(_("%s: PID file \"%s\" does not exist\n"), progname, pid_file);
    1277           0 :         write_stderr(_("Is server running?\n"));
    1278           0 :         exit(1);
    1279             :     }
    1280           2 :     else if (pid < 0)            /* standalone backend, not postmaster */
    1281             :     {
    1282           0 :         pid = -pid;
    1283           0 :         write_stderr(_("%s: cannot rotate log file; "
    1284             :                        "single-user server is running (PID: %ld)\n"),
    1285             :                      progname, pid);
    1286           0 :         exit(1);
    1287             :     }
    1288             : 
    1289           2 :     snprintf(logrotate_file, MAXPGPATH, "%s/logrotate", pg_data);
    1290             : 
    1291           2 :     if ((logrotatefile = fopen(logrotate_file, "w")) == NULL)
    1292             :     {
    1293           0 :         write_stderr(_("%s: could not create log rotation signal file \"%s\": %s\n"),
    1294           0 :                      progname, logrotate_file, strerror(errno));
    1295           0 :         exit(1);
    1296             :     }
    1297           2 :     if (fclose(logrotatefile))
    1298             :     {
    1299           0 :         write_stderr(_("%s: could not write log rotation signal file \"%s\": %s\n"),
    1300           0 :                      progname, logrotate_file, strerror(errno));
    1301           0 :         exit(1);
    1302             :     }
    1303             : 
    1304           2 :     sig = SIGUSR1;
    1305           2 :     if (kill((pid_t) pid, sig) != 0)
    1306             :     {
    1307           0 :         write_stderr(_("%s: could not send log rotation signal (PID: %ld): %s\n"),
    1308           0 :                      progname, pid, strerror(errno));
    1309           0 :         if (unlink(logrotate_file) != 0)
    1310           0 :             write_stderr(_("%s: could not remove log rotation signal file \"%s\": %s\n"),
    1311           0 :                          progname, logrotate_file, strerror(errno));
    1312           0 :         exit(1);
    1313             :     }
    1314             : 
    1315           2 :     print_msg(_("server signaled to rotate log file\n"));
    1316           2 : }
    1317             : 
    1318             : 
    1319             : /*
    1320             :  *  utility routines
    1321             :  */
    1322             : 
    1323             : static bool
    1324          86 : postmaster_is_alive(pid_t pid)
    1325             : {
    1326             :     /*
    1327             :      * Test to see if the process is still there.  Note that we do not
    1328             :      * consider an EPERM failure to mean that the process is still there;
    1329             :      * EPERM must mean that the given PID belongs to some other userid, and
    1330             :      * considering the permissions on $PGDATA, that means it's not the
    1331             :      * postmaster we are after.
    1332             :      *
    1333             :      * Don't believe that our own PID or parent shell's PID is the postmaster,
    1334             :      * either.  (Windows hasn't got getppid(), though.)
    1335             :      */
    1336          86 :     if (pid == getpid())
    1337           0 :         return false;
    1338             : #ifndef WIN32
    1339          86 :     if (pid == getppid())
    1340           0 :         return false;
    1341             : #endif
    1342          86 :     if (kill(pid, 0) == 0)
    1343          86 :         return true;
    1344           0 :     return false;
    1345             : }
    1346             : 
    1347             : static void
    1348           6 : do_status(void)
    1349             : {
    1350             :     pgpid_t     pid;
    1351             : 
    1352           6 :     pid = get_pgpid(true);
    1353             :     /* Is there a pid file? */
    1354           4 :     if (pid != 0)
    1355             :     {
    1356             :         /* standalone backend? */
    1357           2 :         if (pid < 0)
    1358             :         {
    1359           0 :             pid = -pid;
    1360           0 :             if (postmaster_is_alive((pid_t) pid))
    1361             :             {
    1362           0 :                 printf(_("%s: single-user server is running (PID: %ld)\n"),
    1363             :                        progname, pid);
    1364           0 :                 return;
    1365             :             }
    1366             :         }
    1367             :         else
    1368             :             /* must be a postmaster */
    1369             :         {
    1370           2 :             if (postmaster_is_alive((pid_t) pid))
    1371             :             {
    1372             :                 char      **optlines;
    1373             :                 char      **curr_line;
    1374             :                 int         numlines;
    1375             : 
    1376           2 :                 printf(_("%s: server is running (PID: %ld)\n"),
    1377             :                        progname, pid);
    1378             : 
    1379           2 :                 optlines = readfile(postopts_file, &numlines);
    1380           2 :                 if (optlines != NULL)
    1381             :                 {
    1382           4 :                     for (curr_line = optlines; *curr_line != NULL; curr_line++)
    1383           2 :                         puts(*curr_line);
    1384             : 
    1385             :                     /* Free the results of readfile */
    1386           2 :                     free_readfile(optlines);
    1387             :                 }
    1388           2 :                 return;
    1389             :             }
    1390             :         }
    1391             :     }
    1392           2 :     printf(_("%s: no server running\n"), progname);
    1393             : 
    1394             :     /*
    1395             :      * The Linux Standard Base Core Specification 3.1 says this should return
    1396             :      * '3, program is not running'
    1397             :      * https://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html
    1398             :      */
    1399           2 :     exit(3);
    1400             : }
    1401             : 
    1402             : 
    1403             : 
    1404             : static void
    1405           6 : do_kill(pgpid_t pid)
    1406             : {
    1407           6 :     if (kill((pid_t) pid, sig) != 0)
    1408             :     {
    1409           0 :         write_stderr(_("%s: could not send signal %d (PID: %ld): %s\n"),
    1410           0 :                      progname, sig, pid, strerror(errno));
    1411           0 :         exit(1);
    1412             :     }
    1413           6 : }
    1414             : 
    1415             : #ifdef WIN32
    1416             : 
    1417             : static bool
    1418             : pgwin32_IsInstalled(SC_HANDLE hSCM)
    1419             : {
    1420             :     SC_HANDLE   hService = OpenService(hSCM, register_servicename, SERVICE_QUERY_CONFIG);
    1421             :     bool        bResult = (hService != NULL);
    1422             : 
    1423             :     if (bResult)
    1424             :         CloseServiceHandle(hService);
    1425             :     return bResult;
    1426             : }
    1427             : 
    1428             : static char *
    1429             : pgwin32_CommandLine(bool registration)
    1430             : {
    1431             :     PQExpBuffer cmdLine = createPQExpBuffer();
    1432             :     char        cmdPath[MAXPGPATH];
    1433             :     int         ret;
    1434             : 
    1435             :     if (registration)
    1436             :     {
    1437             :         ret = find_my_exec(argv0, cmdPath);
    1438             :         if (ret != 0)
    1439             :         {
    1440             :             write_stderr(_("%s: could not find own program executable\n"), progname);
    1441             :             exit(1);
    1442             :         }
    1443             :     }
    1444             :     else
    1445             :     {
    1446             :         ret = find_other_exec(argv0, "postgres", PG_BACKEND_VERSIONSTR,
    1447             :                               cmdPath);
    1448             :         if (ret != 0)
    1449             :         {
    1450             :             write_stderr(_("%s: could not find postgres program executable\n"), progname);
    1451             :             exit(1);
    1452             :         }
    1453             :     }
    1454             : 
    1455             :     /* if path does not end in .exe, append it */
    1456             :     if (strlen(cmdPath) < 4 ||
    1457             :         pg_strcasecmp(cmdPath + strlen(cmdPath) - 4, ".exe") != 0)
    1458             :         snprintf(cmdPath + strlen(cmdPath), sizeof(cmdPath) - strlen(cmdPath),
    1459             :                  ".exe");
    1460             : 
    1461             :     /* use backslashes in path to avoid problems with some third-party tools */
    1462             :     make_native_path(cmdPath);
    1463             : 
    1464             :     /* be sure to double-quote the executable's name in the command */
    1465             :     appendPQExpBuffer(cmdLine, "\"%s\"", cmdPath);
    1466             : 
    1467             :     /* append assorted switches to the command line, as needed */
    1468             : 
    1469             :     if (registration)
    1470             :         appendPQExpBuffer(cmdLine, " runservice -N \"%s\"",
    1471             :                           register_servicename);
    1472             : 
    1473             :     if (pg_config)
    1474             :     {
    1475             :         /* We need the -D path to be absolute */
    1476             :         char       *dataDir;
    1477             : 
    1478             :         if ((dataDir = make_absolute_path(pg_config)) == NULL)
    1479             :         {
    1480             :             /* make_absolute_path already reported the error */
    1481             :             exit(1);
    1482             :         }
    1483             :         make_native_path(dataDir);
    1484             :         appendPQExpBuffer(cmdLine, " -D \"%s\"", dataDir);
    1485             :         free(dataDir);
    1486             :     }
    1487             : 
    1488             :     if (registration && event_source != NULL)
    1489             :         appendPQExpBuffer(cmdLine, " -e \"%s\"", event_source);
    1490             : 
    1491             :     if (registration && do_wait)
    1492             :         appendPQExpBufferStr(cmdLine, " -w");
    1493             : 
    1494             :     /* Don't propagate a value from an environment variable. */
    1495             :     if (registration && wait_seconds_arg && wait_seconds != DEFAULT_WAIT)
    1496             :         appendPQExpBuffer(cmdLine, " -t %d", wait_seconds);
    1497             : 
    1498             :     if (registration && silent_mode)
    1499             :         appendPQExpBufferStr(cmdLine, " -s");
    1500             : 
    1501             :     if (post_opts)
    1502             :     {
    1503             :         if (registration)
    1504             :             appendPQExpBuffer(cmdLine, " -o \"%s\"", post_opts);
    1505             :         else
    1506             :             appendPQExpBuffer(cmdLine, " %s", post_opts);
    1507             :     }
    1508             : 
    1509             :     return cmdLine->data;
    1510             : }
    1511             : 
    1512             : static void
    1513             : pgwin32_doRegister(void)
    1514             : {
    1515             :     SC_HANDLE   hService;
    1516             :     SC_HANDLE   hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    1517             : 
    1518             :     if (hSCM == NULL)
    1519             :     {
    1520             :         write_stderr(_("%s: could not open service manager\n"), progname);
    1521             :         exit(1);
    1522             :     }
    1523             :     if (pgwin32_IsInstalled(hSCM))
    1524             :     {
    1525             :         CloseServiceHandle(hSCM);
    1526             :         write_stderr(_("%s: service \"%s\" already registered\n"), progname, register_servicename);
    1527             :         exit(1);
    1528             :     }
    1529             : 
    1530             :     if ((hService = CreateService(hSCM, register_servicename, register_servicename,
    1531             :                                   SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
    1532             :                                   pgctl_start_type, SERVICE_ERROR_NORMAL,
    1533             :                                   pgwin32_CommandLine(true),
    1534             :                                   NULL, NULL, "RPCSS\0", register_username, register_password)) == NULL)
    1535             :     {
    1536             :         CloseServiceHandle(hSCM);
    1537             :         write_stderr(_("%s: could not register service \"%s\": error code %lu\n"),
    1538             :                      progname, register_servicename,
    1539             :                      (unsigned long) GetLastError());
    1540             :         exit(1);
    1541             :     }
    1542             :     CloseServiceHandle(hService);
    1543             :     CloseServiceHandle(hSCM);
    1544             : }
    1545             : 
    1546             : static void
    1547             : pgwin32_doUnregister(void)
    1548             : {
    1549             :     SC_HANDLE   hService;
    1550             :     SC_HANDLE   hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    1551             : 
    1552             :     if (hSCM == NULL)
    1553             :     {
    1554             :         write_stderr(_("%s: could not open service manager\n"), progname);
    1555             :         exit(1);
    1556             :     }
    1557             :     if (!pgwin32_IsInstalled(hSCM))
    1558             :     {
    1559             :         CloseServiceHandle(hSCM);
    1560             :         write_stderr(_("%s: service \"%s\" not registered\n"), progname, register_servicename);
    1561             :         exit(1);
    1562             :     }
    1563             : 
    1564             :     if ((hService = OpenService(hSCM, register_servicename, DELETE)) == NULL)
    1565             :     {
    1566             :         CloseServiceHandle(hSCM);
    1567             :         write_stderr(_("%s: could not open service \"%s\": error code %lu\n"),
    1568             :                      progname, register_servicename,
    1569             :                      (unsigned long) GetLastError());
    1570             :         exit(1);
    1571             :     }
    1572             :     if (!DeleteService(hService))
    1573             :     {
    1574             :         CloseServiceHandle(hService);
    1575             :         CloseServiceHandle(hSCM);
    1576             :         write_stderr(_("%s: could not unregister service \"%s\": error code %lu\n"),
    1577             :                      progname, register_servicename,
    1578             :                      (unsigned long) GetLastError());
    1579             :         exit(1);
    1580             :     }
    1581             :     CloseServiceHandle(hService);
    1582             :     CloseServiceHandle(hSCM);
    1583             : }
    1584             : 
    1585             : static void
    1586             : pgwin32_SetServiceStatus(DWORD currentState)
    1587             : {
    1588             :     status.dwCurrentState = currentState;
    1589             :     SetServiceStatus(hStatus, (LPSERVICE_STATUS) &status);
    1590             : }
    1591             : 
    1592             : static void WINAPI
    1593             : pgwin32_ServiceHandler(DWORD request)
    1594             : {
    1595             :     switch (request)
    1596             :     {
    1597             :         case SERVICE_CONTROL_STOP:
    1598             :         case SERVICE_CONTROL_SHUTDOWN:
    1599             : 
    1600             :             /*
    1601             :              * We only need a short wait hint here as it just needs to wait
    1602             :              * for the next checkpoint. They occur every 5 seconds during
    1603             :              * shutdown
    1604             :              */
    1605             :             status.dwWaitHint = 10000;
    1606             :             pgwin32_SetServiceStatus(SERVICE_STOP_PENDING);
    1607             :             SetEvent(shutdownEvent);
    1608             :             return;
    1609             : 
    1610             :         case SERVICE_CONTROL_PAUSE:
    1611             :             /* Win32 config reloading */
    1612             :             status.dwWaitHint = 5000;
    1613             :             kill(postmasterPID, SIGHUP);
    1614             :             return;
    1615             : 
    1616             :             /* FIXME: These could be used to replace other signals etc */
    1617             :         case SERVICE_CONTROL_CONTINUE:
    1618             :         case SERVICE_CONTROL_INTERROGATE:
    1619             :         default:
    1620             :             break;
    1621             :     }
    1622             : }
    1623             : 
    1624             : static void WINAPI
    1625             : pgwin32_ServiceMain(DWORD argc, LPTSTR *argv)
    1626             : {
    1627             :     PROCESS_INFORMATION pi;
    1628             :     DWORD       ret;
    1629             : 
    1630             :     /* Initialize variables */
    1631             :     status.dwWin32ExitCode = S_OK;
    1632             :     status.dwCheckPoint = 0;
    1633             :     status.dwWaitHint = 60000;
    1634             :     status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
    1635             :     status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_PAUSE_CONTINUE;
    1636             :     status.dwServiceSpecificExitCode = 0;
    1637             :     status.dwCurrentState = SERVICE_START_PENDING;
    1638             : 
    1639             :     memset(&pi, 0, sizeof(pi));
    1640             : 
    1641             :     read_post_opts();
    1642             : 
    1643             :     /* Register the control request handler */
    1644             :     if ((hStatus = RegisterServiceCtrlHandler(register_servicename, pgwin32_ServiceHandler)) == (SERVICE_STATUS_HANDLE) 0)
    1645             :         return;
    1646             : 
    1647             :     if ((shutdownEvent = CreateEvent(NULL, true, false, NULL)) == NULL)
    1648             :         return;
    1649             : 
    1650             :     /* Start the postmaster */
    1651             :     pgwin32_SetServiceStatus(SERVICE_START_PENDING);
    1652             :     if (!CreateRestrictedProcess(pgwin32_CommandLine(false), &pi, true))
    1653             :     {
    1654             :         pgwin32_SetServiceStatus(SERVICE_STOPPED);
    1655             :         return;
    1656             :     }
    1657             :     postmasterPID = pi.dwProcessId;
    1658             :     postmasterProcess = pi.hProcess;
    1659             :     CloseHandle(pi.hThread);
    1660             : 
    1661             :     if (do_wait)
    1662             :     {
    1663             :         write_eventlog(EVENTLOG_INFORMATION_TYPE, _("Waiting for server startup...\n"));
    1664             :         if (wait_for_postmaster(postmasterPID, true) != POSTMASTER_READY)
    1665             :         {
    1666             :             write_eventlog(EVENTLOG_ERROR_TYPE, _("Timed out waiting for server startup\n"));
    1667             :             pgwin32_SetServiceStatus(SERVICE_STOPPED);
    1668             :             return;
    1669             :         }
    1670             :         write_eventlog(EVENTLOG_INFORMATION_TYPE, _("Server started and accepting connections\n"));
    1671             :     }
    1672             : 
    1673             :     pgwin32_SetServiceStatus(SERVICE_RUNNING);
    1674             : 
    1675             :     /* Wait for quit... */
    1676             :     ret = WaitForMultipleObjects(2, shutdownHandles, FALSE, INFINITE);
    1677             : 
    1678             :     pgwin32_SetServiceStatus(SERVICE_STOP_PENDING);
    1679             :     switch (ret)
    1680             :     {
    1681             :         case WAIT_OBJECT_0:     /* shutdown event */
    1682             :             {
    1683             :                 /*
    1684             :                  * status.dwCheckPoint can be incremented by
    1685             :                  * wait_for_postmaster(), so it might not start from 0.
    1686             :                  */
    1687             :                 int         maxShutdownCheckPoint = status.dwCheckPoint + 12;
    1688             : 
    1689             :                 kill(postmasterPID, SIGINT);
    1690             : 
    1691             :                 /*
    1692             :                  * Increment the checkpoint and try again. Abort after 12
    1693             :                  * checkpoints as the postmaster has probably hung.
    1694             :                  */
    1695             :                 while (WaitForSingleObject(postmasterProcess, 5000) == WAIT_TIMEOUT && status.dwCheckPoint < maxShutdownCheckPoint)
    1696             :                 {
    1697             :                     status.dwCheckPoint++;
    1698             :                     SetServiceStatus(hStatus, (LPSERVICE_STATUS) &status);
    1699             :                 }
    1700             :                 break;
    1701             :             }
    1702             : 
    1703             :         case (WAIT_OBJECT_0 + 1):   /* postmaster went down */
    1704             :             break;
    1705             : 
    1706             :         default:
    1707             :             /* shouldn't get here? */
    1708             :             break;
    1709             :     }
    1710             : 
    1711             :     CloseHandle(shutdownEvent);
    1712             :     CloseHandle(postmasterProcess);
    1713             : 
    1714             :     pgwin32_SetServiceStatus(SERVICE_STOPPED);
    1715             : }
    1716             : 
    1717             : static void
    1718             : pgwin32_doRunAsService(void)
    1719             : {
    1720             :     SERVICE_TABLE_ENTRY st[] = {{register_servicename, pgwin32_ServiceMain},
    1721             :     {NULL, NULL}};
    1722             : 
    1723             :     if (StartServiceCtrlDispatcher(st) == 0)
    1724             :     {
    1725             :         write_stderr(_("%s: could not start service \"%s\": error code %lu\n"),
    1726             :                      progname, register_servicename,
    1727             :                      (unsigned long) GetLastError());
    1728             :         exit(1);
    1729             :     }
    1730             : }
    1731             : 
    1732             : 
    1733             : /*
    1734             :  * Mingw headers are incomplete, and so are the libraries. So we have to load
    1735             :  * a whole lot of API functions dynamically. Since we have to do this anyway,
    1736             :  * also load the couple of functions that *do* exist in mingw headers but not
    1737             :  * on NT4. That way, we don't break on NT4.
    1738             :  */
    1739             : typedef BOOL (WINAPI * __CreateRestrictedToken) (HANDLE, DWORD, DWORD, PSID_AND_ATTRIBUTES, DWORD, PLUID_AND_ATTRIBUTES, DWORD, PSID_AND_ATTRIBUTES, PHANDLE);
    1740             : typedef BOOL (WINAPI * __IsProcessInJob) (HANDLE, HANDLE, PBOOL);
    1741             : typedef HANDLE (WINAPI * __CreateJobObject) (LPSECURITY_ATTRIBUTES, LPCTSTR);
    1742             : typedef BOOL (WINAPI * __SetInformationJobObject) (HANDLE, JOBOBJECTINFOCLASS, LPVOID, DWORD);
    1743             : typedef BOOL (WINAPI * __AssignProcessToJobObject) (HANDLE, HANDLE);
    1744             : typedef BOOL (WINAPI * __QueryInformationJobObject) (HANDLE, JOBOBJECTINFOCLASS, LPVOID, DWORD, LPDWORD);
    1745             : 
    1746             : /*
    1747             :  * Create a restricted token, a job object sandbox, and execute the specified
    1748             :  * process with it.
    1749             :  *
    1750             :  * Returns 0 on success, non-zero on failure, same as CreateProcess().
    1751             :  *
    1752             :  * On NT4, or any other system not containing the required functions, will
    1753             :  * launch the process under the current token without doing any modifications.
    1754             :  *
    1755             :  * NOTE! Job object will only work when running as a service, because it's
    1756             :  * automatically destroyed when pg_ctl exits.
    1757             :  */
    1758             : static int
    1759             : CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, bool as_service)
    1760             : {
    1761             :     int         r;
    1762             :     BOOL        b;
    1763             :     STARTUPINFO si;
    1764             :     HANDLE      origToken;
    1765             :     HANDLE      restrictedToken;
    1766             :     SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
    1767             :     SID_AND_ATTRIBUTES dropSids[2];
    1768             :     PTOKEN_PRIVILEGES delPrivs;
    1769             : 
    1770             :     /* Functions loaded dynamically */
    1771             :     __CreateRestrictedToken _CreateRestrictedToken = NULL;
    1772             :     __IsProcessInJob _IsProcessInJob = NULL;
    1773             :     __CreateJobObject _CreateJobObject = NULL;
    1774             :     __SetInformationJobObject _SetInformationJobObject = NULL;
    1775             :     __AssignProcessToJobObject _AssignProcessToJobObject = NULL;
    1776             :     __QueryInformationJobObject _QueryInformationJobObject = NULL;
    1777             :     HANDLE      Kernel32Handle;
    1778             :     HANDLE      Advapi32Handle;
    1779             : 
    1780             :     ZeroMemory(&si, sizeof(si));
    1781             :     si.cb = sizeof(si);
    1782             : 
    1783             :     Advapi32Handle = LoadLibrary("ADVAPI32.DLL");
    1784             :     if (Advapi32Handle != NULL)
    1785             :     {
    1786             :         _CreateRestrictedToken = (__CreateRestrictedToken) GetProcAddress(Advapi32Handle, "CreateRestrictedToken");
    1787             :     }
    1788             : 
    1789             :     if (_CreateRestrictedToken == NULL)
    1790             :     {
    1791             :         /*
    1792             :          * NT4 doesn't have CreateRestrictedToken, so just call ordinary
    1793             :          * CreateProcess
    1794             :          */
    1795             :         write_stderr(_("%s: WARNING: cannot create restricted tokens on this platform\n"), progname);
    1796             :         if (Advapi32Handle != NULL)
    1797             :             FreeLibrary(Advapi32Handle);
    1798             :         return CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, processInfo);
    1799             :     }
    1800             : 
    1801             :     /* Open the current token to use as a base for the restricted one */
    1802             :     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &origToken))
    1803             :     {
    1804             :         /*
    1805             :          * Most Windows targets make DWORD a 32-bit unsigned long, but in case
    1806             :          * it doesn't cast DWORD before printing.
    1807             :          */
    1808             :         write_stderr(_("%s: could not open process token: error code %lu\n"),
    1809             :                      progname, (unsigned long) GetLastError());
    1810             :         return 0;
    1811             :     }
    1812             : 
    1813             :     /* Allocate list of SIDs to remove */
    1814             :     ZeroMemory(&dropSids, sizeof(dropSids));
    1815             :     if (!AllocateAndInitializeSid(&NtAuthority, 2,
    1816             :                                   SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,
    1817             :                                   0, &dropSids[0].Sid) ||
    1818             :         !AllocateAndInitializeSid(&NtAuthority, 2,
    1819             :                                   SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0,
    1820             :                                   0, &dropSids[1].Sid))
    1821             :     {
    1822             :         write_stderr(_("%s: could not allocate SIDs: error code %lu\n"),
    1823             :                      progname, (unsigned long) GetLastError());
    1824             :         return 0;
    1825             :     }
    1826             : 
    1827             :     /* Get list of privileges to remove */
    1828             :     delPrivs = GetPrivilegesToDelete(origToken);
    1829             :     if (delPrivs == NULL)
    1830             :         /* Error message already printed */
    1831             :         return 0;
    1832             : 
    1833             :     b = _CreateRestrictedToken(origToken,
    1834             :                                0,
    1835             :                                sizeof(dropSids) / sizeof(dropSids[0]),
    1836             :                                dropSids,
    1837             :                                delPrivs->PrivilegeCount, delPrivs->Privileges,
    1838             :                                0, NULL,
    1839             :                                &restrictedToken);
    1840             : 
    1841             :     free(delPrivs);
    1842             :     FreeSid(dropSids[1].Sid);
    1843             :     FreeSid(dropSids[0].Sid);
    1844             :     CloseHandle(origToken);
    1845             :     FreeLibrary(Advapi32Handle);
    1846             : 
    1847             :     if (!b)
    1848             :     {
    1849             :         write_stderr(_("%s: could not create restricted token: error code %lu\n"),
    1850             :                      progname, (unsigned long) GetLastError());
    1851             :         return 0;
    1852             :     }
    1853             : 
    1854             :     AddUserToTokenDacl(restrictedToken);
    1855             :     r = CreateProcessAsUser(restrictedToken, NULL, cmd, NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, NULL, &si, processInfo);
    1856             : 
    1857             :     Kernel32Handle = LoadLibrary("KERNEL32.DLL");
    1858             :     if (Kernel32Handle != NULL)
    1859             :     {
    1860             :         _IsProcessInJob = (__IsProcessInJob) GetProcAddress(Kernel32Handle, "IsProcessInJob");
    1861             :         _CreateJobObject = (__CreateJobObject) GetProcAddress(Kernel32Handle, "CreateJobObjectA");
    1862             :         _SetInformationJobObject = (__SetInformationJobObject) GetProcAddress(Kernel32Handle, "SetInformationJobObject");
    1863             :         _AssignProcessToJobObject = (__AssignProcessToJobObject) GetProcAddress(Kernel32Handle, "AssignProcessToJobObject");
    1864             :         _QueryInformationJobObject = (__QueryInformationJobObject) GetProcAddress(Kernel32Handle, "QueryInformationJobObject");
    1865             :     }
    1866             : 
    1867             :     /* Verify that we found all functions */
    1868             :     if (_IsProcessInJob == NULL || _CreateJobObject == NULL || _SetInformationJobObject == NULL || _AssignProcessToJobObject == NULL || _QueryInformationJobObject == NULL)
    1869             :     {
    1870             :         /*
    1871             :          * IsProcessInJob() is not available on < WinXP, so there is no need
    1872             :          * to log the error every time in that case
    1873             :          */
    1874             :         if (IsWindowsXPOrGreater())
    1875             : 
    1876             :             /*
    1877             :              * Log error if we can't get version, or if we're on WinXP/2003 or
    1878             :              * newer
    1879             :              */
    1880             :             write_stderr(_("%s: WARNING: could not locate all job object functions in system API\n"), progname);
    1881             :     }
    1882             :     else
    1883             :     {
    1884             :         BOOL        inJob;
    1885             : 
    1886             :         if (_IsProcessInJob(processInfo->hProcess, NULL, &inJob))
    1887             :         {
    1888             :             if (!inJob)
    1889             :             {
    1890             :                 /*
    1891             :                  * Job objects are working, and the new process isn't in one,
    1892             :                  * so we can create one safely. If any problems show up when
    1893             :                  * setting it, we're going to ignore them.
    1894             :                  */
    1895             :                 HANDLE      job;
    1896             :                 char        jobname[128];
    1897             : 
    1898             :                 sprintf(jobname, "PostgreSQL_%lu",
    1899             :                         (unsigned long) processInfo->dwProcessId);
    1900             : 
    1901             :                 job = _CreateJobObject(NULL, jobname);
    1902             :                 if (job)
    1903             :                 {
    1904             :                     JOBOBJECT_BASIC_LIMIT_INFORMATION basicLimit;
    1905             :                     JOBOBJECT_BASIC_UI_RESTRICTIONS uiRestrictions;
    1906             :                     JOBOBJECT_SECURITY_LIMIT_INFORMATION securityLimit;
    1907             : 
    1908             :                     ZeroMemory(&basicLimit, sizeof(basicLimit));
    1909             :                     ZeroMemory(&uiRestrictions, sizeof(uiRestrictions));
    1910             :                     ZeroMemory(&securityLimit, sizeof(securityLimit));
    1911             : 
    1912             :                     basicLimit.LimitFlags = JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION | JOB_OBJECT_LIMIT_PRIORITY_CLASS;
    1913             :                     basicLimit.PriorityClass = NORMAL_PRIORITY_CLASS;
    1914             :                     _SetInformationJobObject(job, JobObjectBasicLimitInformation, &basicLimit, sizeof(basicLimit));
    1915             : 
    1916             :                     uiRestrictions.UIRestrictionsClass = JOB_OBJECT_UILIMIT_DESKTOP | JOB_OBJECT_UILIMIT_DISPLAYSETTINGS |
    1917             :                         JOB_OBJECT_UILIMIT_EXITWINDOWS | JOB_OBJECT_UILIMIT_READCLIPBOARD |
    1918             :                         JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS | JOB_OBJECT_UILIMIT_WRITECLIPBOARD;
    1919             : 
    1920             :                     if (as_service)
    1921             :                     {
    1922             :                         if (!IsWindows7OrGreater())
    1923             :                         {
    1924             :                             /*
    1925             :                              * On Windows 7 (and presumably later),
    1926             :                              * JOB_OBJECT_UILIMIT_HANDLES prevents us from
    1927             :                              * starting as a service. So we only enable it on
    1928             :                              * Vista and earlier (version <= 6.0)
    1929             :                              */
    1930             :                             uiRestrictions.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_HANDLES;
    1931             :                         }
    1932             :                     }
    1933             :                     _SetInformationJobObject(job, JobObjectBasicUIRestrictions, &uiRestrictions, sizeof(uiRestrictions));
    1934             : 
    1935             :                     securityLimit.SecurityLimitFlags = JOB_OBJECT_SECURITY_NO_ADMIN | JOB_OBJECT_SECURITY_ONLY_TOKEN;
    1936             :                     securityLimit.JobToken = restrictedToken;
    1937             :                     _SetInformationJobObject(job, JobObjectSecurityLimitInformation, &securityLimit, sizeof(securityLimit));
    1938             : 
    1939             :                     _AssignProcessToJobObject(job, processInfo->hProcess);
    1940             :                 }
    1941             :             }
    1942             :         }
    1943             :     }
    1944             : 
    1945             : 
    1946             :     CloseHandle(restrictedToken);
    1947             : 
    1948             :     ResumeThread(processInfo->hThread);
    1949             : 
    1950             :     FreeLibrary(Kernel32Handle);
    1951             : 
    1952             :     /*
    1953             :      * We intentionally don't close the job object handle, because we want the
    1954             :      * object to live on until pg_ctl shuts down.
    1955             :      */
    1956             :     return r;
    1957             : }
    1958             : 
    1959             : /*
    1960             :  * Get a list of privileges to delete from the access token. We delete all privileges
    1961             :  * except SeLockMemoryPrivilege which is needed to use large pages, and
    1962             :  * SeChangeNotifyPrivilege which is enabled by default in DISABLE_MAX_PRIVILEGE.
    1963             :  */
    1964             : static PTOKEN_PRIVILEGES
    1965             : GetPrivilegesToDelete(HANDLE hToken)
    1966             : {
    1967             :     int         i,
    1968             :                 j;
    1969             :     DWORD       length;
    1970             :     PTOKEN_PRIVILEGES tokenPrivs;
    1971             :     LUID        luidLockPages;
    1972             :     LUID        luidChangeNotify;
    1973             : 
    1974             :     if (!LookupPrivilegeValue(NULL, SE_LOCK_MEMORY_NAME, &luidLockPages) ||
    1975             :         !LookupPrivilegeValue(NULL, SE_CHANGE_NOTIFY_NAME, &luidChangeNotify))
    1976             :     {
    1977             :         write_stderr(_("%s: could not get LUIDs for privileges: error code %lu\n"),
    1978             :                      progname, (unsigned long) GetLastError());
    1979             :         return NULL;
    1980             :     }
    1981             : 
    1982             :     if (!GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &length) &&
    1983             :         GetLastError() != ERROR_INSUFFICIENT_BUFFER)
    1984             :     {
    1985             :         write_stderr(_("%s: could not get token information: error code %lu\n"),
    1986             :                      progname, (unsigned long) GetLastError());
    1987             :         return NULL;
    1988             :     }
    1989             : 
    1990             :     tokenPrivs = (PTOKEN_PRIVILEGES) pg_malloc_extended(length,
    1991             :                                                         MCXT_ALLOC_NO_OOM);
    1992             :     if (tokenPrivs == NULL)
    1993             :     {
    1994             :         write_stderr(_("%s: out of memory\n"), progname);
    1995             :         return NULL;
    1996             :     }
    1997             : 
    1998             :     if (!GetTokenInformation(hToken, TokenPrivileges, tokenPrivs, length, &length))
    1999             :     {
    2000             :         write_stderr(_("%s: could not get token information: error code %lu\n"),
    2001             :                      progname, (unsigned long) GetLastError());
    2002             :         free(tokenPrivs);
    2003             :         return NULL;
    2004             :     }
    2005             : 
    2006             :     for (i = 0; i < tokenPrivs->PrivilegeCount; i++)
    2007             :     {
    2008             :         if (memcmp(&tokenPrivs->Privileges[i].Luid, &luidLockPages, sizeof(LUID)) == 0 ||
    2009             :             memcmp(&tokenPrivs->Privileges[i].Luid, &luidChangeNotify, sizeof(LUID)) == 0)
    2010             :         {
    2011             :             for (j = i; j < tokenPrivs->PrivilegeCount - 1; j++)
    2012             :                 tokenPrivs->Privileges[j] = tokenPrivs->Privileges[j + 1];
    2013             :             tokenPrivs->PrivilegeCount--;
    2014             :         }
    2015             :     }
    2016             : 
    2017             :     return tokenPrivs;
    2018             : }
    2019             : #endif                          /* WIN32 */
    2020             : 
    2021             : static void
    2022           2 : do_advice(void)
    2023             : {
    2024           2 :     write_stderr(_("Try \"%s --help\" for more information.\n"), progname);
    2025           2 : }
    2026             : 
    2027             : 
    2028             : 
    2029             : static void
    2030           2 : do_help(void)
    2031             : {
    2032           2 :     printf(_("%s is a utility to initialize, start, stop, or control a PostgreSQL server.\n\n"), progname);
    2033           2 :     printf(_("Usage:\n"));
    2034           2 :     printf(_("  %s init[db]   [-D DATADIR] [-s] [-o OPTIONS]\n"), progname);
    2035           2 :     printf(_("  %s start      [-D DATADIR] [-l FILENAME] [-W] [-t SECS] [-s]\n"
    2036             :              "                    [-o OPTIONS] [-p PATH] [-c]\n"), progname);
    2037           2 :     printf(_("  %s stop       [-D DATADIR] [-m SHUTDOWN-MODE] [-W] [-t SECS] [-s]\n"), progname);
    2038           2 :     printf(_("  %s restart    [-D DATADIR] [-m SHUTDOWN-MODE] [-W] [-t SECS] [-s]\n"
    2039             :              "                    [-o OPTIONS] [-c]\n"), progname);
    2040           2 :     printf(_("  %s reload     [-D DATADIR] [-s]\n"), progname);
    2041           2 :     printf(_("  %s status     [-D DATADIR]\n"), progname);
    2042           2 :     printf(_("  %s promote    [-D DATADIR] [-W] [-t SECS] [-s]\n"), progname);
    2043           2 :     printf(_("  %s logrotate  [-D DATADIR] [-s]\n"), progname);
    2044           2 :     printf(_("  %s kill       SIGNALNAME PID\n"), progname);
    2045             : #ifdef WIN32
    2046             :     printf(_("  %s register   [-D DATADIR] [-N SERVICENAME] [-U USERNAME] [-P PASSWORD]\n"
    2047             :              "                    [-S START-TYPE] [-e SOURCE] [-W] [-t SECS] [-s] [-o OPTIONS]\n"), progname);
    2048             :     printf(_("  %s unregister [-N SERVICENAME]\n"), progname);
    2049             : #endif
    2050             : 
    2051           2 :     printf(_("\nCommon options:\n"));
    2052           2 :     printf(_("  -D, --pgdata=DATADIR   location of the database storage area\n"));
    2053             : #ifdef WIN32
    2054             :     printf(_("  -e SOURCE              event source for logging when running as a service\n"));
    2055             : #endif
    2056           2 :     printf(_("  -s, --silent           only print errors, no informational messages\n"));
    2057           2 :     printf(_("  -t, --timeout=SECS     seconds to wait when using -w option\n"));
    2058           2 :     printf(_("  -V, --version          output version information, then exit\n"));
    2059           2 :     printf(_("  -w, --wait             wait until operation completes (default)\n"));
    2060           2 :     printf(_("  -W, --no-wait          do not wait until operation completes\n"));
    2061           2 :     printf(_("  -?, --help             show this help, then exit\n"));
    2062           2 :     printf(_("If the -D option is omitted, the environment variable PGDATA is used.\n"));
    2063             : 
    2064           2 :     printf(_("\nOptions for start or restart:\n"));
    2065             : #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
    2066           2 :     printf(_("  -c, --core-files       allow postgres to produce core files\n"));
    2067             : #else
    2068             :     printf(_("  -c, --core-files       not applicable on this platform\n"));
    2069             : #endif
    2070           2 :     printf(_("  -l, --log=FILENAME     write (or append) server log to FILENAME\n"));
    2071           2 :     printf(_("  -o, --options=OPTIONS  command line options to pass to postgres\n"
    2072             :              "                         (PostgreSQL server executable) or initdb\n"));
    2073           2 :     printf(_("  -p PATH-TO-POSTGRES    normally not necessary\n"));
    2074           2 :     printf(_("\nOptions for stop or restart:\n"));
    2075           2 :     printf(_("  -m, --mode=MODE        MODE can be \"smart\", \"fast\", or \"immediate\"\n"));
    2076             : 
    2077           2 :     printf(_("\nShutdown modes are:\n"));
    2078           2 :     printf(_("  smart       quit after all clients have disconnected\n"));
    2079           2 :     printf(_("  fast        quit directly, with proper shutdown (default)\n"));
    2080           2 :     printf(_("  immediate   quit without complete shutdown; will lead to recovery on restart\n"));
    2081             : 
    2082           2 :     printf(_("\nAllowed signal names for kill:\n"));
    2083           2 :     printf("  ABRT HUP INT KILL QUIT TERM USR1 USR2\n");
    2084             : 
    2085             : #ifdef WIN32
    2086             :     printf(_("\nOptions for register and unregister:\n"));
    2087             :     printf(_("  -N SERVICENAME  service name with which to register PostgreSQL server\n"));
    2088             :     printf(_("  -P PASSWORD     password of account to register PostgreSQL server\n"));
    2089             :     printf(_("  -U USERNAME     user name of account to register PostgreSQL server\n"));
    2090             :     printf(_("  -S START-TYPE   service start type to register PostgreSQL server\n"));
    2091             : 
    2092             :     printf(_("\nStart types are:\n"));
    2093             :     printf(_("  auto       start service automatically during system startup (default)\n"));
    2094             :     printf(_("  demand     start service on demand\n"));
    2095             : #endif
    2096             : 
    2097           2 :     printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
    2098           2 :     printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
    2099           2 : }
    2100             : 
    2101             : 
    2102             : 
    2103             : static void
    2104         478 : set_mode(char *modeopt)
    2105             : {
    2106         478 :     if (strcmp(modeopt, "s") == 0 || strcmp(modeopt, "smart") == 0)
    2107             :     {
    2108           8 :         shutdown_mode = SMART_MODE;
    2109           8 :         sig = SIGTERM;
    2110             :     }
    2111         470 :     else if (strcmp(modeopt, "f") == 0 || strcmp(modeopt, "fast") == 0)
    2112             :     {
    2113         154 :         shutdown_mode = FAST_MODE;
    2114         154 :         sig = SIGINT;
    2115             :     }
    2116         316 :     else if (strcmp(modeopt, "i") == 0 || strcmp(modeopt, "immediate") == 0)
    2117             :     {
    2118         316 :         shutdown_mode = IMMEDIATE_MODE;
    2119         316 :         sig = SIGQUIT;
    2120             :     }
    2121             :     else
    2122             :     {
    2123           0 :         write_stderr(_("%s: unrecognized shutdown mode \"%s\"\n"), progname, modeopt);
    2124           0 :         do_advice();
    2125           0 :         exit(1);
    2126             :     }
    2127         478 : }
    2128             : 
    2129             : 
    2130             : 
    2131             : static void
    2132           6 : set_sig(char *signame)
    2133             : {
    2134           6 :     if (strcmp(signame, "HUP") == 0)
    2135           0 :         sig = SIGHUP;
    2136           6 :     else if (strcmp(signame, "INT") == 0)
    2137           0 :         sig = SIGINT;
    2138           6 :     else if (strcmp(signame, "QUIT") == 0)
    2139           4 :         sig = SIGQUIT;
    2140           2 :     else if (strcmp(signame, "ABRT") == 0)
    2141           0 :         sig = SIGABRT;
    2142           2 :     else if (strcmp(signame, "KILL") == 0)
    2143           2 :         sig = SIGKILL;
    2144           0 :     else if (strcmp(signame, "TERM") == 0)
    2145           0 :         sig = SIGTERM;
    2146           0 :     else if (strcmp(signame, "USR1") == 0)
    2147           0 :         sig = SIGUSR1;
    2148           0 :     else if (strcmp(signame, "USR2") == 0)
    2149           0 :         sig = SIGUSR2;
    2150             :     else
    2151             :     {
    2152           0 :         write_stderr(_("%s: unrecognized signal name \"%s\"\n"), progname, signame);
    2153           0 :         do_advice();
    2154           0 :         exit(1);
    2155             :     }
    2156           6 : }
    2157             : 
    2158             : 
    2159             : #ifdef WIN32
    2160             : static void
    2161             : set_starttype(char *starttypeopt)
    2162             : {
    2163             :     if (strcmp(starttypeopt, "a") == 0 || strcmp(starttypeopt, "auto") == 0)
    2164             :         pgctl_start_type = SERVICE_AUTO_START;
    2165             :     else if (strcmp(starttypeopt, "d") == 0 || strcmp(starttypeopt, "demand") == 0)
    2166             :         pgctl_start_type = SERVICE_DEMAND_START;
    2167             :     else
    2168             :     {
    2169             :         write_stderr(_("%s: unrecognized start type \"%s\"\n"), progname, starttypeopt);
    2170             :         do_advice();
    2171             :         exit(1);
    2172             :     }
    2173             : }
    2174             : #endif
    2175             : 
    2176             : /*
    2177             :  * adjust_data_dir
    2178             :  *
    2179             :  * If a configuration-only directory was specified, find the real data dir.
    2180             :  */
    2181             : static void
    2182        1350 : adjust_data_dir(void)
    2183             : {
    2184             :     char        cmd[MAXPGPATH],
    2185             :                 filename[MAXPGPATH],
    2186             :                *my_exec_path;
    2187             :     FILE       *fd;
    2188             : 
    2189             :     /* do nothing if we're working without knowledge of data dir */
    2190        1350 :     if (pg_config == NULL)
    2191        1350 :         return;
    2192             : 
    2193             :     /* If there is no postgresql.conf, it can't be a config-only dir */
    2194        1344 :     snprintf(filename, sizeof(filename), "%s/postgresql.conf", pg_config);
    2195        1344 :     if ((fd = fopen(filename, "r")) == NULL)
    2196           8 :         return;
    2197        1336 :     fclose(fd);
    2198             : 
    2199             :     /* If PG_VERSION exists, it can't be a config-only dir */
    2200        1336 :     snprintf(filename, sizeof(filename), "%s/PG_VERSION", pg_config);
    2201        1336 :     if ((fd = fopen(filename, "r")) != NULL)
    2202             :     {
    2203        1336 :         fclose(fd);
    2204        1336 :         return;
    2205             :     }
    2206             : 
    2207             :     /* Must be a configuration directory, so find the data directory */
    2208             : 
    2209             :     /* we use a private my_exec_path to avoid interfering with later uses */
    2210           0 :     if (exec_path == NULL)
    2211           0 :         my_exec_path = find_other_exec_or_die(argv0, "postgres", PG_BACKEND_VERSIONSTR);
    2212             :     else
    2213           0 :         my_exec_path = pg_strdup(exec_path);
    2214             : 
    2215             :     /* it's important for -C to be the first option, see main.c */
    2216           0 :     snprintf(cmd, MAXPGPATH, "\"%s\" -C data_directory %s%s",
    2217             :              my_exec_path,
    2218           0 :              pgdata_opt ? pgdata_opt : "",
    2219           0 :              post_opts ? post_opts : "");
    2220             : 
    2221           0 :     fd = popen(cmd, "r");
    2222           0 :     if (fd == NULL || fgets(filename, sizeof(filename), fd) == NULL)
    2223             :     {
    2224           0 :         write_stderr(_("%s: could not determine the data directory using command \"%s\"\n"), progname, cmd);
    2225           0 :         exit(1);
    2226             :     }
    2227           0 :     pclose(fd);
    2228           0 :     free(my_exec_path);
    2229             : 
    2230             :     /* strip trailing newline and carriage return */
    2231           0 :     (void) pg_strip_crlf(filename);
    2232             : 
    2233           0 :     free(pg_data);
    2234           0 :     pg_data = pg_strdup(filename);
    2235           0 :     canonicalize_path(pg_data);
    2236             : }
    2237             : 
    2238             : 
    2239             : static DBState
    2240         164 : get_control_dbstate(void)
    2241             : {
    2242             :     DBState     ret;
    2243             :     bool        crc_ok;
    2244         164 :     ControlFileData *control_file_data = get_controlfile(pg_data, &crc_ok);
    2245             : 
    2246         164 :     if (!crc_ok)
    2247             :     {
    2248           0 :         write_stderr(_("%s: control file appears to be corrupt\n"), progname);
    2249           0 :         exit(1);
    2250             :     }
    2251             : 
    2252         164 :     ret = control_file_data->state;
    2253         164 :     pfree(control_file_data);
    2254         164 :     return ret;
    2255             : }
    2256             : 
    2257             : 
    2258             : int
    2259        1360 : main(int argc, char **argv)
    2260             : {
    2261             :     static struct option long_options[] = {
    2262             :         {"help", no_argument, NULL, '?'},
    2263             :         {"version", no_argument, NULL, 'V'},
    2264             :         {"log", required_argument, NULL, 'l'},
    2265             :         {"mode", required_argument, NULL, 'm'},
    2266             :         {"pgdata", required_argument, NULL, 'D'},
    2267             :         {"options", required_argument, NULL, 'o'},
    2268             :         {"silent", no_argument, NULL, 's'},
    2269             :         {"timeout", required_argument, NULL, 't'},
    2270             :         {"core-files", no_argument, NULL, 'c'},
    2271             :         {"wait", no_argument, NULL, 'w'},
    2272             :         {"no-wait", no_argument, NULL, 'W'},
    2273             :         {NULL, 0, NULL, 0}
    2274             :     };
    2275             : 
    2276             :     char       *env_wait;
    2277             :     int         option_index;
    2278             :     int         c;
    2279        1360 :     pgpid_t     killproc = 0;
    2280             : 
    2281        1360 :     pg_logging_init(argv[0]);
    2282        1360 :     progname = get_progname(argv[0]);
    2283        1360 :     set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_ctl"));
    2284        1360 :     start_time = time(NULL);
    2285             : 
    2286             :     /*
    2287             :      * save argv[0] so do_start() can look for the postmaster if necessary. we
    2288             :      * don't look for postmaster here because in many cases we won't need it.
    2289             :      */
    2290        1360 :     argv0 = argv[0];
    2291             : 
    2292             :     /* Set restrictive mode mask until PGDATA permissions are checked */
    2293        1360 :     umask(PG_MODE_MASK_OWNER);
    2294             : 
    2295             :     /* support --help and --version even if invoked as root */
    2296        1360 :     if (argc > 1)
    2297             :     {
    2298        1360 :         if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
    2299             :         {
    2300           2 :             do_help();
    2301           2 :             exit(0);
    2302             :         }
    2303        1358 :         else if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
    2304             :         {
    2305           6 :             puts("pg_ctl (PostgreSQL) " PG_VERSION);
    2306           6 :             exit(0);
    2307             :         }
    2308             :     }
    2309             : 
    2310             :     /*
    2311             :      * Disallow running as root, to forestall any possible security holes.
    2312             :      */
    2313             : #ifndef WIN32
    2314        1352 :     if (geteuid() == 0)
    2315             :     {
    2316           0 :         write_stderr(_("%s: cannot be run as root\n"
    2317             :                        "Please log in (using, e.g., \"su\") as the "
    2318             :                        "(unprivileged) user that will\n"
    2319             :                        "own the server process.\n"),
    2320             :                      progname);
    2321           0 :         exit(1);
    2322             :     }
    2323             : #endif
    2324             : 
    2325        1352 :     env_wait = getenv("PGCTLTIMEOUT");
    2326        1352 :     if (env_wait != NULL)
    2327           0 :         wait_seconds = atoi(env_wait);
    2328             : 
    2329             :     /*
    2330             :      * 'Action' can be before or after args so loop over both. Some
    2331             :      * getopt_long() implementations will reorder argv[] to place all flags
    2332             :      * first (GNU?), but we don't rely on it. Our /port version doesn't do
    2333             :      * that.
    2334             :      */
    2335        1352 :     optind = 1;
    2336             : 
    2337             :     /* process command-line options */
    2338        2702 :     while (optind < argc)
    2339             :     {
    2340        4446 :         while ((c = getopt_long(argc, argv, "cD:e:l:m:N:o:p:P:sS:t:U:wW",
    2341             :                                 long_options, &option_index)) != -1)
    2342             :         {
    2343        3096 :             switch (c)
    2344             :             {
    2345        1336 :                 case 'D':
    2346             :                     {
    2347             :                         char       *pgdata_D;
    2348             :                         char       *env_var;
    2349             : 
    2350        1336 :                         pgdata_D = pg_strdup(optarg);
    2351        1336 :                         canonicalize_path(pgdata_D);
    2352        1336 :                         env_var = psprintf("PGDATA=%s", pgdata_D);
    2353        1336 :                         putenv(env_var);
    2354             : 
    2355             :                         /*
    2356             :                          * We could pass PGDATA just in an environment
    2357             :                          * variable but we do -D too for clearer postmaster
    2358             :                          * 'ps' display
    2359             :                          */
    2360        1336 :                         pgdata_opt = psprintf("-D \"%s\" ", pgdata_D);
    2361        1336 :                         break;
    2362             :                     }
    2363           0 :                 case 'e':
    2364           0 :                     event_source = pg_strdup(optarg);
    2365           0 :                     break;
    2366         628 :                 case 'l':
    2367         628 :                     log_file = pg_strdup(optarg);
    2368         628 :                     break;
    2369         478 :                 case 'm':
    2370         478 :                     set_mode(optarg);
    2371         478 :                     break;
    2372           0 :                 case 'N':
    2373           0 :                     register_servicename = pg_strdup(optarg);
    2374           0 :                     break;
    2375         496 :                 case 'o':
    2376             :                     /* append option? */
    2377         496 :                     if (!post_opts)
    2378         496 :                         post_opts = pg_strdup(optarg);
    2379             :                     else
    2380             :                     {
    2381           0 :                         char       *old_post_opts = post_opts;
    2382             : 
    2383           0 :                         post_opts = psprintf("%s %s", old_post_opts, optarg);
    2384           0 :                         free(old_post_opts);
    2385             :                     }
    2386         496 :                     break;
    2387           0 :                 case 'p':
    2388           0 :                     exec_path = pg_strdup(optarg);
    2389           0 :                     break;
    2390           0 :                 case 'P':
    2391           0 :                     register_password = pg_strdup(optarg);
    2392           0 :                     break;
    2393         132 :                 case 's':
    2394         132 :                     silent_mode = true;
    2395         132 :                     break;
    2396           0 :                 case 'S':
    2397             : #ifdef WIN32
    2398             :                     set_starttype(optarg);
    2399             : #else
    2400           0 :                     write_stderr(_("%s: -S option not supported on this platform\n"),
    2401             :                                  progname);
    2402           0 :                     exit(1);
    2403             : #endif
    2404             :                     break;
    2405           0 :                 case 't':
    2406           0 :                     wait_seconds = atoi(optarg);
    2407           0 :                     wait_seconds_arg = true;
    2408           0 :                     break;
    2409           0 :                 case 'U':
    2410           0 :                     if (strchr(optarg, '\\'))
    2411           0 :                         register_username = pg_strdup(optarg);
    2412             :                     else
    2413             :                         /* Prepend .\ for local accounts */
    2414           0 :                         register_username = psprintf(".\\%s", optarg);
    2415           0 :                     break;
    2416          22 :                 case 'w':
    2417          22 :                     do_wait = true;
    2418          22 :                     break;
    2419           2 :                 case 'W':
    2420           2 :                     do_wait = false;
    2421           2 :                     break;
    2422           0 :                 case 'c':
    2423           0 :                     allow_core_files = true;
    2424           0 :                     break;
    2425           2 :                 default:
    2426             :                     /* getopt_long already issued a suitable error message */
    2427           2 :                     do_advice();
    2428           2 :                     exit(1);
    2429             :             }
    2430             :         }
    2431             : 
    2432             :         /* Process an action */
    2433        1350 :         if (optind < argc)
    2434             :         {
    2435        1350 :             if (ctl_command != NO_COMMAND)
    2436             :             {
    2437           0 :                 write_stderr(_("%s: too many command-line arguments (first is \"%s\")\n"), progname, argv[optind]);
    2438           0 :                 do_advice();
    2439           0 :                 exit(1);
    2440             :             }
    2441             : 
    2442        1350 :             if (strcmp(argv[optind], "init") == 0
    2443        1350 :                 || strcmp(argv[optind], "initdb") == 0)
    2444           2 :                 ctl_command = INIT_COMMAND;
    2445        1348 :             else if (strcmp(argv[optind], "start") == 0)
    2446         508 :                 ctl_command = START_COMMAND;
    2447         840 :             else if (strcmp(argv[optind], "stop") == 0)
    2448         626 :                 ctl_command = STOP_COMMAND;
    2449         214 :             else if (strcmp(argv[optind], "restart") == 0)
    2450          90 :                 ctl_command = RESTART_COMMAND;
    2451         124 :             else if (strcmp(argv[optind], "reload") == 0)
    2452          58 :                 ctl_command = RELOAD_COMMAND;
    2453          66 :             else if (strcmp(argv[optind], "status") == 0)
    2454           6 :                 ctl_command = STATUS_COMMAND;
    2455          60 :             else if (strcmp(argv[optind], "promote") == 0)
    2456          52 :                 ctl_command = PROMOTE_COMMAND;
    2457           8 :             else if (strcmp(argv[optind], "logrotate") == 0)
    2458           2 :                 ctl_command = LOGROTATE_COMMAND;
    2459           6 :             else if (strcmp(argv[optind], "kill") == 0)
    2460             :             {
    2461           6 :                 if (argc - optind < 3)
    2462             :                 {
    2463           0 :                     write_stderr(_("%s: missing arguments for kill mode\n"), progname);
    2464           0 :                     do_advice();
    2465           0 :                     exit(1);
    2466             :                 }
    2467           6 :                 ctl_command = KILL_COMMAND;
    2468           6 :                 set_sig(argv[++optind]);
    2469           6 :                 killproc = atol(argv[++optind]);
    2470             :             }
    2471             : #ifdef WIN32
    2472             :             else if (strcmp(argv[optind], "register") == 0)
    2473             :                 ctl_command = REGISTER_COMMAND;
    2474             :             else if (strcmp(argv[optind], "unregister") == 0)
    2475             :                 ctl_command = UNREGISTER_COMMAND;
    2476             :             else if (strcmp(argv[optind], "runservice") == 0)
    2477             :                 ctl_command = RUN_AS_SERVICE_COMMAND;
    2478             : #endif
    2479             :             else
    2480             :             {
    2481           0 :                 write_stderr(_("%s: unrecognized operation mode \"%s\"\n"), progname, argv[optind]);
    2482           0 :                 do_advice();
    2483           0 :                 exit(1);
    2484             :             }
    2485        1350 :             optind++;
    2486             :         }
    2487             :     }
    2488             : 
    2489        1350 :     if (ctl_command == NO_COMMAND)
    2490             :     {
    2491           0 :         write_stderr(_("%s: no operation specified\n"), progname);
    2492           0 :         do_advice();
    2493           0 :         exit(1);
    2494             :     }
    2495             : 
    2496             :     /* Note we put any -D switch into the env var above */
    2497        1350 :     pg_config = getenv("PGDATA");
    2498        1350 :     if (pg_config)
    2499             :     {
    2500        1344 :         pg_config = pg_strdup(pg_config);
    2501        1344 :         canonicalize_path(pg_config);
    2502        1344 :         pg_data = pg_strdup(pg_config);
    2503             :     }
    2504             : 
    2505             :     /* -D might point at config-only directory; if so find the real PGDATA */
    2506        1350 :     adjust_data_dir();
    2507             : 
    2508             :     /* Complain if -D needed and not provided */
    2509        1350 :     if (pg_config == NULL &&
    2510           6 :         ctl_command != KILL_COMMAND && ctl_command != UNREGISTER_COMMAND)
    2511             :     {
    2512           0 :         write_stderr(_("%s: no database directory specified and environment variable PGDATA unset\n"),
    2513             :                      progname);
    2514           0 :         do_advice();
    2515           0 :         exit(1);
    2516             :     }
    2517             : 
    2518        1350 :     if (ctl_command == RELOAD_COMMAND)
    2519             :     {
    2520          58 :         sig = SIGHUP;
    2521          58 :         do_wait = false;
    2522             :     }
    2523             : 
    2524        1350 :     if (pg_data)
    2525             :     {
    2526        1344 :         snprintf(postopts_file, MAXPGPATH, "%s/postmaster.opts", pg_data);
    2527        1344 :         snprintf(version_file, MAXPGPATH, "%s/PG_VERSION", pg_data);
    2528        1344 :         snprintf(pid_file, MAXPGPATH, "%s/postmaster.pid", pg_data);
    2529        1344 :         snprintf(backup_file, MAXPGPATH, "%s/backup_label", pg_data);
    2530             : 
    2531             :         /*
    2532             :          * Set mask based on PGDATA permissions,
    2533             :          *
    2534             :          * Don't error here if the data directory cannot be stat'd. This is
    2535             :          * handled differently based on the command and we don't want to
    2536             :          * interfere with that logic.
    2537             :          */
    2538        1344 :         if (GetDataDirectoryCreatePerm(pg_data))
    2539        1336 :             umask(pg_mode_mask);
    2540             :     }
    2541             : 
    2542        1350 :     switch (ctl_command)
    2543             :     {
    2544           2 :         case INIT_COMMAND:
    2545           2 :             do_init();
    2546           2 :             break;
    2547           6 :         case STATUS_COMMAND:
    2548           6 :             do_status();
    2549           2 :             break;
    2550         508 :         case START_COMMAND:
    2551         508 :             do_start();
    2552         496 :             break;
    2553         626 :         case STOP_COMMAND:
    2554         626 :             do_stop();
    2555         624 :             break;
    2556          90 :         case RESTART_COMMAND:
    2557          90 :             do_restart();
    2558          86 :             break;
    2559          58 :         case RELOAD_COMMAND:
    2560          58 :             do_reload();
    2561          58 :             break;
    2562          52 :         case PROMOTE_COMMAND:
    2563          52 :             do_promote();
    2564          46 :             break;
    2565           2 :         case LOGROTATE_COMMAND:
    2566           2 :             do_logrotate();
    2567           2 :             break;
    2568           6 :         case KILL_COMMAND:
    2569           6 :             do_kill(killproc);
    2570           6 :             break;
    2571             : #ifdef WIN32
    2572             :         case REGISTER_COMMAND:
    2573             :             pgwin32_doRegister();
    2574             :             break;
    2575             :         case UNREGISTER_COMMAND:
    2576             :             pgwin32_doUnregister();
    2577             :             break;
    2578             :         case RUN_AS_SERVICE_COMMAND:
    2579             :             pgwin32_doRunAsService();
    2580             :             break;
    2581             : #endif
    2582           0 :         default:
    2583           0 :             break;
    2584             :     }
    2585             : 
    2586        1322 :     exit(0);
    2587             : }

Generated by: LCOV version 1.13