2 * Copyright (c) 2014, 2017 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.
19 #include "daemon-private.h"
25 #include "fatal-signal.h"
26 #include "ovs-thread.h"
27 #include "openvswitch/poll-loop.h"
28 #include "openvswitch/vlog.h"
30 VLOG_DEFINE_THIS_MODULE(daemon_windows
);
32 /* Constants for flock function */
33 #define LOCK_SHARED 0x0 /* Shared lock. */
34 #define LOCK_UNLOCK 0x80000000 /* Unlock. Custom value. */
36 static bool service_create
; /* Was --service specified? */
37 static bool service_started
; /* Have we dispatched service to start? */
39 /* --service-monitor: Should the service be restarted if it dies
43 bool detach
; /* Was --detach specified? */
44 static bool detached
; /* Running as the child process. */
45 static HANDLE write_handle
; /* End of pipe to write to parent. */
47 char *pidfile
; /* --pidfile: Name of pidfile (null if none). */
48 static FILE *filep_pidfile
; /* File pointer to access the pidfile. */
50 /* Handle to the Services Manager and the created service. */
51 static SC_HANDLE manager
, service
;
53 /* Handle to the status information structure for the current service. */
54 static SERVICE_STATUS_HANDLE hstatus
;
56 /* Hold the service's current status. */
57 static SERVICE_STATUS service_status
;
59 /* Handle to an event object used to wakeup from poll_block(). */
62 /* Hold the arguments sent to the main function. */
64 static char ***sargvp
;
66 static void check_service(void);
67 static void handle_scm_callback(void);
68 static void init_service_status(void);
69 static void set_config_failure_actions(void);
71 static bool detach_process(int argc
, char *argv
[]);
73 extern int main(int argc
, char *argv
[]);
79 "\nService options:\n"
80 " --service run in background as a service.\n"
81 " --service-monitor restart the service in case of an "
82 "unexpected failure. \n");
85 /* Registers the call-back and configures the actions in case of a failure
86 * with the Windows services manager. */
88 service_start(int *argcp
, char **argvp
[])
93 SERVICE_TABLE_ENTRY service_table
[] = {
94 {(LPTSTR
)program_name
, (LPSERVICE_MAIN_FUNCTION
)main
},
98 /* If one of the command line option is "--detach", we create
99 * a new process in case of parent, wait for child to start and exit.
100 * In case of the child, we just return. We should not be creating a
101 * service in either case. */
102 if (detach_process(argc
, argv
)) {
106 /* 'service_started' is 'false' when service_start() is called the first
107 * time. It is 'true', when it is called the second time by the Windows
108 * services manager. */
109 if (service_started
) {
110 init_service_status();
112 wevent
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
114 char *msg_buf
= ovs_lasterror_to_string();
115 VLOG_FATAL("Failed to create a event (%s).", msg_buf
);
118 poll_wevent_wait(wevent
);
120 /* Register the control handler. This function is called by the service
121 * manager to stop the service. */
122 hstatus
= RegisterServiceCtrlHandler(program_name
,
123 (LPHANDLER_FUNCTION
)control_handler
);
125 char *msg_buf
= ovs_lasterror_to_string();
126 VLOG_FATAL("Failed to register the service control handler (%s).",
131 set_config_failure_actions();
134 /* When the service control manager does the call back, it does not
135 * send the same arguments as sent to the main function during the
136 * service start. So, use the arguments passed over during the first
141 /* Enable default error mode so we can take advantage of WER
142 * (Windows Error Reporting) crash dumps.
143 * Being a service it does not allow for WER window pop-up.
144 * XXX implement our on crash dump collection mechanism. */
150 assert_single_threaded();
152 /* A reference to arguments passed to the main function the first time.
153 * We need it after the call-back from service control manager. */
157 /* We are only interested in the '--service' and '--service-monitor'
158 * options before the call-back from the service control manager. */
159 for (i
= 0; i
< argc
; i
++) {
160 if (!strcmp(argv
[i
], "--service")) {
161 service_create
= true;
162 } else if (!strcmp(argv
[i
], "--service-monitor")) {
167 /* If '--service' is not a command line option, run in foreground. */
168 if (!service_create
) {
172 /* If we have been configured to run as a service, then that service
173 * should already have been created either manually or through a start up
177 service_started
= true;
179 /* StartServiceCtrlDispatcher blocks and returns after the service is
181 if (!StartServiceCtrlDispatcher(service_table
)) {
182 char *msg_buf
= ovs_lasterror_to_string();
183 VLOG_FATAL("Failed at StartServiceCtrlDispatcher (%s)", msg_buf
);
188 /* This function is registered with the Windows services manager through
189 * a call to RegisterServiceCtrlHandler() and will be called by the Windows
190 * services manager asynchronously to stop the service. */
192 control_handler(DWORD request
)
195 case SERVICE_CONTROL_STOP
:
196 case SERVICE_CONTROL_SHUTDOWN
:
197 service_status
.dwCurrentState
= SERVICE_STOPPED
;
198 service_status
.dwWin32ExitCode
= NO_ERROR
;
200 SetServiceStatus(hstatus
, &service_status
);
208 /* Return 'true' if the Windows services manager has called the
209 * control_handler() and asked the program to terminate. */
211 should_service_stop(void)
213 if (service_started
) {
214 if (service_status
.dwCurrentState
!= SERVICE_RUNNING
) {
217 poll_wevent_wait(wevent
);
223 /* Set the service as stopped. The control manager will terminate the
224 * service soon after this call. Hence, this should ideally be the last
225 * call before termination. */
229 if (!service_started
) {
232 fatal_signal_atexit_handler();
237 service_status
.dwCurrentState
= SERVICE_STOPPED
;
238 service_status
.dwWin32ExitCode
= NO_ERROR
;
239 SetServiceStatus(hstatus
, &service_status
);
242 /* Call this function to signal that the daemon is ready. init_service()
243 * or control_handler() has already initalized/set the
244 * service_status.dwCurrentState .*/
246 service_complete(void)
249 SetServiceStatus(hstatus
, &service_status
);
253 /* Check whether 'program_name' has been created as a service. */
257 /* Establish a connection to the local service control manager. */
258 manager
= OpenSCManager(NULL
, NULL
, SC_MANAGER_ENUMERATE_SERVICE
);
260 char *msg_buf
= ovs_lasterror_to_string();
261 VLOG_FATAL("Failed to open the service control manager (%s).",
265 service
= OpenService(manager
, program_name
, SERVICE_ALL_ACCESS
);
267 char *msg_buf
= ovs_lasterror_to_string();
268 VLOG_FATAL("Failed to open service (%s).", msg_buf
);
272 /* Service status of a service can be checked asynchronously through
273 * tools like 'sc' or through Windows services manager and is set
274 * through a call to SetServiceStatus(). */
276 init_service_status()
278 /* The service runs in its own process. */
279 service_status
.dwServiceType
= SERVICE_WIN32_OWN_PROCESS
;
281 /* The control codes the service accepts. */
282 service_status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
|
283 SERVICE_ACCEPT_SHUTDOWN
;
285 /* Initialize the current state as SERVICE_RUNNING. */
286 service_status
.dwCurrentState
= SERVICE_RUNNING
;
288 /* The exit code to indicate if there was an error. */
289 service_status
.dwWin32ExitCode
= NO_ERROR
;
291 /* The checkpoint value the service increments periodically. Set as 0
292 * as we do not plan to periodically increment the value. */
293 service_status
.dwCheckPoint
= 0;
295 /* The estimated time required for the stop operation in ms. */
296 service_status
.dwWaitHint
= 1000;
299 /* In case of an unexpected termination, configure the action to be
302 set_config_failure_actions()
304 /* In case of a failure, restart the process the first two times
305 * After 'dwResetPeriod', the failure count is reset. */
306 SC_ACTION fail_action
[3] = {
307 {SC_ACTION_RESTART
, 0},
308 {SC_ACTION_RESTART
, 0},
311 SERVICE_FAILURE_ACTIONS service_fail_action
;
313 /* Reset failure count after (in seconds). */
314 service_fail_action
.dwResetPeriod
= 10;
316 /* Reboot message. */
317 service_fail_action
.lpRebootMsg
= NULL
;
319 /* The command line of the process. */
320 service_fail_action
.lpCommand
= NULL
;
322 /* Number of elements in 'fail_actions'. */
323 service_fail_action
.cActions
= sizeof(fail_action
)/sizeof(fail_action
[0]);
325 /* A pointer to an array of SC_ACTION structures. */
326 service_fail_action
.lpsaActions
= fail_action
;
328 if (!ChangeServiceConfig2(service
, SERVICE_CONFIG_FAILURE_ACTIONS
,
329 &service_fail_action
)) {
330 char *msg_buf
= ovs_lasterror_to_string();
331 VLOG_FATAL("Failed to configure service fail actions (%s).", msg_buf
);
335 /* When a daemon is passed the --detach option, we create a new
336 * process and pass an additional non-documented option called --pipe-handle.
337 * Through this option, the parent passes one end of a pipe handle. */
339 set_pipe_handle(const char *pipe_handle
)
341 write_handle
= (HANDLE
) atoi(pipe_handle
);
344 /* If one of the command line option is "--detach", creates
345 * a new process in case of parent, waits for child to start and exits.
346 * In case of the child, returns. */
348 detach_process(int argc
, char *argv
[])
350 SECURITY_ATTRIBUTES sa
;
352 PROCESS_INFORMATION pi
;
353 HANDLE read_pipe
, write_pipe
;
358 /* We are only interested in the '--detach' and '--pipe-handle'. */
359 for (i
= 0; i
< argc
; i
++) {
360 if (!strcmp(argv
[i
], "--detach")) {
362 } else if (!strncmp(argv
[i
], "--pipe-handle", 13)) {
363 /* If running as a child, return. */
369 /* Nothing to do if the option --detach is not set. */
374 /* Set the security attribute such that a process created will
375 * inherit the pipe handles. */
376 sa
.nLength
= sizeof(sa
);
377 sa
.lpSecurityDescriptor
= NULL
;
378 sa
.bInheritHandle
= TRUE
;
380 /* Create an anonymous pipe to communicate with the child. */
381 error
= CreatePipe(&read_pipe
, &write_pipe
, &sa
, 0);
383 VLOG_FATAL("CreatePipe failed (%s)", ovs_lasterror_to_string());
388 /* To the child, we pass an extra argument '--pipe-handle=write_pipe' */
389 buffer
= xasprintf("%s %s=%ld", GetCommandLine(), "--pipe-handle",
392 /* Create a detached child */
393 error
= CreateProcess(NULL
, buffer
, NULL
, NULL
, TRUE
, DETACHED_PROCESS
,
394 NULL
, NULL
, &si
, &pi
);
396 VLOG_FATAL("CreateProcess failed (%s)", ovs_lasterror_to_string());
399 /* Close one end of the pipe in the parent. */
400 CloseHandle(write_pipe
);
402 /* Block and wait for child to say it is ready. */
403 error
= ReadFile(read_pipe
, &ch
, 1, NULL
, NULL
);
405 VLOG_FATAL("Failed to read from child (%s)",
406 ovs_lasterror_to_string());
408 /* The child has successfully started and is ready. */
413 flock(FILE* fd
, int operation
)
418 hFile
= (HANDLE
)_get_osfhandle(fileno(fd
));
419 if (hFile
== INVALID_HANDLE_VALUE
) {
420 VLOG_FATAL("Failed to get PID file handle (%s).",
421 ovs_strerror(errno
));
424 if (operation
& LOCK_UNLOCK
) {
425 if (UnlockFileEx(hFile
, 0, 1, 0, &ov
) == 0) {
426 VLOG_FATAL("Failed to unlock PID file (%s).",
427 ovs_lasterror_to_string());
430 /* Use LOCKFILE_FAIL_IMMEDIATELY flag to avoid hang of another daemon that tries to
431 acquire exclusive lock over the same PID file */
432 if (LockFileEx(hFile
, operation
| LOCKFILE_FAIL_IMMEDIATELY
,
433 0, 1, 0, &ov
) == FALSE
) {
434 VLOG_FATAL("Failed to lock PID file (%s).",
435 ovs_lasterror_to_string());
444 /* Remove the shared lock on file */
445 flock(filep_pidfile
, LOCK_UNLOCK
);
446 fclose(filep_pidfile
);
453 /* If a pidfile has been configured, creates it and stores the running
454 * process's pid in it. Ensures that the pidfile will be deleted when the
461 error
= GetFileAttributes(pidfile
);
462 if (error
!= INVALID_FILE_ATTRIBUTES
) {
463 /* pidfile exists. Try to unlink() it. */
464 error
= unlink(pidfile
);
466 VLOG_FATAL("Failed to delete existing pidfile %s (%s)", pidfile
,
467 ovs_strerror(errno
));
471 filep_pidfile
= fopen(pidfile
, "w");
472 if (filep_pidfile
== NULL
) {
473 VLOG_FATAL("failed to open %s (%s)", pidfile
, ovs_strerror(errno
));
476 flock(filep_pidfile
, LOCKFILE_EXCLUSIVE_LOCK
);
478 fatal_signal_add_hook(unlink_pidfile
, NULL
, NULL
, true);
480 fprintf(filep_pidfile
, "%ld\n", (long int) getpid());
481 if (fflush(filep_pidfile
) == EOF
) {
482 VLOG_FATAL("Failed to write into the pidfile %s", pidfile
);
485 flock(filep_pidfile
, LOCK_SHARED
);
486 /* This will remove the exclusive lock. The shared lock will remain */
487 flock(filep_pidfile
, LOCK_UNLOCK
);
489 /* Don't close the pidfile till the process exits. */
493 daemonize_start(bool access_datapath OVS_UNUSED
)
501 daemonize_complete(void)
503 /* If running as a child because '--detach' option was specified,
504 * communicate with the parent to inform that the child is ready. */
508 close_standard_fds();
510 error
= WriteFile(write_handle
, "a", 1, NULL
, NULL
);
512 VLOG_FATAL("Failed to communicate with the parent (%s)",
513 ovs_lasterror_to_string());
521 daemon_become_new_user(bool access_datapath OVS_UNUSED
)
525 /* Returns the file name that would be used for a pidfile if 'name' were
526 * provided to set_pidfile(). The caller must free the returned string. */
528 make_pidfile_name(const char *name
)
531 if (strchr(name
, ':')) {
532 return xstrdup(name
);
534 return xasprintf("%s/%s", ovs_rundir(), name
);
537 return xasprintf("%s/%s.pid", ovs_rundir(), program_name
);
542 daemon_set_new_user(const char *user_spec OVS_UNUSED
)
544 VLOG_FATAL("--user options is not currently supported.");