1 /*
2 * virnetdaemon.c
3 *
4 * Copyright (C) 2015 Red Hat, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library. If not, see
18 * <http://www.gnu.org/licenses/>.
19 */
20
21 #include <config.h>
22
23 #include <unistd.h>
24 #include <fcntl.h>
25
26 #include "virnetdaemon.h"
27 #include "virlog.h"
28 #include "viralloc.h"
29 #include "virerror.h"
30 #include "virthread.h"
31 #include "virthreadpool.h"
32 #include "virutil.h"
33 #include "virfile.h"
34 #include "virnetserver.h"
35 #include "virgdbus.h"
36 #include "virhash.h"
37 #include "virstring.h"
38 #include "virsystemd.h"
39
40 #define VIR_FROM_THIS VIR_FROM_RPC
41
42 VIR_LOG_INIT("rpc.netdaemon");
43
44 #ifndef WIN32
45 typedef struct _virNetDaemonSignal virNetDaemonSignal;
46 struct _virNetDaemonSignal {
47 struct sigaction oldaction;
48 int signum;
49 virNetDaemonSignalFunc func;
50 void *opaque;
51 };
52 #endif /* !WIN32 */
53
54 struct _virNetDaemon {
55 virObjectLockable parent;
56
57 bool privileged;
58
59 #ifndef WIN32
60 size_t nsignals;
61 virNetDaemonSignal **signals;
62 int sigread;
63 int sigwrite;
64 int sigwatch;
65 #endif /* !WIN32 */
66
67 GHashTable *servers;
68 virJSONValue *srvObject;
69
70 virNetDaemonShutdownCallback shutdownPrepareCb;
71 virNetDaemonShutdownCallback shutdownWaitCb;
72 virThread *stateStopThread;
73 int finishTimer;
74 bool quit;
75 bool finished;
76 bool graceful;
77 bool execRestart;
78
79 unsigned int autoShutdownTimeout;
80 size_t autoShutdownInhibitions;
81 int autoShutdownInhibitFd;
82 };
83
84
85 static virClass *virNetDaemonClass;
86
87 static int
88 daemonServerClose(void *payload,
89 const char *key G_GNUC_UNUSED,
90 void *opaque G_GNUC_UNUSED);
91
92 static void
virNetDaemonDispose(void * obj)93 virNetDaemonDispose(void *obj)
94 {
95 virNetDaemon *dmn = obj;
96 #ifndef WIN32
97 size_t i;
98
99 for (i = 0; i < dmn->nsignals; i++) {
100 sigaction(dmn->signals[i]->signum, &dmn->signals[i]->oldaction, NULL);
101 g_free(dmn->signals[i]);
102 }
103 g_free(dmn->signals);
104 VIR_FORCE_CLOSE(dmn->sigread);
105 VIR_FORCE_CLOSE(dmn->sigwrite);
106 if (dmn->sigwatch > 0)
107 virEventRemoveHandle(dmn->sigwatch);
108 #endif /* !WIN32 */
109
110 VIR_FORCE_CLOSE(dmn->autoShutdownInhibitFd);
111 g_free(dmn->stateStopThread);
112
113 virHashFree(dmn->servers);
114
115 virJSONValueFree(dmn->srvObject);
116 }
117
118 static int
virNetDaemonOnceInit(void)119 virNetDaemonOnceInit(void)
120 {
121 if (!VIR_CLASS_NEW(virNetDaemon, virClassForObjectLockable()))
122 return -1;
123
124 return 0;
125 }
126
127 VIR_ONCE_GLOBAL_INIT(virNetDaemon);
128
129
130 virNetDaemon *
virNetDaemonNew(void)131 virNetDaemonNew(void)
132 {
133 virNetDaemon *dmn;
134 #ifndef WIN32
135 struct sigaction sig_action;
136 #endif /* !WIN32 */
137
138 if (virNetDaemonInitialize() < 0)
139 return NULL;
140
141 if (!(dmn = virObjectLockableNew(virNetDaemonClass)))
142 return NULL;
143
144 dmn->servers = virHashNew(virObjectFreeHashData);
145
146 #ifndef WIN32
147 dmn->sigwrite = dmn->sigread = -1;
148 #endif /* !WIN32 */
149
150 dmn->privileged = geteuid() == 0;
151 dmn->autoShutdownInhibitFd = -1;
152
153 if (virEventRegisterDefaultImpl() < 0)
154 goto error;
155
156 #ifndef WIN32
157 memset(&sig_action, 0, sizeof(sig_action));
158 sig_action.sa_handler = SIG_IGN;
159 sigaction(SIGPIPE, &sig_action, NULL);
160 #endif /* !WIN32 */
161
162 return dmn;
163
164 error:
165 virObjectUnref(dmn);
166 return NULL;
167 }
168
169
170 int
virNetDaemonAddServer(virNetDaemon * dmn,virNetServer * srv)171 virNetDaemonAddServer(virNetDaemon *dmn,
172 virNetServer *srv)
173 {
174 int ret = -1;
175 const char *serverName = virNetServerGetName(srv);
176
177 virObjectLock(dmn);
178
179 if (virHashAddEntry(dmn->servers, serverName, srv) < 0)
180 goto cleanup;
181
182 virObjectRef(srv);
183
184 ret = 0;
185 cleanup:
186 virObjectUnlock(dmn);
187 return ret;
188 }
189
190
191 virNetServer *
virNetDaemonGetServer(virNetDaemon * dmn,const char * serverName)192 virNetDaemonGetServer(virNetDaemon *dmn,
193 const char *serverName)
194 {
195 virNetServer *srv = NULL;
196
197 virObjectLock(dmn);
198 srv = virObjectRef(virHashLookup(dmn->servers, serverName));
199 virObjectUnlock(dmn);
200
201 if (!srv) {
202 virReportError(VIR_ERR_NO_SERVER,
203 _("No server named '%s'"), serverName);
204 }
205
206 return srv;
207 }
208
209 bool
virNetDaemonHasServer(virNetDaemon * dmn,const char * serverName)210 virNetDaemonHasServer(virNetDaemon *dmn,
211 const char *serverName)
212 {
213 void *ent;
214
215 virObjectLock(dmn);
216 ent = virHashLookup(dmn->servers, serverName);
217 virObjectUnlock(dmn);
218
219 return ent != NULL;
220 }
221
222
223 struct collectData {
224 virNetServer ***servers;
225 size_t nservers;
226 };
227
228
229 static int
collectServers(void * payload,const char * name G_GNUC_UNUSED,void * opaque)230 collectServers(void *payload,
231 const char *name G_GNUC_UNUSED,
232 void *opaque)
233 {
234 virNetServer *srv = virObjectRef(payload);
235 struct collectData *data = opaque;
236
237 if (!srv)
238 return -1;
239
240 VIR_APPEND_ELEMENT(*data->servers, data->nservers, srv);
241
242 return 0;
243 }
244
245
246 /*
247 * Returns number of names allocated in *servers, on error sets
248 * *servers to NULL and returns -1. List of *servers must be free()d,
249 * but not the items in it (similarly to virHashGetItems).
250 */
251 ssize_t
virNetDaemonGetServers(virNetDaemon * dmn,virNetServer *** servers)252 virNetDaemonGetServers(virNetDaemon *dmn,
253 virNetServer ***servers)
254 {
255 struct collectData data = { servers, 0 };
256 ssize_t ret = -1;
257
258 *servers = NULL;
259
260 virObjectLock(dmn);
261
262 if (virHashForEach(dmn->servers, collectServers, &data) < 0) {
263 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
264 _("Cannot get all servers from daemon"));
265 goto cleanup;
266 }
267
268 ret = data.nservers;
269
270 cleanup:
271 if (ret < 0)
272 virObjectListFreeCount(*servers, data.nservers);
273 virObjectUnlock(dmn);
274 return ret;
275 }
276
277
278 struct virNetDaemonServerData {
279 virNetDaemon *dmn;
280 virNetDaemonNewServerPostExecRestart cb;
281 void *opaque;
282 };
283
284 static int
virNetDaemonServerIterator(const char * key,virJSONValue * value,void * opaque)285 virNetDaemonServerIterator(const char *key,
286 virJSONValue *value,
287 void *opaque)
288 {
289 struct virNetDaemonServerData *data = opaque;
290 virNetServer *srv;
291
292 VIR_DEBUG("Creating server '%s'", key);
293 srv = data->cb(data->dmn, key, value, data->opaque);
294 if (!srv)
295 return -1;
296
297 if (virHashAddEntry(data->dmn->servers, key, srv) < 0)
298 return -1;
299
300 return 0;
301 }
302
303
304 virNetDaemon *
virNetDaemonNewPostExecRestart(virJSONValue * object,size_t nDefServerNames,const char ** defServerNames,virNetDaemonNewServerPostExecRestart cb,void * opaque)305 virNetDaemonNewPostExecRestart(virJSONValue *object,
306 size_t nDefServerNames,
307 const char **defServerNames,
308 virNetDaemonNewServerPostExecRestart cb,
309 void *opaque)
310 {
311 virNetDaemon *dmn = NULL;
312 virJSONValue *servers = virJSONValueObjectGet(object, "servers");
313 bool new_version = virJSONValueObjectHasKey(object, "servers");
314
315 if (!(dmn = virNetDaemonNew()))
316 goto error;
317
318 if (new_version && !servers) {
319 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
320 _("Malformed servers data in JSON document"));
321 goto error;
322 }
323
324 if (!new_version) {
325 virNetServer *srv;
326
327 if (nDefServerNames < 1) {
328 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
329 _("No default server names provided"));
330 goto error;
331 }
332
333 VIR_DEBUG("No 'servers' data, creating default '%s' name", defServerNames[0]);
334
335 srv = cb(dmn, defServerNames[0], object, opaque);
336
337 if (virHashAddEntry(dmn->servers, defServerNames[0], srv) < 0)
338 goto error;
339 } else if (virJSONValueIsArray(servers)) {
340 size_t i;
341 size_t n = virJSONValueArraySize(servers);
342 if (n > nDefServerNames) {
343 virReportError(VIR_ERR_INTERNAL_ERROR,
344 _("Server count %zd greater than default name count %zu"),
345 n, nDefServerNames);
346 goto error;
347 }
348
349 for (i = 0; i < n; i++) {
350 virNetServer *srv;
351 virJSONValue *value = virJSONValueArrayGet(servers, i);
352
353 VIR_DEBUG("Creating server '%s'", defServerNames[i]);
354 srv = cb(dmn, defServerNames[i], value, opaque);
355 if (!srv)
356 goto error;
357
358 if (virHashAddEntry(dmn->servers, defServerNames[i], srv) < 0) {
359 virObjectUnref(srv);
360 goto error;
361 }
362 }
363 } else {
364 struct virNetDaemonServerData data = {
365 dmn,
366 cb,
367 opaque,
368 };
369 if (virJSONValueObjectForeachKeyValue(servers,
370 virNetDaemonServerIterator,
371 &data) < 0)
372 goto error;
373 }
374
375 return dmn;
376
377 error:
378 virObjectUnref(dmn);
379 return NULL;
380 }
381
382
383 virJSONValue *
virNetDaemonPreExecRestart(virNetDaemon * dmn)384 virNetDaemonPreExecRestart(virNetDaemon *dmn)
385 {
386 size_t i = 0;
387 g_autoptr(virJSONValue) object = virJSONValueNewObject();
388 g_autoptr(virJSONValue) srvObj = virJSONValueNewObject();
389 g_autofree virHashKeyValuePair *srvArray = NULL;
390
391 virObjectLock(dmn);
392
393 if (!(srvArray = virHashGetItems(dmn->servers, NULL, true)))
394 goto error;
395
396 for (i = 0; srvArray[i].key; i++) {
397 virNetServer *server = virHashLookup(dmn->servers, srvArray[i].key);
398 g_autoptr(virJSONValue) srvJSON = NULL;
399
400 if (!server)
401 goto error;
402
403 srvJSON = virNetServerPreExecRestart(server);
404 if (!srvJSON)
405 goto error;
406
407 if (virJSONValueObjectAppend(srvObj, srvArray[i].key, &srvJSON) < 0)
408 goto error;
409 }
410
411 virObjectUnlock(dmn);
412
413 if (virJSONValueObjectAppend(object, "servers", &srvObj) < 0)
414 return NULL;
415
416 return g_steal_pointer(&object);
417
418 error:
419 virObjectUnlock(dmn);
420 return NULL;
421 }
422
423
424 bool
virNetDaemonIsPrivileged(virNetDaemon * dmn)425 virNetDaemonIsPrivileged(virNetDaemon *dmn)
426 {
427 bool priv;
428 virObjectLock(dmn);
429 priv = dmn->privileged;
430 virObjectUnlock(dmn);
431 return priv;
432 }
433
434
435 void
virNetDaemonAutoShutdown(virNetDaemon * dmn,unsigned int timeout)436 virNetDaemonAutoShutdown(virNetDaemon *dmn,
437 unsigned int timeout)
438 {
439 virObjectLock(dmn);
440
441 dmn->autoShutdownTimeout = timeout;
442
443 virObjectUnlock(dmn);
444 }
445
446
447 #ifdef G_OS_UNIX
448 /* As per: https://www.freedesktop.org/wiki/Software/systemd/inhibit */
449 static void
virNetDaemonCallInhibit(virNetDaemon * dmn,const char * what,const char * who,const char * why,const char * mode)450 virNetDaemonCallInhibit(virNetDaemon *dmn,
451 const char *what,
452 const char *who,
453 const char *why,
454 const char *mode)
455 {
456 g_autoptr(GVariant) reply = NULL;
457 g_autoptr(GUnixFDList) replyFD = NULL;
458 g_autoptr(GVariant) message = NULL;
459 GDBusConnection *systemBus;
460 int fd;
461 int rc;
462
463 VIR_DEBUG("dmn=%p what=%s who=%s why=%s mode=%s",
464 dmn, NULLSTR(what), NULLSTR(who), NULLSTR(why), NULLSTR(mode));
465
466 if (virSystemdHasLogind() < 0)
467 return;
468
469 if (!(systemBus = virGDBusGetSystemBus()))
470 return;
471
472 message = g_variant_new("(ssss)", what, who, why, mode);
473
474 rc = virGDBusCallMethodWithFD(systemBus,
475 &reply,
476 G_VARIANT_TYPE("(h)"),
477 &replyFD,
478 NULL,
479 "org.freedesktop.login1",
480 "/org/freedesktop/login1",
481 "org.freedesktop.login1.Manager",
482 "Inhibit",
483 message,
484 NULL);
485
486 if (rc < 0)
487 return;
488
489 if (g_unix_fd_list_get_length(replyFD) <= 0)
490 return;
491
492 fd = g_unix_fd_list_get(replyFD, 0, NULL);
493 if (fd < 0)
494 return;
495
496 if (dmn->autoShutdownInhibitions) {
497 dmn->autoShutdownInhibitFd = fd;
498 VIR_DEBUG("Got inhibit FD %d", fd);
499 } else {
500 /* We stopped the last VM since we made the inhibit call */
501 VIR_DEBUG("Closing inhibit FD %d", fd);
502 VIR_FORCE_CLOSE(fd);
503 }
504 }
505 #endif
506
507 void
virNetDaemonAddShutdownInhibition(virNetDaemon * dmn)508 virNetDaemonAddShutdownInhibition(virNetDaemon *dmn)
509 {
510 virObjectLock(dmn);
511 dmn->autoShutdownInhibitions++;
512
513 VIR_DEBUG("dmn=%p inhibitions=%zu", dmn, dmn->autoShutdownInhibitions);
514
515 #ifdef G_OS_UNIX
516 if (dmn->autoShutdownInhibitions == 1)
517 virNetDaemonCallInhibit(dmn,
518 "shutdown",
519 _("Libvirt"),
520 _("Virtual machines need to be saved"),
521 "delay");
522 #endif
523
524 virObjectUnlock(dmn);
525 }
526
527
528 void
virNetDaemonRemoveShutdownInhibition(virNetDaemon * dmn)529 virNetDaemonRemoveShutdownInhibition(virNetDaemon *dmn)
530 {
531 virObjectLock(dmn);
532 dmn->autoShutdownInhibitions--;
533
534 VIR_DEBUG("dmn=%p inhibitions=%zu", dmn, dmn->autoShutdownInhibitions);
535
536 if (dmn->autoShutdownInhibitions == 0) {
537 VIR_DEBUG("Closing inhibit FD %d", dmn->autoShutdownInhibitFd);
538 VIR_FORCE_CLOSE(dmn->autoShutdownInhibitFd);
539 }
540
541 virObjectUnlock(dmn);
542 }
543
544
545 #ifndef WIN32
546 static sig_atomic_t sigErrors;
547 static int sigLastErrno;
548 static int sigWrite = -1;
549
550 static void
virNetDaemonSignalHandler(int sig,siginfo_t * siginfo,void * context G_GNUC_UNUSED)551 virNetDaemonSignalHandler(int sig, siginfo_t * siginfo,
552 void* context G_GNUC_UNUSED)
553 {
554 int origerrno;
555 int r;
556 siginfo_t tmp;
557
558 if (SA_SIGINFO)
559 tmp = *siginfo;
560 else
561 memset(&tmp, 0, sizeof(tmp));
562
563 /* set the sig num in the struct */
564 tmp.si_signo = sig;
565
566 origerrno = errno;
567 r = safewrite(sigWrite, &tmp, sizeof(tmp));
568 if (r == -1) {
569 sigErrors++;
570 sigLastErrno = errno;
571 }
572 errno = origerrno;
573 }
574
575 static void
virNetDaemonSignalEvent(int watch,int fd G_GNUC_UNUSED,int events G_GNUC_UNUSED,void * opaque)576 virNetDaemonSignalEvent(int watch,
577 int fd G_GNUC_UNUSED,
578 int events G_GNUC_UNUSED,
579 void *opaque)
580 {
581 virNetDaemon *dmn = opaque;
582 siginfo_t siginfo;
583 size_t i;
584
585 virObjectLock(dmn);
586
587 if (saferead(dmn->sigread, &siginfo, sizeof(siginfo)) != sizeof(siginfo)) {
588 virReportSystemError(errno, "%s",
589 _("Failed to read from signal pipe"));
590 virEventRemoveHandle(watch);
591 dmn->sigwatch = -1;
592 goto cleanup;
593 }
594
595 for (i = 0; i < dmn->nsignals; i++) {
596 if (siginfo.si_signo == dmn->signals[i]->signum) {
597 virNetDaemonSignalFunc func = dmn->signals[i]->func;
598 void *funcopaque = dmn->signals[i]->opaque;
599 virObjectUnlock(dmn);
600 func(dmn, &siginfo, funcopaque);
601 return;
602 }
603 }
604
605 virReportError(VIR_ERR_INTERNAL_ERROR,
606 _("Unexpected signal received: %d"), siginfo.si_signo);
607
608 cleanup:
609 virObjectUnlock(dmn);
610 }
611
612 static int
virNetDaemonSignalSetup(virNetDaemon * dmn)613 virNetDaemonSignalSetup(virNetDaemon *dmn)
614 {
615 int fds[2] = { -1, -1 };
616
617 if (dmn->sigwrite != -1)
618 return 0;
619
620 if (virPipeNonBlock(fds) < 0)
621 return -1;
622
623 if ((dmn->sigwatch = virEventAddHandle(fds[0],
624 VIR_EVENT_HANDLE_READABLE,
625 virNetDaemonSignalEvent,
626 dmn, NULL)) < 0) {
627 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
628 _("Failed to add signal handle watch"));
629 goto error;
630 }
631
632 dmn->sigread = fds[0];
633 dmn->sigwrite = fds[1];
634 sigWrite = fds[1];
635
636 return 0;
637
638 error:
639 VIR_FORCE_CLOSE(fds[0]);
640 VIR_FORCE_CLOSE(fds[1]);
641 return -1;
642 }
643
644
645 int
virNetDaemonAddSignalHandler(virNetDaemon * dmn,int signum,virNetDaemonSignalFunc func,void * opaque)646 virNetDaemonAddSignalHandler(virNetDaemon *dmn,
647 int signum,
648 virNetDaemonSignalFunc func,
649 void *opaque)
650 {
651 virNetDaemonSignal *sigdata = NULL;
652 struct sigaction sig_action;
653
654 virObjectLock(dmn);
655
656 if (virNetDaemonSignalSetup(dmn) < 0)
657 goto error;
658
659 VIR_EXPAND_N(dmn->signals, dmn->nsignals, 1);
660
661 sigdata = g_new0(virNetDaemonSignal, 1);
662
663 sigdata->signum = signum;
664 sigdata->func = func;
665 sigdata->opaque = opaque;
666
667 memset(&sig_action, 0, sizeof(sig_action));
668 sig_action.sa_sigaction = virNetDaemonSignalHandler;
669 sig_action.sa_flags = SA_SIGINFO;
670 sigemptyset(&sig_action.sa_mask);
671
672 sigaction(signum, &sig_action, &sigdata->oldaction);
673
674 dmn->signals[dmn->nsignals-1] = sigdata;
675
676 virObjectUnlock(dmn);
677 return 0;
678
679 error:
680 VIR_FREE(sigdata);
681 virObjectUnlock(dmn);
682 return -1;
683 }
684
685 #else /* WIN32 */
686
687 int
virNetDaemonAddSignalHandler(virNetDaemon * dmn G_GNUC_UNUSED,int signum G_GNUC_UNUSED,virNetDaemonSignalFunc func G_GNUC_UNUSED,void * opaque G_GNUC_UNUSED)688 virNetDaemonAddSignalHandler(virNetDaemon *dmn G_GNUC_UNUSED,
689 int signum G_GNUC_UNUSED,
690 virNetDaemonSignalFunc func G_GNUC_UNUSED,
691 void *opaque G_GNUC_UNUSED)
692 {
693 virReportSystemError(ENOSYS, "%s",
694 _("Signal handling not available on this platform"));
695 return -1;
696 }
697
698 #endif /* WIN32 */
699
700
701 static void
virNetDaemonAutoShutdownTimer(int timerid G_GNUC_UNUSED,void * opaque)702 virNetDaemonAutoShutdownTimer(int timerid G_GNUC_UNUSED,
703 void *opaque)
704 {
705 virNetDaemon *dmn = opaque;
706
707 virObjectLock(dmn);
708
709 if (!dmn->autoShutdownInhibitions) {
710 VIR_DEBUG("Automatic shutdown triggered");
711 dmn->quit = true;
712 }
713
714 virObjectUnlock(dmn);
715 }
716
717 static int
daemonServerUpdateServices(void * payload,const char * key G_GNUC_UNUSED,void * opaque)718 daemonServerUpdateServices(void *payload,
719 const char *key G_GNUC_UNUSED,
720 void *opaque)
721 {
722 bool *enable = opaque;
723 virNetServer *srv = payload;
724
725 virNetServerUpdateServices(srv, *enable);
726 return 0;
727 }
728
729 void
virNetDaemonUpdateServices(virNetDaemon * dmn,bool enabled)730 virNetDaemonUpdateServices(virNetDaemon *dmn,
731 bool enabled)
732 {
733 virObjectLock(dmn);
734 virHashForEach(dmn->servers, daemonServerUpdateServices, &enabled);
735 virObjectUnlock(dmn);
736 }
737
738 static int
daemonServerProcessClients(void * payload,const char * key G_GNUC_UNUSED,void * opaque G_GNUC_UNUSED)739 daemonServerProcessClients(void *payload,
740 const char *key G_GNUC_UNUSED,
741 void *opaque G_GNUC_UNUSED)
742 {
743 virNetServer *srv = payload;
744
745 virNetServerProcessClients(srv);
746 return 0;
747 }
748
749 static int
daemonServerShutdownWait(void * payload,const char * key G_GNUC_UNUSED,void * opaque G_GNUC_UNUSED)750 daemonServerShutdownWait(void *payload,
751 const char *key G_GNUC_UNUSED,
752 void *opaque G_GNUC_UNUSED)
753 {
754 virNetServer *srv = payload;
755
756 virNetServerShutdownWait(srv);
757 return 0;
758 }
759
760 static void
daemonShutdownWait(void * opaque)761 daemonShutdownWait(void *opaque)
762 {
763 virNetDaemon *dmn = opaque;
764 bool graceful = false;
765
766 virHashForEach(dmn->servers, daemonServerShutdownWait, NULL);
767 if (dmn->shutdownWaitCb && dmn->shutdownWaitCb() < 0)
768 goto finish;
769
770 if (dmn->stateStopThread)
771 virThreadJoin(dmn->stateStopThread);
772
773 graceful = true;
774
775 finish:
776 virObjectLock(dmn);
777 dmn->graceful = graceful;
778 virEventUpdateTimeout(dmn->finishTimer, 0);
779 virObjectUnlock(dmn);
780 }
781
782 static void
virNetDaemonFinishTimer(int timerid G_GNUC_UNUSED,void * opaque)783 virNetDaemonFinishTimer(int timerid G_GNUC_UNUSED,
784 void *opaque)
785 {
786 virNetDaemon *dmn = opaque;
787
788 virObjectLock(dmn);
789 dmn->finished = true;
790 virObjectUnlock(dmn);
791 }
792
793 void
virNetDaemonRun(virNetDaemon * dmn)794 virNetDaemonRun(virNetDaemon *dmn)
795 {
796 int timerid = -1;
797 bool timerActive = false;
798 virThread shutdownThread;
799
800 virObjectLock(dmn);
801
802 if (dmn->srvObject) {
803 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
804 _("Not all servers restored, cannot run server"));
805 goto cleanup;
806 }
807
808 dmn->quit = false;
809 dmn->finishTimer = -1;
810 dmn->finished = false;
811 dmn->graceful = false;
812
813 if (dmn->autoShutdownTimeout &&
814 (timerid = virEventAddTimeout(-1,
815 virNetDaemonAutoShutdownTimer,
816 dmn, NULL)) < 0) {
817 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
818 _("Failed to register shutdown timeout"));
819 goto cleanup;
820 }
821
822 /* We are accepting connections now. Notify systemd
823 * so it can start dependent services. */
824 virSystemdNotifyStartup();
825
826 VIR_DEBUG("dmn=%p quit=%d", dmn, dmn->quit);
827 while (!dmn->finished) {
828 /* A shutdown timeout is specified, so check
829 * if any drivers have active state, if not
830 * shutdown after timeout seconds
831 */
832 if (dmn->autoShutdownTimeout) {
833 if (timerActive) {
834 if (virNetDaemonHasClients(dmn)) {
835 VIR_DEBUG("Deactivating shutdown timer %d", timerid);
836 virEventUpdateTimeout(timerid, -1);
837 timerActive = false;
838 }
839 } else {
840 if (!virNetDaemonHasClients(dmn)) {
841 VIR_DEBUG("Activating shutdown timer %d", timerid);
842 virEventUpdateTimeout(timerid,
843 dmn->autoShutdownTimeout * 1000);
844 timerActive = true;
845 }
846 }
847 }
848
849 virObjectUnlock(dmn);
850 if (virEventRunDefaultImpl() < 0) {
851 virObjectLock(dmn);
852 VIR_DEBUG("Loop iteration error, exiting");
853 break;
854 }
855 virObjectLock(dmn);
856
857 virHashForEach(dmn->servers, daemonServerProcessClients, NULL);
858
859 /* don't shutdown services when performing an exec-restart */
860 if (dmn->quit && dmn->execRestart)
861 goto cleanup;
862
863 if (dmn->quit && dmn->finishTimer == -1) {
864 virHashForEach(dmn->servers, daemonServerClose, NULL);
865 if (dmn->shutdownPrepareCb && dmn->shutdownPrepareCb() < 0)
866 break;
867
868 if ((dmn->finishTimer = virEventAddTimeout(30 * 1000,
869 virNetDaemonFinishTimer,
870 dmn, NULL)) < 0) {
871 VIR_WARN("Failed to register finish timer.");
872 break;
873 }
874
875 if (virThreadCreateFull(&shutdownThread, true, daemonShutdownWait,
876 "daemon-shutdown", false, dmn) < 0) {
877 VIR_WARN("Failed to register join thread.");
878 break;
879 }
880 }
881 }
882
883 if (dmn->graceful) {
884 virThreadJoin(&shutdownThread);
885 } else {
886 VIR_WARN("Make forcefull daemon shutdown");
887 exit(EXIT_FAILURE);
888 }
889
890 cleanup:
891 virObjectUnlock(dmn);
892 }
893
894
895 void
virNetDaemonSetStateStopWorkerThread(virNetDaemon * dmn,virThread ** thr)896 virNetDaemonSetStateStopWorkerThread(virNetDaemon *dmn,
897 virThread **thr)
898 {
899 virObjectLock(dmn);
900
901 VIR_DEBUG("Setting state stop worker thread on dmn=%p to thr=%p", dmn, thr);
902 dmn->stateStopThread = g_steal_pointer(thr);
903 virObjectUnlock(dmn);
904 }
905
906
907 void
virNetDaemonQuit(virNetDaemon * dmn)908 virNetDaemonQuit(virNetDaemon *dmn)
909 {
910 virObjectLock(dmn);
911
912 VIR_DEBUG("Quit requested %p", dmn);
913 dmn->quit = true;
914
915 virObjectUnlock(dmn);
916 }
917
918
919 void
virNetDaemonQuitExecRestart(virNetDaemon * dmn)920 virNetDaemonQuitExecRestart(virNetDaemon *dmn)
921 {
922 virObjectLock(dmn);
923
924 VIR_DEBUG("Exec-restart requested %p", dmn);
925 dmn->quit = true;
926 dmn->execRestart = true;
927
928 virObjectUnlock(dmn);
929 }
930
931
932 static int
daemonServerClose(void * payload,const char * key G_GNUC_UNUSED,void * opaque G_GNUC_UNUSED)933 daemonServerClose(void *payload,
934 const char *key G_GNUC_UNUSED,
935 void *opaque G_GNUC_UNUSED)
936 {
937 virNetServer *srv = payload;
938
939 virNetServerClose(srv);
940 return 0;
941 }
942
943 static int
daemonServerHasClients(void * payload,const char * key G_GNUC_UNUSED,void * opaque)944 daemonServerHasClients(void *payload,
945 const char *key G_GNUC_UNUSED,
946 void *opaque)
947 {
948 bool *clients = opaque;
949 virNetServer *srv = payload;
950
951 if (virNetServerHasClients(srv))
952 *clients = true;
953
954 return 0;
955 }
956
957 bool
virNetDaemonHasClients(virNetDaemon * dmn)958 virNetDaemonHasClients(virNetDaemon *dmn)
959 {
960 bool ret = false;
961
962 virHashForEach(dmn->servers, daemonServerHasClients, &ret);
963
964 return ret;
965 }
966
967 void
virNetDaemonSetShutdownCallbacks(virNetDaemon * dmn,virNetDaemonShutdownCallback prepareCb,virNetDaemonShutdownCallback waitCb)968 virNetDaemonSetShutdownCallbacks(virNetDaemon *dmn,
969 virNetDaemonShutdownCallback prepareCb,
970 virNetDaemonShutdownCallback waitCb)
971 {
972 virObjectLock(dmn);
973
974 dmn->shutdownPrepareCb = prepareCb;
975 dmn->shutdownWaitCb = waitCb;
976
977 virObjectUnlock(dmn);
978 }
979