CVS User Account cvsuser
Tue Sep 6 14:14:08 PDT 2005
Log Message:
-----------
This patch adds service registration and unregistration and enginge
addition and removal to slon for win32.

Other changes are that the usage information is moved to it's own
function so it could easily be called from more places, and I also added
a "-?" option to force up the usage information.

Finally, this once again fixes the logic for the pgpipe ifdefs so it
works on win32 again - pgpipe is a function and not a macro there..
[Magnus Hagander]

Modified Files:
--------------
    slony1-engine/src/slon/port:
        win32service.c (r1.3 -> r1.4)
        win32service.h (r1.3 -> r1.4)
    slony1-engine/src/slon:
        slon.c (r1.57 -> r1.58)
        slon.h (r1.52 -> r1.53)

-------------- next part --------------
Index: win32service.c
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/src/slon/port/win32service.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -Lsrc/slon/port/win32service.c -Lsrc/slon/port/win32service.c -u -w -r1.3 -r1.4
--- src/slon/port/win32service.c
+++ src/slon/port/win32service.c
@@ -27,6 +27,13 @@
 static bool win32_load_child_list(void);
 static HANDLE win32_start_engine(int num);
 
+static void RegisterService(char *servicename);
+static void UnRegisterService(char *servicename);
+static void ListEngines(char *servicename);
+static void AddEngine(char *servicename, char *configfile);
+static void DelEngine(char *servicename, char *configfile);
+
+
 /* Gobals for service control */
 static SERVICE_STATUS status;
 static SERVICE_STATUS_HANDLE hStatus;
@@ -202,6 +209,26 @@
 }
 
 /*
+ * Open the <servicename>\Parameters\Engines registry key, which holds the list
+ * of all the engines associated with this service.
+ */
+static HKEY OpenEnginesKey(DWORD access)
+{
+	char rootkey[1024];
+	HKEY key;
+	int r;
+
+	sprintf(rootkey,"SYSTEM\\CurrentControlSet\\Services\\%s\\Parameters\\Engines", running_servicename);
+
+	if ((r = RegCreateKeyEx(HKEY_LOCAL_MACHINE, rootkey, 0, NULL, REG_OPTION_NON_VOLATILE, access, NULL, &key, NULL)) != ERROR_SUCCESS)
+	{
+		slon_log(SLON_FATAL, "Failed to open registry key '%s': %lu", rootkey, r);
+		return NULL;
+	}
+	return key;
+}
+
+/*
  * Load the list of slon engines to start
  */
 static bool win32_load_child_list(void)
@@ -215,13 +242,10 @@
 	DWORD regtype;
 	int r;
 
-	sprintf(rootkey,"SYSTEM\\CurrentControlSet\\Services\\%s\\Parameters\\Engines", running_servicename);
-
-	if ((r = RegOpenKeyEx(HKEY_LOCAL_MACHINE, rootkey, 0, KEY_READ, &key)) != ERROR_SUCCESS)
-	{
-		slon_log(SLON_FATAL, "Failed to open registry key '%s': %lu", rootkey, r);
+	key = OpenEnginesKey(KEY_READ);
+	if (!key)
 		return false;
-	}
+	
 	childcount = 0;
 	while ((r=RegEnumValue(key, childcount, valname, &valnamesize, NULL, &regtype, NULL, NULL)) == ERROR_SUCCESS)
 	{
@@ -360,3 +384,253 @@
 	}
 	ReportEvent(evtHandle, elevel, 0, 0, NULL, 1, 0, (const char **)&msg, NULL);
 }
