Extend pg_ctl to handle service management under WIN32. Lacks docs.
Claudio Natoli and Magnus Hagander
This commit is contained in:
parent
df9d87f608
commit
f8dd00c3ef
@ -4,7 +4,7 @@
|
|||||||
*
|
*
|
||||||
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/bin/pg_ctl/pg_ctl.c,v 1.16 2004/06/11 16:36:31 momjian Exp $
|
* $PostgreSQL: pgsql/src/bin/pg_ctl/pg_ctl.c,v 1.17 2004/06/24 18:23:26 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -52,7 +52,10 @@ typedef enum
|
|||||||
RESTART_COMMAND,
|
RESTART_COMMAND,
|
||||||
RELOAD_COMMAND,
|
RELOAD_COMMAND,
|
||||||
STATUS_COMMAND,
|
STATUS_COMMAND,
|
||||||
KILL_COMMAND
|
KILL_COMMAND,
|
||||||
|
REGISTER_COMMAND,
|
||||||
|
UNREGISTER_COMMAND,
|
||||||
|
RUN_AS_SERVICE_COMMAND
|
||||||
} CtlCommand;
|
} CtlCommand;
|
||||||
|
|
||||||
|
|
||||||
@ -63,14 +66,20 @@ static bool silence_echo = false;
|
|||||||
static ShutdownMode shutdown_mode = SMART_MODE;
|
static ShutdownMode shutdown_mode = SMART_MODE;
|
||||||
static int sig = SIGTERM; /* default */
|
static int sig = SIGTERM; /* default */
|
||||||
static CtlCommand ctl_command = NO_COMMAND;
|
static CtlCommand ctl_command = NO_COMMAND;
|
||||||
static char *pg_data_opts = NULL;
|
|
||||||
static char *pg_data = NULL;
|
static char *pg_data = NULL;
|
||||||
static char *post_opts = NULL;
|
static char *post_opts = NULL;
|
||||||
static const char *progname;
|
static const char *progname;
|
||||||
static char *log_file = NULL;
|
static char *log_file = NULL;
|
||||||
static char *postgres_path = NULL;
|
static char *postgres_path = NULL;
|
||||||
|
static char *register_servicename = "PostgreSQL"; /* FIXME: + version ID? */
|
||||||
|
static char *register_username = NULL;
|
||||||
|
static char *register_password = NULL;
|
||||||
static char *argv0 = NULL;
|
static char *argv0 = NULL;
|
||||||
|
|
||||||
|
static void write_stderr(const char *fmt,...)
|
||||||
|
/* This extension allows gcc to check the format string for consistency with
|
||||||
|
the supplied arguments. */
|
||||||
|
__attribute__((format(printf, 1, 2)));
|
||||||
static void *xmalloc(size_t size);
|
static void *xmalloc(size_t size);
|
||||||
static char *xstrdup(const char *s);
|
static char *xstrdup(const char *s);
|
||||||
static void do_advice(void);
|
static void do_advice(void);
|
||||||
@ -83,6 +92,16 @@ static void do_restart(void);
|
|||||||
static void do_reload(void);
|
static void do_reload(void);
|
||||||
static void do_status(void);
|
static void do_status(void);
|
||||||
static void do_kill(pgpid_t pid);
|
static void do_kill(pgpid_t pid);
|
||||||
|
#ifdef WIN32
|
||||||
|
static bool pgwin32_IsInstalled(SC_HANDLE);
|
||||||
|
static char* pgwin32_CommandLine(bool);
|
||||||
|
static void pgwin32_doRegister();
|
||||||
|
static void pgwin32_doUnregister();
|
||||||
|
static void pgwin32_SetServiceStatus(DWORD);
|
||||||
|
static void WINAPI pgwin32_ServiceHandler(DWORD);
|
||||||
|
static void WINAPI pgwin32_ServiceMain(DWORD, LPTSTR*);
|
||||||
|
static void pgwin32_doRunAsService();
|
||||||
|
#endif
|
||||||
static pgpid_t get_pgpid(void);
|
static pgpid_t get_pgpid(void);
|
||||||
static char **readfile(char *path);
|
static char **readfile(char *path);
|
||||||
static int start_postmaster(void);
|
static int start_postmaster(void);
|
||||||
@ -93,6 +112,63 @@ static char postopts_file[MAXPGPATH];
|
|||||||
static char pid_file[MAXPGPATH];
|
static char pid_file[MAXPGPATH];
|
||||||
static char conf_file[MAXPGPATH];
|
static char conf_file[MAXPGPATH];
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
static void
|
||||||
|
write_eventlog(int level, const char *line)
|
||||||
|
{
|
||||||
|
static HANDLE evtHandle = INVALID_HANDLE_VALUE;
|
||||||
|
|
||||||
|
if (evtHandle == INVALID_HANDLE_VALUE) {
|
||||||
|
evtHandle = RegisterEventSource(NULL,"PostgreSQL");
|
||||||
|
if (evtHandle == NULL) {
|
||||||
|
evtHandle = INVALID_HANDLE_VALUE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReportEvent(evtHandle,
|
||||||
|
level,
|
||||||
|
0,
|
||||||
|
0, /* All events are Id 0 */
|
||||||
|
NULL,
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
&line,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write errors to stderr (or by equal means when stderr is
|
||||||
|
* not available).
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
write_stderr(const char *fmt,...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
#ifndef WIN32
|
||||||
|
/* On Unix, we just fprintf to stderr */
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
#else
|
||||||
|
/* On Win32, we print to stderr if running on a console, or write to
|
||||||
|
* eventlog if running as a service */
|
||||||
|
if (!isatty(fileno(stderr))) /* Running as a service */
|
||||||
|
{
|
||||||
|
char errbuf[2048]; /* Arbitrary size? */
|
||||||
|
|
||||||
|
vsnprintf(errbuf, sizeof(errbuf), fmt, ap);
|
||||||
|
|
||||||
|
write_eventlog(EVENTLOG_ERROR_TYPE, errbuf);
|
||||||
|
}
|
||||||
|
else /* Not running as service, write to stderr */
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
#endif
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* routines to check memory allocations and fail noisily.
|
* routines to check memory allocations and fail noisily.
|
||||||
*/
|
*/
|
||||||
@ -105,7 +181,7 @@ xmalloc(size_t size)
|
|||||||
result = malloc(size);
|
result = malloc(size);
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: out of memory\n"), progname);
|
write_stderr(_("%s: out of memory\n"), progname);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -121,7 +197,7 @@ xstrdup(const char *s)
|
|||||||
result = strdup(s);
|
result = strdup(s);
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: out of memory\n"), progname);
|
write_stderr(_("%s: out of memory\n"), progname);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -352,10 +428,9 @@ do_start(void)
|
|||||||
{
|
{
|
||||||
old_pid = get_pgpid();
|
old_pid = get_pgpid();
|
||||||
if (old_pid != 0)
|
if (old_pid != 0)
|
||||||
fprintf(stderr,
|
write_stderr(_("%s: Another postmaster may be running. "
|
||||||
_("%s: Another postmaster may be running. "
|
"Trying to start postmaster anyway.\n"),
|
||||||
"Trying to start postmaster anyway.\n"),
|
progname);
|
||||||
progname);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (post_opts == NULL)
|
if (post_opts == NULL)
|
||||||
@ -371,13 +446,13 @@ do_start(void)
|
|||||||
post_opts = "";
|
post_opts = "";
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: cannot read %s\n"), progname, postopts_file);
|
write_stderr(_("%s: cannot read %s\n"), progname, postopts_file);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (optlines[0] == NULL || optlines[1] != NULL)
|
else if (optlines[0] == NULL || optlines[1] != NULL)
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: option file %s must have exactly 1 line\n"),
|
write_stderr(_("%s: option file %s must have exactly 1 line\n"),
|
||||||
progname, ctl_command == RESTART_COMMAND ?
|
progname, ctl_command == RESTART_COMMAND ?
|
||||||
postopts_file : def_postopts_file);
|
postopts_file : def_postopts_file);
|
||||||
exit(1);
|
exit(1);
|
||||||
@ -419,18 +494,16 @@ do_start(void)
|
|||||||
postmaster_path)) < 0)
|
postmaster_path)) < 0)
|
||||||
{
|
{
|
||||||
if (ret == -1)
|
if (ret == -1)
|
||||||
fprintf(stderr,
|
write_stderr(_("The program \"postmaster\" is needed by %s "
|
||||||
_("The program \"postmaster\" is needed by %s "
|
"but was not found in the same directory as "
|
||||||
"but was not found in the same directory as "
|
"\"%s\".\n"
|
||||||
"\"%s\".\n"
|
"Check your installation.\n"),
|
||||||
"Check your installation.\n"),
|
progname, progname);
|
||||||
progname, progname);
|
|
||||||
else
|
else
|
||||||
fprintf(stderr,
|
write_stderr(_("The program \"postmaster\" was found by %s "
|
||||||
_("The program \"postmaster\" was found by %s "
|
"but was not the same version as \"%s\".\n"
|
||||||
"but was not the same version as \"%s\".\n"
|
"Check your installation.\n"),
|
||||||
"Check your installation.\n"),
|
progname, progname);
|
||||||
progname, progname);
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
postgres_path = postmaster_path;
|
postgres_path = postmaster_path;
|
||||||
@ -438,7 +511,7 @@ do_start(void)
|
|||||||
|
|
||||||
if (start_postmaster() != 0)
|
if (start_postmaster() != 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("Unable to run the postmaster binary\n"));
|
write_stderr(_("Unable to run the postmaster binary\n"));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -448,10 +521,9 @@ do_start(void)
|
|||||||
pid = get_pgpid();
|
pid = get_pgpid();
|
||||||
if (pid == old_pid)
|
if (pid == old_pid)
|
||||||
{
|
{
|
||||||
fprintf(stderr,
|
write_stderr(_("%s: cannot start postmaster\n"
|
||||||
_("%s: cannot start postmaster\n"
|
"Examine the log output\n"),
|
||||||
"Examine the log output\n"),
|
progname);
|
||||||
progname);
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -485,23 +557,22 @@ do_stop(void)
|
|||||||
|
|
||||||
if (pid == 0) /* no pid file */
|
if (pid == 0) /* no pid file */
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: could not find %s\n"), progname, pid_file);
|
write_stderr(_("%s: could not find %s\n"), progname, pid_file);
|
||||||
fprintf(stderr, _("Is postmaster running?\n"));
|
write_stderr(_("Is postmaster running?\n"));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
else if (pid < 0) /* standalone backend, not postmaster */
|
else if (pid < 0) /* standalone backend, not postmaster */
|
||||||
{
|
{
|
||||||
pid = -pid;
|
pid = -pid;
|
||||||
fprintf(stderr,
|
write_stderr(_("%s: cannot stop postmaster; "
|
||||||
_("%s: cannot stop postmaster; "
|
"postgres is running (PID: %ld)\n"),
|
||||||
"postgres is running (PID: %ld)\n"),
|
progname, pid);
|
||||||
progname, pid);
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kill((pid_t) pid, sig) != 0)
|
if (kill((pid_t) pid, sig) != 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("stop signal failed (PID: %ld): %s\n"), pid,
|
write_stderr(_("stop signal failed (PID: %ld): %s\n"), pid,
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@ -540,7 +611,7 @@ do_stop(void)
|
|||||||
if (!silence_echo)
|
if (!silence_echo)
|
||||||
printf(_(" failed\n"));
|
printf(_(" failed\n"));
|
||||||
|
|
||||||
fprintf(stderr, _("%s: postmaster does not shut down\n"), progname);
|
write_stderr(_("%s: postmaster does not shut down\n"), progname);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if (!silence_echo)
|
if (!silence_echo)
|
||||||
@ -565,25 +636,24 @@ do_restart(void)
|
|||||||
|
|
||||||
if (pid == 0) /* no pid file */
|
if (pid == 0) /* no pid file */
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: could not find %s\n"), progname, pid_file);
|
write_stderr(_("%s: could not find %s\n"), progname, pid_file);
|
||||||
fprintf(stderr, _("Is postmaster running?\nstarting postmaster anyway\n"));
|
write_stderr(_("Is postmaster running?\nstarting postmaster anyway\n"));
|
||||||
do_start();
|
do_start();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (pid < 0) /* standalone backend, not postmaster */
|
else if (pid < 0) /* standalone backend, not postmaster */
|
||||||
{
|
{
|
||||||
pid = -pid;
|
pid = -pid;
|
||||||
fprintf(stderr,
|
write_stderr(_("%s: cannot restart postmaster; "
|
||||||
_("%s: cannot restart postmaster; "
|
"postgres is running (PID: %ld)\n"),
|
||||||
"postgres is running (PID: %ld)\n"),
|
progname, pid);
|
||||||
progname, pid);
|
write_stderr(_("Please terminate postgres and try again.\n"));
|
||||||
fprintf(stderr, _("Please terminate postgres and try again.\n"));
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kill((pid_t) pid, sig) != 0)
|
if (kill((pid_t) pid, sig) != 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("stop signal failed (PID: %ld): %s\n"), pid,
|
write_stderr(_("stop signal failed (PID: %ld): %s\n"), pid,
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@ -616,7 +686,7 @@ do_restart(void)
|
|||||||
if (!silence_echo)
|
if (!silence_echo)
|
||||||
printf(_(" failed\n"));
|
printf(_(" failed\n"));
|
||||||
|
|
||||||
fprintf(stderr, _("%s: postmaster does not shut down\n"), progname);
|
write_stderr(_("%s: postmaster does not shut down\n"), progname);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -636,24 +706,23 @@ do_reload(void)
|
|||||||
pid = get_pgpid();
|
pid = get_pgpid();
|
||||||
if (pid == 0) /* no pid file */
|
if (pid == 0) /* no pid file */
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: could not find %s\n"), progname, pid_file);
|
write_stderr(_("%s: could not find %s\n"), progname, pid_file);
|
||||||
fprintf(stderr, _("Is postmaster running?\n"));
|
write_stderr(_("Is postmaster running?\n"));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
else if (pid < 0) /* standalone backend, not postmaster */
|
else if (pid < 0) /* standalone backend, not postmaster */
|
||||||
{
|
{
|
||||||
pid = -pid;
|
pid = -pid;
|
||||||
fprintf(stderr,
|
write_stderr(_("%s: cannot reload postmaster; "
|
||||||
_("%s: cannot reload postmaster; "
|
"postgres is running (PID: %ld)\n"),
|
||||||
"postgres is running (PID: %ld)\n"),
|
progname, pid);
|
||||||
progname, pid);
|
write_stderr(_("Please terminate postgres and try again.\n"));
|
||||||
fprintf(stderr, _("Please terminate postgres and try again.\n"));
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kill((pid_t) pid, sig) != 0)
|
if (kill((pid_t) pid, sig) != 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("reload signal failed (PID: %ld): %s\n"), pid,
|
write_stderr(_("reload signal failed (PID: %ld): %s\n"), pid,
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@ -674,7 +743,7 @@ do_status(void)
|
|||||||
pid = get_pgpid();
|
pid = get_pgpid();
|
||||||
if (pid == 0) /* no pid file */
|
if (pid == 0) /* no pid file */
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: postmaster or postgres not running\n"), progname);
|
write_stderr(_("%s: postmaster or postgres not running\n"), progname);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
else if (pid < 0) /* standalone backend */
|
else if (pid < 0) /* standalone backend */
|
||||||
@ -702,18 +771,244 @@ do_kill(pgpid_t pid)
|
|||||||
{
|
{
|
||||||
if (kill((pid_t) pid, sig) != 0)
|
if (kill((pid_t) pid, sig) != 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("signal %d failed (PID: %ld): %s\n"), sig, pid,
|
write_stderr(_("signal %d failed (PID: %ld): %s\n"), sig, pid,
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
|
||||||
|
static bool pgwin32_IsInstalled(SC_HANDLE hSCM)
|
||||||
|
{
|
||||||
|
SC_HANDLE hService = OpenService(hSCM, register_servicename, SERVICE_QUERY_CONFIG);
|
||||||
|
bool bResult = (hService != NULL);
|
||||||
|
if (bResult)
|
||||||
|
CloseServiceHandle(hService);
|
||||||
|
return bResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char* pgwin32_CommandLine(bool registration)
|
||||||
|
{
|
||||||
|
static char cmdLine[MAXPGPATH];
|
||||||
|
int ret;
|
||||||
|
if (registration)
|
||||||
|
ret = find_my_exec(argv0, cmdLine);
|
||||||
|
else
|
||||||
|
ret = find_other_exec(argv0, "postmaster", PM_VERSIONSTR, cmdLine);
|
||||||
|
if (ret != 0)
|
||||||
|
{
|
||||||
|
write_stderr(_("Unable to find exe"));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (registration)
|
||||||
|
{
|
||||||
|
if (strcasecmp(cmdLine+strlen(cmdLine)-4,".exe"))
|
||||||
|
{
|
||||||
|
/* If commandline does not end in .exe, append it */
|
||||||
|
strcat(cmdLine,".exe");
|
||||||
|
}
|
||||||
|
strcat(cmdLine," runservice -N \"");
|
||||||
|
strcat(cmdLine,register_servicename);
|
||||||
|
strcat(cmdLine,"\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pg_data)
|
||||||
|
{
|
||||||
|
strcat(cmdLine," -D \"");
|
||||||
|
strcat(cmdLine,pg_data);
|
||||||
|
strcat(cmdLine,"\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (post_opts)
|
||||||
|
{
|
||||||
|
strcat(cmdLine," ");
|
||||||
|
if (registration)
|
||||||
|
strcat(cmdLine," -o \"");
|
||||||
|
strcat(cmdLine,post_opts);
|
||||||
|
if (registration)
|
||||||
|
strcat(cmdLine,"\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmdLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pgwin32_doRegister()
|
||||||
|
{
|
||||||
|
SC_HANDLE hService;
|
||||||
|
SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
||||||
|
if (hSCM == NULL)
|
||||||
|
{
|
||||||
|
write_stderr(_("Unable to open service manager\n"));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (pgwin32_IsInstalled(hSCM))
|
||||||
|
{
|
||||||
|
CloseServiceHandle(hSCM);
|
||||||
|
write_stderr(_("Service \"%s\" already registered\n"),register_servicename);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((hService = CreateService(hSCM, register_servicename, register_servicename,
|
||||||
|
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
|
||||||
|
SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
|
||||||
|
pgwin32_CommandLine(true),
|
||||||
|
NULL, NULL, "RPCSS\0", register_username, register_password)) == NULL)
|
||||||
|
{
|
||||||
|
CloseServiceHandle(hSCM);
|
||||||
|
write_stderr(_("Unable to register service \"%s\" [%d]\n"), register_servicename, (int)GetLastError());
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
CloseServiceHandle(hService);
|
||||||
|
CloseServiceHandle(hSCM);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pgwin32_doUnregister()
|
||||||
|
{
|
||||||
|
SC_HANDLE hService;
|
||||||
|
SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
||||||
|
if (hSCM == NULL)
|
||||||
|
{
|
||||||
|
write_stderr(_("Unable to open service manager\n"));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (!pgwin32_IsInstalled(hSCM))
|
||||||
|
{
|
||||||
|
CloseServiceHandle(hSCM);
|
||||||
|
write_stderr(_("Service \"%s\" not registered\n"),register_servicename);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((hService = OpenService(hSCM, register_servicename, DELETE)) == NULL)
|
||||||
|
{
|
||||||
|
CloseServiceHandle(hSCM);
|
||||||
|
write_stderr(_("Unable to open service \"%s\" [%d]\n"), register_servicename, (int)GetLastError());
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (!DeleteService(hService)) {
|
||||||
|
CloseServiceHandle(hService);
|
||||||
|
CloseServiceHandle(hSCM);
|
||||||
|
write_stderr(_("Unable to unregister service \"%s\" [%d]\n"), register_servicename, (int)GetLastError());
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
CloseServiceHandle(hService);
|
||||||
|
CloseServiceHandle(hSCM);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static SERVICE_STATUS status;
|
||||||
|
static SERVICE_STATUS_HANDLE hStatus = (SERVICE_STATUS_HANDLE)0;
|
||||||
|
static HANDLE shutdownHandles[2];
|
||||||
|
static pid_t postmasterPID = -1;
|
||||||
|
#define shutdownEvent shutdownHandles[0]
|
||||||
|
#define postmasterProcess shutdownHandles[1]
|
||||||
|
|
||||||
|
static void pgwin32_SetServiceStatus(DWORD currentState)
|
||||||
|
{
|
||||||
|
status.dwCurrentState = currentState;
|
||||||
|
SetServiceStatus(hStatus, (LPSERVICE_STATUS)&status);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void WINAPI pgwin32_ServiceHandler(DWORD request)
|
||||||
|
{
|
||||||
|
switch (request)
|
||||||
|
{
|
||||||
|
case SERVICE_CONTROL_STOP:
|
||||||
|
case SERVICE_CONTROL_SHUTDOWN:
|
||||||
|
pgwin32_SetServiceStatus(SERVICE_STOP_PENDING);
|
||||||
|
SetEvent(shutdownEvent);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case SERVICE_CONTROL_PAUSE:
|
||||||
|
/* Win32 config reloading */
|
||||||
|
kill(postmasterPID,SIGHUP);
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* FIXME: These could be used to replace other signals etc */
|
||||||
|
case SERVICE_CONTROL_CONTINUE:
|
||||||
|
case SERVICE_CONTROL_INTERROGATE:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void WINAPI pgwin32_ServiceMain(DWORD argc, LPTSTR *argv)
|
||||||
|
{
|
||||||
|
STARTUPINFO si;
|
||||||
|
PROCESS_INFORMATION pi;
|
||||||
|
DWORD ret;
|
||||||
|
|
||||||
|
/* Initialize variables */
|
||||||
|
status.dwWin32ExitCode = S_OK;
|
||||||
|
status.dwCheckPoint = 0;
|
||||||
|
status.dwWaitHint = 0;
|
||||||
|
status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
||||||
|
status.dwControlsAccepted = SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_PAUSE_CONTINUE;
|
||||||
|
status.dwServiceSpecificExitCode = 0;
|
||||||
|
status.dwCurrentState = SERVICE_START_PENDING;
|
||||||
|
|
||||||
|
memset(&pi,0,sizeof(pi));
|
||||||
|
memset(&si,0,sizeof(si));
|
||||||
|
si.cb = sizeof(si);
|
||||||
|
|
||||||
|
/* Register the control request handler */
|
||||||
|
if ((hStatus = RegisterServiceCtrlHandler(register_servicename, pgwin32_ServiceHandler)) == (SERVICE_STATUS_HANDLE)0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((shutdownEvent = CreateEvent(NULL,true,false,NULL)) == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Start the postmaster */
|
||||||
|
pgwin32_SetServiceStatus(SERVICE_START_PENDING);
|
||||||
|
if (!CreateProcess(NULL,pgwin32_CommandLine(false),NULL,NULL,TRUE,0,NULL,NULL,&si,&pi))
|
||||||
|
{
|
||||||
|
pgwin32_SetServiceStatus(SERVICE_STOPPED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
postmasterPID = pi.dwProcessId;
|
||||||
|
postmasterProcess = pi.hProcess;
|
||||||
|
CloseHandle(pi.hThread);
|
||||||
|
pgwin32_SetServiceStatus(SERVICE_RUNNING);
|
||||||
|
|
||||||
|
/* Wait for quit... */
|
||||||
|
ret = WaitForMultipleObjects(2,shutdownHandles,FALSE,INFINITE);
|
||||||
|
pgwin32_SetServiceStatus(SERVICE_STOP_PENDING);
|
||||||
|
switch (ret)
|
||||||
|
{
|
||||||
|
case WAIT_OBJECT_0: /* shutdown event */
|
||||||
|
kill(postmasterPID,SIGINT);
|
||||||
|
WaitForSingleObject(postmasterProcess,INFINITE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (WAIT_OBJECT_0+1): /* postmaster went down */
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* assert(false); */
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseHandle(shutdownEvent);
|
||||||
|
CloseHandle(postmasterProcess);
|
||||||
|
|
||||||
|
pgwin32_SetServiceStatus(SERVICE_STOPPED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pgwin32_doRunAsService()
|
||||||
|
{
|
||||||
|
SERVICE_TABLE_ENTRY st[] = {{ register_servicename, pgwin32_ServiceMain },
|
||||||
|
{ NULL, NULL }};
|
||||||
|
StartServiceCtrlDispatcher(st);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
static void
|
static void
|
||||||
do_advice(void)
|
do_advice(void)
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("\nTry \"%s --help\" for more information.\n"), progname);
|
write_stderr(_("\nTry \"%s --help\" for more information.\n"), progname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -730,9 +1025,18 @@ do_help(void)
|
|||||||
printf(_(" %s reload [-D DATADIR] [-s]\n"), progname);
|
printf(_(" %s reload [-D DATADIR] [-s]\n"), progname);
|
||||||
printf(_(" %s status [-D DATADIR]\n"), progname);
|
printf(_(" %s status [-D DATADIR]\n"), progname);
|
||||||
printf(_(" %s kill SIGNALNAME PROCESSID\n"), progname);
|
printf(_(" %s kill SIGNALNAME PROCESSID\n"), progname);
|
||||||
|
#ifdef WIN32
|
||||||
|
printf(_(" %s register [-N servicename] [-U username] [-P password] [-D DATADIR] [-o \"OPTIONS\"]\n"), progname);
|
||||||
|
printf(_(" %s unregister [-N servicename]\n"), progname);
|
||||||
|
#endif
|
||||||
printf(_("Common options:\n"));
|
printf(_("Common options:\n"));
|
||||||
printf(_(" -D, --pgdata DATADIR location of the database storage area\n"));
|
printf(_(" -D, --pgdata DATADIR location of the database storage area\n"));
|
||||||
printf(_(" -s, --silent only print errors, no informational messages\n"));
|
printf(_(" -s, --silent only print errors, no informational messages\n"));
|
||||||
|
#ifdef WIN32
|
||||||
|
printf(_(" -N service name with which to register PostgreSQL server\n"));
|
||||||
|
printf(_(" -P user name of account to register PostgreSQL server\n"));
|
||||||
|
printf(_(" -U password of account to register PostgreSQL server\n"));
|
||||||
|
#endif
|
||||||
printf(_(" -w wait until operation completes\n"));
|
printf(_(" -w wait until operation completes\n"));
|
||||||
printf(_(" -W do not wait until operation completes\n"));
|
printf(_(" -W do not wait until operation completes\n"));
|
||||||
printf(_(" --help show this help, then exit\n"));
|
printf(_(" --help show this help, then exit\n"));
|
||||||
@ -778,7 +1082,7 @@ set_mode(char *modeopt)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: invalid shutdown mode %s\n"), progname, modeopt);
|
write_stderr(_("%s: invalid shutdown mode %s\n"), progname, modeopt);
|
||||||
do_advice();
|
do_advice();
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@ -811,7 +1115,7 @@ set_sig(char *signame)
|
|||||||
sig = SIGUSR2;
|
sig = SIGUSR2;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: invalid signal \"%s\"\n"), progname, signame);
|
write_stderr(_("%s: invalid signal \"%s\"\n"), progname, signame);
|
||||||
do_advice();
|
do_advice();
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@ -879,19 +1183,17 @@ main(int argc, char **argv)
|
|||||||
/* process command-line options */
|
/* process command-line options */
|
||||||
while (optind < argc)
|
while (optind < argc)
|
||||||
{
|
{
|
||||||
while ((c = getopt_long(argc, argv, "D:l:m:o:p:swW", long_options, &option_index)) != -1)
|
while ((c = getopt_long(argc, argv, "D:l:m:N:o:p:P:sU:wW", long_options, &option_index)) != -1)
|
||||||
{
|
{
|
||||||
switch (c)
|
switch (c)
|
||||||
{
|
{
|
||||||
case 'D':
|
case 'D':
|
||||||
{
|
{
|
||||||
int len = strlen(optarg) + 4;
|
int len = strlen(optarg);
|
||||||
char *env_var;
|
char *env_var;
|
||||||
|
|
||||||
pg_data_opts = xmalloc(len);
|
env_var = xmalloc(len + 8);
|
||||||
snprintf(pg_data_opts, len, "-D %s", optarg);
|
snprintf(env_var, len + 8, "PGDATA=%s", optarg);
|
||||||
env_var = xmalloc(len + sizeof("PGDATA="));
|
|
||||||
snprintf(env_var, len + sizeof("PGDATA="), "PGDATA=%s", optarg);
|
|
||||||
putenv(env_var);
|
putenv(env_var);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -901,15 +1203,36 @@ main(int argc, char **argv)
|
|||||||
case 'm':
|
case 'm':
|
||||||
set_mode(optarg);
|
set_mode(optarg);
|
||||||
break;
|
break;
|
||||||
|
case 'N':
|
||||||
|
register_servicename = xstrdup(optarg);
|
||||||
|
break;
|
||||||
case 'o':
|
case 'o':
|
||||||
post_opts = xstrdup(optarg);
|
post_opts = xstrdup(optarg);
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
postgres_path = xstrdup(optarg);
|
postgres_path = xstrdup(optarg);
|
||||||
break;
|
break;
|
||||||
|
case 'P':
|
||||||
|
register_password = xstrdup(optarg);
|
||||||
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
silence_echo = true;
|
silence_echo = true;
|
||||||
break;
|
break;
|
||||||
|
case 'U':
|
||||||
|
if (strchr(optarg,'\\'))
|
||||||
|
register_username = xstrdup(optarg);
|
||||||
|
else /* Prepend .\ for local accounts */
|
||||||
|
{
|
||||||
|
register_username = malloc(strlen(optarg)+3);
|
||||||
|
if (!register_username)
|
||||||
|
{
|
||||||
|
write_stderr(_("%s: out of memory\n"), progname);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
strcpy(register_username,".\\");
|
||||||
|
strcat(register_username,optarg);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'w':
|
case 'w':
|
||||||
do_wait = true;
|
do_wait = true;
|
||||||
wait_set = true;
|
wait_set = true;
|
||||||
@ -919,7 +1242,7 @@ main(int argc, char **argv)
|
|||||||
wait_set = true;
|
wait_set = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, _("%s: invalid option %s\n"), progname, optarg);
|
write_stderr(_("%s: invalid option %s\n"), progname, optarg);
|
||||||
do_advice();
|
do_advice();
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@ -930,7 +1253,7 @@ main(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
if (ctl_command != NO_COMMAND)
|
if (ctl_command != NO_COMMAND)
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: extra operation mode %s\n"), progname, argv[optind]);
|
write_stderr(_("%s: extra operation mode %s\n"), progname, argv[optind]);
|
||||||
do_advice();
|
do_advice();
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@ -949,7 +1272,7 @@ main(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
if (argc - optind < 3)
|
if (argc - optind < 3)
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: invalid kill syntax\n"), progname);
|
write_stderr(_("%s: invalid kill syntax\n"), progname);
|
||||||
do_advice();
|
do_advice();
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@ -957,32 +1280,45 @@ main(int argc, char **argv)
|
|||||||
set_sig(argv[++optind]);
|
set_sig(argv[++optind]);
|
||||||
killproc = atol(argv[++optind]);
|
killproc = atol(argv[++optind]);
|
||||||
}
|
}
|
||||||
|
#ifdef WIN32
|
||||||
|
else if (strcmp(argv[optind], "register") == 0)
|
||||||
|
ctl_command = REGISTER_COMMAND;
|
||||||
|
else if (strcmp(argv[optind], "unregister") == 0)
|
||||||
|
ctl_command = UNREGISTER_COMMAND;
|
||||||
|
else if (strcmp(argv[optind], "runservice") == 0)
|
||||||
|
ctl_command = RUN_AS_SERVICE_COMMAND;
|
||||||
|
#endif
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: invalid operation mode %s\n"), progname, argv[optind]);
|
write_stderr(_("%s: invalid operation mode %s\n"), progname, argv[optind]);
|
||||||
do_advice();
|
do_advice();
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
optind++;
|
optind++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctl_command == NO_COMMAND)
|
if (ctl_command == NO_COMMAND)
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: no operation specified\n"), progname);
|
write_stderr(_("%s: no operation specified\n"), progname);
|
||||||
do_advice();
|
do_advice();
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Note we put any -D switch into the env var above */
|
||||||
pg_data = getenv("PGDATA");
|
pg_data = getenv("PGDATA");
|
||||||
canonicalize_path(pg_data);
|
if (pg_data)
|
||||||
|
|
||||||
if (pg_data == NULL && ctl_command != KILL_COMMAND)
|
|
||||||
{
|
{
|
||||||
fprintf(stderr,
|
/* XXX modifies environment var in-place ... ugly ... */
|
||||||
_("%s: no database directory specified "
|
canonicalize_path(pg_data);
|
||||||
"and environment variable PGDATA unset\n"),
|
}
|
||||||
progname);
|
|
||||||
|
if (pg_data == NULL &&
|
||||||
|
ctl_command != KILL_COMMAND && ctl_command != UNREGISTER_COMMAND)
|
||||||
|
{
|
||||||
|
write_stderr(_("%s: no database directory specified "
|
||||||
|
"and environment variable PGDATA unset\n"),
|
||||||
|
progname);
|
||||||
do_advice();
|
do_advice();
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@ -1034,6 +1370,17 @@ main(int argc, char **argv)
|
|||||||
case KILL_COMMAND:
|
case KILL_COMMAND:
|
||||||
do_kill(killproc);
|
do_kill(killproc);
|
||||||
break;
|
break;
|
||||||
|
#ifdef WIN32
|
||||||
|
case REGISTER_COMMAND:
|
||||||
|
pgwin32_doRegister();
|
||||||
|
break;
|
||||||
|
case UNREGISTER_COMMAND:
|
||||||
|
pgwin32_doUnregister();
|
||||||
|
break;
|
||||||
|
case RUN_AS_SERVICE_COMMAND:
|
||||||
|
pgwin32_doRunAsService();
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user