daemon: Rename daemon.c as daemon-unix.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 <stdio.h>
20 #include <stdlib.h>
21 #include "poll-loop.h"
22 #include "vlog.h"
23
24 VLOG_DEFINE_THIS_MODULE(daemon_windows);
25
26 static bool service_create;          /* Was --service specified? */
27 static bool service_started;         /* Have we dispatched service to start? */
28
29 /* --service-monitor: Should the service be restarted if it dies
30  * unexpectedly? */
31 static bool monitor;
32
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. */
36
37 static char *pidfile;         /* --pidfile: Name of pidfile (null if none). */
38 static FILE *filep_pidfile;   /* File pointer to access the pidfile. */
39
40 /* Handle to the Services Manager and the created service. */
41 static SC_HANDLE manager, service;
42
43 /* Handle to the status information structure for the current service. */
44 static SERVICE_STATUS_HANDLE hstatus;
45
46 /* Hold the service's current status. */
47 static SERVICE_STATUS service_status;
48
49 /* Handle to an event object used to wakeup from poll_block(). */
50 static HANDLE wevent;
51
52 /* Hold the arguments sent to the main function. */
53 static int sargc;
54 static char ***sargvp;
55
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);
60
61 static bool detach_process(int argc, char *argv[]);
62
63 extern int main(int argc, char *argv[]);
64
65 void
66 daemon_usage(void)
67 {
68     printf(
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);
74 }
75
76 /* Registers the call-back and configures the actions in case of a failure
77  * with the Windows services manager. */
78 void
79 service_start(int *argcp, char **argvp[])
80 {
81     int argc = *argcp;
82     char **argv = *argvp;
83     int i;
84     SERVICE_TABLE_ENTRY service_table[] = {
85         {(LPTSTR)program_name, (LPSERVICE_MAIN_FUNCTION)main},
86         {NULL, NULL}
87     };
88
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)) {
94         return;
95     }
96
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();
102
103         wevent = CreateEvent(NULL, TRUE, FALSE, NULL);
104         if (!wevent) {
105             char *msg_buf = ovs_lasterror_to_string();
106             VLOG_FATAL("Failed to create a event (%s).", msg_buf);
107         }
108
109         poll_fd_wait_event(0, wevent, POLLIN);
110
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);
115         if (!hstatus) {
116             char *msg_buf = ovs_lasterror_to_string();
117             VLOG_FATAL("Failed to register the service control handler (%s).",
118                         msg_buf);
119         }
120
121         if (monitor) {
122             set_config_failure_actions();
123         }
124
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
128          * time. */
129         *argcp = sargc;
130         *argvp = *sargvp;
131
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. */
137         vlog_init();
138
139         return;
140     }
141
142     assert_single_threaded();
143
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. */
146     sargc = argc;
147     sargvp = argvp;
148
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")) {
155             monitor = true;
156         }
157     }
158
159     /* If '--service' is not a command line option, run in foreground. */
160     if (!service_create) {
161         return;
162     }
163
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
166      * script. */
167     check_service();
168
169     service_started = true;
170
171     /* StartServiceCtrlDispatcher blocks and returns after the service is
172      * stopped. */
173     if (!StartServiceCtrlDispatcher(service_table)) {
174         char *msg_buf = ovs_lasterror_to_string();
175         VLOG_FATAL("Failed at StartServiceCtrlDispatcher (%s)", msg_buf);
176     }
177     exit(0);
178 }
179
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. */
183 void
184 control_handler(DWORD request)
185 {
186     switch (request) {
187     case SERVICE_CONTROL_STOP:
188     case SERVICE_CONTROL_SHUTDOWN:
189         service_status.dwCurrentState = SERVICE_STOPPED;
190         service_status.dwWin32ExitCode = NO_ERROR;
191         SetEvent(wevent);
192         break;
193
194     default:
195         break;
196     }
197 }
198
199 /* Return 'true' if the Windows services manager has called the
200  * control_handler() and asked the program to terminate. */
201 bool
202 should_service_stop(void)
203 {
204     if (service_started) {
205         if (service_status.dwCurrentState != SERVICE_RUNNING) {
206             return true;
207         } else {
208             poll_fd_wait_event(0, wevent, POLLIN);
209         }
210     }
211     return false;
212 }
213
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. */
217 void
218 service_stop()
219 {
220     ResetEvent(wevent);
221     CloseHandle(wevent);
222
223     service_status.dwCurrentState = SERVICE_STOPPED;
224     service_status.dwWin32ExitCode = NO_ERROR;
225     SetServiceStatus(hstatus, &service_status);
226 }
227
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 .*/
231 static void
232 service_complete(void)
233 {
234     if (hstatus) {
235         SetServiceStatus(hstatus, &service_status);
236     }
237 }
238
239 /* Check whether 'program_name' has been created as a service. */
240 static void
241 check_service()
242 {
243     /* Establish a connection to the local service control manager. */
244     manager = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
245     if (!manager) {
246         char *msg_buf = ovs_lasterror_to_string();
247         VLOG_FATAL("Failed to open the service control manager (%s).",
248                    msg_buf);
249     }
250
251     service = OpenService(manager, program_name, SERVICE_ALL_ACCESS);
252     if (!service) {
253         char *msg_buf = ovs_lasterror_to_string();
254         VLOG_FATAL("Failed to open service (%s).", msg_buf);
255     }
256 }
257
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(). */
261 static void
262 init_service_status()
263 {
264     /* The service runs in its own process. */
265     service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
266
267     /* The control codes the service accepts. */
268     service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP |
269                                             SERVICE_ACCEPT_SHUTDOWN;
270
271     /* Initialize the current state as SERVICE_RUNNING. */
272     service_status.dwCurrentState = SERVICE_RUNNING;
273
274     /* The exit code to indicate if there was an error. */
275     service_status.dwWin32ExitCode = NO_ERROR;
276
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;
280
281     /* The estimated time required for the stop operation in ms. */
282     service_status.dwWaitHint = 1000;
283 }
284
285 /* In case of an unexpected termination, configure the action to be
286  * taken. */
287 static void
288 set_config_failure_actions()
289 {
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},
295         {SC_ACTION_NONE, 0}
296     };
297     SERVICE_FAILURE_ACTIONS service_fail_action;
298
299     /* Reset failure count after (in seconds). */
300     service_fail_action.dwResetPeriod = 10;
301
302     /* Reboot message. */
303     service_fail_action.lpRebootMsg = NULL;
304
305     /* The command line of the process. */
306     service_fail_action.lpCommand = NULL;
307
308     /* Number of elements in 'fail_actions'. */
309     service_fail_action.cActions = sizeof(fail_action)/sizeof(fail_action[0]);
310
311     /* A pointer to an array of SC_ACTION structures. */
312     service_fail_action.lpsaActions = fail_action;
313
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);
318     }
319 }
320
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. */
324 void
325 set_pipe_handle(const char *pipe_handle)
326 {
327     write_handle = (HANDLE) atoi(pipe_handle);
328 }
329
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. */
333 static bool
334 detach_process(int argc, char *argv[])
335 {
336     SECURITY_ATTRIBUTES sa;
337     STARTUPINFO si;
338     PROCESS_INFORMATION pi;
339     HANDLE read_pipe, write_pipe;
340     char *buffer;
341     int error, i;
342     char ch;
343
344     /* We are only interested in the '--detach' and '--pipe-handle'. */
345     for (i = 0; i < argc; i ++) {
346         if (!strcmp(argv[i], "--detach")) {
347             detach = true;
348         } else if (!strncmp(argv[i], "--pipe-handle", 13)) {
349             /* If running as a child, return. */
350             detached = true;
351             return true;
352         }
353     }
354
355     /* Nothing to do if the option --detach is not set. */
356     if (!detach) {
357         return false;
358     }
359
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;
365
366     /* Create an anonymous pipe to communicate with the child. */
367     error = CreatePipe(&read_pipe, &write_pipe, &sa, 0);
368     if (!error) {
369         VLOG_FATAL("CreatePipe failed (%s)", ovs_lasterror_to_string());
370     }
371
372     GetStartupInfo(&si);
373
374     /* To the child, we pass an extra argument '--pipe-handle=write_pipe' */
375     buffer = xasprintf("%s %s=%ld", GetCommandLine(), "--pipe-handle",
376                        write_pipe);
377
378     /* Create a detached child */
379     error = CreateProcess(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS,
380                           NULL, NULL, &si, &pi);
381     if (!error) {
382         VLOG_FATAL("CreateProcess failed (%s)", ovs_lasterror_to_string());
383     }
384
385     /* Close one end of the pipe in the parent. */
386     CloseHandle(write_pipe);
387
388     /* Block and wait for child to say it is ready. */
389     error = ReadFile(read_pipe, &ch, 1, NULL, NULL);
390     if (!error) {
391         VLOG_FATAL("Failed to read from child (%s)",
392                    ovs_lasterror_to_string());
393     }
394     /* The child has successfully started and is ready. */
395     exit(0);
396 }
397
398 /* Will daemonize() really detach? */
399 bool
400 get_detach()
401 {
402     return detach;
403 }
404
405 void
406 daemon_save_fd(int fd OVS_UNUSED)
407 {
408 }
409
410 void
411 daemonize(void)
412 {
413     daemonize_start();
414     daemonize_complete();
415 }
416
417 static void
418 unlink_pidfile(void)
419 {
420     if (filep_pidfile) {
421         fclose(filep_pidfile);
422     }
423     if (pidfile) {
424         unlink(pidfile);
425     }
426 }
427
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
430  * process exits. */
431 static void
432 make_pidfile(void)
433 {
434     int error;
435
436     error = GetFileAttributes(pidfile);
437     if (error != INVALID_FILE_ATTRIBUTES) {
438         /* pidfile exists. Try to unlink() it. */
439         error = unlink(pidfile);
440         if (error) {
441             VLOG_FATAL("Failed to delete existing pidfile %s (%s)", pidfile,
442                        ovs_strerror(errno));
443         }
444     }
445
446     filep_pidfile = fopen(pidfile, "w");
447     if (filep_pidfile == NULL) {
448         VLOG_FATAL("failed to open %s (%s)", pidfile, ovs_strerror(errno));
449     }
450
451     fatal_signal_add_hook(unlink_pidfile, NULL, NULL, true);
452
453     fprintf(filep_pidfile, "%d\n", _getpid());
454     if (fflush(filep_pidfile) == EOF) {
455         VLOG_FATAL("Failed to write into the pidfile %s", pidfile);
456     }
457
458     /* Don't close the pidfile till the process exits. */
459 }
460
461 void daemonize_start(void)
462 {
463     if (pidfile) {
464         make_pidfile();
465     }
466 }
467
468 void
469 daemonize_complete(void)
470 {
471     /* If running as a child because '--detach' option was specified,
472      * communicate with the parent to inform that the child is ready. */
473     if (detached) {
474         int error;
475         error = WriteFile(write_handle, "a", 1, NULL, NULL);
476         if (!error) {
477             VLOG_FATAL("Failed to communicate with the parent (%s)",
478                        ovs_lasterror_to_string());
479         }
480     }
481
482     service_complete();
483 }
484
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. */
487 static char *
488 make_pidfile_name(const char *name)
489 {
490     if (name && strchr(name, ':')) {
491         return strdup(name);
492     } else {
493         return xasprintf("%s/%s.pid", ovs_rundir(), program_name);
494     }
495 }
496
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
500  * default.
501  *
502  * If 'name' is null, then program_name followed by ".pid" is used. */
503 void
504 set_pidfile(const char *name)
505 {
506     assert_single_threaded();
507     free(pidfile);
508     pidfile = make_pidfile_name(name);
509 }