+
+
+
+/* Deal with service and engine registration and unregistration */
+void win32_serviceconfig(int argc, char *argv[])
+{
+	if (!strcmp(argv[1],"-regservice"))
+	{
+		if (argc != 2 && argc != 3)
+			Usage(argv);
+		RegisterService((argc==3)?argv[2]:"Slony-I");
+	}
+	else if (!strcmp(argv[1],"-unregservice"))
+	{
+		if (argc != 2 && argc != 3)
+			Usage(argv);
+		UnRegisterService((argc==3)?argv[2]:"Slony-I");
+	}
+	else if (!strcmp(argv[1],"-listengines"))
+	{
+		if (argc != 2 && argc != 3)
+			Usage(argv);
+		ListEngines((argc==3)?argv[2]:"Slony-I");
+	}
+	else if (!strcmp(argv[1],"-addengine"))
+	{
+		if (argc != 3 && argc != 4)
+			Usage(argv);
+		AddEngine((argc==4)?argv[2]:"Slony-I", (argc==4)?argv[3]:argv[2]);
+	}
+	else if (!strcmp(argv[1],"-delengine"))
+	{
+		if (argc != 3 && argc != 4)
+			Usage(argv);
+		DelEngine((argc==4)?argv[2]:"Slony-I", (argc==4)?argv[3]:argv[2]);
+	}
+	else
+		Usage(argv);
+	exit(0);
+}
+
+/* Check windows version against Server 2003 to determine service functionality */
+static bool is_windows2003ornewer()
+{
+	OSVERSIONINFO vi;
+
+	vi.dwOSVersionInfoSize = sizeof(vi);
+
+	if (!GetVersionEx(&vi))
+	{
+		fprintf(stderr,"Failed to determine OS version: %lu\n",GetLastError());
+		exit(1);
+	}
+	if (vi.dwMajorVersion > 5) return true; /* Vista + */
+	if (vi.dwMajorVersion ==5 && vi.dwMinorVersion >= 2) return true; /* Win 2003 */
+	return false;
+}
+
+/* Open Service Control Manager */
+static SC_HANDLE openSCM()
+{
+	SC_HANDLE manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
+	if (!manager)
+	{
+		fprintf(stderr,"Failed to open service control manager: %lu\n",GetLastError());
+		exit(1);
+	}
+	return manager;
+}
+
+/* Register a service with the specified name with the local service control manager */
+static void RegisterService(char *servicename)
+{
+	char self[1024];
+	char execpath[1200];
+	SC_HANDLE manager;
+	SC_HANDLE service;
+	char *account = is_windows2003ornewer()?"NT AUTHORITY\\Local Service":NULL;
+
+	ZeroMemory(self,sizeof(self));
+
+	if (!GetModuleFileName(NULL, self, sizeof(self)))
+	{
+		fprintf(stderr,"Failed to determine path name: %lu\n",GetLastError());
+		exit(1);
+	}
+	wsprintf(execpath,"%s -service",self);
+
+	manager = openSCM();
+
+	service =CreateService(
+				manager,
+				servicename,
+				servicename,
+				SERVICE_ALL_ACCESS,
+				SERVICE_WIN32_OWN_PROCESS,
+				SERVICE_AUTO_START,
+				SERVICE_ERROR_NORMAL,
+				execpath,
+				NULL,
+				NULL,
+				"RPCSS\0",
+				account,
+				"");
+	if (!service)
+	{
+		fprintf(stderr,"Failed to create service: %lu\n",GetLastError());
+		exit(1);
+	}
+
+	CloseServiceHandle(service);
+	CloseServiceHandle(manager);
+
+	printf("Service registered.\n");
+	printf("Before you can run Slony, you must also register an engine!\n\n");
+	if (account == NULL)
+	{
+		printf("WARNING! Service is registered to run as Local System. You are\n");
+		printf("encouraged to change this to a low privilege account to increase\n");
+		printf("system security.\n");
+	}
+}
+
+/* Remove a service with the specified name from the local service control manager */
+static void UnRegisterService(char *servicename)
+{
+	SC_HANDLE manager;
+	SC_HANDLE service;
+
+	manager = openSCM();
+	
+	service = OpenService(manager, servicename, SC_MANAGER_ALL_ACCESS);
+	if (!service)
+	{
+		fprintf(stderr,"Failed to open service: %lu\n",GetLastError());
+		exit(1);
+	}
+
+	if (!DeleteService(service))
+	{
+		fprintf(stderr,"Failed to delete service: %lu\n",GetLastError());
+		exit(1);
+	}
+	
+	CloseServiceHandle(service);
+	CloseServiceHandle(manager);
+
+	printf("Service removed.\n");
+}
+
+/* Print a list of all engines associated with the specified service */
+static void ListEngines(char *servicename)
+{
+	int i;
+
+	strcpy(running_servicename, servicename);
+	if (!win32_load_child_list())
+		exit(1);
+
+	printf("\n%i engine(s) registered for service '%s'\n",childcount,servicename);
+	for (i = 0; i < childcount; i++)
+	{
+		printf("Engine %i: %s\n", i+1, children_config_files[i]);
+	}
+}
+
+/*
+ * Verify that a file exists, and also expand the filename to 
+ * an absolute path.
+ */
+static char _vfe_buf[MAXPGPATH];
+static char *VerifyFileExists(char *filename)
+{
+	DWORD r;
+
+	ZeroMemory(_vfe_buf,sizeof(_vfe_buf));
+	r = GetFullPathName(filename, sizeof(_vfe_buf), _vfe_buf, NULL);
+	if (r ==0 || r > sizeof(_vfe_buf))
+	{
+		fprintf(stderr,"Failed to get full pathname for '%s': %i\n", filename, GetLastError());
+		exit(1);
+	}
+
+	if (GetFileAttributes(_vfe_buf) == 0xFFFFFFFF)
+	{
+		fprintf(stderr,"File '%s' could not be opened: %i\n", _vfe_buf, GetLastError());
+		exit(1);
+	}
+	
+	return _vfe_buf;
+}
+
+/* Register a new engine with a specific config file with the specified service */
+static void AddEngine(char *servicename, char *configfile)
+{
+	HKEY key;
+	int r;
+
+	char *full_configfile = VerifyFileExists(configfile);
+
+	strcpy(running_servicename, servicename);
+	key = OpenEnginesKey(KEY_ALL_ACCESS);
+	if (!key)
+		exit(1);
+
+	r = RegQueryValueEx(key, full_configfile, 0, NULL, NULL, NULL);
+	if (r == 0)
+	{
+		fprintf(stderr,"Engine '%s' already registered for service '%s'.\n", full_configfile, servicename);
+		exit(1);
+	}
+
+	r = RegSetValueEx(key, full_configfile, 0, REG_SZ, full_configfile, strlen(full_configfile)+1);
+	RegCloseKey(key);
+	if (r == ERROR_SUCCESS)
+	{
+		printf("Engine added.\n");
+		return;
+	}
+	else
+		fprintf(stderr,"Failed to register engine: %lu.\n", r);
+	exit(1);
+}	
+
+/* Remove an engine registration from the specified service */
+static void DelEngine(char *servicename, char *configfile)
+{
+	HKEY key;
+	int r;
+
+	strcpy(running_servicename, servicename);
+	key = OpenEnginesKey(KEY_ALL_ACCESS);
+	if (!key)
+		exit(1);
+
+	r = RegDeleteValue(key, configfile);
+	RegCloseKey(key);
+	if (r == ERROR_SUCCESS)
+	{
+		printf("Engine removed.\n");
+		return;
+	}
+	else if (r == 2)
+	{
+		fprintf(stderr,"Engine '%s' not registered for service '%s'.\n", configfile, servicename);
+	}
+	else
+		fprintf(stderr,"Failed to unregister engine: %lu\n", r);
+	exit(1);
+}
Index: win32service.h
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/src/slon/port/win32service.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -Lsrc/slon/port/win32service.h -Lsrc/slon/port/win32service.h -u -w -r1.3 -r1.4
--- src/slon/port/win32service.h
+++ src/slon/port/win32service.h
@@ -12,3 +12,4 @@
 void win32_servicestart(void);
 void win32_eventlog(int level, char *msg);
 extern int win32_isservice;
