The goal here is to be able to multiplex several event sources in
lxc-init. It will be a lot easier to add I/O driven features: for
example, a rexec-like service to start extra commands in a
container.

Signed-off-by: Greg Kurz <gk...@fr.ibm.com>
Signed-off-by: Cedric Le Goater <c...@fr.ibm.com>
---

 src/lxc/error.c    |   23 ++++++
 src/lxc/error.h    |    3 +
 src/lxc/lxc_init.c |  206 ++++++++++++++++++++++++++++------------------------
 3 files changed, 137 insertions(+), 95 deletions(-)

diff --git a/src/lxc/error.c b/src/lxc/error.c
index 5ecfbac..e0ba96a 100644
--- a/src/lxc/error.c
+++ b/src/lxc/error.c
@@ -57,3 +57,26 @@ extern int  lxc_error_set_and_log(int pid, int status)
 
        return ret;
 }
+
+int lxc_error_set_and_log_siginfo(siginfo_t *siginfo)
+{
+       int ret = 0;
+
+       if (siginfo->si_code == CLD_EXITED) {
+               if (siginfo->si_status) {
+                       INFO("child <%d> ended on error (%d)",
+                            siginfo->si_pid, siginfo->si_status);
+                       ret = siginfo->si_status;
+               }
+       } else if (siginfo->si_code == CLD_KILLED) {
+               INFO("child <%d> ended on signal (%d)",
+                    siginfo->si_pid, siginfo->si_signo);
+               ret = siginfo->si_signo + 128;
+       } else if (siginfo->si_code == CLD_DUMPED) {
+               INFO("child <%d> dumped core on signal (%d)",
+                    siginfo->si_pid, siginfo->si_signo);
+               ret = siginfo->si_signo + 128;
+       }
+
+       return ret;
+}
diff --git a/src/lxc/error.h b/src/lxc/error.h
index ef25fc3..4684ab5 100644
--- a/src/lxc/error.h
+++ b/src/lxc/error.h
@@ -23,6 +23,9 @@
 #ifndef __lxc_error_h
 #define __lxc_error_h
 
+#include <signal.h>
+
 extern int  lxc_error_set_and_log(int pid, int status);
+extern int  lxc_error_set_and_log_siginfo(siginfo_t *siginfo);
 
 #endif
diff --git a/src/lxc/lxc_init.c b/src/lxc/lxc_init.c
index a534b51..17704cd 100644
--- a/src/lxc/lxc_init.c
+++ b/src/lxc/lxc_init.c
@@ -30,6 +30,7 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <sys/signalfd.h>
 #define _GNU_SOURCE
 #include <getopt.h>
 
@@ -37,6 +38,7 @@
 #include "caps.h"
 #include "error.h"
 #include "utils.h"
+#include "mainloop.h"
 
 lxc_log_define(lxc_init, lxc);
 
@@ -47,23 +49,91 @@ static struct option options[] = {
        { 0, 0, 0, 0 },
 };
 
-static int was_interrupted = 0;
+static pid_t child_pid;
+static int shutting_down;
+static int exit_status;
+static int orphan;
 
