#ifdef WIN32
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <process.h>
#include <direct.h>
#include "httpd.h"
#include "http_conf_globals.h"
#include "http_log.h"
#include "http_main.h"
#include "multithread.h"
#include "service.h"
#include "registry.h"
#include "Win9xConHook.h"
#define SERVICE_APACHE_RESTART 128
static
struct
{
int
(*main_fn)(
int
,
char
**);
int
connected;
SERVICE_STATUS_HANDLE
hServiceStatus;
char
*name;
int
exit_status;
SERVICE_STATUS ssStatus;
FILE
*logFile;
} globdat;
static
BOOL
die_on_logoff = FALSE;
static
HWND
console_wnd = NULL;
static
int
is_service = -1;
static
void
WINAPI service_main_fn(
DWORD
,
LPTSTR
*);
static
void
WINAPI service_ctrl(
DWORD
ctrlCode);
static
int
ReportStatusToSCMgr(
int
currentState,
int
exitCode,
int
waitHint);
static
int
ap_start_service(
SC_HANDLE
,
DWORD
argc,
char
**argv);
static
int
ap_stop_service(
SC_HANDLE
);
static
int
ap_restart_service(
SC_HANDLE
);
int
real_exit_code = 1;
void
hold_console_open_on_error(
void
)
{
HANDLE
hConIn;
HANDLE
hConErr;
DWORD
result;
DWORD
mode;
time_t
start;
time_t
remains;
char
*msg =
"Note the errors or messages above, "
"and press the <ESC> key to exit. "
;
CONSOLE_SCREEN_BUFFER_INFO coninfo;
INPUT_RECORD in;
char
count[16];
#ifdef WIN32
if
(isWindowsNT() && isProcessService() && globdat.connected) {
service_set_status(SERVICE_STOPPED);
ExitThread(0);
}
#endif
if
(!real_exit_code)
return
;
hConIn = GetStdHandle(STD_INPUT_HANDLE);
hConErr = GetStdHandle(STD_ERROR_HANDLE);
if
((hConIn == INVALID_HANDLE_VALUE) || (hConErr == INVALID_HANDLE_VALUE))
return
;
if
(!WriteConsole(hConErr, msg,
strlen
(msg), &result, NULL) || !result)
return
;
if
(!GetConsoleScreenBufferInfo(hConErr, &coninfo))
return
;
if
(isWindowsNT())
mode = ENABLE_MOUSE_INPUT | 0x80;
else
mode = ENABLE_MOUSE_INPUT;
if
(!SetConsoleMode(hConIn, mode))
return
;
start =
time
(NULL);
do
{
while
(PeekConsoleInput(hConIn, &in, 1, &result) && result)
{
if
(!ReadConsoleInput(hConIn, &in, 1, &result) || !result)
return
;
if
((in.EventType == KEY_EVENT) && in.Event.KeyEvent.bKeyDown
&& (in.Event.KeyEvent.uChar.AsciiChar == 27))
return
;
if
(in.EventType == MOUSE_EVENT
&& (in.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK))
return
;
}
remains = ((start + 30) -
time
(NULL));
sprintf
(count,
"%d..."
, remains);
if
(!SetConsoleCursorPosition(hConErr, coninfo.dwCursorPosition))
return
;
if
(!WriteConsole(hConErr, count,
strlen
(count), &result, NULL)
|| !result)
return
;
}
while
((remains > 0) && WaitForSingleObject(hConIn, 1000) != WAIT_FAILED);
}
static
BOOL
CALLBACK ap_control_handler(
DWORD
ctrl_type)
{
switch
(ctrl_type)
{
case
CTRL_C_EVENT:
case
CTRL_BREAK_EVENT:
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, NULL,
"Ctrl+C/Break initiated, shutting down server."
);
real_exit_code = 0;
ap_start_shutdown();
return
TRUE;
case
CTRL_LOGOFF_EVENT:
if
(!die_on_logoff)
return
TRUE;
case
CTRL_CLOSE_EVENT:
case
CTRL_SHUTDOWN_EVENT:
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, NULL,
"Close/Logoff/Shutdown initiated, shutting down server."
);
real_exit_code = 0;
fprintf
(stderr,
"Apache server shutdown initiated...\n"
);
ap_start_shutdown();
Sleep(30000);
return
TRUE;
}
return
FALSE;
}
static
BOOL
CALLBACK EnumttyWindow(
HWND
wnd,
LPARAM
retwnd)
{
char
tmp[20], *tty;
if
(isWindowsNT())
tty =
"ConsoleWindowClass"
;
else
tty =
"tty"
;
if
(GetClassName(wnd, tmp,
sizeof
(tmp)) && !
strcmp
(tmp, tty))
{
DWORD
wndproc, thisproc = GetCurrentProcessId();
GetWindowThreadProcessId(wnd, &wndproc);
if
(wndproc == thisproc) {
*((
HWND
*)retwnd) = wnd;
return
FALSE;
}
}
return
TRUE;
}
void
stop_child_monitor(
void
)
{
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, NULL,
"Unhooking the child process monitor for shutdown."
);
FixConsoleCtrlHandler(ap_control_handler, 0);
}
void
ap_start_child_console(
int
is_child_of_service)
{
int
maxwait = 100;
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, NULL,
"Hooking up the child process monitor to watch for shutdown."
);
is_service = 0;
real_exit_code = 0;
die_on_logoff = !is_child_of_service;
if
(isWindowsNT()) {
if
(!is_child_of_service) {
FreeConsole();
AllocConsole();
EnumWindows(EnumttyWindow, (
long
)(&console_wnd));
if
(console_wnd)
ShowWindow(console_wnd, SW_HIDE);
}
SetProcessShutdownParameters(0x200, 0);
return
;
}
if
(!is_child_of_service) {
FreeConsole();
AllocConsole();
}
while
(!console_wnd && maxwait-- > 0) {
EnumWindows(EnumttyWindow, (
long
)(&console_wnd));
Sleep(100);
}
if
(console_wnd) {
FixConsoleCtrlHandler(ap_control_handler, die_on_logoff ? 1 : 2);
ShowWindow(console_wnd, SW_HIDE);
atexit
(stop_child_monitor);
}
}
void
stop_console_monitor(
void
)
{
SetConsoleCtrlHandler(ap_control_handler, FALSE);
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, NULL,
"Unhooking the console monitor for shutdown."
);
if
(!isWindowsNT())
FixConsoleCtrlHandler(ap_control_handler, 0);
}
void
ap_start_console_monitor(
void
)
{
HANDLE
console_input;
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, NULL,
"Hooking up the console monitor to watch for shutdown."
);
die_on_logoff = TRUE;
is_service = 0;
console_input = GetStdHandle(STD_INPUT_HANDLE);
if
(console_input != INVALID_HANDLE_VALUE)
{
if
(isWindowsNT()) {
SetConsoleCtrlHandler(NULL, FALSE);
SetConsoleMode(console_input, ENABLE_LINE_INPUT
| ENABLE_ECHO_INPUT
| ENABLE_PROCESSED_INPUT
| 0x80);
}
else
{
SetConsoleMode(console_input, ENABLE_LINE_INPUT
| ENABLE_ECHO_INPUT
| ENABLE_PROCESSED_INPUT);
}
}
if
(!isWindowsNT())
FixConsoleCtrlHandler(ap_control_handler, die_on_logoff ? 1 : 2);
SetConsoleCtrlHandler(ap_control_handler, TRUE);
atexit
(stop_console_monitor);
}
void
stop_service_monitor(
void
)
{
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, NULL,
"Unhooking up the service monitor for shutdown."
);
Windows9xServiceCtrlHandler(ap_control_handler, FALSE);
}
int
service95_main(
int
(*main_fn)(
int
,
char
**),
int
argc,
char
**argv,
char
*display_name)
{
char
*service_name;
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, NULL,
"Hooking up the service monitor to watch for shutdown."
);
is_service = 1;
die_on_logoff = FALSE;
ap_server_argv0 = globdat.name = display_name;
service_name = strdup(display_name);
ap_remove_spaces(service_name, display_name);
real_exit_code = 0;
Windows9xServiceCtrlHandler(ap_control_handler, service_name);
atexit
(stop_service_monitor);
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 }
};
ap_server_argv0 = argv[0];
real_exit_code = 0;
is_service = 1;
globdat.main_fn = main_fn;
globdat.connected = 1;
if
(!StartServiceCtrlDispatcher(dispatchTable))
{
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;
if
(!RegCreateKey(HKEY_LOCAL_MACHINE,
"SYSTEM\\CurrentControlSet\\Services"
"\\EventLog\\Application\\Apache Service"
, &hk))
{
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'
;
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,
NO_ERROR,
3000);
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;
}
}
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
));
}
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
));
}
globdat.name = argv[0];
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, NULL,
"Hooked up the Service Error Event Logger."
);
newargv = (
char
**)
malloc
((argc + 3) *
sizeof
(
char
*));
newargv[0] = ap_server_argv0;
newargv[1] =
"-n"
;
memcpy
(newargv + 2, argv, argc *
sizeof
(
char
*));
newargv[argc + 2] = NULL;
argv = newargv;
argc += 2;
ap_server_argv0 = globdat.name;
globdat.exit_status = globdat.main_fn( argc, argv );
}
static
void
set_service_description_string(
const
char
*description)
{
char
szPath[MAX_PATH];
HKEY
hkey;
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
;
}
RegSetValueEx(hkey,
"Description"
, 0, REG_SZ,
(unsigned
char
*) description,
strlen
(description) + 1);
RegCloseKey(hkey);
}
char
*get_service_name(
char
*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)
{
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;
}
typedef
WINADVAPI
BOOL
(WINAPI *CSD_T)(
SC_HANDLE
,
DWORD
,
LPCVOID
);
void
service_set_status(
int
status)
{
const
char
*full_description;
SC_HANDLE
schSCManager;
CSD_T ChangeServiceDescription;
HANDLE
hwin2000scm;
BOOL
ret = 0;
if
(!is_service)
return
;
ReportStatusToSCMgr(status, NO_ERROR, 3000);
if
(status != SERVICE_RUNNING)
return
;
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"
);
if
(!ChangeServiceDescription) {
set_service_description_string(full_description);
return
;
}
schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if
(schSCManager) {
SC_HANDLE
schService = OpenService(schSCManager, globdat.name,
SERVICE_ALL_ACCESS);
if
(schService) {
ret = ChangeServiceDescription(schService,
1
,
&full_description);
CloseServiceHandle(schService);
}
CloseServiceHandle(schSCManager);
}
if
(!ret)
set_service_description_string(full_description);
}
VOID
WINAPI service_ctrl(
DWORD
dwCtrlCode)
{
switch
(dwCtrlCode)
{
case
SERVICE_CONTROL_SHUTDOWN:
case
SERVICE_CONTROL_STOP:
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, NULL,
"Service Stop/Shutdown signaled, shutting down server."
);
ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 15000);
ap_start_shutdown();
break
;
case
SERVICE_APACHE_RESTART:
ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, NULL,
"Service Restart signaled, shutting down server."
);
ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 15000);
ap_start_restart(1);
break
;
case
SERVICE_CONTROL_INTERROGATE:
ReportStatusToSCMgr(globdat.ssStatus.dwCurrentState, NO_ERROR, 0);
break
;
default
:
break
;
}
}
int
ReportStatusToSCMgr(
int
currentState,
int
exitCode,
int
waitHint)
{
static
int
firstTime = 1;
static
int
checkPoint = 1;
int
rv;
if
(firstTime)
{
firstTime = 0;
globdat.ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
globdat.ssStatus.dwServiceSpecificExitCode = 0;
globdat.ssStatus.dwCheckPoint = 1;
}
if
(globdat.connected)
{
if
((currentState == SERVICE_START_PENDING)
|| (currentState == SERVICE_STOP_PENDING))
globdat.ssStatus.dwControlsAccepted = 0;
else
globdat.ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP
| SERVICE_ACCEPT_SHUTDOWN;
globdat.ssStatus.dwCurrentState = currentState;
globdat.ssStatus.dwWin32ExitCode = exitCode;
if
( ( currentState == SERVICE_RUNNING ) ||
( currentState == SERVICE_STOPPED ) )
{
globdat.ssStatus.dwWaitHint = 0;
globdat.ssStatus.dwCheckPoint = 0;
}
else
{
if
(waitHint)
globdat.ssStatus.dwWaitHint = waitHint;
globdat.ssStatus.dwCheckPoint = ++checkPoint;
}
rv = SetServiceStatus(globdat.hServiceStatus, &globdat.ssStatus);
}
return
(1);
}
void
InstallService(pool *p,
char
*display_name,
int
argc,
char
**argv,
int
reconfig)
{
TCHAR
szPath[MAX_PATH];
TCHAR
szQuotedPath[512];
char
*service_name;
int
regargc = 0;
char
default_depends[] =
"Tcpip\0Afd\0"
;
char
*depends = default_depends;
size_t
depends_len =
sizeof
(default_depends);
char
**regargv =
malloc
((argc + 4) *
sizeof
(
char
*));
char
**newelem = regargv;
regargc += 4;
*(newelem++) =
"-d"
;
*(newelem++) = ap_server_root;
*(newelem++) =
"-f"
;
*(newelem++) = ap_server_confname;
while
(++argv, --argc) {
if
((**argv ==
'-'
) &&
strchr
(
"kndf"
, argv[0][1]))
--argc, ++argv;
else
if
((**argv ==
'-'
) && (argv[0][1] ==
'W'
))
{
char
*service = get_service_name(*(argv + 1));
size_t
add_len =
strlen
(service) + 1;
char
*more_depends =
malloc
(depends_len + add_len);
memcpy
(more_depends, depends, depends_len - 1);
memcpy
(more_depends + depends_len - 1, service, add_len);
depends_len += add_len;
depends = more_depends;
depends[depends_len - 1] =
'\0'
;
++argv, --argc;
}
else
if
((**argv !=
'-'
) || !
strchr
(
"iuw"
, argv[0][1]))
*(newelem++) = *argv, ++regargc;
}
service_name = get_service_name(display_name);
printf
(reconfig ?
"Reconfiguring the %s service\n"
:
"Installing the %s service\n"
,
display_name);
if
(GetModuleFileName( NULL, szPath, 512 ) == 0)
{
ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
"GetModuleFileName failed"
);
return
;
}
if
(isWindowsNT())
{
SC_HANDLE
schService;
SC_HANDLE
schSCManager;
ap_snprintf(szQuotedPath,
sizeof
(szQuotedPath),
"\"%s\" --ntservice"
, szPath);
schSCManager = OpenSCManager(
NULL,
NULL,
SC_MANAGER_ALL_ACCESS
);
if
(!schSCManager) {
ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
"OpenSCManager failed"
);
return
;
}
if
(reconfig)
{
schService = OpenService(schSCManager, service_name,
SERVICE_ALL_ACCESS);
if
(!schService)
ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
"OpenService failed"
);
else
if
(!ChangeServiceConfig(
schService,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START,
SERVICE_ERROR_NORMAL,
szQuotedPath,
NULL,
NULL,
depends,
NULL,
NULL,
display_name)) {
ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
"ChangeServiceConfig failed"
);
CloseServiceHandle(schService);
schService = NULL;
}
}
else
{
schService = CreateService(
schSCManager,
service_name,
display_name,
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START,
SERVICE_ERROR_NORMAL,
szQuotedPath,
NULL,
NULL,
depends,
NULL,
NULL);
if
(!schService)
ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
"CreateService failed"
);
}
if
(schService)
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
if
(!schService)
return
;
}
else
{
HKEY
hkey;
DWORD
rv;
ap_snprintf(szQuotedPath,
sizeof
(szQuotedPath),
"\"%s\" -k start -n %s"
,
szPath, service_name);
rv = RegCreateKey(HKEY_LOCAL_MACHINE,
"Software\\Microsoft\\Windows"
"\\CurrentVersion\\RunServices"
, &hkey);
if
(rv != ERROR_SUCCESS) {
SetLastError(rv);
ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
"Could not create/open the RunServices registry key"
);
return
;
}
rv = RegSetValueEx(hkey, service_name, 0, REG_SZ,
(unsigned
char
*)szQuotedPath,
strlen
(szQuotedPath) + 1);
if
(rv != ERROR_SUCCESS) {
SetLastError(rv);
ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
"Unable to install service: "
"Could not add to RunServices Registry Key"
);
RegCloseKey(hkey);
return
;
}
RegCloseKey(hkey);
ap_snprintf(szPath,
sizeof
(szPath),
"SYSTEM\\CurrentControlSet\\Services\\%s"
, service_name);
rv = RegCreateKey(HKEY_LOCAL_MACHINE, szPath, &hkey);
if
(rv != ERROR_SUCCESS) {
SetLastError(rv);
ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
"Could not create/open the %s registry key"
, szPath);
return
;
}
rv = RegSetValueEx(hkey,
"ImagePath"
, 0, REG_SZ,
(unsigned
char
*)szQuotedPath,
strlen
(szQuotedPath) + 1);
if
(rv != ERROR_SUCCESS) {
SetLastError(rv);
ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
"Unable to install service: "
"Could not add ImagePath to %s Registry Key"
,
service_name);
RegCloseKey(hkey);
return
;
}
rv = RegSetValueEx(hkey,
"DisplayName"
, 0, REG_SZ,
(unsigned
char
*)display_name,
strlen
(display_name) + 1);
if
(rv != ERROR_SUCCESS) {
SetLastError(rv);
ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
"Unable to install service: "
"Could not add DisplayName to %s Registry Key"
,
service_name);
RegCloseKey(hkey);
return
;
}
RegCloseKey(hkey);
}
if
(ap_registry_set_service_args(p, regargc, regargv, service_name)) {
return
;
}
printf
(
"The %s service has been %s successfully.\n"
,
display_name, reconfig ?
"reconfigured"
:
"installed"
);
}
void
RemoveService(
char
*display_name)
{
char
*service_name;
BOOL
success = FALSE;
printf
(
"Removing the %s service\n"
, display_name);
service_name = get_service_name(display_name);
if
(isWindowsNT())
{
SC_HANDLE
schService;
SC_HANDLE
schSCManager;
schSCManager = OpenSCManager(
NULL,
NULL,
SC_MANAGER_ALL_ACCESS
);
if
(!schSCManager) {
ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
"OpenSCManager failed"
);
return
;
}
schService = OpenService(schSCManager, service_name, SERVICE_ALL_ACCESS);
if
(schService == NULL) {
ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
"OpenService failed"
);
}
else
{
ap_stop_service(schService);
if
(DeleteService(schService) == 0)
ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
"DeleteService failed"
);
else
success = TRUE;
CloseServiceHandle(schService);
}
CloseServiceHandle(schSCManager);
}
else
{
HKEY
hkey;
DWORD
service_pid;
DWORD
rv;
HWND
hwnd;
hwnd = FindWindow(
"ApacheWin95ServiceMonitor"
, service_name);
if
(hwnd && GetWindowThreadProcessId(hwnd, &service_pid))
{
int
ticks = 120;
char
prefix[20];
ap_snprintf(prefix,
sizeof
(prefix),
"ap%ld"
, (
long
)service_pid);
setup_signal_names(prefix);
ap_start_shutdown();
while
(--ticks) {
if
(!IsWindow(hwnd))
break
;
Sleep(1000);
}
}
rv = RegOpenKey(HKEY_LOCAL_MACHINE,
"Software\\Microsoft\\Windows\\CurrentVersion\\RunServices"
,
&hkey);
if
(rv != ERROR_SUCCESS) {
SetLastError(rv);
ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
"Could not open the RunServices registry key."
);
}
else
{
rv = RegDeleteValue(hkey, service_name);
if
(rv != ERROR_SUCCESS) {
SetLastError(rv);
ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
"Unable to remove service: "
"Could not delete the RunServices entry."
);
}
else
success = TRUE;
}
RegCloseKey(hkey);
rv = RegOpenKey(HKEY_LOCAL_MACHINE,
"SYSTEM\\CurrentControlSet\\Services"
, &hkey);
if
(rv != ERROR_SUCCESS) {
rv = RegDeleteValue(hkey, service_name);
ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
"Could not open the Services registry key."
);
success = FALSE;
}
else
{
rv = RegDeleteKey(hkey, service_name);
if
(rv != ERROR_SUCCESS) {
SetLastError(rv);
ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
"Unable to remove service: "
"Could not delete the Services registry key."
);
success = FALSE;
}
}
RegCloseKey(hkey);
}
if
(success)
printf
(
"The %s service has been removed successfully.\n"
,
display_name);
}
BOOL
isWindowsNT(
void
)
{
static
BOOL
once = FALSE;
static
BOOL
isNT = FALSE;
if
(!once)
{
OSVERSIONINFO osver;
osver.dwOSVersionInfoSize =
sizeof
(osver);
if
(GetVersionEx(&osver))
if
(osver.dwPlatformId == VER_PLATFORM_WIN32_NT)
isNT = TRUE;
once = TRUE;
}
return
isNT;
}
BOOL
isProcessService()
{
if
(is_service != -1)
return
is_service;
if
(!isWindowsNT() || !AllocConsole()) {
return
FALSE;
}
FreeConsole();
is_service = 1;
return
TRUE;
}
BOOL
isValidService(
char
*display_name) {
char
service_key[MAX_PATH];
char
*service_name;
HKEY
hkey;
strcpy
(service_key,
"System\\CurrentControlSet\\Services\\"
);
service_name = get_service_name(display_name);
strcat
(service_key, service_name);
if
(RegOpenKey(HKEY_LOCAL_MACHINE, service_key, &hkey) != ERROR_SUCCESS) {
return
FALSE;
}
RegCloseKey(hkey);
return
TRUE;
}
int
send_signal_to_service(
char
*display_name,
char
*sig,
int
argc,
char
**argv)
{
DWORD
service_pid;
HANDLE
hwnd;
SC_HANDLE
schService;
SC_HANDLE
schSCManager;
char
*service_name;
int
success = FALSE;
enum
{ start, restart, stop, unknown } action;
static
char
*param[] = {
"start"
,
"restart"
,
"shutdown"
};
static
char
*participle[] = {
"starting"
,
"restarting"
,
"stopping"
};
static
char
*past[] = {
"started"
,
"restarted"
,
"stopped"
};
for
(action = start; action < unknown; action++)
if
(!strcasecmp(sig, param[action]))
break
;
if
(action == unknown) {
printf
(
"signal must be start, restart, or shutdown\n"
);
return
FALSE;
}
service_name = get_service_name(display_name);
if
(isWindowsNT())
{
schSCManager = OpenSCManager(
NULL,
NULL,
SC_MANAGER_ALL_ACCESS
);
if
(!schSCManager) {
ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
"OpenSCManager failed"
);
return
FALSE;
}
schService = OpenService(schSCManager, service_name, SERVICE_ALL_ACCESS);
if
(schService == NULL) {
ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
"OpenService failed"
);
CloseServiceHandle(schSCManager);
return
FALSE;
}
if
(!QueryServiceStatus(schService, &globdat.ssStatus)) {
ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_WIN32ERROR, NULL,
"QueryService failed"
);
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
}
}
else
{
hwnd = FindWindow(
"ApacheWin95ServiceMonitor"
, service_name);
if
(hwnd && GetWindowThreadProcessId(hwnd, &service_pid))
globdat.ssStatus.dwCurrentState = SERVICE_RUNNING;
else
globdat.ssStatus.dwCurrentState = SERVICE_STOPPED;
}
if
(globdat.ssStatus.dwCurrentState == SERVICE_STOPPED
&& action == stop) {
printf
(
"The %s service is not started.\n"
, display_name);
return
FALSE;
}
else
if
(globdat.ssStatus.dwCurrentState == SERVICE_RUNNING
&& action == start) {
printf
(
"The %s service has already been started.\n"
, display_name);
strcpy
(sig,
""
);
return
FALSE;
}
else
{
printf
(
"The %s service is %s.\n"
, display_name, participle[action]);
if
(isWindowsNT())
{
if
(action == stop)
success = ap_stop_service(schService);
else
if
((action == start)
|| ((action == restart)
&& (globdat.ssStatus.dwCurrentState
== SERVICE_STOPPED)))
{
char
**args =
malloc
(argc *
sizeof
(
char
*));
int
i, j;
for
(i = 1, j = 0; i < argc; i++) {
if
((argv[i][0] ==
'-'
) && ((argv[i][1] ==
'k'
)
|| (argv[i][1] ==
'n'
)))
++i;
else
args[j++] = argv[i];
}
success = ap_start_service(schService, j, args);
}
else
if
(action == restart)
success = ap_restart_service(schService);
}
else
{
char
prefix[20];
ap_snprintf(prefix,
sizeof
(prefix),
"ap%ld"
, (
long
)service_pid);
setup_signal_names(prefix);
if
(action == stop) {
int
ticks = 60;
ap_start_shutdown();
while
(--ticks)
{
if
(!IsWindow(hwnd)) {
success = TRUE;
break
;
}
Sleep(1000);
}
}
else
if
(action == restart)
{
if
(globdat.ssStatus.dwCurrentState == SERVICE_STOPPED)
{
printf
(
"The %s service has %s.\n"
, display_name,
past[action]);
strcpy
(sig,
"start"
);
return
FALSE;
}
ap_start_restart(1);
success = TRUE;
}
else
{
printf
(
"The %s service is %s.\n"
, display_name,
past[action]);
return
FALSE;
}
}
if
( success )
printf
(
"The %s service has %s.\n"
, display_name, past[action]);
else
printf
(
"Failed to %s the %s service.\n"
, sig, display_name);
}
if
(isWindowsNT()) {
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
}
return
success;
}
int
ap_stop_service(
SC_HANDLE
schService)
{
if
(ControlService(schService, SERVICE_CONTROL_STOP, &globdat.ssStatus)) {
Sleep(1000);
while
(QueryServiceStatus(schService, &globdat.ssStatus)) {
if
(globdat.ssStatus.dwCurrentState == SERVICE_STOP_PENDING)
Sleep(1000);
else
break
;
}
}
if
(QueryServiceStatus(schService, &globdat.ssStatus))
if
(globdat.ssStatus.dwCurrentState == SERVICE_STOPPED)
return
TRUE;
return
FALSE;
}
int
ap_start_service(
SC_HANDLE
schService,
DWORD
argc,
char
**argv) {
if
(StartService(schService, argc, argv)) {
Sleep(1000);
while
(QueryServiceStatus(schService, &globdat.ssStatus)) {
if
(globdat.ssStatus.dwCurrentState == SERVICE_START_PENDING)
Sleep(1000);
else
break
;
}
}
if
(QueryServiceStatus(schService, &globdat.ssStatus))
if
(globdat.ssStatus.dwCurrentState == SERVICE_RUNNING)
return
TRUE;
return
FALSE;
}
int
ap_restart_service(
SC_HANDLE
schService)
{
int
ticks;
if
(ControlService(schService, SERVICE_APACHE_RESTART, &globdat.ssStatus))
{
ticks = 60;
while
(globdat.ssStatus.dwCurrentState == SERVICE_START_PENDING)
{
Sleep(1000);
if
(!QueryServiceStatus(schService, &globdat.ssStatus))
return
FALSE;
if
(!--ticks)
break
;
}
}
if
(globdat.ssStatus.dwCurrentState == SERVICE_RUNNING)
return
TRUE;
return
FALSE;
}
#endif /* WIN32 */