+void win32_serviceconfig(int argc, char *const argv[]);
Index: slon.c
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/src/slon/slon.c,v
retrieving revision 1.57
retrieving revision 1.58
diff -Lsrc/slon/slon.c -Lsrc/slon/slon.c -u -w -r1.57 -r1.58
--- src/slon/slon.c
+++ src/slon/slon.c
@@ -75,6 +75,34 @@
 int			child_status;
 
 
+void Usage(char * const argv[])
+{
+	fprintf(stderr, "usage: %s [options] clustername conninfo\n", argv[0]);
+	fprintf(stderr, "\n");
+	fprintf(stderr, "Options:\n");
+	fprintf(stderr, "    -d <debuglevel>       verbosity of logging (1..4)\n");
+	fprintf(stderr, "    -s <milliseconds>     SYNC check interval (default 10000)\n");
+	fprintf(stderr, "    -t <milliseconds>     SYNC interval timeout (default 60000)\n");
+	fprintf(stderr, "    -g <num>              maximum SYNC group size (default 6)\n");
+	fprintf(stderr, "    -c <num>              how often to vacuum in cleanup cycles\n");
+	fprintf(stderr, "    -p <filename>         slon pid file\n");
+	fprintf(stderr, "    -f <filename>         slon configuration file\n");
+	fprintf(stderr, "    -a <directory>        directory to store SYNC archive files\n");
+	fprintf(stderr, "    -q <num>              Terminate when this node reaches # of SYNCs\n");
+	fprintf(stderr, "    -r <num>              # of syncs for -q option\n");
+	fprintf(stderr, "    -l <interval>         this node should lag providers by this interval\n");
+#ifdef WIN32
+	fprintf(stderr, "\nWindows service registration:\n");
+	fprintf(stderr, " slon -regservice [servicename]\n");
+    fprintf(stderr, " slon -unregservice [servicename]\n");
+	fprintf(stderr, " slon -listengines [servicename]\n");
+	fprintf(stderr, " slon -addengine [servicename] <configfile>\n");
+	fprintf(stderr, " slon -delengine [servicename] <configfile>\n");
+#endif
+	exit(1);
+}
+
+
 /*
  * ---------- main ----------
  */
