]> granicus.if.org Git - apache/blob - server/mpm/winnt/nt_eventlog.c
finished that boring job:
[apache] / server / mpm / winnt / nt_eventlog.c
1 /* ====================================================================
2  * The Apache Software License, Version 1.1
3  *
4  * Copyright (c) 2000-2003 The Apache Software Foundation.  All rights
5  * reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in
16  *    the documentation and/or other materials provided with the
17  *    distribution.
18  *
19  * 3. The end-user documentation included with the redistribution,
20  *    if any, must include the following acknowledgment:
21  *       "This product includes software developed by the
22  *        Apache Software Foundation (http://www.apache.org/)."
23  *    Alternately, this acknowledgment may appear in the software itself,
24  *    if and wherever such third-party acknowledgments normally appear.
25  *
26  * 4. The names "Apache" and "Apache Software Foundation" must
27  *    not be used to endorse or promote products derived from this
28  *    software without prior written permission. For written
29  *    permission, please contact apache@apache.org.
30  *
31  * 5. Products derived from this software may not be called "Apache",
32  *    nor may "Apache" appear in their name, without prior written
33  *    permission of the Apache Software Foundation.
34  *
35  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46  * SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Apache Software Foundation.  For more
51  * information on the Apache Software Foundation, please see
52  * <http://www.apache.org/>.
53  *
54  * Portions of this software are based upon public domain software
55  * originally written at the National Center for Supercomputing Applications,
56  * University of Illinois, Urbana-Champaign.
57  */
58
59 #define CORE_PRIVATE 
60
61 #include "httpd.h"
62 #include "http_log.h"
63 #include "mpm_winnt.h"
64 #include "apr_strings.h"
65 #include "apr_lib.h"
66 #include "ap_regkey.h"
67
68 static char  *display_name  = NULL;
69 static HANDLE stderr_thread = NULL;
70 static HANDLE stderr_ready;
71
72 static DWORD WINAPI service_stderr_thread(LPVOID hPipe)
73 {
74     HANDLE hPipeRead = (HANDLE) hPipe;
75     HANDLE hEventSource;
76     char errbuf[256];
77     char *errmsg = errbuf;
78     const char *errarg[9];
79     DWORD errres;
80     ap_regkey_t *regkey;
81     apr_status_t rv;
82     apr_pool_t *p;
83     
84     apr_pool_sub_make(&p, NULL, NULL);
85
86     errarg[0] = "The Apache service named";
87     errarg[1] = display_name;
88     errarg[2] = "reported the following error:\r\n>>>";
89     errarg[3] = errbuf;
90     errarg[4] = NULL;
91     errarg[5] = NULL;
92     errarg[6] = NULL;
93     errarg[7] = NULL;
94     errarg[8] = NULL;
95
96     /* What are we going to do in here, bail on the user?  not. */
97     if ((rv = ap_regkey_open(&regkey, AP_REGKEY_LOCAL_MACHINE, 
98                              "SYSTEM\\CurrentControlSet\\Services\\"
99                              "EventLog\\Application\\Apache Service",
100                              APR_READ | APR_WRITE | APR_CREATE, p)) 
101             == APR_SUCCESS)
102     {
103         DWORD dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | 
104                        EVENTLOG_INFORMATION_TYPE; 
105  
106         /* The stock message file */
107         ap_regkey_value_set(regkey, "EventMessageFile", 
108                             "%SystemRoot%\\System32\\netmsg.dll", 
109                             AP_REGKEY_EXPAND, p);
110         
111         ap_regkey_value_raw_set(regkey, "TypesSupported", &dwData, 
112                                 sizeof(dwData), REG_DWORD, p);
113         ap_regkey_close(regkey);
114     }
115
116     hEventSource = RegisterEventSourceW(NULL, L"Apache Service");
117
118     SetEvent(stderr_ready);
119
120     while (ReadFile(hPipeRead, errmsg, 1, &errres, NULL) && (errres == 1))
121     {
122         if ((errmsg > errbuf) || !apr_isspace(*errmsg))
123         {
124             ++errmsg;
125             if ((*(errmsg - 1) == '\n') 
126                     || (errmsg >= errbuf + sizeof(errbuf) - 1))
127             {
128                 while ((errmsg > errbuf) && apr_isspace(*(errmsg - 1))) {
129                     --errmsg;
130                 }
131                 *errmsg = '\0';
132
133                 /* Generic message: '%1 %2 %3 %4 %5 %6 %7 %8 %9'
134                  * The event code in netmsg.dll is 3299
135                  */
136                 ReportEvent(hEventSource, EVENTLOG_ERROR_TYPE, 0, 
137                             3299, NULL, 9, 0, errarg, NULL);
138                 errmsg = errbuf;
139             }
140         }
141     }
142
143     if ((errres = GetLastError()) != ERROR_BROKEN_PIPE) {
144         apr_snprintf(errbuf, sizeof(errbuf),
145                      "Win32 error %d reading stderr pipe stream\r\n", 
146                      GetLastError());
147
148         ReportEvent(hEventSource, EVENTLOG_ERROR_TYPE, 0, 
149                     3299, NULL, 9, 0, errarg, NULL);
150     }
151
152     CloseHandle(hPipeRead);
153     DeregisterEventSource(hEventSource);
154     CloseHandle(stderr_thread);
155     stderr_thread = NULL;
156     apr_pool_destroy(p);
157     return 0;
158 }
159
160
161 void mpm_nt_eventlog_stderr_flush(void)
162 {
163     HANDLE cleanup_thread = stderr_thread;
164
165     if (cleanup_thread) {
166         HANDLE hErr = GetStdHandle(STD_ERROR_HANDLE);
167         fclose(stderr);
168         CloseHandle(hErr);
169         WaitForSingleObject(cleanup_thread, 30000);
170         CloseHandle(cleanup_thread);
171     }
172 }
173
174
175 void mpm_nt_eventlog_stderr_open(char *argv0, apr_pool_t *p)
176 {
177     SECURITY_ATTRIBUTES sa;
178     HANDLE hProc = GetCurrentProcess();
179     HANDLE hPipeRead = NULL;
180     HANDLE hPipeWrite = NULL;
181     HANDLE hDup = NULL;
182     DWORD  threadid;
183     int    fd;
184
185     display_name = argv0;
186
187     /* Create a pipe to send stderr messages to the system error log.
188      *
189      * _dup2() duplicates the write handle inheritable for us.
190      */
191     sa.nLength = sizeof(sa);
192     sa.lpSecurityDescriptor = NULL;
193     sa.bInheritHandle = FALSE;
194     CreatePipe(&hPipeRead, &hPipeWrite, NULL, 0); 
195     ap_assert(hPipeRead && hPipeWrite);
196
197     stderr_ready = CreateEvent(NULL, FALSE, FALSE, NULL);
198     stderr_thread = CreateThread(NULL, 0, service_stderr_thread,
199                                  (LPVOID) hPipeRead, 0, &threadid);
200     ap_assert(stderr_ready && stderr_thread);
201
202     WaitForSingleObject(stderr_ready, INFINITE);
203
204     /* Flush stderr and unset its buffer, then commit and replace stderr.
205      * This is typically a noop for Win2K/XP since services with NULL std 
206      * handles [but valid FILE *'s, oddly enough], but is required 
207      * for NT 4.0 and to use this code outside of services.
208      */
209     fflush(stderr);
210     setvbuf(stderr, NULL, _IONBF, 0);
211     _commit(2 /* stderr */);
212     fd = _open_osfhandle((long) hPipeWrite, 
213                          _O_WRONLY | _O_BINARY);
214     _dup2(fd, 2);
215     _close(fd);
216     _setmode(2, _O_BINARY);
217
218     /* hPipeWrite was _close()'ed above, and _dup2()'ed
219      * to fd 2 creating a new, inherited Win32 handle.
220      * Recover that real handle from fd 2.
221      */
222     hPipeWrite = (HANDLE)_get_osfhandle(2);
223
224     SetStdHandle(STD_ERROR_HANDLE, hPipeWrite);
225
226     /* The code above _will_ corrupt the StdHandle... 
227      * and we must do so anyways.  We set this up only
228      * after we initialized the posix stderr API.
229      */
230     ap_open_stderr_log(p);
231 }