使用开源软件最大的一个好处就是能够看到它的实现,便于更深入地学习,这几天正在看pg_ctl的源码,先贴出源码,随后的时间里对各函数一一分析,,顺便测试一下这个编辑器最多支持多少行。呵呵。
- /*-------------------------------------------------------------------------
- *
- * pg_ctl --- start/stops/restarts the PostgreSQL server
- *
- * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
- *
- * $PostgreSQL: pgsql/src/bin/pg_ctl/pg_ctl.c,v 1.122.2.1 2010/09/14 08:05:54 heikki Exp $
- *
- *-------------------------------------------------------------------------
- */
-
- #ifdef WIN32
- /*
- * Need this to get defines for restricted tokens and jobs. And it
- * has to be set before any header from the Win32 API is loaded.
- */
- #define _WIN32_WINNT 0x0501
- #endif
-
- #include "postgres_fe.h"
- #include "libpq-fe.h"
-
- #include <locale.h>
- #include <signal.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <unistd.h>
-
- #ifdef HAVE_SYS_RESOURCE_H
- #include <sys/time.h>
- #include <sys/resource.h>
- #endif
-
- #include "libpq/pqsignal.h"
- #include "getopt_long.h"
- #include "miscadmin.h"
-
- #if defined(__CYGWIN__)
- #include <sys/cygwin.h>
- #include <windows.h>
- /* Cygwin defines WIN32 in windows.h, but we don"t want it. */
- #undef WIN32
- #endif
-
- /* PID can be negative for standalone backend */
- typedef long pgpid_t;
-
-
- typedef enum
- {
- SMART_MODE,
- FAST_MODE,
- IMMEDIATE_MODE
- } ShutdownMode;
-
-
- typedef enum
- {
- NO_COMMAND = 0,
- INIT_COMMAND,
- START_COMMAND,
- STOP_COMMAND,
- RESTART_COMMAND,
- RELOAD_COMMAND,
- STATUS_COMMAND,
- KILL_COMMAND,
- REGISTER_COMMAND,
- UNREGISTER_COMMAND,
- RUN_AS_SERVICE_COMMAND
- } CtlCommand;
-
- #define DEFAULT_WAIT 60
-
- static bool do_wait = false;
- static bool wait_set = false;
- static int wait_seconds = DEFAULT_WAIT;
- static bool silent_mode = false;
- static ShutdownMode shutdown_mode = SMART_MODE;
- static int sig = SIGTERM; /* default */
- static CtlCommand ctl_command = NO_COMMAND;
- static char *pg_data = NULL;
- static char *pgdata_opt = NULL;
- static char *post_opts = NULL;
- static const char *progname;
- static char *log_file = NULL;
- static char *exec_path = NULL;
- static char *register_servicename = "PostgreSQL"; /* FIXME: + version ID? */
- static char *register_username = NULL;
- static char *register_password = NULL;
- static char *argv0 = NULL;
- static bool allow_core_files = false;
-
- static void
- write_stderr(const char *fmt,...)
- /* This extension allows gcc to check the format string for consistency with
- the supplied arguments. */
- __attribute__((format(printf, 1, 2)));
- static void *pg_malloc(size_t size);
- static char *xstrdup(const char *s);
- static void do_advice(void);
- static void do_help(void);
- static void set_mode(char *modeopt);
- static void set_sig(char *signame);
- static void do_init(void);
- static void do_start(void);
- static void do_stop(void);
- static void do_restart(void);
- static void do_reload(void);
- static void do_status(void);
- static void do_kill(pgpid_t pid);
- static void print_msg(const char *msg);
-
- #if defined(WIN32) || defined(__CYGWIN__)
- static bool pgwin32_IsInstalled(SC_HANDLE);
- static char *pgwin32_CommandLine(bool);
- static void pgwin32_doRegister(void);
- static void pgwin32_doUnregister(void);
- static void pgwin32_SetServiceStatus(DWORD);
- static void WINAPI pgwin32_ServiceHandler(DWORD);
- static void WINAPI pgwin32_ServiceMain(DWORD, LPTSTR *);
- static void pgwin32_doRunAsService(void);
- static int CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, bool as_service);
-
- static SERVICE_STATUS status;
- static SERVICE_STATUS_HANDLE hStatus = (SERVICE_STATUS_HANDLE) 0;
- static HANDLE shutdownHandles[2];
- static pid_t postmasterPID = -1;
-
- #define shutdownEvent shutdownHandles[0]
- #define postmasterProcess shutdownHandles[1]
- #endif
-
- static pgpid_t get_pgpid(void);
- static char **readfile(const char *path);
- static int start_postmaster(void);
- static void read_post_opts(void);
-
- static bool test_postmaster_connection(bool);
- static bool postmaster_is_alive(pid_t pid);
-
- static char postopts_file[MAXPGPATH];
- static char pid_file[MAXPGPATH];
- static char conf_file[MAXPGPATH];
- static char backup_file[MAXPGPATH];
- static char recovery_file[MAXPGPATH];
-
- #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
- static void unlimit_core_size(void);
- #endif
-
-
- #if defined(WIN32) || defined(__CYGWIN__)
- static void
- write_eventlog(int level, const char *line)
- {
- static HANDLE evtHandle = INVALID_HANDLE_VALUE;
-
- if (evtHandle == INVALID_HANDLE_VALUE)
- {
- evtHandle = RegisterEventSource(NULL, "PostgreSQL");
- if (evtHandle == NULL)
- {
- evtHandle = INVALID_HANDLE_VALUE;
- return;
- }
- }
-
- ReportEvent(evtHandle,
- level,
- 0,
- 0, /* All events are Id 0 */
- NULL,
- 1,
- 0,
- &line,
- NULL);
- }
- #endif
-
- /*
- * Write errors to stderr (or by equal means when stderr is
- * not available).
- */
- static void
- write_stderr(const char *fmt,...)
- {
- va_list ap;
-
- va_start(ap, fmt);
- #if !defined(WIN32) && !defined(__CYGWIN__)
- /* On Unix, we just fprintf to stderr */
- vfprintf(stderr, fmt, ap);
- #else
-
- /*
- * On Win32, we print to stderr if running on a console, or write to
- * eventlog if running as a service
- */
- if (!isatty(fileno(stderr))) /* Running as a service */
- {
- char errbuf[2048]; /* Arbitrary size? */
-
- vsnprintf(errbuf, sizeof(errbuf), fmt, ap);
-
- write_eventlog(EVENTLOG_ERROR_TYPE, errbuf);
- }
- else
- /* Not running as service, write to stderr */
- vfprintf(stderr, fmt, ap);
- #endif
- va_end(ap);
- }
-
- /*
- * routines to check memory allocations and fail noisily.
- */
-
- static void *
- pg_malloc(size_t size)
- {
- void *result;
-
- result = malloc(size);
- if (!result)
- {
- write_stderr(_("%s: out of memory
"), progname);
- exit(1);
- }
- return result;
- }
-
-
- static char *
- xstrdup(const char *s)
- {
- char *result;
-
- result = strdup(s);
- if (!result)
- {
- write_stderr(_("%s: out of memory
"), progname);
- exit(1);
- }
- return result;
- }
-
- /*
- * Given an already-localized string, print it to stdout unless the
- * user has specified that no messages should be printed.
- */
- static void
- print_msg(const char *msg)
- {
- if (!silent_mode)
- {
- fputs(msg, stdout);
- fflush(stdout);
- }
- }
-
- static pgpid_t
- get_pgpid(void)
- {
- FILE *pidf;
- long pid;
-
- pidf = fopen(pid_file, "r");
- if (pidf == NULL)
- {
- /* No pid file, not an error on startup */
- if (errno == ENOENT)
- return 0;
- else
- {
- write_stderr(_("%s: could not open PID file "%s": %s
"),
- progname, pid_file, strerror(errno));
- exit(1);
- }
- }
- if (fscanf(pidf, "%ld", &pid) != 1)
- {
- write_stderr(_("%s: invalid data in PID file "%s"
"),
- progname, pid_file);
- exit(1);
- }
- fclose(pidf);
- return (pgpid_t) pid;
- }
-
-
- /*
- * get the lines from a text file - return NULL if file can"t be opened
- */
- static char **
- readfile(const char *path)
- {
- FILE *infile;
- int maxlength = 1,
- linelen = 0;
- int nlines = 0;
- char **result;
- char *buffer;
- int c;
-
- if ((infile = fopen(path, "r")) == NULL)
- return NULL;
-
- /* pass over the file twice - the first time to size the result */
-
- while ((c = fgetc(infile)) != EOF)
- {
- linelen++;
- if (c == "
")
- {
- nlines++;
- if (linelen > maxlength)
- maxlength = linelen;
- linelen = 0;
- }
- }
-
- /* handle last line without a terminating newline (yuck) */
- if (linelen)
- nlines++;
- if (linelen > maxlength)
- maxlength = linelen;
-
- /* set up the result and the line buffer */
- result = (char **) pg_malloc((nlines + 1) * sizeof(char *));
- buffer = (char *) pg_malloc(maxlength + 1);
-
- /* now reprocess the file and store the lines */
- rewind(infile);
- nlines = 0;
- while (fgets(buffer, maxlength + 1, infile) != NULL)
- result[nlines++] = xstrdup(buffer);
-
- fclose(infile);
- free(buffer);
- result[nlines] = NULL;
-
- return result;
- }
-
-
-
- /*
- * start/test/stop routines
- */
-
- static int
- start_postmaster(void)
- {
- char cmd[MAXPGPATH];
-
- #ifndef WIN32
-
- /*
- * Since there might be quotes to handle here, it is easier simply to pass
- * everything to a shell to process them.
- */
- if (log_file != NULL)
- snprintf(cmd, MAXPGPATH, SYSTEMQUOTE ""%s" %s%s < "%s" >> "%s" 2>&1 &" SYSTEMQUOTE,
- exec_path, pgdata_opt, post_opts,
- DEVNULL, log_file);
- else
- snprintf(cmd, MAXPGPATH, SYSTEMQUOTE ""%s" %s%s < "%s" 2>&1 &" SYSTEMQUOTE,
- exec_path, pgdata_opt, post_opts, DEVNULL);
-
- return system(cmd);
- #else /* WIN32 */
-
- /*
- * On win32 we don"t use system(). So we don"t need to use & (which would
- * be START /B on win32). However, we still call the shell (CMD.EXE) with
- * it to handle redirection etc.
- */
- PROCESS_INFORMATION pi;
-
- if (log_file != NULL)
- snprintf(cmd, MAXPGPATH, "CMD /C " SYSTEMQUOTE ""%s" %s%s < "%s" >> "%s" 2>&1" SYSTEMQUOTE,
- exec_path, pgdata_opt, post_opts, DEVNULL, log_file);
- else
- snprintf(cmd, MAXPGPATH, "CMD /C " SYSTEMQUOTE ""%s" %s%s < "%s" 2>&1" SYSTEMQUOTE,
- exec_path, pgdata_opt, post_opts, DEVNULL);
-
- if (!CreateRestrictedProcess(cmd, &pi, false))
- return GetLastError();
- CloseHandle(pi.hProcess);
- CloseHandle(pi.hThread);
- return 0;
- #endif /* WIN32 */
- }
-
-
-
- /*
- * Find the pgport and try a connection
- * Note that the checkpoint parameter enables a Windows service control
- * manager checkpoint, it"s got nothing to do with database checkpoints!!
- */
- static bool
- test_postmaster_connection(bool do_checkpoint)
- {
- PGconn *conn;
- bool success = false;
- int i;
- char portstr[32];
- char *p;
- char *q;
- char connstr[128]; /* Should be way more than enough! */
-
- *portstr = " ";
-
- /*
- * Look in post_opts for a -p switch.
- *
- * This parsing code is not amazingly bright; it could for instance get
- * fooled if " -p" occurs within a quoted argument value. Given that few
- * people pass complicated settings in post_opts, it"s probably good
- * enough.
- */
- for (p = post_opts; *p;)
- {
- /* advance past whitespace */
- while (isspace((unsigned char) *p))
- p++;
-
- if (strncmp(p, "-p", 2) == 0)
- {
- p += 2;
- /* advance past any whitespace/quoting */
- while (isspace((unsigned char) *p) || *p == """ || *p == """)
- p++;
- /* find end of value (not including any ending quote!) */
- q = p;
- while (*q &&
- !(isspace((unsigned char) *q) || *q == """ || *q == """))
- q++;
- /* and save the argument value */
- strlcpy(portstr, p, Min((q - p) + 1, sizeof(portstr)));
- /* keep looking, maybe there is another -p */
- p = q;
- }
- /* Advance to next whitespace */
- while (*p && !isspace((unsigned char) *p))
- p++;
- }
-
- /*
- * Search config file for a "port" option.
- *
- * This parsing code isn"t amazingly bright either, but it should be okay
- * for valid port settings.
- */
- if (!*portstr)
- {
- char **optlines;
-
- optlines = readfile(conf_file);
- if (optlines != NULL)
- {
- for (; *optlines != NULL; optlines++)
- {
- p = *optlines;
-
- while (isspace((unsigned char) *p))
- p++;
- if (strncmp(p, "port", 4) != 0)
- continue;
- p += 4;
- while (isspace((unsigned char) *p))
- p++;
- if (*p != "=")
- continue;
- p++;
- /* advance past any whitespace/quoting */
- while (isspace((unsigned char) *p) || *p == """ || *p == """)
- p++;
- /* find end of value (not including any ending quote/comment!) */
- q = p;
- while (*q &&
- !(isspace((unsigned char) *q) ||
- *q == """ || *q == """ || *q == "#"))
- q++;
- /* and save the argument value */
- strlcpy(portstr, p, Min((q - p) + 1, sizeof(portstr)));
- /* keep looking, maybe there is another */
- }
- }
- }
-
- /* Check environment */
- if (!*portstr && getenv("PGPORT") != NULL)
- strlcpy(portstr, getenv("PGPORT"), sizeof(portstr));
-
- /* Else use compiled-in default */
- if (!*portstr)
- snprintf(portstr, sizeof(portstr), "%d", DEF_PGPORT);
-
- /*
- * We need to set a connect timeout otherwise on Windows the SCM will
- * probably timeout first
- */
- snprintf(connstr, sizeof(connstr),
- "dbname=postgres port=%s connect_timeout=5", portstr);
-
- for (i = 0; i < wait_seconds; i++)
- {
- if ((conn = PQconnectdb(connstr)) != NULL &&
- (PQstatus(conn) == CONNECTION_OK ||
- PQconnectionNeedsPassword(conn)))
- {
- PQfinish(conn);
- success = true;
- break;
- }
- else
- {
- PQfinish(conn);
-
- #if defined(WIN32)
- if (do_checkpoint)
- {
- /*
- * Increment the wait hint by 6 secs (connection timeout +
- <