📄 daemon_win32.cpp
字号:
switch (state) { default: svc_status.dwCheckPoint = checkpoint++; break; case SERVICE_RUNNING: case SERVICE_STOPPED: svc_status.dwCheckPoint = 0; } switch (state) { case SERVICE_START_PENDING: case SERVICE_STOP_PENDING: svc_status.dwControlsAccepted = 0; break; default: svc_status.dwControlsAccepted = SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_SHUTDOWN| SERVICE_ACCEPT_PAUSE_CONTINUE|accept_more; break; } if (!SetServiceStatus(svc_handle, &svc_status)) { if (svc_status.dwControlsAccepted & accept_more) { // Retry without SERVICE_ACCEPT_PARAMCHANGE (WinNT4) svc_status.dwControlsAccepted &= ~accept_more; accept_more = 0; SetServiceStatus(svc_handle, &svc_status); } }}// Control the service, called by SCMstatic void WINAPI service_control(DWORD ctrlcode){ switch (ctrlcode) { case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: service_report_status(SERVICE_STOP_PENDING, 30); svc_paused = 0; SetEvent(sigterm_handle); break; case SERVICE_CONTROL_PARAMCHANGE: // Win2000/XP service_report_status(svc_status.dwCurrentState, 0); svc_paused = 0; SetEvent(sighup_handle); // reload break; case SERVICE_CONTROL_PAUSE: service_report_status(SERVICE_PAUSED, 0); svc_paused = 1; break; case SERVICE_CONTROL_CONTINUE: service_report_status(SERVICE_RUNNING, 0); { int was_paused = svc_paused; svc_paused = 0; SetEvent(was_paused ? sighup_handle : sigusr1_handle); // reload:recheck } break; case SERVICE_CONTROL_INTERROGATE: default: // unknown service_report_status(svc_status.dwCurrentState, 0); break; }}// Exit handler for servicestatic void service_exit(void){ // Close signal events int i; for (i = 0; i < num_sig_handlers; i++) CloseHandle(sig_events[i]); num_sig_handlers = 0; // Set exitcode if (daemon_winsvc_exitcode) { svc_status.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR; svc_status.dwServiceSpecificExitCode = daemon_winsvc_exitcode; } // Report stopped service_report_status(SERVICE_STOPPED, 0);}// Variables for passing main(argc, argv) from daemon_main to service_main()static int (*svc_main_func)(int, char **);static int svc_main_argc;static char ** svc_main_argv;// Main function for service, called by service dispatcherstatic void WINAPI service_main(DWORD argc, LPSTR * argv){ char path[MAX_PATH], *p; ARGUSED(argc); // Register control handler svc_handle = RegisterServiceCtrlHandler(argv[0], service_control); // Init service status svc_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS; service_report_status(SERVICE_START_PENDING, 10); // Service started in \windows\system32, change to .exe directory if (GetModuleFileNameA(NULL, path, sizeof(path)) && (p = strrchr(path, '\\'))) { *p = 0; SetCurrentDirectoryA(path); } // Install exit handler atexit(service_exit); // Do the real work, service status later updated by daemon_detach() daemon_winsvc_exitcode = svc_main_func(svc_main_argc, svc_main_argv); exit(daemon_winsvc_exitcode); // ... continued in service_exit()}/////////////////////////////////////////////////////////////////////////////// Windows Service Admin Functions// Set Service description (Win2000/XP)static int svcadm_setdesc(SC_HANDLE hs, const char * desc){ HINSTANCE hdll; BOOL (WINAPI * ChangeServiceConfig2A_p)(SC_HANDLE, DWORD, LPVOID); BOOL ret; if (!(hdll = LoadLibraryA("ADVAPI32.DLL"))) return FALSE; if (!((ChangeServiceConfig2A_p = (BOOL (WINAPI *)(SC_HANDLE, DWORD, LPVOID))GetProcAddress(hdll, "ChangeServiceConfig2A")))) ret = FALSE; else { SERVICE_DESCRIPTIONA sd = { (char *)desc }; ret = ChangeServiceConfig2A_p(hs, SERVICE_CONFIG_DESCRIPTION, &sd); } FreeLibrary(hdll); return ret;}// Service install/remove commandsstatic int svcadm_main(const char * ident, const daemon_winsvc_options * svc_opts, int argc, char **argv ){ int remove; long err; SC_HANDLE hm, hs; if (argc < 2) return -1; if (!strcmp(argv[1], "install")) remove = 0; else if (!strcmp(argv[1], "remove")) { if (argc != 2) { printf("%s: no arguments allowed for command remove\n", ident); return 1; } remove = 1; } else return -1; printf("%s service %s:", (!remove?"Installing":"Removing"), ident); fflush(stdout); // Open SCM if (!(hm = OpenSCManager(NULL/*local*/, NULL/*default*/, SC_MANAGER_ALL_ACCESS))) { if ((err = GetLastError()) == ERROR_ACCESS_DENIED) puts(" access to SCManager denied"); else if (err == ERROR_CALL_NOT_IMPLEMENTED) puts(" services not implemented on this version of Windows"); else printf(" cannot open SCManager, Error=%ld\n", err); return 1; } if (!remove) { char path[MAX_PATH+100]; int i; // Get program path if (!GetModuleFileNameA(NULL, path, MAX_PATH)) { printf(" unknown program path, Error=%ld\n", GetLastError()); CloseServiceHandle(hm); return 1; } // Append options strcat(path, " "); strcat(path, svc_opts->cmd_opt); for (i = 2; i < argc; i++) { const char * s = argv[i]; if (strlen(path)+strlen(s)+1 >= sizeof(path)) break; strcat(path, " "); strcat(path, s); } // Create if (!(hs = CreateService(hm, svc_opts->svcname, svc_opts->dispname, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, path, NULL/*no load ordering*/, NULL/*no tag id*/, ""/*no depedencies*/, NULL/*local system account*/, NULL/*no pw*/))) { if ((err = GetLastError()) == ERROR_SERVICE_EXISTS) puts(" the service is already installed"); else if (err == ERROR_SERVICE_MARKED_FOR_DELETE) puts(" service is still running and marked for deletion\n" "Stop the service and retry install"); else printf(" failed, Error=%ld\n", err); CloseServiceHandle(hm); return 1; } // Set optional description if (svc_opts->descript) svcadm_setdesc(hs, svc_opts->descript); } else { // Open if (!(hs = OpenService(hm, svc_opts->svcname, SERVICE_ALL_ACCESS))) { puts(" not found"); CloseServiceHandle(hm); return 1; } // TODO: Stop service if running // Remove if (!DeleteService(hs)) { if ((err = GetLastError()) == ERROR_SERVICE_MARKED_FOR_DELETE) puts(" service is still running and marked for deletion\n" "Stop the service to remove it"); else printf(" failed, Error=%ld\n", err); CloseServiceHandle(hs); CloseServiceHandle(hm); return 1; } } puts(" done"); CloseServiceHandle(hs); CloseServiceHandle(hm); return 0;}/////////////////////////////////////////////////////////////////////////////// Main Function// This function must be called from main()// main_func is the function doing the real workint daemon_main(const char * ident, const daemon_winsvc_options * svc_opts, int (*main_func)(int, char **), int argc, char **argv ){ int rc;#ifdef _DEBUG // Enable Debug heap checks _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) |_CRTDBG_ALLOC_MEM_DF|_CRTDBG_CHECK_ALWAYS_DF|_CRTDBG_LEAK_CHECK_DF);#endif // Check for [status|stop|reload|restart|sigusr1|sigusr2] parameters if ((rc = initd_main(ident, argc, argv)) >= 0) return rc; // Check for [install|remove] parameters if (svc_opts && (rc = svcadm_main(ident, svc_opts, argc, argv)) >= 0) return rc; // Run as service if svc_opts.cmd_opt is given as first(!) argument svc_mode = (svc_opts && argc >= 2 && !strcmp(argv[1], svc_opts->cmd_opt)); if (!svc_mode) { // Daemon: Try to simulate a Unix-like daemon HANDLE rev; BOOL exists; // Create main event to detect process type: // 1. new: parent process => start child and wait for detach() or exit() of child. // 2. exists && signaled: child process => do the real work, signal detach() to parent // 3. exists && !signaled: already running => exit() if (!(rev = create_event(EVT_RUNNING, TRUE/*signaled*/, TRUE, &exists))) return 100; if (!exists && !debugging()) { // Event new => parent process return parent_main(rev); } if (WaitForSingleObject(rev, 0) == WAIT_OBJECT_0) { // Event was signaled => In child process return child_main(rev, main_func, argc, argv); } // Event no longer signaled => Already running! daemon_help(stdout, ident, "already running"); CloseHandle(rev); return 1; } else { // Service: Start service_main() via SCM SERVICE_TABLE_ENTRY service_table[] = { { (char*)svc_opts->svcname, service_main }, { NULL, NULL } }; svc_main_func = main_func; svc_main_argc = argc; svc_main_argv = argv; if (!StartServiceCtrlDispatcher(service_table)) { printf("%s: cannot dispatch service, Error=%ld\n" "Option \"%s\" cannot be used to start %s as a service from console.\n" "Use \"%s install ...\" to install the service\n" "and \"net start %s\" to start it.\n", ident, GetLastError(), svc_opts->cmd_opt, ident, ident, ident);#ifdef _DEBUG if (debugging()) service_main(argc, argv);#endif return 100; } Sleep(1000); ExitThread(0); // Do not redo exit() processing /*NOTREACHED*/ return 0; }}/////////////////////////////////////////////////////////////////////////////// Test Program#ifdef TESTstatic volatile sig_atomic_t caughtsig = 0;static void sig_handler(int sig){ caughtsig = sig;}static void test_exit(void){ printf("Main exit\n");}int test_main(int argc, char **argv){ int i; int debug = 0; char * cmd = 0; printf("PID=%ld\n", GetCurrentProcessId()); for (i = 0; i < argc; i++) { printf("%d: \"%s\"\n", i, argv[i]); if (!strcmp(argv[i],"-d")) debug = 1; } if (argc > 1 && argv[argc-1][0] != '-') cmd = argv[argc-1]; daemon_signal(SIGINT, sig_handler); daemon_signal(SIGBREAK, sig_handler); daemon_signal(SIGTERM, sig_handler); daemon_signal(SIGHUP, sig_handler); daemon_signal(SIGUSR1, sig_handler); daemon_signal(SIGUSR2, sig_handler); atexit(test_exit); if (!debug) { printf("Preparing to detach...\n"); Sleep(2000); daemon_detach("test"); printf("Detached!\n"); } for (;;) { daemon_sleep(1); printf("."); fflush(stdout); if (caughtsig) { if (caughtsig == SIGUSR2) { debug ^= 1; if (debug) daemon_enable_console("Daemon[Debug]"); else daemon_disable_console(); } else if (caughtsig == SIGUSR1 && cmd) { char inpbuf[200], outbuf[1000]; int rc; strcpy(inpbuf, "Hello\nWorld!\n"); rc = daemon_spawn(cmd, inpbuf, strlen(inpbuf), outbuf, sizeof(outbuf)); if (!debug) daemon_enable_console("Command output"); printf("\"%s\" returns %d\n", cmd, rc); if (rc >= 0) printf("output:\n%s.\n", outbuf); fflush(stdout); if (!debug) { Sleep(10000); daemon_disable_console(); } } printf("[PID=%ld: Signal=%d]", GetCurrentProcessId(), caughtsig); fflush(stdout); if (caughtsig == SIGTERM || caughtsig == SIGBREAK) break; caughtsig = 0; } } printf("\nExiting on signal %d\n", caughtsig); return 0;}int main(int argc, char **argv){ static const daemon_winsvc_options svc_opts = { "-s", "test", "Test Service", "Service to test daemon_win32.c Module" }; return daemon_main("testd", &svc_opts, test_main, argc, argv);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -