2 * Copyright (c) 2014 Nicira, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
21 #include "poll-loop.h"
24 VLOG_DEFINE_THIS_MODULE(daemon_windows);
26 static bool service_create; /* Was --service specified? */
27 static bool service_started; /* Have we dispatched service to start? */
29 /* --service-monitor: Should the service be restarted if it dies
33 static bool detach; /* Was --detach specified? */
34 static bool detached; /* Running as the child process. */
35 static HANDLE write_handle; /* End of pipe to write to parent. */
37 static char *pidfile; /* --pidfile: Name of pidfile (null if none). */
38 static FILE *filep_pidfile; /* File pointer to access the pidfile. */
40 /* Handle to the Services Manager and the created service. */
41 static SC_HANDLE manager, service;
43 /* Handle to the status information structure for the current service. */
44 static SERVICE_STATUS_HANDLE hstatus;
46 /* Hold the service's current status. */
47 static SERVICE_STATUS service_status;
49 /* Handle to an event object used to wakeup from poll_block(). */
52 /* Hold the arguments sent to the main function. */
54 static char ***sargvp;
56 static void check_service(void);
57 static void handle_scm_callback(void);
58 static void init_service_status(void);
59 static void set_config_failure_actions(void);
61 static bool detach_process(int argc, char *argv[]);
63 extern int main(int argc, char *argv[]);
69 "\nService options:\n"
70 " --service run in background as a service.\n"
71 " --service-monitor restart the service in case of an "
72 "unexpected failure. \n",
73 ovs_rundir(), program_name);
76 /* Registers the call-back and configures the actions in case of a failure
77 * with the Windows services manager. */
79 service_start(int *argcp, char **argvp[])
84 SERVICE_TABLE_ENTRY service_table[] = {
85 {(LPTSTR)program_name, (LPSERVICE_MAIN_FUNCTION)main},
89 /* If one of the command line option is "--detach", we create
90 * a new process in case of parent, wait for child to start and exit.
91 * In case of the child, we just return. We should not be creating a
92 * service in either case. */
93 if (detach_process(argc, argv)) {
97 /* 'service_started' is 'false' when service_start() is called the first
98 * time. It is 'true', when it is called the second time by the Windows
99 * services manager. */
100 if (service_started) {
101 init_service_status();
103 wevent = CreateEvent(NULL, TRUE, FALSE, NULL);
105 char *msg_buf = ovs_lasterror_to_string();
106 VLOG_FATAL("Failed to create a event (%s).", msg_buf);
109 poll_fd_wait_event(0, wevent, POLLIN);
111 /* Register the control handler. This function is called by the service
112 * manager to stop the service. */
113 hstatus = RegisterServiceCtrlHandler(program_name,
114 (LPHANDLER_FUNCTION)control_handler);
116 char *msg_buf = ovs_lasterror_to_string();
117 VLOG_FATAL("Failed to register the service control handler (%s).",
122 set_config_failure_actions();
125 /* When the service control manager does the call back, it does not
126 * send the same arguments as sent to the main function during the
127 * service start. So, use the arguments passed over during the first
132 /* XXX: Windows implementation cannot have a unixctl commands in the
133 * traditional sense of unix domain sockets. If an implementation is
134 * done that involves 'unixctl' vlog commands the following call is
135 * needed to make sure that the unixctl commands for vlog get
136 * registered in a daemon, even before the first log message. */
142 assert_single_threaded();
144 /* A reference to arguments passed to the main function the first time.
145 * We need it after the call-back from service control manager. */
149 /* We are only interested in the '--service' and '--service-monitor'
150 * options before the call-back from the service control manager. */
151 for (i = 0; i < argc; i ++) {
152 if (!strcmp(argv[i], "--service")) {
153 service_create = true;
154 } else if (!strcmp(argv[i], "--service-monitor")) {
159 /* If '--service' is not a command line option, run in foreground. */
160 if (!service_create) {
164 /* If we have been configured to run as a service, then that service
165 * should already have been created either manually or through a start up
169 service_started = true;
171 /* StartServiceCtrlDispatcher blocks and returns after the service is
173 if (!StartServiceCtrlDispatcher(service_table)) {
174 char *msg_buf = ovs_lasterror_to_string();
175 VLOG_FATAL("Failed at StartServiceCtrlDispatcher (%s)", msg_buf);
180 /* This function is registered with the Windows services manager through
181 * a call to RegisterServiceCtrlHandler() and will be called by the Windows
182 * services manager asynchronously to stop the service. */
184 control_handler(DWORD request)
187 case SERVICE_CONTROL_STOP:
188 case SERVICE_CONTROL_SHUTDOWN:
189 service_status.dwCurrentState = SERVICE_STOPPED;
190 service_status.dwWin32ExitCode = NO_ERROR;
199 /* Return 'true' if the Windows services manager has called the
200 * control_handler() and asked the program to terminate. */
202 should_service_stop(void)
204 if (service_started) {
205 if (service_status.dwCurrentState != SERVICE_RUNNING) {
208 poll_fd_wait_event(0, wevent, POLLIN);
214 /* Set the service as stopped. The control manager will terminate the
215 * service soon after this call. Hence, this should ideally be the last
216 * call before termination. */
223 service_status.dwCurrentState = SERVICE_STOPPED;
224 service_status.dwWin32ExitCode = NO_ERROR;
225 SetServiceStatus(hstatus, &service_status);
228 /* Call this function to signal that the daemon is ready. init_service()
229 * or control_handler() has already initalized/set the
230 * service_status.dwCurrentState .*/
232 service_complete(void)
235 SetServiceStatus(hstatus, &service_status);
239 /* Check whether 'program_name' has been created as a service. */
243 /* Establish a connection to the local service control manager. */
244 manager = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
246 char *msg_buf = ovs_lasterror_to_string();
247 VLOG_FATAL("Failed to open the service control manager (%s).",
251 service = OpenService(manager, program_name, SERVICE_ALL_ACCESS);
253 char *msg_buf = ovs_lasterror_to_string();
254 VLOG_FATAL("Failed to open service (%s).", msg_buf);
258 /* Service status of a service can be checked asynchronously through
259 * tools like 'sc' or through Windows services manager and is set
260 * through a call to SetServiceStatus(). */
262 init_service_status()
264 /* The service runs in its own process. */
265 service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
267 /* The control codes the service accepts. */
268 service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP |
269 SERVICE_ACCEPT_SHUTDOWN;
271 /* Initialize the current state as SERVICE_RUNNING. */
272 service_status.dwCurrentState = SERVICE_RUNNING;
274 /* The exit code to indicate if there was an error. */
275 service_status.dwWin32ExitCode = NO_ERROR;
277 /* The checkpoint value the service increments periodically. Set as 0
278 * as we do not plan to periodically increment the value. */
279 service_status.dwCheckPoint = 0;
281 /* The estimated time required for the stop operation in ms. */
282 service_status.dwWaitHint = 1000;
285 /* In case of an unexpected termination, configure the action to be
288 set_config_failure_actions()
290 /* In case of a failure, restart the process the first two times
291 * After 'dwResetPeriod', the failure count is reset. */
292 SC_ACTION fail_action[3] = {
293 {SC_ACTION_RESTART, 0},
294 {SC_ACTION_RESTART, 0},
297 SERVICE_FAILURE_ACTIONS service_fail_action;
299 /* Reset failure count after (in seconds). */
300 service_fail_action.dwResetPeriod = 10;
302 /* Reboot message. */
303 service_fail_action.lpRebootMsg = NULL;
305 /* The command line of the process. */
306 service_fail_action.lpCommand = NULL;
308 /* Number of elements in 'fail_actions'. */
309 service_fail_action.cActions = sizeof(fail_action)/sizeof(fail_action[0]);
311 /* A pointer to an array of SC_ACTION structures. */
312 service_fail_action.lpsaActions = fail_action;
314 if (!ChangeServiceConfig2(service, SERVICE_CONFIG_FAILURE_ACTIONS,
315 &service_fail_action)) {
316 char *msg_buf = ovs_lasterror_to_string();
317 VLOG_FATAL("Failed to configure service fail actions (%s).", msg_buf);
321 /* When a daemon is passed the --detach option, we create a new
322 * process and pass an additional non-documented option called --pipe-handle.
323 * Through this option, the parent passes one end of a pipe handle. */
325 set_pipe_handle(const char *pipe_handle)
327 write_handle = (HANDLE) atoi(pipe_handle);
330 /* If one of the command line option is "--detach", creates
331 * a new process in case of parent, waits for child to start and exits.
332 * In case of the child, returns. */
334 detach_process(int argc, char *argv[])
336 SECURITY_ATTRIBUTES sa;
338 PROCESS_INFORMATION pi;
339 HANDLE read_pipe, write_pipe;
344 /* We are only interested in the '--detach' and '--pipe-handle'. */
345 for (i = 0; i < argc; i ++) {
346 if (!strcmp(argv[i], "--detach")) {
348 } else if (!strncmp(argv[i], "--pipe-handle", 13)) {
349 /* If running as a child, return. */
355 /* Nothing to do if the option --detach is not set. */
360 /* Set the security attribute such that a process created will
361 * inherit the pipe handles. */
362 sa.nLength = sizeof(sa);
363 sa.lpSecurityDescriptor = NULL;
364 sa.bInheritHandle = TRUE;
366 /* Create an anonymous pipe to communicate with the child. */
367 error = CreatePipe(&read_pipe, &write_pipe, &sa, 0);
369 VLOG_FATAL("CreatePipe failed (%s)", ovs_lasterror_to_string());
374 /* To the child, we pass an extra argument '--pipe-handle=write_pipe' */
375 buffer = xasprintf("%s %s=%ld", GetCommandLine(), "--pipe-handle",
378 /* Create a detached child */
379 error = CreateProcess(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS,
380 NULL, NULL, &si, &pi);
382 VLOG_FATAL("CreateProcess failed (%s)", ovs_lasterror_to_string());
385 /* Close one end of the pipe in the parent. */
386 CloseHandle(write_pipe);
388 /* Block and wait for child to say it is ready. */
389 error = ReadFile(read_pipe, &ch, 1, NULL, NULL);
391 VLOG_FATAL("Failed to read from child (%s)",
392 ovs_lasterror_to_string());
394 /* The child has successfully started and is ready. */
398 /* Will daemonize() really detach? */
406 daemon_save_fd(int fd OVS_UNUSED)
414 daemonize_complete();
421 fclose(filep_pidfile);
428 /* If a pidfile has been configured, creates it and stores the running
429 * process's pid in it. Ensures that the pidfile will be deleted when the
436 error = GetFileAttributes(pidfile);
437 if (error != INVALID_FILE_ATTRIBUTES) {
438 /* pidfile exists. Try to unlink() it. */
439 error = unlink(pidfile);
441 VLOG_FATAL("Failed to delete existing pidfile %s (%s)", pidfile,
442 ovs_strerror(errno));
446 filep_pidfile = fopen(pidfile, "w");
447 if (filep_pidfile == NULL) {
448 VLOG_FATAL("failed to open %s (%s)", pidfile, ovs_strerror(errno));
451 fatal_signal_add_hook(unlink_pidfile, NULL, NULL, true);
453 fprintf(filep_pidfile, "%d\n", _getpid());
454 if (fflush(filep_pidfile) == EOF) {
455 VLOG_FATAL("Failed to write into the pidfile %s", pidfile);
458 /* Don't close the pidfile till the process exits. */
461 void daemonize_start(void)
469 daemonize_complete(void)
471 /* If running as a child because '--detach' option was specified,
472 * communicate with the parent to inform that the child is ready. */
475 error = WriteFile(write_handle, "a", 1, NULL, NULL);
477 VLOG_FATAL("Failed to communicate with the parent (%s)",
478 ovs_lasterror_to_string());
485 /* Returns the file name that would be used for a pidfile if 'name' were
486 * provided to set_pidfile(). The caller must free the returned string. */
488 make_pidfile_name(const char *name)
490 if (name && strchr(name, ':')) {
493 return xasprintf("%s/%s.pid", ovs_rundir(), program_name);
497 /* Sets up a following call to daemonize() to create a pidfile named 'name'.
498 * If 'name' begins with '/', then it is treated as an absolute path.
499 * Otherwise, it is taken relative to RUNDIR, which is $(prefix)/var/run by
502 * If 'name' is null, then program_name followed by ".pid" is used. */
504 set_pidfile(const char *name)
506 assert_single_threaded();
508 pidfile = make_pidfile_name(name);