📄 daemon_win32.cpp
字号:
/* * os_win32/daemon_win32.cpp * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2004-8 Christian Franke <smartmontools-support@lists.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */#include <stdio.h>#include <stdlib.h>#include <signal.h>#include <io.h>#define WIN32_LEAN_AND_MEAN// Need MB_SERVICE_NOTIFICATION (NT4/2000/XP), IsDebuggerPresent() (Win98/ME/NT4/2000/XP)#define _WIN32_WINNT 0x0400 #include <windows.h>#ifdef _DEBUG#include <crtdbg.h>#endif#include "daemon_win32.h"const char *daemon_win32_c_cvsid = "$Id: daemon_win32.cpp,v 1.12 2008/03/04 22:09:48 ballen4705 Exp $"DAEMON_WIN32_H_CVSID;/////////////////////////////////////////////////////////////////////////////#define ARGUSED(x) ((void)(x))// Prevent spawning of child process if debugging#ifdef _DEBUG#define debugging() IsDebuggerPresent()#else#define debugging() FALSE#endif#define EVT_NAME_LEN 260// Internal events (must be > SIGUSRn)#define EVT_RUNNING 100 // Exists when running, signaled on creation#define EVT_DETACHED 101 // Signaled when child detaches from console#define EVT_RESTART 102 // Signaled when child should restartstatic void make_name(char * name, int sig){ int i; if (!GetModuleFileNameA(NULL, name, EVT_NAME_LEN-10)) strcpy(name, "DaemonEvent"); for (i = 0; name[i]; i++) { char c = name[i]; if (!( ('0' <= c && c <= '9') || ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'))) name[i] = '_'; } sprintf(name+strlen(name), "-%d", sig);}static HANDLE create_event(int sig, BOOL initial, BOOL errmsg, BOOL * exists){ char name[EVT_NAME_LEN]; HANDLE h; if (sig >= 0) make_name(name, sig); else name[0] = 0; if (exists) *exists = FALSE; if (!(h = CreateEventA(NULL, FALSE, initial, (name[0] ? name : NULL)))) { if (errmsg) fprintf(stderr, "CreateEvent(.,\"%s\"): Error=%ld\n", name, GetLastError()); return 0; } if (GetLastError() == ERROR_ALREADY_EXISTS) { if (!exists) { if (errmsg) fprintf(stderr, "CreateEvent(.,\"%s\"): Exists\n", name); CloseHandle(h); return 0; } *exists = TRUE; } return h;}static HANDLE open_event(int sig){ char name[EVT_NAME_LEN]; make_name(name, sig); return OpenEventA(EVENT_MODIFY_STATE, FALSE, name);}static int event_exists(int sig){ char name[EVT_NAME_LEN]; HANDLE h; make_name(name, sig); if (!(h = OpenEventA(EVENT_MODIFY_STATE, FALSE, name))) return 0; CloseHandle(h); return 1;}static int sig_event(int sig){ char name[EVT_NAME_LEN]; HANDLE h; make_name(name, sig); if (!(h = OpenEventA(EVENT_MODIFY_STATE, FALSE, name))) { make_name(name, EVT_RUNNING); if (!(h = OpenEvent(EVENT_MODIFY_STATE, FALSE, name))) return -1; CloseHandle(h); return 0; } SetEvent(h); CloseHandle(h); return 1;}static void daemon_help(FILE * f, const char * ident, const char * message){ fprintf(f, "%s: %s.\n" "Use \"%s status|stop|reload|restart|sigusr1|sigusr2\" to control daemon.\n", ident, message, ident); fflush(f);}/////////////////////////////////////////////////////////////////////////////// Parent Processstatic BOOL WINAPI parent_console_handler(DWORD event){ switch (event) { case CTRL_C_EVENT: case CTRL_BREAK_EVENT: return TRUE; // Ignore } return FALSE; // continue with next handler ...}static int parent_main(HANDLE rev){ HANDLE dev; HANDLE ht[2]; char * cmdline; STARTUPINFO si; PROCESS_INFORMATION pi; DWORD rc, exitcode; // Ignore ^C, ^BREAK in parent SetConsoleCtrlHandler(parent_console_handler, TRUE/*add*/); // Create event used by child to signal daemon_detach() if (!(dev = create_event(EVT_DETACHED, FALSE/*not signaled*/, TRUE, NULL/*must not exist*/))) { CloseHandle(rev); return 101; } // Restart process with same args cmdline = GetCommandLineA(); memset(&si, 0, sizeof(si)); si.cb = sizeof(si); if (!CreateProcessA( NULL, cmdline, NULL, NULL, TRUE/*inherit*/, 0, NULL, NULL, &si, &pi)) { fprintf(stderr, "CreateProcess(.,\"%s\",.) failed, Error=%ld\n", cmdline, GetLastError()); CloseHandle(rev); CloseHandle(dev); return 101; } CloseHandle(pi.hThread); // Wait for daemon_detach() or exit() ht[0] = dev; ht[1] = pi.hProcess; rc = WaitForMultipleObjects(2, ht, FALSE/*or*/, INFINITE); if (!(/*WAIT_OBJECT_0(0) <= rc && */ rc < WAIT_OBJECT_0+2)) { fprintf(stderr, "WaitForMultipleObjects returns %lX\n", rc); TerminateProcess(pi.hProcess, 200); } CloseHandle(rev); CloseHandle(dev); // Get exit code if (!GetExitCodeProcess(pi.hProcess, &exitcode)) exitcode = 201; else if (exitcode == STILL_ACTIVE) // detach()ed, assume OK exitcode = 0; CloseHandle(pi.hProcess); return exitcode;}/////////////////////////////////////////////////////////////////////////////// Child Processstatic int svc_mode; // Running as service?static int svc_paused; // Service paused?static void service_report_status(int state, int waithint);// Tables of signal handler and corresponding eventstypedef void (*sigfunc_t)(int);#define MAX_SIG_HANDLERS 8static int num_sig_handlers = 0;static sigfunc_t sig_handlers[MAX_SIG_HANDLERS];static int sig_numbers[MAX_SIG_HANDLERS];static HANDLE sig_events[MAX_SIG_HANDLERS];static HANDLE sighup_handle, sigint_handle, sigbreak_handle;static HANDLE sigterm_handle, sigusr1_handle;static HANDLE running_event;static int reopen_stdin, reopen_stdout, reopen_stderr;// Handler for windows console eventsstatic BOOL WINAPI child_console_handler(DWORD event){ // Caution: runs in a new thread // TODO: Guard with a mutex HANDLE h = 0; switch (event) { case CTRL_C_EVENT: // <CONTROL-C> (SIGINT) h = sigint_handle; break; case CTRL_BREAK_EVENT: // <CONTROL-Break> (SIGBREAK/SIGQUIT) case CTRL_CLOSE_EVENT: // User closed console or abort via task manager h = sigbreak_handle; break; case CTRL_LOGOFF_EVENT: // Logout/Shutdown (SIGTERM) case CTRL_SHUTDOWN_EVENT: h = sigterm_handle; break; } if (!h) return FALSE; // continue with next handler // Signal event if (!SetEvent(h)) return FALSE; return TRUE;}static void child_exit(void){ int i; char * cmdline; HANDLE rst; STARTUPINFO si; PROCESS_INFORMATION pi; for (i = 0; i < num_sig_handlers; i++) CloseHandle(sig_events[i]); num_sig_handlers = 0; CloseHandle(running_event); running_event = 0; // Restart? if (!(rst = open_event(EVT_RESTART))) return; // No => normal exit // Yes => Signal exit and restart process Sleep(500); SetEvent(rst); CloseHandle(rst); Sleep(500); cmdline = GetCommandLineA(); memset(&si, 0, sizeof(si)); si.cb = sizeof(si); si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; if (!CreateProcessA( NULL, cmdline, NULL, NULL, TRUE/*inherit*/, 0, NULL, NULL, &si, &pi)) { fprintf(stderr, "CreateProcess(.,\"%s\",.) failed, Error=%ld\n", cmdline, GetLastError()); } CloseHandle(pi.hThread); CloseHandle(pi.hProcess);}static int child_main(HANDLE hev,int (*main_func)(int, char **), int argc, char **argv){ // Keep EVT_RUNNING open until exit running_event = hev; // Install console handler SetConsoleCtrlHandler(child_console_handler, TRUE/*add*/); // Install restart handler atexit(child_exit); // Continue in main_func() to do the real work return main_func(argc, argv);}// Simulate signal()sigfunc_t daemon_signal(int sig, sigfunc_t func){ int i; HANDLE h; if (func == SIG_DFL || func == SIG_IGN) return func; // TODO for (i = 0; i < num_sig_handlers; i++) { if (sig_numbers[i] == sig) { sigfunc_t old = sig_handlers[i]; sig_handlers[i] = func; return old; } } if (num_sig_handlers >= MAX_SIG_HANDLERS) return SIG_ERR; if (!(h = create_event((!svc_mode ? sig : -1), FALSE, TRUE, NULL))) return SIG_ERR; sig_events[num_sig_handlers] = h; sig_numbers[num_sig_handlers] = sig; sig_handlers[num_sig_handlers] = func; switch (sig) { case SIGHUP: sighup_handle = h; break; case SIGINT: sigint_handle = h; break; case SIGTERM: sigterm_handle = h; break; case SIGBREAK: sigbreak_handle = h; break; case SIGUSR1: sigusr1_handle = h; break; } num_sig_handlers++; return SIG_DFL;}// strsignal()const char * daemon_strsignal(int sig){ switch (sig) { case SIGHUP: return "SIGHUP"; case SIGINT: return "SIGINT"; case SIGTERM: return "SIGTERM"; case SIGBREAK:return "SIGBREAK"; case SIGUSR1: return "SIGUSR1"; case SIGUSR2: return "SIGUSR2"; default: return "*UNKNOWN*"; }}// Simulate sleep()void daemon_sleep(int seconds){ do { if (num_sig_handlers <= 0) { Sleep(seconds*1000L); } else { // Wait for any signal or timeout DWORD rc = WaitForMultipleObjects(num_sig_handlers, sig_events, FALSE/*OR*/, seconds*1000L); if (rc != WAIT_TIMEOUT) { if (!(/*WAIT_OBJECT_0(0) <= rc && */ rc < WAIT_OBJECT_0+(unsigned)num_sig_handlers)) { fprintf(stderr,"WaitForMultipleObjects returns %lu\n", rc); Sleep(seconds*1000L); return; } // Call Handler sig_handlers[rc-WAIT_OBJECT_0](sig_numbers[rc-WAIT_OBJECT_0]); break; } } } while (svc_paused);}// Disable/Enable consolevoid daemon_disable_console(){ SetConsoleCtrlHandler(child_console_handler, FALSE/*remove*/); reopen_stdin = reopen_stdout = reopen_stderr = 0; if (isatty(fileno(stdin))) { fclose(stdin); reopen_stdin = 1; } if (isatty(fileno(stdout))) { fclose(stdout); reopen_stdout = 1; } if (isatty(fileno(stderr))) { fclose(stderr); reopen_stderr = 1; } FreeConsole(); SetConsoleCtrlHandler(child_console_handler, TRUE/*add*/);}int daemon_enable_console(const char * title){ BOOL ok; SetConsoleCtrlHandler(child_console_handler, FALSE/*remove*/); ok = AllocConsole();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -