00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #ifdef WIN32
00013
00014
00015
00016
00017 #define _WIN32_WINNT 0x0501
00018 #endif
00019
00020 #include "postgres_fe.h"
00021 #include "libpq-fe.h"
00022
00023 #include <fcntl.h>
00024 #include <locale.h>
00025 #include <signal.h>
00026 #include <time.h>
00027 #include <sys/types.h>
00028 #include <sys/stat.h>
00029 #include <unistd.h>
00030
00031 #ifdef HAVE_SYS_RESOURCE_H
00032 #include <sys/time.h>
00033 #include <sys/resource.h>
00034 #endif
00035
00036 #include "getopt_long.h"
00037 #include "miscadmin.h"
00038
00039 #if defined(__CYGWIN__)
00040 #include <sys/cygwin.h>
00041 #include <windows.h>
00042
00043 #undef WIN32
00044 #endif
00045
00046
00047 typedef long pgpid_t;
00048
00049
00050 typedef enum
00051 {
00052 SMART_MODE,
00053 FAST_MODE,
00054 IMMEDIATE_MODE
00055 } ShutdownMode;
00056
00057
00058 typedef enum
00059 {
00060 NO_COMMAND = 0,
00061 INIT_COMMAND,
00062 START_COMMAND,
00063 STOP_COMMAND,
00064 RESTART_COMMAND,
00065 RELOAD_COMMAND,
00066 STATUS_COMMAND,
00067 PROMOTE_COMMAND,
00068 KILL_COMMAND,
00069 REGISTER_COMMAND,
00070 UNREGISTER_COMMAND,
00071 RUN_AS_SERVICE_COMMAND
00072 } CtlCommand;
00073
00074 #define DEFAULT_WAIT 60
00075
00076 static bool do_wait = false;
00077 static bool wait_set = false;
00078 static int wait_seconds = DEFAULT_WAIT;
00079 static bool silent_mode = false;
00080 static ShutdownMode shutdown_mode = SMART_MODE;
00081 static int sig = SIGTERM;
00082 static CtlCommand ctl_command = NO_COMMAND;
00083 static char *pg_data = NULL;
00084 static char *pg_config = NULL;
00085 static char *pgdata_opt = NULL;
00086 static char *post_opts = NULL;
00087 static const char *progname;
00088 static char *log_file = NULL;
00089 static char *exec_path = NULL;
00090 static char *register_servicename = "PostgreSQL";
00091 static char *register_username = NULL;
00092 static char *register_password = NULL;
00093 static char *argv0 = NULL;
00094 static bool allow_core_files = false;
00095 static time_t start_time;
00096
00097 static char postopts_file[MAXPGPATH];
00098 static char pid_file[MAXPGPATH];
00099 static char backup_file[MAXPGPATH];
00100 static char recovery_file[MAXPGPATH];
00101 static char promote_file[MAXPGPATH];
00102
00103 #if defined(WIN32) || defined(__CYGWIN__)
00104 static DWORD pgctl_start_type = SERVICE_AUTO_START;
00105 static SERVICE_STATUS status;
00106 static SERVICE_STATUS_HANDLE hStatus = (SERVICE_STATUS_HANDLE) 0;
00107 static HANDLE shutdownHandles[2];
00108 static pid_t postmasterPID = -1;
00109
00110 #define shutdownEvent shutdownHandles[0]
00111 #define postmasterProcess shutdownHandles[1]
00112 #endif
00113
00114
00115 static void
00116 write_stderr(const char *fmt,...)
00117
00118
00119 __attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
00120 static void do_advice(void);
00121 static void do_help(void);
00122 static void set_mode(char *modeopt);
00123 static void set_sig(char *signame);
00124 static void do_init(void);
00125 static void do_start(void);
00126 static void do_stop(void);
00127 static void do_restart(void);
00128 static void do_reload(void);
00129 static void do_status(void);
00130 static void do_promote(void);
00131 static void do_kill(pgpid_t pid);
00132 static void print_msg(const char *msg);
00133 static void adjust_data_dir(void);
00134
00135 #if defined(WIN32) || defined(__CYGWIN__)
00136 static bool pgwin32_IsInstalled(SC_HANDLE);
00137 static char *pgwin32_CommandLine(bool);
00138 static void pgwin32_doRegister(void);
00139 static void pgwin32_doUnregister(void);
00140 static void pgwin32_SetServiceStatus(DWORD);
00141 static void WINAPI pgwin32_ServiceHandler(DWORD);
00142 static void WINAPI pgwin32_ServiceMain(DWORD, LPTSTR *);
00143 static void pgwin32_doRunAsService(void);
00144 static int CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, bool as_service);
00145 #endif
00146
00147 static pgpid_t get_pgpid(void);
00148 static char **readfile(const char *path);
00149 static int start_postmaster(void);
00150 static void read_post_opts(void);
00151
00152 static PGPing test_postmaster_connection(bool);
00153 static bool postmaster_is_alive(pid_t pid);
00154
00155 #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
00156 static void unlimit_core_size(void);
00157 #endif
00158
00159
00160 #if defined(WIN32) || defined(__CYGWIN__)
00161 static void
00162 write_eventlog(int level, const char *line)
00163 {
00164 static HANDLE evtHandle = INVALID_HANDLE_VALUE;
00165
00166 if (silent_mode && level == EVENTLOG_INFORMATION_TYPE)
00167 return;
00168
00169 if (evtHandle == INVALID_HANDLE_VALUE)
00170 {
00171 evtHandle = RegisterEventSource(NULL, "PostgreSQL");
00172 if (evtHandle == NULL)
00173 {
00174 evtHandle = INVALID_HANDLE_VALUE;
00175 return;
00176 }
00177 }
00178
00179 ReportEvent(evtHandle,
00180 level,
00181 0,
00182 0,
00183 NULL,
00184 1,
00185 0,
00186 &line,
00187 NULL);
00188 }
00189 #endif
00190
00191
00192
00193
00194
00195 static void
00196 write_stderr(const char *fmt,...)
00197 {
00198 va_list ap;
00199
00200 va_start(ap, fmt);
00201 #if !defined(WIN32) && !defined(__CYGWIN__)
00202
00203 vfprintf(stderr, fmt, ap);
00204 #else
00205
00206
00207
00208
00209
00210 if (!isatty(fileno(stderr)))
00211 {
00212 char errbuf[2048];
00213
00214 vsnprintf(errbuf, sizeof(errbuf), fmt, ap);
00215
00216 write_eventlog(EVENTLOG_ERROR_TYPE, errbuf);
00217 }
00218 else
00219
00220 vfprintf(stderr, fmt, ap);
00221 #endif
00222 va_end(ap);
00223 }
00224
00225
00226
00227
00228
00229 static void
00230 print_msg(const char *msg)
00231 {
00232 if (!silent_mode)
00233 {
00234 fputs(msg, stdout);
00235 fflush(stdout);
00236 }
00237 }
00238
00239 static pgpid_t
00240 get_pgpid(void)
00241 {
00242 FILE *pidf;
00243 long pid;
00244
00245 pidf = fopen(pid_file, "r");
00246 if (pidf == NULL)
00247 {
00248
00249 if (errno == ENOENT)
00250 return 0;
00251 else
00252 {
00253 write_stderr(_("%s: could not open PID file \"%s\": %s\n"),
00254 progname, pid_file, strerror(errno));
00255 exit(1);
00256 }
00257 }
00258 if (fscanf(pidf, "%ld", &pid) != 1)
00259 {
00260
00261 if (ftell(pidf) == 0 && feof(pidf))
00262 write_stderr(_("%s: the PID file \"%s\" is empty\n"),
00263 progname, pid_file);
00264 else
00265 write_stderr(_("%s: invalid data in PID file \"%s\"\n"),
00266 progname, pid_file);
00267 exit(1);
00268 }
00269 fclose(pidf);
00270 return (pgpid_t) pid;
00271 }
00272
00273
00274
00275
00276
00277 static char **
00278 readfile(const char *path)
00279 {
00280 int fd;
00281 int nlines;
00282 char **result;
00283 char *buffer;
00284 char *linebegin;
00285 int i;
00286 int n;
00287 int len;
00288 struct stat statbuf;
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298 fd = open(path, O_RDONLY | PG_BINARY, 0);
00299 if (fd < 0)
00300 return NULL;
00301 if (fstat(fd, &statbuf) < 0)
00302 {
00303 close(fd);
00304 return NULL;
00305 }
00306 if (statbuf.st_size == 0)
00307 {
00308
00309 close(fd);
00310 result = (char **) pg_malloc(sizeof(char *));
00311 *result = NULL;
00312 return result;
00313 }
00314 buffer = pg_malloc(statbuf.st_size + 1);
00315
00316 len = read(fd, buffer, statbuf.st_size + 1);
00317 close(fd);
00318 if (len != statbuf.st_size)
00319 {
00320
00321 free(buffer);
00322 return NULL;
00323 }
00324
00325
00326
00327
00328
00329
00330 nlines = 0;
00331 for (i = 0; i < len; i++)
00332 {
00333 if (buffer[i] == '\n')
00334 nlines++;
00335 }
00336
00337
00338 result = (char **) pg_malloc((nlines + 1) * sizeof(char *));
00339
00340
00341 linebegin = buffer;
00342 n = 0;
00343 for (i = 0; i < len; i++)
00344 {
00345 if (buffer[i] == '\n')
00346 {
00347 int slen = &buffer[i] - linebegin + 1;
00348 char *linebuf = pg_malloc(slen + 1);
00349 memcpy(linebuf, linebegin, slen);
00350 linebuf[slen] = '\0';
00351 result[n++] = linebuf;
00352 linebegin = &buffer[i + 1];
00353 }
00354 }
00355 result[n] = NULL;
00356
00357 free(buffer);
00358
00359 return result;
00360 }
00361
00362
00363
00364
00365
00366
00367
00368 static int
00369 start_postmaster(void)
00370 {
00371 char cmd[MAXPGPATH];
00372
00373 #ifndef WIN32
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383 if (log_file != NULL)
00384 snprintf(cmd, MAXPGPATH, SYSTEMQUOTE "\"%s\" %s%s < \"%s\" >> \"%s\" 2>&1 &" SYSTEMQUOTE,
00385 exec_path, pgdata_opt, post_opts,
00386 DEVNULL, log_file);
00387 else
00388 snprintf(cmd, MAXPGPATH, SYSTEMQUOTE "\"%s\" %s%s < \"%s\" 2>&1 &" SYSTEMQUOTE,
00389 exec_path, pgdata_opt, post_opts, DEVNULL);
00390
00391 return system(cmd);
00392 #else
00393
00394
00395
00396
00397
00398
00399 PROCESS_INFORMATION pi;
00400
00401 if (log_file != NULL)
00402 snprintf(cmd, MAXPGPATH, "CMD /C " SYSTEMQUOTE "\"%s\" %s%s < \"%s\" >> \"%s\" 2>&1" SYSTEMQUOTE,
00403 exec_path, pgdata_opt, post_opts, DEVNULL, log_file);
00404 else
00405 snprintf(cmd, MAXPGPATH, "CMD /C " SYSTEMQUOTE "\"%s\" %s%s < \"%s\" 2>&1" SYSTEMQUOTE,
00406 exec_path, pgdata_opt, post_opts, DEVNULL);
00407
00408 if (!CreateRestrictedProcess(cmd, &pi, false))
00409 return GetLastError();
00410 CloseHandle(pi.hProcess);
00411 CloseHandle(pi.hThread);
00412 return 0;
00413 #endif
00414 }
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424 static PGPing
00425 test_postmaster_connection(bool do_checkpoint)
00426 {
00427 PGPing ret = PQPING_NO_RESPONSE;
00428 bool found_stale_pidfile = false;
00429 pgpid_t pm_pid = 0;
00430 char connstr[MAXPGPATH * 2 + 256];
00431 int i;
00432
00433
00434 if (wait_seconds <= 0)
00435 return PQPING_REJECT;
00436
00437 connstr[0] = '\0';
00438
00439 for (i = 0; i < wait_seconds; i++)
00440 {
00441
00442 if (connstr[0] == '\0')
00443 {
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465 char **optlines;
00466
00467
00468 if ((optlines = readfile(pid_file)) != NULL &&
00469 optlines[0] != NULL &&
00470 optlines[1] != NULL &&
00471 optlines[2] != NULL)
00472 {
00473 if (optlines[3] == NULL)
00474 {
00475
00476 write_stderr(_("\n%s: -w option is not supported when starting a pre-9.1 server\n"),
00477 progname);
00478 return PQPING_NO_ATTEMPT;
00479 }
00480 else if (optlines[4] != NULL &&
00481 optlines[5] != NULL)
00482 {
00483
00484 long pmpid;
00485 time_t pmstart;
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496 pmpid = atol(optlines[LOCK_FILE_LINE_PID - 1]);
00497 pmstart = atol(optlines[LOCK_FILE_LINE_START_TIME - 1]);
00498 if (pmpid <= 0 || pmstart < start_time - 2)
00499 {
00500
00501
00502
00503
00504 found_stale_pidfile = true;
00505 }
00506 else
00507 {
00508
00509
00510
00511 int portnum;
00512 char *sockdir;
00513 char *hostaddr;
00514 char host_str[MAXPGPATH];
00515
00516 found_stale_pidfile = false;
00517 pm_pid = (pgpid_t) pmpid;
00518
00519
00520
00521
00522
00523 portnum = atoi(optlines[LOCK_FILE_LINE_PORT - 1]);
00524 sockdir = optlines[LOCK_FILE_LINE_SOCKET_DIR - 1];
00525 hostaddr = optlines[LOCK_FILE_LINE_LISTEN_ADDR - 1];
00526
00527
00528
00529
00530
00531
00532
00533
00534 if (sockdir[0] == '/')
00535 strlcpy(host_str, sockdir, sizeof(host_str));
00536 else
00537 strlcpy(host_str, hostaddr, sizeof(host_str));
00538
00539
00540 if (strchr(host_str, '\n') != NULL)
00541 *strchr(host_str, '\n') = '\0';
00542
00543
00544 if (host_str[0] == '\0')
00545 {
00546 write_stderr(_("\n%s: -w option cannot use a relative socket directory specification\n"),
00547 progname);
00548 return PQPING_NO_ATTEMPT;
00549 }
00550
00551
00552 if (strcmp(host_str, "*") == 0)
00553 strcpy(host_str, "localhost");
00554
00555
00556
00557
00558
00559
00560 snprintf(connstr, sizeof(connstr),
00561 "dbname=postgres port=%d host='%s' connect_timeout=5",
00562 portnum, host_str);
00563 }
00564 }
00565 }
00566 }
00567
00568
00569 if (connstr[0] != '\0')
00570 {
00571 ret = PQping(connstr);
00572 if (ret == PQPING_OK || ret == PQPING_NO_ATTEMPT)
00573 break;
00574 }
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585 if (i >= 5)
00586 {
00587 struct stat statbuf;
00588
00589 if (stat(pid_file, &statbuf) != 0)
00590 return PQPING_NO_RESPONSE;
00591
00592 if (found_stale_pidfile)
00593 {
00594 write_stderr(_("\n%s: this data directory appears to be running a pre-existing postmaster\n"),
00595 progname);
00596 return PQPING_NO_RESPONSE;
00597 }
00598 }
00599
00600
00601
00602
00603
00604
00605
00606 if (pm_pid > 0 && !postmaster_is_alive((pid_t) pm_pid))
00607 return PQPING_NO_RESPONSE;
00608
00609
00610 #if defined(WIN32)
00611 if (do_checkpoint)
00612 {
00613
00614
00615
00616
00617
00618
00619 status.dwWaitHint += 6000;
00620 status.dwCheckPoint++;
00621 SetServiceStatus(hStatus, (LPSERVICE_STATUS) &status);
00622 }
00623 else
00624 #endif
00625 print_msg(".");
00626
00627 pg_usleep(1000000);
00628 }
00629
00630
00631 return ret;
00632 }
00633
00634
00635 #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
00636 static void
00637 unlimit_core_size(void)
00638 {
00639 struct rlimit lim;
00640
00641 getrlimit(RLIMIT_CORE, &lim);
00642 if (lim.rlim_max == 0)
00643 {
00644 write_stderr(_("%s: cannot set core file size limit; disallowed by hard limit\n"),
00645 progname);
00646 return;
00647 }
00648 else if (lim.rlim_max == RLIM_INFINITY || lim.rlim_cur < lim.rlim_max)
00649 {
00650 lim.rlim_cur = lim.rlim_max;
00651 setrlimit(RLIMIT_CORE, &lim);
00652 }
00653 }
00654 #endif
00655
00656 static void
00657 read_post_opts(void)
00658 {
00659 if (post_opts == NULL)
00660 {
00661 post_opts = "";
00662 if (ctl_command == RESTART_COMMAND)
00663 {
00664 char **optlines;
00665
00666 optlines = readfile(postopts_file);
00667 if (optlines == NULL)
00668 {
00669 write_stderr(_("%s: could not read file \"%s\"\n"), progname, postopts_file);
00670 exit(1);
00671 }
00672 else if (optlines[0] == NULL || optlines[1] != NULL)
00673 {
00674 write_stderr(_("%s: option file \"%s\" must have exactly one line\n"),
00675 progname, postopts_file);
00676 exit(1);
00677 }
00678 else
00679 {
00680 int len;
00681 char *optline;
00682 char *arg1;
00683
00684 optline = optlines[0];
00685
00686 len = strcspn(optline, "\r\n");
00687 optline[len] = '\0';
00688
00689
00690
00691
00692
00693 if ((arg1 = strstr(optline, " \"")) != NULL)
00694 {
00695 *arg1 = '\0';
00696
00697 post_opts = arg1 + 1;
00698 }
00699 if (exec_path == NULL)
00700 exec_path = optline;
00701 }
00702 }
00703 }
00704 }
00705
00706 static char *
00707 find_other_exec_or_die(const char *argv0, const char *target, const char *versionstr)
00708 {
00709 int ret;
00710 char *found_path;
00711
00712 found_path = pg_malloc(MAXPGPATH);
00713
00714 if ((ret = find_other_exec(argv0, target, versionstr, found_path)) < 0)
00715 {
00716 char full_path[MAXPGPATH];
00717
00718 if (find_my_exec(argv0, full_path) < 0)
00719 strlcpy(full_path, progname, sizeof(full_path));
00720
00721 if (ret == -1)
00722 write_stderr(_("The program \"%s\" is needed by %s "
00723 "but was not found in the\n"
00724 "same directory as \"%s\".\n"
00725 "Check your installation.\n"),
00726 target, progname, full_path);
00727 else
00728 write_stderr(_("The program \"%s\" was found by \"%s\"\n"
00729 "but was not the same version as %s.\n"
00730 "Check your installation.\n"),
00731 target, full_path, progname);
00732 exit(1);
00733 }
00734
00735 return found_path;
00736 }
00737
00738 static void
00739 do_init(void)
00740 {
00741 char cmd[MAXPGPATH];
00742
00743 if (exec_path == NULL)
00744 exec_path = find_other_exec_or_die(argv0, "initdb", "initdb (PostgreSQL) " PG_VERSION "\n");
00745
00746 if (pgdata_opt == NULL)
00747 pgdata_opt = "";
00748
00749 if (post_opts == NULL)
00750 post_opts = "";
00751
00752 if (!silent_mode)
00753 snprintf(cmd, MAXPGPATH, SYSTEMQUOTE "\"%s\" %s%s" SYSTEMQUOTE,
00754 exec_path, pgdata_opt, post_opts);
00755 else
00756 snprintf(cmd, MAXPGPATH, SYSTEMQUOTE "\"%s\" %s%s > \"%s\"" SYSTEMQUOTE,
00757 exec_path, pgdata_opt, post_opts, DEVNULL);
00758
00759 if (system(cmd) != 0)
00760 {
00761 write_stderr(_("%s: database system initialization failed\n"), progname);
00762 exit(1);
00763 }
00764 }
00765
00766 static void
00767 do_start(void)
00768 {
00769 pgpid_t old_pid = 0;
00770 int exitcode;
00771
00772 if (ctl_command != RESTART_COMMAND)
00773 {
00774 old_pid = get_pgpid();
00775 if (old_pid != 0)
00776 write_stderr(_("%s: another server might be running; "
00777 "trying to start server anyway\n"),
00778 progname);
00779 }
00780
00781 read_post_opts();
00782
00783
00784 if (ctl_command == RESTART_COMMAND || pgdata_opt == NULL)
00785 pgdata_opt = "";
00786
00787 if (exec_path == NULL)
00788 exec_path = find_other_exec_or_die(argv0, "postgres", PG_BACKEND_VERSIONSTR);
00789
00790 #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
00791 if (allow_core_files)
00792 unlimit_core_size();
00793 #endif
00794
00795
00796
00797
00798
00799
00800 #ifndef WIN32
00801 {
00802 static char env_var[32];
00803
00804 snprintf(env_var, sizeof(env_var), "PG_GRANDPARENT_PID=%d",
00805 (int) getppid());
00806 putenv(env_var);
00807 }
00808 #endif
00809
00810 exitcode = start_postmaster();
00811 if (exitcode != 0)
00812 {
00813 write_stderr(_("%s: could not start server: exit code was %d\n"),
00814 progname, exitcode);
00815 exit(1);
00816 }
00817
00818 if (do_wait)
00819 {
00820 print_msg(_("waiting for server to start..."));
00821
00822 switch (test_postmaster_connection(false))
00823 {
00824 case PQPING_OK:
00825 print_msg(_(" done\n"));
00826 print_msg(_("server started\n"));
00827 break;
00828 case PQPING_REJECT:
00829 print_msg(_(" stopped waiting\n"));
00830 print_msg(_("server is still starting up\n"));
00831 break;
00832 case PQPING_NO_RESPONSE:
00833 print_msg(_(" stopped waiting\n"));
00834 write_stderr(_("%s: could not start server\n"
00835 "Examine the log output.\n"),
00836 progname);
00837 exit(1);
00838 break;
00839 case PQPING_NO_ATTEMPT:
00840 print_msg(_(" failed\n"));
00841 write_stderr(_("%s: could not wait for server because of misconfiguration\n"),
00842 progname);
00843 exit(1);
00844 }
00845 }
00846 else
00847 print_msg(_("server starting\n"));
00848 }
00849
00850
00851 static void
00852 do_stop(void)
00853 {
00854 int cnt;
00855 pgpid_t pid;
00856 struct stat statbuf;
00857
00858 pid = get_pgpid();
00859
00860 if (pid == 0)
00861 {
00862 write_stderr(_("%s: PID file \"%s\" does not exist\n"), progname, pid_file);
00863 write_stderr(_("Is server running?\n"));
00864 exit(1);
00865 }
00866 else if (pid < 0)
00867 {
00868 pid = -pid;
00869 write_stderr(_("%s: cannot stop server; "
00870 "single-user server is running (PID: %ld)\n"),
00871 progname, pid);
00872 exit(1);
00873 }
00874
00875 if (kill((pid_t) pid, sig) != 0)
00876 {
00877 write_stderr(_("%s: could not send stop signal (PID: %ld): %s\n"), progname, pid,
00878 strerror(errno));
00879 exit(1);
00880 }
00881
00882 if (!do_wait)
00883 {
00884 print_msg(_("server shutting down\n"));
00885 return;
00886 }
00887 else
00888 {
00889
00890
00891
00892
00893
00894
00895 if (shutdown_mode == SMART_MODE &&
00896 stat(backup_file, &statbuf) == 0 &&
00897 stat(recovery_file, &statbuf) != 0)
00898 {
00899 print_msg(_("WARNING: online backup mode is active\n"
00900 "Shutdown will not complete until pg_stop_backup() is called.\n\n"));
00901 }
00902
00903 print_msg(_("waiting for server to shut down..."));
00904
00905 for (cnt = 0; cnt < wait_seconds; cnt++)
00906 {
00907 if ((pid = get_pgpid()) != 0)
00908 {
00909 print_msg(".");
00910 pg_usleep(1000000);
00911 }
00912 else
00913 break;
00914 }
00915
00916 if (pid != 0)
00917 {
00918 print_msg(_(" failed\n"));
00919
00920 write_stderr(_("%s: server does not shut down\n"), progname);
00921 if (shutdown_mode == SMART_MODE)
00922 write_stderr(_("HINT: The \"-m fast\" option immediately disconnects sessions rather than\n"
00923 "waiting for session-initiated disconnection.\n"));
00924 exit(1);
00925 }
00926 print_msg(_(" done\n"));
00927
00928 print_msg(_("server stopped\n"));
00929 }
00930 }
00931
00932
00933
00934
00935
00936
00937 static void
00938 do_restart(void)
00939 {
00940 int cnt;
00941 pgpid_t pid;
00942 struct stat statbuf;
00943
00944 pid = get_pgpid();
00945
00946 if (pid == 0)
00947 {
00948 write_stderr(_("%s: PID file \"%s\" does not exist\n"),
00949 progname, pid_file);
00950 write_stderr(_("Is server running?\n"));
00951 write_stderr(_("starting server anyway\n"));
00952 do_start();
00953 return;
00954 }
00955 else if (pid < 0)
00956 {
00957 pid = -pid;
00958 if (postmaster_is_alive((pid_t) pid))
00959 {
00960 write_stderr(_("%s: cannot restart server; "
00961 "single-user server is running (PID: %ld)\n"),
00962 progname, pid);
00963 write_stderr(_("Please terminate the single-user server and try again.\n"));
00964 exit(1);
00965 }
00966 }
00967
00968 if (postmaster_is_alive((pid_t) pid))
00969 {
00970 if (kill((pid_t) pid, sig) != 0)
00971 {
00972 write_stderr(_("%s: could not send stop signal (PID: %ld): %s\n"), progname, pid,
00973 strerror(errno));
00974 exit(1);
00975 }
00976
00977
00978
00979
00980
00981
00982
00983 if (shutdown_mode == SMART_MODE &&
00984 stat(backup_file, &statbuf) == 0 &&
00985 stat(recovery_file, &statbuf) != 0)
00986 {
00987 print_msg(_("WARNING: online backup mode is active\n"
00988 "Shutdown will not complete until pg_stop_backup() is called.\n\n"));
00989 }
00990
00991 print_msg(_("waiting for server to shut down..."));
00992
00993
00994
00995 for (cnt = 0; cnt < wait_seconds; cnt++)
00996 {
00997 if ((pid = get_pgpid()) != 0)
00998 {
00999 print_msg(".");
01000 pg_usleep(1000000);
01001 }
01002 else
01003 break;
01004 }
01005
01006 if (pid != 0)
01007 {
01008 print_msg(_(" failed\n"));
01009
01010 write_stderr(_("%s: server does not shut down\n"), progname);
01011 if (shutdown_mode == SMART_MODE)
01012 write_stderr(_("HINT: The \"-m fast\" option immediately disconnects sessions rather than\n"
01013 "waiting for session-initiated disconnection.\n"));
01014 exit(1);
01015 }
01016
01017 print_msg(_(" done\n"));
01018 print_msg(_("server stopped\n"));
01019 }
01020 else
01021 {
01022 write_stderr(_("%s: old server process (PID: %ld) seems to be gone\n"),
01023 progname, pid);
01024 write_stderr(_("starting server anyway\n"));
01025 }
01026
01027 do_start();
01028 }
01029
01030 static void
01031 do_reload(void)
01032 {
01033 pgpid_t pid;
01034
01035 pid = get_pgpid();
01036 if (pid == 0)
01037 {
01038 write_stderr(_("%s: PID file \"%s\" does not exist\n"), progname, pid_file);
01039 write_stderr(_("Is server running?\n"));
01040 exit(1);
01041 }
01042 else if (pid < 0)
01043 {
01044 pid = -pid;
01045 write_stderr(_("%s: cannot reload server; "
01046 "single-user server is running (PID: %ld)\n"),
01047 progname, pid);
01048 write_stderr(_("Please terminate the single-user server and try again.\n"));
01049 exit(1);
01050 }
01051
01052 if (kill((pid_t) pid, sig) != 0)
01053 {
01054 write_stderr(_("%s: could not send reload signal (PID: %ld): %s\n"),
01055 progname, pid, strerror(errno));
01056 exit(1);
01057 }
01058
01059 print_msg(_("server signaled\n"));
01060 }
01061
01062
01063
01064
01065
01066
01067 static void
01068 do_promote(void)
01069 {
01070 FILE *prmfile;
01071 pgpid_t pid;
01072 struct stat statbuf;
01073
01074 pid = get_pgpid();
01075
01076 if (pid == 0)
01077 {
01078 write_stderr(_("%s: PID file \"%s\" does not exist\n"), progname, pid_file);
01079 write_stderr(_("Is server running?\n"));
01080 exit(1);
01081 }
01082 else if (pid < 0)
01083 {
01084 pid = -pid;
01085 write_stderr(_("%s: cannot promote server; "
01086 "single-user server is running (PID: %ld)\n"),
01087 progname, pid);
01088 exit(1);
01089 }
01090
01091
01092 if (stat(recovery_file, &statbuf) != 0)
01093 {
01094 write_stderr(_("%s: cannot promote server; "
01095 "server is not in standby mode\n"),
01096 progname);
01097 exit(1);
01098 }
01099
01100
01101
01102
01103
01104
01105
01106 snprintf(promote_file, MAXPGPATH, "%s/fast_promote", pg_data);
01107
01108 if ((prmfile = fopen(promote_file, "w")) == NULL)
01109 {
01110 write_stderr(_("%s: could not create promote signal file \"%s\": %s\n"),
01111 progname, promote_file, strerror(errno));
01112 exit(1);
01113 }
01114 if (fclose(prmfile))
01115 {
01116 write_stderr(_("%s: could not write promote signal file \"%s\": %s\n"),
01117 progname, promote_file, strerror(errno));
01118 exit(1);
01119 }
01120
01121 sig = SIGUSR1;
01122 if (kill((pid_t) pid, sig) != 0)
01123 {
01124 write_stderr(_("%s: could not send promote signal (PID: %ld): %s\n"),
01125 progname, pid, strerror(errno));
01126 if (unlink(promote_file) != 0)
01127 write_stderr(_("%s: could not remove promote signal file \"%s\": %s\n"),
01128 progname, promote_file, strerror(errno));
01129 exit(1);
01130 }
01131
01132 print_msg(_("server promoting\n"));
01133 }
01134
01135
01136
01137
01138
01139
01140 static bool
01141 postmaster_is_alive(pid_t pid)
01142 {
01143
01144
01145
01146
01147
01148
01149
01150
01151
01152
01153 if (pid == getpid())
01154 return false;
01155 #ifndef WIN32
01156 if (pid == getppid())
01157 return false;
01158 #endif
01159 if (kill(pid, 0) == 0)
01160 return true;
01161 return false;
01162 }
01163
01164 static void
01165 do_status(void)
01166 {
01167 pgpid_t pid;
01168
01169 pid = get_pgpid();
01170
01171 if (pid != 0)
01172 {
01173
01174 if (pid < 0)
01175 {
01176 pid = -pid;
01177 if (postmaster_is_alive((pid_t) pid))
01178 {
01179 printf(_("%s: single-user server is running (PID: %ld)\n"),
01180 progname, pid);
01181 return;
01182 }
01183 }
01184 else
01185
01186 {
01187 if (postmaster_is_alive((pid_t) pid))
01188 {
01189 char **optlines;
01190
01191 printf(_("%s: server is running (PID: %ld)\n"),
01192 progname, pid);
01193
01194 optlines = readfile(postopts_file);
01195 if (optlines != NULL)
01196 for (; *optlines != NULL; optlines++)
01197 fputs(*optlines, stdout);
01198 return;
01199 }
01200 }
01201 }
01202 printf(_("%s: no server running\n"), progname);
01203
01204
01205
01206
01207
01208
01209
01210 exit(3);
01211 }
01212
01213
01214
01215 static void
01216 do_kill(pgpid_t pid)
01217 {
01218 if (kill((pid_t) pid, sig) != 0)
01219 {
01220 write_stderr(_("%s: could not send signal %d (PID: %ld): %s\n"),
01221 progname, sig, pid, strerror(errno));
01222 exit(1);
01223 }
01224 }
01225
01226 #if defined(WIN32) || defined(__CYGWIN__)
01227
01228 static bool
01229 pgwin32_IsInstalled(SC_HANDLE hSCM)
01230 {
01231 SC_HANDLE hService = OpenService(hSCM, register_servicename, SERVICE_QUERY_CONFIG);
01232 bool bResult = (hService != NULL);
01233
01234 if (bResult)
01235 CloseServiceHandle(hService);
01236 return bResult;
01237 }
01238
01239 static char *
01240 pgwin32_CommandLine(bool registration)
01241 {
01242 static char cmdLine[MAXPGPATH];
01243 int ret;
01244
01245 #ifdef __CYGWIN__
01246 char buf[MAXPGPATH];
01247 #endif
01248
01249 if (registration)
01250 {
01251 ret = find_my_exec(argv0, cmdLine);
01252 if (ret != 0)
01253 {
01254 write_stderr(_("%s: could not find own program executable\n"), progname);
01255 exit(1);
01256 }
01257 }
01258 else
01259 {
01260 ret = find_other_exec(argv0, "postgres", PG_BACKEND_VERSIONSTR,
01261 cmdLine);
01262 if (ret != 0)
01263 {
01264 write_stderr(_("%s: could not find postgres program executable\n"), progname);
01265 exit(1);
01266 }
01267 }
01268
01269 #ifdef __CYGWIN__
01270
01271 #if CYGWIN_VERSION_DLL_MAJOR >= 1007
01272 cygwin_conv_path(CCP_POSIX_TO_WIN_A, cmdLine, buf, sizeof(buf));
01273 #else
01274 cygwin_conv_to_full_win32_path(cmdLine, buf);
01275 #endif
01276 strcpy(cmdLine, buf);
01277 #endif
01278
01279 if (registration)
01280 {
01281 if (pg_strcasecmp(cmdLine + strlen(cmdLine) - 4, ".exe") != 0)
01282 {
01283
01284 strcat(cmdLine, ".exe");
01285 }
01286 strcat(cmdLine, " runservice -N \"");
01287 strcat(cmdLine, register_servicename);
01288 strcat(cmdLine, "\"");
01289 }
01290
01291 if (pg_config)
01292 {
01293 strcat(cmdLine, " -D \"");
01294 strcat(cmdLine, pg_config);
01295 strcat(cmdLine, "\"");
01296 }
01297
01298 if (registration && do_wait)
01299 strcat(cmdLine, " -w");
01300
01301 if (registration && wait_seconds != DEFAULT_WAIT)
01302
01303 sprintf(cmdLine + strlen(cmdLine), " -t %d", wait_seconds);
01304
01305 if (registration && silent_mode)
01306 strcat(cmdLine, " -s");
01307
01308 if (post_opts)
01309 {
01310 strcat(cmdLine, " ");
01311 if (registration)
01312 strcat(cmdLine, " -o \"");
01313 strcat(cmdLine, post_opts);
01314 if (registration)
01315 strcat(cmdLine, "\"");
01316 }
01317
01318 return cmdLine;
01319 }
01320
01321 static void
01322 pgwin32_doRegister(void)
01323 {
01324 SC_HANDLE hService;
01325 SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
01326
01327 if (hSCM == NULL)
01328 {
01329 write_stderr(_("%s: could not open service manager\n"), progname);
01330 exit(1);
01331 }
01332 if (pgwin32_IsInstalled(hSCM))
01333 {
01334 CloseServiceHandle(hSCM);
01335 write_stderr(_("%s: service \"%s\" already registered\n"), progname, register_servicename);
01336 exit(1);
01337 }
01338
01339 if ((hService = CreateService(hSCM, register_servicename, register_servicename,
01340 SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
01341 pgctl_start_type, SERVICE_ERROR_NORMAL,
01342 pgwin32_CommandLine(true),
01343 NULL, NULL, "RPCSS\0", register_username, register_password)) == NULL)
01344 {
01345 CloseServiceHandle(hSCM);
01346 write_stderr(_("%s: could not register service \"%s\": error code %lu\n"), progname, register_servicename, GetLastError());
01347 exit(1);
01348 }
01349 CloseServiceHandle(hService);
01350 CloseServiceHandle(hSCM);
01351 }
01352
01353 static void
01354 pgwin32_doUnregister(void)
01355 {
01356 SC_HANDLE hService;
01357 SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
01358
01359 if (hSCM == NULL)
01360 {
01361 write_stderr(_("%s: could not open service manager\n"), progname);
01362 exit(1);
01363 }
01364 if (!pgwin32_IsInstalled(hSCM))
01365 {
01366 CloseServiceHandle(hSCM);
01367 write_stderr(_("%s: service \"%s\" not registered\n"), progname, register_servicename);
01368 exit(1);
01369 }
01370
01371 if ((hService = OpenService(hSCM, register_servicename, DELETE)) == NULL)
01372 {
01373 CloseServiceHandle(hSCM);
01374 write_stderr(_("%s: could not open service \"%s\": error code %lu\n"), progname, register_servicename, GetLastError());
01375 exit(1);
01376 }
01377 if (!DeleteService(hService))
01378 {
01379 CloseServiceHandle(hService);
01380 CloseServiceHandle(hSCM);
01381 write_stderr(_("%s: could not unregister service \"%s\": error code %lu\n"), progname, register_servicename, GetLastError());
01382 exit(1);
01383 }
01384 CloseServiceHandle(hService);
01385 CloseServiceHandle(hSCM);
01386 }
01387
01388 static void
01389 pgwin32_SetServiceStatus(DWORD currentState)
01390 {
01391 status.dwCurrentState = currentState;
01392 SetServiceStatus(hStatus, (LPSERVICE_STATUS) &status);
01393 }
01394
01395 static void WINAPI
01396 pgwin32_ServiceHandler(DWORD request)
01397 {
01398 switch (request)
01399 {
01400 case SERVICE_CONTROL_STOP:
01401 case SERVICE_CONTROL_SHUTDOWN:
01402
01403
01404
01405
01406
01407
01408 status.dwWaitHint = 10000;
01409 pgwin32_SetServiceStatus(SERVICE_STOP_PENDING);
01410 SetEvent(shutdownEvent);
01411 return;
01412
01413 case SERVICE_CONTROL_PAUSE:
01414
01415 status.dwWaitHint = 5000;
01416 kill(postmasterPID, SIGHUP);
01417 return;
01418
01419
01420 case SERVICE_CONTROL_CONTINUE:
01421 case SERVICE_CONTROL_INTERROGATE:
01422 default:
01423 break;
01424 }
01425 }
01426
01427 static void WINAPI
01428 pgwin32_ServiceMain(DWORD argc, LPTSTR *argv)
01429 {
01430 PROCESS_INFORMATION pi;
01431 DWORD ret;
01432
01433
01434 status.dwWin32ExitCode = S_OK;
01435 status.dwCheckPoint = 0;
01436 status.dwWaitHint = 60000;
01437 status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
01438 status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_PAUSE_CONTINUE;
01439 status.dwServiceSpecificExitCode = 0;
01440 status.dwCurrentState = SERVICE_START_PENDING;
01441
01442 memset(&pi, 0, sizeof(pi));
01443
01444 read_post_opts();
01445
01446
01447 if ((hStatus = RegisterServiceCtrlHandler(register_servicename, pgwin32_ServiceHandler)) == (SERVICE_STATUS_HANDLE) 0)
01448 return;
01449
01450 if ((shutdownEvent = CreateEvent(NULL, true, false, NULL)) == NULL)
01451 return;
01452
01453
01454 pgwin32_SetServiceStatus(SERVICE_START_PENDING);
01455 if (!CreateRestrictedProcess(pgwin32_CommandLine(false), &pi, true))
01456 {
01457 pgwin32_SetServiceStatus(SERVICE_STOPPED);
01458 return;
01459 }
01460 postmasterPID = pi.dwProcessId;
01461 postmasterProcess = pi.hProcess;
01462 CloseHandle(pi.hThread);
01463
01464 if (do_wait)
01465 {
01466 write_eventlog(EVENTLOG_INFORMATION_TYPE, _("Waiting for server startup...\n"));
01467 if (test_postmaster_connection(true) != PQPING_OK)
01468 {
01469 write_eventlog(EVENTLOG_ERROR_TYPE, _("Timed out waiting for server startup\n"));
01470 pgwin32_SetServiceStatus(SERVICE_STOPPED);
01471 return;
01472 }
01473 write_eventlog(EVENTLOG_INFORMATION_TYPE, _("Server started and accepting connections\n"));
01474 }
01475
01476 pgwin32_SetServiceStatus(SERVICE_RUNNING);
01477
01478
01479 ret = WaitForMultipleObjects(2, shutdownHandles, FALSE, INFINITE);
01480
01481 pgwin32_SetServiceStatus(SERVICE_STOP_PENDING);
01482 switch (ret)
01483 {
01484 case WAIT_OBJECT_0:
01485 kill(postmasterPID, SIGINT);
01486
01487
01488
01489
01490
01491 while (WaitForSingleObject(postmasterProcess, 5000) == WAIT_TIMEOUT && status.dwCheckPoint < 12)
01492 status.dwCheckPoint++;
01493 break;
01494
01495 case (WAIT_OBJECT_0 + 1):
01496 break;
01497
01498 default:
01499
01500 break;
01501 }
01502
01503 CloseHandle(shutdownEvent);
01504 CloseHandle(postmasterProcess);
01505
01506 pgwin32_SetServiceStatus(SERVICE_STOPPED);
01507 }
01508
01509 static void
01510 pgwin32_doRunAsService(void)
01511 {
01512 SERVICE_TABLE_ENTRY st[] = {{register_servicename, pgwin32_ServiceMain},
01513 {NULL, NULL}};
01514
01515 if (StartServiceCtrlDispatcher(st) == 0)
01516 {
01517 write_stderr(_("%s: could not start service \"%s\": error code %lu\n"), progname, register_servicename, GetLastError());
01518 exit(1);
01519 }
01520 }
01521
01522
01523
01524
01525
01526
01527
01528
01529 typedef BOOL (WINAPI * __CreateRestrictedToken) (HANDLE, DWORD, DWORD, PSID_AND_ATTRIBUTES, DWORD, PLUID_AND_ATTRIBUTES, DWORD, PSID_AND_ATTRIBUTES, PHANDLE);
01530 typedef BOOL (WINAPI * __IsProcessInJob) (HANDLE, HANDLE, PBOOL);
01531 typedef HANDLE (WINAPI * __CreateJobObject) (LPSECURITY_ATTRIBUTES, LPCTSTR);
01532 typedef BOOL (WINAPI * __SetInformationJobObject) (HANDLE, JOBOBJECTINFOCLASS, LPVOID, DWORD);
01533 typedef BOOL (WINAPI * __AssignProcessToJobObject) (HANDLE, HANDLE);
01534 typedef BOOL (WINAPI * __QueryInformationJobObject) (HANDLE, JOBOBJECTINFOCLASS, LPVOID, DWORD, LPDWORD);
01535
01536
01537 #ifndef DISABLE_MAX_PRIVILEGE
01538 #define DISABLE_MAX_PRIVILEGE 0x1
01539 #endif
01540
01541
01542
01543
01544
01545
01546
01547
01548
01549
01550
01551
01552
01553 static int
01554 CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, bool as_service)
01555 {
01556 int r;
01557 BOOL b;
01558 STARTUPINFO si;
01559 HANDLE origToken;
01560 HANDLE restrictedToken;
01561 SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
01562 SID_AND_ATTRIBUTES dropSids[2];
01563
01564
01565 __CreateRestrictedToken _CreateRestrictedToken = NULL;
01566 __IsProcessInJob _IsProcessInJob = NULL;
01567 __CreateJobObject _CreateJobObject = NULL;
01568 __SetInformationJobObject _SetInformationJobObject = NULL;
01569 __AssignProcessToJobObject _AssignProcessToJobObject = NULL;
01570 __QueryInformationJobObject _QueryInformationJobObject = NULL;
01571 HANDLE Kernel32Handle;
01572 HANDLE Advapi32Handle;
01573
01574 ZeroMemory(&si, sizeof(si));
01575 si.cb = sizeof(si);
01576
01577 Advapi32Handle = LoadLibrary("ADVAPI32.DLL");
01578 if (Advapi32Handle != NULL)
01579 {
01580 _CreateRestrictedToken = (__CreateRestrictedToken) GetProcAddress(Advapi32Handle, "CreateRestrictedToken");
01581 }
01582
01583 if (_CreateRestrictedToken == NULL)
01584 {
01585
01586
01587
01588
01589 write_stderr(_("%s: WARNING: cannot create restricted tokens on this platform\n"), progname);
01590 if (Advapi32Handle != NULL)
01591 FreeLibrary(Advapi32Handle);
01592 return CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, processInfo);
01593 }
01594
01595
01596 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &origToken))
01597 {
01598 write_stderr(_("%s: could not open process token: error code %lu\n"), progname, GetLastError());
01599 return 0;
01600 }
01601
01602
01603 ZeroMemory(&dropSids, sizeof(dropSids));
01604 if (!AllocateAndInitializeSid(&NtAuthority, 2,
01605 SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,
01606 0, &dropSids[0].Sid) ||
01607 !AllocateAndInitializeSid(&NtAuthority, 2,
01608 SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0,
01609 0, &dropSids[1].Sid))
01610 {
01611 write_stderr(_("%s: could not allocate SIDs: error code %lu\n"), progname, GetLastError());
01612 return 0;
01613 }
01614
01615 b = _CreateRestrictedToken(origToken,
01616 DISABLE_MAX_PRIVILEGE,
01617 sizeof(dropSids) / sizeof(dropSids[0]),
01618 dropSids,
01619 0, NULL,
01620 0, NULL,
01621 &restrictedToken);
01622
01623 FreeSid(dropSids[1].Sid);
01624 FreeSid(dropSids[0].Sid);
01625 CloseHandle(origToken);
01626 FreeLibrary(Advapi32Handle);
01627
01628 if (!b)
01629 {
01630 write_stderr(_("%s: could not create restricted token: error code %lu\n"), progname, GetLastError());
01631 return 0;
01632 }
01633
01634 #ifndef __CYGWIN__
01635 AddUserToTokenDacl(restrictedToken);
01636 #endif
01637
01638 r = CreateProcessAsUser(restrictedToken, NULL, cmd, NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, NULL, &si, processInfo);
01639
01640 Kernel32Handle = LoadLibrary("KERNEL32.DLL");
01641 if (Kernel32Handle != NULL)
01642 {
01643 _IsProcessInJob = (__IsProcessInJob) GetProcAddress(Kernel32Handle, "IsProcessInJob");
01644 _CreateJobObject = (__CreateJobObject) GetProcAddress(Kernel32Handle, "CreateJobObjectA");
01645 _SetInformationJobObject = (__SetInformationJobObject) GetProcAddress(Kernel32Handle, "SetInformationJobObject");
01646 _AssignProcessToJobObject = (__AssignProcessToJobObject) GetProcAddress(Kernel32Handle, "AssignProcessToJobObject");
01647 _QueryInformationJobObject = (__QueryInformationJobObject) GetProcAddress(Kernel32Handle, "QueryInformationJobObject");
01648 }
01649
01650
01651 if (_IsProcessInJob == NULL || _CreateJobObject == NULL || _SetInformationJobObject == NULL || _AssignProcessToJobObject == NULL || _QueryInformationJobObject == NULL)
01652 {
01653
01654
01655
01656
01657 OSVERSIONINFO osv;
01658
01659 osv.dwOSVersionInfoSize = sizeof(osv);
01660 if (!GetVersionEx(&osv) ||
01661 (osv.dwMajorVersion == 5 && osv.dwMinorVersion > 0) ||
01662 osv.dwMajorVersion > 5)
01663
01664
01665
01666
01667
01668 write_stderr(_("%s: WARNING: could not locate all job object functions in system API\n"), progname);
01669 }
01670 else
01671 {
01672 BOOL inJob;
01673
01674 if (_IsProcessInJob(processInfo->hProcess, NULL, &inJob))
01675 {
01676 if (!inJob)
01677 {
01678
01679
01680
01681
01682
01683 HANDLE job;
01684 char jobname[128];
01685
01686 sprintf(jobname, "PostgreSQL_%lu", processInfo->dwProcessId);
01687
01688 job = _CreateJobObject(NULL, jobname);
01689 if (job)
01690 {
01691 JOBOBJECT_BASIC_LIMIT_INFORMATION basicLimit;
01692 JOBOBJECT_BASIC_UI_RESTRICTIONS uiRestrictions;
01693 JOBOBJECT_SECURITY_LIMIT_INFORMATION securityLimit;
01694 OSVERSIONINFO osv;
01695
01696 ZeroMemory(&basicLimit, sizeof(basicLimit));
01697 ZeroMemory(&uiRestrictions, sizeof(uiRestrictions));
01698 ZeroMemory(&securityLimit, sizeof(securityLimit));
01699
01700 basicLimit.LimitFlags = JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION | JOB_OBJECT_LIMIT_PRIORITY_CLASS;
01701 basicLimit.PriorityClass = NORMAL_PRIORITY_CLASS;
01702 _SetInformationJobObject(job, JobObjectBasicLimitInformation, &basicLimit, sizeof(basicLimit));
01703
01704 uiRestrictions.UIRestrictionsClass = JOB_OBJECT_UILIMIT_DESKTOP | JOB_OBJECT_UILIMIT_DISPLAYSETTINGS |
01705 JOB_OBJECT_UILIMIT_EXITWINDOWS | JOB_OBJECT_UILIMIT_READCLIPBOARD |
01706 JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS | JOB_OBJECT_UILIMIT_WRITECLIPBOARD;
01707
01708 if (as_service)
01709 {
01710 osv.dwOSVersionInfoSize = sizeof(osv);
01711 if (!GetVersionEx(&osv) ||
01712 osv.dwMajorVersion < 6 ||
01713 (osv.dwMajorVersion == 6 && osv.dwMinorVersion == 0))
01714 {
01715
01716
01717
01718
01719
01720
01721 uiRestrictions.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_HANDLES;
01722 }
01723 }
01724 _SetInformationJobObject(job, JobObjectBasicUIRestrictions, &uiRestrictions, sizeof(uiRestrictions));
01725
01726 securityLimit.SecurityLimitFlags = JOB_OBJECT_SECURITY_NO_ADMIN | JOB_OBJECT_SECURITY_ONLY_TOKEN;
01727 securityLimit.JobToken = restrictedToken;
01728 _SetInformationJobObject(job, JobObjectSecurityLimitInformation, &securityLimit, sizeof(securityLimit));
01729
01730 _AssignProcessToJobObject(job, processInfo->hProcess);
01731 }
01732 }
01733 }
01734 }
01735
01736
01737 CloseHandle(restrictedToken);
01738
01739 ResumeThread(processInfo->hThread);
01740
01741 FreeLibrary(Kernel32Handle);
01742
01743
01744
01745
01746
01747 return r;
01748 }
01749 #endif
01750
01751 static void
01752 do_advice(void)
01753 {
01754 write_stderr(_("Try \"%s --help\" for more information.\n"), progname);
01755 }
01756
01757
01758
01759 static void
01760 do_help(void)
01761 {
01762 printf(_("%s is a utility to initialize, start, stop, or control a PostgreSQL server.\n\n"), progname);
01763 printf(_("Usage:\n"));
01764 printf(_(" %s init[db] [-D DATADIR] [-s] [-o \"OPTIONS\"]\n"), progname);
01765 printf(_(" %s start [-w] [-t SECS] [-D DATADIR] [-s] [-l FILENAME] [-o \"OPTIONS\"]\n"), progname);
01766 printf(_(" %s stop [-W] [-t SECS] [-D DATADIR] [-s] [-m SHUTDOWN-MODE]\n"), progname);
01767 printf(_(" %s restart [-w] [-t SECS] [-D DATADIR] [-s] [-m SHUTDOWN-MODE]\n"
01768 " [-o \"OPTIONS\"]\n"), progname);
01769 printf(_(" %s reload [-D DATADIR] [-s]\n"), progname);
01770 printf(_(" %s status [-D DATADIR]\n"), progname);
01771 printf(_(" %s promote [-D DATADIR] [-s]\n"), progname);
01772 printf(_(" %s kill SIGNALNAME PID\n"), progname);
01773 #if defined(WIN32) || defined(__CYGWIN__)
01774 printf(_(" %s register [-N SERVICENAME] [-U USERNAME] [-P PASSWORD] [-D DATADIR]\n"
01775 " [-S START-TYPE] [-w] [-t SECS] [-o \"OPTIONS\"]\n"), progname);
01776 printf(_(" %s unregister [-N SERVICENAME]\n"), progname);
01777 #endif
01778
01779 printf(_("\nCommon options:\n"));
01780 printf(_(" -D, --pgdata=DATADIR location of the database storage area\n"));
01781 printf(_(" -s, --silent only print errors, no informational messages\n"));
01782 printf(_(" -t, --timeout=SECS seconds to wait when using -w option\n"));
01783 printf(_(" -V, --version output version information, then exit\n"));
01784 printf(_(" -w wait until operation completes\n"));
01785 printf(_(" -W do not wait until operation completes\n"));
01786 printf(_(" -?, --help show this help, then exit\n"));
01787 printf(_("(The default is to wait for shutdown, but not for start or restart.)\n\n"));
01788 printf(_("If the -D option is omitted, the environment variable PGDATA is used.\n"));
01789
01790 printf(_("\nOptions for start or restart:\n"));
01791 #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
01792 printf(_(" -c, --core-files allow postgres to produce core files\n"));
01793 #else
01794 printf(_(" -c, --core-files not applicable on this platform\n"));
01795 #endif
01796 printf(_(" -l, --log=FILENAME write (or append) server log to FILENAME\n"));
01797 printf(_(" -o OPTIONS command line options to pass to postgres\n"
01798 " (PostgreSQL server executable) or initdb\n"));
01799 printf(_(" -p PATH-TO-POSTGRES normally not necessary\n"));
01800 printf(_("\nOptions for stop, restart, or promote:\n"));
01801 printf(_(" -m, --mode=MODE MODE can be \"smart\", \"fast\", or \"immediate\"\n"));
01802
01803 printf(_("\nShutdown modes are:\n"));
01804 printf(_(" smart quit after all clients have disconnected\n"));
01805 printf(_(" fast quit directly, with proper shutdown\n"));
01806 printf(_(" immediate quit without complete shutdown; will lead to recovery on restart\n"));
01807
01808 printf(_("\nAllowed signal names for kill:\n"));
01809 printf(" ABRT HUP INT QUIT TERM USR1 USR2\n");
01810
01811 #if defined(WIN32) || defined(__CYGWIN__)
01812 printf(_("\nOptions for register and unregister:\n"));
01813 printf(_(" -N SERVICENAME service name with which to register PostgreSQL server\n"));
01814 printf(_(" -P PASSWORD password of account to register PostgreSQL server\n"));
01815 printf(_(" -U USERNAME user name of account to register PostgreSQL server\n"));
01816 printf(_(" -S START-TYPE service start type to register PostgreSQL server\n"));
01817
01818 printf(_("\nStart types are:\n"));
01819 printf(_(" auto start service automatically during system startup (default)\n"));
01820 printf(_(" demand start service on demand\n"));
01821 #endif
01822
01823 printf(_("\nReport bugs to <[email protected]>.\n"));
01824 }
01825
01826
01827
01828 static void
01829 set_mode(char *modeopt)
01830 {
01831 if (strcmp(modeopt, "s") == 0 || strcmp(modeopt, "smart") == 0)
01832 {
01833 shutdown_mode = SMART_MODE;
01834 sig = SIGTERM;
01835 }
01836 else if (strcmp(modeopt, "f") == 0 || strcmp(modeopt, "fast") == 0)
01837 {
01838 shutdown_mode = FAST_MODE;
01839 sig = SIGINT;
01840 }
01841 else if (strcmp(modeopt, "i") == 0 || strcmp(modeopt, "immediate") == 0)
01842 {
01843 shutdown_mode = IMMEDIATE_MODE;
01844 sig = SIGQUIT;
01845 }
01846 else
01847 {
01848 write_stderr(_("%s: unrecognized shutdown mode \"%s\"\n"), progname, modeopt);
01849 do_advice();
01850 exit(1);
01851 }
01852 }
01853
01854
01855
01856 static void
01857 set_sig(char *signame)
01858 {
01859 if (strcmp(signame, "HUP") == 0)
01860 sig = SIGHUP;
01861 else if (strcmp(signame, "INT") == 0)
01862 sig = SIGINT;
01863 else if (strcmp(signame, "QUIT") == 0)
01864 sig = SIGQUIT;
01865 else if (strcmp(signame, "ABRT") == 0)
01866 sig = SIGABRT;
01867 #if 0
01868
01869 else if (strcmp(signame, "KILL") == 0)
01870 sig = SIGKILL;
01871 #endif
01872 else if (strcmp(signame, "TERM") == 0)
01873 sig = SIGTERM;
01874 else if (strcmp(signame, "USR1") == 0)
01875 sig = SIGUSR1;
01876 else if (strcmp(signame, "USR2") == 0)
01877 sig = SIGUSR2;
01878 else
01879 {
01880 write_stderr(_("%s: unrecognized signal name \"%s\"\n"), progname, signame);
01881 do_advice();
01882 exit(1);
01883 }
01884 }
01885
01886
01887 #if defined(WIN32) || defined(__CYGWIN__)
01888 static void
01889 set_starttype(char *starttypeopt)
01890 {
01891 if (strcmp(starttypeopt, "a") == 0 || strcmp(starttypeopt, "auto") == 0)
01892 pgctl_start_type = SERVICE_AUTO_START;
01893 else if (strcmp(starttypeopt, "d") == 0 || strcmp(starttypeopt, "demand") == 0)
01894 pgctl_start_type = SERVICE_DEMAND_START;
01895 else
01896 {
01897 write_stderr(_("%s: unrecognized start type \"%s\"\n"), progname, starttypeopt);
01898 do_advice();
01899 exit(1);
01900 }
01901 }
01902 #endif
01903
01904
01905
01906
01907
01908
01909 static void
01910 adjust_data_dir(void)
01911 {
01912 char cmd[MAXPGPATH],
01913 filename[MAXPGPATH],
01914 *my_exec_path;
01915 FILE *fd;
01916
01917
01918 if (pg_config == NULL)
01919 return;
01920
01921
01922 snprintf(filename, sizeof(filename), "%s/postgresql.conf", pg_config);
01923 if ((fd = fopen(filename, "r")) == NULL)
01924 return;
01925 fclose(fd);
01926
01927
01928 snprintf(filename, sizeof(filename), "%s/PG_VERSION", pg_config);
01929 if ((fd = fopen(filename, "r")) != NULL)
01930 {
01931 fclose(fd);
01932 return;
01933 }
01934
01935
01936
01937
01938 if (exec_path == NULL)
01939 my_exec_path = find_other_exec_or_die(argv0, "postgres", PG_BACKEND_VERSIONSTR);
01940 else
01941 my_exec_path = pg_strdup(exec_path);
01942
01943 snprintf(cmd, MAXPGPATH, SYSTEMQUOTE "\"%s\" %s%s -C data_directory" SYSTEMQUOTE,
01944 my_exec_path, pgdata_opt ? pgdata_opt : "", post_opts ?
01945 post_opts : "");
01946
01947 fd = popen(cmd, "r");
01948 if (fd == NULL || fgets(filename, sizeof(filename), fd) == NULL)
01949 {
01950 write_stderr(_("%s: could not determine the data directory using command \"%s\"\n"), progname, cmd);
01951 exit(1);
01952 }
01953 pclose(fd);
01954 free(my_exec_path);
01955
01956
01957 if (strchr(filename, '\n') != NULL)
01958 *strchr(filename, '\n') = '\0';
01959
01960 free(pg_data);
01961 pg_data = pg_strdup(filename);
01962 canonicalize_path(pg_data);
01963 }
01964
01965
01966 int
01967 main(int argc, char **argv)
01968 {
01969 static struct option long_options[] = {
01970 {"help", no_argument, NULL, '?'},
01971 {"version", no_argument, NULL, 'V'},
01972 {"log", required_argument, NULL, 'l'},
01973 {"mode", required_argument, NULL, 'm'},
01974 {"pgdata", required_argument, NULL, 'D'},
01975 {"silent", no_argument, NULL, 's'},
01976 {"timeout", required_argument, NULL, 't'},
01977 {"core-files", no_argument, NULL, 'c'},
01978 {NULL, 0, NULL, 0}
01979 };
01980
01981 int option_index;
01982 int c;
01983 pgpid_t killproc = 0;
01984
01985 #if defined(WIN32) || defined(__CYGWIN__)
01986 setvbuf(stderr, NULL, _IONBF, 0);
01987 #endif
01988
01989 progname = get_progname(argv[0]);
01990 set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_ctl"));
01991 start_time = time(NULL);
01992
01993
01994
01995
01996
01997 argv0 = argv[0];
01998
01999 umask(S_IRWXG | S_IRWXO);
02000
02001
02002 if (argc > 1)
02003 {
02004 if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 ||
02005 strcmp(argv[1], "-?") == 0)
02006 {
02007 do_help();
02008 exit(0);
02009 }
02010 else if (strcmp(argv[1], "-V") == 0 || strcmp(argv[1], "--version") == 0)
02011 {
02012 puts("pg_ctl (PostgreSQL) " PG_VERSION);
02013 exit(0);
02014 }
02015 }
02016
02017
02018
02019
02020 #ifndef WIN32
02021 if (geteuid() == 0)
02022 {
02023 write_stderr(_("%s: cannot be run as root\n"
02024 "Please log in (using, e.g., \"su\") as the "
02025 "(unprivileged) user that will\n"
02026 "own the server process.\n"),
02027 progname);
02028 exit(1);
02029 }
02030 #endif
02031
02032
02033
02034
02035
02036
02037
02038 optind = 1;
02039
02040
02041 while (optind < argc)
02042 {
02043 while ((c = getopt_long(argc, argv, "cD:l:m:N:o:p:P:sS:t:U:wW", long_options, &option_index)) != -1)
02044 {
02045 switch (c)
02046 {
02047 case 'D':
02048 {
02049 char *pgdata_D;
02050 char *env_var = pg_malloc(strlen(optarg) + 8);
02051
02052 pgdata_D = pg_strdup(optarg);
02053 canonicalize_path(pgdata_D);
02054 snprintf(env_var, strlen(optarg) + 8, "PGDATA=%s",
02055 pgdata_D);
02056 putenv(env_var);
02057
02058
02059
02060
02061
02062
02063 pgdata_opt = pg_malloc(strlen(pgdata_D) + 7);
02064 snprintf(pgdata_opt, strlen(pgdata_D) + 7,
02065 "-D \"%s\" ",
02066 pgdata_D);
02067 break;
02068 }
02069 case 'l':
02070 log_file = pg_strdup(optarg);
02071 break;
02072 case 'm':
02073 set_mode(optarg);
02074 break;
02075 case 'N':
02076 register_servicename = pg_strdup(optarg);
02077 break;
02078 case 'o':
02079 post_opts = pg_strdup(optarg);
02080 break;
02081 case 'p':
02082 exec_path = pg_strdup(optarg);
02083 break;
02084 case 'P':
02085 register_password = pg_strdup(optarg);
02086 break;
02087 case 's':
02088 silent_mode = true;
02089 break;
02090 case 'S':
02091 #if defined(WIN32) || defined(__CYGWIN__)
02092 set_starttype(optarg);
02093 #else
02094 write_stderr(_("%s: -S option not supported on this platform\n"),
02095 progname);
02096 exit(1);
02097 #endif
02098 break;
02099 case 't':
02100 wait_seconds = atoi(optarg);
02101 break;
02102 case 'U':
02103 if (strchr(optarg, '\\'))
02104 register_username = pg_strdup(optarg);
02105 else
02106
02107 {
02108 register_username = pg_malloc(strlen(optarg) + 3);
02109 strcpy(register_username, ".\\");
02110 strcat(register_username, optarg);
02111 }
02112 break;
02113 case 'w':
02114 do_wait = true;
02115 wait_set = true;
02116 break;
02117 case 'W':
02118 do_wait = false;
02119 wait_set = true;
02120 break;
02121 case 'c':
02122 allow_core_files = true;
02123 break;
02124 default:
02125
02126 do_advice();
02127 exit(1);
02128 }
02129 }
02130
02131
02132 if (optind < argc)
02133 {
02134 if (ctl_command != NO_COMMAND)
02135 {
02136 write_stderr(_("%s: too many command-line arguments (first is \"%s\")\n"), progname, argv[optind]);
02137 do_advice();
02138 exit(1);
02139 }
02140
02141 if (strcmp(argv[optind], "init") == 0
02142 || strcmp(argv[optind], "initdb") == 0)
02143 ctl_command = INIT_COMMAND;
02144 else if (strcmp(argv[optind], "start") == 0)
02145 ctl_command = START_COMMAND;
02146 else if (strcmp(argv[optind], "stop") == 0)
02147 ctl_command = STOP_COMMAND;
02148 else if (strcmp(argv[optind], "restart") == 0)
02149 ctl_command = RESTART_COMMAND;
02150 else if (strcmp(argv[optind], "reload") == 0)
02151 ctl_command = RELOAD_COMMAND;
02152 else if (strcmp(argv[optind], "status") == 0)
02153 ctl_command = STATUS_COMMAND;
02154 else if (strcmp(argv[optind], "promote") == 0)
02155 ctl_command = PROMOTE_COMMAND;
02156 else if (strcmp(argv[optind], "kill") == 0)
02157 {
02158 if (argc - optind < 3)
02159 {
02160 write_stderr(_("%s: missing arguments for kill mode\n"), progname);
02161 do_advice();
02162 exit(1);
02163 }
02164 ctl_command = KILL_COMMAND;
02165 set_sig(argv[++optind]);
02166 killproc = atol(argv[++optind]);
02167 }
02168 #if defined(WIN32) || defined(__CYGWIN__)
02169 else if (strcmp(argv[optind], "register") == 0)
02170 ctl_command = REGISTER_COMMAND;
02171 else if (strcmp(argv[optind], "unregister") == 0)
02172 ctl_command = UNREGISTER_COMMAND;
02173 else if (strcmp(argv[optind], "runservice") == 0)
02174 ctl_command = RUN_AS_SERVICE_COMMAND;
02175 #endif
02176 else
02177 {
02178 write_stderr(_("%s: unrecognized operation mode \"%s\"\n"), progname, argv[optind]);
02179 do_advice();
02180 exit(1);
02181 }
02182 optind++;
02183 }
02184 }
02185
02186 if (ctl_command == NO_COMMAND)
02187 {
02188 write_stderr(_("%s: no operation specified\n"), progname);
02189 do_advice();
02190 exit(1);
02191 }
02192
02193
02194 pg_config = getenv("PGDATA");
02195 if (pg_config)
02196 {
02197 pg_config = pg_strdup(pg_config);
02198 canonicalize_path(pg_config);
02199 pg_data = pg_strdup(pg_config);
02200 }
02201
02202
02203 adjust_data_dir();
02204
02205
02206 if (pg_config == NULL &&
02207 ctl_command != KILL_COMMAND && ctl_command != UNREGISTER_COMMAND)
02208 {
02209 write_stderr(_("%s: no database directory specified and environment variable PGDATA unset\n"),
02210 progname);
02211 do_advice();
02212 exit(1);
02213 }
02214
02215 if (!wait_set)
02216 {
02217 switch (ctl_command)
02218 {
02219 case RESTART_COMMAND:
02220 case START_COMMAND:
02221 do_wait = false;
02222 break;
02223 case STOP_COMMAND:
02224 do_wait = true;
02225 break;
02226 default:
02227 break;
02228 }
02229 }
02230
02231 if (ctl_command == RELOAD_COMMAND)
02232 {
02233 sig = SIGHUP;
02234 do_wait = false;
02235 }
02236
02237 if (pg_data)
02238 {
02239 snprintf(postopts_file, MAXPGPATH, "%s/postmaster.opts", pg_data);
02240 snprintf(pid_file, MAXPGPATH, "%s/postmaster.pid", pg_data);
02241 snprintf(backup_file, MAXPGPATH, "%s/backup_label", pg_data);
02242 snprintf(recovery_file, MAXPGPATH, "%s/recovery.conf", pg_data);
02243 }
02244
02245 switch (ctl_command)
02246 {
02247 case INIT_COMMAND:
02248 do_init();
02249 break;
02250 case STATUS_COMMAND:
02251 do_status();
02252 break;
02253 case START_COMMAND:
02254 do_start();
02255 break;
02256 case STOP_COMMAND:
02257 do_stop();
02258 break;
02259 case RESTART_COMMAND:
02260 do_restart();
02261 break;
02262 case RELOAD_COMMAND:
02263 do_reload();
02264 break;
02265 case PROMOTE_COMMAND:
02266 do_promote();
02267 break;
02268 case KILL_COMMAND:
02269 do_kill(killproc);
02270 break;
02271 #if defined(WIN32) || defined(__CYGWIN__)
02272 case REGISTER_COMMAND:
02273 pgwin32_doRegister();
02274 break;
02275 case UNREGISTER_COMMAND:
02276 pgwin32_doUnregister();
02277 break;
02278 case RUN_AS_SERVICE_COMMAND:
02279 pgwin32_doRunAsService();
02280 break;
02281 #endif
02282 default:
02283 break;
02284 }
02285
02286 exit(0);
02287 }