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(a)redhat.com>
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;
}
--