/* 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); xpipe_nonblocking(signal_fds); for (i = 0; i < ARRAY_SIZE(fatal_signals); i++) { int sig_nr = fatal_signals[i]; 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)); } } atexit(atexit_handler); } }
/* Sets up a following call to daemonize() to create a pidfile named 'name'. * If 'name' begins with '/', then it is treated as an absolute path. * Otherwise, it is taken relative to RUNDIR, which is $(prefix)/var/run by * default. * * If 'name' is null, then program_name followed by ".pid" is used. */ void set_pidfile(const char *name) { assert_single_threaded(); free(pidfile); pidfile = make_pidfile_name(name); }
/* Noramlly, user switch is embedded within daemonize_start(). * However, there in case the user switch needs to be done * before daemonize_start(), the following API can be used. */ void daemon_become_new_user(bool access_datapath) { assert_single_threaded(); if (switch_user) { daemon_become_new_user__(access_datapath); /* daemonize_start() should not switch user again. */ switch_user = false; } }
/* If daemonization is configured, then starts daemonization, by forking and * returning in the child process. The parent process hangs around until the * child lets it know either that it completed startup successfully (by calling * daemon_complete()) or that it failed to start up (by exiting with a nonzero * exit code). */ void daemonize_start(bool access_datapath) { assert_single_threaded(); daemonize_fd = -1; if (switch_user) { daemon_become_new_user__(access_datapath); switch_user = false; } if (detach) { pid_t pid; if (fork_and_wait_for_startup(&daemonize_fd, &pid)) { VLOG_FATAL("could not detach from foreground session"); } if (pid > 0) { /* Running in parent process. */ exit(0); } /* Running in daemon or monitor process. */ setsid(); } if (monitor) { int saved_daemonize_fd = daemonize_fd; pid_t daemon_pid; if (fork_and_wait_for_startup(&daemonize_fd, &daemon_pid)) { VLOG_FATAL("could not initiate process monitoring"); } if (daemon_pid > 0) { /* Running in monitor process. */ fork_notify_startup(saved_daemonize_fd); if (detach) { close_standard_fds(); } monitor_daemon(daemon_pid); } /* Running in daemon process. */ } forbid_forking("running in daemon process"); if (pidfile) { make_pidfile(); } /* Make sure that the unixctl commands for vlog get registered in a * daemon, even before the first log message. */ vlog_init(); }
/* Configures the program to die with SIGALRM 'secs' seconds from now, if * 'secs' is nonzero, or disables the feature if 'secs' is zero. */ void time_alarm(unsigned int secs) { long long int now; long long int msecs; assert_single_threaded(); time_init(); now = time_msec(); msecs = secs * 1000LL; deadline = now < LLONG_MAX - msecs ? now + msecs : LLONG_MAX; }
/* 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); } }
/* If daemonization is configured, then starts daemonization, by forking and * returning in the child process. The parent process hangs around until the * child lets it know either that it completed startup successfully (by calling * daemon_complete()) or that it failed to start up (by exiting with a nonzero * exit code). */ void daemonize_start(void) { assert_single_threaded(); daemonize_fd = -1; if (detach) { if (fork_and_wait_for_startup(&daemonize_fd) > 0) { /* Running in parent process. */ exit(0); } /* Running in daemon or monitor process. */ setsid(); } if (monitor) { int saved_daemonize_fd = daemonize_fd; pid_t daemon_pid; daemon_pid = fork_and_wait_for_startup(&daemonize_fd); if (daemon_pid > 0) { /* Running in monitor process. */ fork_notify_startup(saved_daemonize_fd); close_standard_fds(); monitor_daemon(daemon_pid); } /* Running in daemon process. */ } forbid_forking("running in daemon process"); if (pidfile) { make_pidfile(); } /* Make sure that the unixctl commands for vlog get registered in a * daemon, even before the first log message. */ vlog_init(); }
void add_allowed_ofp_versions(uint32_t bitmap) { assert_single_threaded(); allowed_versions |= bitmap; }
void set_allowed_ofp_versions(const char *string) { assert_single_threaded(); allowed_versions = ofputil_versions_from_string(string); }
/* 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); }