static sig_atomic_t sig_errors = 0;
static int sig_lasterrno = 0;
-static void sig_handler(int sig) {
- unsigned char sigc = sig;
+static void sig_handler(int sig, siginfo_t * siginfo,
+ void* context ATTRIBUTE_UNUSED) {
int origerrno;
int r;
- if (sig == SIGCHLD) /* We explicitly waitpid the child later */
- return;
+ /* set the sig num in the struct */
+ siginfo->si_signo = sig;
origerrno = errno;
- r = safewrite(sigwrite, &sigc, 1);
+ r = safewrite(sigwrite, siginfo, sizeof(*siginfo));
if (r == -1) {
sig_errors++;
sig_lasterrno = errno;
int events ATTRIBUTE_UNUSED,
void *opaque) {
struct qemud_server *server = (struct qemud_server *)opaque;
- unsigned char sigc;
+ siginfo_t siginfo;
int ret;
- if (read(server->sigread, &sigc, 1) != 1) {
+ if (saferead(server->sigread, &siginfo, sizeof(siginfo)) != sizeof(siginfo)) {
qemudLog(QEMUD_ERR, _("Failed to read from signal pipe: %s"),
strerror(errno));
return;
ret = 0;
- switch (sigc) {
+ switch (siginfo.si_signo) {
case SIGHUP:
qemudLog(QEMUD_INFO, "%s", _("Reloading configuration on SIGHUP"));
if (virStateReload() < 0)
case SIGINT:
case SIGQUIT:
case SIGTERM:
- qemudLog(QEMUD_WARN, _("Shutting down on signal %d"), sigc);
+ qemudLog(QEMUD_WARN, _("Shutting down on signal %d"),
+ siginfo.si_signo);
server->shutdown = 1;
break;
default:
+ qemudLog(QEMUD_INFO, _("Received signal %d, dispatching to drivers"),
+ siginfo.si_signo);
+ virStateSigDispatcher(&siginfo);
break;
}
goto error1;
}
- sig_action.sa_handler = sig_handler;
- sig_action.sa_flags = 0;
+ sig_action.sa_sigaction = sig_handler;
+ sig_action.sa_flags = SA_SIGINFO;
sigemptyset(&sig_action.sa_mask);
sigaction(SIGHUP, &sig_action, NULL);
}
/**
- * lxcDomainDestroy:
- * @dom: Ptr to domain to destroy
+ * lxcVmCleanup:
+ * @vm: Ptr to VM to clean up
*
- * Sends SIGKILL to container root process to terminate the container
+ * waitpid() on the container process. kill and wait the tty process
+ * This is called by boh lxcDomainDestroy and lxcSigHandler when a
+ * container exits.
*
* Returns 0 on success or -1 in case of error
*/
-static int lxcDomainDestroy(virDomainPtr dom)
+static int lxcVMCleanup(lxc_driver_t *driver, lxc_vm_t * vm)
{
int rc = -1;
int waitRc;
- lxc_driver_t *driver = (lxc_driver_t*)dom->conn->privateData;
- lxc_vm_t *vm = lxcFindVMByID(driver, dom->id);
- int childStatus;
-
- if (!vm) {
- lxcError(dom->conn, dom, VIR_ERR_INVALID_DOMAIN,
- _("no domain with id %d"), dom->id);
- goto error_out;
- }
-
- if (0 > (kill(vm->def->id, SIGKILL))) {
- if (ESRCH != errno) {
- lxcError(dom->conn, dom, VIR_ERR_INTERNAL_ERROR,
- _("sending SIGKILL failed: %s"), strerror(errno));
-
- goto error_out;
- }
- }
-
- vm->state = VIR_DOMAIN_SHUTDOWN;
+ int childStatus = -1;
while (((waitRc = waitpid(vm->def->id, &childStatus, 0)) == -1) &&
errno == EINTR);
if (waitRc != vm->def->id) {
- lxcError(dom->conn, dom, VIR_ERR_INTERNAL_ERROR,
+ lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
_("waitpid failed to wait for container %d: %d %s"),
vm->def->id, waitRc, strerror(errno));
goto kill_tty;
}
- rc = WEXITSTATUS(childStatus);
- DEBUG("container exited with rc: %d", rc);
+ rc = 0;
+
+ if (WIFEXITED(childStatus)) {
+ rc = WEXITSTATUS(childStatus);
+ DEBUG("container exited with rc: %d", rc);
+ }
kill_tty:
if (0 > (kill(vm->pid, SIGKILL))) {
if (ESRCH != errno) {
- lxcError(dom->conn, dom, VIR_ERR_INTERNAL_ERROR,
+ lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
_("sending SIGKILL to tty process failed: %s"),
strerror(errno));
errno == EINTR);
if (waitRc != vm->pid) {
- lxcError(dom->conn, dom, VIR_ERR_INTERNAL_ERROR,
+ lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
_("waitpid failed to wait for tty %d: %d %s"),
vm->pid, waitRc, strerror(errno));
}
vm->def->id = -1;
driver->nactivevms--;
driver->ninactivevms++;
+ lxcSaveConfig(NULL, driver, vm, vm->def);
- rc = 0;
+ return rc;
+ }
+
+/**
+ * lxcDomainDestroy:
+ * @dom: Ptr to domain to destroy
+ *
+ * Sends SIGKILL to container root process to terminate the container
+ *
+ * Returns 0 on success or -1 in case of error
+ */
+static int lxcDomainDestroy(virDomainPtr dom)
+{
+ int rc = -1;
+ lxc_driver_t *driver = (lxc_driver_t*)dom->conn->privateData;
+ lxc_vm_t *vm = lxcFindVMByID(driver, dom->id);
+
+ if (!vm) {
+ lxcError(dom->conn, dom, VIR_ERR_INVALID_DOMAIN,
+ _("no domain with id %d"), dom->id);
+ goto error_out;
+ }
+
+ if (0 > (kill(vm->def->id, SIGKILL))) {
+ if (ESRCH != errno) {
+ lxcError(dom->conn, dom, VIR_ERR_INTERNAL_ERROR,
+ _("sending SIGKILL failed: %s"), strerror(errno));
+
+ goto error_out;
+ }
+ }
+
+ vm->state = VIR_DOMAIN_SHUTDOWN;
+
+ rc = lxcVMCleanup(driver, vm);
error_out:
return rc;
return 0;
}
+/**
+ * lxcSigHandler:
+ * @siginfo: Pointer to siginfo_t structure
+ *
+ * Handles signals received by libvirtd. Currently this is used to
+ * catch SIGCHLD from an exiting container.
+ *
+ * Returns 0 on success or -1 in case of error
+ */
+static int lxcSigHandler(siginfo_t *siginfo)
+{
+ int rc = -1;
+ lxc_vm_t *vm;
+
+ if (siginfo->si_signo == SIGCHLD) {
+ vm = lxcFindVMByID(lxc_driver, siginfo->si_pid);
+
+ if (NULL == vm) {
+ DEBUG("Ignoring SIGCHLD from non-container process %d\n",
+ siginfo->si_pid);
+ goto cleanup;
+ }
+
+ rc = lxcVMCleanup(lxc_driver, vm);
+
+ }
+
+cleanup:
+ return rc;
+}
+
/* Function Tables */
static virDriver lxcDriver = {
lxcShutdown,
NULL, /* reload */
lxcActive,
+ lxcSigHandler
};
int lxcRegister(void)