fixed scenario loading
authorMartin Willi <martin@strongswan.org>
Thu, 13 Sep 2007 08:10:36 +0000 (08:10 -0000)
committerMartin Willi <martin@strongswan.org>
Thu, 13 Sep 2007 08:10:36 +0000 (08:10 -0000)
src/dumm/Makefile.am
src/dumm/cowfs.c
src/dumm/cowfs.h
src/dumm/dumm.c
src/dumm/dumm.h
src/dumm/guest.c
src/dumm/guest.h
src/dumm/main.c
src/dumm/mconsole.c

index 5f93fab..3356e7a 100644 (file)
@@ -4,9 +4,9 @@ ipsec_PROGRAMS = dumm
 libdumm_la_SOURCES = dumm.c dumm.h guest.c guest.h iface.c iface.h bridge.c bridge.h mconsole.c mconsole.h cowfs.h cowfs.c
 dumm_SOURCES = main.c
 
-libdumm_la_LIBADD = $(top_builddir)/src/libstrongswan/libstrongswan.la -lpthread -lbridge -lfuse -lutil
+libdumm_la_LIBADD = $(top_builddir)/src/libstrongswan/libstrongswan.la -lpthread -lbridge -lfuse -lutil ${xml_LIBS}
 dumm_LDADD = -ldumm -lreadline
 
-INCLUDES = -I$(top_srcdir)/src/libstrongswan
+INCLUDES = -I$(top_srcdir)/src/libstrongswan ${xml_CFLAGS}
 
 AM_CFLAGS = -D_FILE_OFFSET_BITS=64
index 2c5dd38..4c16c7c 100644 (file)
@@ -55,14 +55,14 @@ struct private_cowfs_t {
        char *master;
        /** host filesystem path */
        char *host;
-       /** scenario filesystem path */
-       char *scen;
+       /** overlay filesystem path */
+       char *over;
        /** fd of read only master filesystem */
        int master_fd;
        /** copy on write overlay to master */
        int host_fd;
-       /** optional scenario COW overlay */
-       int scen_fd;
+       /** optional COW overlay */
+       int over_fd;
        /** thread processing FUSE */
        pthread_t thread;
 };
@@ -97,9 +97,9 @@ static int get_rd(const char *path)
 {
        private_cowfs_t *this = get_this();
 
-       if (this->scen_fd > 0 && faccessat(this->scen_fd, path, F_OK, 0) == 0)
+       if (this->over_fd > 0 && faccessat(this->over_fd, path, F_OK, 0) == 0)
        {
-               return this->scen_fd;
+               return this->over_fd;
        }
        if (faccessat(this->host_fd, path, F_OK, 0) == 0)
        {
@@ -114,9 +114,9 @@ static int get_rd(const char *path)
 static int get_wr(const char *path)
 {
        private_cowfs_t *this = get_this();
-       if (this->scen_fd > 0)
+       if (this->over_fd > 0)
        {
-               return this->scen_fd;
+               return this->over_fd;
        }
        return this->host_fd;
 }
@@ -318,7 +318,7 @@ static int cowfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
        
        d1 = get_dir(this->master, path);
        d2 = get_dir(this->host, path);
-       d3 = get_dir(this->scen, path);
+       d3 = get_dir(this->over, path);
        
        if (d1)
        {
@@ -741,9 +741,9 @@ static int cowfs_statfs(const char *path, struct statvfs *stbuf)
        int fd;
        
        fd = this->host_fd;
-       if (this->scen_fd > 0)
+       if (this->over_fd > 0)
        {
-               fd = this->scen_fd;
+               fd = this->over_fd;
        }
 
        if (fstatvfs(fd, stbuf) < 0)
@@ -793,29 +793,29 @@ static struct fuse_operations cowfs_operations = {
 };
 
 /**
- * Implementation of cowfs_t.set_scenario.
+ * Implementation of cowfs_t.set_overlay.
  */
-static bool set_scenario(private_cowfs_t *this, char *path)
+static bool set_overlay(private_cowfs_t *this, char *path)
 {
-       if (this->scen)
+       if (this->over)
        {
-               free(this->scen);
-               this->scen = NULL;
+               free(this->over);
+               this->over = NULL;
        }
-       if (this->scen_fd > 0)
+       if (this->over_fd > 0)
        {
-               close(this->scen_fd);
-               this->scen_fd = -1;
+               close(this->over_fd);
+               this->over_fd = -1;
        }
        if (path)
        {
-               this->scen_fd = open(path, O_RDONLY | O_DIRECTORY);
-               if (this->scen_fd < 0)
+               this->over_fd = open(path, O_RDONLY | O_DIRECTORY);
+               if (this->over_fd < 0)
                {
-                       DBG1("failed to open scenario overlay directory '%s': %m", path);
+                       DBG1("failed to open overlay directory '%s': %m", path);
                        return FALSE;
                }
-               this->scen = strdup(path);
+               this->over = strdup(path);
        }
        return TRUE;
 }
@@ -832,12 +832,12 @@ static void destroy(private_cowfs_t *this)
        free(this->mount);
        free(this->master);
        free(this->host);
-       free(this->scen);
+       free(this->over);
        close(this->master_fd);
        close(this->host_fd);
-       if (this->scen_fd > 0)
+       if (this->over_fd > 0)
        {
-               close(this->scen_fd);
+               close(this->over_fd);
        }
        free(this);
 }
@@ -850,7 +850,7 @@ cowfs_t *cowfs_create(char *master, char *host, char *mount)
        struct fuse_args args = {0, NULL, 0};
        private_cowfs_t *this = malloc_thing(private_cowfs_t);
        
-       this->public.set_scenario = (bool(*)(cowfs_t*, char *path))set_scenario;
+       this->public.set_overlay = (bool(*)(cowfs_t*, char *path))set_overlay;
        this->public.destroy = (void(*)(cowfs_t*))destroy;
        
     this->master_fd = open(master, O_RDONLY | O_DIRECTORY);
@@ -866,7 +866,7 @@ cowfs_t *cowfs_create(char *master, char *host, char *mount)
        close(this->master_fd);
        free(this);
     }
-       this->scen_fd = -1;
+       this->over_fd = -1;
        
     this->chan = fuse_mount(mount, &args);
     if (this->chan == NULL)
@@ -893,7 +893,7 @@ cowfs_t *cowfs_create(char *master, char *host, char *mount)
     this->mount = strdup(mount);
     this->master = strdup(master);
     this->host = strdup(host);
-    this->scen = NULL;
+    this->over = NULL;
        
        if (pthread_create(&this->thread, NULL, (void*)fuse_loop, this->fuse) != 0)
        {
index fb1fc35..419197d 100644 (file)
@@ -27,12 +27,12 @@ typedef struct cowfs_t cowfs_t;
 struct cowfs_t {
        
        /**
-        * @brief Set the scenario copy on write overlay.
+        * @brief Set an additional copy on write overlay.
         *
         * @param path          path of the overlay
         * @return                      FALSE if failed
         */
-       bool (*set_scenario)(cowfs_t *this, char *path);
+       bool (*set_overlay)(cowfs_t *this, char *path);
        
        /**
         * @brief Stop, umount and destroy a cowfs FUSE filesystem.
index cfe403f..560ab8d 100644 (file)
@@ -21,6 +21,8 @@
 #include <stdio.h>
 #include <dirent.h>
 #include <errno.h>
+#include <libxml/xmlreader.h>
+#include <libxml/xmlwriter.h>
 
 #include <debug.h>
 
@@ -28,8 +30,8 @@
 
 #define PERME (S_IRWXU | S_IRWXG)
 #define GUEST_DIR "guests"
-#define SCENARIO_DIR "scenarios"
-#define SCENARIO_DIFF_DIR "diff"
+#define TEMPLATE_DIR "templates"
+#define TEMPLATE_DIR_DIR "diff"
 
 /**
  * instances of dumm, used to deliver signals
@@ -45,10 +47,10 @@ struct private_dumm_t {
        char *dir;
        /** directory of guests */
        char *guest_dir;
-       /** directory of scenarios */
-       char *scenario_dir;
-       /** directory of loaded scenario */
-       char *scenario;
+       /** directory of templates */
+       char *template_dir;
+       /** directory of loaded template */
+       char *template;
        /** list of managed guests */
        linked_list_t *guests;
        /** list of managed bridges */
@@ -105,73 +107,77 @@ static iterator_t* create_bridge_iterator(private_dumm_t *this)
 }
 
 /**
- * disable the currently enabled scenario 
+ * disable the currently enabled template 
  */
-static void clear_scenario(private_dumm_t *this)
+static void clear_template(private_dumm_t *this)
 {
-       iterator_t *iterator;
+       iterator_t *iterator, *ifaces;
        guest_t *guest;
+       iface_t *iface;
 
-       free(this->scenario);
-       this->scenario = NULL;
+       free(this->template);
+       this->template = NULL;
 
        iterator = this->guests->create_iterator(this->guests, TRUE);
        while (iterator->iterate(iterator, (void**)&guest))
        {
-               guest->set_scenario(guest, NULL);
+               guest->load_template(guest, NULL);
+               ifaces = guest->create_iface_iterator(guest);
+               while (ifaces->iterate(ifaces, (void**)&iface))
+               {
+                       ifaces->remove(ifaces);
+                       iface->destroy(iface);
+               }
+               ifaces->destroy(ifaces);
        }
        iterator->destroy(iterator);
 }
 
 /**
- * Implementation of dumm_t.load_scenario.
+ * Implementation of dumm_t.load_template.
  */
-static bool load_scenario(private_dumm_t *this, char *name)
+static bool load_template(private_dumm_t *this, char *name)
 {
        iterator_t *iterator;
        guest_t *guest;
        char dir[PATH_MAX];
        size_t len;
        
+       clear_template(this);
+       
        if (name == NULL)
        {
-               clear_scenario(this);
                return TRUE;
        }
 
-       free(this->scenario);
-       asprintf(&this->scenario, "%s/%s", this->scenario_dir, name);
-       mkdir(this->scenario_dir, PERME);
-       
-       len = snprintf(dir, sizeof(dir), "%s/%s", this->scenario, SCENARIO_DIFF_DIR);
+       free(this->template);
+       asprintf(&this->template, "%s/%s", this->template_dir, name);
+       len = snprintf(dir, sizeof(dir), "%s/%s", this->template, TEMPLATE_DIR_DIR);
        if (len < 0 || len >= sizeof(dir))
        {
-               clear_scenario(this);
                return FALSE;
        }
        
-       if (access(this->scenario, F_OK) != 0)
-       {       /* does not exist, create scenario */
-               if (mkdir(this->scenario, PERME) != 0)
+       if (access(this->template, F_OK) != 0)
+       {       /* does not exist, create template */
+               if (mkdir(this->template, PERME) != 0)
                {
-                       DBG1("creating scenario directory '%s' failed: %m", this->scenario);
-                       clear_scenario(this);
+                       DBG1("creating template directory '%s' failed: %m", this->template);
                        return FALSE;
                }
                if (mkdir(dir, PERME) != 0)
                {
-                       DBG1("creating scenario overlay directory '%s' failed: %m", dir);
-                       clear_scenario(this);
+                       DBG1("creating template overlay directory '%s' failed: %m", dir);
                        return FALSE;
                }
        }
        iterator = this->guests->create_iterator(this->guests, TRUE);
        while (iterator->iterate(iterator, (void**)&guest))
        {
-               if (!guest->set_scenario(guest, dir))
+               if (!guest->load_template(guest, dir))
                {
                        iterator->destroy(iterator);
-                       clear_scenario(this);
+                       clear_template(this);
                        return FALSE;
                }
        }
@@ -180,15 +186,6 @@ static bool load_scenario(private_dumm_t *this, char *name)
 }
 
 /**
- * Implementation of dumm_t.save_scenario.
- */
-static bool save_scenario(private_dumm_t *this)
-{
-       DBG1("scenario loading unimplemented.");
-       return FALSE;
-}
-
-/**
  * signal handler 
  */
 void signal_handler(int sig, siginfo_t *info, void *ucontext)
@@ -303,8 +300,8 @@ static void destroy(private_dumm_t *this)
        this->destroying = TRUE;
        this->guests->destroy_offset(this->guests, offsetof(guest_t, destroy));
        free(this->guest_dir);
-       free(this->scenario_dir);
-       free(this->scenario);
+       free(this->template_dir);
+       free(this->template);
        free(this->dir);
        remove_instance(this);
        free(this);
@@ -357,8 +354,7 @@ dumm_t *dumm_create(char *dir)
        this->public.create_guest_iterator = (iterator_t*(*)(dumm_t*))create_guest_iterator;
        this->public.create_bridge = (bridge_t*(*)(dumm_t*, char *name))create_bridge;
        this->public.create_bridge_iterator = (iterator_t*(*)(dumm_t*))create_bridge_iterator;
-       this->public.load_scenario = (bool(*)(dumm_t*, char *name))load_scenario;
-       this->public.save_scenario = (bool(*)(dumm_t*))save_scenario;
+       this->public.load_template = (bool(*)(dumm_t*, char *name))load_template;
        this->public.destroy = (void(*)(dumm_t*))destroy;
        
        this->destroying = FALSE;
@@ -370,9 +366,9 @@ dumm_t *dumm_create(char *dir)
        {
                asprintf(&this->dir, "%s/%s", cwd, dir);
        }
-       this->scenario = NULL;
+       this->template = NULL;
        asprintf(&this->guest_dir, "%s/%s", this->dir, GUEST_DIR);
-       asprintf(&this->scenario_dir, "%s/%s", this->dir, SCENARIO_DIR);
+       asprintf(&this->template_dir, "%s/%s", this->dir, TEMPLATE_DIR);
        this->guests = linked_list_create();
        this->bridges = linked_list_create();
        
@@ -384,6 +380,12 @@ dumm_t *dumm_create(char *dir)
                destroy(this);
                return NULL;
        }
+       if (mkdir(this->template_dir, PERME) < 0 && errno != EEXIST)
+       {
+               DBG1("creating template directory '%s' failed: %m", this->template_dir);
+               destroy(this);
+               return NULL;
+       }
        
        load_guests(this);
        return &this->public;
index 6fc3279..349e6f1 100644 (file)
@@ -70,19 +70,12 @@ struct dumm_t {
        iterator_t* (*create_bridge_iterator)(dumm_t *this);
        
        /**
-        * @brief Loads a scenario, create a new one if it does not exist.
+        * @brief Loads a template, create a new one if it does not exist.
         *
-        * @param name          name of the scenario to load/create
-        * @return                      FALSE if load/crate failed
+        * @param name          name of the template, NULL to clonse
+        * @return                      FALSE if load/create failed
         */
-       bool (*load_scenario)(dumm_t *this, char *name);
-       
-       /**
-        * @brief Saves the current loaded scenario.
-        *
-        * @return                      FALSE if saving scenario failed
-        */
-       bool (*save_scenario)(dumm_t *this);
+       bool (*load_template)(dumm_t *this, char *name);
        
        /**
         * @brief stop all guests and destroy the modeler
index b74449c..bbb59f4 100644 (file)
@@ -69,19 +69,6 @@ struct private_guest_t {
        cowfs_t *cowfs;
        /** mconsole to control running UML */
        mconsole_t *mconsole;
-       /** pty consoles */
-       struct {
-               /** pty master fd */
-               int master;
-               /** pty slave fd */
-               int slave;
-               /** name of the pty */
-               char name[16];
-               /** currently in use */
-               bool occupied;
-               /** is valid */
-               bool valid;
-       } pty[PTYS];
        /** list of interfaces attached to the guest */
        linked_list_t *ifaces;
 };
@@ -273,16 +260,16 @@ static bool start(private_guest_t *this)
 }      
        
 /**
- * Implementation of guest_t.set_scenario.
+ * Implementation of guest_t.load_template.
  */
-static bool set_scenario(private_guest_t *this, char *path)
+static bool load_template(private_guest_t *this, char *path)
 {
        char dir[PATH_MAX];
        size_t len;
        
        if (path == NULL)
        {
-               return this->cowfs->set_scenario(this->cowfs, NULL);    
+               return this->cowfs->set_overlay(this->cowfs, NULL);     
        }
        
        len = snprintf(dir, sizeof(dir), "%s/%s", path, this->name);
@@ -294,11 +281,11 @@ static bool set_scenario(private_guest_t *this, char *path)
        {
                if (mkdir(dir, PERME) != 0)
                {
-                       DBG1("creating scenario overlay for guest '%s' failed: %m", this->name);
+                       DBG1("creating overlay for guest '%s' failed: %m", this->name);
                        return FALSE;
                }
        }
-       return this->cowfs->set_scenario(this->cowfs, dir);
+       return this->cowfs->set_overlay(this->cowfs, dir);
 }
 
 /**
@@ -306,22 +293,12 @@ static bool set_scenario(private_guest_t *this, char *path)
  */
 static void sigchild(private_guest_t *this)
 {
-       int i;
-
        if (this->state != GUEST_STOPPING)
        {       /* collect zombie if uml crashed */
                waitpid(this->pid, NULL, WNOHANG);
        }
        DESTROY_IF(this->mconsole);
        this->mconsole = NULL;
-       for (i = 0; i < PTYS; i++)
-       {
-               if (this->pty[i].valid)
-               {
-                       close(this->pty[i].master);
-                       close(this->pty[i].slave);
-               }
-       }
        this->state = GUEST_STOPPED;
 }
 
@@ -457,7 +434,7 @@ static private_guest_t *guest_create_generic(char *parent, char *name,
        this->public.start = (void*)start;
        this->public.stop = (void*)stop;
        this->public.get_console = (char*(*)(guest_t*,int))get_console;
-       this->public.set_scenario = (bool(*)(guest_t*, char *path))set_scenario;
+       this->public.load_template = (bool(*)(guest_t*, char *path))load_template;
        this->public.sigchild = (void(*)(guest_t*))sigchild;
        this->public.destroy = (void*)destroy;
                
index 10d42cb..10b37aa 100644 (file)
@@ -89,10 +89,10 @@ struct guest_t {
        /**
         * @brief Get a console pts device.
         *
-        * Every guest has 6 consoles, numbered from 1 to 6. These are associated
+        * Every guest has 5 consoles, numbered from 1 to 5. These are associated
         * to a unique pts device on the host. 
         *
-        * @param console       console number to get (1-6)
+        * @param console       console number to get (1-5)
         * @return                      pts device file name, NULL if failed
         */
        char* (*get_console) (guest_t *this, int console);
@@ -113,12 +113,12 @@ struct guest_t {
        iterator_t* (*create_iface_iterator)(guest_t *this);
        
        /**
-        * @brief Set the scenario COWFS overlay to use.
+        * @brief Set the template COWFS overlay to use.
         *
-        * @param parent        parent directory where scenario diff should point to
+        * @param parent        parent directory where template diff should point to
         * @return                      FALSE if failed
         */
-       bool (*set_scenario)(guest_t *this, char *parent);
+       bool (*load_template)(guest_t *this, char *parent);
 
        /**
         * @brief Called whenever a SIGCHILD for the guests PID is received.
index b4c4352..d6e142e 100644 (file)
@@ -21,6 +21,8 @@
 #include <library.h>
 #include <readline/readline.h>
 #include <readline/history.h>
+#include <dlfcn.h>
+#include <dirent.h>
 
 #include "dumm.h"
 
@@ -469,17 +471,73 @@ static void bridge_list_menu()
        }
 }
 
-static void scenario_menu()
+static void template_menu()
 {
        char *name;
        
-       name = get_line("scenario name (or 'none'): ");
+       name = get_line("template name (or 'none'): ");
        
-       dumm->load_scenario(dumm, streq(name, "none") ? NULL : name);
+       dumm->load_template(dumm, streq(name, "none") ? NULL : name);
        
        free(name);
 }
 
+typedef bool (*uml_test_t)(dumm_t *dumm);
+
+static void test_menu()
+{
+       char *name;
+       void *handle;
+       struct dirent *ent;
+       DIR *dir;
+       uml_test_t test;
+       
+       name = get_line("test name: ");
+       
+       dir = opendir("tests");
+       if (dir)
+       {
+               while ((ent = readdir(dir)))
+               {
+                       char buf[PATH_MAX];
+                       size_t len;
+                       
+                       len = strlen(ent->d_name);
+                       if (strlen(ent->d_name) < 4 || !streq(ent->d_name + len - 3, ".so"))
+                       {
+                               continue;
+                       }
+                       
+                       snprintf(buf, sizeof(buf), "%s/%s", "tests", ent->d_name);
+                       handle = dlopen(buf, RTLD_LAZY);
+                       if (!handle)
+                       {
+                               printf("failed to open test %s\n", ent->d_name);
+                               continue;
+                       }
+                       test = dlsym(handle, "test");
+                       if (test && dumm->load_template(dumm, ent->d_name))
+                       {
+                               printf("running test %s: ", ent->d_name);
+                               if (test(dumm))
+                               {
+                                       printf("success\n");
+                               }
+                               else
+                               {
+                                       printf("failed\n");
+                               }
+                       }
+                       else
+                       {
+                               printf("failed to open test %s\n", ent->d_name);
+                       }
+                       dlclose(handle);
+               }
+       }
+       free(name);
+}
+
 /**
  * Signal handler 
  */
@@ -552,16 +610,21 @@ int main(int argc, char *argv[])
                {
                        bridge_list_menu();
                }
-               else if (streq(line, "scenario"))
+               else if (streq(line, "template"))
+               {
+                       template_menu();
+               }
+               else if (streq(line, "test"))
                {
-                       scenario_menu();
+                       test_menu();
                }
                else
                {
-                       printf("quit|guest|bridge|scenario\n");
+                       printf("quit|guest|bridge|template|test\n");
                }
                free(line);
        }
+       dumm->load_template(dumm, NULL);
        dumm->destroy(dumm);
        clear_history();
        return 0;
index 7757823..25cb846 100644 (file)
@@ -200,6 +200,31 @@ static char* get_console_pts(private_mconsole_t *this, int con)
 }
 
 /**
+ * Poll until guest is ready
+ */
+static bool wait_bootup(private_mconsole_t *this)
+{
+       char *cmd, buf[128];
+       int len, res;
+       
+       cmd = "config con0";
+       while (TRUE)
+       {
+               len = sizeof(buf);
+               res = request(this, cmd, buf, &len);
+               if (res < 0)
+               {
+                       return FALSE;
+               }
+               if (res == 0)
+               {
+                       return TRUE;
+               }
+               usleep(50000);
+       }
+}
+
+/**
  * Implementation of mconsole_t.destroy.
  */
 static void destroy(private_mconsole_t *this)
@@ -313,6 +338,12 @@ mconsole_t *mconsole_create(char *notify)
        }
        unlink(notify);
        
+       if (!wait_bootup(this))
+       {
+               destroy(this);
+               return NULL;
+       }
+       
        return &this->public;
 }