From 1bb19cac499f3cf1ca5090ce44dc09324ecd8d2e Mon Sep 17 00:00:00 2001 From: Stefan Ritt Date: Sat, 5 Jun 2004 21:45:55 +0000 Subject: [PATCH] Added NT service functionality SVN revision: 889 --- src/elogd.c | 331 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 307 insertions(+), 24 deletions(-) diff --git a/src/elogd.c b/src/elogd.c index ea5426c9..5ad16dc4 100755 --- a/src/elogd.c +++ b/src/elogd.c @@ -6,6 +6,9 @@ Contents: Web server program for Electronic Logbook ELOG $Log$ + Revision 1.335 2004/06/05 21:45:55 midas + Added NT service functionality + Revision 1.334 2004/06/04 22:20:20 midas Added missing translations @@ -4523,6 +4526,39 @@ void logf(LOGBOOK * lbs, const char *format, ...) /*------------------------------------------------------------------*/ +/* +void logd(const char *format, ...) +{ + va_list argptr; + char str[10000]; + FILE *f; + time_t now; + char buf[1000]; + + va_start(argptr, format); + vsprintf(str, (char *) format, argptr); + va_end(argptr); + + f = fopen("c:\\tmp\\elogd.log", "a"); + if (!f) + return; + + now = time(0); + strftime(buf, sizeof(buf), "%d-%b-%Y %H:%M:%S", localtime(&now)); + strcat(buf, " "); + + strlcat(buf, str, sizeof(buf)); + if (buf[strlen(buf) - 1] != '\n') + strlcat(buf, "\n", sizeof(buf)); + + fprintf(f, buf); + + fclose(f); +} +*/ + +/*------------------------------------------------------------------*/ + int is_html(char *s) { char *str; @@ -18395,6 +18431,214 @@ void cleanup(void) /*------------------------------------------------------------------*/ +#ifdef OS_WINNT + +/* Routines for Windows service management */ + +// Executable name +#define ELOGDAPPNAME "elogd" + +// Internal service name +#define ELOGDSERVICENAME "elgod" + +// Displayed service name +#define ELOGDSERVICEDISPLAYNAME "ELOG Server" + +SERVICE_STATUS serviceStatus; +SERVICE_STATUS_HANDLE serviceStatusHandle = 0; + +int install_service(void) +{ + OSVERSIONINFO vi; + char path[2048], cmd[2080]; + SC_HANDLE hservice; + SC_HANDLE hsrvmanager; + + /* check for Windows NT+ */ + + vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&vi); + if (vi.dwPlatformId != VER_PLATFORM_WIN32_NT) { + printf("Can install service only under Windows NT/2k/XP\n"); + return -1; + } + + if (GetModuleFileName(NULL, path, sizeof(path)) == 0) { + return -1; + } + + sprintf(cmd, "\"%s\" -D", path); + + /* Open the default, local Service Control Manager database */ + hsrvmanager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (hsrvmanager == NULL) + return -1; + + /* Create an entry for the elogd service */ + hservice = CreateService(hsrvmanager, // SCManager database + ELOGDSERVICENAME, // name of service + ELOGDSERVICEDISPLAYNAME, // name to display + SERVICE_ALL_ACCESS, // desired access + SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, + // service type + SERVICE_AUTO_START, // start type + SERVICE_ERROR_NORMAL, // error control type + cmd, // service's binary + NULL, // no load ordering group + NULL, // no tag identifier + "", // dependencies + NULL, // LocalSystem account + NULL); // no password + + if (hservice == NULL) { + if (GetLastError() == ERROR_SERVICE_EXISTS) + printf("The elogd service is already registered"); + else + printf("The elogd service could not be registered"); + } else { + + /* Try to start the elogd service */ + if (!StartService(hservice, 0, NULL)) + printf("The elogd service could not be started"); + + CloseServiceHandle(hservice); + } + + CloseServiceHandle(hsrvmanager); + return 1; +} + +int remove_service(void) +{ + SC_HANDLE hservice; + SC_HANDLE hsrvmanager; + SERVICE_STATUS status; + + /* Open the SCM */ + hsrvmanager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (hsrvmanager == NULL) + return -1; + + hservice = OpenService(hsrvmanager, ELOGDSERVICENAME, SERVICE_ALL_ACCESS); + if (hservice == NULL) { + printf("The elogd service could not be found"); + return -1; + } + + /* Try to stop the elogd service */ + if (ControlService(hservice, SERVICE_CONTROL_STOP, &status)) { + while (QueryServiceStatus(hservice, &status)) { + if (status.dwCurrentState == SERVICE_STOP_PENDING) + Sleep(1000); + else + break; + } + + if (status.dwCurrentState != SERVICE_STOPPED) { + printf("The elogd service could not be stopped"); + } + } + + /* Now remove the service from the SCM */ + if (!DeleteService(hservice)) { + if (GetLastError() == ERROR_SERVICE_MARKED_FOR_DELETE) + printf("The elogd service is already marked to be unregistered"); + else + printf("The elogd service could not be unregistered"); + } + + CloseServiceHandle(hservice); + CloseServiceHandle(hsrvmanager); + return 1; +} + +void WINAPI ServiceControlHandler(DWORD controlCode) +{ + switch (controlCode) + { + case SERVICE_CONTROL_INTERROGATE: + break; + + case SERVICE_CONTROL_SHUTDOWN: + case SERVICE_CONTROL_STOP: + serviceStatus.dwCurrentState = SERVICE_STOP_PENDING; + SetServiceStatus( serviceStatusHandle, &serviceStatus ); + + _abort = TRUE; + + return; + + case SERVICE_CONTROL_PAUSE: + break; + + case SERVICE_CONTROL_CONTINUE: + break; + + default: + if (controlCode >= 128 && controlCode <= 255) + // user defined control code + break; + else + // unrecognised control code + break; + } + + SetServiceStatus(serviceStatusHandle, &serviceStatus); +} + +void WINAPI ServiceMain(DWORD argc, LPSTR *argv) +{ + // initialise service status + serviceStatus.dwServiceType = SERVICE_WIN32; + serviceStatus.dwCurrentState = SERVICE_STOPPED; + serviceStatus.dwControlsAccepted = 0; + serviceStatus.dwWin32ExitCode = NO_ERROR; + serviceStatus.dwServiceSpecificExitCode = NO_ERROR; + serviceStatus.dwCheckPoint = 0; + serviceStatus.dwWaitHint = 0; + + serviceStatusHandle = RegisterServiceCtrlHandler(ELOGDSERVICENAME, ServiceControlHandler); + + if (serviceStatusHandle) { + // service is starting + serviceStatus.dwCurrentState = SERVICE_START_PENDING; + SetServiceStatus(serviceStatusHandle, &serviceStatus); + + // running + serviceStatus.dwControlsAccepted |= (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN); + serviceStatus.dwCurrentState = SERVICE_RUNNING; + SetServiceStatus(serviceStatusHandle, &serviceStatus); + + /* start main server, exit with "_abort = TRUE" */ + server_loop(tcp_port, FALSE); + + // service was stopped + serviceStatus.dwCurrentState = SERVICE_STOP_PENDING; + SetServiceStatus(serviceStatusHandle, &serviceStatus); + + // service is now stopped + serviceStatus.dwControlsAccepted &= ~(SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN); + serviceStatus.dwCurrentState = SERVICE_STOPPED; + SetServiceStatus(serviceStatusHandle, &serviceStatus); + } +} + +void run_service(void) +{ + SERVICE_TABLE_ENTRY serviceTable[] = + { + { ELOGDSERVICENAME, ServiceMain }, + { 0, 0 } + }; + + StartServiceCtrlDispatcher(serviceTable); + +} + +#endif + +/*------------------------------------------------------------------*/ + int main(int argc, char *argv[]) { int i, fh, tcp_port_cl; @@ -18410,14 +18654,21 @@ int main(int argc, char *argv[]) orig_gid = getegid(); orig_uid = geteuid(); #endif + /* register cleanup function */ atexit(cleanup); + tzset(); + + /* initialize variables */ read_pwd[0] = write_pwd[0] = admin_pwd[0] = logbook[0] = 0; logbook_dir[0] = resource_dir[0] = logbook_dir[0] = pidfile[0] = 0; tcp_port_cl = 0; + use_keepalive = TRUE; + /* default config file */ strcpy(config_file, "elogd.cfg"); + /* evaluate predefined files and directories */ #ifdef CONFIG_FILE strlcpy(config_file, CONFIG_FILE, sizeof(config_file)); @@ -18428,25 +18679,7 @@ int main(int argc, char *argv[]) #ifdef LOGBOOK_DIR strlcpy(logbook_dir, LOGBOOK_DIR, sizeof(logbook_dir)); #endif - /* look for config file in command line parameters */ - for (i = 1; i < argc; i++) { - if (argv[i][0] == '-' && argv[i][1] == 'c') - strcpy(config_file, argv[i + 1]); - } - /* check for configuration file */ - fh = open(config_file, O_RDONLY | O_BINARY); - if (fh < 0) { - printf("Configuration file \"%s\" not found.\n", config_file); - exit(EXIT_FAILURE); - } - close(fh); - /* evaluate directories fron config file */ - if (getcfg("global", "Resource Dir", str)) - strlcpy(resource_dir, str, sizeof(resource_dir)); - if (getcfg("global", "Logbook Dir", str)) - strlcpy(logbook_dir, str, sizeof(logbook_dir)); - use_keepalive = TRUE; /* parse command line parameters */ for (i = 1; i < argc; i++) { if (argv[i][0] == '-' && argv[i][1] == 'D') @@ -18464,7 +18697,19 @@ int main(int argc, char *argv[]) tms->tm_year % 100, tms->tm_mon + 1, tms->tm_mday, tms->tm_hour, tms->tm_min, tms->tm_sec); exit(EXIT_SUCCESS); - } else if (argv[i][0] == '-') { + } + +#ifdef OS_WINNT + else if (stricmp(argv[i], "-install") == 0) { + install_service(); + exit(EXIT_SUCCESS); + } else if (stricmp(argv[i], "-remove") == 0) { + remove_service(); + exit(EXIT_SUCCESS); + } +#endif + + else if (argv[i][0] == '-') { if (i + 1 >= argc || argv[i + 1][0] == '-') goto usage; if (argv[i][1] == 'p') @@ -18483,17 +18728,16 @@ int main(int argc, char *argv[]) strcpy(admin_pwd, argv[++i]); else if (argv[i][1] == 'l') strcpy(logbook, argv[++i]); - else if (argv[i][1] == 'h') + else if (argv[i][1] == 'n') strlcpy(tcp_hostname, argv[++i], sizeof(tcp_hostname)); else if (argv[i][1] == 'f') strlcpy(pidfile, argv[++i], sizeof(pidfile)); else { usage: - printf - ("usage: %s [-p port] [-h hostname] [-D] [-c file] [-r pwd] [-w pwd] [-a pwd] [-l logbook] [-k] [-f file]\n\n", - argv[0]); + printf("\nusage: elogd [-p port] [-n hostname] [-D] [-c file] [-r pwd] "); + printf("[-w pwd] [-a pwd] [-l logbook] [-k] [-f file] [-x]\n\n"); printf(" -p TCP/IP port\n"); - printf(" -h TCP/IP hostname\n"); + printf(" -n TCP/IP hostname\n"); printf(" -D become a daemon\n"); printf(" -c specify configuration file\n"); printf(" -s specify resource directory (themes, icons, ...)\n"); @@ -18506,11 +18750,44 @@ int main(int argc, char *argv[]) printf(" -k do not use keep-alive\n"); printf(" -f path/filename for PID file\n"); printf(" -x enable execution of shell commands\n\n"); + printf(" -h this help\n\n"); +#ifdef OS_WINNT + printf("Windows service funtions:\n"); + printf(" -install install elogd as service and start it\n"); + printf(" -remove stop and remove elogd service\n"); +#endif exit(EXIT_SUCCESS); } } } +#ifdef OS_WINNT + if (daemon) { + /* change to directory of executable */ + strcpy(str, argv[0]); + for (i=strlen(str)-1 ; i>0 ; i--) + if (str[i] != '\\') + str[i] = 0; + else + break; + chdir(str); + } +#endif + + /* check for configuration file */ + fh = open(config_file, O_RDONLY | O_BINARY); + if (fh < 0) { + printf("Configuration file \"%s\" not found.\n", config_file); + exit(EXIT_FAILURE); + } + close(fh); + + /* evaluate directories fron config file */ + if (getcfg("global", "Resource Dir", str)) + strlcpy(resource_dir, str, sizeof(resource_dir)); + if (getcfg("global", "Logbook Dir", str)) + strlcpy(logbook_dir, str, sizeof(logbook_dir)); + if ((read_pwd[0] || write_pwd[0] || admin_pwd[0]) && !logbook[0]) { printf("Must specify a lookbook via the -l parameter.\n"); exit(EXIT_SUCCESS); @@ -18580,6 +18857,12 @@ int main(int argc, char *argv[]) tcp_port = atoi(str); } +#ifdef OS_WINNT + if (daemon) + run_service(); + else +#endif + server_loop(tcp_port, daemon); exit(EXIT_SUCCESS); }