--- embedaddon/smartmontools/os_win32/daemon_win32.cpp 2012/02/21 16:32:16 1.1.1.1 +++ embedaddon/smartmontools/os_win32/daemon_win32.cpp 2013/07/22 01:17:36 1.1.1.2 @@ -3,7 +3,7 @@ * * Home page of code is: http://smartmontools.sourceforge.net * - * Copyright (C) 2004-11 Christian Franke + * Copyright (C) 2004-13 Christian Franke * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -11,15 +11,18 @@ * any later version. * * You should have received a copy of the GNU General Public License - * (for example COPYING); if not, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * (for example COPYING); If not, see . * */ -// Need MB_SERVICE_NOTIFICATION (NT4/2000/XP), IsDebuggerPresent() (Win98/ME/NT4/2000/XP) -#define WINVER 0x0400 +#define WINVER 0x0600 #define _WIN32_WINNT WINVER +#include "daemon_win32.h" + +const char * daemon_win32_cpp_cvsid = "$Id: daemon_win32.cpp,v 1.1.1.2 2013/07/22 01:17:36 misho Exp $" + DAEMON_WIN32_H_CVSID; + #include #include #include @@ -31,16 +34,14 @@ #include #endif -#include "daemon_win32.h" +#ifndef SERVICE_CONFIG_DELAYED_AUTO_START_INFO +// Missing in older MinGW headers +#define SERVICE_CONFIG_DELAYED_AUTO_START_INFO 3 +#endif -const char * daemon_win32_cpp_cvsid = "$Id: daemon_win32.cpp,v 1.1.1.1 2012/02/21 16:32:16 misho Exp $" - DAEMON_WIN32_H_CVSID; - ///////////////////////////////////////////////////////////////////////////// -#define ARGUSED(x) ((void)(x)) - // Prevent spawning of child process if debugging #ifdef _DEBUG #define debugging() IsDebuggerPresent() @@ -58,94 +59,94 @@ const char * daemon_win32_cpp_cvsid = "$Id: daemon_win static void make_name(char * name, int sig) { - int i; - if (!GetModuleFileNameA(NULL, name, EVT_NAME_LEN-10)) - strcpy(name, "DaemonEvent"); - for (i = 0; name[i]; i++) { - char c = name[i]; - if (!( ('0' <= c && c <= '9') - || ('A' <= c && c <= 'Z') - || ('a' <= c && c <= 'z'))) - name[i] = '_'; - } - sprintf(name+strlen(name), "-%d", sig); + int i; + if (!GetModuleFileNameA(NULL, name, EVT_NAME_LEN-10)) + strcpy(name, "DaemonEvent"); + for (i = 0; name[i]; i++) { + char c = name[i]; + if (!( ('0' <= c && c <= '9') + || ('A' <= c && c <= 'Z') + || ('a' <= c && c <= 'z'))) + name[i] = '_'; + } + sprintf(name+strlen(name), "-%d", sig); } static HANDLE create_event(int sig, BOOL initial, BOOL errmsg, BOOL * exists) { - char name[EVT_NAME_LEN]; - HANDLE h; - if (sig >= 0) - make_name(name, sig); - else - name[0] = 0; - if (exists) - *exists = FALSE; - if (!(h = CreateEventA(NULL, FALSE, initial, (name[0] ? name : NULL)))) { - if (errmsg) - fprintf(stderr, "CreateEvent(.,\"%s\"): Error=%ld\n", name, GetLastError()); - return 0; - } + char name[EVT_NAME_LEN]; + HANDLE h; + if (sig >= 0) + make_name(name, sig); + else + name[0] = 0; + if (exists) + *exists = FALSE; + if (!(h = CreateEventA(NULL, FALSE, initial, (name[0] ? name : NULL)))) { + if (errmsg) + fprintf(stderr, "CreateEvent(.,\"%s\"): Error=%ld\n", name, GetLastError()); + return 0; + } - if (GetLastError() == ERROR_ALREADY_EXISTS) { - if (!exists) { - if (errmsg) - fprintf(stderr, "CreateEvent(.,\"%s\"): Exists\n", name); - CloseHandle(h); - return 0; - } - *exists = TRUE; - } - return h; + if (GetLastError() == ERROR_ALREADY_EXISTS) { + if (!exists) { + if (errmsg) + fprintf(stderr, "CreateEvent(.,\"%s\"): Exists\n", name); + CloseHandle(h); + return 0; + } + *exists = TRUE; + } + return h; } static HANDLE open_event(int sig) { - char name[EVT_NAME_LEN]; - make_name(name, sig); - return OpenEventA(EVENT_MODIFY_STATE, FALSE, name); + char name[EVT_NAME_LEN]; + make_name(name, sig); + return OpenEventA(EVENT_MODIFY_STATE, FALSE, name); } static int event_exists(int sig) { - char name[EVT_NAME_LEN]; - HANDLE h; - make_name(name, sig); - if (!(h = OpenEventA(EVENT_MODIFY_STATE, FALSE, name))) - return 0; - CloseHandle(h); - return 1; + char name[EVT_NAME_LEN]; + HANDLE h; + make_name(name, sig); + if (!(h = OpenEventA(EVENT_MODIFY_STATE, FALSE, name))) + return 0; + CloseHandle(h); + return 1; } static int sig_event(int sig) { - char name[EVT_NAME_LEN]; - HANDLE h; - make_name(name, sig); - if (!(h = OpenEventA(EVENT_MODIFY_STATE, FALSE, name))) { - make_name(name, EVT_RUNNING); - if (!(h = OpenEvent(EVENT_MODIFY_STATE, FALSE, name))) - return -1; - CloseHandle(h); - return 0; - } - SetEvent(h); - CloseHandle(h); - return 1; + char name[EVT_NAME_LEN]; + HANDLE h; + make_name(name, sig); + if (!(h = OpenEventA(EVENT_MODIFY_STATE, FALSE, name))) { + make_name(name, EVT_RUNNING); + if (!(h = OpenEvent(EVENT_MODIFY_STATE, FALSE, name))) + return -1; + CloseHandle(h); + return 0; + } + SetEvent(h); + CloseHandle(h); + return 1; } static void daemon_help(FILE * f, const char * ident, const char * message) { - fprintf(f, - "%s: %s.\n" - "Use \"%s status|stop|reload|restart|sigusr1|sigusr2\" to control daemon.\n", - ident, message, ident); - fflush(f); + fprintf(f, + "%s: %s.\n" + "Use \"%s status|stop|reload|restart|sigusr1|sigusr2\" to control daemon.\n", + ident, message, ident); + fflush(f); } @@ -155,64 +156,64 @@ static void daemon_help(FILE * f, const char * ident, static BOOL WINAPI parent_console_handler(DWORD event) { - switch (event) { - case CTRL_C_EVENT: - case CTRL_BREAK_EVENT: - return TRUE; // Ignore - } - return FALSE; // continue with next handler ... + switch (event) { + case CTRL_C_EVENT: + case CTRL_BREAK_EVENT: + return TRUE; // Ignore + } + return FALSE; // continue with next handler ... } static int parent_main(HANDLE rev) { - HANDLE dev; - HANDLE ht[2]; - char * cmdline; - STARTUPINFO si; - PROCESS_INFORMATION pi; - DWORD rc, exitcode; + HANDLE dev; + HANDLE ht[2]; + char * cmdline; + STARTUPINFO si; + PROCESS_INFORMATION pi; + DWORD rc, exitcode; - // Ignore ^C, ^BREAK in parent - SetConsoleCtrlHandler(parent_console_handler, TRUE/*add*/); + // Ignore ^C, ^BREAK in parent + SetConsoleCtrlHandler(parent_console_handler, TRUE/*add*/); - // Create event used by child to signal daemon_detach() - if (!(dev = create_event(EVT_DETACHED, FALSE/*not signaled*/, TRUE, NULL/*must not exist*/))) { - CloseHandle(rev); - return 101; - } + // Create event used by child to signal daemon_detach() + if (!(dev = create_event(EVT_DETACHED, FALSE/*not signaled*/, TRUE, NULL/*must not exist*/))) { + CloseHandle(rev); + return 101; + } - // Restart process with same args - cmdline = GetCommandLineA(); - memset(&si, 0, sizeof(si)); si.cb = sizeof(si); - - if (!CreateProcessA( - NULL, cmdline, - NULL, NULL, TRUE/*inherit*/, - 0, NULL, NULL, &si, &pi)) { - fprintf(stderr, "CreateProcess(.,\"%s\",.) failed, Error=%ld\n", cmdline, GetLastError()); - CloseHandle(rev); CloseHandle(dev); - return 101; - } - CloseHandle(pi.hThread); + // Restart process with same args + cmdline = GetCommandLineA(); + memset(&si, 0, sizeof(si)); si.cb = sizeof(si); - // Wait for daemon_detach() or exit() - ht[0] = dev; ht[1] = pi.hProcess; - rc = WaitForMultipleObjects(2, ht, FALSE/*or*/, INFINITE); - if (!(/*WAIT_OBJECT_0(0) <= rc && */ rc < WAIT_OBJECT_0+2)) { - fprintf(stderr, "WaitForMultipleObjects returns %lX\n", rc); - TerminateProcess(pi.hProcess, 200); - } - CloseHandle(rev); CloseHandle(dev); + if (!CreateProcessA( + NULL, cmdline, + NULL, NULL, TRUE/*inherit*/, + 0, NULL, NULL, &si, &pi)) { + fprintf(stderr, "CreateProcess(.,\"%s\",.) failed, Error=%ld\n", cmdline, GetLastError()); + CloseHandle(rev); CloseHandle(dev); + return 101; + } + CloseHandle(pi.hThread); - // Get exit code - if (!GetExitCodeProcess(pi.hProcess, &exitcode)) - exitcode = 201; - else if (exitcode == STILL_ACTIVE) // detach()ed, assume OK - exitcode = 0; + // Wait for daemon_detach() or exit() + ht[0] = dev; ht[1] = pi.hProcess; + rc = WaitForMultipleObjects(2, ht, FALSE/*or*/, INFINITE); + if (!(/*WAIT_OBJECT_0(0) <= rc && */ rc < WAIT_OBJECT_0+2)) { + fprintf(stderr, "WaitForMultipleObjects returns %lX\n", rc); + TerminateProcess(pi.hProcess, 200); + } + CloseHandle(rev); CloseHandle(dev); - CloseHandle(pi.hProcess); - return exitcode; + // Get exit code + if (!GetExitCodeProcess(pi.hProcess, &exitcode)) + exitcode = 201; + else if (exitcode == STILL_ACTIVE) // detach()ed, assume OK + exitcode = 0; + + CloseHandle(pi.hProcess); + return exitcode; } @@ -248,77 +249,77 @@ static int reopen_stdin, reopen_stdout, reopen_stderr; static BOOL WINAPI child_console_handler(DWORD event) { - // Caution: runs in a new thread - // TODO: Guard with a mutex - HANDLE h = 0; - switch (event) { - case CTRL_C_EVENT: // (SIGINT) - h = sigint_handle; break; - case CTRL_BREAK_EVENT: // (SIGBREAK/SIGQUIT) - case CTRL_CLOSE_EVENT: // User closed console or abort via task manager - h = sigbreak_handle; break; - case CTRL_LOGOFF_EVENT: // Logout/Shutdown (SIGTERM) - case CTRL_SHUTDOWN_EVENT: - h = sigterm_handle; break; - } - if (!h) - return FALSE; // continue with next handler - // Signal event - if (!SetEvent(h)) - return FALSE; - return TRUE; + // Caution: runs in a new thread + // TODO: Guard with a mutex + HANDLE h = 0; + switch (event) { + case CTRL_C_EVENT: // (SIGINT) + h = sigint_handle; break; + case CTRL_BREAK_EVENT: // (SIGBREAK/SIGQUIT) + case CTRL_CLOSE_EVENT: // User closed console or abort via task manager + h = sigbreak_handle; break; + case CTRL_LOGOFF_EVENT: // Logout/Shutdown (SIGTERM) + case CTRL_SHUTDOWN_EVENT: + h = sigterm_handle; break; + } + if (!h) + return FALSE; // continue with next handler + // Signal event + if (!SetEvent(h)) + return FALSE; + return TRUE; } static void child_exit(void) { - int i; - char * cmdline; - HANDLE rst; - STARTUPINFO si; - PROCESS_INFORMATION pi; + int i; + char * cmdline; + HANDLE rst; + STARTUPINFO si; + PROCESS_INFORMATION pi; - for (i = 0; i < num_sig_handlers; i++) - CloseHandle(sig_events[i]); - num_sig_handlers = 0; - CloseHandle(running_event); running_event = 0; + for (i = 0; i < num_sig_handlers; i++) + CloseHandle(sig_events[i]); + num_sig_handlers = 0; + CloseHandle(running_event); running_event = 0; - // Restart? - if (!(rst = open_event(EVT_RESTART))) - return; // No => normal exit + // Restart? + if (!(rst = open_event(EVT_RESTART))) + return; // No => normal exit - // Yes => Signal exit and restart process - Sleep(500); - SetEvent(rst); - CloseHandle(rst); - Sleep(500); + // Yes => Signal exit and restart process + Sleep(500); + SetEvent(rst); + CloseHandle(rst); + Sleep(500); - cmdline = GetCommandLineA(); - memset(&si, 0, sizeof(si)); si.cb = sizeof(si); - si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; + cmdline = GetCommandLineA(); + memset(&si, 0, sizeof(si)); si.cb = sizeof(si); + si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; - if (!CreateProcessA( - NULL, cmdline, - NULL, NULL, TRUE/*inherit*/, - 0, NULL, NULL, &si, &pi)) { - fprintf(stderr, "CreateProcess(.,\"%s\",.) failed, Error=%ld\n", cmdline, GetLastError()); - } - CloseHandle(pi.hThread); CloseHandle(pi.hProcess); + if (!CreateProcessA( + NULL, cmdline, + NULL, NULL, TRUE/*inherit*/, + 0, NULL, NULL, &si, &pi)) { + fprintf(stderr, "CreateProcess(.,\"%s\",.) failed, Error=%ld\n", cmdline, GetLastError()); + } + CloseHandle(pi.hThread); CloseHandle(pi.hProcess); } static int child_main(HANDLE hev,int (*main_func)(int, char **), int argc, char **argv) { - // Keep EVT_RUNNING open until exit - running_event = hev; + // Keep EVT_RUNNING open until exit + running_event = hev; - // Install console handler - SetConsoleCtrlHandler(child_console_handler, TRUE/*add*/); + // Install console handler + SetConsoleCtrlHandler(child_console_handler, TRUE/*add*/); - // Install restart handler - atexit(child_exit); + // Install restart handler + atexit(child_exit); - // Continue in main_func() to do the real work - return main_func(argc, argv); + // Continue in main_func() to do the real work + return main_func(argc, argv); } @@ -326,33 +327,33 @@ static int child_main(HANDLE hev,int (*main_func)(int, sigfunc_t daemon_signal(int sig, sigfunc_t func) { - int i; - HANDLE h; - if (func == SIG_DFL || func == SIG_IGN) - return func; // TODO - for (i = 0; i < num_sig_handlers; i++) { - if (sig_numbers[i] == sig) { - sigfunc_t old = sig_handlers[i]; - sig_handlers[i] = func; - return old; - } - } - if (num_sig_handlers >= MAX_SIG_HANDLERS) - return SIG_ERR; - if (!(h = create_event((!svc_mode ? sig : -1), FALSE, TRUE, NULL))) - return SIG_ERR; - sig_events[num_sig_handlers] = h; - sig_numbers[num_sig_handlers] = sig; - sig_handlers[num_sig_handlers] = func; - switch (sig) { - case SIGHUP: sighup_handle = h; break; - case SIGINT: sigint_handle = h; break; - case SIGTERM: sigterm_handle = h; break; - case SIGBREAK: sigbreak_handle = h; break; - case SIGUSR1: sigusr1_handle = h; break; - } - num_sig_handlers++; - return SIG_DFL; + int i; + HANDLE h; + if (func == SIG_DFL || func == SIG_IGN) + return func; // TODO + for (i = 0; i < num_sig_handlers; i++) { + if (sig_numbers[i] == sig) { + sigfunc_t old = sig_handlers[i]; + sig_handlers[i] = func; + return old; + } + } + if (num_sig_handlers >= MAX_SIG_HANDLERS) + return SIG_ERR; + if (!(h = create_event((!svc_mode ? sig : -1), FALSE, TRUE, NULL))) + return SIG_ERR; + sig_events[num_sig_handlers] = h; + sig_numbers[num_sig_handlers] = sig; + sig_handlers[num_sig_handlers] = func; + switch (sig) { + case SIGHUP: sighup_handle = h; break; + case SIGINT: sigint_handle = h; break; + case SIGTERM: sigterm_handle = h; break; + case SIGBREAK: sigbreak_handle = h; break; + case SIGUSR1: sigusr1_handle = h; break; + } + num_sig_handlers++; + return SIG_DFL; } @@ -360,15 +361,15 @@ sigfunc_t daemon_signal(int sig, sigfunc_t func) const char * daemon_strsignal(int sig) { - switch (sig) { - case SIGHUP: return "SIGHUP"; - case SIGINT: return "SIGINT"; - case SIGTERM: return "SIGTERM"; - case SIGBREAK:return "SIGBREAK"; - case SIGUSR1: return "SIGUSR1"; - case SIGUSR2: return "SIGUSR2"; - default: return "*UNKNOWN*"; - } + switch (sig) { + case SIGHUP: return "SIGHUP"; + case SIGINT: return "SIGINT"; + case SIGTERM: return "SIGTERM"; + case SIGBREAK:return "SIGBREAK"; + case SIGUSR1: return "SIGUSR1"; + case SIGUSR2: return "SIGUSR2"; + default: return "*UNKNOWN*"; + } } @@ -376,26 +377,26 @@ const char * daemon_strsignal(int sig) void daemon_sleep(int seconds) { - do { - if (num_sig_handlers <= 0) { - Sleep(seconds*1000L); - } - else { - // Wait for any signal or timeout - DWORD rc = WaitForMultipleObjects(num_sig_handlers, sig_events, - FALSE/*OR*/, seconds*1000L); - if (rc != WAIT_TIMEOUT) { - if (!(/*WAIT_OBJECT_0(0) <= rc && */ rc < WAIT_OBJECT_0+(unsigned)num_sig_handlers)) { - fprintf(stderr,"WaitForMultipleObjects returns %lu\n", rc); - Sleep(seconds*1000L); - return; - } - // Call Handler - sig_handlers[rc-WAIT_OBJECT_0](sig_numbers[rc-WAIT_OBJECT_0]); - break; - } - } - } while (svc_paused); + do { + if (num_sig_handlers <= 0) { + Sleep(seconds*1000L); + } + else { + // Wait for any signal or timeout + DWORD rc = WaitForMultipleObjects(num_sig_handlers, sig_events, + FALSE/*OR*/, seconds*1000L); + if (rc != WAIT_TIMEOUT) { + if (!(/*WAIT_OBJECT_0(0) <= rc && */ rc < WAIT_OBJECT_0+(unsigned)num_sig_handlers)) { + fprintf(stderr,"WaitForMultipleObjects returns %lu\n", rc); + Sleep(seconds*1000L); + return; + } + // Call Handler + sig_handlers[rc-WAIT_OBJECT_0](sig_numbers[rc-WAIT_OBJECT_0]); + break; + } + } + } while (svc_paused); } @@ -403,39 +404,39 @@ void daemon_sleep(int seconds) void daemon_disable_console() { - SetConsoleCtrlHandler(child_console_handler, FALSE/*remove*/); - reopen_stdin = reopen_stdout = reopen_stderr = 0; - if (isatty(fileno(stdin))) { - fclose(stdin); reopen_stdin = 1; - } - if (isatty(fileno(stdout))) { - fclose(stdout); reopen_stdout = 1; - } - if (isatty(fileno(stderr))) { - fclose(stderr); reopen_stderr = 1; - } - FreeConsole(); - SetConsoleCtrlHandler(child_console_handler, TRUE/*add*/); + SetConsoleCtrlHandler(child_console_handler, FALSE/*remove*/); + reopen_stdin = reopen_stdout = reopen_stderr = 0; + if (isatty(fileno(stdin))) { + fclose(stdin); reopen_stdin = 1; + } + if (isatty(fileno(stdout))) { + fclose(stdout); reopen_stdout = 1; + } + if (isatty(fileno(stderr))) { + fclose(stderr); reopen_stderr = 1; + } + FreeConsole(); + SetConsoleCtrlHandler(child_console_handler, TRUE/*add*/); } int daemon_enable_console(const char * title) { - BOOL ok; - SetConsoleCtrlHandler(child_console_handler, FALSE/*remove*/); - ok = AllocConsole(); - SetConsoleCtrlHandler(child_console_handler, TRUE/*add*/); - if (!ok) - return -1; - if (title) - SetConsoleTitleA(title); - if (reopen_stdin) - freopen("conin$", "r", stdin); - if (reopen_stdout) - freopen("conout$", "w", stdout); - if (reopen_stderr) - freopen("conout$", "w", stderr); - reopen_stdin = reopen_stdout = reopen_stderr = 0; - return 0; + BOOL ok; + SetConsoleCtrlHandler(child_console_handler, FALSE/*remove*/); + ok = AllocConsole(); + SetConsoleCtrlHandler(child_console_handler, TRUE/*add*/); + if (!ok) + return -1; + if (title) + SetConsoleTitleA(title); + if (reopen_stdin) + freopen("conin$", "r", stdin); + if (reopen_stdout) + freopen("conout$", "w", stdout); + if (reopen_stderr) + freopen("conout$", "w", stderr); + reopen_stdin = reopen_stdout = reopen_stderr = 0; + return 0; } @@ -443,106 +444,33 @@ int daemon_enable_console(const char * title) int daemon_detach(const char * ident) { - if (!svc_mode) { - if (ident) { - // Print help - FILE * f = ( isatty(fileno(stdout)) ? stdout - : isatty(fileno(stderr)) ? stderr : NULL); - if (f) - daemon_help(f, ident, "now detaches from console into background mode"); - } - // Signal detach to parent - if (sig_event(EVT_DETACHED) != 1) { - if (!debugging()) - return -1; - } - daemon_disable_console(); - } - else { - // Signal end of initialization to service control manager - service_report_status(SERVICE_RUNNING, 0); - reopen_stdin = reopen_stdout = reopen_stderr = 1; - } + if (!svc_mode) { + if (ident) { + // Print help + FILE * f = ( isatty(fileno(stdout)) ? stdout + : isatty(fileno(stderr)) ? stderr : NULL); + if (f) + daemon_help(f, ident, "now detaches from console into background mode"); + } + // Signal detach to parent + if (sig_event(EVT_DETACHED) != 1) { + if (!debugging()) + return -1; + } + daemon_disable_console(); + } + else { + // Signal end of initialization to service control manager + service_report_status(SERVICE_RUNNING, 0); + reopen_stdin = reopen_stdout = reopen_stderr = 1; + } - return 0; + return 0; } ///////////////////////////////////////////////////////////////////////////// -// MessageBox -#ifndef _MT -//MT runtime not necessary, because mbox_thread uses no unsafe lib functions -//#error Program must be linked with multithreaded runtime library -#endif - -static LONG mbox_count; // # mbox_thread()s -static HANDLE mbox_mutex; // Show 1 box at a time (not necessary for service) - -typedef struct mbox_args_s { - HANDLE taken; const char * title, * text; int mode; -} mbox_args; - - -// Thread to display one message box - -static ULONG WINAPI mbox_thread(LPVOID arg) -{ - // Take args - mbox_args * mb = (mbox_args *)arg; - char title[100]; char text[1000]; int mode; - strncpy(title, mb->title, sizeof(title)-1); title[sizeof(title)-1] = 0; - strncpy(text , mb->text , sizeof(text )-1); text [sizeof(text )-1] = 0; - mode = mb->mode; - SetEvent(mb->taken); - - // Show only one box at a time - WaitForSingleObject(mbox_mutex, INFINITE); - MessageBoxA(NULL, text, title, mode); - ReleaseMutex(mbox_mutex); - - InterlockedDecrement(&mbox_count); - return 0; -} - - -// Display a message box -int daemon_messagebox(int system, const char * title, const char * text) -{ - mbox_args mb; - HANDLE ht; DWORD tid; - - // Create mutex during first call - if (!mbox_mutex) - mbox_mutex = CreateMutex(NULL/*!inherit*/, FALSE/*!owned*/, NULL/*unnamed*/); - - // Allow at most 10 threads - if (InterlockedIncrement(&mbox_count) > 10) { - InterlockedDecrement(&mbox_count); - return -1; - } - - // Create thread - mb.taken = CreateEvent(NULL/*!inherit*/, FALSE, FALSE/*!signaled*/, NULL/*unnamed*/); - mb.mode = MB_OK|MB_ICONWARNING - |(svc_mode?MB_SERVICE_NOTIFICATION:0) - |(system?MB_SYSTEMMODAL:MB_APPLMODAL); - mb.title = title; - mb.text = text; - if (!(ht = CreateThread(NULL, 0, mbox_thread, &mb, 0, &tid))) - return -1; - - // Wait for args taken - if (WaitForSingleObject(mb.taken, 10000) != WAIT_OBJECT_0) - TerminateThread(ht, 0); - CloseHandle(mb.taken); - CloseHandle(ht); - return 0; -} - - -///////////////////////////////////////////////////////////////////////////// - // Spawn a command and redirect outbuf // return command's exitcode or -1 on error @@ -550,151 +478,108 @@ int daemon_spawn(const char * cmd, const char * inpbuf, int inpsize, char * outbuf, int outsize ) { - HANDLE pipe_inp_r, pipe_inp_w, pipe_out_r, pipe_out_w, pipe_err_w, h; - char temp_path[MAX_PATH]; - DWORD flags, num_io, exitcode; - int use_file, state, i; - SECURITY_ATTRIBUTES sa; - STARTUPINFO si; PROCESS_INFORMATION pi; - HANDLE self = GetCurrentProcess(); + HANDLE self = GetCurrentProcess(); - if (GetVersion() & 0x80000000L) { - // Win9x/ME: A calling process never receives EOF if output of COMMAND.COM or - // any other DOS program is redirected via a pipe. Using a temp file instead. - use_file = 1; flags = DETACHED_PROCESS; - } - else { - // NT4/2000/XP: If DETACHED_PROCESS is used, CMD.EXE opens a new console window - // for each external command in a redirected .BAT file. - // Even (DETACHED_PROCESS|CREATE_NO_WINDOW) does not work. - use_file = 0; flags = CREATE_NO_WINDOW; - } + // Create stdin pipe with inheritable read side + SECURITY_ATTRIBUTES sa; + memset(&sa, 0, sizeof(sa)); sa.nLength = sizeof(sa); + sa.bInheritHandle = TRUE; + HANDLE pipe_inp_r, pipe_inp_w, h; + if (!CreatePipe(&pipe_inp_r, &h, &sa/*inherit*/, inpsize*2+13)) + return -1; + if (!DuplicateHandle(self, h, self, &pipe_inp_w, + 0, FALSE/*!inherit*/, DUPLICATE_SAME_ACCESS|DUPLICATE_CLOSE_SOURCE)) { + CloseHandle(pipe_inp_r); + return -1; + } - // Create stdin pipe with inheritable read side - memset(&sa, 0, sizeof(sa)); sa.nLength = sizeof(sa); - sa.bInheritHandle = TRUE; - if (!CreatePipe(&pipe_inp_r, &h, &sa/*inherit*/, inpsize*2+13)) - return -1; - if (!DuplicateHandle(self, h, self, &pipe_inp_w, - 0, FALSE/*!inherit*/, DUPLICATE_SAME_ACCESS|DUPLICATE_CLOSE_SOURCE)) { - CloseHandle(pipe_inp_r); - return -1; - } + // Create stdout pipe with inheritable write side + memset(&sa, 0, sizeof(sa)); sa.nLength = sizeof(sa); + sa.bInheritHandle = TRUE; + HANDLE pipe_out_w; + if (!CreatePipe(&h, &pipe_out_w, &sa/*inherit*/, outsize)) { + CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w); + return -1; + } - memset(&sa, 0, sizeof(sa)); sa.nLength = sizeof(sa); - sa.bInheritHandle = TRUE; - if (!use_file) { - // Create stdout pipe with inheritable write side - if (!CreatePipe(&h, &pipe_out_w, &sa/*inherit*/, outsize)) { - CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w); - return -1; - } - } - else { - // Create temp file with inheritable write handle - char temp_dir[MAX_PATH]; - if (!GetTempPathA(sizeof(temp_dir), temp_dir)) - strcpy(temp_dir, "."); - if (!GetTempFileNameA(temp_dir, "out"/*prefix*/, 0/*create unique*/, temp_path)) { - CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w); - return -1; - } - if ((h = CreateFileA(temp_path, GENERIC_READ|GENERIC_WRITE, - 0/*no sharing*/, &sa/*inherit*/, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) { - CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w); - return -1; - } - if (!DuplicateHandle(self, h, self, &pipe_out_w, - GENERIC_WRITE, TRUE/*inherit*/, 0)) { - CloseHandle(h); CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w); - return -1; - } - } + HANDLE pipe_out_r; + if (!DuplicateHandle(self, h, self, &pipe_out_r, + GENERIC_READ, FALSE/*!inherit*/, DUPLICATE_CLOSE_SOURCE)) { + CloseHandle(pipe_out_w); CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w); + return -1; + } - if (!DuplicateHandle(self, h, self, &pipe_out_r, - GENERIC_READ, FALSE/*!inherit*/, DUPLICATE_CLOSE_SOURCE)) { - CloseHandle(pipe_out_w); CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w); - return -1; - } + // Create stderr handle as dup of stdout write side + HANDLE pipe_err_w; + if (!DuplicateHandle(self, pipe_out_w, self, &pipe_err_w, + 0, TRUE/*inherit*/, DUPLICATE_SAME_ACCESS)) { + CloseHandle(pipe_out_r); CloseHandle(pipe_out_w); + CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w); + return -1; + } - // Create stderr handle as dup of stdout write side - if (!DuplicateHandle(self, pipe_out_w, self, &pipe_err_w, - 0, TRUE/*inherit*/, DUPLICATE_SAME_ACCESS)) { - CloseHandle(pipe_out_r); CloseHandle(pipe_out_w); - CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w); - return -1; - } + // Create process with pipes as stdio + STARTUPINFO si; + memset(&si, 0, sizeof(si)); si.cb = sizeof(si); + si.hStdInput = pipe_inp_r; + si.hStdOutput = pipe_out_w; + si.hStdError = pipe_err_w; + si.dwFlags = STARTF_USESTDHANDLES; + PROCESS_INFORMATION pi; + if (!CreateProcessA( + NULL, (char*)cmd, + NULL, NULL, TRUE/*inherit*/, + CREATE_NO_WINDOW, // DETACHED_PROCESS does not work + NULL, NULL, &si, &pi)) { + CloseHandle(pipe_err_w); + CloseHandle(pipe_out_r); CloseHandle(pipe_out_w); + CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w); + return -1; + } + CloseHandle(pi.hThread); + // Close inherited handles + CloseHandle(pipe_inp_r); + CloseHandle(pipe_out_w); + CloseHandle(pipe_err_w); - // Create process with pipes/file as stdio - memset(&si, 0, sizeof(si)); si.cb = sizeof(si); - si.hStdInput = pipe_inp_r; - si.hStdOutput = pipe_out_w; - si.hStdError = pipe_err_w; - si.dwFlags = STARTF_USESTDHANDLES; - if (!CreateProcessA( - NULL, (char*)cmd, - NULL, NULL, TRUE/*inherit*/, - flags/*DETACHED_PROCESS or CREATE_NO_WINDOW*/, - NULL, NULL, &si, &pi)) { - CloseHandle(pipe_err_w); - CloseHandle(pipe_out_r); CloseHandle(pipe_out_w); - CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w); - return -1; - } - CloseHandle(pi.hThread); - // Close inherited handles - CloseHandle(pipe_inp_r); - CloseHandle(pipe_out_w); - CloseHandle(pipe_err_w); + // Copy inpbuf to stdin + // convert \n => \r\n + DWORD num_io; + int i; + for (i = 0; i < inpsize; ) { + int len = 0; + while (i+len < inpsize && inpbuf[i+len] != '\n') + len++; + if (len > 0) + WriteFile(pipe_inp_w, inpbuf+i, len, &num_io, NULL); + i += len; + if (i < inpsize) { + WriteFile(pipe_inp_w, "\r\n", 2, &num_io, NULL); + i++; + } + } + CloseHandle(pipe_inp_w); - // Copy inpbuf to stdin - // convert \n => \r\n - for (i = 0; i < inpsize; ) { - int len = 0; - while (i+len < inpsize && inpbuf[i+len] != '\n') - len++; - if (len > 0) - WriteFile(pipe_inp_w, inpbuf+i, len, &num_io, NULL); - i += len; - if (i < inpsize) { - WriteFile(pipe_inp_w, "\r\n", 2, &num_io, NULL); - i++; - } - } - CloseHandle(pipe_inp_w); + // Copy stdout to output buffer until full, rest to /dev/null + // convert \r\n => \n + for (i = 0; ; ) { + char buf[256]; + if (!ReadFile(pipe_out_r, buf, sizeof(buf), &num_io, NULL) || num_io == 0) + break; + for (int j = 0; i < outsize-1 && j < (int)num_io; j++) { + if (buf[j] != '\r') + outbuf[i++] = buf[j]; + } + } + outbuf[i] = 0; + CloseHandle(pipe_out_r); - exitcode = 42; - for (state = 0; state < 2; state++) { - // stdout pipe: read pipe first - // stdout file: wait for process first - if (state == use_file) { - // Copy stdout to output buffer until full, rest to /dev/null - // convert \r\n => \n - if (use_file) - SetFilePointer(pipe_out_r, 0, NULL, FILE_BEGIN); - for (i = 0; ; ) { - char buf[256]; - int j; - if (!ReadFile(pipe_out_r, buf, sizeof(buf), &num_io, NULL) || num_io == 0) - break; - for (j = 0; i < outsize-1 && j < (int)num_io; j++) { - if (buf[j] != '\r') - outbuf[i++] = buf[j]; - } - } - outbuf[i] = 0; - CloseHandle(pipe_out_r); - if (use_file) - DeleteFileA(temp_path); - } - else { - // Wait for process exitcode - WaitForSingleObject(pi.hProcess, INFINITE); - GetExitCodeProcess(pi.hProcess, &exitcode); - CloseHandle(pi.hProcess); - } - } - return exitcode; + // Wait for process exitcode + DWORD exitcode = 42; + WaitForSingleObject(pi.hProcess, INFINITE); + GetExitCodeProcess(pi.hProcess, &exitcode); + CloseHandle(pi.hProcess); + return exitcode; } @@ -703,128 +588,128 @@ int daemon_spawn(const char * cmd, static int wait_signaled(HANDLE h, int seconds) { - int i; - for (i = 0; ; ) { - if (WaitForSingleObject(h, 1000L) == WAIT_OBJECT_0) - return 0; - if (++i >= seconds) - return -1; - fputchar('.'); fflush(stdout); - } + int i; + for (i = 0; ; ) { + if (WaitForSingleObject(h, 1000L) == WAIT_OBJECT_0) + return 0; + if (++i >= seconds) + return -1; + fputchar('.'); fflush(stdout); + } } static int wait_evt_running(int seconds, int exists) { - int i; - if (event_exists(EVT_RUNNING) == exists) - return 0; - for (i = 0; ; ) { - Sleep(1000); - if (event_exists(EVT_RUNNING) == exists) - return 0; - if (++i >= seconds) - return -1; - fputchar('.'); fflush(stdout); - } + int i; + if (event_exists(EVT_RUNNING) == exists) + return 0; + for (i = 0; ; ) { + Sleep(1000); + if (event_exists(EVT_RUNNING) == exists) + return 0; + if (++i >= seconds) + return -1; + fputchar('.'); fflush(stdout); + } } static int is_initd_command(char * s) { - if (!strcmp(s, "status")) - return EVT_RUNNING; - if (!strcmp(s, "stop")) - return SIGTERM; - if (!strcmp(s, "reload")) - return SIGHUP; - if (!strcmp(s, "sigusr1")) - return SIGUSR1; - if (!strcmp(s, "sigusr2")) - return SIGUSR2; - if (!strcmp(s, "restart")) - return EVT_RESTART; - return -1; + if (!strcmp(s, "status")) + return EVT_RUNNING; + if (!strcmp(s, "stop")) + return SIGTERM; + if (!strcmp(s, "reload")) + return SIGHUP; + if (!strcmp(s, "sigusr1")) + return SIGUSR1; + if (!strcmp(s, "sigusr2")) + return SIGUSR2; + if (!strcmp(s, "restart")) + return EVT_RESTART; + return -1; } static int initd_main(const char * ident, int argc, char **argv) { - int rc; - if (argc < 2) - return -1; - if ((rc = is_initd_command(argv[1])) < 0) - return -1; - if (argc != 2) { - printf("%s: no arguments allowed for command %s\n", ident, argv[1]); - return 1; - } + int rc; + if (argc < 2) + return -1; + if ((rc = is_initd_command(argv[1])) < 0) + return -1; + if (argc != 2) { + printf("%s: no arguments allowed for command %s\n", ident, argv[1]); + return 1; + } - switch (rc) { - default: - case EVT_RUNNING: - printf("Checking for %s:", ident); fflush(stdout); - rc = event_exists(EVT_RUNNING); - puts(rc ? " running" : " not running"); - return (rc ? 0 : 1); + switch (rc) { + default: + case EVT_RUNNING: + printf("Checking for %s:", ident); fflush(stdout); + rc = event_exists(EVT_RUNNING); + puts(rc ? " running" : " not running"); + return (rc ? 0 : 1); - case SIGTERM: - printf("Stopping %s:", ident); fflush(stdout); - rc = sig_event(SIGTERM); - if (rc <= 0) { - puts(rc < 0 ? " not running" : " error"); - return (rc < 0 ? 0 : 1); - } - rc = wait_evt_running(10, 0); - puts(!rc ? " done" : " timeout"); - return (!rc ? 0 : 1); + case SIGTERM: + printf("Stopping %s:", ident); fflush(stdout); + rc = sig_event(SIGTERM); + if (rc <= 0) { + puts(rc < 0 ? " not running" : " error"); + return (rc < 0 ? 0 : 1); + } + rc = wait_evt_running(10, 0); + puts(!rc ? " done" : " timeout"); + return (!rc ? 0 : 1); - case SIGHUP: - printf("Reloading %s:", ident); fflush(stdout); - rc = sig_event(SIGHUP); - puts(rc > 0 ? " done" : rc == 0 ? " error" : " not running"); - return (rc > 0 ? 0 : 1); + case SIGHUP: + printf("Reloading %s:", ident); fflush(stdout); + rc = sig_event(SIGHUP); + puts(rc > 0 ? " done" : rc == 0 ? " error" : " not running"); + return (rc > 0 ? 0 : 1); - case SIGUSR1: - case SIGUSR2: - printf("Sending SIGUSR%d to %s:", (rc-SIGUSR1+1), ident); fflush(stdout); - rc = sig_event(rc); - puts(rc > 0 ? " done" : rc == 0 ? " error" : " not running"); - return (rc > 0 ? 0 : 1); + case SIGUSR1: + case SIGUSR2: + printf("Sending SIGUSR%d to %s:", (rc-SIGUSR1+1), ident); fflush(stdout); + rc = sig_event(rc); + puts(rc > 0 ? " done" : rc == 0 ? " error" : " not running"); + return (rc > 0 ? 0 : 1); - case EVT_RESTART: - { - HANDLE rst; - printf("Stopping %s:", ident); fflush(stdout); - if (event_exists(EVT_DETACHED)) { - puts(" not detached, cannot restart"); - return 1; - } - if (!(rst = create_event(EVT_RESTART, FALSE, FALSE, NULL))) { - puts(" error"); - return 1; - } - rc = sig_event(SIGTERM); - if (rc <= 0) { - puts(rc < 0 ? " not running" : " error"); - CloseHandle(rst); - return 1; - } - rc = wait_signaled(rst, 10); - CloseHandle(rst); - if (rc) { - puts(" timeout"); - return 1; - } - puts(" done"); - Sleep(100); + case EVT_RESTART: + { + HANDLE rst; + printf("Stopping %s:", ident); fflush(stdout); + if (event_exists(EVT_DETACHED)) { + puts(" not detached, cannot restart"); + return 1; + } + if (!(rst = create_event(EVT_RESTART, FALSE, FALSE, NULL))) { + puts(" error"); + return 1; + } + rc = sig_event(SIGTERM); + if (rc <= 0) { + puts(rc < 0 ? " not running" : " error"); + CloseHandle(rst); + return 1; + } + rc = wait_signaled(rst, 10); + CloseHandle(rst); + if (rc) { + puts(" timeout"); + return 1; + } + puts(" done"); + Sleep(100); - printf("Starting %s:", ident); fflush(stdout); - rc = wait_evt_running(10, 1); - puts(!rc ? " done" : " error"); - return (!rc ? 0 : 1); - } - } + printf("Starting %s:", ident); fflush(stdout); + rc = wait_evt_running(10, 1); + puts(!rc ? " done" : " error"); + return (!rc ? 0 : 1); + } + } } @@ -841,38 +726,30 @@ static SERVICE_STATUS svc_status; static void service_report_status(int state, int seconds) { - // TODO: Avoid race - static DWORD checkpoint = 1; - static DWORD accept_more = SERVICE_ACCEPT_PARAMCHANGE; // Win2000/XP - svc_status.dwCurrentState = state; - svc_status.dwWaitHint = seconds*1000; - switch (state) { - default: - svc_status.dwCheckPoint = checkpoint++; - break; - case SERVICE_RUNNING: - case SERVICE_STOPPED: - svc_status.dwCheckPoint = 0; - } - switch (state) { - case SERVICE_START_PENDING: - case SERVICE_STOP_PENDING: - svc_status.dwControlsAccepted = 0; - break; - default: - svc_status.dwControlsAccepted = - SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_SHUTDOWN| - SERVICE_ACCEPT_PAUSE_CONTINUE|accept_more; - break; - } - if (!SetServiceStatus(svc_handle, &svc_status)) { - if (svc_status.dwControlsAccepted & accept_more) { - // Retry without SERVICE_ACCEPT_PARAMCHANGE (WinNT4) - svc_status.dwControlsAccepted &= ~accept_more; - accept_more = 0; - SetServiceStatus(svc_handle, &svc_status); - } - } + // TODO: Avoid race + static DWORD checkpoint = 1; + svc_status.dwCurrentState = state; + svc_status.dwWaitHint = seconds*1000; + switch (state) { + default: + svc_status.dwCheckPoint = checkpoint++; + break; + case SERVICE_RUNNING: + case SERVICE_STOPPED: + svc_status.dwCheckPoint = 0; + } + switch (state) { + case SERVICE_START_PENDING: + case SERVICE_STOP_PENDING: + svc_status.dwControlsAccepted = 0; + break; + default: + svc_status.dwControlsAccepted = + SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_SHUTDOWN| + SERVICE_ACCEPT_PAUSE_CONTINUE|SERVICE_ACCEPT_PARAMCHANGE; + break; + } + SetServiceStatus(svc_handle, &svc_status); } @@ -880,35 +757,35 @@ static void service_report_status(int state, int secon static void WINAPI service_control(DWORD ctrlcode) { - switch (ctrlcode) { - case SERVICE_CONTROL_STOP: - case SERVICE_CONTROL_SHUTDOWN: - service_report_status(SERVICE_STOP_PENDING, 30); - svc_paused = 0; - SetEvent(sigterm_handle); - break; - case SERVICE_CONTROL_PARAMCHANGE: // Win2000/XP - service_report_status(svc_status.dwCurrentState, 0); - svc_paused = 0; - SetEvent(sighup_handle); // reload - break; - case SERVICE_CONTROL_PAUSE: - service_report_status(SERVICE_PAUSED, 0); - svc_paused = 1; - break; - case SERVICE_CONTROL_CONTINUE: - service_report_status(SERVICE_RUNNING, 0); - { - int was_paused = svc_paused; - svc_paused = 0; - SetEvent(was_paused ? sighup_handle : sigusr1_handle); // reload:recheck - } - break; - case SERVICE_CONTROL_INTERROGATE: - default: // unknown - service_report_status(svc_status.dwCurrentState, 0); - break; - } + switch (ctrlcode) { + case SERVICE_CONTROL_STOP: + case SERVICE_CONTROL_SHUTDOWN: + service_report_status(SERVICE_STOP_PENDING, 30); + svc_paused = 0; + SetEvent(sigterm_handle); + break; + case SERVICE_CONTROL_PARAMCHANGE: // Win2000/XP + service_report_status(svc_status.dwCurrentState, 0); + svc_paused = 0; + SetEvent(sighup_handle); // reload + break; + case SERVICE_CONTROL_PAUSE: + service_report_status(SERVICE_PAUSED, 0); + svc_paused = 1; + break; + case SERVICE_CONTROL_CONTINUE: + service_report_status(SERVICE_RUNNING, 0); + { + int was_paused = svc_paused; + svc_paused = 0; + SetEvent(was_paused ? sighup_handle : sigusr1_handle); // reload:recheck + } + break; + case SERVICE_CONTROL_INTERROGATE: + default: // unknown + service_report_status(svc_status.dwCurrentState, 0); + break; + } } @@ -916,19 +793,19 @@ static void WINAPI service_control(DWORD ctrlcode) static void service_exit(void) { - // Close signal events - int i; - for (i = 0; i < num_sig_handlers; i++) - CloseHandle(sig_events[i]); - num_sig_handlers = 0; + // Close signal events + int i; + for (i = 0; i < num_sig_handlers; i++) + CloseHandle(sig_events[i]); + num_sig_handlers = 0; - // Set exitcode - if (daemon_winsvc_exitcode) { - svc_status.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR; - svc_status.dwServiceSpecificExitCode = daemon_winsvc_exitcode; - } - // Report stopped - service_report_status(SERVICE_STOPPED, 0); + // Set exitcode + if (daemon_winsvc_exitcode) { + svc_status.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR; + svc_status.dwServiceSpecificExitCode = daemon_winsvc_exitcode; + } + // Report stopped + service_report_status(SERVICE_STOPPED, 0); } @@ -939,167 +816,236 @@ static char ** svc_main_argv; // Main function for service, called by service dispatcher -static void WINAPI service_main(DWORD argc, LPSTR * argv) +static void WINAPI service_main(DWORD /*argc*/, LPSTR * argv) { - char path[MAX_PATH], *p; - ARGUSED(argc); + char path[MAX_PATH], *p; - // Register control handler - svc_handle = RegisterServiceCtrlHandler(argv[0], service_control); + // Register control handler + svc_handle = RegisterServiceCtrlHandler(argv[0], service_control); - // Init service status - svc_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS; - service_report_status(SERVICE_START_PENDING, 10); + // Init service status + svc_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + service_report_status(SERVICE_START_PENDING, 10); - // Service started in \windows\system32, change to .exe directory - if (GetModuleFileNameA(NULL, path, sizeof(path)) && (p = strrchr(path, '\\'))) { - *p = 0; SetCurrentDirectoryA(path); - } - - // Install exit handler - atexit(service_exit); + // Service started in \windows\system32, change to .exe directory + if (GetModuleFileNameA(NULL, path, sizeof(path)) && (p = strrchr(path, '\\'))) { + *p = 0; SetCurrentDirectoryA(path); + } - // Do the real work, service status later updated by daemon_detach() - daemon_winsvc_exitcode = svc_main_func(svc_main_argc, svc_main_argv); + // Install exit handler + atexit(service_exit); - exit(daemon_winsvc_exitcode); - // ... continued in service_exit() + // Do the real work, service status later updated by daemon_detach() + daemon_winsvc_exitcode = svc_main_func(svc_main_argc, svc_main_argv); + + exit(daemon_winsvc_exitcode); + // ... continued in service_exit() } ///////////////////////////////////////////////////////////////////////////// // Windows Service Admin Functions -// Set Service description (Win2000/XP) -static int svcadm_setdesc(SC_HANDLE hs, const char * desc) +// Make registry key name for event message file +static bool make_evtkey(char * buf, unsigned size, const char * ident) { - HINSTANCE hdll; - BOOL (WINAPI * ChangeServiceConfig2A_p)(SC_HANDLE, DWORD, LPVOID); - BOOL ret; - if (!(hdll = LoadLibraryA("ADVAPI32.DLL"))) - return FALSE; - if (!((ChangeServiceConfig2A_p = (BOOL (WINAPI *)(SC_HANDLE, DWORD, LPVOID))GetProcAddress(hdll, "ChangeServiceConfig2A")))) - ret = FALSE; - else { - SERVICE_DESCRIPTIONA sd = { (char *)desc }; - ret = ChangeServiceConfig2A_p(hs, SERVICE_CONFIG_DESCRIPTION, &sd); - } - FreeLibrary(hdll); - return ret; + static const char prefix[] = "SYSTEM\\CurrentControlSet\\Services\\Eventlog\\Application\\"; + const unsigned pfxlen = sizeof(prefix)-1; + unsigned idlen = strlen(ident); + if (pfxlen + idlen >= size) { + printf(" Buffer overflow\n"); + return false; + } + memcpy(buf, prefix, pfxlen); + memcpy(buf+pfxlen, ident, idlen+1); + return true; } +// Install this exe as event message file +static void inst_evtmsg(const char * ident) +{ + printf("Installing event message file for %s:", ident); fflush(stdout); + char mypath[MAX_PATH]; + if (!GetModuleFileNameA((HMODULE)0, mypath, sizeof(mypath))) { + printf(" unknown program path, Error=%ld\n", GetLastError()); + return; + } + + char subkey[MAX_PATH]; + if (!make_evtkey(subkey, sizeof(subkey), ident)) + return; + + HKEY hk; + LONG err = RegCreateKeyExA(HKEY_LOCAL_MACHINE, subkey, 0, (char *)0, 0, KEY_ALL_ACCESS, + (SECURITY_ATTRIBUTES *)0, &hk, (DWORD *)0); + if (err != ERROR_SUCCESS) { + printf(" RegCreateKeyEx failed, error=%ld\n", err); + return; + } + + err = RegSetValueExA(hk, "EventMessageFile", 0, REG_SZ, + (const BYTE *)mypath, strlen(mypath)+1); + if (err == ERROR_SUCCESS) { + DWORD val = EVENTLOG_INFORMATION_TYPE + |EVENTLOG_WARNING_TYPE + |EVENTLOG_ERROR_TYPE; + err = RegSetValueExA(hk, "TypesSupported", 0, REG_DWORD, + (const BYTE *)&val, sizeof(val)); + } + if (err != ERROR_SUCCESS) + printf(" RegSetValueEx failed, error=%ld\n", err); + + RegCloseKey(hk); + puts(" done"); +} + +// Uninstall event message file +static void uninst_evtmsg(const char * ident) +{ + printf("Removing event message file for %s:", ident); fflush(stdout); + + char subkey[MAX_PATH]; + if (!make_evtkey(subkey, sizeof(subkey), ident)) + return; + + LONG err = RegDeleteKeyA(HKEY_LOCAL_MACHINE, subkey); + if (err != ERROR_SUCCESS && err != ERROR_FILE_NOT_FOUND) { + printf(" RegDeleteKey failed, error=%ld\n", err); + return; + } + puts(" done"); +} + + // Service install/remove commands static int svcadm_main(const char * ident, const daemon_winsvc_options * svc_opts, int argc, char **argv ) { - int remove; long err; - SC_HANDLE hm, hs; + int remove; long err; + SC_HANDLE hm, hs; - if (argc < 2) - return -1; - if (!strcmp(argv[1], "install")) - remove = 0; - else if (!strcmp(argv[1], "remove")) { - if (argc != 2) { - printf("%s: no arguments allowed for command remove\n", ident); - return 1; - } - remove = 1; - } - else - return -1; + if (argc < 2) + return -1; + if (!strcmp(argv[1], "install")) + remove = 0; + else if (!strcmp(argv[1], "remove")) { + if (argc != 2) { + printf("%s: no arguments allowed for command remove\n", ident); + return 1; + } + remove = 1; + } + else + return -1; - printf("%s service %s:", (!remove?"Installing":"Removing"), ident); fflush(stdout); + printf("%s service %s:", (!remove?"Installing":"Removing"), ident); fflush(stdout); - // Open SCM - if (!(hm = OpenSCManager(NULL/*local*/, NULL/*default*/, SC_MANAGER_ALL_ACCESS))) { - if ((err = GetLastError()) == ERROR_ACCESS_DENIED) - puts(" access to SCManager denied"); - else if (err == ERROR_CALL_NOT_IMPLEMENTED) - puts(" services not implemented on this version of Windows"); - else - printf(" cannot open SCManager, Error=%ld\n", err); - return 1; - } + // Open SCM + if (!(hm = OpenSCManager(NULL/*local*/, NULL/*default*/, SC_MANAGER_ALL_ACCESS))) { + if ((err = GetLastError()) == ERROR_ACCESS_DENIED) + puts(" access to SCManager denied"); + else + printf(" cannot open SCManager, Error=%ld\n", err); + return 1; + } - if (!remove) { - char path[MAX_PATH+100]; - int i; - // Get program path - if (!GetModuleFileNameA(NULL, path, MAX_PATH)) { - printf(" unknown program path, Error=%ld\n", GetLastError()); - CloseServiceHandle(hm); - return 1; - } - // Add quotes if necessary - if (strchr(path, ' ')) { - i = strlen(path); - path[i+1] = '"'; path[i+2] = 0; - while (--i >= 0) - path[i+1] = path[i]; - path[0] = '"'; - } - // Append options - strcat(path, " "); strcat(path, svc_opts->cmd_opt); - for (i = 2; i < argc; i++) { - const char * s = argv[i]; - if (strlen(path)+1+1+strlen(s)+1 >= sizeof(path)) - break; - // Add quotes if necessary - if (strchr(s, ' ') && !strchr(s, '"')) { - strcat(path, " \""); strcat(path, s); strcat(path, "\""); - } - else { - strcat(path, " "); strcat(path, s); - } - } - // Create - if (!(hs = CreateService(hm, - svc_opts->svcname, svc_opts->dispname, - SERVICE_ALL_ACCESS, - SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS, - SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, path, - NULL/*no load ordering*/, NULL/*no tag id*/, - ""/*no depedencies*/, NULL/*local system account*/, NULL/*no pw*/))) { - if ((err = GetLastError()) == ERROR_SERVICE_EXISTS) - puts(" the service is already installed"); - else if (err == ERROR_SERVICE_MARKED_FOR_DELETE) - puts(" service is still running and marked for deletion\n" - "Stop the service and retry install"); - else - printf(" failed, Error=%ld\n", err); - CloseServiceHandle(hm); - return 1; - } - // Set optional description - if (svc_opts->descript) - svcadm_setdesc(hs, svc_opts->descript); - } - else { - // Open - if (!(hs = OpenService(hm, svc_opts->svcname, SERVICE_ALL_ACCESS))) { - puts(" not found"); - CloseServiceHandle(hm); - return 1; - } - // TODO: Stop service if running - // Remove - if (!DeleteService(hs)) { - if ((err = GetLastError()) == ERROR_SERVICE_MARKED_FOR_DELETE) - puts(" service is still running and marked for deletion\n" - "Stop the service to remove it"); - else - printf(" failed, Error=%ld\n", err); - CloseServiceHandle(hs); CloseServiceHandle(hm); - return 1; - } - } - puts(" done"); - CloseServiceHandle(hs); CloseServiceHandle(hm); - return 0; + if (!remove) { + char path[MAX_PATH+100]; + int i; + // Get program path + if (!GetModuleFileNameA(NULL, path, MAX_PATH)) { + printf(" unknown program path, Error=%ld\n", GetLastError()); + CloseServiceHandle(hm); + return 1; + } + // Add quotes if necessary + if (strchr(path, ' ')) { + i = strlen(path); + path[i+1] = '"'; path[i+2] = 0; + while (--i >= 0) + path[i+1] = path[i]; + path[0] = '"'; + } + // Append options + strcat(path, " "); strcat(path, svc_opts->cmd_opt); + for (i = 2; i < argc; i++) { + const char * s = argv[i]; + if (strlen(path)+1+1+strlen(s)+1 >= sizeof(path)) + break; + // Add quotes if necessary + if (strchr(s, ' ') && !strchr(s, '"')) { + strcat(path, " \""); strcat(path, s); strcat(path, "\""); + } + else { + strcat(path, " "); strcat(path, s); + } + } + // Create + if (!(hs = CreateService(hm, + svc_opts->svcname, svc_opts->dispname, + SERVICE_ALL_ACCESS, + SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS, + SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, path, + NULL/*no load ordering*/, NULL/*no tag id*/, + ""/*no depedencies*/, NULL/*local system account*/, NULL/*no pw*/))) { + if ((err = GetLastError()) == ERROR_SERVICE_EXISTS) + puts(" the service is already installed"); + else if (err == ERROR_SERVICE_MARKED_FOR_DELETE) + puts(" service is still running and marked for deletion\n" + "Stop the service and retry install"); + else + printf(" failed, Error=%ld\n", err); + CloseServiceHandle(hm); + return 1; + } + // Set optional description + if (svc_opts->descript) { + SERVICE_DESCRIPTIONA sd = { const_cast(svc_opts->descript) }; + ChangeServiceConfig2A(hs, SERVICE_CONFIG_DESCRIPTION, &sd); + } + // Enable delayed auto start if supported + OSVERSIONINFOA ver; ver.dwOSVersionInfoSize = sizeof(ver); + if ( GetVersionExA(&ver) + && ver.dwPlatformId == VER_PLATFORM_WIN32_NT + && ver.dwMajorVersion >= 6 /* Vista */ ) { + SERVICE_DELAYED_AUTO_START_INFO sdasi = { TRUE }; + ChangeServiceConfig2A(hs, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, &sdasi); + } + } + else { + // Open + if (!(hs = OpenService(hm, svc_opts->svcname, SERVICE_ALL_ACCESS))) { + puts(" not found"); + CloseServiceHandle(hm); + return 1; + } + // TODO: Stop service if running + // Remove + if (!DeleteService(hs)) { + if ((err = GetLastError()) == ERROR_SERVICE_MARKED_FOR_DELETE) + puts(" service is still running and marked for deletion\n" + "Stop the service to remove it"); + else + printf(" failed, Error=%ld\n", err); + CloseServiceHandle(hs); CloseServiceHandle(hm); + return 1; + } + } + puts(" done"); + CloseServiceHandle(hs); CloseServiceHandle(hm); + + // Install/Remove event message file registry entry + if (!remove) { + inst_evtmsg(ident); + } + else { + uninst_evtmsg(ident); + } + + return 0; } @@ -1112,77 +1058,77 @@ static int svcadm_main(const char * ident, const daemo int daemon_main(const char * ident, const daemon_winsvc_options * svc_opts, int (*main_func)(int, char **), int argc, char **argv ) { - int rc; + int rc; #ifdef _DEBUG - // Enable Debug heap checks - _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) - |_CRTDBG_ALLOC_MEM_DF|_CRTDBG_CHECK_ALWAYS_DF|_CRTDBG_LEAK_CHECK_DF); + // Enable Debug heap checks + _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) + |_CRTDBG_ALLOC_MEM_DF|_CRTDBG_CHECK_ALWAYS_DF|_CRTDBG_LEAK_CHECK_DF); #endif - // Check for [status|stop|reload|restart|sigusr1|sigusr2] parameters - if ((rc = initd_main(ident, argc, argv)) >= 0) - return rc; - // Check for [install|remove] parameters - if (svc_opts && (rc = svcadm_main(ident, svc_opts, argc, argv)) >= 0) - return rc; + // Check for [status|stop|reload|restart|sigusr1|sigusr2] parameters + if ((rc = initd_main(ident, argc, argv)) >= 0) + return rc; + // Check for [install|remove] parameters + if (svc_opts && (rc = svcadm_main(ident, svc_opts, argc, argv)) >= 0) + return rc; - // Run as service if svc_opts.cmd_opt is given as first(!) argument - svc_mode = (svc_opts && argc >= 2 && !strcmp(argv[1], svc_opts->cmd_opt)); + // Run as service if svc_opts.cmd_opt is given as first(!) argument + svc_mode = (svc_opts && argc >= 2 && !strcmp(argv[1], svc_opts->cmd_opt)); - if (!svc_mode) { - // Daemon: Try to simulate a Unix-like daemon - HANDLE rev; - BOOL exists; + if (!svc_mode) { + // Daemon: Try to simulate a Unix-like daemon + HANDLE rev; + BOOL exists; - // Create main event to detect process type: - // 1. new: parent process => start child and wait for detach() or exit() of child. - // 2. exists && signaled: child process => do the real work, signal detach() to parent - // 3. exists && !signaled: already running => exit() - if (!(rev = create_event(EVT_RUNNING, TRUE/*signaled*/, TRUE, &exists))) - return 100; + // Create main event to detect process type: + // 1. new: parent process => start child and wait for detach() or exit() of child. + // 2. exists && signaled: child process => do the real work, signal detach() to parent + // 3. exists && !signaled: already running => exit() + if (!(rev = create_event(EVT_RUNNING, TRUE/*signaled*/, TRUE, &exists))) + return 100; - if (!exists && !debugging()) { - // Event new => parent process - return parent_main(rev); - } + if (!exists && !debugging()) { + // Event new => parent process + return parent_main(rev); + } - if (WaitForSingleObject(rev, 0) == WAIT_OBJECT_0) { - // Event was signaled => In child process - return child_main(rev, main_func, argc, argv); - } + if (WaitForSingleObject(rev, 0) == WAIT_OBJECT_0) { + // Event was signaled => In child process + return child_main(rev, main_func, argc, argv); + } - // Event no longer signaled => Already running! - daemon_help(stdout, ident, "already running"); - CloseHandle(rev); - return 1; - } - else { - // Service: Start service_main() via SCM - SERVICE_TABLE_ENTRY service_table[] = { - { (char*)svc_opts->svcname, service_main }, { NULL, NULL } - }; + // Event no longer signaled => Already running! + daemon_help(stdout, ident, "already running"); + CloseHandle(rev); + return 1; + } + else { + // Service: Start service_main() via SCM + SERVICE_TABLE_ENTRY service_table[] = { + { (char*)svc_opts->svcname, service_main }, { NULL, NULL } + }; - svc_main_func = main_func; - svc_main_argc = argc; - svc_main_argv = argv; - if (!StartServiceCtrlDispatcher(service_table)) { - printf("%s: cannot dispatch service, Error=%ld\n" - "Option \"%s\" cannot be used to start %s as a service from console.\n" - "Use \"%s install ...\" to install the service\n" - "and \"net start %s\" to start it.\n", - ident, GetLastError(), svc_opts->cmd_opt, ident, ident, ident); + svc_main_func = main_func; + svc_main_argc = argc; + svc_main_argv = argv; + if (!StartServiceCtrlDispatcher(service_table)) { + printf("%s: cannot dispatch service, Error=%ld\n" + "Option \"%s\" cannot be used to start %s as a service from console.\n" + "Use \"%s install ...\" to install the service\n" + "and \"net start %s\" to start it.\n", + ident, GetLastError(), svc_opts->cmd_opt, ident, ident, ident); #ifdef _DEBUG - if (debugging()) - service_main(argc, argv); + if (debugging()) + service_main(argc, argv); #endif - return 100; - } - Sleep(1000); - ExitThread(0); // Do not redo exit() processing - /*NOTREACHED*/ - return 0; - } + return 100; + } + Sleep(1000); + ExitThread(0); // Do not redo exit() processing + /*NOTREACHED*/ + return 0; + } } @@ -1195,88 +1141,88 @@ static volatile sig_atomic_t caughtsig = 0; static void sig_handler(int sig) { - caughtsig = sig; + caughtsig = sig; } static void test_exit(void) { - printf("Main exit\n"); + printf("Main exit\n"); } int test_main(int argc, char **argv) { - int i; - int debug = 0; - char * cmd = 0; + int i; + int debug = 0; + char * cmd = 0; - printf("PID=%ld\n", GetCurrentProcessId()); - for (i = 0; i < argc; i++) { - printf("%d: \"%s\"\n", i, argv[i]); - if (!strcmp(argv[i],"-d")) - debug = 1; - } - if (argc > 1 && argv[argc-1][0] != '-') - cmd = argv[argc-1]; + printf("PID=%ld\n", GetCurrentProcessId()); + for (i = 0; i < argc; i++) { + printf("%d: \"%s\"\n", i, argv[i]); + if (!strcmp(argv[i],"-d")) + debug = 1; + } + if (argc > 1 && argv[argc-1][0] != '-') + cmd = argv[argc-1]; - daemon_signal(SIGINT, sig_handler); - daemon_signal(SIGBREAK, sig_handler); - daemon_signal(SIGTERM, sig_handler); - daemon_signal(SIGHUP, sig_handler); - daemon_signal(SIGUSR1, sig_handler); - daemon_signal(SIGUSR2, sig_handler); + daemon_signal(SIGINT, sig_handler); + daemon_signal(SIGBREAK, sig_handler); + daemon_signal(SIGTERM, sig_handler); + daemon_signal(SIGHUP, sig_handler); + daemon_signal(SIGUSR1, sig_handler); + daemon_signal(SIGUSR2, sig_handler); - atexit(test_exit); + atexit(test_exit); - if (!debug) { - printf("Preparing to detach...\n"); - Sleep(2000); - daemon_detach("test"); - printf("Detached!\n"); - } + if (!debug) { + printf("Preparing to detach...\n"); + Sleep(2000); + daemon_detach("test"); + printf("Detached!\n"); + } - for (;;) { - daemon_sleep(1); - printf("."); fflush(stdout); - if (caughtsig) { - if (caughtsig == SIGUSR2) { - debug ^= 1; - if (debug) - daemon_enable_console("Daemon[Debug]"); - else - daemon_disable_console(); - } - else if (caughtsig == SIGUSR1 && cmd) { - char inpbuf[200], outbuf[1000]; int rc; - strcpy(inpbuf, "Hello\nWorld!\n"); - rc = daemon_spawn(cmd, inpbuf, strlen(inpbuf), outbuf, sizeof(outbuf)); - if (!debug) - daemon_enable_console("Command output"); - printf("\"%s\" returns %d\n", cmd, rc); - if (rc >= 0) - printf("output:\n%s.\n", outbuf); - fflush(stdout); - if (!debug) { - Sleep(10000); daemon_disable_console(); - } - } - printf("[PID=%ld: Signal=%d]", GetCurrentProcessId(), caughtsig); fflush(stdout); - if (caughtsig == SIGTERM || caughtsig == SIGBREAK) - break; - caughtsig = 0; - } - } - printf("\nExiting on signal %d\n", caughtsig); - return 0; + for (;;) { + daemon_sleep(1); + printf("."); fflush(stdout); + if (caughtsig) { + if (caughtsig == SIGUSR2) { + debug ^= 1; + if (debug) + daemon_enable_console("Daemon[Debug]"); + else + daemon_disable_console(); + } + else if (caughtsig == SIGUSR1 && cmd) { + char inpbuf[200], outbuf[1000]; int rc; + strcpy(inpbuf, "Hello\nWorld!\n"); + rc = daemon_spawn(cmd, inpbuf, strlen(inpbuf), outbuf, sizeof(outbuf)); + if (!debug) + daemon_enable_console("Command output"); + printf("\"%s\" returns %d\n", cmd, rc); + if (rc >= 0) + printf("output:\n%s.\n", outbuf); + fflush(stdout); + if (!debug) { + Sleep(10000); daemon_disable_console(); + } + } + printf("[PID=%ld: Signal=%d]", GetCurrentProcessId(), caughtsig); fflush(stdout); + if (caughtsig == SIGTERM || caughtsig == SIGBREAK) + break; + caughtsig = 0; + } + } + printf("\nExiting on signal %d\n", caughtsig); + return 0; } int main(int argc, char **argv) { - static const daemon_winsvc_options svc_opts = { - "-s", "test", "Test Service", "Service to test daemon_win32.c Module" - }; + static const daemon_winsvc_options svc_opts = { + "-s", "test", "Test Service", "Service to test daemon_win32.c Module" + }; - return daemon_main("testd", &svc_opts, test_main, argc, argv); + return daemon_main("testd", &svc_opts, test_main, argc, argv); } #endif