commit 368d31d4816d2b3a346918bb426efce8ba716283
Author: Hamish Coleman <hamish@zot.org>
Date:   Sun Sep 26 12:19:45 2010 +1000

    Update win-scm with new learnings, also add a service test helper program

diff --git a/.gitignore b/.gitignore
index c2ec4a6..6e99c90 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@
 # Ignore the built binaries
 wconsd.exe
 portenum.exe
+svctest.exe
 
 # Ignore the object files
 *.o
diff --git a/Makefile b/Makefile
index a660885..025427c 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
 
-all: wconsd.exe portenum.exe
+all: wconsd.exe portenum.exe svctest.exe
 
 get:
 	pscp 192.168.1.1:s/src/wconsd/*.c ./
@@ -23,6 +23,9 @@ MODULES:=modules.o win-scm.o
 wconsd.exe: wconsd.o $(MODULES) $(LIBCLI)
 	$(CC) -o $@ $^ -lws2_32
 
+svctest.exe: svctest.o win-scm.c
+	$(CC) -o $@ $^
+
 portenum.exe: portenum.c
 	$(CC) $(CFLAGS) -o $@ portenum.c -lwinspool -lsetupapi
 
@@ -36,4 +39,4 @@ wine: wconsd
 	/usr/lib/wine/wine.bin wconsd.exe.so -p 9600
 
 clean:
-	rm -f *.o wconsd.exe portenum.exe
+	rm -f *.o wconsd.exe portenum.exe svctest.exe
diff --git a/svctest.c b/svctest.c
new file mode 100644
index 0000000..182779c
--- /dev/null
+++ b/svctest.c
@@ -0,0 +1,142 @@
+/*
+ * Test framework for win-svc
+ *
+ */
+
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include "scm.h"
+
+/*
+ * log a debug message
+ */
+int dprintf_level = 1;
+int dprintf_to_stdout = 0;
+int dprintf(unsigned char severity, const char *fmt, ...) {
+        va_list args;
+        char buf[1024];
+        int i;
+
+        if (severity > dprintf_level)
+                return 0;
+
+        va_start(args,fmt);
+        i=vsnprintf(buf,sizeof(buf),fmt,args);
+        va_end(args);
+
+        if (dprintf_to_stdout) {
+                printf("%s",buf);
+        } else {
+                OutputDebugStringA(buf);
+        }
+        return i;
+}
+#define trace(s) \
+	dprintf(1,"%s:%i(%s) %s\n",__FILE__,__LINE__,__FUNCTION__,s)
+
+int svctest_init(int argc, char **argv);
+int svctest_main(int param1);
+int svctest_stop(int param1);
+
+struct SCM_def sd = {
+        .name = "svctest",
+        .desc = "svctest - test win-scm",
+        .init = svctest_init,
+        .main = svctest_main,
+        .stop = svctest_stop,
+};
+
+static int do_getopt(const int argc, char **argv) {
+	static struct option long_options[] = {
+		{"install", 1, 0, 'i'},
+		{"remove", 0, 0, 'r'},
+		{"debug", 2, 0, 'd'},
+		{0,0,0,0}
+	};
+
+	while(1) {
+		int c = getopt_long(argc,argv, "ird::",
+			long_options,NULL);
+		if (c==-1)
+			break;
+
+		switch(c) {
+			case 'i': {
+				/* request service installation */
+				char *path = SCM_Install(&sd,optarg);
+				if (!path) {
+					printf("Service installation failed\n");
+					return 2;
+				}
+				printf("Service '%s' installed, binary path '%s'\n",sd.name,path);
+				printf("You should now start the service using the service manager.\n");
+				return 1;
+			}
+			case 'r':
+				// request service removal
+				if (SCM_Remove(&sd)==0) {
+					printf("Deleted service '%s'\n",sd.name);
+				} else {
+					printf("Service removal failed\n");
+				}
+				return 1;
+		}
+	}
+	return 0;
+}
+
+
+int svctest_init(int argc, char **argv) {
+	dprintf(1,"%s:%i(%s) argc==%i\n",__FILE__,__LINE__,__FUNCTION__,argc);
+	int i;
+	for (i=0;i<argc;i++) {
+		dprintf(1,"%s:%i: argv==%s\n",__FILE__,__LINE__,argv[i]);
+	}
+	dprintf(1,"%s:%i(%s) sd.mode==%i\n",__FILE__,__LINE__,__FUNCTION__,sd.mode);
+
+	if (do_getopt(argc,argv)) {
+		/* do_getopt returns nonzero if we should not continue */
+		return 1;
+	}
+
+	trace("return 0");
+        return 0;
+}
+
+int run = 1;
+int svctest_main(int param1) {
+	while(run) {
+		1;
+		/* FIXME - sleep */
+	}
+	trace("return 0");
+        return 0;
+}
+
+int svctest_stop(int param1) {
+	run = 0;
+	trace("return 0");
+        return 0;
+}
+
+int main(int argc, char **argv)
+{
+	dprintf(1,"%s:%i: argc==%i\n",__FILE__,__LINE__,argc);
+	char **arg = argv;
+	while(*arg) {
+		dprintf(1,"%s:%i: argv==%s\n",__FILE__,__LINE__,*arg);
+		arg++;
+	}
+
+        if (SCM_Start(&sd,argc,argv)!=SVC_OK) {
+		dprintf(1,"%s:%i: SCM_Start!=SVC_OK\n",__FILE__,__LINE__);
+                return 1;
+        }
+
+	trace("return 0");
+        return 0;
+}
+
diff --git a/wconsd.c b/wconsd.c
index f9dedb1..7681e55 100644
--- a/wconsd.c
+++ b/wconsd.c
@@ -426,7 +426,7 @@ static int do_getopt(const int argc, char **argv) {
 		switch(c) {
 			case 'i': {
 				/* request service installation */
-				char *path = SCM_Install(&sd);
+				char *path = SCM_Install(&sd,NULL);
 				if (!path) {
 					printf("Service installation failed\n");
 					return 2;
diff --git a/win-scm.c b/win-scm.c
index d880867..c895c75 100644
--- a/win-scm.c
+++ b/win-scm.c
@@ -71,6 +71,7 @@ VOID WINAPI ServiceMain(DWORD argc, LPSTR *argv)
 	SetServiceStatus( svcHandle, &svcStatus );
 
 	sd->mode=SVC_OK;
+	/* TODO - use either saved cmdline args or scm args here */
 	if ((err=sd->init(argc,argv))!=0) {
 		svcStatus.dwCurrentState = SERVICE_STOPPED;
 		svcStatus.dwWin32ExitCode = err;
@@ -90,15 +91,15 @@ VOID WINAPI ServiceMain(DWORD argc, LPSTR *argv)
 	return;
 }
 
-int SCM_Start_Console(int argc, char **argv) {
+int SCM_Start_Console(struct SCM_def *sd) {
 
-	global_sd->mode=SVC_CONSOLE;
-	int err = global_sd->init(argc,argv);
+	sd->mode=SVC_CONSOLE;
+	int err = sd->init(sd->argc,sd->argv);
 	if (err!=0) {
 		return SVC_FAIL;
 	}
 
-	global_sd->main(0);
+	sd->main(0);
 	return SVC_OK;
 }
 
@@ -108,21 +109,28 @@ int SCM_Start(struct SCM_def *sd, int argc, char **argv) {
 		{ NULL, NULL }
 	};
 
+	/* save the cmdline for possible use later */
+	sd->argc=argc;
+	sd->argv=argv;
+
 	global_sd = sd;
 
+#if 0
+	/* turns out to be untrue! */
 	/* If we have commandline args, then we cannot have been started
 	 * by the Windows SCM
 	 */
 	if (argc>1) {
-		return SCM_Start_Console(argc,argv);
+		return SCM_Start_Console(sd);
 	}
+#endif
 
 	/* try to run as a service */
 	if (StartServiceCtrlDispatcher(ServiceTable)==0) {
 		int err = GetLastError();
 
 		if (err == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {
-			return SCM_Start_Console(argc,argv);
+			return SCM_Start_Console(sd);
 		}
 
 		/* any other error, assume fatal */
@@ -132,7 +140,7 @@ int SCM_Start(struct SCM_def *sd, int argc, char **argv) {
 	return SVC_OK;
 }
 
-char *SCM_Install(struct SCM_def *sd) {
+char *SCM_Install(struct SCM_def *sd, char *args) {
 	SC_HANDLE schSCManager, schService;
 
 	static char path[MAX_PATH];
@@ -142,6 +150,24 @@ char *SCM_Install(struct SCM_def *sd) {
 		return NULL;
 	}
 
+	/*
+	 * Note - the above path calculation does not work for paths containing
+	 * spaces.  This is because Windows is stupid, mosttly due to bad
+	 * design - see the next below.
+	 */
+
+	static char cmdline[MAX_PATH+10];
+	if (args) {
+		/*
+		 * The "BinaryPathName" can also have cmdline params
+		 * embedded into it.  Stupid windows
+		 */
+
+		snprintf(cmdline,sizeof(cmdline),"\"%s\" %s",path,args);
+	} else {
+		snprintf(cmdline,sizeof(cmdline),"\"%s\"",path);
+	}
+
 	schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
 
 	schService = CreateService(
@@ -152,7 +178,7 @@ char *SCM_Install(struct SCM_def *sd) {
 		SERVICE_WIN32_OWN_PROCESS,
 		SERVICE_AUTO_START,
 		SERVICE_ERROR_NORMAL,
-		path,
+		cmdline,
 		NULL, NULL, NULL, NULL, NULL);
 
 	if (schService == NULL) {
