PostgreSQL工具pg_ctl实现代码
使用开源软件最大的一个好处就是能够看到它的实现,便于更深入地学习,这几天正在看pg_ctl的源码,先贴出源码,随后的时间里对各函数一一分析,,顺便测试一下这个编辑器最多支持多少行。呵呵。
-
-
-
-
-
-
-
-
-
-
-
- #ifdef WIN32
-
-
-
-
- #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>
-
- #undef WIN32
- #endif
-
-
- 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;
- 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";
- 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,...)
-
-
- __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,
- NULL,
- 1,
- 0,
- &line,
- NULL);
- }
- #endif
-
-
-
-
-
- static void
- write_stderr(const char *fmt,...)
- {
- va_list ap;
-
- va_start(ap, fmt);
- #if !defined(WIN32) && !defined(__CYGWIN__)
-
- vfprintf(stderr, fmt, ap);
- #else
-
-
-
-
-
- if (!isatty(fileno(stderr)))
- {
- char errbuf[2048];
-
- vsnprintf(errbuf, sizeof(errbuf), fmt, ap);
-
- write_eventlog(EVENTLOG_ERROR_TYPE, errbuf);
- }
- else
-
- vfprintf(stderr, fmt, ap);
- #endif
- va_end(ap);
- }
-
-
-
-
-
- static void *
- pg_malloc(size_t size)
- {
- void *result;
-
- result = malloc(size);
- if (!result)
- {
- write_stderr(_("%s: out of memory\n"), progname);
- exit(1);
- }
- return result;
- }
-
-
- static char *
- xstrdup(const char *s)
- {
- char *result;
-
- result = strdup(s);
- if (!result)
- {
- write_stderr(_("%s: out of memory\n"), progname);
- exit(1);
- }
- return result;
- }
-
-
-
-
-
- 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)
- {
-
- if (errno == ENOENT)
- return 0;
- else
- {
- write_stderr(_("%s: could not open PID file \"%s\": %s\n"),
- progname, pid_file, strerror(errno));
- exit(1);
- }
- }
- if (fscanf(pidf, "%ld", &pid) != 1)
- {
- write_stderr(_("%s: invalid data in PID file \"%s\"\n"),
- progname, pid_file);
- exit(1);
- }
- fclose(pidf);
- return (pgpid_t) pid;
- }
-
-
-
-
-
- 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;
-
-
-
- while ((c = fgetc(infile)) != EOF)
- {
- linelen++;
- if (c == '\n')
- {
- nlines++;
- if (linelen > maxlength)
- maxlength = linelen;
- linelen = 0;
- }
- }
-
-
- if (linelen)
- nlines++;
- if (linelen > maxlength)
- maxlength = linelen;
-
-
- result = (char **) pg_malloc((nlines + 1) * sizeof(char *));
- buffer = (char *) pg_malloc(maxlength + 1);
-
-
- rewind(infile);
- nlines = 0;
- while (fgets(buffer, maxlength + 1, infile) != NULL)
- result[nlines++] = xstrdup(buffer);
-
- fclose(infile);
- free(buffer);
- result[nlines] = NULL;
-
- return result;
- }
-
-
-
-
-
-
-
- static int
- start_postmaster(void)
- {
- char cmd[MAXPGPATH];
-
- #ifndef WIN32
-
-
-
-
-
- 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 */
-
-
-
-
-
-
- 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 */
- }
-
-
-
-
-
-
-
-
- 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];
-
- *portstr = '\0';
-
-
-
-
-
-
-
-
-
- for (p = post_opts; *p;)
- {
-
- while (isspace((unsigned char) *p))
- p++;
-
- if (strncmp(p, "-p", 2) == 0)
- {
- p += 2;
-
- while (isspace((unsigned char) *p) || *p == '\'' || *p == '"')
- p++;
-
- q = p;
- while (*q &&
- !(isspace((unsigned char) *q) || *q == '\'' || *q == '"'))
- q++;
-
- strlcpy(portstr, p, Min((q - p) + 1, sizeof(portstr)));
-
- p = q;
- }
-
- while (*p && !isspace((unsigned char) *p))
- p++;
- }
-
-
-
-
-
-
-
- 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++;
-
- while (isspace((unsigned char) *p) || *p == '\'' || *p == '"')
- p++;
-
- q = p;
- while (*q &&
- !(isspace((unsigned char) *q) ||
- *q == '\'' || *q == '"' || *q == '#'))
- q++;
-
- strlcpy(portstr, p, Min((q - p) + 1, sizeof(portstr)));
-
- }
- }
- }
-
-
- if (!*portstr && getenv("PGPORT") != NULL)
- strlcpy(portstr, getenv("PGPORT"), sizeof(portstr));
-
-
- if (!*portstr)
- snprintf(portstr, sizeof(portstr), "%d", DEF_PGPORT);
-
-
-
-
-
- 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)
- {
-
-
-
-
-
-
-
- status.dwWaitHint += 6000;
- status.dwCheckPoint++;
- SetServiceStatus(hStatus, (LPSERVICE_STATUS) &status);
- }
-
- else
- #endif
- print_msg(".");
-
- pg_usleep(1000000);
- }
- }
-
- return success;
- }
-
-
- #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
- static void
- unlimit_core_size(void)
- {
- struct rlimit lim;
-
- getrlimit(RLIMIT_CORE, &lim);
- if (lim.rlim_max == 0)
- {
- write_stderr(_("%s: cannot set core file size limit; disallowed by hard limit\n"),
- progname);
- return;
- }
- else if (lim.rlim_max == RLIM_INFINITY || lim.rlim_cur < lim.rlim_max)
- {
- lim.rlim_cur = lim.rlim_max;
- setrlimit(RLIMIT_CORE, &lim);
- }
- }
- #endif
-
- static void
- read_post_opts(void)
- {
- if (post_opts == NULL)
- {
- post_opts = "";
- if (ctl_command == RESTART_COMMAND)
- {
- char **optlines;
-
- optlines = readfile(postopts_file);
- if (optlines == NULL)
- {
- write_stderr(_("%s: could not read file \"%s\"\n"), progname, postopts_file);
- exit(1);
- }
- else if (optlines[0] == NULL || optlines[1] != NULL)
- {
- write_stderr(_("%s: option file \"%s\" must have exactly one line\n"),
- progname, postopts_file);
- exit(1);
- }
- else
- {
- int len;
- char *optline;
- char *arg1;
-
- optline = optlines[0];
-
- len = strcspn(optline, "\r\n");
- optline[len] = '\0';
-
-
-
-
-
- if ((arg1 = strstr(optline, " \"")) != NULL)
- {
- *arg1 = '\0';
-
- post_opts = arg1 + 1;
- }
- if (exec_path == NULL)
- exec_path = optline;
- }
- }
- }
- }
-
- static char *
- find_other_exec_or_die(const char *argv0, const char *target, const char *versionstr)
- {
- int ret;
- char *found_path;
-
- found_path = pg_malloc(MAXPGPATH);
-
- if ((ret = find_other_exec(argv0, target, versionstr, found_path)) < 0)
- {
- char full_path[MAXPGPATH];
-
- if (find_my_exec(argv0, full_path) < 0)
- strlcpy(full_path, progname, sizeof(full_path));
-
- if (ret == -1)
- write_stderr(_("The program \"%s\" is needed by %s "
- "but was not found in the\n"
- "same directory as \"%s\".\n"
- "Check your installation.\n"),
- target, progname, full_path);
- else
- write_stderr(_("The program \"%s\" was found by \"%s\"\n"
- "but was not the same version as %s.\n"
- "Check your installation.\n"),
- target, full_path, progname);
- exit(1);
- }
-
- return found_path;
- }
-
- static void
- do_init(void)
- {
- char cmd[MAXPGPATH];
-
- if (exec_path == NULL)
- exec_path = find_other_exec_or_die(argv0, "initdb", "initdb (PostgreSQL) " PG_VERSION "\n");
-
- if (pgdata_opt == NULL)
- pgdata_opt = "";
-
- if (post_opts == NULL)
- post_opts = "";
-
- if (!silent_mode)
- snprintf(cmd, MAXPGPATH, SYSTEMQUOTE "\"%s\" %s%s" SYSTEMQUOTE,
- exec_path, pgdata_opt, post_opts);
- else
- snprintf(cmd, MAXPGPATH, SYSTEMQUOTE "\"%s\" %s%s > \"%s\"" SYSTEMQUOTE,
- exec_path, pgdata_opt, post_opts, DEVNULL);
-
- if (system(cmd) != 0)
- {
- write_stderr(_("%s: database system initialization failed\n"), progname);
- exit(1);
- }
- }
-
- static void
- do_start(void)
- {
- pgpid_t pid;
- pgpid_t old_pid = 0;
- int exitcode;
-
- if (ctl_command != RESTART_COMMAND)
- {
- old_pid = get_pgpid();
- if (old_pid != 0)
- write_stderr(_("%s: another server might be running; "
- "trying to start server anyway\n"),
- progname);
- }
-
- read_post_opts();
-
-
- if (ctl_command == RESTART_COMMAND || pgdata_opt == NULL)
- pgdata_opt = "";
-
- if (exec_path == NULL)
- exec_path = find_other_exec_or_die(argv0, "postgres", PG_BACKEND_VERSIONSTR);
-
- #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
- if (allow_core_files)
- unlimit_core_size();
- #endif
-
-
-
-
-
-
- #ifndef WIN32
- {
- static char env_var[32];
-
- snprintf(env_var, sizeof(env_var), "PG_GRANDPARENT_PID=%d",
- (int) getppid());
- putenv(env_var);
- }
- #endif
-
- exitcode = start_postmaster();
- if (exitcode != 0)
- {
- write_stderr(_("%s: could not start server: exit code was %d\n"),
- progname, exitcode);
- exit(1);
- }
-
- if (old_pid != 0)
- {
- pg_usleep(1000000);
- pid = get_pgpid();
- if (pid == old_pid)
- {
- write_stderr(_("%s: could not start server\n"
- "Examine the log output.\n"),
- progname);
- exit(1);
- }
- }
-
- if (do_wait)
- {
- print_msg(_("waiting for server to start..."));
-
- if (test_postmaster_connection(false) == false)
- {
- write_stderr(_("%s: could not start server\n"
- "Examine the log output.\n"),
- progname);
- exit(1);
- }
- else
- {
- print_msg(_(" done\n"));
- print_msg(_("server started\n"));
- }
- }
- else
- print_msg(_("server starting\n"));
- }
-
-
- static void
- do_stop(void)
- {
- int cnt;
- pgpid_t pid;
- struct stat statbuf;
-
- pid = get_pgpid();
-
- if (pid == 0)
- {
- write_stderr(_("%s: PID file \"%s\" does not exist\n"), progname, pid_file);
- write_stderr(_("Is server running?\n"));
- exit(1);
- }
- else if (pid < 0)
- {
- pid = -pid;
- write_stderr(_("%s: cannot stop server; "
- "single-user server is running (PID: %ld)\n"),
- progname, pid);
- exit(1);
- }
-
- if (kill((pid_t) pid, sig) != 0)
- {
- write_stderr(_("%s: could not send stop signal (PID: %ld): %s\n"), progname, pid,
- strerror(errno));
- exit(1);
- }
-
- if (!do_wait)
- {
- print_msg(_("server shutting down\n"));
- return;
- }
- else
- {
-
-
-
-
-
-
- if (shutdown_mode == SMART_MODE &&
- stat(backup_file, &statbuf) == 0 &&
- stat(recovery_file, &statbuf) != 0)
- {
- print_msg(_("WARNING: online backup mode is active\n"
- "Shutdown will not complete until pg_stop_backup() is called.\n\n"));
- }
-
- print_msg(_("waiting for server to shut down..."));
-
- for (cnt = 0; cnt < wait_seconds; cnt++)
- {
- if ((pid = get_pgpid()) != 0)
- {
- print_msg(".");
- pg_usleep(1000000);
- }
- else
- break;
- }
-
- if (pid != 0)
- {
- print_msg(_(" failed\n"));
-
- write_stderr(_("%s: server does not shut down\n"), progname);
- exit(1);
- }
- print_msg(_(" done\n"));
-
- print_msg(_("server stopped\n"));
- }
- }
-
-
-
-
-
-
- static void
- do_restart(void)
- {
- int cnt;
- pgpid_t pid;
- struct stat statbuf;
-
- pid = get_pgpid();
-
- if (pid == 0)
- {
- write_stderr(_("%s: PID file \"%s\" does not exist\n"),
- progname, pid_file);
- write_stderr(_("Is server running?\n"));
- write_stderr(_("starting server anyway\n"));
- do_start();
- return;
- }
- else if (pid < 0)
- {
- pid = -pid;
- if (postmaster_is_alive((pid_t) pid))
- {
- write_stderr(_("%s: cannot restart server; "
- "single-user server is running (PID: %ld)\n"),
- progname, pid);
- write_stderr(_("Please terminate the single-user server and try again.\n"));
- exit(1);
- }
- }
-
- if (postmaster_is_alive((pid_t) pid))
- {
- if (kill((pid_t) pid, sig) != 0)
- {
- write_stderr(_("%s: could not send stop signal (PID: %ld): %s\n"), progname, pid,
- strerror(errno));
- exit(1);
- }
-
-
-
-
-
-
-
- if (shutdown_mode == SMART_MODE &&
- stat(backup_file, &statbuf) == 0 &&
- stat(recovery_file, &statbuf) != 0)
- {
- print_msg(_("WARNING: online backup mode is active\n"
- "Shutdown will not complete until pg_stop_backup() is called.\n\n"));
- }
-
- print_msg(_("waiting for server to shut down..."));
-
-
-
- for (cnt = 0; cnt < wait_seconds; cnt++)
- {
- if ((pid = get_pgpid()) != 0)
- {
- print_msg(".");
- pg_usleep(1000000);
- }
- else
- break;
- }
-
- if (pid != 0)
- {
- print_msg(_(" failed\n"));
-
- write_stderr(_("%s: server does not shut down\n"), progname);
- exit(1);
- }
-
- print_msg(_(" done\n"));
- print_msg(_("server stopped\n"));
- }
- else
- {
- write_stderr(_("%s: old server process (PID: %ld) seems to be gone\n"),
- progname, pid);
- write_stderr(_("starting server anyway\n"));
- }
-
- do_start();
- }
-
-
- static void
- do_reload(void)
- {
- pgpid_t pid;
-
- pid = get_pgpid();
- if (pid == 0)
- {
- write_stderr(_("%s: PID file \"%s\" does not exist\n"), progname, pid_file);
- write_stderr(_("Is server running?\n"));
- exit(1);
- }
- else if (pid < 0)
- {
- pid = -pid;
- write_stderr(_("%s: cannot reload server; "
- "single-user server is running (PID: %ld)\n"),
- progname, pid);
- write_stderr(_("Please terminate the single-user server and try again.\n"));
- exit(1);
- }
-
- if (kill((pid_t) pid, sig) != 0)
- {
- write_stderr(_("%s: could not send reload signal (PID: %ld): %s\n"),
- progname, pid, strerror(errno));
- exit(1);
- }
-
- print_msg(_("server signaled\n"));
- }
-
-
-
-
-
- static bool
- postmaster_is_alive(pid_t pid)
- {
-
-
-
-
-
-
-
-
-
-
- if (pid == getpid())
- return false;
- #ifndef WIN32
- if (pid == getppid())
- return false;
- #endif
- if (kill(pid, 0) == 0)
- return true;
- return false;
- }
-
- static void
- do_status(void)
- {
- pgpid_t pid;
-
- pid = get_pgpid();
- if (pid != 0)
- {
- if (pid < 0)
- {
- pid = -pid;
- if (postmaster_is_alive((pid_t) pid))
- {
- printf(_("%s: single-user server is running (PID: %ld)\n"),
- progname, pid);
- return;
- }
- }
- else
-
- {
- if (postmaster_is_alive((pid_t) pid))
- {
- char **optlines;
-
- printf(_("%s: server is running (PID: %ld)\n"),
- progname, pid);
-
- optlines = readfile(postopts_file);
- if (optlines != NULL)
- for (; *optlines != NULL; optlines++)
- fputs(*optlines, stdout);
- return;
- }
- }
- }
- printf(_("%s: no server running\n"), progname);
- exit(1);
- }
-
-
-
- static void
- do_kill(pgpid_t pid)
- {
- if (kill((pid_t) pid, sig) != 0)
- {
- write_stderr(_("%s: could not send signal %d (PID: %ld): %s\n"),
- progname, sig, pid, strerror(errno));
- exit(1);
- }
- }
-
- #if defined(WIN32) || defined(__CYGWIN__)
-
- static bool
- pgwin32_IsInstalled(SC_HANDLE hSCM)
- {
- SC_HANDLE hService = OpenService(hSCM, register_servicename, SERVICE_QUERY_CONFIG);
- bool bResult = (hService != NULL);
-
- if (bResult)
- CloseServiceHandle(hService);
- return bResult;
- }
-
- static char *
- pgwin32_CommandLine(bool registration)
- {
- static char cmdLine[MAXPGPATH];
- int ret;
-
- #ifdef __CYGWIN__
- char buf[MAXPGPATH];
- #endif
-
- if (registration)
- {
- ret = find_my_exec(argv0, cmdLine);
- if (ret != 0)
- {
- write_stderr(_("%s: could not find own program executable\n"), progname);
- exit(1);
- }
- }
- else
- {
- ret = find_other_exec(argv0, "postgres", PG_BACKEND_VERSIONSTR,
- cmdLine);
- if (ret != 0)
- {
- write_stderr(_("%s: could not find postgres program executable\n"), progname);
- exit(1);
- }
- }
-
- #ifdef __CYGWIN__
-
- #if CYGWIN_VERSION_DLL_MAJOR >= 1007
- cygwin_conv_path(CCP_POSIX_TO_WIN_A, cmdLine, buf, sizeof(buf));
- #else
- cygwin_conv_to_full_win32_path(cmdLine, buf);
- #endif
- strcpy(cmdLine, buf);
- #endif
-
- if (registration)
- {
- if (pg_strcasecmp(cmdLine + strlen(cmdLine) - 4, ".exe"))
- {
-
- strcat(cmdLine, ".exe");
- }
- strcat(cmdLine, " runservice -N \"");
- strcat(cmdLine, register_servicename);
- strcat(cmdLine, "\"");
- }
-
- if (pg_data)
- {
- strcat(cmdLine, " -D \"");
- strcat(cmdLine, pg_data);
- strcat(cmdLine, "\"");
- }
-
- if (registration && do_wait)
- strcat(cmdLine, " -w");
-
- if (registration && wait_seconds != DEFAULT_WAIT)
-
- sprintf(cmdLine + strlen(cmdLine), " -t %d", wait_seconds);
-
- if (post_opts)
- {
- strcat(cmdLine, " ");
- if (registration)
- strcat(cmdLine, " -o \"");
- strcat(cmdLine, post_opts);
- if (registration)
- strcat(cmdLine, "\"");
- }
-
- return cmdLine;
- }
-
- static void
- pgwin32_doRegister(void)
- {
- SC_HANDLE hService;
- SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
-
- if (hSCM == NULL)
- {
- write_stderr(_("%s: could not open service manager\n"), progname);
- exit(1);
- }
- if (pgwin32_IsInstalled(hSCM))
- {
- CloseServiceHandle(hSCM);
- write_stderr(_("%s: service \"%s\" already registered\n"), progname, register_servicename);
- exit(1);
- }
-
- if ((hService = CreateService(hSCM, register_servicename, register_servicename,
- SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
- SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
- pgwin32_CommandLine(true),
- NULL, NULL, "RPCSS\0", register_username, register_password)) == NULL)
- {
- CloseServiceHandle(hSCM);
- write_stderr(_("%s: could not register service \"%s\": error code %d\n"), progname, register_servicename, (int) GetLastError());
- exit(1);
- }
- CloseServiceHandle(hService);
- CloseServiceHandle(hSCM);
- }
-
- static void
- pgwin32_doUnregister(void)
- {
- SC_HANDLE hService;
- SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
-
- if (hSCM == NULL)
- {
- write_stderr(_("%s: could not open service manager\n"), progname);
- exit(1);
- }
- if (!pgwin32_IsInstalled(hSCM))
- {
- CloseServiceHandle(hSCM);
- write_stderr(_("%s: service \"%s\" not registered\n"), progname, register_servicename);
- exit(1);
- }
-
- if ((hService = OpenService(hSCM, register_servicename, DELETE)) == NULL)
- {
- CloseServiceHandle(hSCM);
- write_stderr(_("%s: could not open service \"%s\": error code %d\n"), progname, register_servicename, (int) GetLastError());
- exit(1);
- }
- if (!DeleteService(hService))
- {
- CloseServiceHandle(hService);
- CloseServiceHandle(hSCM);
- write_stderr(_("%s: could not unregister service \"%s\": error code %d\n"), progname, register_servicename, (int) GetLastError());
- exit(1);
- }
- CloseServiceHandle(hService);
- CloseServiceHandle(hSCM);
- }
-
- static void
- pgwin32_SetServiceStatus(DWORD currentState)
- {
- status.dwCurrentState = currentState;
- SetServiceStatus(hStatus, (LPSERVICE_STATUS) &status);
- }
-
- static void WINAPI
- pgwin32_ServiceHandler(DWORD request)
- {
- switch (request)
- {
- case SERVICE_CONTROL_STOP:
- case SERVICE_CONTROL_SHUTDOWN:
-
-
-
-
-
-
- status.dwWaitHint = 10000;
- pgwin32_SetServiceStatus(SERVICE_STOP_PENDING);
- SetEvent(shutdownEvent);
- return;
-
- case SERVICE_CONTROL_PAUSE:
-
- status.dwWaitHint = 5000;
- kill(postmasterPID, SIGHUP);
- return;
-
-
- case SERVICE_CONTROL_CONTINUE:
- case SERVICE_CONTROL_INTERROGATE:
- default:
- break;
- }
- }
-
- static void WINAPI
- pgwin32_ServiceMain(DWORD argc, LPTSTR *argv)
- {
- PROCESS_INFORMATION pi;
- DWORD ret;
- DWORD check_point_start;
-
-
- status.dwWin32ExitCode = S_OK;
- status.dwCheckPoint = 0;
- status.dwWaitHint = 60000;
- status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
- status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_PAUSE_CONTINUE;
- status.dwServiceSpecificExitCode = 0;
- status.dwCurrentState = SERVICE_START_PENDING;
-
- memset(&pi, 0, sizeof(pi));
-
- read_post_opts();
-
-
- if ((hStatus = RegisterServiceCtrlHandler(register_servicename, pgwin32_ServiceHandler)) == (SERVICE_STATUS_HANDLE) 0)
- return;
-
- if ((shutdownEvent = CreateEvent(NULL, true, false, NULL)) == NULL)
- return;
-
-
- pgwin32_SetServiceStatus(SERVICE_START_PENDING);
- if (!CreateRestrictedProcess(pgwin32_CommandLine(false), &pi, true))
- {
- pgwin32_SetServiceStatus(SERVICE_STOPPED);
- return;
- }
- postmasterPID = pi.dwProcessId;
- postmasterProcess = pi.hProcess;
- CloseHandle(pi.hThread);
-
- if (do_wait)
- {
- write_eventlog(EVENTLOG_INFORMATION_TYPE, _("Waiting for server startup...\n"));
- if (test_postmaster_connection(true) == false)
- {
- write_eventlog(EVENTLOG_INFORMATION_TYPE, _("Timed out waiting for server startup\n"));
- pgwin32_SetServiceStatus(SERVICE_STOPPED);
- return;
- }
- write_eventlog(EVENTLOG_INFORMATION_TYPE, _("Server started and accepting connections\n"));
- }
-
-
-
-
-
- check_point_start = status.dwCheckPoint;
-
- pgwin32_SetServiceStatus(SERVICE_RUNNING);
-
-
- ret = WaitForMultipleObjects(2, shutdownHandles, FALSE, INFINITE);
-
- pgwin32_SetServiceStatus(SERVICE_STOP_PENDING);
- switch (ret)
- {
- case WAIT_OBJECT_0:
- kill(postmasterPID, SIGINT);
-
-
-
-
-
- while (WaitForSingleObject(postmasterProcess, 5000) == WAIT_TIMEOUT && status.dwCheckPoint < 12)
- status.dwCheckPoint++;
- break;
-
- case (WAIT_OBJECT_0 + 1):
- break;
-
- default:
-
- break;
- }
-
- CloseHandle(shutdownEvent);
- CloseHandle(postmasterProcess);
-
- pgwin32_SetServiceStatus(SERVICE_STOPPED);
- }
-
- static void
- pgwin32_doRunAsService(void)
- {
- SERVICE_TABLE_ENTRY st[] = {{register_servicename, pgwin32_ServiceMain},
- {NULL, NULL}};
-
- if (StartServiceCtrlDispatcher(st) == 0)
- {
- write_stderr(_("%s: could not start service \"%s\": error code %d\n"), progname, register_servicename, (int) GetLastError());
- exit(1);
- }
- }
-
-
-
-
-
-
-
-
- typedef BOOL (WINAPI * __CreateRestrictedToken) (HANDLE, DWORD, DWORD, PSID_AND_ATTRIBUTES, DWORD, PLUID_AND_ATTRIBUTES, DWORD, PSID_AND_ATTRIBUTES, PHANDLE);
- typedef BOOL (WINAPI * __IsProcessInJob) (HANDLE, HANDLE, PBOOL);
- typedef HANDLE (WINAPI * __CreateJobObject) (LPSECURITY_ATTRIBUTES, LPCTSTR);
- typedef BOOL (WINAPI * __SetInformationJobObject) (HANDLE, JOBOBJECTINFOCLASS, LPVOID, DWORD);
- typedef BOOL (WINAPI * __AssignProcessToJobObject) (HANDLE, HANDLE);
- typedef BOOL (WINAPI * __QueryInformationJobObject) (HANDLE, JOBOBJECTINFOCLASS, LPVOID, DWORD, LPDWORD);
-
-
- #define DISABLE_MAX_PRIVILEGE 0x1
-
-
-
-
-
-
-
-
-
-
-
-
-
- static int
- CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, bool as_service)
- {
- int r;
- BOOL b;
- STARTUPINFO si;
- HANDLE origToken;
- HANDLE restrictedToken;
- SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
- SID_AND_ATTRIBUTES dropSids[2];
-
-
- __CreateRestrictedToken _CreateRestrictedToken = NULL;
- __IsProcessInJob _IsProcessInJob = NULL;
- __CreateJobObject _CreateJobObject = NULL;
- __SetInformationJobObject _SetInformationJobObject = NULL;
- __AssignProcessToJobObject _AssignProcessToJobObject = NULL;
- __QueryInformationJobObject _QueryInformationJobObject = NULL;
- HANDLE Kernel32Handle;
- HANDLE Advapi32Handle;
-
- ZeroMemory(&si, sizeof(si));
- si.cb = sizeof(si);
-
- Advapi32Handle = LoadLibrary("ADVAPI32.DLL");
- if (Advapi32Handle != NULL)
- {
- _CreateRestrictedToken = (__CreateRestrictedToken) GetProcAddress(Advapi32Handle, "CreateRestrictedToken");
- }
-
- if (_CreateRestrictedToken == NULL)
- {
-
-
-
-
- write_stderr("WARNING: cannot create restricted tokens on this platform\n");
- if (Advapi32Handle != NULL)
- FreeLibrary(Advapi32Handle);
- return CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, processInfo);
- }
-
-
- if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &origToken))
- {
- write_stderr("Failed to open process token: %lu\n", GetLastError());
- return 0;
- }
-
-
- ZeroMemory(&dropSids, sizeof(dropSids));
- if (!AllocateAndInitializeSid(&NtAuthority, 2,
- SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,
- 0, &dropSids[0].Sid) ||
- !AllocateAndInitializeSid(&NtAuthority, 2,
- SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0,
- 0, &dropSids[1].Sid))
- {
- write_stderr("Failed to allocate SIDs: %lu\n", GetLastError());
- return 0;
- }
-
- b = _CreateRestrictedToken(origToken,
- DISABLE_MAX_PRIVILEGE,
- sizeof(dropSids) / sizeof(dropSids[0]),
- dropSids,
- 0, NULL,
- 0, NULL,
- &restrictedToken);
-
- FreeSid(dropSids[1].Sid);
- FreeSid(dropSids[0].Sid);
- CloseHandle(origToken);
- FreeLibrary(Advapi32Handle);
-
- if (!b)
- {
- write_stderr("Failed to create restricted token: %lu\n", GetLastError());
- return 0;
- }
-
- #ifndef __CYGWIN__
- AddUserToTokenDacl(restrictedToken);
- #endif
-
- r = CreateProcessASUSEr(restrictedToken, NULL, cmd, NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, NULL, &si, processInfo);
-
- Kernel32Handle = LoadLibrary("KERNEL32.DLL");
- if (Kernel32Handle != NULL)
- {
- _IsProcessInJob = (__IsProcessInJob) GetProcAddress(Kernel32Handle, "IsProcessInJob");
- _CreateJobObject = (__CreateJobObject) GetProcAddress(Kernel32Handle, "CreateJobObjectA");
- _SetInformationJobObject = (__SetInformationJobObject) GetProcAddress(Kernel32Handle, "SetInformationJobObject");
- _AssignProcessToJobObject = (__AssignProcessToJobObject) GetProcAddress(Kernel32Handle, "AssignProcessToJobObject");
- _QueryInformationJobObject = (__QueryInformationJobObject) GetProcAddress(Kernel32Handle, "QueryInformationJobObject");
- }
-
-
- if (_IsProcessInJob == NULL || _CreateJobObject == NULL || _SetInformationJobObject == NULL || _AssignProcessToJobObject == NULL || _QueryInformationJobObject == NULL)
- {
-
-
-
-
- OSVERSIONINFO osv;
-
- osv.dwOSVersionInfoSize = sizeof(osv);
- if (!GetVersionEx(&osv) ||
- (osv.dwMajorVersion == 5 && osv.dwMinorVersion > 0) ||
- osv.dwMajorVersion > 5)
-
-
-
-
-
- write_stderr("WARNING: could not locate all job object functions in system API\n");
- }
- else
- {
- BOOL inJob;
-
- if (_IsProcessInJob(processInfo->hProcess, NULL, &inJob))
- {
- if (!inJob)
- {
-
-
-
-
-
- HANDLE job;
- char jobname[128];
-
- sprintf(jobname, "PostgreSQL_%lu", processInfo->dwProcessId);
-
- job = _CreateJobObject(NULL, jobname);
- if (job)
- {
- JOBOBJECT_BASIC_LIMIT_INFORMATION basicLimit;
- JOBOBJECT_BASIC_UI_RESTRICTIONS uiRestrictions;
- JOBOBJECT_SECURITY_LIMIT_INFORMATION securityLimit;
- OSVERSIONINFO osv;
-
- ZeroMemory(&basicLimit, sizeof(basicLimit));
- ZeroMemory(&uiRestrictions, sizeof(uiRestrictions));
- ZeroMemory(&securityLimit, sizeof(securityLimit));
-
- basicLimit.LimitFlags = JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION | JOB_OBJECT_LIMIT_PRIORITY_CLASS;
- basicLimit.PriorityClass = NORMAL_PRIORITY_CLASS;
- _SetInformationJobObject(job, JobObjectBasicLimitInformation, &basicLimit, sizeof(basicLimit));
-
- uiRestrictions.UIRestrictionsClass = JOB_OBJECT_UILIMIT_DESKTOP | JOB_OBJECT_UILIMIT_DISPLAYSETTINGS |
- JOB_OBJECT_UILIMIT_EXITWINDOWS | JOB_OBJECT_UILIMIT_READCLIPBOARD |
- JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS | JOB_OBJECT_UILIMIT_WRITECLIPBOARD;
-
- if (as_service)
- {
- osv.dwOSVersionInfoSize = sizeof(osv);
- if (!GetVersionEx(&osv) ||
- osv.dwMajorVersion < 6 ||
- (osv.dwMajorVersion == 6 && osv.dwMinorVersion == 0))
- {
-
-
-
-
-
-
- uiRestrictions.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_HANDLES;
- }
- }
- _SetInformationJobObject(job, JobObjectBasicUIRestrictions, &uiRestrictions, sizeof(uiRestrictions));
-
- securityLimit.SecurityLimitFlags = JOB_OBJECT_SECURITY_NO_ADMIN | JOB_OBJECT_SECURITY_ONLY_TOKEN;
- securityLimit.JobToken = restrictedToken;
- _SetInformationJobObject(job, JobObjectSecurityLimitInformation, &securityLimit, sizeof(securityLimit));
-
- _AssignProcessToJobObject(job, processInfo->hProcess);
- }
- }
- }
- }
-
-
- CloseHandle(restrictedToken);
-
- ResumeThread(processInfo->hThread);
-
- FreeLibrary(Kernel32Handle);
-
-
-
-
-
- return r;
- }
- #endif
-
- static void
- do_advice(void)
- {
- write_stderr(_("Try \"%s --help\" for more information.\n"), progname);
- }
-
-
-
- static void
- do_help(void)
- {
- printf(_("%s is a utility to start, stop, restart, reload configuration files,\n"
- "report the status of a PostgreSQL server, or signal a PostgreSQL process.\n\n"), progname);
- printf(_("Usage:\n"));
- printf(_(" %s init[db] [-D DATADIR] [-s] [-o \"OPTIONS\"]\n"), progname);
- printf(_(" %s start [-w] [-t SECS] [-D DATADIR] [-s] [-l FILENAME] [-o \"OPTIONS\"]\n"), progname);
- printf(_(" %s stop [-W] [-t SECS] [-D DATADIR] [-s] [-m SHUTDOWN-MODE]\n"), progname);
- printf(_(" %s restart [-w] [-t SECS] [-D DATADIR] [-s] [-m SHUTDOWN-MODE]\n"
- " [-o \"OPTIONS\"]\n"), progname);
- printf(_(" %s reload [-D DATADIR] [-s]\n"), progname);
- printf(_(" %s status [-D DATADIR]\n"), progname);
- printf(_(" %s kill SIGNALNAME PID\n"), progname);
- #if defined(WIN32) || defined(__CYGWIN__)
- printf(_(" %s register [-N SERVICENAME] [-U USERNAME] [-P PASSWORD] [-D DATADIR]\n"
- " [-w] [-t SECS] [-o \"OPTIONS\"]\n"), progname);
- printf(_(" %s unregister [-N SERVICENAME]\n"), progname);
- #endif
-
- printf(_("\nCommon options:\n"));
- printf(_(" -D, --pgdata DATADIR location of the database storage area\n"));
- printf(_(" -s, --silent only print errors, no informational messages\n"));
- printf(_(" -t SECS seconds to wait when using -w option\n"));
- printf(_(" -w wait until operation completes\n"));
- printf(_(" -W do not wait until operation completes\n"));
- printf(_(" --help show this help, then exit\n"));
- printf(_(" --version output version information, then exit\n"));
- printf(_("(The default is to wait for shutdown, but not for start or restart.)\n\n"));
- printf(_("If the -D option is omitted, the environment variable PGDATA is used.\n"));
-
- printf(_("\nOptions for start or restart:\n"));
- #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
- printf(_(" -c, --core-files allow postgres to produce core files\n"));
- #else
- printf(_(" -c, --core-files not applicable on this platform\n"));
- #endif
- printf(_(" -l, --log FILENAME write (or append) server log to FILENAME\n"));
- printf(_(" -o OPTIONS command line options to pass to postgres\n"
- " (PostgreSQL server executable) or initdb\n"));
- printf(_(" -p PATH-TO-POSTGRES normally not necessary\n"));
- printf(_("\nOptions for stop or restart:\n"));
- printf(_(" -m SHUTDOWN-MODE can be \"smart\", \"fast\", or \"immediate\"\n"));
-
- printf(_("\nShutdown modes are:\n"));
- printf(_(" smart quit after all clients have disconnected\n"));
- printf(_(" fast quit directly, with proper shutdown\n"));
- printf(_(" immediate quit without complete shutdown; will lead to recovery on restart\n"));
-
- printf(_("\nAllowed signal names for kill:\n"));
- printf(" HUP INT QUIT ABRT TERM USR1 USR2\n");
-
- #if defined(WIN32) || defined(__CYGWIN__)
- printf(_("\nOptions for register and unregister:\n"));
- printf(_(" -N SERVICENAME service name with which to register PostgreSQL server\n"));
- printf(_(" -P PASSWORD password of account to register PostgreSQL server\n"));
- printf(_(" -U USERNAME user name of account to register PostgreSQL server\n"));
- #endif
-
- printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
- }
-
-
-
- static void
- set_mode(char *modeopt)
- {
- if (strcmp(modeopt, "s") == 0 || strcmp(modeopt, "smart") == 0)
- {
- shutdown_mode = SMART_MODE;
- sig = SIGTERM;
- }
- else if (strcmp(modeopt, "f") == 0 || strcmp(modeopt, "fast") == 0)
- {
- shutdown_mode = FAST_MODE;
- sig = SIGINT;
- }
- else if (strcmp(modeopt, "i") == 0 || strcmp(modeopt, "immediate") == 0)
- {
- shutdown_mode = IMMEDIATE_MODE;
- sig = SIGQUIT;
- }
- else
- {
- write_stderr(_("%s: unrecognized shutdown mode \"%s\"\n"), progname, modeopt);
- do_advice();
- exit(1);
- }
- }
-
-
-
- static void
- set_sig(char *signame)
- {
- if (!strcmp(signame, "HUP"))
- sig = SIGHUP;
- else if (!strcmp(signame, "INT"))
- sig = SIGINT;
- else if (!strcmp(signame, "QUIT"))
- sig = SIGQUIT;
- else if (!strcmp(signame, "ABRT"))
- sig = SIGABRT;
-
-
-
-
-
-
- else if (!strcmp(signame, "TERM"))
- sig = SIGTERM;
- else if (!strcmp(signame, "USR1"))
- sig = SIGUSR1;
- else if (!strcmp(signame, "USR2"))
- sig = SIGUSR2;
- else
- {
- write_stderr(_("%s: unrecognized signal name \"%s\"\n"), progname, signame);
- do_advice();
- exit(1);
- }
-
- }
评论暂时关闭