nt_eventlog.c revision fb7819ee2f9c29baa75b4803880188b6250d43e5
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000-2002 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* Portions of this software are based upon public domain software
* originally written at the National Center for Supercomputing Applications,
* University of Illinois, Urbana-Champaign.
*/
#define CORE_PRIVATE
#include "httpd.h"
#include "http_log.h"
#include "mpm_winnt.h"
#include "apr_strings.h"
#include "apr_lib.h"
static char *display_name = NULL;
static HANDLE stderr_thread = NULL;
static HANDLE stderr_ready;
static DWORD WINAPI service_stderr_thread(LPVOID hPipe)
{
HANDLE hPipeRead = (HANDLE) hPipe;
HANDLE hEventSource;
char errbuf[256];
char *errmsg = errbuf;
const char *errarg[9];
DWORD errres;
HKEY hk;
errarg[0] = "The Apache service named";
errarg[1] = display_name;
errarg[2] = "reported the following error:\r\n>>>";
errarg[3] = errbuf;
errarg[4] = NULL;
errarg[5] = NULL;
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");
SetEvent(stderr_ready);
while (ReadFile(hPipeRead, errmsg, 1, &errres, NULL) && (errres == 1))
{
if ((errmsg > errbuf) || !isspace(*errmsg))
{
++errmsg;
if ((*(errmsg - 1) == '\n')
|| (errmsg >= errbuf + sizeof(errbuf) - 1))
{
while ((errmsg > errbuf) && isspace(*(errmsg - 1))) {
--errmsg;
}
*errmsg = '\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;
}
}
}
if ((errres = GetLastError()) != ERROR_BROKEN_PIPE) {
apr_snprintf(errbuf, sizeof(errbuf),
"Win32 error %d reading stderr pipe stream\r\n",
GetLastError());
ReportEvent(hEventSource, EVENTLOG_ERROR_TYPE, 0,
3299, NULL, 9, 0, errarg, NULL);
}
CloseHandle(hPipeRead);
DeregisterEventSource(hEventSource);
CloseHandle(stderr_thread);
stderr_thread = NULL;
return 0;
}
void mpm_nt_eventlog_stderr_flush(void)
{
HANDLE cleanup_thread = stderr_thread;
if (cleanup_thread) {
HANDLE hErr = GetStdHandle(STD_ERROR_HANDLE);
fclose(stderr);
CloseHandle(hErr);
WaitForSingleObject(cleanup_thread, 30000);
CloseHandle(cleanup_thread);
}
}
void mpm_nt_eventlog_stderr_open(char *argv0, apr_pool_t *p)
{
SECURITY_ATTRIBUTES sa;
HANDLE hProc = GetCurrentProcess();
HANDLE hPipeRead = NULL;
HANDLE hPipeWrite = NULL;
HANDLE hDup = NULL;
DWORD threadid;
int fd;
display_name = argv0;
/* Create a pipe to send stderr messages to the system error log.
*
* _dup2() duplicates the write handle inheritable for us.
*/
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = FALSE;
CreatePipe(&hPipeRead, &hPipeWrite, NULL, 0);
ap_assert(hPipeRead && hPipeWrite);
stderr_ready = CreateEvent(NULL, FALSE, FALSE, NULL);
stderr_thread = CreateThread(NULL, 0, service_stderr_thread,
(LPVOID) hPipeRead, 0, &threadid);
ap_assert(stderr_ready && stderr_thread);
WaitForSingleObject(stderr_ready, INFINITE);
/* Flush stderr and unset its buffer, then commit and replace stderr.
* This is typically a noop for Win2K/XP since services with NULL std
* handles [but valid FILE *'s, oddly enough], but is required
* for NT 4.0 and to use this code outside of services.
*/
fflush(stderr);
setvbuf(stderr, NULL, _IONBF, 0);
_commit(2 /* stderr */);
fd = _open_osfhandle((long) hPipeWrite,
_O_WRONLY | _O_BINARY);
_dup2(fd, 2);
_close(fd);
_setmode(2, _O_BINARY);
/* hPipeWrite was _close()'ed above, and _dup2()'ed
* to fd 2 creating a new, inherited Win32 handle.
* Recover that real handle from fd 2.
*/
hPipeWrite = (HANDLE)_get_osfhandle(2);
SetStdHandle(STD_ERROR_HANDLE, hPipeWrite);
/* The code above _will_ corrupt the StdHandle...
* and we must do so anyways. We set this up only
* after we initialized the posix stderr API.
*/
ap_open_stderr_log(p);
}