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