@@ -117,14 +145,25 @@
 		argc--;
 		argv++;
 	}
+	if (argc >= 2 && argc <= 4 && (
+				!strcmp(argv[1],"-regservice") ||
+				!strcmp(argv[1],"-unregservice") ||
+				!strcmp(argv[1],"-addengine") ||
+				!strcmp(argv[1],"-delengine") ||
+				!strcmp(argv[1],"-listengines")))
+	{
+		win32_serviceconfig(argc, argv);
+	}
 #endif
 	
 	InitializeConfOptions();
 
-	while ((c = getopt(argc, argv, "f:a:d:s:t:g:c:p:o:q:r:l:hv")) != EOF)
+	while ((c = getopt(argc, argv, "f:a:d:s:t:g:c:p:o:q:r:l:hv?")) != EOF)
 	{
 		switch (c)
 		{
+				case '?':
+					Usage(argv);
 		        case 'q':
 			        set_config_option("quit_sync_provider", optarg);
 				break;
@@ -245,21 +284,7 @@
 
 	if (errors != 0)
 	{
-		fprintf(stderr, "usage: %s [options] clustername conninfo\n", argv[0]);
-		fprintf(stderr, "\n");
-		fprintf(stderr, "Options:\n");
-		fprintf(stderr, "    -d <debuglevel>       verbosity of logging (1..4)\n");
-		fprintf(stderr, "    -s <milliseconds>     SYNC check interval (default 10000)\n");
-		fprintf(stderr, "    -t <milliseconds>     SYNC interval timeout (default 60000)\n");
-		fprintf(stderr, "    -g <num>              maximum SYNC group size (default 6)\n");
-		fprintf(stderr, "    -c <num>              how often to vacuum in cleanup cycles\n");
-		fprintf(stderr, "    -p <filename>         slon pid file\n");
-		fprintf(stderr, "    -f <filename>         slon configuration file\n");
-		fprintf(stderr, "    -a <directory>        directory to store SYNC archive files\n");
-		fprintf(stderr, "    -q <num>              Terminate when this node reaches # of SYNCs\n");
-		fprintf(stderr, "    -r <num>              # of syncs for -q option\n");
-		fprintf(stderr, "    -l <interval>         this node should lag providers by this interval\n");
-		return 1;
+		Usage(argv);
 	}
 
 #ifdef WIN32
Index: slon.h
===================================================================
RCS file: /usr/local/cvsroot/slony1/slony1-engine/src/slon/slon.h,v
retrieving revision 1.52
retrieving revision 1.53
diff -Lsrc/slon/slon.h -Lsrc/slon/slon.h -u -w -r1.52 -r1.53
--- src/slon/slon.h
+++ src/slon/slon.h
@@ -372,6 +372,7 @@
 #endif
 
 extern void slon_exit(int code);
+extern void Usage(char * const argv[]);
 
 extern int	slon_restart_request;
 extern int watchdog_pipe[];
@@ -538,7 +539,7 @@
  */
 extern int	slon_log_level;
 
-#ifndef pgpipe
+#if !defined(pgpipe) && !defined(WIN32)
 /* -----------------------------------
  * pgpipe is not defined in PG pre-8.0
  * -----------------------------------


More information about the Slony1-commit mailing list