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

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

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