📄 daemon_win32.cpp
字号:
SetConsoleCtrlHandler(child_console_handler, TRUE/*add*/); if (!ok) return -1; if (title) SetConsoleTitleA(title); if (reopen_stdin) freopen("conin$", "r", stdin); if (reopen_stdout) freopen("conout$", "w", stdout); if (reopen_stderr) freopen("conout$", "w", stderr); reopen_stdin = reopen_stdout = reopen_stderr = 0; return 0;}// Detach daemon from console & parentint daemon_detach(const char * ident){ if (!svc_mode) { if (ident) { // Print help FILE * f = ( isatty(fileno(stdout)) ? stdout : isatty(fileno(stderr)) ? stderr : NULL); if (f) daemon_help(f, ident, "now detaches from console into background mode"); } // Signal detach to parent if (sig_event(EVT_DETACHED) != 1) { if (!debugging()) return -1; } daemon_disable_console(); } else { // Signal end of initialization to service control manager service_report_status(SERVICE_RUNNING, 0); reopen_stdin = reopen_stdout = reopen_stderr = 1; } return 0;}/////////////////////////////////////////////////////////////////////////////// MessageBox#ifndef _MT//MT runtime not necessary, because mbox_thread uses no unsafe lib functions//#error Program must be linked with multithreaded runtime library#endifstatic LONG mbox_count; // # mbox_thread()sstatic HANDLE mbox_mutex; // Show 1 box at a time (not necessary for service)typedef struct mbox_args_s { HANDLE taken; const char * title, * text; int mode;} mbox_args;// Thread to display one message boxstatic ULONG WINAPI mbox_thread(LPVOID arg){ // Take args mbox_args * mb = (mbox_args *)arg; char title[100]; char text[1000]; int mode; strncpy(title, mb->title, sizeof(title)-1); title[sizeof(title)-1] = 0; strncpy(text , mb->text , sizeof(text )-1); text [sizeof(text )-1] = 0; mode = mb->mode; SetEvent(mb->taken); // Show only one box at a time WaitForSingleObject(mbox_mutex, INFINITE); MessageBoxA(NULL, text, title, mode); ReleaseMutex(mbox_mutex); InterlockedDecrement(&mbox_count); return 0;}// Display a message boxint daemon_messagebox(int system, const char * title, const char * text){ mbox_args mb; HANDLE ht; DWORD tid; // Create mutex during first call if (!mbox_mutex) mbox_mutex = CreateMutex(NULL/*!inherit*/, FALSE/*!owned*/, NULL/*unnamed*/); // Allow at most 10 threads if (InterlockedIncrement(&mbox_count) > 10) { InterlockedDecrement(&mbox_count); return -1; } // Create thread mb.taken = CreateEvent(NULL/*!inherit*/, FALSE, FALSE/*!signaled*/, NULL/*unnamed*/); mb.mode = MB_OK|MB_ICONWARNING |(svc_mode?MB_SERVICE_NOTIFICATION:0) |(system?MB_SYSTEMMODAL:MB_APPLMODAL); mb.title = title; mb.text = text; mb.text = text; if (!(ht = CreateThread(NULL, 0, mbox_thread, &mb, 0, &tid))) return -1; // Wait for args taken if (WaitForSingleObject(mb.taken, 10000) != WAIT_OBJECT_0) TerminateThread(ht, 0); CloseHandle(mb.taken); CloseHandle(ht); return 0;}/////////////////////////////////////////////////////////////////////////////// Spawn a command and redirect <inpbuf >outbuf// return command's exitcode or -1 on errorint daemon_spawn(const char * cmd, const char * inpbuf, int inpsize, char * outbuf, int outsize ){ HANDLE pipe_inp_r, pipe_inp_w, pipe_out_r, pipe_out_w, pipe_err_w, h; char temp_path[MAX_PATH]; DWORD flags, num_io, exitcode; int use_file, state, i; SECURITY_ATTRIBUTES sa; STARTUPINFO si; PROCESS_INFORMATION pi; HANDLE self = GetCurrentProcess(); if (GetVersion() & 0x80000000L) { // Win9x/ME: A calling process never receives EOF if output of COMMAND.COM or // any other DOS program is redirected via a pipe. Using a temp file instead. use_file = 1; flags = DETACHED_PROCESS; } else { // NT4/2000/XP: If DETACHED_PROCESS is used, CMD.EXE opens a new console window // for each external command in a redirected .BAT file. // Even (DETACHED_PROCESS|CREATE_NO_WINDOW) does not work. use_file = 0; flags = CREATE_NO_WINDOW; } // Create stdin pipe with inheritable read side memset(&sa, 0, sizeof(sa)); sa.nLength = sizeof(sa); sa.bInheritHandle = TRUE; if (!CreatePipe(&pipe_inp_r, &h, &sa/*inherit*/, inpsize*2+13)) return -1; if (!DuplicateHandle(self, h, self, &pipe_inp_w, 0, FALSE/*!inherit*/, DUPLICATE_SAME_ACCESS|DUPLICATE_CLOSE_SOURCE)) { CloseHandle(pipe_inp_r); return -1; } memset(&sa, 0, sizeof(sa)); sa.nLength = sizeof(sa); sa.bInheritHandle = TRUE; if (!use_file) { // Create stdout pipe with inheritable write side if (!CreatePipe(&h, &pipe_out_w, &sa/*inherit*/, outsize)) { CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w); return -1; } } else { // Create temp file with inheritable write handle char temp_dir[MAX_PATH]; if (!GetTempPathA(sizeof(temp_dir), temp_dir)) strcpy(temp_dir, "."); if (!GetTempFileNameA(temp_dir, "out"/*prefix*/, 0/*create unique*/, temp_path)) { CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w); return -1; } if ((h = CreateFileA(temp_path, GENERIC_READ|GENERIC_WRITE, 0/*no sharing*/, &sa/*inherit*/, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) { CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w); return -1; } if (!DuplicateHandle(self, h, self, &pipe_out_w, GENERIC_WRITE, TRUE/*inherit*/, 0)) { CloseHandle(h); CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w); return -1; } } if (!DuplicateHandle(self, h, self, &pipe_out_r, GENERIC_READ, FALSE/*!inherit*/, DUPLICATE_CLOSE_SOURCE)) { CloseHandle(pipe_out_w); CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w); return -1; } // Create stderr handle as dup of stdout write side if (!DuplicateHandle(self, pipe_out_w, self, &pipe_err_w, 0, TRUE/*inherit*/, DUPLICATE_SAME_ACCESS)) { CloseHandle(pipe_out_r); CloseHandle(pipe_out_w); CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w); return -1; } // Create process with pipes/file as stdio memset(&si, 0, sizeof(si)); si.cb = sizeof(si); si.hStdInput = pipe_inp_r; si.hStdOutput = pipe_out_w; si.hStdError = pipe_err_w; si.dwFlags = STARTF_USESTDHANDLES; if (!CreateProcessA( NULL, (char*)cmd, NULL, NULL, TRUE/*inherit*/, flags/*DETACHED_PROCESS or CREATE_NO_WINDOW*/, NULL, NULL, &si, &pi)) { CloseHandle(pipe_err_w); CloseHandle(pipe_out_r); CloseHandle(pipe_out_w); CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w); return -1; } CloseHandle(pi.hThread); // Close inherited handles CloseHandle(pipe_inp_r); CloseHandle(pipe_out_w); CloseHandle(pipe_err_w); // Copy inpbuf to stdin // convert \n => \r\n for (i = 0; i < inpsize; ) { int len = 0; while (i+len < inpsize && inpbuf[i+len] != '\n') len++; if (len > 0) WriteFile(pipe_inp_w, inpbuf+i, len, &num_io, NULL); i += len; if (i < inpsize) { WriteFile(pipe_inp_w, "\r\n", 2, &num_io, NULL); i++; } } CloseHandle(pipe_inp_w); exitcode = 42; for (state = 0; state < 2; state++) { // stdout pipe: read pipe first // stdout file: wait for process first if (state == use_file) { // Copy stdout to output buffer until full, rest to /dev/null // convert \r\n => \n if (use_file) SetFilePointer(pipe_out_r, 0, NULL, FILE_BEGIN); for (i = 0; ; ) { char buf[256]; int j; if (!ReadFile(pipe_out_r, buf, sizeof(buf), &num_io, NULL) || num_io == 0) break; for (j = 0; i < outsize-1 && j < (int)num_io; j++) { if (buf[j] != '\r') outbuf[i++] = buf[j]; } } outbuf[i] = 0; CloseHandle(pipe_out_r); if (use_file) DeleteFileA(temp_path); } else { // Wait for process exitcode WaitForSingleObject(pi.hProcess, INFINITE); GetExitCodeProcess(pi.hProcess, &exitcode); CloseHandle(pi.hProcess); } } return exitcode;}/////////////////////////////////////////////////////////////////////////////// Initd Functionsstatic int wait_signaled(HANDLE h, int seconds){ int i; for (i = 0; ; ) { if (WaitForSingleObject(h, 1000L) == WAIT_OBJECT_0) return 0; if (++i >= seconds) return -1; fputchar('.'); fflush(stdout); }}static int wait_evt_running(int seconds, int exists){ int i; if (event_exists(EVT_RUNNING) == exists) return 0; for (i = 0; ; ) { Sleep(1000); if (event_exists(EVT_RUNNING) == exists) return 0; if (++i >= seconds) return -1; fputchar('.'); fflush(stdout); }}static int is_initd_command(char * s){ if (!strcmp(s, "status")) return EVT_RUNNING; if (!strcmp(s, "stop")) return SIGTERM; if (!strcmp(s, "reload")) return SIGHUP; if (!strcmp(s, "sigusr1")) return SIGUSR1; if (!strcmp(s, "sigusr2")) return SIGUSR2; if (!strcmp(s, "restart")) return EVT_RESTART; return -1;}static int initd_main(const char * ident, int argc, char **argv){ int rc; if (argc < 2) return -1; if ((rc = is_initd_command(argv[1])) < 0) return -1; if (argc != 2) { printf("%s: no arguments allowed for command %s\n", ident, argv[1]); return 1; } switch (rc) { default: case EVT_RUNNING: printf("Checking for %s:", ident); fflush(stdout); rc = event_exists(EVT_RUNNING); puts(rc ? " running" : " not running"); return (rc ? 0 : 1); case SIGTERM: printf("Stopping %s:", ident); fflush(stdout); rc = sig_event(SIGTERM); if (rc <= 0) { puts(rc < 0 ? " not running" : " error"); return (rc < 0 ? 0 : 1); } rc = wait_evt_running(10, 0); puts(!rc ? " done" : " timeout"); return (!rc ? 0 : 1); case SIGHUP: printf("Reloading %s:", ident); fflush(stdout); rc = sig_event(SIGHUP); puts(rc > 0 ? " done" : rc == 0 ? " error" : " not running"); return (rc > 0 ? 0 : 1); case SIGUSR1: case SIGUSR2: printf("Sending SIGUSR%d to %s:", (rc-SIGUSR1+1), ident); fflush(stdout); rc = sig_event(rc); puts(rc > 0 ? " done" : rc == 0 ? " error" : " not running"); return (rc > 0 ? 0 : 1); case EVT_RESTART: { HANDLE rst; printf("Stopping %s:", ident); fflush(stdout); if (event_exists(EVT_DETACHED)) { puts(" not detached, cannot restart"); return 1; } if (!(rst = create_event(EVT_RESTART, FALSE, FALSE, NULL))) { puts(" error"); return 1; } rc = sig_event(SIGTERM); if (rc <= 0) { puts(rc < 0 ? " not running" : " error"); CloseHandle(rst); return 1; } rc = wait_signaled(rst, 10); CloseHandle(rst); if (rc) { puts(" timeout"); return 1; } puts(" done"); Sleep(100); printf("Starting %s:", ident); fflush(stdout); rc = wait_evt_running(10, 1); puts(!rc ? " done" : " error"); return (!rc ? 0 : 1); } }}/////////////////////////////////////////////////////////////////////////////// Windows Service Functionsint daemon_winsvc_exitcode; // Set by app to exit(code)static SERVICE_STATUS_HANDLE svc_handle;static SERVICE_STATUS svc_status;// Report status to SCMstatic void service_report_status(int state, int seconds){ // TODO: Avoid race static DWORD checkpoint = 1; static DWORD accept_more = SERVICE_ACCEPT_PARAMCHANGE; // Win2000/XP svc_status.dwCurrentState = state; svc_status.dwWaitHint = seconds*1000;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -