Handle SIGHUP by shutting down all guests and networks and re-loading configs Handle SIGTERM/SIGINT by cleanly shutting down Signed-off-by: Mark McLoughlin <markmc@xxxxxxxxxx> Index: libvirt/qemud/internal.h =================================================================== --- libvirt.orig/qemud/internal.h +++ libvirt/qemud/internal.h @@ -275,6 +275,7 @@ struct qemud_server { int qemuVersion; int nclients; struct qemud_client *clients; + int sigread; int nvmfds; int nactivevms; struct qemud_vm *activevms; @@ -291,6 +292,7 @@ struct qemud_server { char networkConfigDir[PATH_MAX]; char errorMessage[QEMUD_MAX_ERROR_LEN]; int errorCode; + unsigned int shutdown : 1; }; int qemudStartVMDaemon(struct qemud_server *server, Index: libvirt/qemud/qemud.c =================================================================== --- libvirt.orig/qemud/qemud.c +++ libvirt/qemud/qemud.c @@ -52,9 +52,85 @@ #include "conf.h" #include "iptables.h" -static void reapchild(int sig ATTRIBUTE_UNUSED) { - /* We explicitly waitpid the child later */ +static int sigwrite = -1; + +static void sig_handler(int sig) { + unsigned char sigc = sig; + int origerrno; + + if (sig == SIGCHLD) /* We explicitly waitpid the child later */ + return; + + origerrno = errno; + write(sigwrite, &sigc, 1); + errno = origerrno; +} + +static int qemudDispatchSignal(struct qemud_server *server) +{ + unsigned char sigc; + struct qemud_vm *vm; + struct qemud_network *network; + int ret; + + if (read(server->sigread, &sigc, 1) != 1) + return -1; + + /* shutdown active VMs */ + vm = server->activevms; + while (vm) { + struct qemud_vm *next = vm->next; + qemudShutdownVMDaemon(server, vm); + vm = next; + } + + /* free inactive VMs */ + vm = server->inactivevms; + while (vm) { + struct qemud_vm *next = vm->next; + qemudFreeVM(vm); + vm = next; + } + server->inactivevms = NULL; + server->ninactivevms = 0; + + /* shutdown active networks */ + network = server->activenetworks; + while (network) { + struct qemud_network *next = network->next; + qemudShutdownNetworkDaemon(server, network); + network = next; + } + + /* free inactive networks */ + network = server->inactivenetworks; + while (network) { + struct qemud_network *next = network->next; + qemudFreeNetwork(network); + network = next; + } + server->inactivenetworks = NULL; + server->ninactivenetworks = 0; + + ret = 0; + + switch (sigc) { + case SIGHUP: + ret = qemudScanConfigs(server); + break; + + case SIGINT: + case SIGTERM: + server->shutdown = 1; + break; + + default: + break; + } + + return ret; } + static int qemudSetCloseExec(int fd) { int flags; if ((flags = fcntl(fd, F_GETFD)) < 0) { @@ -230,7 +306,7 @@ static int qemudListen(struct qemud_serv return 0; } -static struct qemud_server *qemudInitialize(int sys) { +static struct qemud_server *qemudInitialize(int sys, int sigread) { struct qemud_server *server; char libvirtConf[PATH_MAX]; @@ -241,6 +317,7 @@ static struct qemud_server *qemudInitial server->qemuVersion = (0*1000000)+(8*1000)+(0); /* We don't have a dom-0, so start from 1 */ server->nextvmid = 1; + server->sigread = sigread; if (sys) { if (snprintf(libvirtConf, sizeof(libvirtConf), "%s/libvirt", SYSCONF_DIR) >= (int)sizeof(libvirtConf)) { @@ -1141,6 +1218,12 @@ static int qemudDispatchPoll(struct qemu int ret = 0; int fd = 0; + if (fds[fd++].revents && qemudDispatchSignal(server) < 0) + return -1; + + if (server->shutdown) + return 0; + while (sock) { struct qemud_socket *next = sock->next; if (fds[fd].revents) @@ -1249,6 +1332,10 @@ static void qemudPreparePoll(struct qemu struct qemud_client *client; struct qemud_vm *vm; + fds[fd].fd = server->sigread; + fds[fd].events = POLLIN; + fd++; + for (sock = server->sockets ; sock ; sock = sock->next) { fds[fd].fd = sock->fd; fds[fd].events = POLLIN; @@ -1282,7 +1369,7 @@ static void qemudPreparePoll(struct qemu static int qemudOneLoop(struct qemud_server *server, int timeout) { - int nfds = server->nsockets + server->nclients + server->nvmfds; + int nfds = server->nsockets + server->nclients + server->nvmfds + 1; /* server->sigread */ struct pollfd fds[nfds]; int thistimeout = -1; int ret; @@ -1318,7 +1405,7 @@ static int qemudOneLoop(struct qemud_ser static int qemudRunLoop(struct qemud_server *server, int timeout) { int ret; - while ((ret = qemudOneLoop(server, timeout)) == 0) + while ((ret = qemudOneLoop(server, timeout)) == 0 && !server->shutdown) ; return ret == -1 ? -1 : 0; @@ -1326,6 +1413,7 @@ static int qemudRunLoop(struct qemud_ser static void qemudCleanup(struct qemud_server *server) { struct qemud_socket *sock = server->sockets; + close(server->sigread); while (sock) { close(sock->fd); sock = sock->next; @@ -1344,6 +1432,8 @@ int main(int argc, char **argv) { int sys = 0; int timeout = -1; struct qemud_server *server; + struct sigaction sig_action; + int sigpipe[2]; struct option opts[] = { { "verbose", no_argument, &verbose, 1}, @@ -1394,10 +1484,24 @@ int main(int argc, char **argv) { } } - if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) - return 3; - if (signal(SIGCHLD, reapchild) == SIG_ERR) - return 3; + if (pipe(sigpipe) < 0 || + qemudSetNonBlock(sigpipe[0]) < 0 || + qemudSetNonBlock(sigpipe[1]) < 0) + return 1; + + sigwrite = sigpipe[1]; + + sig_action.sa_handler = sig_handler; + sig_action.sa_flags = 0; + sigemptyset(&sig_action.sa_mask); + + sigaction(SIGHUP, &sig_action, NULL); + sigaction(SIGINT, &sig_action, NULL); + sigaction(SIGTERM, &sig_action, NULL); + sigaction(SIGCHLD, &sig_action, NULL); + + sig_action.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &sig_action, NULL); if (godaemon) { int pid = qemudGoDaemon(); @@ -1407,13 +1511,15 @@ int main(int argc, char **argv) { return 0; } - if (!(server = qemudInitialize(sys))) + if (!(server = qemudInitialize(sys, sigpipe[0]))) return 2; qemudRunLoop(server, timeout); qemudCleanup(server); + close(sigwrite); + return 0; } --