]> git.proxmox.com Git - ovs.git/blame - lib/daemon-windows.c
compat: Add ipv6 GRE and IPV6 Tunneling
[ovs.git] / lib / daemon-windows.c
CommitLineData
fda546bd 1/*
133fb2c7 2 * Copyright (c) 2014, 2017 Nicira, Inc.
fda546bd
GS
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"
3834bcf2 19#include "daemon-private.h"
fda546bd 20#include <stdio.h>
568b9dc8 21#include <io.h>
fda546bd 22#include <stdlib.h>
133fb2c7 23#include <unistd.h>
3f97b664 24#include "dirs.h"
133fb2c7 25#include "fatal-signal.h"
94a72fd6 26#include "ovs-thread.h"
fd016ae3 27#include "openvswitch/poll-loop.h"
e6211adc 28#include "openvswitch/vlog.h"
fda546bd 29
a91dc444 30VLOG_DEFINE_THIS_MODULE(daemon_windows);
fda546bd 31
568b9dc8
PB
32/* Constants for flock function */
33#define LOCK_SHARED 0x0 /* Shared lock. */
34#define LOCK_UNLOCK 0x80000000 /* Unlock. Custom value. */
35
69b17834
GS
36static bool service_create; /* Was --service specified? */
37static bool service_started; /* Have we dispatched service to start? */
fda546bd
GS
38
39/* --service-monitor: Should the service be restarted if it dies
40 * unexpectedly? */
41static bool monitor;
42
3834bcf2
GS
43bool detach; /* Was --detach specified? */
44static bool detached; /* Running as the child process. */
45static HANDLE write_handle; /* End of pipe to write to parent. */
4ec4776c 46
3834bcf2
GS
47char *pidfile; /* --pidfile: Name of pidfile (null if none). */
48static FILE *filep_pidfile; /* File pointer to access the pidfile. */
a9e9db79 49
fda546bd
GS
50/* Handle to the Services Manager and the created service. */
51static SC_HANDLE manager, service;
52
53/* Handle to the status information structure for the current service. */
54static SERVICE_STATUS_HANDLE hstatus;
55
56/* Hold the service's current status. */
57static SERVICE_STATUS service_status;
58
59/* Handle to an event object used to wakeup from poll_block(). */
60static HANDLE wevent;
61
62/* Hold the arguments sent to the main function. */
63static int sargc;
64static char ***sargvp;
65
66static void check_service(void);
67static void handle_scm_callback(void);
68static void init_service_status(void);
69static void set_config_failure_actions(void);
70
4ec4776c
GS
71static bool detach_process(int argc, char *argv[]);
72
fda546bd
GS
73extern int main(int argc, char *argv[]);
74
75void
76daemon_usage(void)
77{
78 printf(
79 "\nService options:\n"
80 " --service run in background as a service.\n"
81 " --service-monitor restart the service in case of an "
1b92d314 82 "unexpected failure. \n");
fda546bd
GS
83}
84
85/* Registers the call-back and configures the actions in case of a failure
86 * with the Windows services manager. */
87void
88service_start(int *argcp, char **argvp[])
89{
90 int argc = *argcp;
91 char **argv = *argvp;
92 int i;
93 SERVICE_TABLE_ENTRY service_table[] = {
94 {(LPTSTR)program_name, (LPSERVICE_MAIN_FUNCTION)main},
95 {NULL, NULL}
96 };
97
4ec4776c
GS
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)) {
103 return;
104 }
105
69b17834
GS
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) {
fda546bd
GS
110 init_service_status();
111
112 wevent = CreateEvent(NULL, TRUE, FALSE, NULL);
113 if (!wevent) {
114 char *msg_buf = ovs_lasterror_to_string();
115 VLOG_FATAL("Failed to create a event (%s).", msg_buf);
116 }
117
1ca3348e 118 poll_wevent_wait(wevent);
fda546bd
GS
119
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);
124 if (!hstatus) {
125 char *msg_buf = ovs_lasterror_to_string();
126 VLOG_FATAL("Failed to register the service control handler (%s).",
127 msg_buf);
128 }
129
130 if (monitor) {
131 set_config_failure_actions();
132 }
133
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
137 * time. */
138 *argcp = sargc;
139 *argvp = *sargvp;
140
44820d2a
AGS
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. */
145 SetErrorMode(0);
146
fda546bd
GS
147 return;
148 }
149
150 assert_single_threaded();
151
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. */
154 sargc = argc;
155 sargvp = argvp;
156
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")) {
69b17834 161 service_create = true;
fda546bd
GS
162 } else if (!strcmp(argv[i], "--service-monitor")) {
163 monitor = true;
164 }
165 }
166
167 /* If '--service' is not a command line option, run in foreground. */
69b17834 168 if (!service_create) {
fda546bd
GS
169 return;
170 }
171
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
174 * script. */
175 check_service();
176
69b17834 177 service_started = true;
fda546bd
GS
178
179 /* StartServiceCtrlDispatcher blocks and returns after the service is
180 * stopped. */
181 if (!StartServiceCtrlDispatcher(service_table)) {
182 char *msg_buf = ovs_lasterror_to_string();
183 VLOG_FATAL("Failed at StartServiceCtrlDispatcher (%s)", msg_buf);
184 }
185 exit(0);
186}
187
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. */
191void
192control_handler(DWORD request)
193{
194 switch (request) {
195 case SERVICE_CONTROL_STOP:
196 case SERVICE_CONTROL_SHUTDOWN:
197 service_status.dwCurrentState = SERVICE_STOPPED;
198 service_status.dwWin32ExitCode = NO_ERROR;
199 SetEvent(wevent);
e2d12c07 200 SetServiceStatus(hstatus, &service_status);
fda546bd
GS
201 break;
202
203 default:
204 break;
205 }
206}
207
208/* Return 'true' if the Windows services manager has called the
209 * control_handler() and asked the program to terminate. */
210bool
211should_service_stop(void)
212{
69b17834 213 if (service_started) {
fda546bd
GS
214 if (service_status.dwCurrentState != SERVICE_RUNNING) {
215 return true;
216 } else {
1ca3348e 217 poll_wevent_wait(wevent);
fda546bd
GS
218 }
219 }
220 return false;
221}
222
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. */
226void
227service_stop()
228{
02a514ef
GS
229 if (!service_started) {
230 return;
231 }
232 fatal_signal_atexit_handler();
233
fda546bd
GS
234 ResetEvent(wevent);
235 CloseHandle(wevent);
236
237 service_status.dwCurrentState = SERVICE_STOPPED;
238 service_status.dwWin32ExitCode = NO_ERROR;
239 SetServiceStatus(hstatus, &service_status);
240}
241
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 .*/
245static void
246service_complete(void)
247{
248 if (hstatus) {
249 SetServiceStatus(hstatus, &service_status);
250 }
251}
252
253/* Check whether 'program_name' has been created as a service. */
254static void
255check_service()
256{
257 /* Establish a connection to the local service control manager. */
258 manager = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
259 if (!manager) {
260 char *msg_buf = ovs_lasterror_to_string();
261 VLOG_FATAL("Failed to open the service control manager (%s).",
262 msg_buf);
263 }
264
265 service = OpenService(manager, program_name, SERVICE_ALL_ACCESS);
266 if (!service) {
267 char *msg_buf = ovs_lasterror_to_string();
268 VLOG_FATAL("Failed to open service (%s).", msg_buf);
269 }
270}
271
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(). */
275static void
276init_service_status()
277{
278 /* The service runs in its own process. */
279 service_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
280
281 /* The control codes the service accepts. */
282 service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP |
283 SERVICE_ACCEPT_SHUTDOWN;
284
285 /* Initialize the current state as SERVICE_RUNNING. */
286 service_status.dwCurrentState = SERVICE_RUNNING;
287
288 /* The exit code to indicate if there was an error. */
289 service_status.dwWin32ExitCode = NO_ERROR;
290
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;
294
295 /* The estimated time required for the stop operation in ms. */
296 service_status.dwWaitHint = 1000;
297}
298
299/* In case of an unexpected termination, configure the action to be
300 * taken. */
301static void
302set_config_failure_actions()
303{
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},
309 {SC_ACTION_NONE, 0}
310 };
311 SERVICE_FAILURE_ACTIONS service_fail_action;
312
313 /* Reset failure count after (in seconds). */
314 service_fail_action.dwResetPeriod = 10;
315
316 /* Reboot message. */
317 service_fail_action.lpRebootMsg = NULL;
318
319 /* The command line of the process. */
320 service_fail_action.lpCommand = NULL;
321
322 /* Number of elements in 'fail_actions'. */
323 service_fail_action.cActions = sizeof(fail_action)/sizeof(fail_action[0]);
324
325 /* A pointer to an array of SC_ACTION structures. */
326 service_fail_action.lpsaActions = fail_action;
327
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);
332 }
333}
334
4ec4776c
GS
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. */
338void
339set_pipe_handle(const char *pipe_handle)
340{
341 write_handle = (HANDLE) atoi(pipe_handle);
342}
343
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. */
347static bool
348detach_process(int argc, char *argv[])
349{
350 SECURITY_ATTRIBUTES sa;
351 STARTUPINFO si;
352 PROCESS_INFORMATION pi;
353 HANDLE read_pipe, write_pipe;
354 char *buffer;
355 int error, i;
356 char ch;
357
358 /* We are only interested in the '--detach' and '--pipe-handle'. */
359 for (i = 0; i < argc; i ++) {
360 if (!strcmp(argv[i], "--detach")) {
361 detach = true;
362 } else if (!strncmp(argv[i], "--pipe-handle", 13)) {
363 /* If running as a child, return. */
364 detached = true;
365 return true;
366 }
367 }
368
369 /* Nothing to do if the option --detach is not set. */
370 if (!detach) {
371 return false;
372 }
373
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;
379
380 /* Create an anonymous pipe to communicate with the child. */
381 error = CreatePipe(&read_pipe, &write_pipe, &sa, 0);
382 if (!error) {
383 VLOG_FATAL("CreatePipe failed (%s)", ovs_lasterror_to_string());
384 }
385
386 GetStartupInfo(&si);
387
388 /* To the child, we pass an extra argument '--pipe-handle=write_pipe' */
389 buffer = xasprintf("%s %s=%ld", GetCommandLine(), "--pipe-handle",
390 write_pipe);
391
392 /* Create a detached child */
393 error = CreateProcess(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS,
394 NULL, NULL, &si, &pi);
395 if (!error) {
396 VLOG_FATAL("CreateProcess failed (%s)", ovs_lasterror_to_string());
397 }
398
399 /* Close one end of the pipe in the parent. */
400 CloseHandle(write_pipe);
401
402 /* Block and wait for child to say it is ready. */
403 error = ReadFile(read_pipe, &ch, 1, NULL, NULL);
404 if (!error) {
405 VLOG_FATAL("Failed to read from child (%s)",
406 ovs_lasterror_to_string());
407 }
408 /* The child has successfully started and is ready. */
409 exit(0);
410}
411
568b9dc8
PB
412static void
413flock(FILE* fd, int operation)
414{
415 HANDLE hFile;
416 OVERLAPPED ov = {0};
417
418 hFile = (HANDLE)_get_osfhandle(fileno(fd));
419 if (hFile == INVALID_HANDLE_VALUE) {
420 VLOG_FATAL("Failed to get PID file handle (%s).",
9364ae65 421 ovs_strerror(errno));
568b9dc8
PB
422 }
423
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());
428 }
429 } else {
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());
436 }
437 }
438}
439
a9e9db79
GS
440static void
441unlink_pidfile(void)
442{
443 if (filep_pidfile) {
568b9dc8
PB
444 /* Remove the shared lock on file */
445 flock(filep_pidfile, LOCK_UNLOCK);
a9e9db79
GS
446 fclose(filep_pidfile);
447 }
448 if (pidfile) {
449 unlink(pidfile);
450 }
451}
452
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
455 * process exits. */
456static void
457make_pidfile(void)
458{
459 int error;
460
461 error = GetFileAttributes(pidfile);
462 if (error != INVALID_FILE_ATTRIBUTES) {
463 /* pidfile exists. Try to unlink() it. */
464 error = unlink(pidfile);
465 if (error) {
466 VLOG_FATAL("Failed to delete existing pidfile %s (%s)", pidfile,
467 ovs_strerror(errno));
468 }
469 }
470
471 filep_pidfile = fopen(pidfile, "w");
472 if (filep_pidfile == NULL) {
473 VLOG_FATAL("failed to open %s (%s)", pidfile, ovs_strerror(errno));
474 }
475
568b9dc8
PB
476 flock(filep_pidfile, LOCKFILE_EXCLUSIVE_LOCK);
477
a9e9db79
GS
478 fatal_signal_add_hook(unlink_pidfile, NULL, NULL, true);
479
133fb2c7 480 fprintf(filep_pidfile, "%ld\n", (long int) getpid());
a9e9db79
GS
481 if (fflush(filep_pidfile) == EOF) {
482 VLOG_FATAL("Failed to write into the pidfile %s", pidfile);
483 }
484
568b9dc8
PB
485 flock(filep_pidfile, LOCK_SHARED);
486 /* This will remove the exclusive lock. The shared lock will remain */
487 flock(filep_pidfile, LOCK_UNLOCK);
488
a9e9db79 489 /* Don't close the pidfile till the process exits. */
fda546bd
GS
490}
491
e91b927d
AZ
492void
493daemonize_start(bool access_datapath OVS_UNUSED)
fda546bd 494{
a9e9db79
GS
495 if (pidfile) {
496 make_pidfile();
497 }
fda546bd
GS
498}
499
500void
501daemonize_complete(void)
502{
4ec4776c
GS
503 /* If running as a child because '--detach' option was specified,
504 * communicate with the parent to inform that the child is ready. */
505 if (detached) {
506 int error;
d6bc33f3
GS
507
508 close_standard_fds();
509
4ec4776c
GS
510 error = WriteFile(write_handle, "a", 1, NULL, NULL);
511 if (!error) {
512 VLOG_FATAL("Failed to communicate with the parent (%s)",
513 ovs_lasterror_to_string());
514 }
515 }
516
fda546bd
GS
517 service_complete();
518}
a9e9db79 519
e91b927d
AZ
520void
521daemon_become_new_user(bool access_datapath OVS_UNUSED)
522{
523}
524
a9e9db79
GS
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. */
3834bcf2 527char *
a9e9db79
GS
528make_pidfile_name(const char *name)
529{
5b73d2c0
PB
530 if (name) {
531 if (strchr(name, ':')) {
532 return xstrdup(name);
533 } else {
534 return xasprintf("%s/%s", ovs_rundir(), name);
535 }
a9e9db79
GS
536 } else {
537 return xasprintf("%s/%s.pid", ovs_rundir(), program_name);
538 }
539}
e91b927d
AZ
540
541void
542daemon_set_new_user(const char *user_spec OVS_UNUSED)
543{
544 VLOG_FATAL("--user options is not currently supported.");
545}