1/* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to You under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "httpd.h" 18#include "http_log.h" 19#include "mpm_winnt.h" 20#include "apr_strings.h" 21#include "apr_lib.h" 22#include "apr_portable.h" 23#include "ap_regkey.h" 24 25static const char *display_name = NULL; 26static HANDLE stderr_thread = NULL; 27static HANDLE stderr_ready; 28 29static DWORD WINAPI service_stderr_thread(LPVOID hPipe) 30{ 31 HANDLE hPipeRead = (HANDLE) hPipe; 32 HANDLE hEventSource; 33 char errbuf[256]; 34 char *errmsg = errbuf; 35 const char *errarg[9]; 36 DWORD errres; 37 ap_regkey_t *regkey; 38 apr_status_t rv; 39 apr_pool_t *p; 40 41 apr_pool_create_ex(&p, NULL, NULL, NULL); 42 43 errarg[0] = "The Apache service named"; 44 errarg[1] = display_name; 45 errarg[2] = "reported the following error:\r\n>>>"; 46 errarg[3] = errbuf; 47 errarg[4] = NULL; 48 errarg[5] = NULL; 49 errarg[6] = NULL; 50 errarg[7] = NULL; 51 errarg[8] = NULL; 52 53 /* What are we going to do in here, bail on the user? not. */ 54 if ((rv = ap_regkey_open(®key, AP_REGKEY_LOCAL_MACHINE, 55 "SYSTEM\\CurrentControlSet\\Services\\" 56 "EventLog\\Application\\Apache Service", 57 APR_READ | APR_WRITE | APR_CREATE, p)) 58 == APR_SUCCESS) 59 { 60 DWORD dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | 61 EVENTLOG_INFORMATION_TYPE; 62 63 /* The stock message file */ 64 ap_regkey_value_set(regkey, "EventMessageFile", 65 "%SystemRoot%\\System32\\netmsg.dll", 66 AP_REGKEY_EXPAND, p); 67 68 ap_regkey_value_raw_set(regkey, "TypesSupported", &dwData, 69 sizeof(dwData), REG_DWORD, p); 70 ap_regkey_close(regkey); 71 } 72 73 hEventSource = RegisterEventSourceW(NULL, L"Apache Service"); 74 75 SetEvent(stderr_ready); 76 77 while (ReadFile(hPipeRead, errmsg, 1, &errres, NULL) && (errres == 1)) 78 { 79 if ((errmsg > errbuf) || !apr_isspace(*errmsg)) 80 { 81 ++errmsg; 82 if ((*(errmsg - 1) == '\n') 83 || (errmsg >= errbuf + sizeof(errbuf) - 1)) 84 { 85 while ((errmsg > errbuf) && apr_isspace(*(errmsg - 1))) { 86 --errmsg; 87 } 88 *errmsg = '\0'; 89 90 /* Generic message: '%1 %2 %3 %4 %5 %6 %7 %8 %9' 91 * The event code in netmsg.dll is 3299 92 */ 93 ReportEvent(hEventSource, EVENTLOG_ERROR_TYPE, 0, 94 3299, NULL, 9, 0, errarg, NULL); 95 errmsg = errbuf; 96 } 97 } 98 } 99 100 if ((errres = GetLastError()) != ERROR_BROKEN_PIPE) { 101 apr_snprintf(errbuf, sizeof(errbuf), 102 "Win32 error %lu reading stderr pipe stream\r\n", 103 GetLastError()); 104 105 ReportEvent(hEventSource, EVENTLOG_ERROR_TYPE, 0, 106 3299, NULL, 9, 0, errarg, NULL); 107 } 108 109 CloseHandle(hPipeRead); 110 DeregisterEventSource(hEventSource); 111 CloseHandle(stderr_thread); 112 stderr_thread = NULL; 113 apr_pool_destroy(p); 114 return 0; 115} 116 117 118void mpm_nt_eventlog_stderr_flush(void) 119{ 120 HANDLE cleanup_thread = stderr_thread; 121 122 if (cleanup_thread) { 123 HANDLE hErr = GetStdHandle(STD_ERROR_HANDLE); 124 fclose(stderr); 125 CloseHandle(hErr); 126 WaitForSingleObject(cleanup_thread, 30000); 127 CloseHandle(cleanup_thread); 128 } 129} 130 131 132void mpm_nt_eventlog_stderr_open(const char *argv0, apr_pool_t *p) 133{ 134 SECURITY_ATTRIBUTES sa; 135 HANDLE hPipeRead = NULL; 136 HANDLE hPipeWrite = NULL; 137 DWORD threadid; 138 apr_file_t *eventlog_file; 139 apr_file_t *stderr_file; 140 141 display_name = argv0; 142 143 /* Create a pipe to send stderr messages to the system error log. 144 * 145 * _dup2() duplicates the write handle inheritable for us. 146 */ 147 sa.nLength = sizeof(sa); 148 sa.lpSecurityDescriptor = NULL; 149 sa.bInheritHandle = FALSE; 150 CreatePipe(&hPipeRead, &hPipeWrite, NULL, 0); 151 ap_assert(hPipeRead && hPipeWrite); 152 153 stderr_ready = CreateEvent(NULL, FALSE, FALSE, NULL); 154 stderr_thread = CreateThread(NULL, 65536, service_stderr_thread, 155 (LPVOID)hPipeRead, stack_res_flag, &threadid); 156 ap_assert(stderr_ready && stderr_thread); 157 158 WaitForSingleObject(stderr_ready, INFINITE); 159 160 if ((apr_file_open_stderr(&stderr_file, p) 161 == APR_SUCCESS) 162 && (apr_os_file_put(&eventlog_file, &hPipeWrite, APR_WRITE, p) 163 == APR_SUCCESS)) 164 apr_file_dup2(stderr_file, eventlog_file, p); 165 166 /* The code above _will_ corrupt the StdHandle... 167 * and we must do so anyways. We set this up only 168 * after we initialized the posix stderr API. 169 */ 170 ap_open_stderr_log(p); 171} 172