Index: pg_ctl.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/bin/pg_ctl/pg_ctl.c,v
retrieving revision 1.16
diff -c -c -r1.16 pg_ctl.c
*** pg_ctl.c	11 Jun 2004 16:36:31 -0000	1.16
--- pg_ctl.c	20 Jun 2004 15:09:30 -0000
***************
*** 52,58 ****
  	RESTART_COMMAND,
  	RELOAD_COMMAND,
  	STATUS_COMMAND,
! 	KILL_COMMAND
  }	CtlCommand;


--- 52,61 ----
  	RESTART_COMMAND,
  	RELOAD_COMMAND,
  	STATUS_COMMAND,
! 	KILL_COMMAND,
! 	REGISTER_COMMAND,
! 	UNREGISTER_COMMAND,
! 	RUN_AS_SERVICE_COMMAND
  }	CtlCommand;


***************
*** 69,74 ****
--- 72,80 ----
  static const char *progname;
  static char *log_file = NULL;
  static char *postgres_path = NULL;
+ static char *register_servicename = "PostgreSQL"; /* FIXME: + version ID? */
+ static char *register_username = NULL;
+ static char *register_password = NULL;
  static char *argv0 = NULL;

  static void *xmalloc(size_t size);
***************
*** 83,88 ****
--- 89,104 ----
  static void do_reload(void);
  static void do_status(void);
  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 char **readfile(char *path);
  static int start_postmaster(void);
***************
*** 93,98 ****
--- 109,171 ----
  static char pid_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).
+  */
+ 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.
   */
***************
*** 105,111 ****
  	result = malloc(size);
  	if (!result)
  	{
! 		fprintf(stderr, _("%s: out of memory\n"), progname);
  		exit(1);
  	}
  	return result;
--- 178,184 ----
  	result = malloc(size);
  	if (!result)
  	{
! 		write_stderr( _("%s: out of memory\n"), progname);
  		exit(1);
  	}
  	return result;
***************
*** 121,127 ****
  	result = strdup(s);
  	if (!result)
  	{
! 		fprintf(stderr, _("%s: out of memory\n"), progname);
  		exit(1);
  	}
  	return result;
--- 194,200 ----
  	result = strdup(s);
  	if (!result)
  	{
! 		write_stderr( _("%s: out of memory\n"), progname);
  		exit(1);
  	}
  	return result;
***************
*** 352,358 ****
  	{
  		old_pid = get_pgpid();
  		if (old_pid != 0)
! 			fprintf(stderr,
  					_("%s: Another postmaster may be running. "
  					"Trying to start postmaster anyway.\n"),
  					progname);
--- 425,431 ----
  	{
  		old_pid = get_pgpid();
  		if (old_pid != 0)
! 			write_stderr(
  					_("%s: Another postmaster may be running. "
  					"Trying to start postmaster anyway.\n"),
  					progname);
***************
*** 371,383 ****
  				post_opts = "";
  			else
  			{
! 				fprintf(stderr, _("%s: cannot read %s\n"), progname, postopts_file);
  				exit(1);
  			}
  		}
  		else if (optlines[0] == NULL || optlines[1] != NULL)
  		{
! 			fprintf(stderr, _("%s: option file %s must have exactly 1 line\n"),
  					progname, ctl_command == RESTART_COMMAND ?
  					postopts_file : def_postopts_file);
  			exit(1);
--- 444,456 ----
  				post_opts = "";
  			else
  			{
! 				write_stderr( _("%s: cannot read %s\n"), progname, postopts_file);
  				exit(1);
  			}
  		}
  		else if (optlines[0] == NULL || optlines[1] != NULL)
  		{
! 			write_stderr( _("%s: option file %s must have exactly 1 line\n"),
  					progname, ctl_command == RESTART_COMMAND ?
  					postopts_file : def_postopts_file);
  			exit(1);
***************
*** 419,432 ****
  								   postmaster_path)) < 0)
  		{
  			if (ret == -1)
! 				fprintf(stderr,
  						_("The program \"postmaster\" is needed by %s "
  						  "but was not found in the same directory as "
  						  "\"%s\".\n"
  						  "Check your installation.\n"),
  						progname, progname);
  			else
! 				fprintf(stderr,
  						_("The program \"postmaster\" was found by %s "
  						  "but was not the same version as \"%s\".\n"
  						  "Check your installation.\n"),
--- 492,505 ----
  								   postmaster_path)) < 0)
  		{
  			if (ret == -1)
! 				write_stderr(
  						_("The program \"postmaster\" is needed by %s "
  						  "but was not found in the same directory as "
  						  "\"%s\".\n"
  						  "Check your installation.\n"),
  						progname, progname);
  			else
! 				write_stderr(
  						_("The program \"postmaster\" was found by %s "
  						  "but was not the same version as \"%s\".\n"
  						  "Check your installation.\n"),
***************
*** 438,444 ****

  	if (start_postmaster() != 0)
  	{
! 		fprintf(stderr, _("Unable to run the postmaster binary\n"));
  		exit(1);
  	}

--- 511,517 ----

  	if (start_postmaster() != 0)
  	{
! 		write_stderr( _("Unable to run the postmaster binary\n"));
  		exit(1);
  	}
  
***************
*** 448,454 ****
  		pid = get_pgpid();
  		if (pid == old_pid)
  		{
! 			fprintf(stderr,
  					_("%s: cannot start postmaster\n"
  					"Examine the log output\n"),
  					progname);
--- 521,527 ----
  		pid = get_pgpid();
  		if (pid == old_pid)
  		{
! 			write_stderr(
  					_("%s: cannot start postmaster\n"
  					"Examine the log output\n"),
  					progname);
***************
*** 485,498 ****
  
  	if (pid == 0)				/* no pid file */
  	{
! 		fprintf(stderr, _("%s: could not find %s\n"), progname, pid_file);
! 		fprintf(stderr, _("Is postmaster running?\n"));
  		exit(1);
  	}
  	else if (pid < 0)			/* standalone backend, not postmaster */
  	{
  		pid = -pid;
! 		fprintf(stderr,
  				_("%s: cannot stop postmaster; "
  				"postgres is running (PID: %ld)\n"),
  				progname, pid);
--- 558,571 ----
  
  	if (pid == 0)				/* no pid file */
  	{
! 		write_stderr( _("%s: could not find %s\n"), progname, pid_file);
! 		write_stderr( _("Is postmaster running?\n"));
  		exit(1);
  	}
  	else if (pid < 0)			/* standalone backend, not postmaster */
  	{
  		pid = -pid;
! 		write_stderr(
  				_("%s: cannot stop postmaster; "
  				"postgres is running (PID: %ld)\n"),
  				progname, pid);
***************
*** 501,507 ****
  
  	if (kill((pid_t) pid, sig) != 0)
  	{
! 		fprintf(stderr, _("stop signal failed (PID: %ld): %s\n"), pid,
  				strerror(errno));
  		exit(1);
  	}
--- 574,580 ----
  
  	if (kill((pid_t) pid, sig) != 0)
  	{
! 		write_stderr( _("stop signal failed (PID: %ld): %s\n"), pid,
  				strerror(errno));
  		exit(1);
  	}
***************
*** 540,546 ****
  			if (!silence_echo)
  				printf(_(" failed\n"));
  	
! 			fprintf(stderr, _("%s: postmaster does not shut down\n"), progname);
  			exit(1);
  		}
  		if (!silence_echo)
--- 613,619 ----
  			if (!silence_echo)
  				printf(_(" failed\n"));
  	
! 			write_stderr( _("%s: postmaster does not shut down\n"), progname);
  			exit(1);
  		}
  		if (!silence_echo)
***************
*** 565,589 ****
  
  	if (pid == 0)				/* no pid file */
  	{
! 		fprintf(stderr, _("%s: could not find %s\n"), progname, pid_file);
! 		fprintf(stderr, _("Is postmaster running?\nstarting postmaster anyway\n"));
  		do_start();
  		return;
  	}
  	else if (pid < 0)			/* standalone backend, not postmaster */
  	{
  		pid = -pid;
! 		fprintf(stderr,
  				_("%s: cannot restart postmaster; "
  				"postgres is running (PID: %ld)\n"),
  				progname, pid);
! 		fprintf(stderr, _("Please terminate postgres and try again.\n"));
  		exit(1);
  	}
  
  	if (kill((pid_t) pid, sig) != 0)
  	{
! 		fprintf(stderr, _("stop signal failed (PID: %ld): %s\n"), pid,
  				strerror(errno));
  		exit(1);
  	}
--- 638,662 ----
  
  	if (pid == 0)				/* no pid file */
  	{
! 		write_stderr( _("%s: could not find %s\n"), progname, pid_file);
! 		write_stderr( _("Is postmaster running?\nstarting postmaster anyway\n"));
  		do_start();
  		return;
  	}
  	else if (pid < 0)			/* standalone backend, not postmaster */
  	{
  		pid = -pid;
! 		write_stderr(
  				_("%s: cannot restart postmaster; "
  				"postgres is running (PID: %ld)\n"),
  				progname, pid);
! 		write_stderr( _("Please terminate postgres and try again.\n"));
  		exit(1);
  	}
  
  	if (kill((pid_t) pid, sig) != 0)
  	{
! 		write_stderr( _("stop signal failed (PID: %ld): %s\n"), pid,
  				strerror(errno));
  		exit(1);
  	}
***************
*** 616,622 ****
  		if (!silence_echo)
  			printf(_(" failed\n"));
  
! 		fprintf(stderr, _("%s: postmaster does not shut down\n"), progname);
  		exit(1);
  	}
  
--- 689,695 ----
  		if (!silence_echo)
  			printf(_(" failed\n"));
  
! 		write_stderr( _("%s: postmaster does not shut down\n"), progname);
  		exit(1);
  	}
  
***************
*** 636,659 ****
  	pid = get_pgpid();
  	if (pid == 0)				/* no pid file */
  	{
! 		fprintf(stderr, _("%s: could not find %s\n"), progname, pid_file);
! 		fprintf(stderr, _("Is postmaster running?\n"));
  		exit(1);
  	}
  	else if (pid < 0)			/* standalone backend, not postmaster */
  	{
  		pid = -pid;
! 		fprintf(stderr,
  				_("%s: cannot reload postmaster; "
  				"postgres is running (PID: %ld)\n"),
  				progname, pid);
! 		fprintf(stderr, _("Please terminate postgres and try again.\n"));
  		exit(1);
  	}
  
  	if (kill((pid_t) pid, sig) != 0)
  	{
! 		fprintf(stderr, _("reload signal failed (PID: %ld): %s\n"), pid,
  				strerror(errno));
  		exit(1);
  	}
--- 709,732 ----
  	pid = get_pgpid();
  	if (pid == 0)				/* no pid file */
  	{
! 		write_stderr( _("%s: could not find %s\n"), progname, pid_file);
! 		write_stderr( _("Is postmaster running?\n"));
  		exit(1);
  	}
  	else if (pid < 0)			/* standalone backend, not postmaster */
  	{
  		pid = -pid;
! 		write_stderr(
  				_("%s: cannot reload postmaster; "
  				"postgres is running (PID: %ld)\n"),
  				progname, pid);
! 		write_stderr( _("Please terminate postgres and try again.\n"));
  		exit(1);
  	}
  
  	if (kill((pid_t) pid, sig) != 0)
  	{
! 		write_stderr( _("reload signal failed (PID: %ld): %s\n"), pid,
  				strerror(errno));
  		exit(1);
  	}
***************
*** 674,680 ****
  	pid = get_pgpid();
  	if (pid == 0)				/* no pid file */
  	{
! 		fprintf(stderr, _("%s: postmaster or postgres not running\n"), progname);
  		exit(1);
  	}
  	else if (pid < 0)			/* standalone backend */
--- 747,753 ----
  	pid = get_pgpid();
  	if (pid == 0)				/* no pid file */
  	{
! 		write_stderr( _("%s: postmaster or postgres not running\n"), progname);
  		exit(1);
  	}
  	else if (pid < 0)			/* standalone backend */
***************
*** 702,719 ****
  {
  	if (kill((pid_t) pid, sig) != 0)
  	{
! 		fprintf(stderr, _("signal %d failed (PID: %ld): %s\n"), sig, pid,
  				strerror(errno));
  		exit(1);
  	}
  }
  
  
  
  static void
  do_advice(void)
  {
! 	fprintf(stderr, _("\nTry \"%s --help\" for more information.\n"), progname);
  }
  
  
--- 775,1018 ----
  {
  	if (kill((pid_t) pid, sig) != 0)
  	{
! 		write_stderr( _("signal %d failed (PID: %ld): %s\n"), sig, pid,
  				strerror(errno));
  		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
  do_advice(void)
  {
! 	write_stderr( _("\nTry \"%s --help\" for more information.\n"), progname);
  }
  
  
***************
*** 730,738 ****
--- 1029,1046 ----
  	printf(_("  %s reload  [-D DATADIR] [-s]\n"), progname);
  	printf(_("  %s status  [-D DATADIR]\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(_("  -D, --pgdata DATADIR   location of the database storage area\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           do not wait until operation completes\n"));
  	printf(_("  --help       show this help, then exit\n"));
***************
*** 778,784 ****
  	}
  	else
  	{
! 		fprintf(stderr, _("%s: invalid shutdown mode %s\n"), progname, modeopt);
  		do_advice();
  		exit(1);
  	}
--- 1086,1092 ----
  	}
  	else
  	{
! 		write_stderr( _("%s: invalid shutdown mode %s\n"), progname, modeopt);
  		do_advice();
  		exit(1);
  	}
***************
*** 811,817 ****
  		sig = SIGUSR2;
  	else
  	{
! 		fprintf(stderr, _("%s: invalid signal \"%s\"\n"), progname, signame);
  		do_advice();
  		exit(1);
  	}
--- 1119,1125 ----
  		sig = SIGUSR2;
  	else
  	{
! 		write_stderr( _("%s: invalid signal \"%s\"\n"), progname, signame);
  		do_advice();
  		exit(1);
  	}
***************
*** 837,842 ****
--- 1145,1151 ----
  	int			c;
  	pgpid_t		killproc = 0;
  	
+ 
  #ifdef WIN32
  	setvbuf(stderr, NULL, _IONBF, 0);
  #endif
***************
*** 879,885 ****
  	/* process command-line options */
  	while (optind < argc)
  	{
! 		while ((c = getopt_long(argc, argv, "D:l:m:o:p:swW", long_options, &option_index)) != -1)
  		{
  			switch (c)
  			{
--- 1188,1194 ----
  	/* process command-line options */
  	while (optind < argc)
  	{
! 		while ((c = getopt_long(argc, argv, "D:l:m:N:o:p:P:sU:wW", long_options, &option_index)) != -1)
  		{
  			switch (c)
  			{
***************
*** 901,915 ****
--- 1210,1245 ----
  				case 'm':
  					set_mode(optarg);
  					break;
+ 				case 'N':
+ 					register_servicename = xstrdup(optarg);
+ 					break;
  				case 'o':
  					post_opts = xstrdup(optarg);
  					break;
  				case 'p':
  					postgres_path = xstrdup(optarg);
  					break;
+ 				case 'P':
+ 					register_password  = xstrdup(optarg);
+ 					break;
  				case 's':
  					silence_echo = true;
  					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':
  					do_wait = true;
  					wait_set = true;
***************
*** 919,925 ****
  					wait_set = true;
  					break;
  				default:
! 					fprintf(stderr, _("%s: invalid option %s\n"), progname, optarg);
  					do_advice();
  					exit(1);
  			}
--- 1249,1255 ----
  					wait_set = true;
  					break;
  				default:
! 					write_stderr( _("%s: invalid option %s\n"), progname, optarg);
  					do_advice();
  					exit(1);
  			}
***************
*** 930,936 ****
  		{
  			if (ctl_command != NO_COMMAND)
  			{
! 				fprintf(stderr, _("%s: extra operation mode %s\n"), progname, argv[optind]);
  				do_advice();
  				exit(1);
  			}
--- 1260,1266 ----
  		{
  			if (ctl_command != NO_COMMAND)
  			{
! 				write_stderr( _("%s: extra operation mode %s\n"), progname, argv[optind]);
  				do_advice();
  				exit(1);
  			}
***************
*** 949,955 ****
  			{
  				if (argc - optind < 3)
  				{
! 					fprintf(stderr, _("%s: invalid kill syntax\n"), progname);
  					do_advice();
  					exit(1);
  				}
--- 1279,1285 ----
  			{
  				if (argc - optind < 3)
  				{
! 					write_stderr( _("%s: invalid kill syntax\n"), progname);
  					do_advice();
  					exit(1);
  				}
***************
*** 957,965 ****
  				set_sig(argv[++optind]);
  				killproc = atol(argv[++optind]);
  			}
  			else
  			{
! 				fprintf(stderr, _("%s: invalid operation mode %s\n"), progname, argv[optind]);
  				do_advice();
  				exit(1);
  			}
--- 1287,1303 ----
  				set_sig(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
  			{
! 				write_stderr( _("%s: invalid operation mode %s\n"), progname, argv[optind]);
  				do_advice();
  				exit(1);
  			}
***************
*** 969,985 ****

  	if (ctl_command == NO_COMMAND)
  	{
! 		fprintf(stderr, _("%s: no operation specified\n"), progname);
  		do_advice();
  		exit(1);
  	}
  
  	pg_data = getenv("PGDATA");
  	canonicalize_path(pg_data);
  
! 	if (pg_data == NULL && ctl_command != KILL_COMMAND)
  	{
! 		fprintf(stderr,
  				_("%s: no database directory specified "
  				"and environment variable PGDATA unset\n"),
  				progname);
--- 1307,1324 ----

  	if (ctl_command == NO_COMMAND)
  	{
! 		write_stderr( _("%s: no operation specified\n"), progname);
  		do_advice();
  		exit(1);
  	}
  
  	pg_data = getenv("PGDATA");
+ 	if (pg_data)
  	canonicalize_path(pg_data);
  
! 	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);
***************
*** 1034,1039 ****
--- 1373,1389 ----
  		case KILL_COMMAND:
  			do_kill(killproc);
  			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:
  			break;
  	}
