📄 pg_ctl.c
字号:
/*------------------------------------------------------------------------- * * pg_ctl --- start/stops/restarts the PostgreSQL server * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * * $PostgreSQL: pgsql/src/bin/pg_ctl/pg_ctl.c,v 1.61.2.2 2006/01/14 16:16:08 petere Exp $ * *------------------------------------------------------------------------- */#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>#include "libpq/pqsignal.h"#include "getopt_long.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#ifndef HAVE_INT_OPTRESETint optreset;#endif/* PID can be negative for standalone backend */typedef long pgpid_t;#define WHITESPACE "\f\n\r\t\v" /* as defined by isspace() *//* postmaster version ident string */#define PM_VERSIONSTR "postmaster (PostgreSQL) " PG_VERSION "\n"typedef enum{ SMART_MODE, FAST_MODE, IMMEDIATE_MODE} ShutdownMode;typedef enum{ NO_COMMAND = 0, START_COMMAND, STOP_COMMAND, RESTART_COMMAND, RELOAD_COMMAND, STATUS_COMMAND, KILL_COMMAND, REGISTER_COMMAND, UNREGISTER_COMMAND, RUN_AS_SERVICE_COMMAND} CtlCommand;static bool do_wait = false;static bool wait_set = false;static int wait_seconds = 60;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 *postgres_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 voidwrite_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_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);#endifstatic pgpid_t get_pgpid(void);static char **readfile(const char *path);static int start_postmaster(void);static bool test_postmaster_connection(void);static bool postmaster_is_alive(pid_t pid);static char def_postopts_file[MAXPGPATH];static char postopts_file[MAXPGPATH];static char pid_file[MAXPGPATH];static char conf_file[MAXPGPATH];#if defined(WIN32) || defined(__CYGWIN__)static voidwrite_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 voidwrite_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\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;}/* * Given an already-localized string, print it to stdout unless the * user has specified that no messages should be printed. */static voidprint_msg(const char *msg){ if (!silent_mode) { fputs(msg, stdout); fflush(stdout); }}static pgpid_tget_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\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;}/* * 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 = 0, 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 == '\n') { 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); result[nlines] = NULL; return result;}/* * start/test/stop routines */static intstart_postmaster(void){ /* * Since there might be quotes to handle here, it is easier simply to pass * everything to a shell to process them. */ char cmd[MAXPGPATH]; /* * Win32 needs START /B rather than "&". * * Win32 has a problem with START and quoted executable names. You must * add a "" as the title at the beginning so you can quote the executable * name: http://www.winnetmag.com/Article/ArticleID/14589/14589.html * http://dev.remotenetworktechnology.com/cmd/cmdfaq.htm */ if (log_file != NULL)#ifndef WIN32 /* Cygwin doesn't have START */ snprintf(cmd, MAXPGPATH, "%s\"%s\" %s%s < \"%s\" >> \"%s\" 2>&1 &%s", SYSTEMQUOTE, postgres_path, pgdata_opt, post_opts, DEVNULL, log_file, SYSTEMQUOTE);#else snprintf(cmd, MAXPGPATH, "%sSTART /B \"\" \"%s\" %s%s < \"%s\" >> \"%s\" 2>&1%s", SYSTEMQUOTE, postgres_path, pgdata_opt, post_opts, DEVNULL, log_file, SYSTEMQUOTE);#endif else#ifndef WIN32 /* Cygwin doesn't have START */ snprintf(cmd, MAXPGPATH, "%s\"%s\" %s%s < \"%s\" 2>&1 &%s", SYSTEMQUOTE, postgres_path, pgdata_opt, post_opts, DEVNULL, SYSTEMQUOTE);#else snprintf(cmd, MAXPGPATH, "%sSTART /B \"\" \"%s\" %s%s < \"%s\" 2>&1%s", SYSTEMQUOTE, postgres_path, pgdata_opt, post_opts, DEVNULL, SYSTEMQUOTE);#endif return system(cmd);}/* Find the pgport and try a connection */static booltest_postmaster_connection(void){ PGconn *conn; bool success = false; int i; char portstr[32]; char *p; *portstr = '\0'; /* post_opts */ for (p = post_opts; *p;) { /* advance past whitespace/quoting */ while (isspace((unsigned char) *p) || *p == '\'' || *p == '"') p++; if (strncmp(p, "-p", strlen("-p")) == 0) { p += strlen("-p"); /* advance past whitespace/quoting */ while (isspace((unsigned char) *p) || *p == '\'' || *p == '"') p++; StrNCpy(portstr, p, Min(strcspn(p, "\"'" WHITESPACE) + 1, sizeof(portstr))); /* keep looking, maybe there is another -p */ } /* Advance to next whitespace */ while (*p && !isspace((unsigned char) *p)) p++; } /* config file */ 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", strlen("port")) != 0) continue; p += strlen("port"); while (isspace((unsigned char) *p)) p++; if (*p != '=') continue; p++; while (isspace((unsigned char) *p)) p++; StrNCpy(portstr, p, Min(strcspn(p, "#" WHITESPACE) + 1, sizeof(portstr))); /* keep looking, maybe there is another */ } } } /* environment */ if (!*portstr && getenv("PGPORT") != NULL) StrNCpy(portstr, getenv("PGPORT"), sizeof(portstr)); /* default */ if (!*portstr) snprintf(portstr, sizeof(portstr), "%d", DEF_PGPORT); for (i = 0; i < wait_seconds; i++) { if ((conn = PQsetdbLogin(NULL, portstr, NULL, NULL, "postgres", NULL, NULL)) != NULL && (PQstatus(conn) == CONNECTION_OK || (strcmp(PQerrorMessage(conn), PQnoPasswordSupplied) == 0))) { PQfinish(conn); success = true; break; } else { print_msg("."); pg_usleep(1000000); /* 1 sec */ } } return success;}static voiddo_start(void){ pgpid_t pid; pgpid_t old_pid = 0; char *optline = NULL; int exitcode; if (ctl_command != RESTART_COMMAND) { old_pid = get_pgpid(); if (old_pid != 0) write_stderr(_("%s: another postmaster may be running; " "trying to start postmaster anyway\n"), progname); } if (post_opts == NULL) { char **optlines; int len; optlines = readfile(ctl_command == RESTART_COMMAND ? postopts_file : def_postopts_file); if (optlines == NULL) { if (ctl_command == START_COMMAND) post_opts = ""; else { 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, ctl_command == RESTART_COMMAND ? postopts_file : def_postopts_file); exit(1); } else { optline = optlines[0]; len = strcspn(optline, "\r\n"); optline[len] = '\0'; if (ctl_command == RESTART_COMMAND) { char *arg1; arg1 = strchr(optline, *SYSTEMQUOTE); if (arg1 == NULL || arg1 == optline) post_opts = ""; else { *(arg1 - 1) = '\0'; /* this should be a space */ post_opts = arg1; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -