Annotation of embedaddon/smartmontools/os_win32/daemon_win32.cpp, revision 1.1.1.3

1.1       misho       1: /*
                      2:  * os_win32/daemon_win32.cpp
                      3:  *
                      4:  * Home page of code is: http://smartmontools.sourceforge.net
                      5:  *
1.1.1.2   misho       6:  * Copyright (C) 2004-13 Christian Franke <smartmontools-support@lists.sourceforge.net>
1.1       misho       7:  *
                      8:  * This program is free software; you can redistribute it and/or modify
                      9:  * it under the terms of the GNU General Public License as published by
                     10:  * the Free Software Foundation; either version 2, or (at your option)
                     11:  * any later version.
                     12:  *
                     13:  * You should have received a copy of the GNU General Public License
1.1.1.2   misho      14:  * (for example COPYING); If not, see <http://www.gnu.org/licenses/>.
1.1       misho      15:  *
                     16:  */
                     17: 
1.1.1.2   misho      18: #define WINVER 0x0600
1.1       misho      19: #define _WIN32_WINNT WINVER
                     20: 
1.1.1.2   misho      21: #include "daemon_win32.h"
                     22: 
1.1.1.3 ! misho      23: const char * daemon_win32_cpp_cvsid = "$Id: daemon_win32.cpp 3834 2013-07-20 16:17:13Z chrfranke $"
1.1.1.2   misho      24:   DAEMON_WIN32_H_CVSID;
                     25: 
1.1       misho      26: #include <stdio.h>
                     27: #include <stdlib.h>
                     28: #include <signal.h>
                     29: #include <io.h>
                     30: 
                     31: #define WIN32_LEAN_AND_MEAN
                     32: #include <windows.h>
                     33: #ifdef _DEBUG
                     34: #include <crtdbg.h>
                     35: #endif
                     36: 
1.1.1.2   misho      37: #ifndef SERVICE_CONFIG_DELAYED_AUTO_START_INFO
                     38: // Missing in older MinGW headers
                     39: #define SERVICE_CONFIG_DELAYED_AUTO_START_INFO 3
                     40: #endif
1.1       misho      41: 
                     42: 
                     43: /////////////////////////////////////////////////////////////////////////////
                     44: 
                     45: // Prevent spawning of child process if debugging
                     46: #ifdef _DEBUG
                     47: #define debugging() IsDebuggerPresent()
                     48: #else
                     49: #define debugging() FALSE
                     50: #endif
                     51: 
                     52: 
                     53: #define EVT_NAME_LEN 260
                     54: 
                     55: // Internal events (must be > SIGUSRn)
                     56: #define EVT_RUNNING   100 // Exists when running, signaled on creation
                     57: #define EVT_DETACHED  101 // Signaled when child detaches from console
                     58: #define EVT_RESTART   102 // Signaled when child should restart
                     59: 
                     60: static void make_name(char * name, int sig)
                     61: {
1.1.1.2   misho      62:   int i;
                     63:   if (!GetModuleFileNameA(NULL, name, EVT_NAME_LEN-10))
                     64:     strcpy(name, "DaemonEvent");
                     65:   for (i = 0; name[i]; i++) {
                     66:     char c = name[i];
                     67:     if (!(   ('0' <= c && c <= '9')
                     68:           || ('A' <= c && c <= 'Z')
                     69:           || ('a' <= c && c <= 'z')))
                     70:         name[i] = '_';
                     71:   }
                     72:   sprintf(name+strlen(name), "-%d", sig);
1.1       misho      73: }
                     74: 
                     75: 
                     76: static HANDLE create_event(int sig, BOOL initial, BOOL errmsg, BOOL * exists)
                     77: {
1.1.1.2   misho      78:   char name[EVT_NAME_LEN];
                     79:   HANDLE h;
                     80:   if (sig >= 0)
                     81:     make_name(name, sig);
                     82:   else
                     83:     name[0] = 0;
                     84:   if (exists)
                     85:     *exists = FALSE;
                     86:   if (!(h = CreateEventA(NULL, FALSE, initial, (name[0] ? name : NULL)))) {
                     87:     if (errmsg)
                     88:       fprintf(stderr, "CreateEvent(.,\"%s\"): Error=%ld\n", name, GetLastError());
                     89:     return 0;
                     90:   }
                     91: 
                     92:   if (GetLastError() == ERROR_ALREADY_EXISTS) {
                     93:     if (!exists) {
                     94:       if (errmsg)
                     95:         fprintf(stderr, "CreateEvent(.,\"%s\"): Exists\n", name);
                     96:       CloseHandle(h);
                     97:       return 0;
                     98:     }
                     99:     *exists = TRUE;
                    100:   }
                    101:   return h;
1.1       misho     102: }
                    103: 
                    104: 
                    105: static HANDLE open_event(int sig)
                    106: {
1.1.1.2   misho     107:   char name[EVT_NAME_LEN];
                    108:   make_name(name, sig);
                    109:   return OpenEventA(EVENT_MODIFY_STATE, FALSE, name);
1.1       misho     110: }
                    111: 
                    112: 
                    113: static int event_exists(int sig)
                    114: {
1.1.1.2   misho     115:   char name[EVT_NAME_LEN];
                    116:   HANDLE h;
                    117:   make_name(name, sig);
                    118:   if (!(h = OpenEventA(EVENT_MODIFY_STATE, FALSE, name)))
                    119:     return 0;
                    120:   CloseHandle(h);
                    121:   return 1;
1.1       misho     122: }
                    123: 
                    124: 
                    125: static int sig_event(int sig)
                    126: {
1.1.1.2   misho     127:   char name[EVT_NAME_LEN];
                    128:   HANDLE h;
                    129:   make_name(name, sig);
                    130:   if (!(h = OpenEventA(EVENT_MODIFY_STATE, FALSE, name))) {
                    131:     make_name(name, EVT_RUNNING);
                    132:     if (!(h = OpenEvent(EVENT_MODIFY_STATE, FALSE, name)))
                    133:       return -1;
                    134:     CloseHandle(h);
                    135:     return 0;
                    136:   }
                    137:   SetEvent(h);
                    138:   CloseHandle(h);
                    139:   return 1;
1.1       misho     140: }
                    141: 
                    142: 
                    143: static void daemon_help(FILE * f, const char * ident, const char * message)
                    144: {
1.1.1.2   misho     145:   fprintf(f,
                    146:     "%s: %s.\n"
                    147:     "Use \"%s status|stop|reload|restart|sigusr1|sigusr2\" to control daemon.\n",
                    148:     ident, message, ident);
                    149:   fflush(f);
1.1       misho     150: }
                    151: 
                    152: 
                    153: /////////////////////////////////////////////////////////////////////////////
                    154: // Parent Process
                    155: 
                    156: 
                    157: static BOOL WINAPI parent_console_handler(DWORD event)
                    158: {
1.1.1.2   misho     159:   switch (event) {
                    160:     case CTRL_C_EVENT:
                    161:     case CTRL_BREAK_EVENT:
                    162:       return TRUE; // Ignore
                    163:   }
                    164:   return FALSE; // continue with next handler ...
1.1       misho     165: }
                    166: 
                    167: 
                    168: static int parent_main(HANDLE rev)
                    169: {
1.1.1.2   misho     170:   HANDLE dev;
                    171:   HANDLE ht[2];
                    172:   char * cmdline;
                    173:   STARTUPINFO si;
                    174:   PROCESS_INFORMATION pi;
                    175:   DWORD rc, exitcode;
                    176: 
                    177:   // Ignore ^C, ^BREAK in parent
                    178:   SetConsoleCtrlHandler(parent_console_handler, TRUE/*add*/);
                    179: 
                    180:   // Create event used by child to signal daemon_detach()
                    181:   if (!(dev = create_event(EVT_DETACHED, FALSE/*not signaled*/, TRUE, NULL/*must not exist*/))) {
                    182:     CloseHandle(rev);
                    183:     return 101;
                    184:   }
                    185: 
                    186:   // Restart process with same args
                    187:   cmdline = GetCommandLineA();
                    188:   memset(&si, 0, sizeof(si)); si.cb = sizeof(si);
                    189: 
                    190:   if (!CreateProcessA(
                    191:     NULL, cmdline,
                    192:     NULL, NULL, TRUE/*inherit*/,
                    193:     0, NULL, NULL, &si, &pi)) {
                    194:     fprintf(stderr, "CreateProcess(.,\"%s\",.) failed, Error=%ld\n", cmdline, GetLastError());
                    195:     CloseHandle(rev); CloseHandle(dev);
                    196:     return 101;
                    197:   }
                    198:   CloseHandle(pi.hThread);
                    199: 
                    200:   // Wait for daemon_detach() or exit()
                    201:   ht[0] = dev; ht[1] = pi.hProcess;
                    202:   rc = WaitForMultipleObjects(2, ht, FALSE/*or*/, INFINITE);
                    203:   if (!(/*WAIT_OBJECT_0(0) <= rc && */ rc < WAIT_OBJECT_0+2)) {
                    204:     fprintf(stderr, "WaitForMultipleObjects returns %lX\n", rc);
                    205:     TerminateProcess(pi.hProcess, 200);
                    206:   }
                    207:   CloseHandle(rev); CloseHandle(dev);
                    208: 
                    209:   // Get exit code
                    210:   if (!GetExitCodeProcess(pi.hProcess, &exitcode))
                    211:     exitcode = 201;
                    212:   else if (exitcode == STILL_ACTIVE) // detach()ed, assume OK
                    213:     exitcode = 0;
1.1       misho     214: 
1.1.1.2   misho     215:   CloseHandle(pi.hProcess);
                    216:   return exitcode;
1.1       misho     217: }
                    218: 
                    219: 
                    220: /////////////////////////////////////////////////////////////////////////////
                    221: // Child Process
                    222: 
                    223: 
                    224: static int svc_mode;   // Running as service?
                    225: static int svc_paused; // Service paused?
                    226: 
                    227: static void service_report_status(int state, int waithint);
                    228: 
                    229: 
                    230: // Tables of signal handler and corresponding events
                    231: typedef void (*sigfunc_t)(int);
                    232: 
                    233: #define MAX_SIG_HANDLERS 8
                    234: 
                    235: static int num_sig_handlers = 0;
                    236: static sigfunc_t sig_handlers[MAX_SIG_HANDLERS];
                    237: static int sig_numbers[MAX_SIG_HANDLERS];
                    238: static HANDLE sig_events[MAX_SIG_HANDLERS];
                    239: 
                    240: static HANDLE sighup_handle, sigint_handle, sigbreak_handle;
                    241: static HANDLE sigterm_handle, sigusr1_handle;
                    242: 
                    243: static HANDLE running_event;
                    244: 
                    245: static int reopen_stdin, reopen_stdout, reopen_stderr;
                    246: 
                    247: 
                    248: // Handler for windows console events
                    249: 
                    250: static BOOL WINAPI child_console_handler(DWORD event)
                    251: {
1.1.1.2   misho     252:   // Caution: runs in a new thread
                    253:   // TODO: Guard with a mutex
                    254:   HANDLE h = 0;
                    255:   switch (event) {
                    256:     case CTRL_C_EVENT: // <CONTROL-C> (SIGINT)
                    257:       h = sigint_handle; break;
                    258:     case CTRL_BREAK_EVENT: // <CONTROL-Break> (SIGBREAK/SIGQUIT)
                    259:     case CTRL_CLOSE_EVENT: // User closed console or abort via task manager
                    260:       h = sigbreak_handle; break;
                    261:     case CTRL_LOGOFF_EVENT: // Logout/Shutdown (SIGTERM)
                    262:     case CTRL_SHUTDOWN_EVENT:
                    263:       h = sigterm_handle; break;
                    264:   }
                    265:   if (!h)
                    266:     return FALSE; // continue with next handler
                    267:   // Signal event
                    268:   if (!SetEvent(h))
                    269:     return FALSE;
                    270:   return TRUE;
1.1       misho     271: }
                    272: 
                    273: 
                    274: static void child_exit(void)
                    275: {
1.1.1.2   misho     276:   int i;
                    277:   char * cmdline;
                    278:   HANDLE rst;
                    279:   STARTUPINFO si;
                    280:   PROCESS_INFORMATION pi;
                    281: 
                    282:   for (i = 0; i < num_sig_handlers; i++)
                    283:     CloseHandle(sig_events[i]);
                    284:   num_sig_handlers = 0;
                    285:   CloseHandle(running_event); running_event = 0;
                    286: 
                    287:   // Restart?
                    288:   if (!(rst = open_event(EVT_RESTART)))
                    289:     return; // No => normal exit
                    290: 
                    291:   // Yes => Signal exit and restart process
                    292:   Sleep(500);
                    293:   SetEvent(rst);
                    294:   CloseHandle(rst);
                    295:   Sleep(500);
                    296: 
                    297:   cmdline = GetCommandLineA();
                    298:   memset(&si, 0, sizeof(si)); si.cb = sizeof(si);
                    299:   si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE;
                    300: 
                    301:   if (!CreateProcessA(
                    302:     NULL, cmdline,
                    303:     NULL, NULL, TRUE/*inherit*/,
                    304:     0, NULL, NULL, &si, &pi)) {
                    305:     fprintf(stderr, "CreateProcess(.,\"%s\",.) failed, Error=%ld\n", cmdline, GetLastError());
                    306:   }
                    307:   CloseHandle(pi.hThread); CloseHandle(pi.hProcess);
1.1       misho     308: }
                    309: 
                    310: static int child_main(HANDLE hev,int (*main_func)(int, char **), int argc, char **argv)
                    311: {
1.1.1.2   misho     312:   // Keep EVT_RUNNING open until exit
                    313:   running_event = hev;
1.1       misho     314: 
1.1.1.2   misho     315:   // Install console handler
                    316:   SetConsoleCtrlHandler(child_console_handler, TRUE/*add*/);
1.1       misho     317: 
1.1.1.2   misho     318:   // Install restart handler
                    319:   atexit(child_exit);
1.1       misho     320: 
1.1.1.2   misho     321:   // Continue in main_func() to do the real work
                    322:   return main_func(argc, argv);
1.1       misho     323: }
                    324: 
                    325: 
                    326: // Simulate signal()
                    327: 
                    328: sigfunc_t daemon_signal(int sig, sigfunc_t func)
                    329: {
1.1.1.2   misho     330:   int i;
                    331:   HANDLE h;
                    332:   if (func == SIG_DFL || func == SIG_IGN)
                    333:     return func; // TODO
                    334:   for (i = 0; i < num_sig_handlers; i++) {
                    335:     if (sig_numbers[i] == sig) {
                    336:       sigfunc_t old = sig_handlers[i];
                    337:       sig_handlers[i] = func;
                    338:       return old;
                    339:     }
                    340:   }
                    341:   if (num_sig_handlers >= MAX_SIG_HANDLERS)
                    342:     return SIG_ERR;
                    343:   if (!(h = create_event((!svc_mode ? sig : -1), FALSE, TRUE, NULL)))
                    344:     return SIG_ERR;
                    345:   sig_events[num_sig_handlers]   = h;
                    346:   sig_numbers[num_sig_handlers]  = sig;
                    347:   sig_handlers[num_sig_handlers] = func;
                    348:   switch (sig) {
                    349:     case SIGHUP:   sighup_handle   = h; break;
                    350:     case SIGINT:   sigint_handle   = h; break;
                    351:     case SIGTERM:  sigterm_handle  = h; break;
                    352:     case SIGBREAK: sigbreak_handle = h; break;
                    353:     case SIGUSR1:  sigusr1_handle  = h; break;
                    354:   }
                    355:   num_sig_handlers++;
                    356:   return SIG_DFL;
1.1       misho     357: }
                    358: 
                    359: 
                    360: // strsignal()
                    361: 
                    362: const char * daemon_strsignal(int sig)
                    363: {
1.1.1.2   misho     364:   switch (sig) {
                    365:     case SIGHUP:  return "SIGHUP";
                    366:     case SIGINT:  return "SIGINT";
                    367:     case SIGTERM: return "SIGTERM";
                    368:     case SIGBREAK:return "SIGBREAK";
                    369:     case SIGUSR1: return "SIGUSR1";
                    370:     case SIGUSR2: return "SIGUSR2";
                    371:     default:      return "*UNKNOWN*";
                    372:   }
1.1       misho     373: }
                    374: 
                    375: 
                    376: // Simulate sleep()
                    377: 
                    378: void daemon_sleep(int seconds)
                    379: {
1.1.1.2   misho     380:   do {
                    381:     if (num_sig_handlers <= 0) {
                    382:       Sleep(seconds*1000L);
                    383:     }
                    384:     else {
                    385:       // Wait for any signal or timeout
                    386:       DWORD rc = WaitForMultipleObjects(num_sig_handlers, sig_events,
                    387:         FALSE/*OR*/, seconds*1000L);
                    388:       if (rc != WAIT_TIMEOUT) {
                    389:         if (!(/*WAIT_OBJECT_0(0) <= rc && */ rc < WAIT_OBJECT_0+(unsigned)num_sig_handlers)) {
                    390:           fprintf(stderr,"WaitForMultipleObjects returns %lu\n", rc);
                    391:           Sleep(seconds*1000L);
                    392:           return;
                    393:         }
                    394:         // Call Handler
                    395:         sig_handlers[rc-WAIT_OBJECT_0](sig_numbers[rc-WAIT_OBJECT_0]);
                    396:         break;
                    397:       }
                    398:     }
                    399:   } while (svc_paused);
1.1       misho     400: }
                    401: 
                    402: 
                    403: // Disable/Enable console
                    404: 
                    405: void daemon_disable_console()
                    406: {
1.1.1.2   misho     407:   SetConsoleCtrlHandler(child_console_handler, FALSE/*remove*/);
                    408:   reopen_stdin = reopen_stdout = reopen_stderr = 0;
                    409:   if (isatty(fileno(stdin))) {
                    410:     fclose(stdin); reopen_stdin = 1;
                    411:   }
                    412:   if (isatty(fileno(stdout))) {
                    413:     fclose(stdout); reopen_stdout = 1;
                    414:   }
                    415:   if (isatty(fileno(stderr))) {
                    416:     fclose(stderr); reopen_stderr = 1;
                    417:   }
                    418:   FreeConsole();
                    419:   SetConsoleCtrlHandler(child_console_handler, TRUE/*add*/);
1.1       misho     420: }
                    421: 
                    422: int daemon_enable_console(const char * title)
                    423: {
1.1.1.2   misho     424:   BOOL ok;
                    425:   SetConsoleCtrlHandler(child_console_handler, FALSE/*remove*/);
                    426:   ok = AllocConsole();
                    427:   SetConsoleCtrlHandler(child_console_handler, TRUE/*add*/);
                    428:   if (!ok)
                    429:     return -1;
                    430:   if (title)
                    431:     SetConsoleTitleA(title);
                    432:   if (reopen_stdin)
                    433:     freopen("conin$",  "r", stdin);
                    434:   if (reopen_stdout)
                    435:     freopen("conout$", "w", stdout);
                    436:   if (reopen_stderr)
                    437:     freopen("conout$", "w", stderr);
                    438:   reopen_stdin = reopen_stdout = reopen_stderr = 0;
                    439:   return 0;
1.1       misho     440: }
                    441: 
                    442: 
                    443: // Detach daemon from console & parent
                    444: 
                    445: int daemon_detach(const char * ident)
                    446: {
1.1.1.2   misho     447:   if (!svc_mode) {
                    448:     if (ident) {
                    449:       // Print help
                    450:       FILE * f = ( isatty(fileno(stdout)) ? stdout
                    451:              : isatty(fileno(stderr)) ? stderr : NULL);
                    452:       if (f)
                    453:         daemon_help(f, ident, "now detaches from console into background mode");
                    454:     }
                    455:     // Signal detach to parent
                    456:     if (sig_event(EVT_DETACHED) != 1) {
                    457:       if (!debugging())
                    458:         return -1;
                    459:     }
                    460:     daemon_disable_console();
                    461:   }
                    462:   else {
                    463:     // Signal end of initialization to service control manager
                    464:     service_report_status(SERVICE_RUNNING, 0);
                    465:     reopen_stdin = reopen_stdout = reopen_stderr = 1;
                    466:   }
1.1       misho     467: 
1.1.1.2   misho     468:   return 0;
1.1       misho     469: }
                    470: 
                    471: 
                    472: /////////////////////////////////////////////////////////////////////////////
                    473: 
                    474: // Spawn a command and redirect <inpbuf >outbuf
                    475: // return command's exitcode or -1 on error
                    476: 
                    477: int daemon_spawn(const char * cmd,
                    478:                  const char * inpbuf, int inpsize,
                    479:                  char *       outbuf, int outsize )
                    480: {
1.1.1.2   misho     481:   HANDLE self = GetCurrentProcess();
                    482: 
                    483:   // Create stdin pipe with inheritable read side
                    484:   SECURITY_ATTRIBUTES sa;
                    485:   memset(&sa, 0, sizeof(sa)); sa.nLength = sizeof(sa);
                    486:   sa.bInheritHandle = TRUE;
                    487:   HANDLE pipe_inp_r, pipe_inp_w, h;
                    488:   if (!CreatePipe(&pipe_inp_r, &h, &sa/*inherit*/, inpsize*2+13))
                    489:     return -1;
                    490:   if (!DuplicateHandle(self, h, self, &pipe_inp_w,
                    491:     0, FALSE/*!inherit*/, DUPLICATE_SAME_ACCESS|DUPLICATE_CLOSE_SOURCE)) {
                    492:     CloseHandle(pipe_inp_r);
                    493:     return -1;
                    494:   }
                    495: 
                    496:   // Create stdout pipe with inheritable write side
                    497:   memset(&sa, 0, sizeof(sa)); sa.nLength = sizeof(sa);
                    498:   sa.bInheritHandle = TRUE;
                    499:   HANDLE pipe_out_w;
                    500:   if (!CreatePipe(&h, &pipe_out_w, &sa/*inherit*/, outsize)) {
                    501:     CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w);
                    502:     return -1;
                    503:   }
                    504: 
                    505:   HANDLE pipe_out_r;
                    506:   if (!DuplicateHandle(self, h, self, &pipe_out_r,
                    507:     GENERIC_READ, FALSE/*!inherit*/, DUPLICATE_CLOSE_SOURCE)) {
                    508:     CloseHandle(pipe_out_w); CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w);
                    509:     return -1;
                    510:   }
                    511: 
                    512:   // Create stderr handle as dup of stdout write side
                    513:   HANDLE pipe_err_w;
                    514:   if (!DuplicateHandle(self, pipe_out_w, self, &pipe_err_w,
                    515:     0, TRUE/*inherit*/, DUPLICATE_SAME_ACCESS)) {
                    516:     CloseHandle(pipe_out_r); CloseHandle(pipe_out_w);
                    517:     CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w);
                    518:     return -1;
                    519:   }
                    520: 
                    521:   // Create process with pipes as stdio
                    522:   STARTUPINFO si;
                    523:   memset(&si, 0, sizeof(si)); si.cb = sizeof(si);
                    524:   si.hStdInput  = pipe_inp_r;
                    525:   si.hStdOutput = pipe_out_w;
                    526:   si.hStdError  = pipe_err_w;
                    527:   si.dwFlags = STARTF_USESTDHANDLES;
                    528:   PROCESS_INFORMATION pi;
                    529:   if (!CreateProcessA(
                    530:     NULL, (char*)cmd,
                    531:     NULL, NULL, TRUE/*inherit*/,
                    532:     CREATE_NO_WINDOW, // DETACHED_PROCESS does not work
                    533:     NULL, NULL, &si, &pi)) {
                    534:     CloseHandle(pipe_err_w);
                    535:     CloseHandle(pipe_out_r); CloseHandle(pipe_out_w);
                    536:     CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w);
                    537:     return -1;
                    538:   }
                    539:   CloseHandle(pi.hThread);
                    540:   // Close inherited handles
                    541:   CloseHandle(pipe_inp_r);
                    542:   CloseHandle(pipe_out_w);
                    543:   CloseHandle(pipe_err_w);
                    544: 
                    545:   // Copy inpbuf to stdin
                    546:   // convert \n => \r\n
                    547:   DWORD num_io;
                    548:   int i;
                    549:   for (i = 0; i < inpsize; ) {
                    550:     int len = 0;
                    551:     while (i+len < inpsize && inpbuf[i+len] != '\n')
                    552:       len++;
                    553:     if (len > 0)
                    554:       WriteFile(pipe_inp_w, inpbuf+i, len, &num_io, NULL);
                    555:     i += len;
                    556:     if (i < inpsize) {
                    557:       WriteFile(pipe_inp_w, "\r\n", 2, &num_io, NULL);
                    558:       i++;
                    559:     }
                    560:   }
                    561:   CloseHandle(pipe_inp_w);
                    562: 
                    563:   // Copy stdout to output buffer until full, rest to /dev/null
                    564:   // convert \r\n => \n
                    565:   for (i = 0; ; ) {
                    566:     char buf[256];
                    567:     if (!ReadFile(pipe_out_r, buf, sizeof(buf), &num_io, NULL) || num_io == 0)
                    568:       break;
                    569:     for (int j = 0; i < outsize-1 && j < (int)num_io; j++) {
                    570:       if (buf[j] != '\r')
                    571:         outbuf[i++] = buf[j];
                    572:     }
                    573:   }
                    574:   outbuf[i] = 0;
                    575:   CloseHandle(pipe_out_r);
                    576: 
                    577:   // Wait for process exitcode
                    578:   DWORD exitcode = 42;
                    579:   WaitForSingleObject(pi.hProcess, INFINITE);
                    580:   GetExitCodeProcess(pi.hProcess, &exitcode);
                    581:   CloseHandle(pi.hProcess);
                    582:   return exitcode;
1.1       misho     583: }
                    584: 
                    585: 
                    586: /////////////////////////////////////////////////////////////////////////////
                    587: // Initd Functions
                    588: 
                    589: static int wait_signaled(HANDLE h, int seconds)
                    590: {
1.1.1.2   misho     591:   int i;
                    592:   for (i = 0; ; ) {
                    593:     if (WaitForSingleObject(h, 1000L) == WAIT_OBJECT_0)
                    594:       return 0;
                    595:     if (++i >= seconds)
                    596:       return -1;
                    597:     fputchar('.'); fflush(stdout);
                    598:   }
1.1       misho     599: }
                    600: 
                    601: 
                    602: static int wait_evt_running(int seconds, int exists)
                    603: {
1.1.1.2   misho     604:   int i;
                    605:   if (event_exists(EVT_RUNNING) == exists)
                    606:     return 0;
                    607:   for (i = 0; ; ) {
                    608:     Sleep(1000);
                    609:     if (event_exists(EVT_RUNNING) == exists)
                    610:       return 0;
                    611:     if (++i >= seconds)
                    612:       return -1;
                    613:     fputchar('.'); fflush(stdout);
                    614:   }
1.1       misho     615: }
                    616: 
                    617: 
                    618: static int is_initd_command(char * s)
                    619: {
1.1.1.2   misho     620:   if (!strcmp(s, "status"))
                    621:     return EVT_RUNNING;
                    622:   if (!strcmp(s, "stop"))
                    623:     return SIGTERM;
                    624:   if (!strcmp(s, "reload"))
                    625:     return SIGHUP;
                    626:   if (!strcmp(s, "sigusr1"))
                    627:     return SIGUSR1;
                    628:   if (!strcmp(s, "sigusr2"))
                    629:     return SIGUSR2;
                    630:   if (!strcmp(s, "restart"))
                    631:     return EVT_RESTART;
                    632:   return -1;
1.1       misho     633: }
                    634: 
                    635: 
                    636: static int initd_main(const char * ident, int argc, char **argv)
                    637: {
1.1.1.2   misho     638:   int rc;
                    639:   if (argc < 2)
                    640:     return -1;
                    641:   if ((rc = is_initd_command(argv[1])) < 0)
                    642:     return -1;
                    643:   if (argc != 2) {
                    644:     printf("%s: no arguments allowed for command %s\n", ident, argv[1]);
                    645:     return 1;
                    646:   }
                    647: 
                    648:   switch (rc) {
                    649:     default:
                    650:     case EVT_RUNNING:
                    651:       printf("Checking for %s:", ident); fflush(stdout);
                    652:       rc = event_exists(EVT_RUNNING);
                    653:       puts(rc ? " running" : " not running");
                    654:       return (rc ? 0 : 1);
                    655: 
                    656:     case SIGTERM:
                    657:       printf("Stopping %s:", ident); fflush(stdout);
                    658:       rc = sig_event(SIGTERM);
                    659:       if (rc <= 0) {
                    660:         puts(rc < 0 ? " not running" : " error");
                    661:         return (rc < 0 ? 0 : 1);
                    662:       }
                    663:       rc = wait_evt_running(10, 0);
                    664:       puts(!rc ? " done" : " timeout");
                    665:       return (!rc ? 0 : 1);
                    666: 
                    667:     case SIGHUP:
                    668:       printf("Reloading %s:", ident); fflush(stdout);
                    669:       rc = sig_event(SIGHUP);
                    670:       puts(rc > 0 ? " done" : rc == 0 ? " error" : " not running");
                    671:       return (rc > 0 ? 0 : 1);
                    672: 
                    673:     case SIGUSR1:
                    674:     case SIGUSR2:
                    675:       printf("Sending SIGUSR%d to %s:", (rc-SIGUSR1+1), ident); fflush(stdout);
                    676:       rc = sig_event(rc);
                    677:       puts(rc > 0 ? " done" : rc == 0 ? " error" : " not running");
                    678:       return (rc > 0 ? 0 : 1);
                    679: 
                    680:     case EVT_RESTART:
                    681:       {
                    682:         HANDLE rst;
                    683:         printf("Stopping %s:", ident); fflush(stdout);
                    684:         if (event_exists(EVT_DETACHED)) {
                    685:           puts(" not detached, cannot restart");
                    686:           return 1;
                    687:         }
                    688:         if (!(rst = create_event(EVT_RESTART, FALSE, FALSE, NULL))) {
                    689:           puts(" error");
                    690:           return 1;
                    691:         }
                    692:         rc = sig_event(SIGTERM);
                    693:         if (rc <= 0) {
                    694:           puts(rc < 0 ? " not running" : " error");
                    695:           CloseHandle(rst);
                    696:           return 1;
                    697:         }
                    698:         rc = wait_signaled(rst, 10);
                    699:         CloseHandle(rst);
                    700:         if (rc) {
                    701:           puts(" timeout");
                    702:           return 1;
                    703:         }
                    704:         puts(" done");
                    705:         Sleep(100);
                    706: 
                    707:         printf("Starting %s:", ident); fflush(stdout);
                    708:         rc = wait_evt_running(10, 1);
                    709:         puts(!rc ? " done" : " error");
                    710:         return (!rc ? 0 : 1);
                    711:       }
                    712:   }
1.1       misho     713: }
                    714: 
                    715: 
                    716: /////////////////////////////////////////////////////////////////////////////
                    717: // Windows Service Functions
                    718: 
                    719: int daemon_winsvc_exitcode; // Set by app to exit(code)
                    720: 
                    721: static SERVICE_STATUS_HANDLE svc_handle;
                    722: static SERVICE_STATUS svc_status;
                    723: 
                    724: 
                    725: // Report status to SCM
                    726: 
                    727: static void service_report_status(int state, int seconds)
                    728: {
1.1.1.2   misho     729:   // TODO: Avoid race
                    730:   static DWORD checkpoint = 1;
                    731:   svc_status.dwCurrentState = state;
                    732:   svc_status.dwWaitHint = seconds*1000;
                    733:   switch (state) {
                    734:     default:
                    735:       svc_status.dwCheckPoint = checkpoint++;
                    736:       break;
                    737:     case SERVICE_RUNNING:
                    738:     case SERVICE_STOPPED:
                    739:       svc_status.dwCheckPoint = 0;
                    740:   }
                    741:   switch (state) {
                    742:     case SERVICE_START_PENDING:
                    743:     case SERVICE_STOP_PENDING:
                    744:       svc_status.dwControlsAccepted = 0;
                    745:       break;
                    746:     default:
                    747:       svc_status.dwControlsAccepted =
                    748:         SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_SHUTDOWN|
                    749:         SERVICE_ACCEPT_PAUSE_CONTINUE|SERVICE_ACCEPT_PARAMCHANGE;
                    750:       break;
                    751:   }
                    752:   SetServiceStatus(svc_handle, &svc_status);
1.1       misho     753: }
                    754: 
                    755: 
                    756: // Control the service, called by SCM
                    757: 
                    758: static void WINAPI service_control(DWORD ctrlcode)
                    759: {
1.1.1.2   misho     760:   switch (ctrlcode) {
                    761:     case SERVICE_CONTROL_STOP:
                    762:     case SERVICE_CONTROL_SHUTDOWN:
                    763:       service_report_status(SERVICE_STOP_PENDING, 30);
                    764:       svc_paused = 0;
                    765:       SetEvent(sigterm_handle);
                    766:       break;
                    767:     case SERVICE_CONTROL_PARAMCHANGE: // Win2000/XP
                    768:       service_report_status(svc_status.dwCurrentState, 0);
                    769:       svc_paused = 0;
                    770:       SetEvent(sighup_handle); // reload
                    771:       break;
                    772:     case SERVICE_CONTROL_PAUSE:
                    773:       service_report_status(SERVICE_PAUSED, 0);
                    774:       svc_paused = 1;
                    775:       break;
                    776:     case SERVICE_CONTROL_CONTINUE:
                    777:       service_report_status(SERVICE_RUNNING, 0);
                    778:       {
                    779:         int was_paused = svc_paused;
                    780:         svc_paused = 0;
                    781:         SetEvent(was_paused ? sighup_handle : sigusr1_handle); // reload:recheck
                    782:       }
                    783:       break;
                    784:     case SERVICE_CONTROL_INTERROGATE:
                    785:     default: // unknown
                    786:       service_report_status(svc_status.dwCurrentState, 0);
                    787:       break;
                    788:   }
1.1       misho     789: }
                    790: 
                    791: 
                    792: // Exit handler for service
                    793: 
                    794: static void service_exit(void)
                    795: {
1.1.1.2   misho     796:   // Close signal events
                    797:   int i;
                    798:   for (i = 0; i < num_sig_handlers; i++)
                    799:     CloseHandle(sig_events[i]);
                    800:   num_sig_handlers = 0;
                    801: 
                    802:   // Set exitcode
                    803:   if (daemon_winsvc_exitcode) {
                    804:     svc_status.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
                    805:     svc_status.dwServiceSpecificExitCode = daemon_winsvc_exitcode;
                    806:   }
                    807:   // Report stopped
                    808:   service_report_status(SERVICE_STOPPED, 0);
1.1       misho     809: }
                    810: 
                    811: 
                    812: // Variables for passing main(argc, argv) from daemon_main to service_main()
                    813: static int (*svc_main_func)(int, char **);
                    814: static int svc_main_argc;
                    815: static char ** svc_main_argv;
                    816: 
                    817: // Main function for service, called by service dispatcher
                    818: 
1.1.1.2   misho     819: static void WINAPI service_main(DWORD /*argc*/, LPSTR * argv)
1.1       misho     820: {
1.1.1.2   misho     821:   char path[MAX_PATH], *p;
1.1       misho     822: 
1.1.1.2   misho     823:   // Register control handler
                    824:   svc_handle = RegisterServiceCtrlHandler(argv[0], service_control);
1.1       misho     825: 
1.1.1.2   misho     826:   // Init service status
                    827:   svc_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
                    828:   service_report_status(SERVICE_START_PENDING, 10);
1.1       misho     829: 
1.1.1.2   misho     830:   // Service started in \windows\system32, change to .exe directory
                    831:   if (GetModuleFileNameA(NULL, path, sizeof(path)) && (p = strrchr(path, '\\'))) {
                    832:     *p = 0; SetCurrentDirectoryA(path);
                    833:   }
1.1       misho     834: 
1.1.1.2   misho     835:   // Install exit handler
                    836:   atexit(service_exit);
                    837: 
                    838:   // Do the real work, service status later updated by daemon_detach()
                    839:   daemon_winsvc_exitcode = svc_main_func(svc_main_argc, svc_main_argv);
                    840: 
                    841:   exit(daemon_winsvc_exitcode);
                    842:   // ... continued in service_exit()
1.1       misho     843: }
                    844: 
                    845: 
                    846: /////////////////////////////////////////////////////////////////////////////
                    847: // Windows Service Admin Functions
                    848: 
                    849: 
1.1.1.2   misho     850: // Make registry key name for event message file
                    851: static bool make_evtkey(char * buf, unsigned size, const char * ident)
1.1       misho     852: {
1.1.1.2   misho     853:   static const char prefix[] = "SYSTEM\\CurrentControlSet\\Services\\Eventlog\\Application\\";
                    854:   const unsigned pfxlen = sizeof(prefix)-1;
                    855:   unsigned idlen = strlen(ident);
                    856:   if (pfxlen + idlen >= size) {
                    857:     printf(" Buffer overflow\n");
                    858:     return false;
                    859:   }
                    860:   memcpy(buf, prefix, pfxlen);
                    861:   memcpy(buf+pfxlen, ident, idlen+1);
                    862:   return true;
                    863: }
                    864: 
                    865: // Install this exe as event message file
                    866: static void inst_evtmsg(const char * ident)
                    867: {
                    868:   printf("Installing event message file for %s:", ident); fflush(stdout);
                    869: 
                    870:   char mypath[MAX_PATH];
                    871:   if (!GetModuleFileNameA((HMODULE)0, mypath, sizeof(mypath))) {
                    872:     printf(" unknown program path, Error=%ld\n", GetLastError());
                    873:     return;
                    874:   }
                    875: 
                    876:   char subkey[MAX_PATH];
                    877:   if (!make_evtkey(subkey, sizeof(subkey), ident))
                    878:     return;
                    879: 
                    880:   HKEY hk;
                    881:   LONG err = RegCreateKeyExA(HKEY_LOCAL_MACHINE, subkey, 0, (char *)0, 0, KEY_ALL_ACCESS,
                    882:                              (SECURITY_ATTRIBUTES *)0, &hk, (DWORD *)0);
                    883:   if (err != ERROR_SUCCESS) {
                    884:     printf(" RegCreateKeyEx failed, error=%ld\n", err);
                    885:     return;
                    886:   }
                    887: 
                    888:   err = RegSetValueExA(hk, "EventMessageFile", 0, REG_SZ,
                    889:                        (const BYTE *)mypath, strlen(mypath)+1);
                    890:   if (err == ERROR_SUCCESS) {
                    891:     DWORD val = EVENTLOG_INFORMATION_TYPE
                    892:                |EVENTLOG_WARNING_TYPE
                    893:                |EVENTLOG_ERROR_TYPE;
                    894:     err = RegSetValueExA(hk, "TypesSupported", 0, REG_DWORD,
                    895:                          (const BYTE *)&val, sizeof(val));
                    896:   }
                    897:   if (err != ERROR_SUCCESS)
                    898:     printf(" RegSetValueEx failed, error=%ld\n", err);
                    899: 
                    900:   RegCloseKey(hk);
                    901:   puts(" done");
                    902: }
                    903: 
                    904: // Uninstall event message file
                    905: static void uninst_evtmsg(const char * ident)
                    906: {
                    907:   printf("Removing event message file for %s:", ident); fflush(stdout);
                    908: 
                    909:   char subkey[MAX_PATH];
                    910:   if (!make_evtkey(subkey, sizeof(subkey), ident))
                    911:     return;
                    912: 
                    913:   LONG err = RegDeleteKeyA(HKEY_LOCAL_MACHINE, subkey);
                    914:   if (err != ERROR_SUCCESS && err != ERROR_FILE_NOT_FOUND) {
                    915:     printf(" RegDeleteKey failed, error=%ld\n", err);
                    916:     return;
                    917:   }
                    918:   puts(" done");
1.1       misho     919: }
                    920: 
                    921: 
                    922: // Service install/remove commands
                    923: 
                    924: static int svcadm_main(const char * ident, const daemon_winsvc_options * svc_opts,
                    925:                        int argc, char **argv                                      )
                    926: {
1.1.1.2   misho     927:   int remove; long err;
                    928:   SC_HANDLE hm, hs;
                    929: 
                    930:   if (argc < 2)
                    931:     return -1;
                    932:   if (!strcmp(argv[1], "install"))
                    933:     remove = 0;
                    934:   else if (!strcmp(argv[1], "remove")) {
                    935:     if (argc != 2) {
                    936:       printf("%s: no arguments allowed for command remove\n", ident);
                    937:       return 1;
                    938:     }
                    939:     remove = 1;
                    940:   }
                    941:   else
                    942:     return -1;
                    943: 
                    944:   printf("%s service %s:", (!remove?"Installing":"Removing"), ident); fflush(stdout);
                    945: 
                    946:   // Open SCM
                    947:   if (!(hm = OpenSCManager(NULL/*local*/, NULL/*default*/, SC_MANAGER_ALL_ACCESS))) {
                    948:     if ((err = GetLastError()) == ERROR_ACCESS_DENIED)
                    949:       puts(" access to SCManager denied");
                    950:     else
                    951:       printf(" cannot open SCManager, Error=%ld\n", err);
                    952:     return 1;
                    953:   }
                    954: 
                    955:   if (!remove) {
                    956:     char path[MAX_PATH+100];
                    957:     int i;
                    958:     // Get program path
                    959:     if (!GetModuleFileNameA(NULL, path, MAX_PATH)) {
                    960:       printf(" unknown program path, Error=%ld\n", GetLastError());
                    961:       CloseServiceHandle(hm);
                    962:       return 1;
                    963:     }
                    964:     // Add quotes if necessary
                    965:     if (strchr(path, ' ')) {
                    966:       i = strlen(path);
                    967:       path[i+1] = '"'; path[i+2] = 0;
                    968:       while (--i >= 0)
                    969:         path[i+1] = path[i];
                    970:       path[0] = '"';
                    971:     }
                    972:     // Append options
                    973:     strcat(path, " "); strcat(path, svc_opts->cmd_opt);
                    974:     for (i = 2; i < argc; i++) {
                    975:       const char * s = argv[i];
                    976:       if (strlen(path)+1+1+strlen(s)+1 >= sizeof(path))
                    977:         break;
                    978:       // Add quotes if necessary
                    979:       if (strchr(s, ' ') && !strchr(s, '"')) {
                    980:         strcat(path, " \""); strcat(path, s); strcat(path, "\"");
                    981:       }
                    982:       else {
                    983:         strcat(path, " "); strcat(path, s);
                    984:       }
                    985:     }
                    986:     // Create
                    987:     if (!(hs = CreateService(hm,
                    988:       svc_opts->svcname, svc_opts->dispname,
                    989:       SERVICE_ALL_ACCESS,
1.1.1.3 ! misho     990:       SERVICE_WIN32_OWN_PROCESS,
1.1.1.2   misho     991:       SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, path,
                    992:       NULL/*no load ordering*/, NULL/*no tag id*/,
                    993:       ""/*no depedencies*/, NULL/*local system account*/, NULL/*no pw*/))) {
                    994:       if ((err = GetLastError()) == ERROR_SERVICE_EXISTS)
                    995:         puts(" the service is already installed");
                    996:       else if (err == ERROR_SERVICE_MARKED_FOR_DELETE)
                    997:         puts(" service is still running and marked for deletion\n"
                    998:              "Stop the service and retry install");
                    999:       else
                   1000:         printf(" failed, Error=%ld\n", err);
                   1001:       CloseServiceHandle(hm);
                   1002:       return 1;
                   1003:     }
                   1004:     // Set optional description
                   1005:     if (svc_opts->descript) {
                   1006:       SERVICE_DESCRIPTIONA sd = { const_cast<char *>(svc_opts->descript) };
                   1007:       ChangeServiceConfig2A(hs, SERVICE_CONFIG_DESCRIPTION, &sd);
                   1008:     }
                   1009:     // Enable delayed auto start if supported
                   1010:     OSVERSIONINFOA ver; ver.dwOSVersionInfoSize = sizeof(ver);
                   1011:     if (   GetVersionExA(&ver)
                   1012:         && ver.dwPlatformId == VER_PLATFORM_WIN32_NT
                   1013:         && ver.dwMajorVersion >= 6 /* Vista */      ) {
                   1014:       SERVICE_DELAYED_AUTO_START_INFO sdasi = { TRUE };
                   1015:       ChangeServiceConfig2A(hs, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, &sdasi);
                   1016:     }
                   1017:   }
                   1018:   else {
                   1019:     // Open
                   1020:     if (!(hs = OpenService(hm, svc_opts->svcname, SERVICE_ALL_ACCESS))) {
                   1021:       puts(" not found");
                   1022:       CloseServiceHandle(hm);
                   1023:       return 1;
                   1024:     }
                   1025:     // TODO: Stop service if running
                   1026:     // Remove
                   1027:     if (!DeleteService(hs)) {
                   1028:       if ((err = GetLastError()) == ERROR_SERVICE_MARKED_FOR_DELETE)
                   1029:         puts(" service is still running and marked for deletion\n"
                   1030:              "Stop the service to remove it");
                   1031:       else
                   1032:         printf(" failed, Error=%ld\n", err);
                   1033:       CloseServiceHandle(hs); CloseServiceHandle(hm);
                   1034:       return 1;
                   1035:     }
                   1036:   }
                   1037:   puts(" done");
                   1038:   CloseServiceHandle(hs); CloseServiceHandle(hm);
                   1039: 
                   1040:   // Install/Remove event message file registry entry
                   1041:   if (!remove) {
                   1042:     inst_evtmsg(ident);
                   1043:   }
                   1044:   else {
                   1045:     uninst_evtmsg(ident);
                   1046:   }
1.1       misho    1047: 
1.1.1.2   misho    1048:   return 0;
1.1       misho    1049: }
                   1050: 
                   1051: 
                   1052: /////////////////////////////////////////////////////////////////////////////
                   1053: // Main Function
                   1054: 
                   1055: // This function must be called from main()
                   1056: // main_func is the function doing the real work
                   1057: 
                   1058: int daemon_main(const char * ident, const daemon_winsvc_options * svc_opts,
                   1059:                 int (*main_func)(int, char **), int argc, char **argv      )
                   1060: {
1.1.1.2   misho    1061:   int rc;
1.1       misho    1062: #ifdef _DEBUG
1.1.1.2   misho    1063:   // Enable Debug heap checks
                   1064:   _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)
                   1065:     |_CRTDBG_ALLOC_MEM_DF|_CRTDBG_CHECK_ALWAYS_DF|_CRTDBG_LEAK_CHECK_DF);
1.1       misho    1066: #endif
                   1067: 
1.1.1.2   misho    1068:   // Check for [status|stop|reload|restart|sigusr1|sigusr2] parameters
                   1069:   if ((rc = initd_main(ident, argc, argv)) >= 0)
                   1070:     return rc;
                   1071:   // Check for [install|remove] parameters
                   1072:   if (svc_opts && (rc = svcadm_main(ident, svc_opts, argc, argv)) >= 0)
                   1073:     return rc;
                   1074: 
                   1075:   // Run as service if svc_opts.cmd_opt is given as first(!) argument
                   1076:   svc_mode = (svc_opts && argc >= 2 && !strcmp(argv[1], svc_opts->cmd_opt));
                   1077: 
                   1078:   if (!svc_mode) {
                   1079:     // Daemon: Try to simulate a Unix-like daemon
                   1080:     HANDLE rev;
                   1081:     BOOL exists;
                   1082: 
                   1083:     // Create main event to detect process type:
                   1084:     // 1. new: parent process => start child and wait for detach() or exit() of child.
                   1085:     // 2. exists && signaled: child process => do the real work, signal detach() to parent
                   1086:     // 3. exists && !signaled: already running => exit()
                   1087:     if (!(rev = create_event(EVT_RUNNING, TRUE/*signaled*/, TRUE, &exists)))
                   1088:       return 100;
                   1089: 
                   1090:     if (!exists && !debugging()) {
                   1091:       // Event new => parent process
                   1092:       return parent_main(rev);
                   1093:     }
                   1094: 
                   1095:     if (WaitForSingleObject(rev, 0) == WAIT_OBJECT_0) {
                   1096:       // Event was signaled => In child process
                   1097:       return child_main(rev, main_func, argc, argv);
                   1098:     }
                   1099: 
                   1100:     // Event no longer signaled => Already running!
                   1101:     daemon_help(stdout, ident, "already running");
                   1102:     CloseHandle(rev);
                   1103:     return 1;
                   1104:   }
                   1105:   else {
                   1106:     // Service: Start service_main() via SCM
                   1107:     SERVICE_TABLE_ENTRY service_table[] = {
                   1108:       { (char*)svc_opts->svcname, service_main }, { NULL, NULL }
                   1109:     };
                   1110: 
                   1111:     svc_main_func = main_func;
                   1112:     svc_main_argc = argc;
                   1113:     svc_main_argv = argv;
                   1114:     if (!StartServiceCtrlDispatcher(service_table)) {
                   1115:       printf("%s: cannot dispatch service, Error=%ld\n"
                   1116:         "Option \"%s\" cannot be used to start %s as a service from console.\n"
                   1117:         "Use \"%s install ...\" to install the service\n"
                   1118:         "and \"net start %s\" to start it.\n",
                   1119:         ident, GetLastError(), svc_opts->cmd_opt, ident, ident, ident);
1.1       misho    1120: 
                   1121: #ifdef _DEBUG
1.1.1.2   misho    1122:       if (debugging())
                   1123:         service_main(argc, argv);
1.1       misho    1124: #endif
1.1.1.2   misho    1125:       return 100;
                   1126:     }
                   1127:     Sleep(1000);
                   1128:     ExitThread(0); // Do not redo exit() processing
                   1129:     /*NOTREACHED*/
                   1130:     return 0;
                   1131:   }
1.1       misho    1132: }
                   1133: 
                   1134: 
                   1135: /////////////////////////////////////////////////////////////////////////////
                   1136: // Test Program
                   1137: 
                   1138: #ifdef TEST
                   1139: 
                   1140: static volatile sig_atomic_t caughtsig = 0;
                   1141: 
                   1142: static void sig_handler(int sig)
                   1143: {
1.1.1.2   misho    1144:   caughtsig = sig;
1.1       misho    1145: }
                   1146: 
                   1147: static void test_exit(void)
                   1148: {
1.1.1.2   misho    1149:   printf("Main exit\n");
1.1       misho    1150: }
                   1151: 
                   1152: int test_main(int argc, char **argv)
                   1153: {
1.1.1.2   misho    1154:   int i;
                   1155:   int debug = 0;
                   1156:   char * cmd = 0;
                   1157: 
                   1158:   printf("PID=%ld\n", GetCurrentProcessId());
                   1159:   for (i = 0; i < argc; i++) {
                   1160:     printf("%d: \"%s\"\n", i, argv[i]);
                   1161:     if (!strcmp(argv[i],"-d"))
                   1162:       debug = 1;
                   1163:   }
                   1164:   if (argc > 1 && argv[argc-1][0] != '-')
                   1165:     cmd = argv[argc-1];
                   1166: 
                   1167:   daemon_signal(SIGINT, sig_handler);
                   1168:   daemon_signal(SIGBREAK, sig_handler);
                   1169:   daemon_signal(SIGTERM, sig_handler);
                   1170:   daemon_signal(SIGHUP, sig_handler);
                   1171:   daemon_signal(SIGUSR1, sig_handler);
                   1172:   daemon_signal(SIGUSR2, sig_handler);
                   1173: 
                   1174:   atexit(test_exit);
                   1175: 
                   1176:   if (!debug) {
                   1177:     printf("Preparing to detach...\n");
                   1178:     Sleep(2000);
                   1179:     daemon_detach("test");
                   1180:     printf("Detached!\n");
                   1181:   }
                   1182: 
                   1183:   for (;;) {
                   1184:     daemon_sleep(1);
                   1185:     printf("."); fflush(stdout);
                   1186:     if (caughtsig) {
                   1187:       if (caughtsig == SIGUSR2) {
                   1188:         debug ^= 1;
                   1189:         if (debug)
                   1190:           daemon_enable_console("Daemon[Debug]");
                   1191:         else
                   1192:           daemon_disable_console();
                   1193:       }
                   1194:       else if (caughtsig == SIGUSR1 && cmd) {
                   1195:         char inpbuf[200], outbuf[1000]; int rc;
                   1196:         strcpy(inpbuf, "Hello\nWorld!\n");
                   1197:         rc = daemon_spawn(cmd, inpbuf, strlen(inpbuf), outbuf, sizeof(outbuf));
                   1198:         if (!debug)
                   1199:           daemon_enable_console("Command output");
                   1200:         printf("\"%s\" returns %d\n", cmd, rc);
                   1201:         if (rc >= 0)
                   1202:           printf("output:\n%s.\n", outbuf);
                   1203:         fflush(stdout);
                   1204:         if (!debug) {
                   1205:           Sleep(10000); daemon_disable_console();
                   1206:         }
                   1207:       }
                   1208:       printf("[PID=%ld: Signal=%d]", GetCurrentProcessId(), caughtsig); fflush(stdout);
                   1209:       if (caughtsig == SIGTERM || caughtsig == SIGBREAK)
                   1210:         break;
                   1211:       caughtsig = 0;
                   1212:     }
                   1213:   }
                   1214:   printf("\nExiting on signal %d\n", caughtsig);
                   1215:   return 0;
1.1       misho    1216: }
                   1217: 
                   1218: 
                   1219: int main(int argc, char **argv)
                   1220: {
1.1.1.2   misho    1221:   static const daemon_winsvc_options svc_opts = {
                   1222:   "-s", "test", "Test Service", "Service to test daemon_win32.c Module"
                   1223:   };
1.1       misho    1224: 
1.1.1.2   misho    1225:   return daemon_main("testd", &svc_opts, test_main, argc, argv);
1.1       misho    1226: }
                   1227: 
                   1228: #endif

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