-int main(int argc, char *argv[])
+static int handle_child(void)
 {
+       for(;;) {
+               siginfo_t siginfo;
+
+               siginfo.si_pid = 0;
+
+               if (waitid(P_ALL, -1, &siginfo, WEXITED|WNOHANG) < 0) {
+                       /* ECHILD means we're the last process */
+                       if (errno != ECHILD)
+                               ERROR("failed to wait child : %s",
+                                     strerror(errno));
+                       return 1;
+               }
+
+               /* No process exited */
+               if (!siginfo.si_pid)
+                       return 0;
+
+               /* reset timer each time a process exited */
+               if (shutting_down)
+                       alarm(1);
+
+               /*
+                * keep the exit code of started application
+                * (not wrapped pid) and continue to wait for
+                * the end of the orphan group.
+                */
+               if ((siginfo.si_pid != child_pid) || orphan)
+                       continue;
+
+               orphan = 1;
 
-       void interrupt_handler(int sig)
-       {
-               if (!was_interrupted)
-                       was_interrupted = sig;
+               exit_status =
+                       lxc_error_set_and_log_siginfo(&siginfo);
        }
+}
 
-       pid_t pid;
+static int handle_signal(int fd, void* data, struct lxc_epoll_descr *descr)
+{
+       struct signalfd_siginfo siginfo;
+
+       /* If we get woken up, we have at least one siginfo to read: no need
+        * to check for errors.
+        */
+       read(fd, &siginfo, sizeof(siginfo));
+
+       switch (siginfo.ssi_signo) {
+       case SIGTERM:
+               if (!shutting_down) {
+                       shutting_down = 1;
+                       kill(-1, SIGTERM);
+                       alarm(1);
+               }
+               break;
+
+       case SIGALRM:
+               kill(-1, SIGKILL);
+               break;
+
+       case SIGCHLD:
+               return handle_child();
+               break;
+
+       default:
+               kill(child_pid, siginfo.ssi_signo);
+               break;
+       }
+
+       return 0;
+}
+
+int main(int argc, char *argv[])
+{
        int nbargs = 0;
        int err = -1;
        char **aargv;
-       sigset_t mask, omask;
-       int i, shutdown = 0;
+       sigset_t mask;
+       struct lxc_epoll_descr mainloop_descr;
+       int signal_fd;
 
        while (1) {
                int ret = getopt_long_only(argc, argv, "", options, NULL);
@@ -90,44 +160,18 @@ int main(int argc, char *argv[])
        aargv = &argv[optind];
        argc -= nbargs;
 
-        /*
-        * mask all the signals so we are safe to install a
-        * signal handler and to fork
-        */
-       sigfillset(&mask);
-       sigprocmask(SIG_SETMASK, &mask, &omask);
-
-       for (i = 1; i < NSIG; i++) {
-               struct sigaction act;
-
-               sigfillset(&act.sa_mask);
-               sigdelset(&mask, SIGILL);
-               sigdelset(&mask, SIGSEGV);
-               sigdelset(&mask, SIGBUS);
-               act.sa_flags = 0;
-               act.sa_handler = interrupt_handler;
-               sigaction(i, &act, NULL);
-       }
-
        if (lxc_setup_fs())
                exit(err);
 
        if (lxc_caps_reset())
                exit(err);
 
-       pid = fork();
+       child_pid = fork();
 
-       if (pid < 0)
+       if (child_pid < 0)
                exit(err);
 
-       if (!pid) {
-
-               /* restore default signal handlers */
-               for (i = 1; i < NSIG; i++)
-                       signal(i, SIG_DFL);
-
-               sigprocmask(SIG_SETMASK, &omask, NULL);
-
+       if (!child_pid) {
                NOTICE("about to exec '%s'", aargv[0]);
 
                execvp(aargv[0], aargv);
@@ -135,69 +179,41 @@ int main(int argc, char *argv[])
                exit(err);
        }
 
-       /* let's process the signals now */
-       sigdelset(&omask, SIGALRM);
-       sigprocmask(SIG_SETMASK, &omask, NULL);
-
        /* no need of other inherited fds but stderr */
        close(fileno(stdin));
        close(fileno(stdout));
 
-       err = 0;
-       for (;;) {
-               int status;
-               int orphan = 0;
-               pid_t waited_pid;
-
-               switch (was_interrupted) {
-
-               case 0:
-                       break;
-
-               case SIGTERM:
-                       if (!shutdown) {
-                               shutdown = 1;
-                               kill(-1, SIGTERM);
-                               alarm(1);
-                       }
-                       break;
-
-               case SIGALRM:
-                       kill(-1, SIGKILL);
-                       break;
+       /* All signals except the ones that are related to a really serious 
error
+        * or the uncatchable ones will be handled by signalfd() and forwarded
+        * to the container.
+        */
+       sigfillset(&mask);
+       sigdelset(&mask, SIGILL);
+       sigdelset(&mask, SIGSEGV);
+       sigdelset(&mask, SIGBUS);
+       sigdelset(&mask, SIGSTOP);
+       sigdelset(&mask, SIGKILL);
+       sigprocmask(SIG_SETMASK, &mask, NULL);
+
+       signal_fd = signalfd(-1, &mask, SFD_CLOEXEC);
+       if (signal_fd < 0) {
+               SYSERROR("failed to create signal fd");
+               exit(err);
+       }
 
-               default:
-                       kill(pid, was_interrupted);
-                       break;
-               }
+       if (lxc_mainloop_open(&mainloop_descr)) {
+               ERROR("failed to create mainloop");
+               exit(err);
+       }
 
-               was_interrupted = 0;
-               waited_pid = wait(&status);
-               if (waited_pid < 0) {
-                       if (errno == ECHILD)
-                               goto out;
-                       if (errno == EINTR)
-                               continue;
-
-                       ERROR("failed to wait child : %s",
-                             strerror(errno));
-                       goto out;
-               }
+       if (lxc_mainloop_add_handler(&mainloop_descr, signal_fd, handle_signal,
+                                    NULL)) {
+               ERROR("failed to install signal handler");
+               exit(err);
+       }
 
-               /* reset timer each time a process exited */
-               if (shutdown)
-                       alarm(1);
+       if (lxc_mainloop(&mainloop_descr))
+               exit(err);
 
-               /*
-                * keep the exit code of started application
-                * (not wrapped pid) and continue to wait for
-                * the end of the orphan group.
-                */
-               if ((waited_pid != pid) || (orphan ==1))
-                       continue;
-               orphan = 1;
-               err = lxc_error_set_and_log(waited_pid, status);
-       }
-out:
-       return err;
+       exit(exit_status);
 }


------------------------------------------------------------------------------
RSA(R) Conference 2012
Save $700 by Nov 18
Register now
http://p.sf.net/sfu/rsa-sfdev2dev1
_______________________________________________
Lxc-devel mailing list
Lxc-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/lxc-devel

Reply via email to