📄 service.c
字号:
/* * This source code is a part of coLinux source package. * * Dan Aloni <da-x@colinux.org>, 2003 (c) * * Service support by Jaroslaw Kowalski <jaak@zd.com.pl>, 2004 (c) * Driver service separation by Daniel R. Slater <dan_slater@yahoo.com>, 2004 (c) * * The code is licensed under the GPL. See the COPYING file at * the root directory. * */ #include <windows.h>#include <winsvc.h>#include <shlwapi.h>#include <colinux/user/daemon.h>#include <colinux/user/manager.h>#include <colinux/os/user/misc.h>#include <colinux/os/winnt/kernel/driver.h>#include <colinux/os/winnt/user/misc.h>#include "main.h"#include "cmdline.h"#include "misc.h"#include "driver.h"#include "service.h"#include "res/service-message.h"/* * The coLinux driver that the colinux service depends on - needs * to be double-null terminated */#define CO_DRIVER_DEPENDENCY_NAME CO_DRIVER_NAME "\0\0"#define MAX_CMD_LINE_PATCHED 1024/* * ChangeServiceConfig2 is only supported on Windows 2000 * and later. Will try to dynamically load the function pointer * so we still can run under Windows NT 4.0 */void co_winnt_set_service_restart_options(SC_HANDLE schService){ BOOL (WINAPI *ChangeServiceConfig2Ptr)(SC_HANDLE h, DWORD dw, LPVOID lp) = NULL; HINSTANCE hLib = NULL; hLib = LoadLibrary("Advapi32.dll"); if (hLib != NULL) { ChangeServiceConfig2Ptr = GetProcAddress(hLib,"ChangeServiceConfig2A"); FreeLibrary(hLib); } if (ChangeServiceConfig2Ptr) { SC_ACTION actions[3] = { {0} }; SERVICE_FAILURE_ACTIONS actions_info = {0}; co_terminal_print("daemon: setting restart options\n"); actions[0].Type = SC_ACTION_RESTART; /* restart the service */ actions[0].Delay = 1000; /* wait 1 second */ actions[1].Type = SC_ACTION_RESTART; /* restart the service */ actions[1].Delay = 1000; /* wait 1 second */ actions[2].Type = SC_ACTION_NONE; /* abandon our efforts */ actions[2].Delay = 0; /* wait 1 second */ actions_info.dwResetPeriod = 90; /* if we run for 90 seconds, then reset the failure count */ actions_info.cActions = 3; actions_info.lpsaActions = actions; ChangeServiceConfig2Ptr(schService,SERVICE_CONFIG_FAILURE_ACTIONS,&actions_info); }}static char * co_winnt_get_path_from_exe(void){ static char exe_name[512]; if (!GetModuleFileName(0, exe_name, sizeof(exe_name))) { co_debug_error("daemon: cannot determine exe name."); return NULL; } if (!PathRemoveFileSpec(exe_name)) { co_debug_error("daemon: cannot get path from exe name."); return NULL; } return exe_name;}void co_winnt_change_directory_for_service(int argc, char **argv){ char *p; static const char run_service []= { "--run-service" }; while (*argv && argc--) { p = *argv++; if (0 == strncmp(p, run_service, sizeof(run_service)-1)) { p += sizeof(run_service)-1; /* With path? */ if (*p == ':') { /* remove the ':', let p point to path */ *p++ = '\0'; } else { p = co_winnt_get_path_from_exe(); } co_debug("cd '%s'", p); if (SetCurrentDirectory(p) == 0) co_terminal_print_last_error("daemon: Set working directory for service failed.\n"); return; } }}static void patch_command_line_for_service(char *destbuf, const char *srcbuf){ char *destmax = destbuf + MAX_CMD_LINE_PATCHED; while (*srcbuf && destbuf < destmax) { if (0 == strncmp(srcbuf, "--install-service", 17)) { /* replace any instance of --install-service with --run-service */ srcbuf += 17; strcpy(destbuf, "--run-service:"); destbuf = destbuf + strlen(destbuf); /* Add current working directory for service run later */ GetCurrentDirectory(destmax-destbuf, destbuf); if (0 == strcasecmp(destbuf, co_winnt_get_path_from_exe())) { /* CWD is the path of exe. No need extra path. */ destbuf--; } else { destbuf = destbuf + strlen(destbuf); } continue; } *destbuf++ = *srcbuf++; } *destbuf = 0;}co_rc_t co_winnt_daemon_install_as_service(const char *service_name, const char *original_commandline) { SC_HANDLE schService; SC_HANDLE schSCManager; char exe_name[512]; char command[1024]; char patched_commandline[MAX_CMD_LINE_PATCHED]; char error_message[1024]; char *service_user_name = NULL; co_terminal_print("daemon: installing service '%s'\n", service_name); if (!GetModuleFileName(0, exe_name, sizeof(exe_name))) { co_terminal_print("Cannot determin exe name. Install failed.\n"); return CO_RC(ERROR); } schSCManager = OpenSCManager(0, 0, SC_MANAGER_ALL_ACCESS); if (schSCManager == 0) { co_terminal_print("daemon: cannot open service control maanger. Install failed.\n"); return CO_RC(ERROR); } patch_command_line_for_service(patched_commandline, original_commandline); co_snprintf(command, sizeof(command), "\"%s\" %s", exe_name, patched_commandline); co_terminal_print("daemon: service command line: %s\n", command);#if (0) /* broken somehow for recent TAP driver */ if (co_winnt_is_winxp_or_better()) service_user_name = "NT AUTHORITY\\NetworkService";#endif schService = CreateService(schSCManager, service_name, service_name, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, command, NULL, NULL, CO_DRIVER_DEPENDENCY_NAME, service_user_name, NULL); if (schService != 0) { co_winnt_set_service_restart_options(schService); co_terminal_print("daemon: service installed.\n"); CloseServiceHandle(schService); CloseServiceHandle(schSCManager); return CO_RC(OK); } co_winnt_get_last_error(error_message, sizeof(error_message)); co_terminal_print("daemon: failed to install service: %s\n", error_message); CloseServiceHandle(schSCManager); return CO_RC(ERROR);}int co_winnt_daemon_remove_service(const char *service_name) { SC_HANDLE schService; SC_HANDLE schSCManager; char error_message[1024]; co_terminal_print("daemon: removing service '%s'\n", service_name); schSCManager = OpenSCManager(0, 0, SC_MANAGER_ALL_ACCESS); if (schSCManager == 0) { co_terminal_print("daemon: cannot open service control manager. Remove failed.\n"); return CO_RC(ERROR); } schService = OpenService(schSCManager, service_name, SERVICE_ALL_ACCESS); if (schService == 0) { co_winnt_get_last_error(error_message, sizeof(error_message)); co_terminal_print("daemon: failed to remove service. OpenService() failed\n"); CloseServiceHandle(schSCManager); return CO_RC(ERROR); } if (!DeleteService(schService)) { co_winnt_get_last_error(error_message, sizeof(error_message)); co_terminal_print("daemon: failed to remove service: %s\n", error_message); CloseServiceHandle(schService); return CO_RC(ERROR); } CloseServiceHandle(schService); CloseServiceHandle(schSCManager); co_terminal_print("daemon: service '%s' removed successfully.\n", service_name); return CO_RC(OK);}static co_start_parameters_t *daemon_start_parameters;static SERVICE_STATUS ssStatus;static SERVICE_STATUS_HANDLE sshStatusHandle;void co_winnt_sc_report_status(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint){ static DWORD dwCheckPoint = 1; if (dwCurrentState == SERVICE_START_PENDING) ssStatus.dwControlsAccepted = 0; else ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; ssStatus.dwCurrentState = dwCurrentState; ssStatus.dwWin32ExitCode = dwWin32ExitCode; ssStatus.dwWaitHint = dwWaitHint; if ((dwCurrentState == SERVICE_RUNNING) || (dwCurrentState == SERVICE_STOPPED)) ssStatus.dwCheckPoint = 0; else ssStatus.dwCheckPoint = dwCheckPoint++; SetServiceStatus(sshStatusHandle, &ssStatus);}void WINAPI co_winnt_service_control_callback(DWORD dwCtrlCode){ switch(dwCtrlCode) { case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: co_ntevent_print("daemon: service control %s.\n", (dwCtrlCode == SERVICE_CONTROL_STOP) ? "STOP" : "SHUTDOWN"); co_winnt_sc_report_status(SERVICE_STOP_PENDING, NO_ERROR, 0); co_winnt_daemon_stop(); return; case SERVICE_CONTROL_INTERROGATE: break; default: break; } co_winnt_sc_report_status(ssStatus.dwCurrentState, NO_ERROR, 0);}static void WINAPI service_main(int _argc, char **_argv) { sshStatusHandle = RegisterServiceCtrlHandler("", co_winnt_service_control_callback); if (sshStatusHandle) { ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; ssStatus.dwServiceSpecificExitCode = 0; co_winnt_sc_report_status(SERVICE_RUNNING, NO_ERROR, 3000); co_ntevent_print("daemon: service running.\n"); co_winnt_daemon_main(daemon_start_parameters); co_ntevent_print("daemon: service stopped.\n"); co_winnt_sc_report_status(SERVICE_STOPPED, 0, 0); }}bool_t co_winnt_daemon_initialize_service(co_start_parameters_t *start_parameters) { SERVICE_TABLE_ENTRY dispatch_table[] = { { "", (LPSERVICE_MAIN_FUNCTION)service_main }, { 0, 0 }, }; daemon_start_parameters = start_parameters; if (!StartServiceCtrlDispatcher(dispatch_table)) { co_terminal_print_last_error("service: Failed to initialize"); return PFALSE; } else { return PTRUE; }}void co_ntevent_print(const char *format, ...){ HANDLE hEventLog; char buf[0x100]; va_list ap; va_start(ap, format); co_vsnprintf(buf, sizeof(buf), format, ap); va_end(ap); co_terminal_print("%s", buf); if (co_running_as_service != PTRUE) return; hEventLog = RegisterEventSource(NULL, "coLinux"); if (hEventLog == NULL) { co_terminal_print("Error registering event source."); return; } const char* szMsgs[] = { buf }; if (ReportEvent(hEventLog, // Event Log Handle EVENTLOG_INFORMATION_TYPE, // Event type 0, // Event category MSG_SERVICE_INFO, // Event ID NULL, // User Security Identifier 1, // # of Strings 0, // Size of Data in Bytes szMsgs, // Message Strings NULL) == 0) // Address of Data co_terminal_print_last_error("Error reporting to Event Log!"); DeregisterEventSource(hEventLog);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -