daemon-windows: Add a missing header.
[cascardo/ovs.git] / lib / daemon-windows.c
1 /*
2  * Copyright (c) 2014 Nicira, Inc.
3  *
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:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include <config.h>
18 #include "daemon.h"
19 #include "daemon-private.h"
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include "ovs-thread.h"
23 #include "poll-loop.h"
24 #include "openvswitch/vlog.h"
25
26 VLOG_DEFINE_THIS_MODULE(daemon_windows);
27
28 static bool service_create;          /* Was --service specified? */
29 static bool service_started;         /* Have we dispatched service to start? */
30
31 /* --service-monitor: Should the service be restarted if it dies
32  * unexpectedly? */
33 static bool monitor;
34
35 bool detach;                 /* Was --detach specified? */
36 static bool detached;        /* Running as the child process. */
37 static HANDLE write_handle;  /* End of pipe to write to parent. */
38
39 char *pidfile;                 /* --pidfile: Name of pidfile (null if none). */
40 static FILE *filep_pidfile;    /* File pointer to access the pidfile. */
41
42 /* Handle to the Services Manager and the created service. */
43 static SC_HANDLE manager, service;
44
45 /* Handle to the status information structure for the current service. */
46 static SERVICE_STATUS_HANDLE hstatus;
47
48 /* Hold the service's current status. */
49 static SERVICE_STATUS service_status;
50
51 /* Handle to an event object used to wakeup from poll_block(). */
52 static HANDLE wevent;
53
54 /* Hold the arguments sent to the main function. */
55 static int sargc;
56 static char ***sargvp;
57
58 static void check_service(void);
59 static void handle_scm_callback(void);
60 static void init_service_status(void);
61 static void set_config_failure_actions(void);
62
63 static bool detach_process(int argc, char *argv[]);
64
65 extern int main(int argc, char *argv[]);
66
67 void
68 daemon_usage(void)
69 {
70     printf(
71         "\nService options:\n"
72         "  --service               run in background as a service.\n"
73         "  --service-monitor       restart the service in case of an "
74                                    "unexpected failure. \n",
75         ovs_rundir(), program_name);
76 }
77
78 /* Registers the call-back and configures the actions in case of a failure
79  * with the Windows services manager. */
80 void
81 service_start(int *argcp, char **argvp[])
82 {
83     int argc = *argcp;
84     char **argv = *argvp;
85     int i;
86     SERVICE_TABLE_ENTRY service_table[] = {
87         {(LPTSTR)program_name, (LPSERVICE_MAIN_FUNCTION)main},
88         {NULL, NULL}
89     };
90
91     /* If one of the command line option is "--detach", we create
92      * a new process in case of parent, wait for child to start and exit.
93      * In case of the child, we just return. We should not be creating a
94      * service in either case. */
95     if (detach_process(argc, argv)) {
96         return;
97     }
98
99     /* 'service_started' is 'false' when service_start() is called the first
100      * time.  It is 'true', when it is called the second time by the Windows
101      * services manager. */
102     if (service_started) {
103         init_service_status();
104
105         wevent = CreateEvent(NULL, TRUE, FALSE, NULL);
106         if (!wevent) {
107             char *msg_buf = ovs_lasterror_to_string();
108             VLOG_FATAL("Failed to create a event (%s).", msg_buf);
109         }
110
111         poll_wevent_wait(wevent);
112
113         /* Register the control handler. This function is called by the service
114          * manager to stop the service. */
115         hstatus = RegisterServiceCtrlHandler(program_name,
116                                          (LPHANDLER_FUNCTION)control_handler);
117         if (!hstatus) {
118             char *msg_buf = ovs_lasterror_to_string();
119             VLOG_FATAL("Failed to register the service control handler (%s).",
120                         msg_buf);
121         }
122
123         if (monitor) {
124             set_config_failure_actions();
125         }
126
127         /* When the service control manager does the call back, it does not
128          * send the same arguments as sent to the main function during the
129          * service start. So, use the arguments passed over during the first
130          * time. */
131         *argcp = sargc;
132         *argvp = *sargvp;
133
134         /* XXX: Windows implementation cannot have a unixctl commands in the
135         * traditional sense of unix domain sockets. If an implementation is
136         * done that involves 'unixctl' vlog commands the following call is
137         * needed to make sure that the unixctl commands for vlog get
138         * registered in a daemon, even before the first log message. */
139         vlog_init();
140
141         return;
142     }
143
144     assert_single_threaded();
145
146     /* A reference to arguments passed to the main function the first time.
147      * We need it after the call-back from service control manager. */
148     sargc = argc;
149     sargvp = argvp;
150
151     /* We are only interested in the '--service' and '--service-monitor'
152      * options before the call-back from the service control manager. */
153     for (i = 0; i < argc; i ++) {
154         if (!strcmp(argv[i], "--service")) {
155             service_create = true;
156         } else if (!strcmp(argv[i], "--service-monitor")) {
157             monitor = true;
158         }
159     }
160
161     /* If '--service' is not a command line option, run in foreground. */
162     if (!service_create) {
163         return;
164     }
165
166     /* If we have been configured to run as a service, then that service
167      * should already have been created either manually or through a start up
168      * script. */
169     check_service();
170
171     service_started = true;
172
173     /* StartServiceCtrlDispatcher blocks and returns after the service is
174      * stopped. */
175     if (!StartServiceCtrlDispatcher(service_table)) {
176         char *msg_buf = ovs_lasterror_to_string();
177         VLOG_FATAL("Failed at StartServiceCtrlDispatcher (%s)", msg_buf);
178     }
179     exit(0);
180 }
181
182 /* This function is registered with the Windows services manager through
183  * a call to RegisterServiceCtrlHandler() and will be called by the Windows
184  * services manager asynchronously to stop the service. */
185 void
186 control_handler(DWORD request)
187 {
188     switch (request) {
189     case SERVICE_CONTROL_STOP:
190     case SERVICE_CONTROL_SHUTDOWN:
191         service_status.dwCurrentState = SERVICE_STOPPED;
192         service_status.dwWin32ExitCode = NO_ERROR;
193         SetEvent(wevent);
194         break;
195
196     default:
197         break;
198     }
199 }
200
201 /* Return 'true' if the Windows services manager has called the
202  * control_handler() and asked the program to terminate. */
203 bool
204 should_service_stop(void)
205 {
206     if (service_started) {
207         if (service_status.dwCurrentState != SERVICE_RUNNING) {
208             return true;
209         } else {
210             poll_wevent_wait(wevent);
211         }
212     }
213     return false;
214 }
215
216 /* Set the service as stopped. The control manager will terminate the
217  * service soon after this call. Hence, this should ideally be the last
218  * call before termination. */
219 void
220 service_stop()
221 {
222     if (!service_started) {
223         return;
224     }
225     fatal_signal_atexit_handler();
226
227     ResetEvent(wevent);
228     CloseHandle(wevent);
229
230     service_status.dwCurrentState = SERVICE_STOPPED;
231     service_status.dwWin32ExitCode = NO_ERROR;
232     SetServiceStatus(hstatus, &service_status);
233 }
234
235 /* Call this function to signal that the daemon is ready. init_service()
236  * or control_handler() has already initalized/set the
237  * service_status.dwCurrentState .*/
238 static void
239 service_complete(void)
240 {
241     if (hstatus) {
242         SetServiceStatus(hstatus, &service_status);
243     }
244 }
245
246 /* Check whether 'program_name' has been created as a service. */
247 static void
248 check_service()
249 {
250     /* Establish a connection to the local service control manager. */
251     manager = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
252     if (!manager) {
253         char *msg_buf = ovs_lasterror_to_string();
254         VLOG_FATAL("Failed to open the service control manager (%s).",
255                    msg_buf);
256     }
257
258     service = OpenService(manager, program_name, SERVICE_ALL_ACCESS);
259     if (!service) {
260         char *msg_buf = ovs_lasterror_to_string();
261         VLOG_FATAL("Failed to open service (%s).", msg_buf);
262     }
263 }
264
265 /* Service status of a service can be checked asynchronously through
266  * tools like 'sc' or through Windows services manager and is set
267  * through a call to SetServiceStatus(). */
268 static void
269 init_service_status()
270 {
271     /* The service runs in its own process. */
272     service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
273
274     /* The control codes the service accepts. */
275     service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP |
276                                             SERVICE_ACCEPT_SHUTDOWN;
277
278     /* Initialize the current state as SERVICE_RUNNING. */
279     service_status.dwCurrentState = SERVICE_RUNNING;
280
281     /* The exit code to indicate if there was an error. */
282     service_status.dwWin32ExitCode = NO_ERROR;
283
284     /* The checkpoint value the service increments periodically. Set as 0
285      * as we do not plan to periodically increment the value. */
286     service_status.dwCheckPoint = 0;
287
288     /* The estimated time required for the stop operation in ms. */
289     service_status.dwWaitHint = 1000;
290 }
291
292 /* In case of an unexpected termination, configure the action to be
293  * taken. */
294 static void
295 set_config_failure_actions()
296 {
297     /* In case of a failure, restart the process the first two times
298      * After 'dwResetPeriod', the failure count is reset. */
299     SC_ACTION fail_action[3] = {
300         {SC_ACTION_RESTART, 0},
301         {SC_ACTION_RESTART, 0},
302         {SC_ACTION_NONE, 0}
303     };
304     SERVICE_FAILURE_ACTIONS service_fail_action;
305
306     /* Reset failure count after (in seconds). */
307     service_fail_action.dwResetPeriod = 10;
308
309     /* Reboot message. */
310     service_fail_action.lpRebootMsg = NULL;
311
312     /* The command line of the process. */
313     service_fail_action.lpCommand = NULL;
314
315     /* Number of elements in 'fail_actions'. */
316     service_fail_action.cActions = sizeof(fail_action)/sizeof(fail_action[0]);
317
318     /* A pointer to an array of SC_ACTION structures. */
319     service_fail_action.lpsaActions = fail_action;
320
321     if (!ChangeServiceConfig2(service, SERVICE_CONFIG_FAILURE_ACTIONS,
322                               &service_fail_action)) {
323         char *msg_buf = ovs_lasterror_to_string();
324         VLOG_FATAL("Failed to configure service fail actions (%s).", msg_buf);
325     }
326 }
327
328 /* When a daemon is passed the --detach option, we create a new
329  * process and pass an additional non-documented option called --pipe-handle.
330  * Through this option, the parent passes one end of a pipe handle. */
331 void
332 set_pipe_handle(const char *pipe_handle)
333 {
334     write_handle = (HANDLE) atoi(pipe_handle);
335 }
336
337 /* If one of the command line option is "--detach", creates
338  * a new process in case of parent, waits for child to start and exits.
339  * In case of the child, returns. */
340 static bool
341 detach_process(int argc, char *argv[])
342 {
343     SECURITY_ATTRIBUTES sa;
344     STARTUPINFO si;
345     PROCESS_INFORMATION pi;
346     HANDLE read_pipe, write_pipe;
347     char *buffer;
348     int error, i;
349     char ch;
350
351     /* We are only interested in the '--detach' and '--pipe-handle'. */
352     for (i = 0; i < argc; i ++) {
353         if (!strcmp(argv[i], "--detach")) {
354             detach = true;
355         } else if (!strncmp(argv[i], "--pipe-handle", 13)) {
356             /* If running as a child, return. */
357             detached = true;
358             return true;
359         }
360     }
361
362     /* Nothing to do if the option --detach is not set. */
363     if (!detach) {
364         return false;
365     }
366
367     /* Set the security attribute such that a process created will
368      * inherit the pipe handles. */
369     sa.nLength = sizeof(sa);
370     sa.lpSecurityDescriptor = NULL;
371     sa.bInheritHandle = TRUE;
372
373     /* Create an anonymous pipe to communicate with the child. */
374     error = CreatePipe(&read_pipe, &write_pipe, &sa, 0);
375     if (!error) {
376         VLOG_FATAL("CreatePipe failed (%s)", ovs_lasterror_to_string());
377     }
378
379     GetStartupInfo(&si);
380
381     /* To the child, we pass an extra argument '--pipe-handle=write_pipe' */
382     buffer = xasprintf("%s %s=%ld", GetCommandLine(), "--pipe-handle",
383                        write_pipe);
384
385     /* Create a detached child */
386     error = CreateProcess(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS,
387                           NULL, NULL, &si, &pi);
388     if (!error) {
389         VLOG_FATAL("CreateProcess failed (%s)", ovs_lasterror_to_string());
390     }
391
392     /* Close one end of the pipe in the parent. */
393     CloseHandle(write_pipe);
394
395     /* Block and wait for child to say it is ready. */
396     error = ReadFile(read_pipe, &ch, 1, NULL, NULL);
397     if (!error) {
398         VLOG_FATAL("Failed to read from child (%s)",
399                    ovs_lasterror_to_string());
400     }
401     /* The child has successfully started and is ready. */
402     exit(0);
403 }
404
405 static void
406 unlink_pidfile(void)
407 {
408     if (filep_pidfile) {
409         fclose(filep_pidfile);
410     }
411     if (pidfile) {
412         unlink(pidfile);
413     }
414 }
415
416 /* If a pidfile has been configured, creates it and stores the running
417  * process's pid in it.  Ensures that the pidfile will be deleted when the
418  * process exits. */
419 static void
420 make_pidfile(void)
421 {
422     int error;
423
424     error = GetFileAttributes(pidfile);
425     if (error != INVALID_FILE_ATTRIBUTES) {
426         /* pidfile exists. Try to unlink() it. */
427         error = unlink(pidfile);
428         if (error) {
429             VLOG_FATAL("Failed to delete existing pidfile %s (%s)", pidfile,
430                        ovs_strerror(errno));
431         }
432     }
433
434     filep_pidfile = fopen(pidfile, "w");
435     if (filep_pidfile == NULL) {
436         VLOG_FATAL("failed to open %s (%s)", pidfile, ovs_strerror(errno));
437     }
438
439     fatal_signal_add_hook(unlink_pidfile, NULL, NULL, true);
440
441     fprintf(filep_pidfile, "%d\n", _getpid());
442     if (fflush(filep_pidfile) == EOF) {
443         VLOG_FATAL("Failed to write into the pidfile %s", pidfile);
444     }
445
446     /* Don't close the pidfile till the process exits. */
447 }
448
449 void daemonize_start(void)
450 {
451     if (pidfile) {
452         make_pidfile();
453     }
454 }
455
456 void
457 daemonize_complete(void)
458 {
459     /* If running as a child because '--detach' option was specified,
460      * communicate with the parent to inform that the child is ready. */
461     if (detached) {
462         int error;
463
464         close_standard_fds();
465
466         error = WriteFile(write_handle, "a", 1, NULL, NULL);
467         if (!error) {
468             VLOG_FATAL("Failed to communicate with the parent (%s)",
469                        ovs_lasterror_to_string());
470         }
471     }
472
473     service_complete();
474 }
475
476 /* Returns the file name that would be used for a pidfile if 'name' were
477  * provided to set_pidfile().  The caller must free the returned string. */
478 char *
479 make_pidfile_name(const char *name)
480 {
481     if (name && strchr(name, ':')) {
482         return xstrdup(name);
483     } else {
484         return xasprintf("%s/%s.pid", ovs_rundir(), program_name);
485     }
486 }