/* Initializes 'buffer' with 'n' bytes of high-quality random numbers. Returns * 0 if successful, otherwise a positive errno value or EOF on error. */ int get_entropy(void *buffer, size_t n) { #ifndef _WIN32 size_t bytes_read; int error; int fd; fd = open(urandom, O_RDONLY); if (fd < 0) { VLOG_ERR("%s: open failed (%s)", urandom, ovs_strerror(errno)); return errno ? errno : EINVAL; } error = read_fully(fd, buffer, n, &bytes_read); close(fd); if (error) { VLOG_ERR("%s: read error (%s)", urandom, ovs_retval_to_string(error)); } #else int error = 0; HCRYPTPROV crypt_prov = 0; CryptAcquireContext(&crypt_prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); if (!CryptGenRandom(crypt_prov, n, buffer)) { VLOG_ERR("CryptGenRandom: read error (%s)", ovs_lasterror_to_string()); error = EINVAL; } CryptReleaseContext(crypt_prov, 0); #endif return error; }
/* In case of an unexpected termination, configure the action to be * taken. */ static void set_config_failure_actions() { /* In case of a failure, restart the process the first two times * After 'dwResetPeriod', the failure count is reset. */ SC_ACTION fail_action[3] = { {SC_ACTION_RESTART, 0}, {SC_ACTION_RESTART, 0}, {SC_ACTION_NONE, 0} }; SERVICE_FAILURE_ACTIONS service_fail_action; /* Reset failure count after (in seconds). */ service_fail_action.dwResetPeriod = 10; /* Reboot message. */ service_fail_action.lpRebootMsg = NULL; /* The command line of the process. */ service_fail_action.lpCommand = NULL; /* Number of elements in 'fail_actions'. */ service_fail_action.cActions = sizeof(fail_action)/sizeof(fail_action[0]); /* A pointer to an array of SC_ACTION structures. */ service_fail_action.lpsaActions = fail_action; if (!ChangeServiceConfig2(service, SERVICE_CONFIG_FAILURE_ACTIONS, &service_fail_action)) { char *msg_buf = ovs_lasterror_to_string(); VLOG_FATAL("Failed to configure service fail actions (%s).", msg_buf); } }
/* Check whether 'program_name' has been created as a service. */ static void check_service() { /* Establish a connection to the local service control manager. */ manager = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE); if (!manager) { char *msg_buf = ovs_lasterror_to_string(); VLOG_FATAL("Failed to open the service control manager (%s).", msg_buf); } service = OpenService(manager, program_name, SERVICE_ALL_ACCESS); if (!service) { char *msg_buf = ovs_lasterror_to_string(); VLOG_FATAL("Failed to open service (%s).", msg_buf); } }
int getrusage(int who, struct rusage *usage) { FILETIME creation_time, exit_time, kernel_time, user_time; PROCESS_MEMORY_COUNTERS pmc; memset(usage, 0, sizeof(struct rusage)); if (who == RUSAGE_SELF) { if (!GetProcessTimes(GetCurrentProcess(), &creation_time, &exit_time, &kernel_time, &user_time)) { VLOG_ERR("failed at GetProcessTimes: %s", ovs_lasterror_to_string()); return -1; } if (!GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) { VLOG_ERR("failed at GetProcessMemoryInfo: %s", ovs_lasterror_to_string()); return -1; } usage_to_timeval(&kernel_time, &usage->ru_stime); usage_to_timeval(&user_time, &usage->ru_utime); usage->ru_majflt = pmc.PageFaultCount; usage->ru_maxrss = pmc.PeakWorkingSetSize / 1024; return 0; } else if (who == RUSAGE_THREAD) { if (!GetThreadTimes(GetCurrentThread(), &creation_time, &exit_time, &kernel_time, &user_time)) { VLOG_ERR("failed at GetThreadTimes: %s", ovs_lasterror_to_string()); return -1; } usage_to_timeval(&kernel_time, &usage->ru_stime); usage_to_timeval(&user_time, &usage->ru_utime); return 0; } else { return -1; } }
/* Initializes the fatal signal handling module. Calling this function is * optional, because calling any other function in the module will also * initialize it. However, in a multithreaded program, the module must be * initialized while the process is still single-threaded. */ void fatal_signal_init(void) { static bool inited = false; if (!inited) { size_t i; assert_single_threaded(); inited = true; ovs_mutex_init_recursive(&mutex); #ifndef _WIN32 xpipe_nonblocking(signal_fds); #else wevent = CreateEvent(NULL, TRUE, FALSE, NULL); if (!wevent) { char *msg_buf = ovs_lasterror_to_string(); VLOG_FATAL("Failed to create a event (%s).", msg_buf); } /* Register a function to handle Ctrl+C. */ SetConsoleCtrlHandler(ConsoleHandlerRoutine, true); #endif for (i = 0; i < ARRAY_SIZE(fatal_signals); i++) { int sig_nr = fatal_signals[i]; #ifndef _WIN32 struct sigaction old_sa; xsigaction(sig_nr, NULL, &old_sa); if (old_sa.sa_handler == SIG_DFL && signal(sig_nr, fatal_signal_handler) == SIG_ERR) { VLOG_FATAL("signal failed (%s)", ovs_strerror(errno)); } #else if (signal(sig_nr, fatal_signal_handler) == SIG_ERR) { VLOG_FATAL("signal failed (%s)", ovs_strerror(errno)); } #endif } atexit(fatal_signal_atexit_handler); } }
void daemonize_complete(void) { /* If running as a child because '--detach' option was specified, * communicate with the parent to inform that the child is ready. */ if (detached) { int error; close_standard_fds(); error = WriteFile(write_handle, "a", 1, NULL, NULL); if (!error) { VLOG_FATAL("Failed to communicate with the parent (%s)", ovs_lasterror_to_string()); } } service_complete(); }
/* Registers the call-back and configures the actions in case of a failure * with the Windows services manager. */ void service_start(int *argcp, char **argvp[]) { int argc = *argcp; char **argv = *argvp; int i; SERVICE_TABLE_ENTRY service_table[] = { {(LPTSTR)program_name, (LPSERVICE_MAIN_FUNCTION)main}, {NULL, NULL} }; /* 'detached' is 'false' when service_start() is called the first time. * It is 'true', when it is called the second time by the Windows services * manager. */ if (detached) { init_service_status(); wevent = CreateEvent(NULL, TRUE, FALSE, NULL); if (!wevent) { char *msg_buf = ovs_lasterror_to_string(); VLOG_FATAL("Failed to create a event (%s).", msg_buf); } poll_fd_wait_event(0, wevent, POLLIN); /* Register the control handler. This function is called by the service * manager to stop the service. */ hstatus = RegisterServiceCtrlHandler(program_name, (LPHANDLER_FUNCTION)control_handler); if (!hstatus) { char *msg_buf = ovs_lasterror_to_string(); VLOG_FATAL("Failed to register the service control handler (%s).", msg_buf); } if (monitor) { set_config_failure_actions(); } /* When the service control manager does the call back, it does not * send the same arguments as sent to the main function during the * service start. So, use the arguments passed over during the first * time. */ *argcp = sargc; *argvp = *sargvp; /* XXX: Windows implementation cannot have a unixctl commands in the * traditional sense of unix domain sockets. If an implementation is * done that involves 'unixctl' vlog commands the following call is * needed to make sure that the unixctl commands for vlog get * registered in a daemon, even before the first log message. */ vlog_init(); return; } assert_single_threaded(); /* A reference to arguments passed to the main function the first time. * We need it after the call-back from service control manager. */ sargc = argc; sargvp = argvp; /* We are only interested in the '--service' and '--service-monitor' * options before the call-back from the service control manager. */ for (i = 0; i < argc; i ++) { if (!strcmp(argv[i], "--service")) { detach = true; } else if (!strcmp(argv[i], "--service-monitor")) { monitor = true; } } /* If '--service' is not a command line option, run in foreground. */ if (!detach) { return; } /* If we have been configured to run as a service, then that service * should already have been created either manually or through a start up * script. */ check_service(); detached = true; /* StartServiceCtrlDispatcher blocks and returns after the service is * stopped. */ if (!StartServiceCtrlDispatcher(service_table)) { char *msg_buf = ovs_lasterror_to_string(); VLOG_FATAL("Failed at StartServiceCtrlDispatcher (%s)", msg_buf); } exit(0); }
/* If one of the command line option is "--detach", creates * a new process in case of parent, waits for child to start and exits. * In case of the child, returns. */ static bool detach_process(int argc, char *argv[]) { SECURITY_ATTRIBUTES sa; STARTUPINFO si; PROCESS_INFORMATION pi; HANDLE read_pipe, write_pipe; char *buffer; int error, i; char ch; /* We are only interested in the '--detach' and '--pipe-handle'. */ for (i = 0; i < argc; i ++) { if (!strcmp(argv[i], "--detach")) { detach = true; } else if (!strncmp(argv[i], "--pipe-handle", 13)) { /* If running as a child, return. */ detached = true; return true; } } /* Nothing to do if the option --detach is not set. */ if (!detach) { return false; } /* Set the security attribute such that a process created will * inherit the pipe handles. */ sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; /* Create an anonymous pipe to communicate with the child. */ error = CreatePipe(&read_pipe, &write_pipe, &sa, 0); if (!error) { VLOG_FATAL("CreatePipe failed (%s)", ovs_lasterror_to_string()); } GetStartupInfo(&si); /* To the child, we pass an extra argument '--pipe-handle=write_pipe' */ buffer = xasprintf("%s %s=%ld", GetCommandLine(), "--pipe-handle", write_pipe); /* Create a detached child */ error = CreateProcess(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &si, &pi); if (!error) { VLOG_FATAL("CreateProcess failed (%s)", ovs_lasterror_to_string()); } /* Close one end of the pipe in the parent. */ CloseHandle(write_pipe); /* Block and wait for child to say it is ready. */ error = ReadFile(read_pipe, &ch, 1, NULL, NULL); if (!error) { VLOG_FATAL("Failed to read from child (%s)", ovs_lasterror_to_string()); } /* The child has successfully started and is ready. */ exit(0); }