usable without scenarios
authorMartin Willi <martin@strongswan.org>
Wed, 8 Aug 2007 12:35:24 +0000 (12:35 -0000)
committerMartin Willi <martin@strongswan.org>
Wed, 8 Aug 2007 12:35:24 +0000 (12:35 -0000)
src/dumm/Makefile
src/dumm/bridge.c
src/dumm/bridge.h
src/dumm/dumm.c
src/dumm/dumm.h
src/dumm/guest.c
src/dumm/guest.h
src/dumm/iface.c
src/dumm/iface.h
src/dumm/main.c

index d7f43ce..76ce4c7 100644 (file)
@@ -1,3 +1,3 @@
 
 dumm:  dumm.c dumm.h guest.c guest.h iface.c iface.h bridge.c bridge.h mconsole.c mconsole.h cowfs.h cowfs.c main.c
-       gcc -o dumm dumm.c guest.c iface.c bridge.c mconsole.c cowfs.c main.c `pkg-config fuse --cflags --libs` -lreadline -lbridge -lpthread -lstrongswan -I../libstrongswan/ -g -O2 -Wall -Wno-format -Wno-strict-aliasing
+       gcc -o dumm dumm.c guest.c iface.c bridge.c mconsole.c cowfs.c main.c `pkg-config fuse --cflags --libs` -ledit -lbridge -lpthread -lstrongswan -I../libstrongswan/ -g -O2 -Wall -Wno-format -Wno-strict-aliasing
index fa30ab6..c6068e6 100644 (file)
@@ -49,9 +49,9 @@ static iterator_t* create_iface_iterator(private_bridge_t *this)
 }
 
 /**
- * Implementation of bridge_t.del_iface.
+ * Implementation of bridge_t.disconnect_iface.
  */
-static bool del_iface(private_bridge_t *this, iface_t *iface)
+static bool disconnect_iface(private_bridge_t *this, iface_t *iface)
 {
        iterator_t *iterator;
        iface_t *current;
@@ -69,6 +69,7 @@ static bool del_iface(private_bridge_t *this, iface_t *iface)
                        }
                        else
                        {
+                               iface->set_bridge(iface, NULL);
                                good = TRUE;
                        }
                        break;
@@ -84,9 +85,9 @@ static bool del_iface(private_bridge_t *this, iface_t *iface)
 }
 
 /**
- * Implementation of bridge_t.add_iface.
+ * Implementation of bridge_t.connect_iface.
  */
-static bool add_iface(private_bridge_t *this, iface_t *iface)
+static bool connect_iface(private_bridge_t *this, iface_t *iface)
 {
        if (br_add_interface(this->name, iface->get_hostif(iface)) != 0)
        {
@@ -94,6 +95,7 @@ static bool add_iface(private_bridge_t *this, iface_t *iface)
                         iface->get_hostif(iface), this->name);
                return FALSE;
        }
+       iface->set_bridge(iface, &this->public);
        this->ifaces->insert_last(this->ifaces, iface);
        return TRUE;
 }
@@ -104,10 +106,19 @@ static bool add_iface(private_bridge_t *this, iface_t *iface)
 static int instances = 0;
 
 /**
+ * unregister an interface from bridge
+ */
+static void unregister(iface_t *iface)
+{
+       iface->set_bridge(iface, NULL);
+}
+
+/**
  * Implementation of bridge_t.destroy.
  */
 static void destroy(private_bridge_t *this)
 {
+       this->ifaces->invoke_function(this->ifaces, (void(*)(void*))unregister);
        this->ifaces->destroy(this->ifaces);
        if (br_del_bridge(this->name) != 0)
        {
@@ -140,8 +151,8 @@ bridge_t *bridge_create(char *name)
        this = malloc_thing(private_bridge_t);
        this->public.get_name = (char*(*)(bridge_t*))get_name;
        this->public.create_iface_iterator = (iterator_t*(*)(bridge_t*))create_iface_iterator;
-       this->public.del_iface = (bool(*)(bridge_t*, iface_t *iface))del_iface;
-       this->public.add_iface = (bool(*)(bridge_t*, iface_t *iface))add_iface;
+       this->public.disconnect_iface = (bool(*)(bridge_t*, iface_t *iface))disconnect_iface;
+       this->public.connect_iface = (bool(*)(bridge_t*, iface_t *iface))connect_iface;
        this->public.destroy = (void*)destroy;
 
        if (br_add_bridge(name) != 0)
index d47f7ee..6d28ed3 100644 (file)
 #include <library.h>
 #include <utils/iterator.h>
 
-#include "iface.h"
-
 typedef struct bridge_t bridge_t;
 
+#include "iface.h"
+
 /**
  * @brief Interface in a guest, connected to a tap device on the host.
  */
@@ -41,15 +41,15 @@ struct bridge_t {
         * @param iface                 interface to add
         * @return                              TRUE if interface added
         */
-       bool (*add_iface)(bridge_t *this, iface_t *iface);
+       bool (*connect_iface)(bridge_t *this, iface_t *iface);
        
        /**
         * @brief Remove an interface from a bridge.
         *
         * @param iface                 interface to remove
-        * @return                              TRUE ifinterface removed
+        * @return                              TRUE if interface removed
         */
-       bool (*del_iface)(bridge_t *this, iface_t *iface);
+       bool (*disconnect_iface)(bridge_t *this, iface_t *iface);
        
        /**
         * @brief Create an iterator over all interfaces.
index 3246284..3d2ec58 100644 (file)
 #define _GNU_SOURCE
 
 #include <sys/types.h>
+#include <sys/stat.h>
 #include <unistd.h>
 #include <stdio.h>
 #include <dirent.h>
+#include <errno.h>
 
 #include <debug.h>
 
 #include "dumm.h"
 
+#define PERME (S_IRWXU | S_IRWXG)
+#define GUEST_DIR "guests"
+#define SCENARIO_DIR "scenarios"
+#define SCENARIO_DIFF_DIR "diff"
+
 /**
  * instances of dumm, used to deliver signals
  */
@@ -36,6 +43,12 @@ struct private_dumm_t {
        dumm_t public;
        /** working dir */
        char *dir;
+       /** directory of guests */
+       char *guest_dir;
+       /** directory of scenarios */
+       char *scenario_dir;
+       /** directory of loaded scenario */
+       char *scenario;
        /** list of managed guests */
        linked_list_t *guests;
        /** list of managed bridges */
@@ -52,7 +65,7 @@ static guest_t* create_guest(private_dumm_t *this, char *name, char *kernel,
 {
        guest_t *guest;
        
-       guest = guest_create(this->dir, name, kernel, master, mem);
+       guest = guest_create(this->guest_dir, name, kernel, master, mem);
        if (guest)
        {
                this->guests->insert_last(this->guests, guest);
@@ -91,6 +104,80 @@ static iterator_t* create_bridge_iterator(private_dumm_t *this)
        return this->bridges->create_iterator(this->bridges, TRUE);
 }
 
+
+static void clear_scenario(private_dumm_t *this)
+{
+       iterator_t *iterator;
+       guest_t *guest;
+
+       free(this->scenario);
+       this->scenario = NULL;
+
+       iterator = this->guests->create_iterator(this->guests, TRUE);
+       while (iterator->iterate(iterator, (void**)&guest))
+       {
+               guest->set_scenario(guest, NULL);
+       }
+       iterator->destroy(iterator);
+}
+
+/**
+ * Implementation of dumm_t.load_scenario.
+ */
+static bool load_scenario(private_dumm_t *this, char *name)
+{
+       iterator_t *iterator;
+       guest_t *guest;
+       char dir[PATH_MAX];
+       size_t len;
+
+       free(this->scenario);
+       asprintf(&this->scenario, "%s/%s", this->scenario_dir, name);
+       
+       if (access(this->scenario, F_OK) == 0)
+       {       /* exists, load scenario */
+               DBG1("scenario loading unimplemented.");
+               return FALSE;
+       }
+       else
+       {       /* does not exist, create scenario */
+               if (mkdir(this->scenario, PERME) != 0)
+               {
+                       DBG1("creating scenario directory '%s' failed: %m", this->scenario);
+                       clear_scenario(this);
+                       return FALSE;
+               }                       
+               len = snprintf(dir, sizeof(dir), "%s/%s/%s", this->scenario,
+                                          SCENARIO_DIR, SCENARIO_DIFF_DIR);
+               if (len < 0 || len >= sizeof(dir))
+               {
+                       clear_scenario(this);
+                       return FALSE;
+               }
+               iterator = this->guests->create_iterator(this->guests, TRUE);
+               while (iterator->iterate(iterator, (void**)&guest))
+               {
+                       if (!guest->set_scenario(guest, dir))
+                       {
+                               iterator->destroy(iterator);
+                               clear_scenario(this);
+                               return FALSE;
+                       }
+               }
+               iterator->destroy(iterator);
+       }
+       return TRUE;
+}
+
+/**
+ * Implementation of dumm_t.save_scenario.
+ */
+static bool save_scenario(private_dumm_t *this)
+{
+       DBG1("scenario loading unimplemented.");
+       return FALSE;
+}
+
 /**
  * signal handler 
  */
@@ -205,6 +292,9 @@ 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->dir);
        remove_instance(this);
        free(this);
@@ -219,7 +309,7 @@ static void load_guests(private_dumm_t *this)
        struct dirent *ent;
        guest_t *guest;
        
-       dir = opendir(this->dir);
+       dir = opendir(this->guest_dir);
        if (dir == NULL)
        {
                return;
@@ -231,9 +321,10 @@ static void load_guests(private_dumm_t *this)
                {
                        continue;
                }
-               guest = guest_load(this->dir, ent->d_name);
+               guest = guest_load(this->guest_dir, ent->d_name);
                if (guest)
                {
+                       DBG1("loaded guest '%s'", ent->d_name);
                        this->guests->insert_last(this->guests, guest);
                }
                else
@@ -256,6 +347,8 @@ 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.destroy = (void(*)(dumm_t*))destroy;
        
        this->destroying = FALSE;
@@ -267,11 +360,21 @@ dumm_t *dumm_create(char *dir)
        {
                asprintf(&this->dir, "%s/%s", cwd, dir);
        }
+       this->scenario = NULL;
+       asprintf(&this->guest_dir, "%s/%s", this->dir, GUEST_DIR);
+       asprintf(&this->scenario_dir, "%s/%s", this->dir, SCENARIO_DIR);
        this->guests = linked_list_create();
        this->bridges = linked_list_create();
        
        add_instance(this);
        
+       if (mkdir(this->guest_dir, PERME) < 0 && errno != EEXIST)
+       {
+               DBG1("creating guest directory '%s' failed: %m", this->guest_dir);
+               destroy(this);
+               return NULL;
+       }
+       
        load_guests(this);
        return &this->public;
 }
index dea5f34..6fc3279 100644 (file)
@@ -70,6 +70,21 @@ struct dumm_t {
        iterator_t* (*create_bridge_iterator)(dumm_t *this);
        
        /**
+        * @brief Loads a scenario, create a new one if it does not exist.
+        *
+        * @param name          name of the scenario to load/create
+        * @return                      FALSE if load/crate 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);
+       
+       /**
         * @brief stop all guests and destroy the modeler
         */
        void (*destroy) (dumm_t *this);
index 0506c00..24736f4 100644 (file)
 #define PERME (S_IRWXU | S_IRWXG)
 #define PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)
 
+#define MASTER_DIR "master"
+#define DIFF_DIR "diff"
+#define UNION_DIR "union"
+#define MEMORY_FILE "mem"
+#define KERNEL_FILE "linux"
+#define LOG_FILE "boot.log"
+#define NOTIFY_FILE "notify"
+
 typedef struct private_guest_t private_guest_t;
 
 struct private_guest_t {
@@ -178,7 +186,7 @@ static void stop(private_guest_t *this)
 /**
  * Implementation of guest_t.start.
  */
-static bool start(private_guest_t *this, char *kernel)
+static bool start(private_guest_t *this)
 {
        char buf[2048];
        char *notify;
@@ -241,6 +249,31 @@ static bool start(private_guest_t *this, char *kernel)
        }
        this->state = GUEST_RUNNING;
        return TRUE;
+}      
+       
+/**
+ * Implementation of guest_t.set_scenario.
+ */
+static bool set_scenario(private_guest_t *this, char *path)
+{
+       char dir[PATH_MAX];
+       size_t len;
+       
+       len = snprintf(dir, sizeof(dir), "%s/%s", path, this->name);
+       if (len < 0 || len >= sizeof(dir))
+       {
+               return FALSE;
+       }
+       if (access(dir, F_OK) != 0)
+       {
+               if (mkdir(dir, PERME) != 0)
+               {
+                       DBG1("creating scenario overlay for guest '%s' failed: %m", this->name);
+                       return FALSE;
+               }
+       }
+       this->cowfs->set_scenario(this->cowfs, dir);
+       return TRUE;
 }
 
 /**
@@ -388,6 +421,7 @@ static private_guest_t *guest_create_generic(char *parent, char *name,
        this->public.create_iface_iterator = (iterator_t*(*)(guest_t*))create_iface_iterator;
        this->public.start = (void*)start;
        this->public.stop = (void*)stop;
+       this->public.set_scenario = (bool(*)(guest_t*, char *path))set_scenario;
        this->public.sigchild = (void(*)(guest_t*))sigchild;
        this->public.destroy = (void*)destroy;
        
index d9845e8..eb85ccb 100644 (file)
 
 #include "iface.h"
 
-#define MASTER_DIR "master"
-#define DIFF_DIR "diff"
-#define UNION_DIR "union"
-#define MEMORY_FILE "mem"
-#define KERNEL_FILE "linux"
-#define LOG_FILE "boot.log"
-#define NOTIFY_FILE "notify"
-
 typedef enum guest_state_t guest_state_t;
 
 /**
@@ -72,6 +64,7 @@ struct guest_t {
         * @return              name of the guest
         */
        pid_t (*get_pid) (guest_t *this);
+       
        /**
         * @brief Get the state of the guest (stopped, started, etc.).
         *
@@ -82,10 +75,9 @@ struct guest_t {
        /**
         * @brief Start the guest.
         *
-        * @param kernel        kernel to boot for this guest
         * @return              TRUE if guest successfully started
         */
-       bool (*start) (guest_t *this, char *kernel);
+       bool (*start) (guest_t *this);
        
        /**
         * @brief Kill the guest.
@@ -95,7 +87,7 @@ struct guest_t {
        bool (*stop) (guest_t *this);
        
        /**
-        * @brief Create a new interface for that host.
+        * @brief Create a new interface in the current scenario.
         *
         * @param name  name of the interface in the guest
         * @return              created interface, or NULL if failed
@@ -110,7 +102,15 @@ struct guest_t {
        iterator_t* (*create_iface_iterator)(guest_t *this);
        
        /**
-        * @brief Called whenever a SIGCHILD is received.
+        * @brief Set the scenario COWFS overlay to use.
+        *
+        * @param parent        parent directory where scenario diff should point to
+        * @return                      FALSE if failed
+        */
+       bool (*set_scenario)(guest_t *this, char *parent);
+
+       /**
+        * @brief Called whenever a SIGCHILD for the guests PID is received.
         */
        void (*sigchild)(guest_t *this);
        
index 798251c..3c1bfc4 100644 (file)
@@ -37,6 +37,8 @@ struct private_iface_t {
        char *guestif;
        /** device name at host (tap0) */
        char *hostif;
+       /** bridge this interface is attached to */
+       bridge_t *bridge;
        /** mconsole for guest */
        mconsole_t *mconsole;
 };
@@ -58,6 +60,14 @@ static char* get_hostif(private_iface_t *this)
 }
 
 /**
+ * Implementation of iface_t.set_bridge.
+ */
+static void set_bridge(private_iface_t *this, bridge_t *bridge)
+{
+       this->bridge = bridge;
+}
+
+/**
  * destroy the tap device
  */
 static bool destroy_tap(private_iface_t *this)
@@ -121,6 +131,10 @@ static char* create_tap(private_iface_t *this, char *guest)
  */
 static void destroy(private_iface_t *this)
 {
+       if (this->bridge)
+       {
+               this->bridge->disconnect_iface(this->bridge, &this->public);
+       }
        this->mconsole->del_iface(this->mconsole, this->guestif);
        destroy_tap(this);
        free(this->guestif);
@@ -137,11 +151,13 @@ iface_t *iface_create(char *guest, char *guestif, mconsole_t *mconsole)
        
        this->public.get_hostif = (char*(*)(iface_t*))get_hostif;
        this->public.get_guestif = (char*(*)(iface_t*))get_guestif;
+       this->public.set_bridge = (void(*)(iface_t*, bridge_t*))set_bridge;
        this->public.destroy = (void*)destroy;
 
        this->mconsole = mconsole;
        this->guestif = strdup(guestif);
        this->hostif = create_tap(this, guest);
+       this->bridge = NULL;
        if (this->hostif == NULL)
        {
                destroy_tap(this);
index 06270e8..59de99f 100644 (file)
 #include <library.h>
 #include <utils/iterator.h>
 
-#include "mconsole.h"
-
 #define TAP_DEVICE "/dev/net/tun"
 
 typedef struct iface_t iface_t;
 
+#include "mconsole.h"
+#include "bridge.h"
+
 /**
  * @brief Interface in a guest, connected to a tap device on the host.
  */
@@ -33,22 +34,28 @@ struct iface_t {
        /**
         * @brief Get the interface name in the guest (e.g. eth0).
         *
-        * @return              guest interface name
+        * @return                      guest interface name
         */
        char* (*get_guestif)(iface_t *this);
        
        /**
         * @brief Get the interface name at the host (e.g. tap0).
         *
-        * @return              host interface (tap device) name
+        * @return                      host interface (tap device) name
         */
        char* (*get_hostif)(iface_t *this);
        
+       /**
+        * @brief Set the bridge this interface is attached to.
+        *
+        * @param bridge        assigned bridge, or NULL for none
+        */
+       void (*set_bridge)(iface_t *this, bridge_t *bridge);
+       
        /*
        bool (*up) (iface_t *this);
        bool (*down) (iface_t *this);
        bool (*add_addr) (iface_t *this, host_t *addr);
-       bool (*del_addr) (iface_t *this, host_t *addr);
        iterator_t* (*create_addr_iterator) (iface_t *this);
        */
        
@@ -69,3 +76,4 @@ struct iface_t {
 iface_t *iface_create(char *guest, char *guestif, mconsole_t *mconsole);
 
 #endif /* IFACE_H */
+
index aca5967..4f838e6 100644 (file)
@@ -39,34 +39,7 @@ static void usage()
        printf("  --help|-h                  show this help\n");
 }
 
-/**
- * help for dumm root shell
- */
-static void help()
-{
-       printf("create name=<name>            start a guest named <name>\n");
-       printf("       [master=<dir>]         read only master root filesystem\n");
-       printf("       [memory=<MB>]          guest main memory in megabyte\n");
-       printf("list                          list running guests\n");
-       printf("guest <name>                  open guest menu for <name>\n");
-       printf("help                          show this help\n");
-       printf("quit                          kill quests and exit\n");
-}
-
-/**
- * help for guest shell
- */
-static void help_guest()
-{
-       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");
-       printf("help                          show this help\n");
-       printf("quit                          quit the guest menu\n");
-}
-
+#if 0
 /**
  * add an iface to a guest
  */
@@ -133,267 +106,403 @@ static void list_if(guest_t *guest)
        }
        iterator->destroy(iterator);
 }
+#endif
 
 /**
- * start an UML guest
+ * readline() wrapper
  */
-static void start_guest(guest_t *guest, char *line)
+static char* get_line(char *format, ...)
 {
-       enum {
-               KERNEL = 0,
-       };
-       char *const opts[] = {
-               [KERNEL] = "kernel",
-               NULL
-       };
-       char *value;
-       char *kernel = NULL;
+       char *line = NULL;
+       char *prompt = "";
+       va_list args;
+       
+       va_start(args, format);
+       vasprintf(&prompt, format, args);
+       va_end(args);
        
        while (TRUE)
        {
-               switch (getsubopt(&line, opts, &value))
+               line = readline(prompt);
+               if (line == NULL)
                {
-                       case KERNEL:
-                               kernel = value;
-                               continue;
-                       default:
-                               break;
+                       continue;
+               }
+               if (*line == '\0')
+               {
+                       free(line);
+                       continue;
                }
+               add_history(line);
                break;
        }
-       if (kernel == NULL)
-       {
-               kernel = "./linux";
-       }
+       free(prompt);
+       return line;
+}
+
+/**
+ * get a guest by name
+ */
+static guest_t* get_guest(char *name)
+{
+       iterator_t *iterator;
+       guest_t *guest = NULL;
        
-       printf("starting guest '%s'... \n", guest->get_name(guest));
-       if (guest->start(guest, kernel))
-       {
-               printf("guest '%s' is up\n", guest->get_name(guest));
-       }
-       else
+       iterator = dumm->create_guest_iterator(dumm);
+       while (iterator->iterate(iterator, (void**)&guest))
        {
-               printf("failed to start guest '%s'!\n", guest->get_name(guest));
+               if (streq(guest->get_name(guest), name))
+               {
+                       break;
+               }
+               guest = NULL;
        }
+       iterator->destroy(iterator);
+       return guest;
 }
 
 /**
- * stop (kill) an UML guest
+ * get a bridge by name
  */
-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));
+static bridge_t* get_bridge(char *name)
+{
+       iterator_t *iterator;
+       bridge_t *bridge = NULL;
+       
+       iterator = dumm->create_bridge_iterator(dumm);
+       while (iterator->iterate(iterator, (void**)&bridge))
+       {
+               if (streq(bridge->get_name(bridge), name))
+               {
+                       break;
+               }
+               bridge = NULL;
+       }
+       iterator->destroy(iterator);
+       return bridge;
 }
 
 /**
- * subshell for guests
+ * get an interface by guest name
  */
-static void guest(char *name)
+static iface_t* get_iface(char *name, char *ifname)
 {
-       char *line = NULL;
-       char prompt[32];
-       int len;
-       iterator_t *iterator;
+       iterator_t *guests, *ifaces;
        guest_t *guest;
+       iface_t *iface;
+       
+       guests = dumm->create_guest_iterator(dumm);
+       while (guests->iterate(guests, (void**)&guest))
+       {
+               if (streq(guest->get_name(guest), name))
+               {
+                       iface = NULL;
+                       ifaces = guest->create_iface_iterator(guest);
+                       while (ifaces->iterate(ifaces, (void**)&iface))
+                       {
+                               if (streq(iface->get_guestif(iface), ifname))
+                               {
+                                       break;
+                               }
+                               iface = NULL;
+                       }
+                       ifaces->destroy(ifaces);
+                       if (iface)
+                       {
+                               break;
+                       }
+               }
+       }
+       guests->destroy(guests);
+       return iface;
+}
+
+static void guest_addif_menu(guest_t *guest)
+{
+       char *name;
+       
+       name = get_line("interface name: ");
+       
+       if (!guest->create_iface(guest, name))
+       {
+               printf("creating interface failed\n");
+       }
+}
+
+static void guest_delif_menu(guest_t *guest)
+{
+       char *name;
+       iface_t *iface;
+       iterator_t *iterator;
        bool found = FALSE;
        
-       iterator = dumm->create_guest_iterator(dumm);
-       while (iterator->iterate(iterator, (void**)&guest))
+       name = get_line("interface name: ");
+       
+       iterator = guest->create_iface_iterator(guest);
+       while (iterator->iterate(iterator, (void**)&iface))
        {
-               if (streq(name, guest->get_name(guest)))
+               if (streq(iface->get_guestif(iface), name))
                {
+                       iterator->remove(iterator);
+                       iface->destroy(iface);
                        found = TRUE;
                        break;
                }
        }
        iterator->destroy(iterator);
+       
        if (!found)
        {
-               printf("guest '%s' not found\n", name);
-               return;
+               printf("interface '%s' not found\n");
        }
+}
+
+static void guest_menu(guest_t *guest)
+{
+       while (TRUE)
+       {
+               char *line = get_line("guest/%s# ", guest->get_name(guest));
+               
+               if (streq(line, "back"))
+               {
+                       free(line);
+                       break;
+               }
+               else if (streq(line, "start"))
+               {
+                       if (guest->start(guest))
+                       {
+                               printf("guest '%s' is booting\n", guest->get_name(guest));
+                       }
+                       else
+                       {
+                               printf("failed to start guest '%s'\n", guest->get_name(guest));
+                       }
+               }
+               else if (streq(line, "stop"))
+               {
+                       printf("stopping guest '%s'...\n", guest->get_name(guest));
+                       guest->stop(guest);
+                       printf("guest '%s' is down\n", guest->get_name(guest));
+               }
+               else if (streq(line, "addif"))
+               {
+                       guest_addif_menu(guest);
+               }
+               else if (streq(line, "delif"))
+               {
+                       guest_delif_menu(guest);
+               }
+               else
+               {
+                       printf("back|start|stop|addif|delif\n");
+               }
+               free(line);
+       }
+}
+
+static void guest_create_menu()
+{
+       char *name, *kernel, *master, *mem;
+       guest_t *guest;
        
-       len = snprintf(prompt, sizeof(prompt), "dumm@%s# ", name);
-       if (len < 0 || len >= sizeof(prompt))
+       name = get_line("guest name: ");
+       kernel = get_line("kernel image: ");
+       master = get_line("master filesystem: ");
+       mem = get_line("amount of memory in MB: ");
+       
+       guest = dumm->create_guest(dumm, name, kernel, master, atoi(mem));
+       if (guest)
+       {
+               printf("guest '%s' created\n", guest->get_name(guest));
+               guest_menu(guest);
+       }
+       else
        {
-               return;
+               printf("failed to create guest '%s'\n", name);
        }
+}
 
+static void guest_list_menu()
+{
        while (TRUE)
        {
-               enum {
-                       QUIT = 0,
-                       HELP,
-                       START,
-                       STOP,
-                       ADDIF,
-                       DELIF,
-                       LISTIF,
-               };
-               char *const opts[] = {
-                       [QUIT] = "quit",
-                       [HELP] = "help",
-                       [START] = "start",
-                       [STOP] = "stop",
-                       [ADDIF] = "addif",
-                       [DELIF] = "delif",
-                       [LISTIF] = "listif",
-                       NULL
-               };
-               char *pos, *value;
+               iterator_t *iterator;
+               guest_t *guest;
+               char *line = get_line("guest# ");
                
-               free(line);
-               line = readline(prompt);
-               if (line == NULL || *line == '\0')
+               if (streq(line, "back"))
                {
-                       continue;
+                       free(line);
+                       break;
                }
-               add_history(line);
-               pos = line;
-               while (*pos != '\0')
+               else if (streq(line, "list"))
                {
-                       if (*pos == ' ')
+                       iterator = dumm->create_guest_iterator(dumm);
+                       while (iterator->iterate(iterator, (void**)&guest))
                        {
-                               *pos = ',';
+                               printf("%s\n", guest->get_name(guest));
                        }
-                       pos++;
+                       iterator->destroy(iterator);
                }
-               pos = line;
-               switch (getsubopt(&pos, opts, &value))
+               else if (streq(line, "create"))
                {
-                       case QUIT:
-                               free(line);
-                               break;
-                       case HELP:
-                               help_guest();
-                               continue;
-                       case START:
-                               start_guest(guest, pos);
-                               continue;
-                       case STOP:
-                               stop_guest(guest, pos);
-                               continue;
-                       case ADDIF:
-                               add_if(guest, pos);
-                               continue;
-                       case DELIF:
-                               del_if(guest, pos);
-                               continue;
-                       case LISTIF:
-                               list_if(guest);
-                               continue;
-                       default:
-                               printf("command unknown: '%s'\n", line);
-                               continue;
+                       guest_create_menu();
                }
-               break;
+               else
+               {
+                       guest = get_guest(line);
+                       if (guest)
+                       {
+                               guest_menu(guest);
+                       }
+                       else
+                       {
+                               printf("back|list|create|<guest>\n");
+                       }
+               }
+               free(line);
        }
 }
 
-
-/**
- * create an bridge
- */
-static void create_bridge(char *name)
+static void bridge_addif_menu(bridge_t *bridge)
 {
-       dumm->create_bridge(dumm, name);
-
+       char *name, *ifname;
+       iface_t *iface;
+       
+       name = get_line("guest name: ");
+       ifname = get_line("interface name: ");
+       
+       iface = get_iface(name, ifname);
+       if (!iface)
+       {
+               printf("guest '%s' has no interface named '%s'\n", name, ifname);
+       }
+       else if (!bridge->connect_iface(bridge, iface))
+       {
+               printf("failed to add interface '%s' to bridge '%s'\n", ifname,
+                          bridge->get_name(bridge));
+       }
 }
 
-/**
- * create an UML guest
- */
-static void create_guest(char *line)
+static void bridge_delif_menu(bridge_t *bridge)
 {
-       enum {
-               NAME = 0,
-               KERNEL,
-               MASTER,
-               MEMORY,
-       };
-       char *const opts[] = {
-               [NAME] = "name",
-               [KERNEL] = "kernel",
-               [MASTER] = "master",
-               [MEMORY] = "memory",
-               NULL
-       };
-       char *value;
-       char *name = NULL;
-       char *master = NULL;
-       char *kernel = NULL;
-       int mem = 128;
+       char *name, *ifname;
+       iface_t *iface;
        
-       while (TRUE)
+       name = get_line("guest name: ");
+       ifname = get_line("interface name: ");
+       
+       iface = get_iface(name, ifname);
+       if (!iface)
        {
-               switch (getsubopt(&line, opts, &value))
-               {
-                       case NAME:
-                               name = value;
-                               continue;
-                       case KERNEL:
-                               kernel = value;
-                               continue;
-                       case MASTER:
-                               master = value;
-                               continue;
-                       case MEMORY:
-                               if (value)
-                               {
-                                       mem = atoi(value);
-                               }
-                               continue;
-                       default:
-                               break;
-               }
-               break;
+               printf("guest '%s' has no interface named '%s'\n", name, ifname);
        }
-       if (name == NULL || master == NULL || kernel == NULL)
+       else if (!bridge->disconnect_iface(bridge, iface))
        {
-               printf("too few arguments!\n");
-               help();
-               return;
+               printf("failed to remove interface '%s' from bridge '%s'\n", ifname,
+                          bridge->get_name(bridge));
        }
-       if (mem == 0)
+}
+
+static void bridge_menu(bridge_t *bridge)
+{
+       while (TRUE)
        {
-               mem = 128;
+               char *line = get_line("bridge/%s# ", bridge->get_name(bridge));
+               
+               if (streq(line, "back"))
+               {
+                       free(line);
+                       break;
+               }
+               else if (streq(line, "list"))
+               {
+                       iterator_t *iterator;
+                       iface_t *iface;
+
+                       iterator = bridge->create_iface_iterator(bridge);
+                       while (iterator->iterate(iterator, (void**)&iface))
+                       {
+                               printf("%s (%s)\n", iface->get_guestif(iface), iface->get_hostif(iface));
+                       }
+                       iterator->destroy(iterator);
+               }
+               else if (streq(line, "addif"))
+               {
+                       bridge_addif_menu(bridge);
+               }
+               else if (streq(line, "delif"))
+               {
+                       bridge_delif_menu(bridge);
+               }
+               else
+               {
+                       printf("back|list|addif|delif\n");
+               }
+               free(line);
        }
-       if (dumm->create_guest(dumm, name, kernel, master, mem))
+}
+
+static void bridge_create_menu()
+{
+       char *name;
+       bridge_t *bridge;
+       
+       name = get_line("bridge name: ");
+       
+       bridge = dumm->create_bridge(dumm, name);
+       if (bridge)
        {
-               printf("guest '%s' created\n", name);
-               guest(name);
+               printf("bridge '%s' created\n", bridge->get_name(bridge));
+               bridge_menu(bridge);
        }
        else
        {
-               printf("failed to create guest '%s'!\n", name);
+               printf("failed to create bridge '%s'\n", name);
        }
 }
 
-/**
- * list running UML guests
- */
-static void list()
+static void bridge_list_menu()
 {
-       iterator_t *guests, *ifaces;
-       guest_t *guest;
-       iface_t *iface;
-       
-       guests = dumm->create_guest_iterator(dumm);
-       while (guests->iterate(guests, (void**)&guest))
+       while (TRUE)
        {
-               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))
+               iterator_t *iterator;
+               bridge_t *bridge;
+               char *line = get_line("bridge# ");
+               
+               if (streq(line, "back"))
+               {
+                       free(line);
+                       break;
+               }
+               else if (streq(line, "list"))
                {
-                       printf("  '%s' => '%s'\n",
-                                  iface->get_guestif(iface), iface->get_hostif(iface));
+                       iterator = dumm->create_bridge_iterator(dumm);
+                       while (iterator->iterate(iterator, (void**)&bridge))
+                       {
+                               printf("%s\n", bridge->get_name(bridge));
+                       }
+                       iterator->destroy(iterator);
+               }
+               else if (streq(line, "create"))
+               {
+                       bridge_create_menu();
+               }
+               else
+               {
+                       bridge = get_bridge(line);
+                       if (bridge)
+                       {
+                               bridge_menu(bridge);
+                       }
+                       else
+                       {
+                               printf("back|list|create|<bridge>\n");
+                       }
                }
-               ifaces->destroy(ifaces);
+               free(line);
        }
-       guests->destroy(guests);
 }
 
 /**
@@ -401,7 +510,9 @@ static void list()
  */
 void signal_action(int sig, siginfo_t *info, void *ucontext)
 {
-       printf("\nuse 'quit'\ndumm# ");
+       dumm->destroy(dumm);
+       clear_history();
+       exit(0);
 }
 
 /**
@@ -409,7 +520,6 @@ void signal_action(int sig, siginfo_t *info, void *ucontext)
  */
 int main(int argc, char *argv[])
 {
-       char *line = NULL;
        struct sigaction action;
        char *dir = ".";
 
@@ -438,8 +548,6 @@ int main(int argc, char *argv[])
                break;
        }
        
-       dumm = dumm_create(dir);
-       
        memset(&action, 0, sizeof(action));
        action.sa_sigaction = signal_action;
        action.sa_flags = SA_SIGINFO;
@@ -450,71 +558,30 @@ int main(int argc, char *argv[])
                printf("signal handler setup failed: %m.\n");
                return 1;
        }
-
+       
+       dumm = dumm_create(dir);
        while (TRUE)
        {
-               enum {
-                       QUIT = 0,
-                       HELP,
-                       CREATE,
-                       BRIDGE,
-                       LIST,
-                       GUEST,
-               };
-               char *const opts[] = {
-                       [QUIT] = "quit",
-                       [HELP] = "help",
-                       [CREATE] = "create",
-                       [BRIDGE] = "bridge",
-                       [LIST] = "list",
-                       [GUEST] = "guest",
-                       NULL
-               };
-               char *pos, *value;
+               char *line = get_line("# ");
                
-               free(line);
-               line = readline("dumm# ");
-               if (line == NULL || *line == '\0')
+               if (streq(line, "quit"))
                {
-                       continue;
+                       free(line);
+                       break;
                }
-               
-               add_history(line);
-               pos = line;
-               while (*pos != '\0')
+               else if (streq(line, "guest"))
                {
-                       if (*pos == ' ')
-                       {
-                               *pos = ',';
-                       }
-                       pos++;
+                       guest_list_menu();
                }
-               pos = line;
-               switch (getsubopt(&pos, opts, &value))
+               else if (streq(line, "bridge"))
                {
-                       case QUIT:
-                               free(line);
-                               break;
-                       case HELP:
-                               help();
-                               continue;
-                       case CREATE:
-                               create_guest(pos);
-                               continue;
-                       case BRIDGE:
-                               create_bridge(pos);
-                               continue;
-                       case LIST:
-                               list();
-                               continue;
-                       case GUEST:
-                               guest(pos);
-                               continue;
-                       default:
-                               printf("command unknown: '%s'\n", line);
-                               continue;
+                       bridge_list_menu();
                }
-               break;
+               else
+               {
+                       printf("quit|guest|bridge\n");
+               }
+               free(line);
        }
        dumm->destroy(dumm);
        clear_history();