Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * pg_ctl --- start/stops/restarts the PostgreSQL server
4 : *
5 : * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
6 : *
7 : * src/bin/pg_ctl/pg_ctl.c
8 : *
9 : *-------------------------------------------------------------------------
10 : */
11 :
12 : #ifdef WIN32
13 : /*
14 : * Need this to get defines for restricted tokens and jobs. And it
15 : * has to be set before any header from the Win32 API is loaded.
16 : */
17 : #define _WIN32_WINNT 0x0501
18 : #endif
19 :
20 : #include "postgres_fe.h"
21 :
22 : #include <fcntl.h>
23 : #include <signal.h>
24 : #include <time.h>
25 : #include <sys/stat.h>
26 : #include <sys/wait.h>
27 : #include <unistd.h>
28 :
29 : #ifdef HAVE_SYS_RESOURCE_H
30 : #include <sys/time.h>
31 : #include <sys/resource.h>
32 : #endif
33 :
34 : #include "catalog/pg_control.h"
35 : #include "common/controldata_utils.h"
36 : #include "getopt_long.h"
37 : #include "utils/pidfile.h"
38 :
39 : #ifdef WIN32 /* on Unix, we don't need libpq */
40 : #include "pqexpbuffer.h"
41 : #endif
42 :
43 : /* PID can be negative for standalone backend */
44 : typedef long pgpid_t;
45 :
46 :
47 : typedef enum
48 : {
49 : SMART_MODE,
50 : FAST_MODE,
51 : IMMEDIATE_MODE
52 : } ShutdownMode;
53 :
54 : typedef enum
55 : {
56 : POSTMASTER_READY,
57 : POSTMASTER_STILL_STARTING,
58 : POSTMASTER_FAILED
59 : } WaitPMResult;
60 :
61 : typedef enum
62 : {
63 : NO_COMMAND = 0,
64 : INIT_COMMAND,
65 : START_COMMAND,
66 : STOP_COMMAND,
67 : RESTART_COMMAND,
68 : RELOAD_COMMAND,
69 : STATUS_COMMAND,
70 : PROMOTE_COMMAND,
71 : KILL_COMMAND,
72 : REGISTER_COMMAND,
73 : UNREGISTER_COMMAND,
74 : RUN_AS_SERVICE_COMMAND
75 : } CtlCommand;
76 :
77 : #define DEFAULT_WAIT 60
78 :
79 : #define USEC_PER_SEC 1000000
80 :
81 : #define WAITS_PER_SEC 10 /* should divide USEC_PER_SEC evenly */
82 :
83 : static bool do_wait = true;
84 : static int wait_seconds = DEFAULT_WAIT;
85 : static bool wait_seconds_arg = false;
86 : static bool silent_mode = false;
87 : static ShutdownMode shutdown_mode = FAST_MODE;
88 : static int sig = SIGINT; /* default */
89 : static CtlCommand ctl_command = NO_COMMAND;
90 : static char *pg_data = NULL;
91 : static char *pg_config = NULL;
92 : static char *pgdata_opt = NULL;
93 : static char *post_opts = NULL;
94 : static const char *progname;
95 : static char *log_file = NULL;
96 : static char *exec_path = NULL;
97 : static char *event_source = NULL;
98 : static char *register_servicename = "PostgreSQL"; /* FIXME: + version ID? */
99 : static char *register_username = NULL;
100 : static char *register_password = NULL;
101 : static char *argv0 = NULL;
102 : static bool allow_core_files = false;
103 : static time_t start_time;
104 :
105 : static char postopts_file[MAXPGPATH];
106 : static char version_file[MAXPGPATH];
107 : static char pid_file[MAXPGPATH];
108 : static char backup_file[MAXPGPATH];
109 : static char promote_file[MAXPGPATH];
110 :
111 : #ifdef WIN32
112 : static DWORD pgctl_start_type = SERVICE_AUTO_START;
113 : static SERVICE_STATUS status;
114 : static SERVICE_STATUS_HANDLE hStatus = (SERVICE_STATUS_HANDLE) 0;
115 : static HANDLE shutdownHandles[2];
116 : static pid_t postmasterPID = -1;
117 :
118 : #define shutdownEvent shutdownHandles[0]
119 : #define postmasterProcess shutdownHandles[1]
120 : #endif
121 :
122 :
123 : static void write_stderr(const char *fmt,...) pg_attribute_printf(1, 2);
124 : static void do_advice(void);
125 : static void do_help(void);
126 : static void set_mode(char *modeopt);
127 : static void set_sig(char *signame);
128 : static void do_init(void);
129 : static void do_start(void);
130 : static void do_stop(void);
131 : static void do_restart(void);
132 : static void do_reload(void);
133 : static void do_status(void);
134 : static void do_promote(void);
135 : static void do_kill(pgpid_t pid);
136 : static void print_msg(const char *msg);
137 : static void adjust_data_dir(void);
138 :
139 : #ifdef WIN32
140 : #if (_MSC_VER >= 1800)
141 : #include <versionhelpers.h>
142 : #else
143 : static bool IsWindowsXPOrGreater(void);
144 : static bool IsWindows7OrGreater(void);
145 : #endif
146 : static bool pgwin32_IsInstalled(SC_HANDLE);
147 : static char *pgwin32_CommandLine(bool);
148 : static void pgwin32_doRegister(void);
149 : static void pgwin32_doUnregister(void);
150 : static void pgwin32_SetServiceStatus(DWORD);
151 : static void WINAPI pgwin32_ServiceHandler(DWORD);
152 : static void WINAPI pgwin32_ServiceMain(DWORD, LPTSTR *);
153 : static void pgwin32_doRunAsService(void);
154 : static int CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, bool as_service);
155 : #endif
156 :
157 : static pgpid_t get_pgpid(bool is_status_request);
158 : static char **readfile(const char *path, int *numlines);
159 : static void free_readfile(char **optlines);
160 : static pgpid_t start_postmaster(void);
161 : static void read_post_opts(void);
162 :
163 : static WaitPMResult wait_for_postmaster(pgpid_t pm_pid, bool do_checkpoint);
164 : static bool postmaster_is_alive(pid_t pid);
165 :
166 : #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
167 : static void unlimit_core_size(void);
168 : #endif
169 :
170 : static DBState get_control_dbstate(void);
171 :
172 :
173 : #ifdef WIN32
174 : static void
175 : write_eventlog(int level, const char *line)
176 : {
177 : static HANDLE evtHandle = INVALID_HANDLE_VALUE;
178 :
179 : if (silent_mode && level == EVENTLOG_INFORMATION_TYPE)
180 : return;
181 :
182 : if (evtHandle == INVALID_HANDLE_VALUE)
183 : {
184 : evtHandle = RegisterEventSource(NULL,
185 : event_source ? event_source : DEFAULT_EVENT_SOURCE);
186 : if (evtHandle == NULL)
187 : {
188 : evtHandle = INVALID_HANDLE_VALUE;
189 : return;
190 : }
191 : }
192 :
193 : ReportEvent(evtHandle,
194 : level,
195 : 0,
196 : 0, /* All events are Id 0 */
197 : NULL,
198 : 1,
199 : 0,
200 : &line,
201 : NULL);
202 : }
203 : #endif
204 :
205 : /*
206 : * Write errors to stderr (or by equal means when stderr is
207 : * not available).
208 : */
209 : static void
210 0 : write_stderr(const char *fmt,...)
211 : {
212 : va_list ap;
213 :
214 0 : va_start(ap, fmt);
215 : #ifndef WIN32
216 : /* On Unix, we just fprintf to stderr */
217 0 : vfprintf(stderr, fmt, ap);
218 : #else
219 :
220 : /*
221 : * On Win32, we print to stderr if running on a console, or write to
222 : * eventlog if running as a service
223 : */
224 : if (pgwin32_is_service()) /* Running as a service */
225 : {
226 : char errbuf[2048]; /* Arbitrary size? */
227 :
228 : vsnprintf(errbuf, sizeof(errbuf), fmt, ap);
229 :
230 : write_eventlog(EVENTLOG_ERROR_TYPE, errbuf);
231 : }
232 : else
233 : /* Not running as service, write to stderr */
234 : vfprintf(stderr, fmt, ap);
235 : #endif
236 0 : va_end(ap);
237 0 : }
238 :
239 : /*
240 : * Given an already-localized string, print it to stdout unless the
241 : * user has specified that no messages should be printed.
242 : */
243 : static void
244 4 : print_msg(const char *msg)
245 : {
246 4 : if (!silent_mode)
247 : {
248 0 : fputs(msg, stdout);
249 0 : fflush(stdout);
250 : }
251 4 : }
252 :
253 : static pgpid_t
254 10 : get_pgpid(bool is_status_request)
255 : {
256 : FILE *pidf;
257 : long pid;
258 : struct stat statbuf;
259 :
260 10 : if (stat(pg_data, &statbuf) != 0)
261 : {
262 0 : if (errno == ENOENT)
263 0 : write_stderr(_("%s: directory \"%s\" does not exist\n"), progname,
264 : pg_data);
265 : else
266 0 : write_stderr(_("%s: could not access directory \"%s\": %s\n"), progname,
267 0 : pg_data, strerror(errno));
268 :
269 : /*
270 : * The Linux Standard Base Core Specification 3.1 says this should
271 : * return '4, program or service status is unknown'
272 : * https://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html
273 : */
274 0 : exit(is_status_request ? 4 : 1);
275 : }
276 :
277 10 : if (stat(version_file, &statbuf) != 0 && errno == ENOENT)
278 : {
279 0 : write_stderr(_("%s: directory \"%s\" is not a database cluster directory\n"),
280 : progname, pg_data);
281 0 : exit(is_status_request ? 4 : 1);
282 : }
283 :
284 10 : pidf = fopen(pid_file, "r");
285 10 : if (pidf == NULL)
286 : {
287 : /* No pid file, not an error on startup */
288 1 : if (errno == ENOENT)
289 1 : return 0;
290 : else
291 : {
292 0 : write_stderr(_("%s: could not open PID file \"%s\": %s\n"),
293 0 : progname, pid_file, strerror(errno));
294 0 : exit(1);
295 : }
296 : }
297 9 : if (fscanf(pidf, "%ld", &pid) != 1)
298 : {
299 : /* Is the file empty? */
300 0 : if (ftell(pidf) == 0 && feof(pidf))
301 0 : write_stderr(_("%s: the PID file \"%s\" is empty\n"),
302 : progname, pid_file);
303 : else
304 0 : write_stderr(_("%s: invalid data in PID file \"%s\"\n"),
305 : progname, pid_file);
306 0 : exit(1);
307 : }
308 9 : fclose(pidf);
309 9 : return (pgpid_t) pid;
310 : }
311 :
312 :
313 : /*
314 : * get the lines from a text file - return NULL if file can't be opened
315 : *
316 : * Trailing newlines are deleted from the lines (this is a change from pre-v10)
317 : *
318 : * *numlines is set to the number of line pointers returned; there is
319 : * also an additional NULL pointer after the last real line.
320 : */
321 : static char **
322 0 : readfile(const char *path, int *numlines)
323 : {
324 : int fd;
325 : int nlines;
326 : char **result;
327 : char *buffer;
328 : char *linebegin;
329 : int i;
330 : int n;
331 : int len;
332 : struct stat statbuf;
333 :
334 0 : *numlines = 0; /* in case of failure or empty file */
335 :
336 : /*
337 : * Slurp the file into memory.
338 : *
339 : * The file can change concurrently, so we read the whole file into memory
340 : * with a single read() call. That's not guaranteed to get an atomic
341 : * snapshot, but in practice, for a small file, it's close enough for the
342 : * current use.
343 : */
344 0 : fd = open(path, O_RDONLY | PG_BINARY, 0);
345 0 : if (fd < 0)
346 0 : return NULL;
347 0 : if (fstat(fd, &statbuf) < 0)
348 : {
349 0 : close(fd);
350 0 : return NULL;
351 : }
352 0 : if (statbuf.st_size == 0)
353 : {
354 : /* empty file */
355 0 : close(fd);
356 0 : result = (char **) pg_malloc(sizeof(char *));
357 0 : *result = NULL;
358 0 : return result;
359 : }
360 0 : buffer = pg_malloc(statbuf.st_size + 1);
361 :
362 0 : len = read(fd, buffer, statbuf.st_size + 1);
363 0 : close(fd);
364 0 : if (len != statbuf.st_size)
365 : {
366 : /* oops, the file size changed between fstat and read */
367 0 : free(buffer);
368 0 : return NULL;
369 : }
370 :
371 : /*
372 : * Count newlines. We expect there to be a newline after each full line,
373 : * including one at the end of file. If there isn't a newline at the end,
374 : * any characters after the last newline will be ignored.
375 : */
376 0 : nlines = 0;
377 0 : for (i = 0; i < len; i++)
378 : {
379 0 : if (buffer[i] == '\n')
380 0 : nlines++;
381 : }
382 :
383 : /* set up the result buffer */
384 0 : result = (char **) pg_malloc((nlines + 1) * sizeof(char *));
385 0 : *numlines = nlines;
386 :
387 : /* now split the buffer into lines */
388 0 : linebegin = buffer;
389 0 : n = 0;
390 0 : for (i = 0; i < len; i++)
391 : {
392 0 : if (buffer[i] == '\n')
393 : {
394 0 : int slen = &buffer[i] - linebegin;
395 0 : char *linebuf = pg_malloc(slen + 1);
396 :
397 0 : memcpy(linebuf, linebegin, slen);
398 : /* we already dropped the \n, but get rid of any \r too */
399 0 : if (slen > 0 && linebuf[slen - 1] == '\r')
400 0 : slen--;
401 0 : linebuf[slen] = '\0';
402 0 : result[n++] = linebuf;
403 0 : linebegin = &buffer[i + 1];
404 : }
405 : }
406 0 : result[n] = NULL;
407 :
408 0 : free(buffer);
409 :
410 0 : return result;
411 : }
412 :
413 :
414 : /*
415 : * Free memory allocated for optlines through readfile()
416 : */
417 : static void
418 0 : free_readfile(char **optlines)
419 : {
420 0 : char *curr_line = NULL;
421 0 : int i = 0;
422 :
423 0 : if (!optlines)
424 0 : return;
425 :
426 0 : while ((curr_line = optlines[i++]))
427 0 : free(curr_line);
428 :
429 0 : free(optlines);
430 :
431 0 : return;
432 : }
433 :
434 : /*
435 : * start/test/stop routines
436 : */
437 :
438 : /*
439 : * Start the postmaster and return its PID.
440 : *
441 : * Currently, on Windows what we return is the PID of the shell process
442 : * that launched the postmaster (and, we trust, is waiting for it to exit).
443 : * So the PID is usable for "is the postmaster still running" checks,
444 : * but cannot be compared directly to postmaster.pid.
445 : *
446 : * On Windows, we also save aside a handle to the shell process in
447 : * "postmasterProcess", which the caller should close when done with it.
448 : */
449 : static pgpid_t
450 0 : start_postmaster(void)
451 : {
452 : char cmd[MAXPGPATH];
453 :
454 : #ifndef WIN32
455 : pgpid_t pm_pid;
456 :
457 : /* Flush stdio channels just before fork, to avoid double-output problems */
458 0 : fflush(stdout);
459 0 : fflush(stderr);
460 :
461 0 : pm_pid = fork();
462 0 : if (pm_pid < 0)
463 : {
464 : /* fork failed */
465 0 : write_stderr(_("%s: could not start server: %s\n"),
466 0 : progname, strerror(errno));
467 0 : exit(1);
468 : }
469 0 : if (pm_pid > 0)
470 : {
471 : /* fork succeeded, in parent */
472 0 : return pm_pid;
473 : }
474 :
475 : /* fork succeeded, in child */
476 :
477 : /*
478 : * Since there might be quotes to handle here, it is easier simply to pass
479 : * everything to a shell to process them. Use exec so that the postmaster
480 : * has the same PID as the current child process.
481 : */
482 0 : if (log_file != NULL)
483 0 : snprintf(cmd, MAXPGPATH, "exec \"%s\" %s%s < \"%s\" >> \"%s\" 2>&1",
484 : exec_path, pgdata_opt, post_opts,
485 : DEVNULL, log_file);
486 : else
487 0 : snprintf(cmd, MAXPGPATH, "exec \"%s\" %s%s < \"%s\" 2>&1",
488 : exec_path, pgdata_opt, post_opts, DEVNULL);
489 :
490 0 : (void) execl("/bin/sh", "/bin/sh", "-c", cmd, (char *) NULL);
491 :
492 : /* exec failed */
493 0 : write_stderr(_("%s: could not start server: %s\n"),
494 0 : progname, strerror(errno));
495 0 : exit(1);
496 :
497 : return 0; /* keep dumb compilers quiet */
498 :
499 : #else /* WIN32 */
500 :
501 : /*
502 : * As with the Unix case, it's easiest to use the shell (CMD.EXE) to
503 : * handle redirection etc. Unfortunately CMD.EXE lacks any equivalent of
504 : * "exec", so we don't get to find out the postmaster's PID immediately.
505 : */
506 : PROCESS_INFORMATION pi;
507 :
508 : if (log_file != NULL)
509 : snprintf(cmd, MAXPGPATH, "CMD /C \"\"%s\" %s%s < \"%s\" >> \"%s\" 2>&1\"",
510 : exec_path, pgdata_opt, post_opts, DEVNULL, log_file);
511 : else
512 : snprintf(cmd, MAXPGPATH, "CMD /C \"\"%s\" %s%s < \"%s\" 2>&1\"",
513 : exec_path, pgdata_opt, post_opts, DEVNULL);
514 :
515 : if (!CreateRestrictedProcess(cmd, &pi, false))
516 : {
517 : write_stderr(_("%s: could not start server: error code %lu\n"),
518 : progname, (unsigned long) GetLastError());
519 : exit(1);
520 : }
521 : /* Don't close command process handle here; caller must do so */
522 : postmasterProcess = pi.hProcess;
523 : CloseHandle(pi.hThread);
524 : return pi.dwProcessId; /* Shell's PID, not postmaster's! */
525 : #endif /* WIN32 */
526 : }
527 :
528 :
529 :
530 : /*
531 : * Wait for the postmaster to become ready.
532 : *
533 : * On Unix, pm_pid is the PID of the just-launched postmaster. On Windows,
534 : * it may be the PID of an ancestor shell process, so we can't check the
535 : * contents of postmaster.pid quite as carefully.
536 : *
537 : * On Windows, the static variable postmasterProcess is an implicit argument
538 : * to this routine; it contains a handle to the postmaster process or an
539 : * ancestor shell process thereof.
540 : *
541 : * Note that the checkpoint parameter enables a Windows service control
542 : * manager checkpoint, it's got nothing to do with database checkpoints!!
543 : */
544 : static WaitPMResult
545 0 : wait_for_postmaster(pgpid_t pm_pid, bool do_checkpoint)
546 : {
547 : int i;
548 :
549 0 : for (i = 0; i < wait_seconds * WAITS_PER_SEC; i++)
550 : {
551 : char **optlines;
552 : int numlines;
553 :
554 : /*
555 : * Try to read the postmaster.pid file. If it's not valid, or if the
556 : * status line isn't there yet, just keep waiting.
557 : */
558 0 : if ((optlines = readfile(pid_file, &numlines)) != NULL &&
559 0 : numlines >= LOCK_FILE_LINE_PM_STATUS)
560 : {
561 : /* File is complete enough for us, parse it */
562 : pgpid_t pmpid;
563 : time_t pmstart;
564 :
565 : /*
566 : * Make sanity checks. If it's for the wrong PID, or the recorded
567 : * start time is before pg_ctl started, then either we are looking
568 : * at the wrong data directory, or this is a pre-existing pidfile
569 : * that hasn't (yet?) been overwritten by our child postmaster.
570 : * Allow 2 seconds slop for possible cross-process clock skew.
571 : */
572 0 : pmpid = atol(optlines[LOCK_FILE_LINE_PID - 1]);
573 0 : pmstart = atol(optlines[LOCK_FILE_LINE_START_TIME - 1]);
574 0 : if (pmstart >= start_time - 2 &&
575 : #ifndef WIN32
576 : pmpid == pm_pid
577 : #else
578 : /* Windows can only reject standalone-backend PIDs */
579 : pmpid > 0
580 : #endif
581 : )
582 : {
583 : /*
584 : * OK, seems to be a valid pidfile from our child. Check the
585 : * status line (this assumes a v10 or later server).
586 : */
587 0 : char *pmstatus = optlines[LOCK_FILE_LINE_PM_STATUS - 1];
588 :
589 0 : if (strcmp(pmstatus, PM_STATUS_READY) == 0 ||
590 0 : strcmp(pmstatus, PM_STATUS_STANDBY) == 0)
591 : {
592 : /* postmaster is done starting up */
593 0 : free_readfile(optlines);
594 0 : return POSTMASTER_READY;
595 : }
596 : }
597 : }
598 :
599 : /*
600 : * Free the results of readfile.
601 : *
602 : * This is safe to call even if optlines is NULL.
603 : */
604 0 : free_readfile(optlines);
605 :
606 : /*
607 : * Check whether the child postmaster process is still alive. This
608 : * lets us exit early if the postmaster fails during startup.
609 : *
610 : * On Windows, we may be checking the postmaster's parent shell, but
611 : * that's fine for this purpose.
612 : */
613 : #ifndef WIN32
614 : {
615 : int exitstatus;
616 :
617 0 : if (waitpid((pid_t) pm_pid, &exitstatus, WNOHANG) == (pid_t) pm_pid)
618 0 : return POSTMASTER_FAILED;
619 : }
620 : #else
621 : if (WaitForSingleObject(postmasterProcess, 0) == WAIT_OBJECT_0)
622 : return POSTMASTER_FAILED;
623 : #endif
624 :
625 : /* Startup still in process; wait, printing a dot once per second */
626 0 : if (i % WAITS_PER_SEC == 0)
627 : {
628 : #ifdef WIN32
629 : if (do_checkpoint)
630 : {
631 : /*
632 : * Increment the wait hint by 6 secs (connection timeout +
633 : * sleep). We must do this to indicate to the SCM that our
634 : * startup time is changing, otherwise it'll usually send a
635 : * stop signal after 20 seconds, despite incrementing the
636 : * checkpoint counter.
637 : */
638 : status.dwWaitHint += 6000;
639 : status.dwCheckPoint++;
640 : SetServiceStatus(hStatus, (LPSERVICE_STATUS) &status);
641 : }
642 : else
643 : #endif
644 0 : print_msg(".");
645 : }
646 :
647 0 : pg_usleep(USEC_PER_SEC / WAITS_PER_SEC);
648 : }
649 :
650 : /* out of patience; report that postmaster is still starting up */
651 0 : return POSTMASTER_STILL_STARTING;
652 : }
653 :
654 :
655 : #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
656 : static void
657 0 : unlimit_core_size(void)
658 : {
659 : struct rlimit lim;
660 :
661 0 : getrlimit(RLIMIT_CORE, &lim);
662 0 : if (lim.rlim_max == 0)
663 : {
664 0 : write_stderr(_("%s: cannot set core file size limit; disallowed by hard limit\n"),
665 : progname);
666 0 : return;
667 : }
668 0 : else if (lim.rlim_max == RLIM_INFINITY || lim.rlim_cur < lim.rlim_max)
669 : {
670 0 : lim.rlim_cur = lim.rlim_max;
671 0 : setrlimit(RLIMIT_CORE, &lim);
672 : }
673 : }
674 : #endif
675 :
676 : static void
677 0 : read_post_opts(void)
678 : {
679 0 : if (post_opts == NULL)
680 : {
681 0 : post_opts = ""; /* default */
682 0 : if (ctl_command == RESTART_COMMAND)
683 : {
684 : char **optlines;
685 : int numlines;
686 :
687 0 : optlines = readfile(postopts_file, &numlines);
688 0 : if (optlines == NULL)
689 : {
690 0 : write_stderr(_("%s: could not read file \"%s\"\n"), progname, postopts_file);
691 0 : exit(1);
692 : }
693 0 : else if (numlines != 1)
694 : {
695 0 : write_stderr(_("%s: option file \"%s\" must have exactly one line\n"),
696 : progname, postopts_file);
697 0 : exit(1);
698 : }
699 : else
700 : {
701 : char *optline;
702 : char *arg1;
703 :
704 0 : optline = optlines[0];
705 :
706 : /*
707 : * Are we at the first option, as defined by space and
708 : * double-quote?
709 : */
710 0 : if ((arg1 = strstr(optline, " \"")) != NULL)
711 : {
712 0 : *arg1 = '\0'; /* terminate so we get only program name */
713 0 : post_opts = pg_strdup(arg1 + 1); /* point past whitespace */
714 : }
715 0 : if (exec_path == NULL)
716 0 : exec_path = pg_strdup(optline);
717 : }
718 :
719 : /* Free the results of readfile. */
720 0 : free_readfile(optlines);
721 : }
722 : }
723 0 : }
724 :
725 : static char *
726 0 : find_other_exec_or_die(const char *argv0, const char *target, const char *versionstr)
727 : {
728 : int ret;
729 : char *found_path;
730 :
731 0 : found_path = pg_malloc(MAXPGPATH);
732 :
733 0 : if ((ret = find_other_exec(argv0, target, versionstr, found_path)) < 0)
734 : {
735 : char full_path[MAXPGPATH];
736 :
737 0 : if (find_my_exec(argv0, full_path) < 0)
738 0 : strlcpy(full_path, progname, sizeof(full_path));
739 :
740 0 : if (ret == -1)
741 0 : write_stderr(_("The program \"%s\" is needed by %s "
742 : "but was not found in the\n"
743 : "same directory as \"%s\".\n"
744 : "Check your installation.\n"),
745 : target, progname, full_path);
746 : else
747 0 : write_stderr(_("The program \"%s\" was found by \"%s\"\n"
748 : "but was not the same version as %s.\n"
749 : "Check your installation.\n"),
750 : target, full_path, progname);
751 0 : exit(1);
752 : }
753 :
754 0 : return found_path;
755 : }
756 :
757 : static void
758 0 : do_init(void)
759 : {
760 : char cmd[MAXPGPATH];
761 :
762 0 : if (exec_path == NULL)
763 0 : exec_path = find_other_exec_or_die(argv0, "initdb", "initdb (PostgreSQL) " PG_VERSION "\n");
764 :
765 0 : if (pgdata_opt == NULL)
766 0 : pgdata_opt = "";
767 :
768 0 : if (post_opts == NULL)
769 0 : post_opts = "";
770 :
771 0 : if (!silent_mode)
772 0 : snprintf(cmd, MAXPGPATH, "\"%s\" %s%s",
773 : exec_path, pgdata_opt, post_opts);
774 : else
775 0 : snprintf(cmd, MAXPGPATH, "\"%s\" %s%s > \"%s\"",
776 : exec_path, pgdata_opt, post_opts, DEVNULL);
777 :
778 0 : if (system(cmd) != 0)
779 : {
780 0 : write_stderr(_("%s: database system initialization failed\n"), progname);
781 0 : exit(1);
782 : }
783 0 : }
784 :
785 : static void
786 0 : do_start(void)
787 : {
788 0 : pgpid_t old_pid = 0;
789 : pgpid_t pm_pid;
790 :
791 0 : if (ctl_command != RESTART_COMMAND)
792 : {
793 0 : old_pid = get_pgpid(false);
794 0 : if (old_pid != 0)
795 0 : write_stderr(_("%s: another server might be running; "
796 : "trying to start server anyway\n"),
797 : progname);
798 : }
799 :
800 0 : read_post_opts();
801 :
802 : /* No -D or -D already added during server start */
803 0 : if (ctl_command == RESTART_COMMAND || pgdata_opt == NULL)
804 0 : pgdata_opt = "";
805 :
806 0 : if (exec_path == NULL)
807 0 : exec_path = find_other_exec_or_die(argv0, "postgres", PG_BACKEND_VERSIONSTR);
808 :
809 : #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
810 0 : if (allow_core_files)
811 0 : unlimit_core_size();
812 : #endif
813 :
814 : /*
815 : * If possible, tell the postmaster our parent shell's PID (see the
816 : * comments in CreateLockFile() for motivation). Windows hasn't got
817 : * getppid() unfortunately.
818 : */
819 : #ifndef WIN32
820 : {
821 : static char env_var[32];
822 :
823 0 : snprintf(env_var, sizeof(env_var), "PG_GRANDPARENT_PID=%d",
824 : (int) getppid());
825 0 : putenv(env_var);
826 : }
827 : #endif
828 :
829 0 : pm_pid = start_postmaster();
830 :
831 0 : if (do_wait)
832 : {
833 0 : print_msg(_("waiting for server to start..."));
834 :
835 0 : switch (wait_for_postmaster(pm_pid, false))
836 : {
837 : case POSTMASTER_READY:
838 0 : print_msg(_(" done\n"));
839 0 : print_msg(_("server started\n"));
840 0 : break;
841 : case POSTMASTER_STILL_STARTING:
842 0 : print_msg(_(" stopped waiting\n"));
843 0 : write_stderr(_("%s: server did not start in time\n"),
844 : progname);
845 0 : exit(1);
846 : break;
847 : case POSTMASTER_FAILED:
848 0 : print_msg(_(" stopped waiting\n"));
849 0 : write_stderr(_("%s: could not start server\n"
850 : "Examine the log output.\n"),
851 : progname);
852 0 : exit(1);
853 : break;
854 : }
855 : }
856 : else
857 0 : print_msg(_("server starting\n"));
858 :
859 : #ifdef WIN32
860 : /* Now we don't need the handle to the shell process anymore */
861 : CloseHandle(postmasterProcess);
862 : postmasterProcess = INVALID_HANDLE_VALUE;
863 : #endif
864 0 : }
865 :
866 :
867 : static void
868 1 : do_stop(void)
869 : {
870 : int cnt;
871 : pgpid_t pid;
872 : struct stat statbuf;
873 :
874 1 : pid = get_pgpid(false);
875 :
876 1 : if (pid == 0) /* no pid file */
877 : {
878 0 : write_stderr(_("%s: PID file \"%s\" does not exist\n"), progname, pid_file);
879 0 : write_stderr(_("Is server running?\n"));
880 0 : exit(1);
881 : }
882 1 : else if (pid < 0) /* standalone backend, not postmaster */
883 : {
884 0 : pid = -pid;
885 0 : write_stderr(_("%s: cannot stop server; "
886 : "single-user server is running (PID: %ld)\n"),
887 : progname, pid);
888 0 : exit(1);
889 : }
890 :
891 1 : if (kill((pid_t) pid, sig) != 0)
892 : {
893 0 : write_stderr(_("%s: could not send stop signal (PID: %ld): %s\n"), progname, pid,
894 0 : strerror(errno));
895 0 : exit(1);
896 : }
897 :
898 1 : if (!do_wait)
899 : {
900 0 : print_msg(_("server shutting down\n"));
901 1 : return;
902 : }
903 : else
904 : {
905 : /*
906 : * If backup_label exists, an online backup is running. Warn the user
907 : * that smart shutdown will wait for it to finish. However, if the
908 : * server is in archive recovery, we're recovering from an online
909 : * backup instead of performing one.
910 : */
911 1 : if (shutdown_mode == SMART_MODE &&
912 0 : stat(backup_file, &statbuf) == 0 &&
913 0 : get_control_dbstate() != DB_IN_ARCHIVE_RECOVERY)
914 : {
915 0 : print_msg(_("WARNING: online backup mode is active\n"
916 : "Shutdown will not complete until pg_stop_backup() is called.\n\n"));
917 : }
918 :
919 1 : print_msg(_("waiting for server to shut down..."));
920 :
921 9 : for (cnt = 0; cnt < wait_seconds * WAITS_PER_SEC; cnt++)
922 : {
923 9 : if ((pid = get_pgpid(false)) != 0)
924 : {
925 8 : if (cnt % WAITS_PER_SEC == 0)
926 1 : print_msg(".");
927 8 : pg_usleep(USEC_PER_SEC / WAITS_PER_SEC);
928 : }
929 : else
930 1 : break;
931 : }
932 :
933 1 : if (pid != 0) /* pid file still exists */
934 : {
935 0 : print_msg(_(" failed\n"));
936 :
937 0 : write_stderr(_("%s: server does not shut down\n"), progname);
938 0 : if (shutdown_mode == SMART_MODE)
939 0 : write_stderr(_("HINT: The \"-m fast\" option immediately disconnects sessions rather than\n"
940 : "waiting for session-initiated disconnection.\n"));
941 0 : exit(1);
942 : }
943 1 : print_msg(_(" done\n"));
944 :
945 1 : print_msg(_("server stopped\n"));
946 : }
947 : }
948 :
949 :
950 : /*
951 : * restart/reload routines
952 : */
953 :
954 : static void
955 0 : do_restart(void)
956 : {
957 : int cnt;
958 : pgpid_t pid;
959 : struct stat statbuf;
960 :
961 0 : pid = get_pgpid(false);
962 :
963 0 : if (pid == 0) /* no pid file */
964 : {
965 0 : write_stderr(_("%s: PID file \"%s\" does not exist\n"),
966 : progname, pid_file);
967 0 : write_stderr(_("Is server running?\n"));
968 0 : write_stderr(_("starting server anyway\n"));
969 0 : do_start();
970 0 : return;
971 : }
972 0 : else if (pid < 0) /* standalone backend, not postmaster */
973 : {
974 0 : pid = -pid;
975 0 : if (postmaster_is_alive((pid_t) pid))
976 : {
977 0 : write_stderr(_("%s: cannot restart server; "
978 : "single-user server is running (PID: %ld)\n"),
979 : progname, pid);
980 0 : write_stderr(_("Please terminate the single-user server and try again.\n"));
981 0 : exit(1);
982 : }
983 : }
984 :
985 0 : if (postmaster_is_alive((pid_t) pid))
986 : {
987 0 : if (kill((pid_t) pid, sig) != 0)
988 : {
989 0 : write_stderr(_("%s: could not send stop signal (PID: %ld): %s\n"), progname, pid,
990 0 : strerror(errno));
991 0 : exit(1);
992 : }
993 :
994 : /*
995 : * If backup_label exists, an online backup is running. Warn the user
996 : * that smart shutdown will wait for it to finish. However, if the
997 : * server is in archive recovery, we're recovering from an online
998 : * backup instead of performing one.
999 : */
1000 0 : if (shutdown_mode == SMART_MODE &&
1001 0 : stat(backup_file, &statbuf) == 0 &&
1002 0 : get_control_dbstate() != DB_IN_ARCHIVE_RECOVERY)
1003 : {
1004 0 : print_msg(_("WARNING: online backup mode is active\n"
1005 : "Shutdown will not complete until pg_stop_backup() is called.\n\n"));
1006 : }
1007 :
1008 0 : print_msg(_("waiting for server to shut down..."));
1009 :
1010 : /* always wait for restart */
1011 :
1012 0 : for (cnt = 0; cnt < wait_seconds * WAITS_PER_SEC; cnt++)
1013 : {
1014 0 : if ((pid = get_pgpid(false)) != 0)
1015 : {
1016 0 : if (cnt % WAITS_PER_SEC == 0)
1017 0 : print_msg(".");
1018 0 : pg_usleep(USEC_PER_SEC / WAITS_PER_SEC);
1019 : }
1020 : else
1021 0 : break;
1022 : }
1023 :
1024 0 : if (pid != 0) /* pid file still exists */
1025 : {
1026 0 : print_msg(_(" failed\n"));
1027 :
1028 0 : write_stderr(_("%s: server does not shut down\n"), progname);
1029 0 : if (shutdown_mode == SMART_MODE)
1030 0 : write_stderr(_("HINT: The \"-m fast\" option immediately disconnects sessions rather than\n"
1031 : "waiting for session-initiated disconnection.\n"));
1032 0 : exit(1);
1033 : }
1034 :
1035 0 : print_msg(_(" done\n"));
1036 0 : print_msg(_("server stopped\n"));
1037 : }
1038 : else
1039 : {
1040 0 : write_stderr(_("%s: old server process (PID: %ld) seems to be gone\n"),
1041 : progname, pid);
1042 0 : write_stderr(_("starting server anyway\n"));
1043 : }
1044 :
1045 0 : do_start();
1046 : }
1047 :
1048 : static void
1049 0 : do_reload(void)
1050 : {
1051 : pgpid_t pid;
1052 :
1053 0 : pid = get_pgpid(false);
1054 0 : if (pid == 0) /* no pid file */
1055 : {
1056 0 : write_stderr(_("%s: PID file \"%s\" does not exist\n"), progname, pid_file);
1057 0 : write_stderr(_("Is server running?\n"));
1058 0 : exit(1);
1059 : }
1060 0 : else if (pid < 0) /* standalone backend, not postmaster */
1061 : {
1062 0 : pid = -pid;
1063 0 : write_stderr(_("%s: cannot reload server; "
1064 : "single-user server is running (PID: %ld)\n"),
1065 : progname, pid);
1066 0 : write_stderr(_("Please terminate the single-user server and try again.\n"));
1067 0 : exit(1);
1068 : }
1069 :
1070 0 : if (kill((pid_t) pid, sig) != 0)
1071 : {
1072 0 : write_stderr(_("%s: could not send reload signal (PID: %ld): %s\n"),
1073 0 : progname, pid, strerror(errno));
1074 0 : exit(1);
1075 : }
1076 :
1077 0 : print_msg(_("server signaled\n"));
1078 0 : }
1079 :
1080 :
1081 : /*
1082 : * promote
1083 : */
1084 :
1085 : static void
1086 0 : do_promote(void)
1087 : {
1088 : FILE *prmfile;
1089 : pgpid_t pid;
1090 :
1091 0 : pid = get_pgpid(false);
1092 :
1093 0 : if (pid == 0) /* no pid file */
1094 : {
1095 0 : write_stderr(_("%s: PID file \"%s\" does not exist\n"), progname, pid_file);
1096 0 : write_stderr(_("Is server running?\n"));
1097 0 : exit(1);
1098 : }
1099 0 : else if (pid < 0) /* standalone backend, not postmaster */
1100 : {
1101 0 : pid = -pid;
1102 0 : write_stderr(_("%s: cannot promote server; "
1103 : "single-user server is running (PID: %ld)\n"),
1104 : progname, pid);
1105 0 : exit(1);
1106 : }
1107 :
1108 0 : if (get_control_dbstate() != DB_IN_ARCHIVE_RECOVERY)
1109 : {
1110 0 : write_stderr(_("%s: cannot promote server; "
1111 : "server is not in standby mode\n"),
1112 : progname);
1113 0 : exit(1);
1114 : }
1115 :
1116 : /*
1117 : * For 9.3 onwards, "fast" promotion is performed. Promotion with a full
1118 : * checkpoint is still possible by writing a file called
1119 : * "fallback_promote" instead of "promote"
1120 : */
1121 0 : snprintf(promote_file, MAXPGPATH, "%s/promote", pg_data);
1122 :
1123 0 : if ((prmfile = fopen(promote_file, "w")) == NULL)
1124 : {
1125 0 : write_stderr(_("%s: could not create promote signal file \"%s\": %s\n"),
1126 0 : progname, promote_file, strerror(errno));
1127 0 : exit(1);
1128 : }
1129 0 : if (fclose(prmfile))
1130 : {
1131 0 : write_stderr(_("%s: could not write promote signal file \"%s\": %s\n"),
1132 0 : progname, promote_file, strerror(errno));
1133 0 : exit(1);
1134 : }
1135 :
1136 0 : sig = SIGUSR1;
1137 0 : if (kill((pid_t) pid, sig) != 0)
1138 : {
1139 0 : write_stderr(_("%s: could not send promote signal (PID: %ld): %s\n"),
1140 0 : progname, pid, strerror(errno));
1141 0 : if (unlink(promote_file) != 0)
1142 0 : write_stderr(_("%s: could not remove promote signal file \"%s\": %s\n"),
1143 0 : progname, promote_file, strerror(errno));
1144 0 : exit(1);
1145 : }
1146 :
1147 0 : if (do_wait)
1148 : {
1149 0 : DBState state = DB_STARTUP;
1150 : int cnt;
1151 :
1152 0 : print_msg(_("waiting for server to promote..."));
1153 0 : for (cnt = 0; cnt < wait_seconds * WAITS_PER_SEC; cnt++)
1154 : {
1155 0 : state = get_control_dbstate();
1156 0 : if (state == DB_IN_PRODUCTION)
1157 0 : break;
1158 :
1159 0 : if (cnt % WAITS_PER_SEC == 0)
1160 0 : print_msg(".");
1161 0 : pg_usleep(USEC_PER_SEC / WAITS_PER_SEC);
1162 : }
1163 0 : if (state == DB_IN_PRODUCTION)
1164 : {
1165 0 : print_msg(_(" done\n"));
1166 0 : print_msg(_("server promoted\n"));
1167 : }
1168 : else
1169 : {
1170 0 : print_msg(_(" stopped waiting\n"));
1171 0 : write_stderr(_("%s: server did not promote in time\n"),
1172 : progname);
1173 0 : exit(1);
1174 : }
1175 : }
1176 : else
1177 0 : print_msg(_("server promoting\n"));
1178 0 : }
1179 :
1180 :
1181 : /*
1182 : * utility routines
1183 : */
1184 :
1185 : static bool
1186 0 : postmaster_is_alive(pid_t pid)
1187 : {
1188 : /*
1189 : * Test to see if the process is still there. Note that we do not
1190 : * consider an EPERM failure to mean that the process is still there;
1191 : * EPERM must mean that the given PID belongs to some other userid, and
1192 : * considering the permissions on $PGDATA, that means it's not the
1193 : * postmaster we are after.
1194 : *
1195 : * Don't believe that our own PID or parent shell's PID is the postmaster,
1196 : * either. (Windows hasn't got getppid(), though.)
1197 : */
1198 0 : if (pid == getpid())
1199 0 : return false;
1200 : #ifndef WIN32
1201 0 : if (pid == getppid())
1202 0 : return false;
1203 : #endif
1204 0 : if (kill(pid, 0) == 0)
1205 0 : return true;
1206 0 : return false;
1207 : }
1208 :
1209 : static void
1210 0 : do_status(void)
1211 : {
1212 : pgpid_t pid;
1213 :
1214 0 : pid = get_pgpid(true);
1215 : /* Is there a pid file? */
1216 0 : if (pid != 0)
1217 : {
1218 : /* standalone backend? */
1219 0 : if (pid < 0)
1220 : {
1221 0 : pid = -pid;
1222 0 : if (postmaster_is_alive((pid_t) pid))
1223 : {
1224 0 : printf(_("%s: single-user server is running (PID: %ld)\n"),
1225 : progname, pid);
1226 0 : return;
1227 : }
1228 : }
1229 : else
1230 : /* must be a postmaster */
1231 : {
1232 0 : if (postmaster_is_alive((pid_t) pid))
1233 : {
1234 : char **optlines;
1235 : char **curr_line;
1236 : int numlines;
1237 :
1238 0 : printf(_("%s: server is running (PID: %ld)\n"),
1239 : progname, pid);
1240 :
1241 0 : optlines = readfile(postopts_file, &numlines);
1242 0 : if (optlines != NULL)
1243 : {
1244 0 : for (curr_line = optlines; *curr_line != NULL; curr_line++)
1245 0 : puts(*curr_line);
1246 :
1247 : /* Free the results of readfile */
1248 0 : free_readfile(optlines);
1249 : }
1250 0 : return;
1251 : }
1252 : }
1253 : }
1254 0 : printf(_("%s: no server running\n"), progname);
1255 :
1256 : /*
1257 : * The Linux Standard Base Core Specification 3.1 says this should return
1258 : * '3, program is not running'
1259 : * https://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html
1260 : */
1261 0 : exit(3);
1262 : }
1263 :
1264 :
1265 :
1266 : static void
1267 0 : do_kill(pgpid_t pid)
1268 : {
1269 0 : if (kill((pid_t) pid, sig) != 0)
1270 : {
1271 0 : write_stderr(_("%s: could not send signal %d (PID: %ld): %s\n"),
1272 0 : progname, sig, pid, strerror(errno));
1273 0 : exit(1);
1274 : }
1275 0 : }
1276 :
1277 : #ifdef WIN32
1278 :
1279 : #if (_MSC_VER < 1800)
1280 : static bool
1281 : IsWindowsXPOrGreater(void)
1282 : {
1283 : OSVERSIONINFO osv;
1284 :
1285 : osv.dwOSVersionInfoSize = sizeof(osv);
1286 :
1287 : /* Windows XP = Version 5.1 */
1288 : return (!GetVersionEx(&osv) || /* could not get version */
1289 : osv.dwMajorVersion > 5 || (osv.dwMajorVersion == 5 && osv.dwMinorVersion >= 1));
1290 : }
1291 :
1292 : static bool
1293 : IsWindows7OrGreater(void)
1294 : {
1295 : OSVERSIONINFO osv;
1296 :
1297 : osv.dwOSVersionInfoSize = sizeof(osv);
1298 :
1299 : /* Windows 7 = Version 6.0 */
1300 : return (!GetVersionEx(&osv) || /* could not get version */
1301 : osv.dwMajorVersion > 6 || (osv.dwMajorVersion == 6 && osv.dwMinorVersion >= 0));
1302 : }
1303 : #endif
1304 :
1305 : static bool
1306 : pgwin32_IsInstalled(SC_HANDLE hSCM)
1307 : {
1308 : SC_HANDLE hService = OpenService(hSCM, register_servicename, SERVICE_QUERY_CONFIG);
1309 : bool bResult = (hService != NULL);
1310 :
1311 : if (bResult)
1312 : CloseServiceHandle(hService);
1313 : return bResult;
1314 : }
1315 :
1316 : static char *
1317 : pgwin32_CommandLine(bool registration)
1318 : {
1319 : PQExpBuffer cmdLine = createPQExpBuffer();
1320 : char cmdPath[MAXPGPATH];
1321 : int ret;
1322 :
1323 : if (registration)
1324 : {
1325 : ret = find_my_exec(argv0, cmdPath);
1326 : if (ret != 0)
1327 : {
1328 : write_stderr(_("%s: could not find own program executable\n"), progname);
1329 : exit(1);
1330 : }
1331 : }
1332 : else
1333 : {
1334 : ret = find_other_exec(argv0, "postgres", PG_BACKEND_VERSIONSTR,
1335 : cmdPath);
1336 : if (ret != 0)
1337 : {
1338 : write_stderr(_("%s: could not find postgres program executable\n"), progname);
1339 : exit(1);
1340 : }
1341 : }
1342 :
1343 : /* if path does not end in .exe, append it */
1344 : if (strlen(cmdPath) < 4 ||
1345 : pg_strcasecmp(cmdPath + strlen(cmdPath) - 4, ".exe") != 0)
1346 : snprintf(cmdPath + strlen(cmdPath), sizeof(cmdPath) - strlen(cmdPath),
1347 : ".exe");
1348 :
1349 : /* use backslashes in path to avoid problems with some third-party tools */
1350 : make_native_path(cmdPath);
1351 :
1352 : /* be sure to double-quote the executable's name in the command */
1353 : appendPQExpBuffer(cmdLine, "\"%s\"", cmdPath);
1354 :
1355 : /* append assorted switches to the command line, as needed */
1356 :
1357 : if (registration)
1358 : appendPQExpBuffer(cmdLine, " runservice -N \"%s\"",
1359 : register_servicename);
1360 :
1361 : if (pg_config)
1362 : {
1363 : /* We need the -D path to be absolute */
1364 : char *dataDir;
1365 :
1366 : if ((dataDir = make_absolute_path(pg_config)) == NULL)
1367 : {
1368 : /* make_absolute_path already reported the error */
1369 : exit(1);
1370 : }
1371 : make_native_path(dataDir);
1372 : appendPQExpBuffer(cmdLine, " -D \"%s\"", dataDir);
1373 : free(dataDir);
1374 : }
1375 :
1376 : if (registration && event_source != NULL)
1377 : appendPQExpBuffer(cmdLine, " -e \"%s\"", event_source);
1378 :
1379 : if (registration && do_wait)
1380 : appendPQExpBuffer(cmdLine, " -w");
1381 :
1382 : /* Don't propagate a value from an environment variable. */
1383 : if (registration && wait_seconds_arg && wait_seconds != DEFAULT_WAIT)
1384 : appendPQExpBuffer(cmdLine, " -t %d", wait_seconds);
1385 :
1386 : if (registration && silent_mode)
1387 : appendPQExpBuffer(cmdLine, " -s");
1388 :
1389 : if (post_opts)
1390 : {
1391 : if (registration)
1392 : appendPQExpBuffer(cmdLine, " -o \"%s\"", post_opts);
1393 : else
1394 : appendPQExpBuffer(cmdLine, " %s", post_opts);
1395 : }
1396 :
1397 : return cmdLine->data;
1398 : }
1399 :
1400 : static void
1401 : pgwin32_doRegister(void)
1402 : {
1403 : SC_HANDLE hService;
1404 : SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
1405 :
1406 : if (hSCM == NULL)
1407 : {
1408 : write_stderr(_("%s: could not open service manager\n"), progname);
1409 : exit(1);
1410 : }
1411 : if (pgwin32_IsInstalled(hSCM))
1412 : {
1413 : CloseServiceHandle(hSCM);
1414 : write_stderr(_("%s: service \"%s\" already registered\n"), progname, register_servicename);
1415 : exit(1);
1416 : }
1417 :
1418 : if ((hService = CreateService(hSCM, register_servicename, register_servicename,
1419 : SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
1420 : pgctl_start_type, SERVICE_ERROR_NORMAL,
1421 : pgwin32_CommandLine(true),
1422 : NULL, NULL, "RPCSS\0", register_username, register_password)) == NULL)
1423 : {
1424 : CloseServiceHandle(hSCM);
1425 : write_stderr(_("%s: could not register service \"%s\": error code %lu\n"),
1426 : progname, register_servicename,
1427 : (unsigned long) GetLastError());
1428 : exit(1);
1429 : }
1430 : CloseServiceHandle(hService);
1431 : CloseServiceHandle(hSCM);
1432 : }
1433 :
1434 : static void
1435 : pgwin32_doUnregister(void)
1436 : {
1437 : SC_HANDLE hService;
1438 : SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
1439 :
1440 : if (hSCM == NULL)
1441 : {
1442 : write_stderr(_("%s: could not open service manager\n"), progname);
1443 : exit(1);
1444 : }
1445 : if (!pgwin32_IsInstalled(hSCM))
1446 : {
1447 : CloseServiceHandle(hSCM);
1448 : write_stderr(_("%s: service \"%s\" not registered\n"), progname, register_servicename);
1449 : exit(1);
1450 : }
1451 :
1452 : if ((hService = OpenService(hSCM, register_servicename, DELETE)) == NULL)
1453 : {
1454 : CloseServiceHandle(hSCM);
1455 : write_stderr(_("%s: could not open service \"%s\": error code %lu\n"),
1456 : progname, register_servicename,
1457 : (unsigned long) GetLastError());
1458 : exit(1);
1459 : }
1460 : if (!DeleteService(hService))
1461 : {
1462 : CloseServiceHandle(hService);
1463 : CloseServiceHandle(hSCM);
1464 : write_stderr(_("%s: could not unregister service \"%s\": error code %lu\n"),
1465 : progname, register_servicename,
1466 : (unsigned long) GetLastError());
1467 : exit(1);
1468 : }
1469 : CloseServiceHandle(hService);
1470 : CloseServiceHandle(hSCM);
1471 : }
1472 :
1473 : static void
1474 : pgwin32_SetServiceStatus(DWORD currentState)
1475 : {
1476 : status.dwCurrentState = currentState;
1477 : SetServiceStatus(hStatus, (LPSERVICE_STATUS) &status);
1478 : }
1479 :
1480 : static void WINAPI
1481 : pgwin32_ServiceHandler(DWORD request)
1482 : {
1483 : switch (request)
1484 : {
1485 : case SERVICE_CONTROL_STOP:
1486 : case SERVICE_CONTROL_SHUTDOWN:
1487 :
1488 : /*
1489 : * We only need a short wait hint here as it just needs to wait
1490 : * for the next checkpoint. They occur every 5 seconds during
1491 : * shutdown
1492 : */
1493 : status.dwWaitHint = 10000;
1494 : pgwin32_SetServiceStatus(SERVICE_STOP_PENDING);
1495 : SetEvent(shutdownEvent);
1496 : return;
1497 :
1498 : case SERVICE_CONTROL_PAUSE:
1499 : /* Win32 config reloading */
1500 : status.dwWaitHint = 5000;
1501 : kill(postmasterPID, SIGHUP);
1502 : return;
1503 :
1504 : /* FIXME: These could be used to replace other signals etc */
1505 : case SERVICE_CONTROL_CONTINUE:
1506 : case SERVICE_CONTROL_INTERROGATE:
1507 : default:
1508 : break;
1509 : }
1510 : }
1511 :
1512 : static void WINAPI
1513 : pgwin32_ServiceMain(DWORD argc, LPTSTR *argv)
1514 : {
1515 : PROCESS_INFORMATION pi;
1516 : DWORD ret;
1517 :
1518 : /* Initialize variables */
1519 : status.dwWin32ExitCode = S_OK;
1520 : status.dwCheckPoint = 0;
1521 : status.dwWaitHint = 60000;
1522 : status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
1523 : status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_PAUSE_CONTINUE;
1524 : status.dwServiceSpecificExitCode = 0;
1525 : status.dwCurrentState = SERVICE_START_PENDING;
1526 :
1527 : memset(&pi, 0, sizeof(pi));
1528 :
1529 : read_post_opts();
1530 :
1531 : /* Register the control request handler */
1532 : if ((hStatus = RegisterServiceCtrlHandler(register_servicename, pgwin32_ServiceHandler)) == (SERVICE_STATUS_HANDLE) 0)
1533 : return;
1534 :
1535 : if ((shutdownEvent = CreateEvent(NULL, true, false, NULL)) == NULL)
1536 : return;
1537 :
1538 : /* Start the postmaster */
1539 : pgwin32_SetServiceStatus(SERVICE_START_PENDING);
1540 : if (!CreateRestrictedProcess(pgwin32_CommandLine(false), &pi, true))
1541 : {
1542 : pgwin32_SetServiceStatus(SERVICE_STOPPED);
1543 : return;
1544 : }
1545 : postmasterPID = pi.dwProcessId;
1546 : postmasterProcess = pi.hProcess;
1547 : CloseHandle(pi.hThread);
1548 :
1549 : if (do_wait)
1550 : {
1551 : write_eventlog(EVENTLOG_INFORMATION_TYPE, _("Waiting for server startup...\n"));
1552 : if (wait_for_postmaster(postmasterPID, true) != POSTMASTER_READY)
1553 : {
1554 : write_eventlog(EVENTLOG_ERROR_TYPE, _("Timed out waiting for server startup\n"));
1555 : pgwin32_SetServiceStatus(SERVICE_STOPPED);
1556 : return;
1557 : }
1558 : write_eventlog(EVENTLOG_INFORMATION_TYPE, _("Server started and accepting connections\n"));
1559 : }
1560 :
1561 : pgwin32_SetServiceStatus(SERVICE_RUNNING);
1562 :
1563 : /* Wait for quit... */
1564 : ret = WaitForMultipleObjects(2, shutdownHandles, FALSE, INFINITE);
1565 :
1566 : pgwin32_SetServiceStatus(SERVICE_STOP_PENDING);
1567 : switch (ret)
1568 : {
1569 : case WAIT_OBJECT_0: /* shutdown event */
1570 : {
1571 : /*
1572 : * status.dwCheckPoint can be incremented by
1573 : * wait_for_postmaster(), so it might not start from 0.
1574 : */
1575 : int maxShutdownCheckPoint = status.dwCheckPoint + 12;
1576 :
1577 : kill(postmasterPID, SIGINT);
1578 :
1579 : /*
1580 : * Increment the checkpoint and try again. Abort after 12
1581 : * checkpoints as the postmaster has probably hung.
1582 : */
1583 : while (WaitForSingleObject(postmasterProcess, 5000) == WAIT_TIMEOUT && status.dwCheckPoint < maxShutdownCheckPoint)
1584 : {
1585 : status.dwCheckPoint++;
1586 : SetServiceStatus(hStatus, (LPSERVICE_STATUS) &status);
1587 : }
1588 : break;
1589 : }
1590 :
1591 : case (WAIT_OBJECT_0 + 1): /* postmaster went down */
1592 : break;
1593 :
1594 : default:
1595 : /* shouldn't get here? */
1596 : break;
1597 : }
1598 :
1599 : CloseHandle(shutdownEvent);
1600 : CloseHandle(postmasterProcess);
1601 :
1602 : pgwin32_SetServiceStatus(SERVICE_STOPPED);
1603 : }
1604 :
1605 : static void
1606 : pgwin32_doRunAsService(void)
1607 : {
1608 : SERVICE_TABLE_ENTRY st[] = {{register_servicename, pgwin32_ServiceMain},
1609 : {NULL, NULL}};
1610 :
1611 : if (StartServiceCtrlDispatcher(st) == 0)
1612 : {
1613 : write_stderr(_("%s: could not start service \"%s\": error code %lu\n"),
1614 : progname, register_servicename,
1615 : (unsigned long) GetLastError());
1616 : exit(1);
1617 : }
1618 : }
1619 :
1620 :
1621 : /*
1622 : * Mingw headers are incomplete, and so are the libraries. So we have to load
1623 : * a whole lot of API functions dynamically. Since we have to do this anyway,
1624 : * also load the couple of functions that *do* exist in minwg headers but not
1625 : * on NT4. That way, we don't break on NT4.
1626 : */
1627 : typedef BOOL (WINAPI * __CreateRestrictedToken) (HANDLE, DWORD, DWORD, PSID_AND_ATTRIBUTES, DWORD, PLUID_AND_ATTRIBUTES, DWORD, PSID_AND_ATTRIBUTES, PHANDLE);
1628 : typedef BOOL (WINAPI * __IsProcessInJob) (HANDLE, HANDLE, PBOOL);
1629 : typedef HANDLE (WINAPI * __CreateJobObject) (LPSECURITY_ATTRIBUTES, LPCTSTR);
1630 : typedef BOOL (WINAPI * __SetInformationJobObject) (HANDLE, JOBOBJECTINFOCLASS, LPVOID, DWORD);
1631 : typedef BOOL (WINAPI * __AssignProcessToJobObject) (HANDLE, HANDLE);
1632 : typedef BOOL (WINAPI * __QueryInformationJobObject) (HANDLE, JOBOBJECTINFOCLASS, LPVOID, DWORD, LPDWORD);
1633 :
1634 : /* Windows API define missing from some versions of MingW headers */
1635 : #ifndef DISABLE_MAX_PRIVILEGE
1636 : #define DISABLE_MAX_PRIVILEGE 0x1
1637 : #endif
1638 :
1639 : /*
1640 : * Create a restricted token, a job object sandbox, and execute the specified
1641 : * process with it.
1642 : *
1643 : * Returns 0 on success, non-zero on failure, same as CreateProcess().
1644 : *
1645 : * On NT4, or any other system not containing the required functions, will
1646 : * launch the process under the current token without doing any modifications.
1647 : *
1648 : * NOTE! Job object will only work when running as a service, because it's
1649 : * automatically destroyed when pg_ctl exits.
1650 : */
1651 : static int
1652 : CreateRestrictedProcess(char *cmd, PROCESS_INFORMATION *processInfo, bool as_service)
1653 : {
1654 : int r;
1655 : BOOL b;
1656 : STARTUPINFO si;
1657 : HANDLE origToken;
1658 : HANDLE restrictedToken;
1659 : SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
1660 : SID_AND_ATTRIBUTES dropSids[2];
1661 :
1662 : /* Functions loaded dynamically */
1663 : __CreateRestrictedToken _CreateRestrictedToken = NULL;
1664 : __IsProcessInJob _IsProcessInJob = NULL;
1665 : __CreateJobObject _CreateJobObject = NULL;
1666 : __SetInformationJobObject _SetInformationJobObject = NULL;
1667 : __AssignProcessToJobObject _AssignProcessToJobObject = NULL;
1668 : __QueryInformationJobObject _QueryInformationJobObject = NULL;
1669 : HANDLE Kernel32Handle;
1670 : HANDLE Advapi32Handle;
1671 :
1672 : ZeroMemory(&si, sizeof(si));
1673 : si.cb = sizeof(si);
1674 :
1675 : Advapi32Handle = LoadLibrary("ADVAPI32.DLL");
1676 : if (Advapi32Handle != NULL)
1677 : {
1678 : _CreateRestrictedToken = (__CreateRestrictedToken) GetProcAddress(Advapi32Handle, "CreateRestrictedToken");
1679 : }
1680 :
1681 : if (_CreateRestrictedToken == NULL)
1682 : {
1683 : /*
1684 : * NT4 doesn't have CreateRestrictedToken, so just call ordinary
1685 : * CreateProcess
1686 : */
1687 : write_stderr(_("%s: WARNING: cannot create restricted tokens on this platform\n"), progname);
1688 : if (Advapi32Handle != NULL)
1689 : FreeLibrary(Advapi32Handle);
1690 : return CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, processInfo);
1691 : }
1692 :
1693 : /* Open the current token to use as a base for the restricted one */
1694 : if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &origToken))
1695 : {
1696 : /*
1697 : * Most Windows targets make DWORD a 32-bit unsigned long, but in case
1698 : * it doesn't cast DWORD before printing.
1699 : */
1700 : write_stderr(_("%s: could not open process token: error code %lu\n"),
1701 : progname, (unsigned long) GetLastError());
1702 : return 0;
1703 : }
1704 :
1705 : /* Allocate list of SIDs to remove */
1706 : ZeroMemory(&dropSids, sizeof(dropSids));
1707 : if (!AllocateAndInitializeSid(&NtAuthority, 2,
1708 : SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0,
1709 : 0, &dropSids[0].Sid) ||
1710 : !AllocateAndInitializeSid(&NtAuthority, 2,
1711 : SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0,
1712 : 0, &dropSids[1].Sid))
1713 : {
1714 : write_stderr(_("%s: could not allocate SIDs: error code %lu\n"),
1715 : progname, (unsigned long) GetLastError());
1716 : return 0;
1717 : }
1718 :
1719 : b = _CreateRestrictedToken(origToken,
1720 : DISABLE_MAX_PRIVILEGE,
1721 : sizeof(dropSids) / sizeof(dropSids[0]),
1722 : dropSids,
1723 : 0, NULL,
1724 : 0, NULL,
1725 : &restrictedToken);
1726 :
1727 : FreeSid(dropSids[1].Sid);
1728 : FreeSid(dropSids[0].Sid);
1729 : CloseHandle(origToken);
1730 : FreeLibrary(Advapi32Handle);
1731 :
1732 : if (!b)
1733 : {
1734 : write_stderr(_("%s: could not create restricted token: error code %lu\n"),
1735 : progname, (unsigned long) GetLastError());
1736 : return 0;
1737 : }
1738 :
1739 : AddUserToTokenDacl(restrictedToken);
1740 : r = CreateProcessAsUser(restrictedToken, NULL, cmd, NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, NULL, &si, processInfo);
1741 :
1742 : Kernel32Handle = LoadLibrary("KERNEL32.DLL");
1743 : if (Kernel32Handle != NULL)
1744 : {
1745 : _IsProcessInJob = (__IsProcessInJob) GetProcAddress(Kernel32Handle, "IsProcessInJob");
1746 : _CreateJobObject = (__CreateJobObject) GetProcAddress(Kernel32Handle, "CreateJobObjectA");
1747 : _SetInformationJobObject = (__SetInformationJobObject) GetProcAddress(Kernel32Handle, "SetInformationJobObject");
1748 : _AssignProcessToJobObject = (__AssignProcessToJobObject) GetProcAddress(Kernel32Handle, "AssignProcessToJobObject");
1749 : _QueryInformationJobObject = (__QueryInformationJobObject) GetProcAddress(Kernel32Handle, "QueryInformationJobObject");
1750 : }
1751 :
1752 : /* Verify that we found all functions */
1753 : if (_IsProcessInJob == NULL || _CreateJobObject == NULL || _SetInformationJobObject == NULL || _AssignProcessToJobObject == NULL || _QueryInformationJobObject == NULL)
1754 : {
1755 : /*
1756 : * IsProcessInJob() is not available on < WinXP, so there is no need
1757 : * to log the error every time in that case
1758 : */
1759 : if (IsWindowsXPOrGreater())
1760 :
1761 : /*
1762 : * Log error if we can't get version, or if we're on WinXP/2003 or
1763 : * newer
1764 : */
1765 : write_stderr(_("%s: WARNING: could not locate all job object functions in system API\n"), progname);
1766 : }
1767 : else
1768 : {
1769 : BOOL inJob;
1770 :
1771 : if (_IsProcessInJob(processInfo->hProcess, NULL, &inJob))
1772 : {
1773 : if (!inJob)
1774 : {
1775 : /*
1776 : * Job objects are working, and the new process isn't in one,
1777 : * so we can create one safely. If any problems show up when
1778 : * setting it, we're going to ignore them.
1779 : */
1780 : HANDLE job;
1781 : char jobname[128];
1782 :
1783 : sprintf(jobname, "PostgreSQL_%lu",
1784 : (unsigned long) processInfo->dwProcessId);
1785 :
1786 : job = _CreateJobObject(NULL, jobname);
1787 : if (job)
1788 : {
1789 : JOBOBJECT_BASIC_LIMIT_INFORMATION basicLimit;
1790 : JOBOBJECT_BASIC_UI_RESTRICTIONS uiRestrictions;
1791 : JOBOBJECT_SECURITY_LIMIT_INFORMATION securityLimit;
1792 :
1793 : ZeroMemory(&basicLimit, sizeof(basicLimit));
1794 : ZeroMemory(&uiRestrictions, sizeof(uiRestrictions));
1795 : ZeroMemory(&securityLimit, sizeof(securityLimit));
1796 :
1797 : basicLimit.LimitFlags = JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION | JOB_OBJECT_LIMIT_PRIORITY_CLASS;
1798 : basicLimit.PriorityClass = NORMAL_PRIORITY_CLASS;
1799 : _SetInformationJobObject(job, JobObjectBasicLimitInformation, &basicLimit, sizeof(basicLimit));
1800 :
1801 : uiRestrictions.UIRestrictionsClass = JOB_OBJECT_UILIMIT_DESKTOP | JOB_OBJECT_UILIMIT_DISPLAYSETTINGS |
1802 : JOB_OBJECT_UILIMIT_EXITWINDOWS | JOB_OBJECT_UILIMIT_READCLIPBOARD |
1803 : JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS | JOB_OBJECT_UILIMIT_WRITECLIPBOARD;
1804 :
1805 : if (as_service)
1806 : {
1807 : if (!IsWindows7OrGreater())
1808 : {
1809 : /*
1810 : * On Windows 7 (and presumably later),
1811 : * JOB_OBJECT_UILIMIT_HANDLES prevents us from
1812 : * starting as a service. So we only enable it on
1813 : * Vista and earlier (version <= 6.0)
1814 : */
1815 : uiRestrictions.UIRestrictionsClass |= JOB_OBJECT_UILIMIT_HANDLES;
1816 : }
1817 : }
1818 : _SetInformationJobObject(job, JobObjectBasicUIRestrictions, &uiRestrictions, sizeof(uiRestrictions));
1819 :
1820 : securityLimit.SecurityLimitFlags = JOB_OBJECT_SECURITY_NO_ADMIN | JOB_OBJECT_SECURITY_ONLY_TOKEN;
1821 : securityLimit.JobToken = restrictedToken;
1822 : _SetInformationJobObject(job, JobObjectSecurityLimitInformation, &securityLimit, sizeof(securityLimit));
1823 :
1824 : _AssignProcessToJobObject(job, processInfo->hProcess);
1825 : }
1826 : }
1827 : }
1828 : }
1829 :
1830 :
1831 : CloseHandle(restrictedToken);
1832 :
1833 : ResumeThread(processInfo->hThread);
1834 :
1835 : FreeLibrary(Kernel32Handle);
1836 :
1837 : /*
1838 : * We intentionally don't close the job object handle, because we want the
1839 : * object to live on until pg_ctl shuts down.
1840 : */
1841 : return r;
1842 : }
1843 : #endif /* WIN32 */
1844 :
1845 : static void
1846 0 : do_advice(void)
1847 : {
1848 0 : write_stderr(_("Try \"%s --help\" for more information.\n"), progname);
1849 0 : }
1850 :
1851 :
1852 :
1853 : static void
1854 0 : do_help(void)
1855 : {
1856 0 : printf(_("%s is a utility to initialize, start, stop, or control a PostgreSQL server.\n\n"), progname);
1857 0 : printf(_("Usage:\n"));
1858 0 : printf(_(" %s init[db] [-D DATADIR] [-s] [-o OPTIONS]\n"), progname);
1859 0 : printf(_(" %s start [-D DATADIR] [-l FILENAME] [-W] [-t SECS] [-s]\n"
1860 : " [-o OPTIONS] [-p PATH] [-c]\n"), progname);
1861 0 : printf(_(" %s stop [-D DATADIR] [-m SHUTDOWN-MODE] [-W] [-t SECS] [-s]\n"), progname);
1862 0 : printf(_(" %s restart [-D DATADIR] [-m SHUTDOWN-MODE] [-W] [-t SECS] [-s]\n"
1863 : " [-o OPTIONS] [-c]\n"), progname);
1864 0 : printf(_(" %s reload [-D DATADIR] [-s]\n"), progname);
1865 0 : printf(_(" %s status [-D DATADIR]\n"), progname);
1866 0 : printf(_(" %s promote [-D DATADIR] [-W] [-t SECS] [-s]\n"), progname);
1867 0 : printf(_(" %s kill SIGNALNAME PID\n"), progname);
1868 : #ifdef WIN32
1869 : printf(_(" %s register [-D DATADIR] [-N SERVICENAME] [-U USERNAME] [-P PASSWORD]\n"
1870 : " [-S START-TYPE] [-e SOURCE] [-W] [-t SECS] [-s] [-o OPTIONS]\n"), progname);
1871 : printf(_(" %s unregister [-N SERVICENAME]\n"), progname);
1872 : #endif
1873 :
1874 0 : printf(_("\nCommon options:\n"));
1875 0 : printf(_(" -D, --pgdata=DATADIR location of the database storage area\n"));
1876 : #ifdef WIN32
1877 : printf(_(" -e SOURCE event source for logging when running as a service\n"));
1878 : #endif
1879 0 : printf(_(" -s, --silent only print errors, no informational messages\n"));
1880 0 : printf(_(" -t, --timeout=SECS seconds to wait when using -w option\n"));
1881 0 : printf(_(" -V, --version output version information, then exit\n"));
1882 0 : printf(_(" -w, --wait wait until operation completes (default)\n"));
1883 0 : printf(_(" -W, --no-wait do not wait until operation completes\n"));
1884 0 : printf(_(" -?, --help show this help, then exit\n"));
1885 0 : printf(_("If the -D option is omitted, the environment variable PGDATA is used.\n"));
1886 :
1887 0 : printf(_("\nOptions for start or restart:\n"));
1888 : #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
1889 0 : printf(_(" -c, --core-files allow postgres to produce core files\n"));
1890 : #else
1891 : printf(_(" -c, --core-files not applicable on this platform\n"));
1892 : #endif
1893 0 : printf(_(" -l, --log=FILENAME write (or append) server log to FILENAME\n"));
1894 0 : printf(_(" -o, --options=OPTIONS command line options to pass to postgres\n"
1895 : " (PostgreSQL server executable) or initdb\n"));
1896 0 : printf(_(" -p PATH-TO-POSTGRES normally not necessary\n"));
1897 0 : printf(_("\nOptions for stop or restart:\n"));
1898 0 : printf(_(" -m, --mode=MODE MODE can be \"smart\", \"fast\", or \"immediate\"\n"));
1899 :
1900 0 : printf(_("\nShutdown modes are:\n"));
1901 0 : printf(_(" smart quit after all clients have disconnected\n"));
1902 0 : printf(_(" fast quit directly, with proper shutdown (default)\n"));
1903 0 : printf(_(" immediate quit without complete shutdown; will lead to recovery on restart\n"));
1904 :
1905 0 : printf(_("\nAllowed signal names for kill:\n"));
1906 0 : printf(" ABRT HUP INT QUIT TERM USR1 USR2\n");
1907 :
1908 : #ifdef WIN32
1909 : printf(_("\nOptions for register and unregister:\n"));
1910 : printf(_(" -N SERVICENAME service name with which to register PostgreSQL server\n"));
1911 : printf(_(" -P PASSWORD password of account to register PostgreSQL server\n"));
1912 : printf(_(" -U USERNAME user name of account to register PostgreSQL server\n"));
1913 : printf(_(" -S START-TYPE service start type to register PostgreSQL server\n"));
1914 :
1915 : printf(_("\nStart types are:\n"));
1916 : printf(_(" auto start service automatically during system startup (default)\n"));
1917 : printf(_(" demand start service on demand\n"));
1918 : #endif
1919 :
1920 0 : printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
1921 0 : }
1922 :
1923 :
1924 :
1925 : static void
1926 0 : set_mode(char *modeopt)
1927 : {
1928 0 : if (strcmp(modeopt, "s") == 0 || strcmp(modeopt, "smart") == 0)
1929 : {
1930 0 : shutdown_mode = SMART_MODE;
1931 0 : sig = SIGTERM;
1932 : }
1933 0 : else if (strcmp(modeopt, "f") == 0 || strcmp(modeopt, "fast") == 0)
1934 : {
1935 0 : shutdown_mode = FAST_MODE;
1936 0 : sig = SIGINT;
1937 : }
1938 0 : else if (strcmp(modeopt, "i") == 0 || strcmp(modeopt, "immediate") == 0)
1939 : {
1940 0 : shutdown_mode = IMMEDIATE_MODE;
1941 0 : sig = SIGQUIT;
1942 : }
1943 : else
1944 : {
1945 0 : write_stderr(_("%s: unrecognized shutdown mode \"%s\"\n"), progname, modeopt);
1946 0 : do_advice();
1947 0 : exit(1);
1948 : }
1949 0 : }
1950 :
1951 :
1952 :
1953 : static void
1954 0 : set_sig(char *signame)
1955 : {
1956 0 : if (strcmp(signame, "HUP") == 0)
1957 0 : sig = SIGHUP;
1958 0 : else if (strcmp(signame, "INT") == 0)
1959 0 : sig = SIGINT;
1960 0 : else if (strcmp(signame, "QUIT") == 0)
1961 0 : sig = SIGQUIT;
1962 0 : else if (strcmp(signame, "ABRT") == 0)
1963 0 : sig = SIGABRT;
1964 : #if 0
1965 : /* probably should NOT provide SIGKILL */
1966 : else if (strcmp(signame, "KILL") == 0)
1967 : sig = SIGKILL;
1968 : #endif
1969 0 : else if (strcmp(signame, "TERM") == 0)
1970 0 : sig = SIGTERM;
1971 0 : else if (strcmp(signame, "USR1") == 0)
1972 0 : sig = SIGUSR1;
1973 0 : else if (strcmp(signame, "USR2") == 0)
1974 0 : sig = SIGUSR2;
1975 : else
1976 : {
1977 0 : write_stderr(_("%s: unrecognized signal name \"%s\"\n"), progname, signame);
1978 0 : do_advice();
1979 0 : exit(1);
1980 : }
1981 0 : }
1982 :
1983 :
1984 : #ifdef WIN32
1985 : static void
1986 : set_starttype(char *starttypeopt)
1987 : {
1988 : if (strcmp(starttypeopt, "a") == 0 || strcmp(starttypeopt, "auto") == 0)
1989 : pgctl_start_type = SERVICE_AUTO_START;
1990 : else if (strcmp(starttypeopt, "d") == 0 || strcmp(starttypeopt, "demand") == 0)
1991 : pgctl_start_type = SERVICE_DEMAND_START;
1992 : else
1993 : {
1994 : write_stderr(_("%s: unrecognized start type \"%s\"\n"), progname, starttypeopt);
1995 : do_advice();
1996 : exit(1);
1997 : }
1998 : }
1999 : #endif
2000 :
2001 : /*
2002 : * adjust_data_dir
2003 : *
2004 : * If a configuration-only directory was specified, find the real data dir.
2005 : */
2006 : static void
2007 1 : adjust_data_dir(void)
2008 : {
2009 : char cmd[MAXPGPATH],
2010 : filename[MAXPGPATH],
2011 : *my_exec_path;
2012 : FILE *fd;
2013 :
2014 : /* do nothing if we're working without knowledge of data dir */
2015 1 : if (pg_config == NULL)
2016 1 : return;
2017 :
2018 : /* If there is no postgresql.conf, it can't be a config-only dir */
2019 1 : snprintf(filename, sizeof(filename), "%s/postgresql.conf", pg_config);
2020 1 : if ((fd = fopen(filename, "r")) == NULL)
2021 0 : return;
2022 1 : fclose(fd);
2023 :
2024 : /* If PG_VERSION exists, it can't be a config-only dir */
2025 1 : snprintf(filename, sizeof(filename), "%s/PG_VERSION", pg_config);
2026 1 : if ((fd = fopen(filename, "r")) != NULL)
2027 : {
2028 1 : fclose(fd);
2029 1 : return;
2030 : }
2031 :
2032 : /* Must be a configuration directory, so find the data directory */
2033 :
2034 : /* we use a private my_exec_path to avoid interfering with later uses */
2035 0 : if (exec_path == NULL)
2036 0 : my_exec_path = find_other_exec_or_die(argv0, "postgres", PG_BACKEND_VERSIONSTR);
2037 : else
2038 0 : my_exec_path = pg_strdup(exec_path);
2039 :
2040 : /* it's important for -C to be the first option, see main.c */
2041 0 : snprintf(cmd, MAXPGPATH, "\"%s\" -C data_directory %s%s",
2042 : my_exec_path,
2043 0 : pgdata_opt ? pgdata_opt : "",
2044 0 : post_opts ? post_opts : "");
2045 :
2046 0 : fd = popen(cmd, "r");
2047 0 : if (fd == NULL || fgets(filename, sizeof(filename), fd) == NULL)
2048 : {
2049 0 : write_stderr(_("%s: could not determine the data directory using command \"%s\"\n"), progname, cmd);
2050 0 : exit(1);
2051 : }
2052 0 : pclose(fd);
2053 0 : free(my_exec_path);
2054 :
2055 : /* Remove trailing newline */
2056 0 : if (strchr(filename, '\n') != NULL)
2057 0 : *strchr(filename, '\n') = '\0';
2058 :
2059 0 : free(pg_data);
2060 0 : pg_data = pg_strdup(filename);
2061 0 : canonicalize_path(pg_data);
2062 : }
2063 :
2064 :
2065 : static DBState
2066 0 : get_control_dbstate(void)
2067 : {
2068 : DBState ret;
2069 : bool crc_ok;
2070 0 : ControlFileData *control_file_data = get_controlfile(pg_data, progname, &crc_ok);
2071 :
2072 0 : if (!crc_ok)
2073 : {
2074 0 : write_stderr(_("%s: control file appears to be corrupt\n"), progname);
2075 0 : exit(1);
2076 : }
2077 :
2078 0 : ret = control_file_data->state;
2079 0 : pfree(control_file_data);
2080 0 : return ret;
2081 : }
2082 :
2083 :
2084 : int
2085 1 : main(int argc, char **argv)
2086 : {
2087 : static struct option long_options[] = {
2088 : {"help", no_argument, NULL, '?'},
2089 : {"version", no_argument, NULL, 'V'},
2090 : {"log", required_argument, NULL, 'l'},
2091 : {"mode", required_argument, NULL, 'm'},
2092 : {"pgdata", required_argument, NULL, 'D'},
2093 : {"options", required_argument, NULL, 'o'},
2094 : {"silent", no_argument, NULL, 's'},
2095 : {"timeout", required_argument, NULL, 't'},
2096 : {"core-files", no_argument, NULL, 'c'},
2097 : {"wait", no_argument, NULL, 'w'},
2098 : {"no-wait", no_argument, NULL, 'W'},
2099 : {NULL, 0, NULL, 0}
2100 : };
2101 :
2102 : char *env_wait;
2103 : int option_index;
2104 : int c;
2105 1 : pgpid_t killproc = 0;
2106 :
2107 : #ifdef WIN32
2108 : setvbuf(stderr, NULL, _IONBF, 0);
2109 : #endif
2110 :
2111 1 : progname = get_progname(argv[0]);
2112 1 : set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_ctl"));
2113 1 : start_time = time(NULL);
2114 :
2115 : /*
2116 : * save argv[0] so do_start() can look for the postmaster if necessary. we
2117 : * don't look for postmaster here because in many cases we won't need it.
2118 : */
2119 1 : argv0 = argv[0];
2120 :
2121 1 : umask(S_IRWXG | S_IRWXO);
2122 :
2123 : /* support --help and --version even if invoked as root */
2124 1 : if (argc > 1)
2125 : {
2126 1 : if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
2127 : {
2128 0 : do_help();
2129 0 : exit(0);
2130 : }
2131 1 : else if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
2132 : {
2133 0 : puts("pg_ctl (PostgreSQL) " PG_VERSION);
2134 0 : exit(0);
2135 : }
2136 : }
2137 :
2138 : /*
2139 : * Disallow running as root, to forestall any possible security holes.
2140 : */
2141 : #ifndef WIN32
2142 1 : if (geteuid() == 0)
2143 : {
2144 0 : write_stderr(_("%s: cannot be run as root\n"
2145 : "Please log in (using, e.g., \"su\") as the "
2146 : "(unprivileged) user that will\n"
2147 : "own the server process.\n"),
2148 : progname);
2149 0 : exit(1);
2150 : }
2151 : #endif
2152 :
2153 1 : env_wait = getenv("PGCTLTIMEOUT");
2154 1 : if (env_wait != NULL)
2155 0 : wait_seconds = atoi(env_wait);
2156 :
2157 : /*
2158 : * 'Action' can be before or after args so loop over both. Some
2159 : * getopt_long() implementations will reorder argv[] to place all flags
2160 : * first (GNU?), but we don't rely on it. Our /port version doesn't do
2161 : * that.
2162 : */
2163 1 : optind = 1;
2164 :
2165 : /* process command-line options */
2166 3 : while (optind < argc)
2167 : {
2168 4 : while ((c = getopt_long(argc, argv, "cD:e:l:m:N:o:p:P:sS:t:U:wW",
2169 : long_options, &option_index)) != -1)
2170 : {
2171 2 : switch (c)
2172 : {
2173 : case 'D':
2174 : {
2175 : char *pgdata_D;
2176 : char *env_var;
2177 :
2178 1 : pgdata_D = pg_strdup(optarg);
2179 1 : canonicalize_path(pgdata_D);
2180 1 : env_var = psprintf("PGDATA=%s", pgdata_D);
2181 1 : putenv(env_var);
2182 :
2183 : /*
2184 : * We could pass PGDATA just in an environment
2185 : * variable but we do -D too for clearer postmaster
2186 : * 'ps' display
2187 : */
2188 1 : pgdata_opt = psprintf("-D \"%s\" ", pgdata_D);
2189 1 : break;
2190 : }
2191 : case 'e':
2192 0 : event_source = pg_strdup(optarg);
2193 0 : break;
2194 : case 'l':
2195 0 : log_file = pg_strdup(optarg);
2196 0 : break;
2197 : case 'm':
2198 0 : set_mode(optarg);
2199 0 : break;
2200 : case 'N':
2201 0 : register_servicename = pg_strdup(optarg);
2202 0 : break;
2203 : case 'o':
2204 : /* append option? */
2205 0 : if (!post_opts)
2206 0 : post_opts = pg_strdup(optarg);
2207 : else
2208 : {
2209 0 : char *old_post_opts = post_opts;
2210 :
2211 0 : post_opts = psprintf("%s %s", old_post_opts, optarg);
2212 0 : free(old_post_opts);
2213 : }
2214 0 : break;
2215 : case 'p':
2216 0 : exec_path = pg_strdup(optarg);
2217 0 : break;
2218 : case 'P':
2219 0 : register_password = pg_strdup(optarg);
2220 0 : break;
2221 : case 's':
2222 1 : silent_mode = true;
2223 1 : break;
2224 : case 'S':
2225 : #ifdef WIN32
2226 : set_starttype(optarg);
2227 : #else
2228 0 : write_stderr(_("%s: -S option not supported on this platform\n"),
2229 : progname);
2230 0 : exit(1);
2231 : #endif
2232 : break;
2233 : case 't':
2234 0 : wait_seconds = atoi(optarg);
2235 0 : wait_seconds_arg = true;
2236 0 : break;
2237 : case 'U':
2238 0 : if (strchr(optarg, '\\'))
2239 0 : register_username = pg_strdup(optarg);
2240 : else
2241 : /* Prepend .\ for local accounts */
2242 0 : register_username = psprintf(".\\%s", optarg);
2243 0 : break;
2244 : case 'w':
2245 0 : do_wait = true;
2246 0 : break;
2247 : case 'W':
2248 0 : do_wait = false;
2249 0 : break;
2250 : case 'c':
2251 0 : allow_core_files = true;
2252 0 : break;
2253 : default:
2254 : /* getopt_long already issued a suitable error message */
2255 0 : do_advice();
2256 0 : exit(1);
2257 : }
2258 : }
2259 :
2260 : /* Process an action */
2261 1 : if (optind < argc)
2262 : {
2263 1 : if (ctl_command != NO_COMMAND)
2264 : {
2265 0 : write_stderr(_("%s: too many command-line arguments (first is \"%s\")\n"), progname, argv[optind]);
2266 0 : do_advice();
2267 0 : exit(1);
2268 : }
2269 :
2270 1 : if (strcmp(argv[optind], "init") == 0
2271 1 : || strcmp(argv[optind], "initdb") == 0)
2272 0 : ctl_command = INIT_COMMAND;
2273 1 : else if (strcmp(argv[optind], "start") == 0)
2274 0 : ctl_command = START_COMMAND;
2275 1 : else if (strcmp(argv[optind], "stop") == 0)
2276 1 : ctl_command = STOP_COMMAND;
2277 0 : else if (strcmp(argv[optind], "restart") == 0)
2278 0 : ctl_command = RESTART_COMMAND;
2279 0 : else if (strcmp(argv[optind], "reload") == 0)
2280 0 : ctl_command = RELOAD_COMMAND;
2281 0 : else if (strcmp(argv[optind], "status") == 0)
2282 0 : ctl_command = STATUS_COMMAND;
2283 0 : else if (strcmp(argv[optind], "promote") == 0)
2284 0 : ctl_command = PROMOTE_COMMAND;
2285 0 : else if (strcmp(argv[optind], "kill") == 0)
2286 : {
2287 0 : if (argc - optind < 3)
2288 : {
2289 0 : write_stderr(_("%s: missing arguments for kill mode\n"), progname);
2290 0 : do_advice();
2291 0 : exit(1);
2292 : }
2293 0 : ctl_command = KILL_COMMAND;
2294 0 : set_sig(argv[++optind]);
2295 0 : killproc = atol(argv[++optind]);
2296 : }
2297 : #ifdef WIN32
2298 : else if (strcmp(argv[optind], "register") == 0)
2299 : ctl_command = REGISTER_COMMAND;
2300 : else if (strcmp(argv[optind], "unregister") == 0)
2301 : ctl_command = UNREGISTER_COMMAND;
2302 : else if (strcmp(argv[optind], "runservice") == 0)
2303 : ctl_command = RUN_AS_SERVICE_COMMAND;
2304 : #endif
2305 : else
2306 : {
2307 0 : write_stderr(_("%s: unrecognized operation mode \"%s\"\n"), progname, argv[optind]);
2308 0 : do_advice();
2309 0 : exit(1);
2310 : }
2311 1 : optind++;
2312 : }
2313 : }
2314 :
2315 1 : if (ctl_command == NO_COMMAND)
2316 : {
2317 0 : write_stderr(_("%s: no operation specified\n"), progname);
2318 0 : do_advice();
2319 0 : exit(1);
2320 : }
2321 :
2322 : /* Note we put any -D switch into the env var above */
2323 1 : pg_config = getenv("PGDATA");
2324 1 : if (pg_config)
2325 : {
2326 1 : pg_config = pg_strdup(pg_config);
2327 1 : canonicalize_path(pg_config);
2328 1 : pg_data = pg_strdup(pg_config);
2329 : }
2330 :
2331 : /* -D might point at config-only directory; if so find the real PGDATA */
2332 1 : adjust_data_dir();
2333 :
2334 : /* Complain if -D needed and not provided */
2335 1 : if (pg_config == NULL &&
2336 0 : ctl_command != KILL_COMMAND && ctl_command != UNREGISTER_COMMAND)
2337 : {
2338 0 : write_stderr(_("%s: no database directory specified and environment variable PGDATA unset\n"),
2339 : progname);
2340 0 : do_advice();
2341 0 : exit(1);
2342 : }
2343 :
2344 1 : if (ctl_command == RELOAD_COMMAND)
2345 : {
2346 0 : sig = SIGHUP;
2347 0 : do_wait = false;
2348 : }
2349 :
2350 1 : if (pg_data)
2351 : {
2352 1 : snprintf(postopts_file, MAXPGPATH, "%s/postmaster.opts", pg_data);
2353 1 : snprintf(version_file, MAXPGPATH, "%s/PG_VERSION", pg_data);
2354 1 : snprintf(pid_file, MAXPGPATH, "%s/postmaster.pid", pg_data);
2355 1 : snprintf(backup_file, MAXPGPATH, "%s/backup_label", pg_data);
2356 : }
2357 :
2358 1 : switch (ctl_command)
2359 : {
2360 : case INIT_COMMAND:
2361 0 : do_init();
2362 0 : break;
2363 : case STATUS_COMMAND:
2364 0 : do_status();
2365 0 : break;
2366 : case START_COMMAND:
2367 0 : do_start();
2368 0 : break;
2369 : case STOP_COMMAND:
2370 1 : do_stop();
2371 1 : break;
2372 : case RESTART_COMMAND:
2373 0 : do_restart();
2374 0 : break;
2375 : case RELOAD_COMMAND:
2376 0 : do_reload();
2377 0 : break;
2378 : case PROMOTE_COMMAND:
2379 0 : do_promote();
2380 0 : break;
2381 : case KILL_COMMAND:
2382 0 : do_kill(killproc);
2383 0 : break;
2384 : #ifdef WIN32
2385 : case REGISTER_COMMAND:
2386 : pgwin32_doRegister();
2387 : break;
2388 : case UNREGISTER_COMMAND:
2389 : pgwin32_doUnregister();
2390 : break;
2391 : case RUN_AS_SERVICE_COMMAND:
2392 : pgwin32_doRunAsService();
2393 : break;
2394 : #endif
2395 : default:
2396 0 : break;
2397 : }
2398 :
2399 1 : exit(0);
2400 : }
|