PostgreSQL工具pg_ctl实现代码


使用开源软件最大的一个好处就是能够看到它的实现,便于更深入地学习,这几天正在看pg_ctl的源码,先贴出源码,随后的时间里对各函数一一分析,,顺便测试一下这个编辑器最多支持多少行。呵呵。
  1. /*------------------------------------------------------------------------- 
  2.  * 
  3.  * pg_ctl --- start/stops/restarts the PostgreSQL server 
  4.  * 
  5.  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group 
  6.  * 
  7.  * $PostgreSQL: pgsql/src/bin/pg_ctl/pg_ctl.c,v 1.122.2.1 2010/09/14 08:05:54 heikki Exp $ 
  8.  * 
  9.  *------------------------------------------------------------------------- 
  10.  */  
  11.   
  12. #ifdef WIN32   
  13. /* 
  14.  * Need this to get defines for restricted tokens and jobs. And it 
  15.  * has to be set before any header from the Win32 API is loaded. 
  16.  */  
  17. #define _WIN32_WINNT 0x0501   
  18. #endif   
  19.   
  20. #include "postgres_fe.h"   
  21. #include "libpq-fe.h"   
  22.   
  23. #include <locale.h>   
  24. #include <signal.h>   
  25. #include <sys/types.h>   
  26. #include <sys/stat.h>   
  27. #include <unistd.h>   
  28.   
  29. #ifdef HAVE_SYS_RESOURCE_H   
  30. #include <sys/time.h>   
  31. #include <sys/resource.h>   
  32. #endif   
  33.   
  34. #include "libpq/pqsignal.h"   
  35. #include "getopt_long.h"   
  36. #include "miscadmin.h"   
  37.   
  38. #if defined(__CYGWIN__)   
  39. #include <sys/cygwin.h>   
  40. #include <windows.h>   
  41. /* Cygwin defines WIN32 in windows.h, but we don't want it. */  
  42. #undef WIN32   
  43. #endif   
  44.   
  45. /* PID can be negative for standalone backend */  
  46. typedef long pgpid_t;  
  47.   
  48.   
  49. typedef enum  
  50. {  
  51.     SMART_MODE,  
  52.     FAST_MODE,  
  53.     IMMEDIATE_MODE  
  54. } ShutdownMode;  
  55.   
  56.   
  57. typedef enum  
  58. {  
  59.     NO_COMMAND = 0,  
  60.     INIT_COMMAND,  
  61.     START_COMMAND,  
  62.     STOP_COMMAND,  
  63.     RESTART_COMMAND,  
  64.     RELOAD_COMMAND,  
  65.     STATUS_COMMAND,  
  66.     KILL_COMMAND,  
  67.     REGISTER_COMMAND,  
  68.     UNREGISTER_COMMAND,  
  69.     RUN_AS_SERVICE_COMMAND  
  70. } CtlCommand;  
  71.   
  72. #define DEFAULT_WAIT    60   
  73.   
  74. static bool do_wait = false;  
  75. static bool wait_set = false;  
  76. static int  wait_seconds = DEFAULT_WAIT;  
  77. static bool silent_mode = false;  
  78. static ShutdownMode shutdown_mode = SMART_MODE;  
  79. static int  sig = SIGTERM;      /* default */  
  80. static CtlCommand ctl_command = NO_COMMAND;  
  81. static char *pg_data = NULL;  
  82. static char *pgdata_opt = NULL;  
  83. static char *post_opts = NULL;  
  84. static const char *progname;  
  85. static char *log_file = NULL;  
  86. static char *exec_path = NULL;  
  87. static char *register_servicename = "PostgreSQL";       /* FIXME: + version ID? */  
  88. static char *register_username = NULL;  
  89. static char *register_password = NULL;  
  90. static char *argv0 = NULL;  
  91. static bool allow_core_files = false;  
  92.   
  93. static void  
  94. write_stderr(const char *fmt,...)  
  95. /* This extension allows gcc to check the format string for consistency with 
  96.    the supplied arguments. */  
  97. __attribute__((format(printf, 1, 2)));  
  98. static void *pg_malloc(size_t size);  
  99. static char *xstrdup(const char *s);  
  100. static void do_advice(void);  
  101. static void do_help(void);  
  102. static void set_mode(char *modeopt);  
  103. static void set_sig(char *signame);  
  104. static void do_init(void);  
  105. static void do_start(void);  
  106. static void do_stop(void);  
  107. static void do_restart(void);  
  108. static void do_reload(void);  
  109. static void do_status(void);  
  110. static void do_kill(pgpid_t pid);  
  111. static void print_msg(const char *msg);  
  112.   
  113. #if defined(WIN32) || defined(__CYGWIN__)   
  114. static bool pgwin32_IsInstalled(SC_HANDLE);  
  115. static char *pgwin32_CommandLine(bool);  
  116. static void pgwin32_doRegister(void);  
  117. static void pgwin32_doUnregister(void);  
  118. static void pgwin32_SetServiceStatus(DWORD);  
  119. static void WINAPI pgwin32_ServiceHandler(DWORD);  
  120. static void WINAPI pgwin32_ServiceMain(DWORDLPTSTR *);  
  121. static void pgwin32_doRunAsService(void);  
  122. static int  CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, bool as_service);  
  123.   
  124. static SERVICE_STATUS status;  
  125. static SERVICE_STATUS_HANDLE hStatus = (SERVICE_STATUS_HANDLE) 0;  
  126. static HANDLE shutdownHandles[2];  
  127. static pid_t postmasterPID = -1;  
  128.   
  129. #define shutdownEvent     shutdownHandles[0]   
  130. #define postmasterProcess shutdownHandles[1]   
  131. #endif   
  132.   
  133. static pgpid_t get_pgpid(void);  
  134. static char **readfile(const char *path);  
  135. static int  start_postmaster(void);  
  136. static void read_post_opts(void);  
  137.   
  138. static bool test_postmaster_connection(bool);  
  139. static bool postmaster_is_alive(pid_t pid);  
  140.   
  141. static char postopts_file[MAXPGPATH];  
  142. static char pid_file[MAXPGPATH];  
  143. static char conf_file[MAXPGPATH];  
  144. static char backup_file[MAXPGPATH];  
  145. static char recovery_file[MAXPGPATH];  
  146.   
  147. #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)   
  148. static void unlimit_core_size(void);  
  149. #endif   
  150.   
  151.   
  152. #if defined(WIN32) || defined(__CYGWIN__)   
  153. static void  
  154. write_eventlog(int level, const char *line)  
  155. {  
  156.     static HANDLE evtHandle = INVALID_HANDLE_VALUE;  
  157.   
  158.     if (evtHandle == INVALID_HANDLE_VALUE)  
  159.     {  
  160.         evtHandle = RegisterEventSource(NULL, "PostgreSQL");  
  161.         if (evtHandle == NULL)  
  162.         {  
  163.             evtHandle = INVALID_HANDLE_VALUE;  
  164.             return;  
  165.         }  
  166.     }  
  167.   
  168.     ReportEvent(evtHandle,  
  169.                 level,  
  170.                 0,  
  171.                 0,              /* All events are Id 0 */  
  172.                 NULL,  
  173.                 1,  
  174.                 0,  
  175.                 &line,  
  176.                 NULL);  
  177. }  
  178. #endif   
  179.   
  180. /* 
  181.  * Write errors to stderr (or by equal means when stderr is 
  182.  * not available). 
  183.  */  
  184. static void  
  185. write_stderr(const char *fmt,...)  
  186. {  
  187.     va_list     ap;  
  188.   
  189.     va_start(ap, fmt);  
  190. #if !defined(WIN32) && !defined(__CYGWIN__)   
  191.     /* On Unix, we just fprintf to stderr */  
  192.     vfprintf(stderr, fmt, ap);  
  193. #else   
  194.   
  195.     /* 
  196.      * On Win32, we print to stderr if running on a console, or write to 
  197.      * eventlog if running as a service 
  198.      */  
  199.     if (!isatty(fileno(stderr)))    /* Running as a service */  
  200.     {  
  201.         char        errbuf[2048];       /* Arbitrary size? */  
  202.   
  203.         vsnprintf(errbuf, sizeof(errbuf), fmt, ap);  
  204.   
  205.         write_eventlog(EVENTLOG_ERROR_TYPE, errbuf);  
  206.     }  
  207.     else  
  208.         /* Not running as service, write to stderr */  
  209.         vfprintf(stderr, fmt, ap);  
  210. #endif   
  211.     va_end(ap);  
  212. }  
  213.   
  214. /* 
  215.  * routines to check memory allocations and fail noisily. 
  216.  */  
  217.   
  218. static void *  
  219. pg_malloc(size_t size)  
  220. {  
  221.     void       *result;  
  222.   
  223.     result = malloc(size);  
  224.     if (!result)  
  225.     {  
  226.         write_stderr(_("%s: out of memory\n"), progname);  
  227.         exit(1);  
  228.     }  
  229.     return result;  
  230. }  
  231.   
  232.   
  233. static char *  
  234. xstrdup(const char *s)  
  235. {  
  236.     char       *result;  
  237.   
  238.     result = strdup(s);  
  239.     if (!result)  
  240.     {  
  241.         write_stderr(_("%s: out of memory\n"), progname);  
  242.         exit(1);  
  243.     }  
  244.     return result;  
  245. }  
  246.   
  247. /* 
  248.  * Given an already-localized string, print it to stdout unless the 
  249.  * user has specified that no messages should be printed. 
  250.  */  
  251. static void  
  252. print_msg(const char *msg)  
  253. {  
  254.     if (!silent_mode)  
  255.     {  
  256.         fputs(msg, stdout);  
  257.         fflush(stdout);  
  258.     }  
  259. }  
  260.   
  261. static pgpid_t  
  262. get_pgpid(void)  
  263. {  
  264.     FILE       *pidf;  
  265.     long        pid;  
  266.   
  267.     pidf = fopen(pid_file, "r");  
  268.     if (pidf == NULL)  
  269.     {  
  270.         /* No pid file, not an error on startup */  
  271.         if (errno == ENOENT)  
  272.             return 0;  
  273.         else  
  274.         {  
  275.             write_stderr(_("%s: could not open PID file \"%s\": %s\n"),  
  276.                          progname, pid_file, strerror(errno));  
  277.             exit(1);  
  278.         }  
  279.     }  
  280.     if (fscanf(pidf, "%ld", &pid) != 1)  
  281.     {  
  282.         write_stderr(_("%s: invalid data in PID file \"%s\"\n"),  
  283.                      progname, pid_file);  
  284.         exit(1);  
  285.     }  
  286.     fclose(pidf);  
  287.     return (pgpid_t) pid;  
  288. }  
  289.   
  290.   
  291. /* 
  292.  * get the lines from a text file - return NULL if file can't be opened 
  293.  */  
  294. static char **  
  295. readfile(const char *path)  
  296. {  
  297.     FILE       *infile;  
  298.     int         maxlength = 1,  
  299.                 linelen = 0;  
  300.     int         nlines = 0;  
  301.     char      **result;  
  302.     char       *buffer;  
  303.     int         c;  
  304.   
  305.     if ((infile = fopen(path, "r")) == NULL)  
  306.         return NULL;  
  307.   
  308.     /* pass over the file twice - the first time to size the result */  
  309.   
  310.     while ((c = fgetc(infile)) != EOF)  
  311.     {  
  312.         linelen++;  
  313.         if (c == '\n')  
  314.         {  
  315.             nlines++;  
  316.             if (linelen > maxlength)  
  317.                 maxlength = linelen;  
  318.             linelen = 0;  
  319.         }  
  320.     }  
  321.   
  322.     /* handle last line without a terminating newline (yuck) */  
  323.     if (linelen)  
  324.         nlines++;  
  325.     if (linelen > maxlength)  
  326.         maxlength = linelen;  
  327.   
  328.     /* set up the result and the line buffer */  
  329.     result = (char **) pg_malloc((nlines + 1) * sizeof(char *));  
  330.     buffer = (char *) pg_malloc(maxlength + 1);  
  331.   
  332.     /* now reprocess the file and store the lines */  
  333.     rewind(infile);  
  334.     nlines = 0;  
  335.     while (fgets(buffer, maxlength + 1, infile) != NULL)  
  336.         result[nlines++] = xstrdup(buffer);  
  337.   
  338.     fclose(infile);  
  339.     free(buffer);  
  340.     result[nlines] = NULL;  
  341.   
  342.     return result;  
  343. }  
  344.   
  345.   
  346.   
  347. /* 
  348.  * start/test/stop routines 
  349.  */  
  350.   
  351. static int  
  352. start_postmaster(void)  
  353. {  
  354.     char        cmd[MAXPGPATH];  
  355.   
  356. #ifndef WIN32   
  357.   
  358.     /* 
  359.      * Since there might be quotes to handle here, it is easier simply to pass 
  360.      * everything to a shell to process them. 
  361.      */  
  362.     if (log_file != NULL)  
  363.         snprintf(cmd, MAXPGPATH, SYSTEMQUOTE "\"%s\" %s%s < \"%s\" >> \"%s\" 2>&1 &" SYSTEMQUOTE,  
  364.                  exec_path, pgdata_opt, post_opts,  
  365.                  DEVNULL, log_file);  
  366.     else  
  367.         snprintf(cmd, MAXPGPATH, SYSTEMQUOTE "\"%s\" %s%s < \"%s\" 2>&1 &" SYSTEMQUOTE,  
  368.                  exec_path, pgdata_opt, post_opts, DEVNULL);  
  369.   
  370.     return system(cmd);  
  371. #else                           /* WIN32 */   
  372.   
  373.     /* 
  374.      * On win32 we don't use system(). So we don't need to use & (which would 
  375.      * be START /B on win32). However, we still call the shell (CMD.EXE) with 
  376.      * it to handle redirection etc. 
  377.      */  
  378.     PROCESS_INFORMATION pi;  
  379.   
  380.     if (log_file != NULL)  
  381.         snprintf(cmd, MAXPGPATH, "CMD /C " SYSTEMQUOTE "\"%s\" %s%s < \"%s\" >> \"%s\" 2>&1" SYSTEMQUOTE,  
  382.                  exec_path, pgdata_opt, post_opts, DEVNULL, log_file);  
  383.     else  
  384.         snprintf(cmd, MAXPGPATH, "CMD /C " SYSTEMQUOTE "\"%s\" %s%s < \"%s\" 2>&1" SYSTEMQUOTE,  
  385.                  exec_path, pgdata_opt, post_opts, DEVNULL);  
  386.   
  387.     if (!CreateRestrictedProcess(cmd, &pi, false))  
  388.         return GetLastError();  
  389.     CloseHandle(pi.hProcess);  
  390.     CloseHandle(pi.hThread);  
  391.     return 0;  
  392. #endif   /* WIN32 */   
  393. }  
  394.   
  395.   
  396.   
  397. /* 
  398.  * Find the pgport and try a connection 
  399.  * Note that the checkpoint parameter enables a Windows service control 
  400.  * manager checkpoint, it's got nothing to do with database checkpoints!! 
  401.  */  
  402. static bool  
  403. test_postmaster_connection(bool do_checkpoint)  
  404. {  
  405.     PGconn     *conn;  
  406.     bool        success = false;  
  407.     int         i;  
  408.     char        portstr[32];  
  409.     char       *p;  
  410.     char       *q;  
  411.     char        connstr[128];   /* Should be way more than enough! */  
  412.   
  413.     *portstr = '\0';  
  414.   
  415.     /* 
  416.      * Look in post_opts for a -p switch. 
  417.      * 
  418.      * This parsing code is not amazingly bright; it could for instance get 
  419.      * fooled if ' -p' occurs within a quoted argument value.  Given that few 
  420.      * people pass complicated settings in post_opts, it's probably good 
  421.      * enough. 
  422.      */  
  423.     for (p = post_opts; *p;)  
  424.     {  
  425.         /* advance past whitespace */  
  426.         while (isspace((unsigned char) *p))  
  427.             p++;  
  428.   
  429.         if (strncmp(p, "-p", 2) == 0)  
  430.         {  
  431.             p += 2;  
  432.             /* advance past any whitespace/quoting */  
  433.             while (isspace((unsigned char) *p) || *p == '\'' || *p == '"')  
  434.                 p++;  
  435.             /* find end of value (not including any ending quote!) */  
  436.             q = p;  
  437.             while (*q &&  
  438.                    !(isspace((unsigned char) *q) || *q == '\'' || *q == '"'))  
  439.                 q++;  
  440.             /* and save the argument value */  
  441.             strlcpy(portstr, p, Min((q - p) + 1, sizeof(portstr)));  
  442.             /* keep looking, maybe there is another -p */  
  443.             p = q;  
  444.         }  
  445.         /* Advance to next whitespace */  
  446.         while (*p && !isspace((unsigned char) *p))  
  447.             p++;  
  448.     }  
  449.   
  450.     /* 
  451.      * Search config file for a 'port' option. 
  452.      * 
  453.      * This parsing code isn't amazingly bright either, but it should be okay 
  454.      * for valid port settings. 
  455.      */  
  456.     if (!*portstr)  
  457.     {  
  458.         char      **optlines;  
  459.   
  460.         optlines = readfile(conf_file);  
  461.         if (optlines != NULL)  
  462.         {  
  463.             for (; *optlines != NULL; optlines++)  
  464.             {  
  465.                 p = *optlines;  
  466.   
  467.                 while (isspace((unsigned char) *p))  
  468.                     p++;  
  469.                 if (strncmp(p, "port", 4) != 0)  
  470.                     continue;  
  471.                 p += 4;  
  472.                 while (isspace((unsigned char) *p))  
  473.                     p++;  
  474.                 if (*p != '=')  
  475.                     continue;  
  476.                 p++;  
  477.                 /* advance past any whitespace/quoting */  
  478.                 while (isspace((unsigned char) *p) || *p == '\'' || *p == '"')  
  479.                     p++;  
  480.                 /* find end of value (not including any ending quote/comment!) */  
  481.                 q = p;  
  482.                 while (*q &&  
  483.                        !(isspace((unsigned char) *q) ||  
  484.                          *q == '\'' || *q == '"' || *q == '#'))  
  485.                     q++;  
  486.                 /* and save the argument value */  
  487.                 strlcpy(portstr, p, Min((q - p) + 1, sizeof(portstr)));  
  488.                 /* keep looking, maybe there is another */  
  489.             }  
  490.         }  
  491.     }  
  492.   
  493.     /* Check environment */  
  494.     if (!*portstr && getenv("PGPORT") != NULL)  
  495.         strlcpy(portstr, getenv("PGPORT"), sizeof(portstr));  
  496.   
  497.     /* Else use compiled-in default */  
  498.     if (!*portstr)  
  499.         snprintf(portstr, sizeof(portstr), "%d", DEF_PGPORT);  
  500.   
  501.     /* 
  502.      * We need to set a connect timeout otherwise on Windows the SCM will 
  503.      * probably timeout first 
  504.      */  
  505.     snprintf(connstr, sizeof(connstr),  
  506.              "dbname=postgres port=%s connect_timeout=5", portstr);  
  507.   
  508.     for (i = 0; i < wait_seconds; i++)  
  509.     {  
  510.         if ((conn = PQconnectdb(connstr)) != NULL &&  
  511.             (PQstatus(conn) == CONNECTION_OK ||  
  512.              PQconnectionNeedsPassword(conn)))  
  513.         {  
  514.             PQfinish(conn);  
  515.             success = true;  
  516.             break;  
  517.         }  
  518.         else  
  519.         {  
  520.             PQfinish(conn);  
  521.   
  522. #if defined(WIN32)   
  523.             if (do_checkpoint)  
  524.             {  
  525.                 /* 
  526.                  * Increment the wait hint by 6 secs (connection timeout + 
  527.                  * sleep) We must do this to indicate to the SCM that our 
  528.                  * startup time is changing, otherwise it'll usually send a 
  529.                  * stop signal after 20 seconds, despite incrementing the 
  530.                  * checkpoint counter. 
  531.                  */  
  532.                 status.dwWaitHint += 6000;  
  533.                 status.dwCheckPoint++;  
  534.                 SetServiceStatus(hStatus, (LPSERVICE_STATUS) &status);  
  535.             }  
  536.   
  537.             else  
  538. #endif   
  539.                 print_msg(".");  
  540.   
  541.             pg_usleep(1000000); /* 1 sec */  
  542.         }  
  543.     }  
  544.   
  545.     return success;  
  546. }  
  547.   
  548.   
  549. #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)   
  550. static void  
  551. unlimit_core_size(void)  
  552. {  
  553.     struct rlimit lim;  
  554.   
  555.     getrlimit(RLIMIT_CORE, &lim);  
  556.     if (lim.rlim_max == 0)  
  557.     {  
  558.         write_stderr(_("%s: cannot set core file size limit; disallowed by hard limit\n"),  
  559.                      progname);  
  560.         return;  
  561.     }  
  562.     else if (lim.rlim_max == RLIM_INFINITY || lim.rlim_cur < lim.rlim_max)  
  563.     {  
  564.         lim.rlim_cur = lim.rlim_max;  
  565.         setrlimit(RLIMIT_CORE, &lim);  
  566.     }  
  567. }  
  568. #endif   
  569.   
  570. static void  
  571. read_post_opts(void)  
  572. {  
  573.     if (post_opts == NULL)  
  574.     {  
  575.         post_opts = "";         /* default */  
  576.         if (ctl_command == RESTART_COMMAND)  
  577.         {  
  578.             char      **optlines;  
  579.   
  580.             optlines = readfile(postopts_file);  
  581.             if (optlines == NULL)  
  582.             {  
  583.                 write_stderr(_("%s: could not read file \"%s\"\n"), progname, postopts_file);  
  584.                 exit(1);  
  585.             }  
  586.             else if (optlines[0] == NULL || optlines[1] != NULL)  
  587.             {  
  588.                 write_stderr(_("%s: option file \"%s\" must have exactly one line\n"),  
  589.                              progname, postopts_file);  
  590.                 exit(1);  
  591.             }  
  592.             else  
  593.             {  
  594.                 int         len;  
  595.                 char       *optline;  
  596.                 char       *arg1;  
  597.   
  598.                 optline = optlines[0];  
  599.                 /* trim off line endings */  
  600.                 len = strcspn(optline, "\r\n");  
  601.                 optline[len] = '\0';  
  602.   
  603.                 /* 
  604.                  * Are we at the first option, as defined by space and 
  605.                  * double-quote? 
  606.                  */  
  607.                 if ((arg1 = strstr(optline, " \"")) != NULL)  
  608.                 {  
  609.                     *arg1 = '\0';       /* terminate so we get only program 
  610.                                          * name */  
  611.                     post_opts = arg1 + 1;       /* point past whitespace */  
  612.                 }  
  613.                 if (exec_path == NULL)  
  614.                     exec_path = optline;  
  615.             }  
  616.         }  
  617.     }  
  618. }  
  619.   
  620. static char *  
  621. find_other_exec_or_die(const char *argv0, const char *target, const char *versionstr)  
  622. {  
  623.     int         ret;  
  624.     char       *found_path;  
  625.   
  626.     found_path = pg_malloc(MAXPGPATH);  
  627.   
  628.     if ((ret = find_other_exec(argv0, target, versionstr, found_path)) < 0)  
  629.     {  
  630.         char        full_path[MAXPGPATH];  
  631.   
  632.         if (find_my_exec(argv0, full_path) < 0)  
  633.             strlcpy(full_path, progname, sizeof(full_path));  
  634.   
  635.         if (ret == -1)  
  636.             write_stderr(_("The program \"%s\" is needed by %s "  
  637.                            "but was not found in the\n"  
  638.                            "same directory as \"%s\".\n"  
  639.                            "Check your installation.\n"),  
  640.                          target, progname, full_path);  
  641.         else  
  642.             write_stderr(_("The program \"%s\" was found by \"%s\"\n"  
  643.                            "but was not the same version as %s.\n"  
  644.                            "Check your installation.\n"),  
  645.                          target, full_path, progname);  
  646.         exit(1);  
  647.     }  
  648.   
  649.     return found_path;  
  650. }  
  651.   
  652. static void  
  653. do_init(void)  
  654. {  
  655.     char        cmd[MAXPGPATH];  
  656.   
  657.     if (exec_path == NULL)  
  658.         exec_path = find_other_exec_or_die(argv0, "initdb""initdb (PostgreSQL) " PG_VERSION "\n");  
  659.   
  660.     if (pgdata_opt == NULL)  
  661.         pgdata_opt = "";  
  662.   
  663.     if (post_opts == NULL)  
  664.         post_opts = "";  
  665.   
  666.     if (!silent_mode)  
  667.         snprintf(cmd, MAXPGPATH, SYSTEMQUOTE "\"%s\" %s%s" SYSTEMQUOTE,  
  668.                  exec_path, pgdata_opt, post_opts);  
  669.     else  
  670.         snprintf(cmd, MAXPGPATH, SYSTEMQUOTE "\"%s\" %s%s > \"%s\"" SYSTEMQUOTE,  
  671.                  exec_path, pgdata_opt, post_opts, DEVNULL);  
  672.   
  673.     if (system(cmd) != 0)  
  674.     {  
  675.         write_stderr(_("%s: database system initialization failed\n"), progname);  
  676.         exit(1);  
  677.     }  
  678. }  
  679.   
  680. static void  
  681. do_start(void)  
  682. {  
  683.     pgpid_t     pid;  
  684.     pgpid_t     old_pid = 0;  
  685.     int         exitcode;  
  686.   
  687.     if (ctl_command != RESTART_COMMAND)  
  688.     {  
  689.         old_pid = get_pgpid();  
  690.         if (old_pid != 0)  
  691.             write_stderr(_("%s: another server might be running; "  
  692.                            "trying to start server anyway\n"),  
  693.                          progname);  
  694.     }  
  695.   
  696.     read_post_opts();  
  697.   
  698.     /* No -D or -D already added during server start */  
  699.     if (ctl_command == RESTART_COMMAND || pgdata_opt == NULL)  
  700.         pgdata_opt = "";  
  701.   
  702.     if (exec_path == NULL)  
  703.         exec_path = find_other_exec_or_die(argv0, "postgres", PG_BACKEND_VERSIONSTR);  
  704.   
  705. #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)   
  706.     if (allow_core_files)  
  707.         unlimit_core_size();  
  708. #endif   
  709.   
  710.     /* 
  711.      * If possible, tell the postmaster our parent shell's PID (see the 
  712.      * comments in CreateLockFile() for motivation).  Windows hasn't got 
  713.      * getppid() unfortunately. 
  714.      */  
  715. #ifndef WIN32   
  716.     {  
  717.         static char env_var[32];  
  718.   
  719.         snprintf(env_var, sizeof(env_var), "PG_GRANDPARENT_PID=%d",  
  720.                  (int) getppid());  
  721.         putenv(env_var);  
  722.     }  
  723. #endif   
  724.   
  725.     exitcode = start_postmaster();  
  726.     if (exitcode != 0)  
  727.     {  
  728.         write_stderr(_("%s: could not start server: exit code was %d\n"),  
  729.                      progname, exitcode);  
  730.         exit(1);  
  731.     }  
  732.   
  733.     if (old_pid != 0)  
  734.     {  
  735.         pg_usleep(1000000);  
  736.         pid = get_pgpid();  
  737.         if (pid == old_pid)  
  738.         {  
  739.             write_stderr(_("%s: could not start server\n"  
  740.                            "Examine the log output.\n"),  
  741.                          progname);  
  742.             exit(1);  
  743.         }  
  744.     }  
  745.   
  746.     if (do_wait)  
  747.     {  
  748.         print_msg(_("waiting for server to start..."));  
  749.   
  750.         if (test_postmaster_connection(false) == false)  
  751.         {  
  752.             write_stderr(_("%s: could not start server\n"  
  753.                            "Examine the log output.\n"),  
  754.                          progname);  
  755.             exit(1);  
  756.         }  
  757.         else  
  758.         {  
  759.             print_msg(_(" done\n"));  
  760.             print_msg(_("server started\n"));  
  761.         }  
  762.     }  
  763.     else  
  764.         print_msg(_("server starting\n"));  
  765. }  
  766.   
  767.   
  768. static void  
  769. do_stop(void)  
  770. {  
  771.     int         cnt;  
  772.     pgpid_t     pid;  
  773.     struct stat statbuf;  
  774.   
  775.     pid = get_pgpid();  
  776.   
  777.     if (pid == 0)               /* no pid file */  
  778.     {  
  779.         write_stderr(_("%s: PID file \"%s\" does not exist\n"), progname, pid_file);  
  780.         write_stderr(_("Is server running?\n"));  
  781.         exit(1);  
  782.     }  
  783.     else if (pid < 0)            /* standalone backend, not postmaster */  
  784.     {  
  785.         pid = -pid;  
  786.         write_stderr(_("%s: cannot stop server; "  
  787.                        "single-user server is running (PID: %ld)\n"),  
  788.                      progname, pid);  
  789.         exit(1);  
  790.     }  
  791.   
  792.     if (kill((pid_t) pid, sig) != 0)  
  793.     {  
  794.         write_stderr(_("%s: could not send stop signal (PID: %ld): %s\n"), progname, pid,  
  795.                      strerror(errno));  
  796.         exit(1);  
  797.     }  
  798.   
  799.     if (!do_wait)  
  800.     {  
  801.         print_msg(_("server shutting down\n"));  
  802.         return;  
  803.     }  
  804.     else  
  805.     {  
  806.         /* 
  807.          * If backup_label exists, an online backup is running. Warn the 
  808.          * user that smart shutdown will wait for it to finish. However, if 
  809.          * recovery.conf is also present, we're recovering from an online 
  810.          * backup instead of performing one. 
  811.          */  
  812.         if (shutdown_mode == SMART_MODE &&  
  813.             stat(backup_file, &statbuf) == 0 &&  
  814.             stat(recovery_file, &statbuf) != 0)  
  815.         {  
  816.             print_msg(_("WARNING: online backup mode is active\n"  
  817.                         "Shutdown will not complete until pg_stop_backup() is called.\n\n"));  
  818.         }  
  819.   
  820.         print_msg(_("waiting for server to shut down..."));  
  821.   
  822.         for (cnt = 0; cnt < wait_seconds; cnt++)  
  823.         {  
  824.             if ((pid = get_pgpid()) != 0)  
  825.             {  
  826.                 print_msg(".");  
  827.                 pg_usleep(1000000);     /* 1 sec */  
  828.             }  
  829.             else  
  830.                 break;  
  831.         }  
  832.   
  833.         if (pid != 0)           /* pid file still exists */  
  834.         {  
  835.             print_msg(_(" failed\n"));  
  836.   
  837.             write_stderr(_("%s: server does not shut down\n"), progname);  
  838.             exit(1);  
  839.         }  
  840.         print_msg(_(" done\n"));  
  841.   
  842.         print_msg(_("server stopped\n"));  
  843.     }  
  844. }  
  845.   
  846.   
  847. /* 
  848.  *  restart/reload routines 
  849.  */  
  850.   
  851. static void  
  852. do_restart(void)  
  853. {  
  854.     int         cnt;  
  855.     pgpid_t     pid;  
  856.     struct stat statbuf;  
  857.   
  858.     pid = get_pgpid();  
  859.   
  860.     if (pid == 0)               /* no pid file */  
  861.     {  
  862.         write_stderr(_("%s: PID file \"%s\" does not exist\n"),  
  863.                      progname, pid_file);  
  864.         write_stderr(_("Is server running?\n"));  
  865.         write_stderr(_("starting server anyway\n"));  
  866.         do_start();  
  867.         return;  
  868.     }  
  869.     else if (pid < 0)            /* standalone backend, not postmaster */  
  870.     {  
  871.         pid = -pid;  
  872.         if (postmaster_is_alive((pid_t) pid))  
  873.         {  
  874.             write_stderr(_("%s: cannot restart server; "  
  875.                            "single-user server is running (PID: %ld)\n"),  
  876.                          progname, pid);  
  877.             write_stderr(_("Please terminate the single-user server and try again.\n"));  
  878.             exit(1);  
  879.         }  
  880.     }  
  881.   
  882.     if (postmaster_is_alive((pid_t) pid))  
  883.     {  
  884.         if (kill((pid_t) pid, sig) != 0)  
  885.         {  
  886.             write_stderr(_("%s: could not send stop signal (PID: %ld): %s\n"), progname, pid,  
  887.                          strerror(errno));  
  888.             exit(1);  
  889.         }  
  890.   
  891.         /* 
  892.          * If backup_label exists, an online backup is running. Warn the 
  893.          * user that smart shutdown will wait for it to finish. However, if 
  894.          * recovery.conf is also present, we're recovering from an online 
  895.          * backup instead of performing one. 
  896.          */  
  897.         if (shutdown_mode == SMART_MODE &&  
  898.             stat(backup_file, &statbuf) == 0 &&  
  899.             stat(recovery_file, &statbuf) != 0)  
  900.         {  
  901.             print_msg(_("WARNING: online backup mode is active\n"  
  902.                         "Shutdown will not complete until pg_stop_backup() is called.\n\n"));  
  903.         }  
  904.   
  905.         print_msg(_("waiting for server to shut down..."));  
  906.   
  907.         /* always wait for restart */  
  908.   
  909.         for (cnt = 0; cnt < wait_seconds; cnt++)  
  910.         {  
  911.             if ((pid = get_pgpid()) != 0)  
  912.             {  
  913.                 print_msg(".");  
  914.                 pg_usleep(1000000);     /* 1 sec */  
  915.             }  
  916.             else  
  917.                 break;  
  918.         }  
  919.   
  920.         if (pid != 0)           /* pid file still exists */  
  921.         {  
  922.             print_msg(_(" failed\n"));  
  923.   
  924.             write_stderr(_("%s: server does not shut down\n"), progname);  
  925.             exit(1);  
  926.         }  
  927.   
  928.         print_msg(_(" done\n"));  
  929.         print_msg(_("server stopped\n"));  
  930.     }  
  931.     else  
  932.     {  
  933.         write_stderr(_("%s: old server process (PID: %ld) seems to be gone\n"),  
  934.                      progname, pid);  
  935.         write_stderr(_("starting server anyway\n"));  
  936.     }  
  937.   
  938.     do_start();  
  939. }  
  940.   
  941.   
  942. static void  
  943. do_reload(void)  
  944. {  
  945.     pgpid_t     pid;  
  946.   
  947.     pid = get_pgpid();  
  948.     if (pid == 0)               /* no pid file */  
  949.     {  
  950.         write_stderr(_("%s: PID file \"%s\" does not exist\n"), progname, pid_file);  
  951.         write_stderr(_("Is server running?\n"));  
  952.         exit(1);  
  953.     }  
  954.     else if (pid < 0)            /* standalone backend, not postmaster */  
  955.     {  
  956.         pid = -pid;  
  957.         write_stderr(_("%s: cannot reload server; "  
  958.                        "single-user server is running (PID: %ld)\n"),  
  959.                      progname, pid);  
  960.         write_stderr(_("Please terminate the single-user server and try again.\n"));  
  961.         exit(1);  
  962.     }  
  963.   
  964.     if (kill((pid_t) pid, sig) != 0)  
  965.     {  
  966.         write_stderr(_("%s: could not send reload signal (PID: %ld): %s\n"),  
  967.                      progname, pid, strerror(errno));  
  968.         exit(1);  
  969.     }  
  970.   
  971.     print_msg(_("server signaled\n"));  
  972. }  
  973.   
  974. /* 
  975.  *  utility routines 
  976.  */  
  977.   
  978. static bool  
  979. postmaster_is_alive(pid_t pid)  
  980. {  
  981.     /* 
  982.      * Test to see if the process is still there.  Note that we do not 
  983.      * consider an EPERM failure to mean that the process is still there; 
  984.      * EPERM must mean that the given PID belongs to some other userid, and 
  985.      * considering the permissions on $PGDATA, that means it's not the 
  986.      * postmaster we are after. 
  987.      * 
  988.      * Don't believe that our own PID or parent shell's PID is the postmaster, 
  989.      * either.  (Windows hasn't got getppid(), though.) 
  990.      */  
  991.     if (pid == getpid())  
  992.         return false;  
  993. #ifndef WIN32   
  994.     if (pid == getppid())  
  995.         return false;  
  996. #endif   
  997.     if (kill(pid, 0) == 0)  
  998.         return true;  
  999.     return false;  
  1000. }  
  1001.   
  1002. static void  
  1003. do_status(void)  
  1004. {  
  1005.     pgpid_t     pid;  
  1006.   
  1007.     pid = get_pgpid();  
  1008.     if (pid != 0)               /* 0 means no pid file */  
  1009.     {  
  1010.         if (pid < 0)         /* standalone backend */  
  1011.         {  
  1012.             pid = -pid;  
  1013.             if (postmaster_is_alive((pid_t) pid))  
  1014.             {  
  1015.                 printf(_("%s: single-user server is running (PID: %ld)\n"),  
  1016.                        progname, pid);  
  1017.                 return;  
  1018.             }  
  1019.         }  
  1020.         else  
  1021.             /* postmaster */  
  1022.         {  
  1023.             if (postmaster_is_alive((pid_t) pid))  
  1024.             {  
  1025.                 char      **optlines;  
  1026.   
  1027.                 printf(_("%s: server is running (PID: %ld)\n"),  
  1028.                        progname, pid);  
  1029.   
  1030.                 optlines = readfile(postopts_file);  
  1031.                 if (optlines != NULL)  
  1032.                     for (; *optlines != NULL; optlines++)  
  1033.                         fputs(*optlines, stdout);  
  1034.                 return;  
  1035.             }  
  1036.         }  
  1037.     }  
  1038.     printf(_("%s: no server running\n"), progname);  
  1039.     exit(1);  
  1040. }  
  1041.   
  1042.   
  1043.   
  1044. static void  
  1045. do_kill(pgpid_t pid)  
  1046. {  
  1047.     if (kill((pid_t) pid, sig) != 0)  
  1048.     {  
  1049.         write_stderr(_("%s: could not send signal %d (PID: %ld): %s\n"),  
  1050.                      progname, sig, pid, strerror(errno));  
  1051.         exit(1);  
  1052.     }  
  1053. }  
  1054.   
  1055. #if defined(WIN32) || defined(__CYGWIN__)   
  1056.   
  1057. static bool  
  1058. pgwin32_IsInstalled(SC_HANDLE hSCM)  
  1059. {  
  1060.     SC_HANDLE   hService = OpenService(hSCM, register_servicename, SERVICE_QUERY_CONFIG);  
  1061.     bool        bResult = (hService != NULL);  
  1062.   
  1063.     if (bResult)  
  1064.         CloseServiceHandle(hService);  
  1065.     return bResult;  
  1066. }  
  1067.   
  1068. static char *  
  1069. pgwin32_CommandLine(bool registration)  
  1070. {  
  1071.     static char cmdLine[MAXPGPATH];  
  1072.     int         ret;  
  1073.   
  1074. #ifdef __CYGWIN__   
  1075.     char        buf[MAXPGPATH];  
  1076. #endif   
  1077.   
  1078.     if (registration)  
  1079.     {  
  1080.         ret = find_my_exec(argv0, cmdLine);  
  1081.         if (ret != 0)  
  1082.         {  
  1083.             write_stderr(_("%s: could not find own program executable\n"), progname);  
  1084.             exit(1);  
  1085.         }  
  1086.     }  
  1087.     else  
  1088.     {  
  1089.         ret = find_other_exec(argv0, "postgres", PG_BACKEND_VERSIONSTR,  
  1090.                               cmdLine);  
  1091.         if (ret != 0)  
  1092.         {  
  1093.             write_stderr(_("%s: could not find postgres program executable\n"), progname);  
  1094.             exit(1);  
  1095.         }  
  1096.     }  
  1097.   
  1098. #ifdef __CYGWIN__   
  1099.     /* need to convert to windows path */  
  1100. #if CYGWIN_VERSION_DLL_MAJOR >= 1007   
  1101.     cygwin_conv_path(CCP_POSIX_TO_WIN_A, cmdLine, buf, sizeof(buf));  
  1102. #else   
  1103.     cygwin_conv_to_full_win32_path(cmdLine, buf);  
  1104. #endif   
  1105.     strcpy(cmdLine, buf);  
  1106. #endif   
  1107.   
  1108.     if (registration)  
  1109.     {  
  1110.         if (pg_strcasecmp(cmdLine + strlen(cmdLine) - 4, ".exe"))  
  1111.         {  
  1112.             /* If commandline does not end in .exe, append it */  
  1113.             strcat(cmdLine, ".exe");  
  1114.         }  
  1115.         strcat(cmdLine, " runservice -N \"");  
  1116.         strcat(cmdLine, register_servicename);  
  1117.         strcat(cmdLine, "\"");  
  1118.     }  
  1119.   
  1120.     if (pg_data)  
  1121.     {  
  1122.         strcat(cmdLine, " -D \"");  
  1123.         strcat(cmdLine, pg_data);  
  1124.         strcat(cmdLine, "\"");  
  1125.     }  
  1126.   
  1127.     if (registration && do_wait)  
  1128.         strcat(cmdLine, " -w");  
  1129.   
  1130.     if (registration && wait_seconds != DEFAULT_WAIT)  
  1131.         /* concatenate */  
  1132.         sprintf(cmdLine + strlen(cmdLine), " -t %d", wait_seconds);  
  1133.   
  1134.     if (post_opts)  
  1135.     {  
  1136.         strcat(cmdLine, " ");  
  1137.         if (registration)  
  1138.             strcat(cmdLine, " -o \"");  
  1139.         strcat(cmdLine, post_opts);  
  1140.         if (registration)  
  1141.             strcat(cmdLine, "\"");  
  1142.     }  
  1143.   
  1144.     return cmdLine;  
  1145. }  
  1146.   
  1147. static void  
  1148. pgwin32_doRegister(void)  
  1149. {  
  1150.     SC_HANDLE   hService;  
  1151.     SC_HANDLE   hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);  
  1152.   
  1153.     if (hSCM == NULL)  
  1154.     {  
  1155.         write_stderr(_("%s: could not open service manager\n"), progname);  
  1156.         exit(1);  
  1157.     }  
  1158.     if (pgwin32_IsInstalled(hSCM))  
  1159.     {  
  1160.         CloseServiceHandle(hSCM);  
  1161.         write_stderr(_("%s: service \"%s\" already registered\n"), progname, register_servicename);  
  1162.         exit(1);  
  1163.     }  
  1164.   
  1165.     if ((hService = CreateService(hSCM, register_servicename, register_servicename,  
  1166.                                SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,  
  1167.                                   SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,  
  1168.                                   pgwin32_CommandLine(true),  
  1169.        NULL, NULL, "RPCSS\0", register_username, register_password)) == NULL)  
  1170.     {  
  1171.         CloseServiceHandle(hSCM);  
  1172.         write_stderr(_("%s: could not register service \"%s\": error code %d\n"), progname, register_servicename, (int) GetLastError());  
  1173.         exit(1);  
  1174.     }  
  1175.     CloseServiceHandle(hService);  
  1176.     CloseServiceHandle(hSCM);  
  1177. }  
  1178.   
  1179. static void  
  1180. pgwin32_doUnregister(void)  
  1181. {  
  1182.     SC_HANDLE   hService;  
  1183.     SC_HANDLE   hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);  
  1184.   
  1185.     if (hSCM == NULL)  
  1186.     {  
  1187.         write_stderr(_("%s: could not open service manager\n"), progname);  
  1188.         exit(1);  
  1189.     }  
  1190.     if (!pgwin32_IsInstalled(hSCM))  
  1191.     {  
  1192.         CloseServiceHandle(hSCM);  
  1193.         write_stderr(_("%s: service \"%s\" not registered\n"), progname, register_servicename);  
  1194.         exit(1);  
  1195.     }  
  1196.   
  1197.     if ((hService = OpenService(hSCM, register_servicename, DELETE)) == NULL)  
  1198.     {  
  1199.         CloseServiceHandle(hSCM);  
  1200.         write_stderr(_("%s: could not open service \"%s\": error code %d\n"), progname, register_servicename, (int) GetLastError());  
  1201.         exit(1);  
  1202.     }  
  1203.     if (!DeleteService(hService))  
  1204.     {  
  1205.         CloseServiceHandle(hService);  
  1206.         CloseServiceHandle(hSCM);  
  1207.         write_stderr(_("%s: could not unregister service \"%s\": error code %d\n"), progname, register_servicename, (int) GetLastError());  
  1208.         exit(1);  
  1209.     }  
  1210.     CloseServiceHandle(hService);  
  1211.     CloseServiceHandle(hSCM);  
  1212. }  
  1213.   
  1214. static void  
  1215. pgwin32_SetServiceStatus(DWORD currentState)  
  1216. {  
  1217.     status.dwCurrentState = currentState;  
  1218.     SetServiceStatus(hStatus, (LPSERVICE_STATUS) &status);  
  1219. }  
  1220.   
  1221. static void WINAPI  
  1222. pgwin32_ServiceHandler(DWORD request)  
  1223. {  
  1224.     switch (request)  
  1225.     {  
  1226.         case SERVICE_CONTROL_STOP:  
  1227.         case SERVICE_CONTROL_SHUTDOWN:  
  1228.   
  1229.             /* 
  1230.              * We only need a short wait hint here as it just needs to wait 
  1231.              * for the next checkpoint. They occur every 5 seconds during 
  1232.              * shutdown 
  1233.              */  
  1234.             status.dwWaitHint = 10000;  
  1235.             pgwin32_SetServiceStatus(SERVICE_STOP_PENDING);  
  1236.             SetEvent(shutdownEvent);  
  1237.             return;  
  1238.   
  1239.         case SERVICE_CONTROL_PAUSE:  
  1240.             /* Win32 config reloading */  
  1241.             status.dwWaitHint = 5000;  
  1242.             kill(postmasterPID, SIGHUP);  
  1243.             return;  
  1244.   
  1245.             /* FIXME: These could be used to replace other signals etc */  
  1246.         case SERVICE_CONTROL_CONTINUE:  
  1247.         case SERVICE_CONTROL_INTERROGATE:  
  1248.         default:  
  1249.             break;  
  1250.     }  
  1251. }  
  1252.   
  1253. static void WINAPI  
  1254. pgwin32_ServiceMain(DWORD argc, LPTSTR *argv)  
  1255. {  
  1256.     PROCESS_INFORMATION pi;  
  1257.     DWORD       ret;  
  1258.     DWORD       check_point_start;  
  1259.   
  1260.     /* Initialize variables */  
  1261.     status.dwWin32ExitCode = S_OK;  
  1262.     status.dwCheckPoint = 0;  
  1263.     status.dwWaitHint = 60000;  
  1264.     status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;  
  1265.     status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_PAUSE_CONTINUE;  
  1266.     status.dwServiceSpecificExitCode = 0;  
  1267.     status.dwCurrentState = SERVICE_START_PENDING;  
  1268.   
  1269.     memset(&pi, 0, sizeof(pi));  
  1270.   
  1271.     read_post_opts();  
  1272.   
  1273.     /* Register the control request handler */  
  1274.     if ((hStatus = RegisterServiceCtrlHandler(register_servicename, pgwin32_ServiceHandler)) == (SERVICE_STATUS_HANDLE) 0)  
  1275.         return;  
  1276.   
  1277.     if ((shutdownEvent = CreateEvent(NULL, truefalse, NULL)) == NULL)  
  1278.         return;  
  1279.   
  1280.     /* Start the postmaster */  
  1281.     pgwin32_SetServiceStatus(SERVICE_START_PENDING);  
  1282.     if (!CreateRestrictedProcess(pgwin32_CommandLine(false), &pi, true))  
  1283.     {  
  1284.         pgwin32_SetServiceStatus(SERVICE_STOPPED);  
  1285.         return;  
  1286.     }  
  1287.     postmasterPID = pi.dwProcessId;  
  1288.     postmasterProcess = pi.hProcess;  
  1289.     CloseHandle(pi.hThread);  
  1290.   
  1291.     if (do_wait)  
  1292.     {  
  1293.         write_eventlog(EVENTLOG_INFORMATION_TYPE, _("Waiting for server startup...\n"));  
  1294.         if (test_postmaster_connection(true) == false)  
  1295.         {  
  1296.             write_eventlog(EVENTLOG_INFORMATION_TYPE, _("Timed out waiting for server startup\n"));  
  1297.             pgwin32_SetServiceStatus(SERVICE_STOPPED);  
  1298.             return;  
  1299.         }  
  1300.         write_eventlog(EVENTLOG_INFORMATION_TYPE, _("Server started and accepting connections\n"));  
  1301.     }  
  1302.   
  1303.     /* 
  1304.      * Save the checkpoint value as it might have been incremented in 
  1305.      * test_postmaster_connection 
  1306.      */  
  1307.     check_point_start = status.dwCheckPoint;  
  1308.   
  1309.     pgwin32_SetServiceStatus(SERVICE_RUNNING);  
  1310.   
  1311.     /* Wait for quit... */  
  1312.     ret = WaitForMultipleObjects(2, shutdownHandles, FALSE, INFINITE);  
  1313.   
  1314.     pgwin32_SetServiceStatus(SERVICE_STOP_PENDING);  
  1315.     switch (ret)  
  1316.     {  
  1317.         case WAIT_OBJECT_0:     /* shutdown event */  
  1318.             kill(postmasterPID, SIGINT);  
  1319.   
  1320.             /* 
  1321.              * Increment the checkpoint and try again Abort after 12 
  1322.              * checkpoints as the postmaster has probably hung 
  1323.              */  
  1324.             while (WaitForSingleObject(postmasterProcess, 5000) == WAIT_TIMEOUT && status.dwCheckPoint < 12)  
  1325.                 status.dwCheckPoint++;  
  1326.             break;  
  1327.   
  1328.         case (WAIT_OBJECT_0 + 1):       /* postmaster went down */  
  1329.             break;  
  1330.   
  1331.         default:  
  1332.             /* shouldn't get here? */  
  1333.             break;  
  1334.     }  
  1335.   
  1336.     CloseHandle(shutdownEvent);  
  1337.     CloseHandle(postmasterProcess);  
  1338.   
  1339.     pgwin32_SetServiceStatus(SERVICE_STOPPED);  
  1340. }  
  1341.   
  1342. static void  
  1343. pgwin32_doRunAsService(void)  
  1344. {  
  1345.     SERVICE_TABLE_ENTRY st[] = {{register_servicename, pgwin32_ServiceMain},  
  1346.     {NULL, NULL}};  
  1347.   
  1348.     if (StartServiceCtrlDispatcher(st) == 0)  
  1349.     {  
  1350.         write_stderr(_("%s: could not start service \"%s\": error code %d\n"), progname, register_servicename, (int) GetLastError());  
  1351.         exit(1);  
  1352.     }  
  1353. }  
  1354.   
  1355.   
  1356. /* 
  1357.  * Mingw headers are incomplete, and so are the libraries. So we have to load 
  1358.  * a whole lot of API functions dynamically. Since we have to do this anyway, 
  1359.  * also load the couple of functions that *do* exist in minwg headers but not 
  1360.  * on NT4. That way, we don't break on NT4. 
  1361.  */  
  1362. typedef BOOL (WINAPI * __CreateRestrictedToken) (HANDLEDWORDDWORD, PSID_AND_ATTRIBUTES, DWORD, PLUID_AND_ATTRIBUTES, DWORD, PSID_AND_ATTRIBUTES, PHANDLE);  
  1363. typedef BOOL (WINAPI * __IsProcessInJob) (HANDLEHANDLEPBOOL);  
  1364. typedef HANDLE (WINAPI * __CreateJobObject) (LPSECURITY_ATTRIBUTES, LPCTSTR);  
  1365. typedef BOOL (WINAPI * __SetInformationJobObject) (HANDLE, JOBOBJECTINFOCLASS, LPVOIDDWORD);  
  1366. typedef BOOL (WINAPI * __AssignProcessToJobObject) (HANDLEHANDLE);  
  1367. typedef BOOL (WINAPI * __QueryInformationJobObject) (HANDLE, JOBOBJECTINFOCLASS, LPVOIDDWORDLPDWORD);  
  1368.   
  1369. /* Windows API define missing from MingW headers */  
  1370. #define DISABLE_MAX_PRIVILEGE   0x1   
  1371.   
  1372. /* 
  1373.  * Create a restricted token, a job object sandbox, and execute the specified 
  1374.  * process with it. 
  1375.  * 
  1376.  * Returns 0 on success, non-zero on failure, same as CreateProcess(). 
  1377.  * 
  1378.  * On NT4, or any other system not containing the required functions, will 
  1379.  * launch the process under the current token without doing any modifications. 
  1380.  * 
  1381.  * NOTE! Job object will only work when running as a service, because it's 
  1382.  * automatically destroyed when pg_ctl exits. 
  1383.  */  
  1384. static int  
  1385. CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, bool as_service)  
  1386. {  
  1387.     int         r;  
  1388.     BOOL        b;  
  1389.     STARTUPINFO si;  
  1390.     HANDLE      origToken;  
  1391.     HANDLE      restrictedToken;  
  1392.     SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};  
  1393.     SID_AND_ATTRIBUTES dropSids[2];  
  1394.   
  1395.     /* Functions loaded dynamically */  
  1396.     __CreateRestrictedToken _CreateRestrictedToken = NULL;  
  1397.     __IsProcessInJob _IsProcessInJob = NULL;  
  1398.     __CreateJobObject _CreateJobObject = NULL;  
  1399.     __SetInformationJobObject _SetInformationJobObject = NULL;  
  1400.     __AssignProcessToJobObject _AssignProcessToJobObject = NULL;  
  1401.     __QueryInformationJobObject _QueryInformationJobObject = NULL;  
  1402.     HANDLE      Kernel32Handle;  
  1403.     HANDLE      Advapi32Handle;  
  1404.   
  1405.     ZeroMemory(&si, sizeof(si));  
  1406.     si.cb = sizeof(si);  
  1407.   
  1408.     Advapi32Handle = LoadLibrary("ADVAPI32.DLL");  
  1409.     if (Advapi32Handle != NULL)  
  1410.     {  
  1411.         _CreateRestrictedToken = (__CreateRestrictedToken) GetProcAddress(Advapi32Handle, "CreateRestrictedToken");  
  1412.     }  
  1413.   
  1414.     if (_CreateRestrictedToken == NULL)  
  1415.     {  
  1416.         /* 
  1417.          * NT4 doesn't have CreateRestrictedToken, so just call ordinary 
  1418.          * CreateProcess 
  1419.          */  
  1420.         write_stderr("WARNING: cannot create restricted tokens on this platform\n");  
  1421.         if (Advapi32Handle != NULL)  
  1422.             FreeLibrary(Advapi32Handle);  
  1423.         return CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, processInfo);  
  1424.     }  
  1425.   
  1426.     /* Open the current token to use as a base for the restricted one */  
  1427.     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &origToken))  
  1428.     {  
  1429.         write_stderr("Failed to open process token: %lu\n", GetLastError());  
  1430.         return 0;  
  1431.     }  
  1432.   
  1433.     /* Allocate list of SIDs to remove */  
  1434.     ZeroMemory(&dropSids, sizeof(dropSids));  
  1435.     if (!AllocateAndInitializeSid(&NtAuthority, 2,  
  1436.          SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,  
  1437.                                   0, &dropSids[0].Sid) ||  
  1438.         !AllocateAndInitializeSid(&NtAuthority, 2,  
  1439.     SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0,  
  1440.                                   0, &dropSids[1].Sid))  
  1441.     {  
  1442.         write_stderr("Failed to allocate SIDs: %lu\n", GetLastError());  
  1443.         return 0;  
  1444.     }  
  1445.   
  1446.     b = _CreateRestrictedToken(origToken,  
  1447.                                DISABLE_MAX_PRIVILEGE,  
  1448.                                sizeof(dropSids) / sizeof(dropSids[0]),  
  1449.                                dropSids,  
  1450.                                0, NULL,  
  1451.                                0, NULL,  
  1452.                                &restrictedToken);  
  1453.   
  1454.     FreeSid(dropSids[1].Sid);  
  1455.     FreeSid(dropSids[0].Sid);  
  1456.     CloseHandle(origToken);  
  1457.     FreeLibrary(Advapi32Handle);  
  1458.   
  1459.     if (!b)  
  1460.     {  
  1461.         write_stderr("Failed to create restricted token: %lu\n", GetLastError());  
  1462.         return 0;  
  1463.     }  
  1464.   
  1465. #ifndef __CYGWIN__   
  1466.     AddUserToTokenDacl(restrictedToken);  
  1467. #endif   
  1468.   
  1469.     r = CreateProcessASUSEr(restrictedToken, NULL, cmd, NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, NULL, &si, processInfo);  
  1470.   
  1471.     Kernel32Handle = LoadLibrary("KERNEL32.DLL");  
  1472.     if (Kernel32Handle != NULL)  
  1473.     {  
  1474.         _IsProcessInJob = (__IsProcessInJob) GetProcAddress(Kernel32Handle, "IsProcessInJob");  
  1475.         _CreateJobObject = (__CreateJobObject) GetProcAddress(Kernel32Handle, "CreateJobObjectA");  
  1476.         _SetInformationJobObject = (__SetInformationJobObject) GetProcAddress(Kernel32Handle, "SetInformationJobObject");  
  1477.         _AssignProcessToJobObject = (__AssignProcessToJobObject) GetProcAddress(Kernel32Handle, "AssignProcessToJobObject");  
  1478.         _QueryInformationJobObject = (__QueryInformationJobObject) GetProcAddress(Kernel32Handle, "QueryInformationJobObject");  
  1479.     }  
  1480.   
  1481.     /* Verify that we found all functions */  
  1482.     if (_IsProcessInJob == NULL || _CreateJobObject == NULL || _SetInformationJobObject == NULL || _AssignProcessToJobObject == NULL || _QueryInformationJobObject == NULL)  
  1483.     {  
  1484.         /* 
  1485.          * IsProcessInJob() is not available on < WinXP, so there is no need 
  1486.          * to log the error every time in that case 
  1487.          */  
  1488.         OSVERSIONINFO osv;  
  1489.   
  1490.         osv.dwOSVersionInfoSize = sizeof(osv);  
  1491.         if (!GetVersionEx(&osv) ||      /* could not get version */  
  1492.             (osv.dwMajorVersion == 5 && osv.dwMinorVersion > 0) ||       /* 5.1=xp, 5.2=2003, etc */  
  1493.             osv.dwMajorVersion > 5)      /* anything newer should have the API */  
  1494.   
  1495.             /* 
  1496.              * Log error if we can't get version, or if we're on WinXP/2003 or 
  1497.              * newer 
  1498.              */  
  1499.             write_stderr("WARNING: could not locate all job object functions in system API\n");  
  1500.     }  
  1501.     else  
  1502.     {  
  1503.         BOOL        inJob;  
  1504.   
  1505.         if (_IsProcessInJob(processInfo->hProcess, NULL, &inJob))  
  1506.         {  
  1507.             if (!inJob)  
  1508.             {  
  1509.                 /* 
  1510.                  * Job objects are working, and the new process isn't in one, 
  1511.                  * so we can create one safely. If any problems show up when 
  1512.                  * setting it, we're going to ignore them. 
  1513.                  */  
  1514.                 HANDLE      job;  
  1515.                 char        jobname[128];  
  1516.   
  1517.                 sprintf(jobname, "PostgreSQL_%lu", processInfo->dwProcessId);  
  1518.   
  1519.                 job = _CreateJobObject(NULL, jobname);  
  1520.                 if (job)  
  1521.                 {  
  1522.                     JOBOBJECT_BASIC_LIMIT_INFORMATION basicLimit;  
  1523.                     JOBOBJECT_BASIC_UI_RESTRICTIONS uiRestrictions;  
  1524.                     JOBOBJECT_SECURITY_LIMIT_INFORMATION securityLimit;  
  1525.                     OSVERSIONINFO osv;  
  1526.   
  1527.                     ZeroMemory(&basicLimit, sizeof(basicLimit));  
  1528.                     ZeroMemory(&uiRestrictions, sizeof(uiRestrictions));  
  1529.                     ZeroMemory(&securityLimit, sizeof(securityLimit));  
  1530.   
  1531.                     basicLimit.LimitFlags = JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION | JOB_OBJECT_LIMIT_PRIORITY_CLASS;  
  1532.                     basicLimit.PriorityClass = NORMAL_PRIORITY_CLASS;  
  1533.                     _SetInformationJobObject(job, JobObjectBasicLimitInformation, &basicLimit, sizeof(basicLimit));  
  1534.   
  1535.                     uiRestrictions.UIRestrictionsClass = JOB_OBJECT_UILIMIT_DESKTOP | JOB_OBJECT_UILIMIT_DISPLAYSETTINGS |  
  1536.                         JOB_OBJECT_UILIMIT_EXITWINDOWS | JOB_OBJECT_UILIMIT_READCLIPBOARD |  
  1537.                         JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS | JOB_OBJECT_UILIMIT_WRITECLIPBOARD;  
  1538.   
  1539.                     if (as_service)  
  1540.                     {  
  1541.                         osv.dwOSVersionInfoSize = sizeof(osv);  
  1542.                         if (!GetVersionEx(&osv) ||  
  1543.                             osv.dwMajorVersion < 6 ||  
  1544.                         (osv.dwMajorVersion == 6 && osv.dwMinorVersion == 0))  
  1545.                         {  
  1546.                             /* 
  1547.                              * On Windows 7 (and presumably later), 
  1548.                              * JOB_OBJECT_UILIMIT_HANDLES prevents us from 
  1549.                              * starting as a service. So we only enable it on 
  1550.                              * Vista and earlier (version <= 6.0) 
  1551.                              */  
  1552.                             uiRestrictions.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_HANDLES;  
  1553.                         }  
  1554.                     }  
  1555.                     _SetInformationJobObject(job, JobObjectBasicUIRestrictions, &uiRestrictions, sizeof(uiRestrictions));  
  1556.   
  1557.                     securityLimit.SecurityLimitFlags = JOB_OBJECT_SECURITY_NO_ADMIN | JOB_OBJECT_SECURITY_ONLY_TOKEN;  
  1558.                     securityLimit.JobToken = restrictedToken;  
  1559.                     _SetInformationJobObject(job, JobObjectSecurityLimitInformation, &securityLimit, sizeof(securityLimit));  
  1560.   
  1561.                     _AssignProcessToJobObject(job, processInfo->hProcess);  
  1562.                 }  
  1563.             }  
  1564.         }  
  1565.     }  
  1566.   
  1567.   
  1568.     CloseHandle(restrictedToken);  
  1569.   
  1570.     ResumeThread(processInfo->hThread);  
  1571.   
  1572.     FreeLibrary(Kernel32Handle);  
  1573.   
  1574.     /* 
  1575.      * We intentionally don't close the job object handle, because we want the 
  1576.      * object to live on until pg_ctl shuts down. 
  1577.      */  
  1578.     return r;  
  1579. }  
  1580. #endif   
  1581.   
  1582. static void  
  1583. do_advice(void)  
  1584. {  
  1585.     write_stderr(_("Try \"%s --help\" for more information.\n"), progname);  
  1586. }  
  1587.   
  1588.   
  1589.   
  1590. static void  
  1591. do_help(void)  
  1592. {  
  1593.     printf(_("%s is a utility to start, stop, restart, reload configuration files,\n"  
  1594.              "report the status of a PostgreSQL server, or signal a PostgreSQL process.\n\n"), progname);  
  1595.     printf(_("Usage:\n"));  
  1596.     printf(_("  %s init[db]               [-D DATADIR] [-s] [-o \"OPTIONS\"]\n"), progname);  
  1597.     printf(_("  %s start   [-w] [-t SECS] [-D DATADIR] [-s] [-l FILENAME] [-o \"OPTIONS\"]\n"), progname);  
  1598.     printf(_("  %s stop    [-W] [-t SECS] [-D DATADIR] [-s] [-m SHUTDOWN-MODE]\n"), progname);  
  1599.     printf(_("  %s restart [-w] [-t SECS] [-D DATADIR] [-s] [-m SHUTDOWN-MODE]\n"  
  1600.              "                 [-o \"OPTIONS\"]\n"), progname);  
  1601.     printf(_("  %s reload  [-D DATADIR] [-s]\n"), progname);  
  1602.     printf(_("  %s status  [-D DATADIR]\n"), progname);  
  1603.     printf(_("  %s kill    SIGNALNAME PID\n"), progname);  
  1604. #if defined(WIN32) || defined(__CYGWIN__)   
  1605.     printf(_("  %s register   [-N SERVICENAME] [-U USERNAME] [-P PASSWORD] [-D DATADIR]\n"  
  1606.          "                    [-w] [-t SECS] [-o \"OPTIONS\"]\n"), progname);  
  1607.     printf(_("  %s unregister [-N SERVICENAME]\n"), progname);  
  1608. #endif   
  1609.   
  1610.     printf(_("\nCommon options:\n"));  
  1611.     printf(_("  -D, --pgdata DATADIR   location of the database storage area\n"));  
  1612.     printf(_("  -s, --silent           only print errors, no informational messages\n"));  
  1613.     printf(_("  -t SECS                seconds to wait when using -w option\n"));  
  1614.     printf(_("  -w                     wait until operation completes\n"));  
  1615.     printf(_("  -W                     do not wait until operation completes\n"));  
  1616.     printf(_("  --help                 show this help, then exit\n"));  
  1617.     printf(_("  --version              output version information, then exit\n"));  
  1618.     printf(_("(The default is to wait for shutdown, but not for start or restart.)\n\n"));  
  1619.     printf(_("If the -D option is omitted, the environment variable PGDATA is used.\n"));  
  1620.   
  1621.     printf(_("\nOptions for start or restart:\n"));  
  1622. #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)   
  1623.     printf(_("  -c, --core-files       allow postgres to produce core files\n"));  
  1624. #else   
  1625.     printf(_("  -c, --core-files       not applicable on this platform\n"));  
  1626. #endif   
  1627.     printf(_("  -l, --log FILENAME     write (or append) server log to FILENAME\n"));  
  1628.     printf(_("  -o OPTIONS             command line options to pass to postgres\n"  
  1629.      "                         (PostgreSQL server executable) or initdb\n"));  
  1630.     printf(_("  -p PATH-TO-POSTGRES    normally not necessary\n"));  
  1631.     printf(_("\nOptions for stop or restart:\n"));  
  1632.     printf(_("  -m SHUTDOWN-MODE   can be \"smart\", \"fast\", or \"immediate\"\n"));  
  1633.   
  1634.     printf(_("\nShutdown modes are:\n"));  
  1635.     printf(_("  smart       quit after all clients have disconnected\n"));  
  1636.     printf(_("  fast        quit directly, with proper shutdown\n"));  
  1637.     printf(_("  immediate   quit without complete shutdown; will lead to recovery on restart\n"));  
  1638.   
  1639.     printf(_("\nAllowed signal names for kill:\n"));  
  1640.     printf("  HUP INT QUIT ABRT TERM USR1 USR2\n");  
  1641.   
  1642. #if defined(WIN32) || defined(__CYGWIN__)   
  1643.     printf(_("\nOptions for register and unregister:\n"));  
  1644.     printf(_("  -N SERVICENAME  service name with which to register PostgreSQL server\n"));  
  1645.     printf(_("  -P PASSWORD     password of account to register PostgreSQL server\n"));  
  1646.     printf(_("  -U USERNAME     user name of account to register PostgreSQL server\n"));  
  1647. #endif   
  1648.   
  1649.     printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));  
  1650. }  
  1651.   
  1652.   
  1653.   
  1654. static void  
  1655. set_mode(char *modeopt)  
  1656. {  
  1657.     if (strcmp(modeopt, "s") == 0 || strcmp(modeopt, "smart") == 0)  
  1658.     {  
  1659.         shutdown_mode = SMART_MODE;  
  1660.         sig = SIGTERM;  
  1661.     }  
  1662.     else if (strcmp(modeopt, "f") == 0 || strcmp(modeopt, "fast") == 0)  
  1663.     {  
  1664.         shutdown_mode = FAST_MODE;  
  1665.         sig = SIGINT;  
  1666.     }  
  1667.     else if (strcmp(modeopt, "i") == 0 || strcmp(modeopt, "immediate") == 0)  
  1668.     {  
  1669.         shutdown_mode = IMMEDIATE_MODE;  
  1670.         sig = SIGQUIT;  
  1671.     }  
  1672.     else  
  1673.     {  
  1674.         write_stderr(_("%s: unrecognized shutdown mode \"%s\"\n"), progname, modeopt);  
  1675.         do_advice();  
  1676.         exit(1);  
  1677.     }  
  1678. }  
  1679.   
  1680.   
  1681.   
  1682. static void  
  1683. set_sig(char *signame)  
  1684. {  
  1685.     if (!strcmp(signame, "HUP"))  
  1686.         sig = SIGHUP;  
  1687.     else if (!strcmp(signame, "INT"))  
  1688.         sig = SIGINT;  
  1689.     else if (!strcmp(signame, "QUIT"))  
  1690.         sig = SIGQUIT;  
  1691.     else if (!strcmp(signame, "ABRT"))  
  1692.         sig = SIGABRT;  
  1693.   
  1694.     /* 
  1695.      * probably should NOT provide SIGKILL 
  1696.      * 
  1697.      * else if (!strcmp(signame,"KILL")) sig = SIGKILL; 
  1698.      */  
  1699.     else if (!strcmp(signame, "TERM"))  
  1700.         sig = SIGTERM;  
  1701.     else if (!strcmp(signame, "USR1"))  
  1702.         sig = SIGUSR1;  
  1703.     else if (!strcmp(signame, "USR2"))  
  1704.         sig = SIGUSR2;  
  1705.     else  
  1706.     {  
  1707.         write_stderr(_("%s: unrecognized signal name \"%s\"\n"), progname, signame);  
  1708.         do_advice();  
  1709.         exit(1);  
  1710.     }  
  1711.   
  1712. }  
  • 1
  • 2
  • 下一页

相关内容