📄 service.c
字号:
/* Prevent holding open the (hidden) console */ real_exit_code = 0; Windows9xServiceCtrlHandler(ap_control_handler, service_name); atexit(stop_service_monitor); /* Run the service */ globdat.exit_status = main_fn(argc, argv); return (globdat.exit_status);}static HANDLE eventlog_pipewrite = NULL;static HANDLE eventlog_thread = NULL;int service_main(int (*main_fn)(int, char **), int argc, char **argv ){ SERVICE_TABLE_ENTRY dispatchTable[] = { { "", service_main_fn }, { NULL, NULL } }; /* Prevent holding open the (nonexistant) console and allow us past * the first NT service to parse the service's args in apache_main() */ ap_server_argv0 = argv[0]; real_exit_code = 0; /* keep the server from going to any real effort, since we know */ is_service = 1; globdat.main_fn = main_fn; globdat.connected = 1; if(!StartServiceCtrlDispatcher(dispatchTable)) { /* This is a genuine failure of the SCM. */ ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL, "Error starting service control dispatcher"); } globdat.connected = 0; if (eventlog_pipewrite) { CloseHandle(eventlog_pipewrite); WaitForSingleObject(eventlog_thread, 10000); eventlog_pipewrite = NULL; } return(globdat.exit_status);}long __stdcall service_stderr_thread(LPVOID hPipe){ HANDLE hPipeRead = (HANDLE) hPipe; HANDLE hEventSource; char errbuf[256]; char *errmsg = errbuf; char *errarg[9]; DWORD errlen = 0; DWORD errres; HKEY hk; errarg[0] = "The Apache service named"; errarg[1] = ap_server_argv0; errarg[2] = "reported the following error:\r\n>>>"; errarg[3] = errmsg; errarg[4] = "<<<\r\n before the error.log file could be opened.\r\n"; errarg[5] = "More information may be available in the error.log file."; errarg[6] = NULL; errarg[7] = NULL; errarg[8] = NULL; /* What are we going to do in here, bail on the user? not. */ if (!RegCreateKey(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services" "\\EventLog\\Application\\Apache Service", &hk)) { /* The stock message file */ char *netmsgkey = "%SystemRoot%\\System32\\netmsg.dll"; DWORD dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE; RegSetValueEx(hk, "EventMessageFile", 0, REG_EXPAND_SZ, (LPBYTE) netmsgkey, strlen(netmsgkey) + 1); RegSetValueEx(hk, "TypesSupported", 0, REG_DWORD, (LPBYTE) &dwData, sizeof(dwData)); RegCloseKey(hk); } hEventSource = RegisterEventSource(NULL, "Apache Service"); while (ReadFile(hPipeRead, errmsg, 1, &errres, NULL) && (errres == 1)) { if ((errmsg > errbuf) || !isspace(*errmsg)) { ++errlen; ++errmsg; if ((*(errmsg - 1) == '\n') || (errlen == sizeof(errbuf) - 1)) { while (errlen && isspace(errbuf[errlen - 1])) --errlen; errbuf[errlen] = '\0'; /* Generic message: '%1 %2 %3 %4 %5 %6 %7 %8 %9' * The event code in netmsg.dll is 3299 */ ReportEvent(hEventSource, EVENTLOG_ERROR_TYPE, 0, 3299, NULL, 9, 0, errarg, NULL); errmsg = errbuf; errlen = 0; } } } ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, NULL, "Shut down the Service Error Event Logger."); CloseHandle(eventlog_pipewrite); eventlog_pipewrite = NULL; CloseHandle(hPipeRead); CloseHandle(eventlog_thread); eventlog_thread = NULL; return 0;}void __stdcall service_main_fn(DWORD argc, LPTSTR *argv){ HANDLE hCurrentProcess; HANDLE hPipeRead = NULL; HANDLE hPipeReadDup; HANDLE hNullFile; DWORD threadid; SECURITY_ATTRIBUTES sa = {0}; char **newargv; if(!(globdat.hServiceStatus = RegisterServiceCtrlHandler(argv[0], service_ctrl))) { ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL, "Failure registering service handler"); return; } ReportStatusToSCMgr( SERVICE_START_PENDING, // service state NO_ERROR, // exit code 3000); // wait hint /* Create a pipe to send stderr messages to the system error log */ hCurrentProcess = GetCurrentProcess(); if (CreatePipe(&hPipeRead, &eventlog_pipewrite, &sa, 0)) { if (DuplicateHandle(hCurrentProcess, hPipeRead, hCurrentProcess, &hPipeReadDup, 0, FALSE, DUPLICATE_SAME_ACCESS)) { CloseHandle(hPipeRead); hPipeRead = hPipeReadDup; eventlog_thread = CreateThread(NULL, 0, service_stderr_thread, (LPVOID) hPipeRead, 0, &threadid); if (eventlog_thread) { int fh; FILE *fl; fflush(stderr); SetStdHandle(STD_ERROR_HANDLE, eventlog_pipewrite); fh = _open_osfhandle((long) STD_ERROR_HANDLE, _O_WRONLY | _O_BINARY); dup2(fh, STDERR_FILENO); fl = _fdopen(STDERR_FILENO, "wcb"); memcpy(stderr, fl, sizeof(FILE)); } else { CloseHandle(hPipeRead); CloseHandle(eventlog_pipewrite); eventlog_pipewrite = NULL; } } else { CloseHandle(hPipeRead); CloseHandle(eventlog_pipewrite); eventlog_pipewrite = NULL; } } /* Open a null handle to nak our stdin */ hNullFile = CreateFile("nul", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, OPEN_EXISTING, 0, NULL); if (hNullFile == INVALID_HANDLE_VALUE) { ap_log_error(APLOG_MARK, APLOG_WIN32ERROR | APLOG_CRIT, NULL, "Parent: Unable to create null stdin pipe for this service process.\n"); } else { int fh; FILE *fl; fflush(stdin); SetStdHandle(STD_INPUT_HANDLE, hNullFile); fh = _open_osfhandle((long) STD_INPUT_HANDLE, _O_RDONLY | _O_BINARY); dup2(fh, STDIN_FILENO); fl = _fdopen(STDIN_FILENO, "rcb"); memcpy(stdin, fl, sizeof(FILE)); } /* Open a null handle to soak our stdout */ hNullFile = CreateFile("nul", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, OPEN_EXISTING, 0, NULL); if (hNullFile == INVALID_HANDLE_VALUE) { ap_log_error(APLOG_MARK, APLOG_WIN32ERROR | APLOG_CRIT, NULL, "Parent: Unable to create null stdout pipe for this service process.\n"); } else { int fh; FILE *fl; fflush(stdout); SetStdHandle(STD_OUTPUT_HANDLE, hNullFile); fh = _open_osfhandle((long) STD_OUTPUT_HANDLE, _O_WRONLY | _O_BINARY); dup2(fh, STDOUT_FILENO); fl = _fdopen(STDOUT_FILENO, "wcb"); memcpy(stdout, fl, sizeof(FILE)); } /* Grab it or lose it */ globdat.name = argv[0]; ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, NULL, "Hooked up the Service Error Event Logger."); /* Fold the "Start Parameters" in with the true executable argv[0], * and insert a -n tag to pass the service name from the SCM's argv[0] */ newargv = (char**) malloc((argc + 3) * sizeof(char*)); newargv[0] = ap_server_argv0; /* The true executable name */ newargv[1] = "-n"; /* True service name follows (argv[0]) */ memcpy (newargv + 2, argv, argc * sizeof(char*)); newargv[argc + 2] = NULL; /* SCM doesn't null terminate the array */ argv = newargv; argc += 2; /* Use the name of the service as the error log marker */ ap_server_argv0 = globdat.name; globdat.exit_status = globdat.main_fn( argc, argv );}/* Set the service description regardless of platform. * We revert to set_service_description_string on NT/9x, the * very long way so any Apache management program can grab the * description. This would be bad on Win2000, since it wouldn't * notify the service control manager of the name change. */static void set_service_description_string(const char *description){ char szPath[MAX_PATH]; HKEY hkey; /* Create/Find the Service key that Monitor Applications iterate */ ap_snprintf(szPath, sizeof(szPath), "SYSTEM\\CurrentControlSet\\Services\\%s", globdat.name); ap_remove_spaces(szPath, szPath); if (RegCreateKey(HKEY_LOCAL_MACHINE, szPath, &hkey) != ERROR_SUCCESS) { return; } /* Attempt to set the Description value for our service */ RegSetValueEx(hkey, "Description", 0, REG_SZ, (unsigned char *) description, strlen(description) + 1); RegCloseKey(hkey);}char *get_service_name(char *display_name){ /* Get the service's true name from the SCM on NT/2000, since it * can be changed by the user on 2000, especially, from the * service control panel. We can't trust the service name to * match a space-collapsed display name. */ char service_name[MAX_PATH]; if (isWindowsNT()) { SC_HANDLE scm = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE); DWORD namelen = sizeof(service_name); if (scm) { BOOL ok = GetServiceKeyName(scm, display_name, service_name, &namelen); CloseServiceHandle(scm); if (ok) return strdup(service_name); } } ap_remove_spaces(service_name, display_name); return strdup(service_name);}char *get_display_name(char *service_name){ /* Get the service's display name from the SCM on NT/2000, since it * can be changed by the user on 2000, especially, from the * service control panel. We can't trust the service name as * provided by the user. */ if (isWindowsNT()) { char display_name[MAX_PATH]; SC_HANDLE scm = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE); DWORD namelen = sizeof(display_name); if (scm) { BOOL ok = GetServiceDisplayName(scm, service_name, display_name, &namelen); CloseServiceHandle(scm); if (ok) return strdup(display_name); } } return service_name;}/* ChangeServiceConfig2() prototype: */typedef WINADVAPI BOOL (WINAPI *CSD_T)(SC_HANDLE, DWORD, LPCVOID);/* Windows 2000 alone supports ChangeServiceConfig2 in order to * register our server_version string... so we need some fixups * to avoid binding to that function if we are on WinNT/9x. * Fall back on set_service_description_string if we fail. */void service_set_status(int status){ const char *full_description; SC_HANDLE schSCManager; CSD_T ChangeServiceDescription; HANDLE hwin2000scm; BOOL ret = 0; /* Nothing to do if we are a console */ if (!is_service) return; ReportStatusToSCMgr(status, NO_ERROR, 3000); if (status != SERVICE_RUNNING) return; /* Time to fix up the description, upon each successful restart */ full_description = ap_get_server_version(); hwin2000scm = GetModuleHandle("ADVAPI32.DLL"); if (!hwin2000scm) { set_service_description_string(full_description); return; } ChangeServiceDescription = (CSD_T) GetProcAddress(hwin2000scm, "ChangeServiceConfig2A");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -