support for killing guests properly
authorMartin Willi <martin@strongswan.org>
Fri, 27 Jul 2007 07:37:15 +0000 (07:37 -0000)
committerMartin Willi <martin@strongswan.org>
Fri, 27 Jul 2007 07:37:15 +0000 (07:37 -0000)
src/dumm/Makefile
src/dumm/dumm.c
src/dumm/dumm.h
src/dumm/guest.c
src/dumm/guest.h
src/dumm/main.c

index c60e57d..62aa929 100644 (file)
@@ -1,3 +1,3 @@
 
 dumm:  dumm.c dumm.h guest.c guest.h iface.c iface.h mconsole.c mconsole.h main.c
-       gcc -o dumm dumm.c guest.c iface.c mconsole.c main.c -lreadline -lstrongswan -I../libstrongswan/ -g -Wall
+       gcc -o dumm dumm.c guest.c iface.c mconsole.c main.c -lreadline -lstrongswan -I../libstrongswan/ -g -O2 -Wall -Wno-format -Wno-strict-aliasing
index bc690c5..b8f0e0f 100644 (file)
@@ -41,6 +41,38 @@ static guest_t* create_guest(private_dumm_t *this, char *name, char *master, int
 static iterator_t* create_guest_iterator(private_dumm_t *this)
 {
        return this->guests->create_iterator(this->guests, TRUE);
+}      
+       
+/**
+ * Implementation of dumm_t.sigchild_handler.
+ */
+static void sigchild_handler(private_dumm_t *this, siginfo_t *info)
+{
+       switch (info->si_code)
+       {
+               case CLD_EXITED:
+               case CLD_KILLED:
+               case CLD_DUMPED:
+               case CLD_STOPPED:
+               {
+                       iterator_t *iterator;
+                       guest_t *guest;
+                       
+                       iterator = this->guests->create_iterator(this->guests, TRUE);
+                       while (iterator->iterate(iterator, (void**)&guest))
+                       {
+                               if (guest->get_pid(guest) == info->si_pid)
+                               {
+                                       guest->sigchild(guest);
+                                       break;
+                               }
+                       }
+                       iterator->destroy(iterator);
+                       break;
+               }
+               default:
+                       break;
+       }
 }
 
 static void destroy(private_dumm_t *this)
@@ -67,6 +99,7 @@ dumm_t *dumm_create()
 {
        private_dumm_t *this = malloc_thing(private_dumm_t);
        
+       this->public.sigchild_handler = (void(*)(dumm_t*, siginfo_t *info))sigchild_handler;
        this->public.create_guest = (void*)create_guest;
        this->public.create_guest_iterator = (void*)create_guest_iterator;
        this->public.destroy = (void*)destroy;
index e33d14b..fe4f9ca 100644 (file)
@@ -16,6 +16,8 @@
 #ifndef DUMM_H
 #define DUMM_H
 
+#include <signal.h>
+
 #include <library.h>
 #include <utils/linked_list.h>
 
@@ -53,6 +55,18 @@ struct dumm_t {
        iterator_t* (*create_guest_iterator) (dumm_t *this);
        
        /**
+        * @brief Handler for received SIG_CHILD signals.
+        *
+        * Dumm spans children, UML kernels. To track and cleanup these kernel
+        * processes, it is required that this method is called whenever a SIG_CHILD
+        * is received. The user is responsible to call sigchild_handler on each
+        * dumm_t instance with the signals siginfo_t. 
+        *
+        * @param info          siginfo associated to the SIG_CHILD signal
+        */
+       void (*sigchild_handler)(dumm_t *this, siginfo_t *info);
+       
+       /**
         * @brief stop all guests and destroy the modeler
         */
        void (*destroy) (dumm_t *this);
index dc97c2d..59e5014 100644 (file)
@@ -78,7 +78,7 @@ static iface_t* create_iface(private_guest_t *this, char *name)
        iterator_t *iterator;
        iface_t *iface;
        
-       if (this->pid == 0)
+       if (this->state != GUEST_RUNNING)
        {
                DBG1("guest '%s' not running, unable to add interface", this->name);
                return NULL;
@@ -225,14 +225,29 @@ static bool start(private_guest_t *this, char *kernel)
  */
 static void stop(private_guest_t *this)
 {
-       if (this->pid)
+       if (this->state != GUEST_STOPPED)
        {
+               this->ifaces->destroy_offset(this->ifaces, offsetof(iface_t, destroy));
+               this->ifaces = linked_list_create();
                kill(this->pid, SIGINT);
-               this->pid = 0;
+               this->state = GUEST_STOPPING;
+               while (this->state == GUEST_STOPPING)
+               {
+                       sched_yield();
+               }
        }
 }
 
 /**
+ * Implementation of guest_t.sigchild.
+ */
+static void sigchild(private_guest_t *this)
+{
+       this->state = GUEST_STOPPED;
+       this->pid = 0;
+}
+
+/**
  * Check if directory exists, create otherwise
  */
 static bool makedir(char *dir, char *name)
@@ -326,7 +341,6 @@ static void destroy(private_guest_t *this)
 {
        stop(this);
        umount_unionfs(this->name);
-       this->ifaces->destroy_offset(this->ifaces, offsetof(iface_t, destroy));
        DESTROY_IF(this->mconsole);
        free(this->name);
        free(this->master);
@@ -347,6 +361,7 @@ guest_t *guest_create(char *name, char *master, int mem)
        this->public.create_iface_iterator = (iterator_t*(*)(guest_t*))create_iface_iterator;
        this->public.start = (void*)start;
        this->public.stop = (void*)stop;
+       this->public.sigchild = (void(*)(guest_t*))sigchild;
        this->public.destroy = (void*)destroy;
        
        if (!makedir(HOST_DIR, name) || !makedir(MOUNT_DIR, name) ||
index 38aef4b..48cfbf2 100644 (file)
@@ -100,7 +100,12 @@ struct guest_t {
         * @return              iterator over iface_t's
         */
        iterator_t* (*create_iface_iterator)(guest_t *this);
-
+       
+       /**
+        * @brief Called whenever a SIGCHILD is received.
+        */
+       void (*sigchild)(guest_t *this);
+       
        /**
         * @brief Close and destroy a guest with all interfaces
         */     
index 86fb08a..e4fc660 100644 (file)
 #include "dumm.h"
 
 /**
+ * global set of UMLs guests
+ */
+dumm_t *dumm;
+
+/**
  * show usage information (program arguments)
  */
 static void usage()
@@ -53,7 +58,8 @@ static void help()
  */
 static void help_guest()
 {
-       printf("start [kernel=<uml-kernel>]   start the guest\n");
+       printf("start [kernel=<uml-kernel>]   start a stopped guest\n");
+       printf("stop                          stop a started guest\n");
        printf("addif <name>                  add an interface to the guest\n");
        printf("delif <name>                  remove the interface\n");
        printf("listif                        list guests interfaces\n");
@@ -172,9 +178,19 @@ static void start_guest(guest_t *guest, char *line)
 }
 
 /**
+ * stop (kill) an UML guest
+ */
+static void stop_guest(guest_t *guest, char *line)
+{      
+       printf("stopping guest '%s'...\n", guest->get_name(guest));
+       guest->stop(guest);
+       printf("guest '%s' is down\n", guest->get_name(guest));
+}
+
+/**
  * subshell for guests
  */
-static void guest(dumm_t *dumm, char *name)
+static void guest(char *name)
 {
        char *line = NULL;
        char prompt[32];
@@ -211,6 +227,7 @@ static void guest(dumm_t *dumm, char *name)
                        QUIT = 0,
                        HELP,
                        START,
+                       STOP,
                        ADDIF,
                        DELIF,
                        LISTIF,
@@ -219,6 +236,7 @@ static void guest(dumm_t *dumm, char *name)
                        [QUIT] = "quit",
                        [HELP] = "help",
                        [START] = "start",
+                       [STOP] = "stop",
                        [ADDIF] = "addif",
                        [DELIF] = "delif",
                        [LISTIF] = "listif",
@@ -254,6 +272,9 @@ static void guest(dumm_t *dumm, char *name)
                        case START:
                                start_guest(guest, pos);
                                continue;
+                       case STOP:
+                               stop_guest(guest, pos);
+                               continue;
                        case ADDIF:
                                add_if(guest, pos);
                                continue;
@@ -274,7 +295,7 @@ static void guest(dumm_t *dumm, char *name)
 /**
  * create an UML guest
  */
-static void create_guest(dumm_t *dumm, char *line)
+static void create_guest(char *line)
 {
        enum {
                NAME = 0,
@@ -330,7 +351,7 @@ static void create_guest(dumm_t *dumm, char *line)
        if (dumm->create_guest(dumm, name, master, mem))
        {
                printf("guest '%s' created\n", name);
-               guest(dumm, name);
+               guest(name);
        }
        else
        {
@@ -341,7 +362,7 @@ static void create_guest(dumm_t *dumm, char *line)
 /**
  * list running UML guests
  */
-static void list(dumm_t *dumm)
+static void list()
 {
        iterator_t *guests, *ifaces;
        guest_t *guest;
@@ -350,7 +371,8 @@ static void list(dumm_t *dumm)
        guests = dumm->create_guest_iterator(dumm);
        while (guests->iterate(guests, (void**)&guest))
        {
-               printf("%s\n", guest->get_name(guest));
+               printf("%s (%N)\n", guest->get_name(guest),
+                          guest_state_names, guest->get_state(guest));
                ifaces = guest->create_iface_iterator(guest);
                while (ifaces->iterate(ifaces, (void**)&iface))
                {
@@ -363,12 +385,30 @@ static void list(dumm_t *dumm)
 }
 
 /**
+ * Signal handler 
+ */
+void signal_action(int sig, siginfo_t *info, void *ucontext)
+{
+       if (sig == SIGCHLD)
+       {
+               dumm->sigchild_handler(dumm, info);
+       }
+       else
+       {
+               dumm->destroy(dumm);
+               clear_history();
+               printf("\n");
+               exit(0);
+       }
+}
+
+/**
  * main routine, parses args and reads from console
  */
 int main(int argc, char *argv[])
 {
-       dumm_t *dumm;
        char *line = NULL;
+       struct sigaction action;
 
        while (TRUE)
        {
@@ -400,6 +440,18 @@ int main(int argc, char *argv[])
        }
        
        dumm = dumm_create();
+       
+       memset(&action, 0, sizeof(action));
+       action.sa_sigaction = signal_action;
+       action.sa_flags = SA_SIGINFO;
+       if (sigaction(SIGCHLD, &action, NULL) != 0 ||
+               sigaction(SIGINT, &action, NULL) != 0 ||
+               sigaction(SIGQUIT, &action, NULL) != 0 ||
+               sigaction(SIGTERM, &action, NULL) != 0)
+       {
+               printf("signal handler setup failed: %m.\n");
+               return 1;
+       }
 
        while (TRUE)
        {
@@ -447,13 +499,13 @@ int main(int argc, char *argv[])
                                help();
                                continue;
                        case CREATE:
-                               create_guest(dumm, pos);
+                               create_guest(pos);
                                continue;
                        case LIST:
-                               list(dumm);
+                               list();
                                continue;
                        case GUEST:
-                               guest(dumm, pos);
+                               guest(pos);
                                continue;
                        default:
                                printf("command unknown: '%s'\n", line);