Annotation of embedaddon/smartmontools/os_win32/daemon_win32.cpp, revision 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>