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