Welcome 微信登录
编程资源 图片资源库 蚂蚁家优选

首页 / 数据库 / MySQL / 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 "), 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 "), 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 "),  
  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" "),  
  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 == " ")  
  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) * sizeofchar *));  
  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 = "";  
  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. <