/*
* os_win32/daemon_win32.cpp
*
- * Home page of code is: http://smartmontools.sourceforge.net
+ * Home page of code is: http://www.smartmontools.org
*
- * Copyright (C) 2004-10 Christian Franke <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2004-14 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
* 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 <http://www.gnu.org/licenses/>.
*
*/
-// 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 4431 2017-08-08 19:38:15Z chrfranke $"
+ DAEMON_WIN32_H_CVSID;
+
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <crtdbg.h>
#endif
-#include "daemon_win32.h"
-
-const char * daemon_win32_cpp_cvsid = "$Id: daemon_win32.cpp 3267 2011-02-21 17:14:25Z chrfranke $"
- DAEMON_WIN32_H_CVSID;
-
/////////////////////////////////////////////////////////////////////////////
-#define ARGUSED(x) ((void)(x))
-
// Prevent spawning of child process if debugging
#ifdef _DEBUG
#define debugging() IsDebuggerPresent()
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;
- }
-
- if (GetLastError() == ERROR_ALREADY_EXISTS) {
- if (!exists) {
- if (errmsg)
- fprintf(stderr, "CreateEvent(.,\"%s\"): Exists\n", name);
- CloseHandle(h);
- return 0;
- }
- *exists = TRUE;
- }
- return h;
+ 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;
}
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);
}
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;
-
- // 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;
- }
-
- // 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);
-
- // 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);
-
- // 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;
+ 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*/);
+
+ // 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);
+
+ // 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);
+
+ // 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;
}
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: // <CONTROL-C> (SIGINT)
- h = sigint_handle; break;
- case CTRL_BREAK_EVENT: // <CONTROL-Break> (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: // <CONTROL-C> (SIGINT)
+ h = sigint_handle; break;
+ case CTRL_BREAK_EVENT: // <CONTROL-Break> (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;
-
- 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
-
- // 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;
-
- 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);
+ 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;
+
+ // 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);
+
+ 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);
}
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);
}
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;
}
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*";
+ }
}
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);
}
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;
}
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;
- }
-
- 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;
+ 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;
}
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();
-
- 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
- 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;
- }
-
- 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;
- }
- }
-
- 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
- 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/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
- 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);
-
- 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;
+ HANDLE self = GetCurrentProcess();
+
+ // 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 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;
+ }
+
+ 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;
+ }
+
+ // 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 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);
+
+ // 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 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);
+
+ // Wait for process exitcode
+ DWORD exitcode = 42;
+ WaitForSingleObject(pi.hProcess, INFINITE);
+ GetExitCodeProcess(pi.hProcess, &exitcode);
+ CloseHandle(pi.hProcess);
+ return exitcode;
}
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;
- }
-
- 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 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 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);
- }
- }
+ 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);
+
+ 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 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);
+
+ printf("Starting %s:", ident); fflush(stdout);
+ rc = wait_evt_running(10, 1);
+ puts(!rc ? " done" : " error");
+ return (!rc ? 0 : 1);
+ }
+ }
}
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);
}
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;
+ }
}
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;
-
- // 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);
+ // 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);
}
// 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_report_status(SERVICE_START_PENDING, 10);
- // Init service status
- svc_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_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);
+ }
- // 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);
+ // Install exit handler
+ atexit(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);
+ // 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()
+ 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)
+{
+ 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)
{
- 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;
+ 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");
}
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;
-
- 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);
-
- // 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;
- }
-
- 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;
- }
- // Append options
- strcat(path, " "); strcat(path, svc_opts->cmd_opt);
- for (i = 2; i < argc; i++) {
- const char * s = argv[i];
- if (strlen(path)+strlen(s)+1 >= sizeof(path))
- break;
- 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;
+ 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;
+
+ 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
+ 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_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<char *>(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_{,CONFIG_}DELAYED_AUTO_START_INFO are missing in older MinGW headers
+ struct /* SERVICE_DELAYED_AUTO_START_INFO */ {
+ BOOL fDelayedAutostart;
+ } sdasi = { TRUE };
+ // typedef char ASSERT_sizeof_sdasi[sizeof(sdasi) == sizeof(SERVICE_DELAYED_AUTO_START_INFO) ? 1 : -1];
+ // typedef char ASSERT_const_scdasi[SERVICE_CONFIG_DELAYED_AUTO_START_INFO == 3 ? 1 : -1];
+ ChangeServiceConfig2A(hs, 3 /* 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;
}
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;
-
- // 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;
-
- // 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 (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 }
- };
-
- 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);
+ // 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));
+
+ 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;
+
+ 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);
+ }
+
+ // 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);
#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;
+ }
}
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;
-
- 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);
-
- atexit(test_exit);
-
- 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;
+ 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];
+
+ 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);
+
+ 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;
}
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