#include #include #include #include #include #include "mix3.h" #ifdef WIN32SERVICE #define SVCNAME "Mixmaster" #define SVCDISPLAYNAME "Mixmaster Service" /* internal variables */ static SERVICE_STATUS ssStatus; static SERVICE_STATUS_HANDLE sshStatusHandle; static BOOL not_service = FALSE; static HANDLE hThread = NULL; static HANDLE hMustTerminate = NULL; /* internal function prototypes */ VOID WINAPI service_ctrl(DWORD ctrl_code); VOID WINAPI service_main(DWORD argc, LPSTR *argv); static DWORD service_run(void); static void service_stop(); static int set_stdfiles(); static int install_service(); static int remove_service(); static int run_notservice(int argc, char **argv); BOOL WINAPI console_ctrl_handler(DWORD ctrl_type); static char *GetLastErrorText(); static BOOL send_status(DWORD current_state, DWORD exit_code, DWORD wait_hint, DWORD id); static void event_log(DWORD id, char *eventmsg); int mix_main(int argc, char *argv[]); int main(int argc, char *argv[]) { SERVICE_TABLE_ENTRY dispatchTable[] = { {SVCNAME, (LPSERVICE_MAIN_FUNCTION)service_main}, {NULL, NULL} }; if ((argc > 1) && ((argv[1][0] == '-') && (argv[1][1] == '-'))) { if (!_stricmp("install-svc", argv[1]+2)) return install_service(); else if (!_stricmp("remove-svc", argv[1]+2)) return remove_service(); else if (_stricmp("run-svc", argv[1]+2) && !is_nt_service()) return run_notservice(argc, argv); } else if (!is_nt_service()) { return run_notservice(argc, argv); } printf("mix --install-svc install the service\n"); printf("mix --remove-svc remove the service\n"); printf("mix --run-svc run as a service\n"); printf("mix -h view a summary of the command line options.\n"); printf("\nStartServiceCtrlDispatcher being called.\n" ); printf("This may take several seconds. Please wait.\n" ); if (!StartServiceCtrlDispatcher(dispatchTable)) { printf("Service not started: StartServiceCtrlDispatcher failed.\n" ); event_log(1000, "Service not started: StartServiceCtrlDispatcher failed"); } return 0; } /* main */ VOID WINAPI service_main(DWORD argc, LPSTR *argv) { DWORD err = 0; if (!(sshStatusHandle = RegisterServiceCtrlHandler(SVCNAME, service_ctrl))) return; ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; ssStatus.dwServiceSpecificExitCode = 0; if (send_status(SERVICE_START_PENDING, NO_ERROR, 1000, 1020)) err = service_run(); send_status(SERVICE_STOPPED, err, 0, err ? 1030 : 30); } /* service_main */ VOID WINAPI service_ctrl(DWORD ctrl_code) { /* Handle the requested control code. */ if (ctrl_code == SERVICE_CONTROL_STOP || ctrl_code == SERVICE_CONTROL_SHUTDOWN) service_stop(); else send_status(ssStatus.dwCurrentState, NO_ERROR, 0, 1040 + ctrl_code); } /* service_ctrl */ static DWORD service_run(void) { char filename[_MAX_PATH+1]; char home[_MAX_PATH+1], *p; char *svc_argv[2] = {filename, "-D"}; if (!hMustTerminate) hMustTerminate = CreateEvent(NULL, FALSE, FALSE, NULL); set_nt_exit_event(hMustTerminate); DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &hThread, 0, FALSE, DUPLICATE_SAME_ACCESS); GetModuleFileName(NULL , filename, _MAX_PATH); strcpy(home, filename); if (p = strrchr(home, '\\')) { *p = 0; chdir(home); } if (!set_stdfiles()) { event_log(1010, "stdin|stdout|stderr not created"); return ERROR_SERVICE_NOT_ACTIVE; } send_status(SERVICE_RUNNING, NO_ERROR, 0, 1060); event_log(10, "Mixmaster Service started"); mix_main(2, svc_argv); return 0; } /* service_run */ static void service_stop(void) { send_status(SERVICE_STOP_PENDING, NO_ERROR, 5000, 1070); if (hMustTerminate) { SetEvent(hMustTerminate); if (WaitForSingleObject(hThread, 4500) == WAIT_TIMEOUT) { if (hThread) { TerminateThread(hThread, 0); event_log(1080, "Mixmaster Service terminated forcibly"); } } else event_log(20, "Mixmaster Service stopped"); CloseHandle(hMustTerminate); hMustTerminate = NULL; } else if (hThread) TerminateThread(hThread, 0); if (hThread) CloseHandle(hThread); hThread = NULL; ssStatus.dwCurrentState = SERVICE_STOPPED; } /* service_stop */ static int set_stdfiles() { /* needed for _popen() */ static DWORD std_handles[]={STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE}; FILE *stdfile[]={stdin, stdout, stderr}; HANDLE hStd; int fh, stf_fileno; FILE *fl; AllocConsole(); for (stf_fileno=0; stf_fileno<=2; stf_fileno++) { hStd = GetStdHandle(std_handles[stf_fileno]); if (hStd == INVALID_HANDLE_VALUE) return 0; fh = _open_osfhandle((long)std_handles[stf_fileno], (stf_fileno ? _O_WRONLY : _O_RDONLY ) | _O_BINARY); dup2(fh, stf_fileno); fl = _fdopen(stf_fileno, (stf_fileno ? "wcb" : "rcb" )); fflush(stdfile[stf_fileno]); memcpy(stdfile[stf_fileno], fl, sizeof(FILE)); } return 1; } /* set_stdfiles */ static BOOL send_status(DWORD current_state, DWORD exit_code, DWORD wait_hint, DWORD id) { static DWORD dwCheckPoint = 1; BOOL ret_val; if (not_service) return TRUE; ssStatus.dwCurrentState = current_state; ssStatus.dwWin32ExitCode = exit_code; ssStatus.dwWaitHint = wait_hint; ssStatus.dwControlsAccepted = (current_state == SERVICE_START_PENDING) ? 0 : SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; ssStatus.dwCheckPoint = ((current_state == SERVICE_RUNNING) || (current_state == SERVICE_STOPPED)) ? 0 : dwCheckPoint++; if (!(ret_val = SetServiceStatus(sshStatusHandle, &ssStatus))) event_log(id, "SetServiceStatus failed"); return ret_val; } /* send_status */ static void event_log(DWORD id, char *eventmsg) { HANDLE hEventSource; char *pStrings[2] = {"", eventmsg}; if (not_service) return; if (id > 1000) pStrings[0] = GetLastErrorText(); if (!(hEventSource = RegisterEventSource(NULL, SVCNAME))) return; ReportEvent(hEventSource, (WORD)((id < 1000) ? EVENTLOG_SUCCESS : EVENTLOG_ERROR_TYPE), 0, id, NULL, 2, 0, pStrings, NULL); DeregisterEventSource(hEventSource); } /* event_log */ static int run_notservice(int argc, char ** argv) { not_service = TRUE; return mix_main(argc, argv); } /* run_notservice */ static int install_service() { SC_HANDLE schService, schSCManager; char filename[_MAX_PATH+10]; if (GetModuleFileName(NULL, filename, _MAX_PATH) == 0) { printf("Unable to install Mixmaster Service: %s\n", GetLastErrorText()); return 1; } strcat(filename, " --run-svc"); if (!(schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS))) { printf("OpenSCManager failed: %s\n", GetLastErrorText()); return 1; } schService = CreateService(schSCManager, SVCNAME, SVCDISPLAYNAME, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, filename, NULL, NULL, NULL, NULL, NULL); if (schService) { printf("Mixmaster Service installed.\n"); CloseServiceHandle(schService); } else { printf("CreateService failed: %s\n", GetLastErrorText()); } CloseServiceHandle(schSCManager); return 0; } /* install_service */ static int remove_service() { SC_HANDLE schService, schSCManager; int ret_val = 0; if (!(schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS))) { printf("OpenSCManager failed: %s\n", GetLastErrorText()); return 1; } if (!(schService = OpenService(schSCManager, SVCNAME, SERVICE_ALL_ACCESS))) { CloseServiceHandle(schSCManager); printf("OpenService failed: %s\n", GetLastErrorText()); return 1; } /* try to stop the service */ if (ControlService(schService, SERVICE_CONTROL_STOP, &ssStatus)) { printf("Stopping Mixmaster Service"); do { Sleep(1000); printf("."); QueryServiceStatus(schService, &ssStatus); } while (ssStatus.dwCurrentState != SERVICE_STOP_PENDING); if (ssStatus.dwCurrentState == SERVICE_STOPPED) printf("\nMixmaster Service stopped.\n"); else printf("\n%Mixmaster Service failed to stop.\n"); } /* now remove the service */ if (!DeleteService(schService)) { ret_val = 1; printf("DeleteService failed: %s\n", GetLastErrorText()); } else printf("Mixmaster Service removed.\n"); CloseServiceHandle(schService); CloseServiceHandle(schSCManager); return ret_val; } /* remove_service */ static char *GetLastErrorText() { static char error_buf[256]; DWORD dwRet, err; LPSTR lpszTemp = NULL; dwRet = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY, NULL, err=GetLastError(), LANG_NEUTRAL, (LPSTR)&lpszTemp, 0, NULL); /* supplied buffer is not long enough */ if (!dwRet || (256 < (long)dwRet+14)) sprintf(error_buf, "Error (0x%x)", err); else { lpszTemp[lstrlen(lpszTemp)-2] = '\0'; /* remove cr and newline character */ sprintf(error_buf, "%s (0x%x)", lpszTemp, err); } if (lpszTemp) LocalFree((HLOCAL)lpszTemp); return error_buf; } /* GetLastErrorText */ #endif /* WIN32SERVICE */