Diff for /embedaddon/smartmontools/os_win32/daemon_win32.cpp between versions 1.1.1.1 and 1.1.1.2

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

Removed from v.1.1.1.1  
changed lines
  Added in v.1.1.1.2


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>