diff --git a/src/dumm/Makefile b/src/dumm/Makefile index d7f43ce89..76ce4c716 100644 --- a/src/dumm/Makefile +++ b/src/dumm/Makefile @@ -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 diff --git a/src/dumm/bridge.c b/src/dumm/bridge.c index fa30ab6e9..c6068e60c 100644 --- a/src/dumm/bridge.c +++ b/src/dumm/bridge.c @@ -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; } @@ -103,11 +105,20 @@ 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) diff --git a/src/dumm/bridge.h b/src/dumm/bridge.h index d47f7ee54..6d28ed376 100644 --- a/src/dumm/bridge.h +++ b/src/dumm/bridge.h @@ -19,10 +19,10 @@ #include #include -#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. diff --git a/src/dumm/dumm.c b/src/dumm/dumm.c index 32462845b..3d2ec58d8 100644 --- a/src/dumm/dumm.c +++ b/src/dumm/dumm.c @@ -16,14 +16,21 @@ #define _GNU_SOURCE #include +#include #include #include #include +#include #include #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; } diff --git a/src/dumm/dumm.h b/src/dumm/dumm.h index dea5f3428..6fc32799b 100644 --- a/src/dumm/dumm.h +++ b/src/dumm/dumm.h @@ -69,6 +69,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 */ diff --git a/src/dumm/guest.c b/src/dumm/guest.c index 0506c00f1..24736f47d 100644 --- a/src/dumm/guest.c +++ b/src/dumm/guest.c @@ -36,6 +36,14 @@ #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; diff --git a/src/dumm/guest.h b/src/dumm/guest.h index d9845e8a8..eb85ccb3c 100644 --- a/src/dumm/guest.h +++ b/src/dumm/guest.h @@ -21,14 +21,6 @@ #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); diff --git a/src/dumm/iface.c b/src/dumm/iface.c index 798251c3c..3c1bfc470 100644 --- a/src/dumm/iface.c +++ b/src/dumm/iface.c @@ -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; }; @@ -57,6 +59,14 @@ static char* get_hostif(private_iface_t *this) return this->hostif; } +/** + * Implementation of iface_t.set_bridge. + */ +static void set_bridge(private_iface_t *this, bridge_t *bridge) +{ + this->bridge = bridge; +} + /** * destroy the tap device */ @@ -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); diff --git a/src/dumm/iface.h b/src/dumm/iface.h index 06270e836..59de99f22 100644 --- a/src/dumm/iface.h +++ b/src/dumm/iface.h @@ -19,12 +19,13 @@ #include #include -#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 */ + diff --git a/src/dumm/main.c b/src/dumm/main.c index aca5967c2..4f838e652 100644 --- a/src/dumm/main.c +++ b/src/dumm/main.c @@ -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= start a guest named \n"); - printf(" [master=] read only master root filesystem\n"); - printf(" [memory=] guest main memory in megabyte\n"); - printf("list list running guests\n"); - printf("guest open guest menu for \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=] start a stopped guest\n"); - printf("stop stop a started guest\n"); - printf("addif add an interface to the guest\n"); - printf("delif 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,248 +106,86 @@ 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"; - } - - 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 - { - printf("failed to start guest '%s'!\n", guest->get_name(guest)); - } + free(prompt); + return line; } /** - * stop (kill) an UML guest + * get a guest 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)); -} - -/** - * subshell for guests - */ -static void guest(char *name) +static guest_t* get_guest(char *name) { - char *line = NULL; - char prompt[32]; - int len; iterator_t *iterator; - guest_t *guest; - bool found = FALSE; + guest_t *guest = NULL; iterator = dumm->create_guest_iterator(dumm); while (iterator->iterate(iterator, (void**)&guest)) { - if (streq(name, guest->get_name(guest))) + if (streq(guest->get_name(guest), name)) { - found = TRUE; break; } + guest = NULL; } iterator->destroy(iterator); - if (!found) - { - printf("guest '%s' not found\n", name); - return; - } - - len = snprintf(prompt, sizeof(prompt), "dumm@%s# ", name); - if (len < 0 || len >= sizeof(prompt)) - { - return; - } - - 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; - - free(line); - line = readline(prompt); - if (line == NULL || *line == '\0') - { - continue; - } - add_history(line); - pos = line; - while (*pos != '\0') - { - if (*pos == ' ') - { - *pos = ','; - } - pos++; - } - pos = line; - switch (getsubopt(&pos, opts, &value)) - { - 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; - } - break; - } + return guest; } - /** - * create an bridge + * get a bridge by name */ -static void create_bridge(char *name) +static bridge_t* get_bridge(char *name) { - dumm->create_bridge(dumm, name); - -} - -/** - * create an UML guest - */ -static void create_guest(char *line) -{ - 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; + iterator_t *iterator; + bridge_t *bridge = NULL; - while (TRUE) + iterator = dumm->create_bridge_iterator(dumm); + while (iterator->iterate(iterator, (void**)&bridge)) { - switch (getsubopt(&line, opts, &value)) + if (streq(bridge->get_name(bridge), name)) { - 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; } - break; - } - if (name == NULL || master == NULL || kernel == NULL) - { - printf("too few arguments!\n"); - help(); - return; - } - if (mem == 0) - { - mem = 128; - } - if (dumm->create_guest(dumm, name, kernel, master, mem)) - { - printf("guest '%s' created\n", name); - guest(name); - } - else - { - printf("failed to create guest '%s'!\n", name); + bridge = NULL; } + iterator->destroy(iterator); + return bridge; } /** - * list running UML guests + * get an interface by guest name */ -static void list() +static iface_t* get_iface(char *name, char *ifname) { iterator_t *guests, *ifaces; guest_t *guest; @@ -383,17 +194,315 @@ static void list() guests = dumm->create_guest_iterator(dumm); while (guests->iterate(guests, (void**)&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)) + if (streq(guest->get_name(guest), name)) { - printf(" '%s' => '%s'\n", - iface->get_guestif(iface), iface->get_hostif(iface)); + 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; + } } - ifaces->destroy(ifaces); } 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; + + name = get_line("interface name: "); + + iterator = guest->create_iface_iterator(guest); + while (iterator->iterate(iterator, (void**)&iface)) + { + if (streq(iface->get_guestif(iface), name)) + { + iterator->remove(iterator); + iface->destroy(iface); + found = TRUE; + break; + } + } + iterator->destroy(iterator); + + if (!found) + { + 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; + + 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 + { + printf("failed to create guest '%s'\n", name); + } +} + +static void guest_list_menu() +{ + while (TRUE) + { + iterator_t *iterator; + guest_t *guest; + char *line = get_line("guest# "); + + if (streq(line, "back")) + { + free(line); + break; + } + else if (streq(line, "list")) + { + iterator = dumm->create_guest_iterator(dumm); + while (iterator->iterate(iterator, (void**)&guest)) + { + printf("%s\n", guest->get_name(guest)); + } + iterator->destroy(iterator); + } + else if (streq(line, "create")) + { + guest_create_menu(); + } + else + { + guest = get_guest(line); + if (guest) + { + guest_menu(guest); + } + else + { + printf("back|list|create|\n"); + } + } + free(line); + } +} + +static void bridge_addif_menu(bridge_t *bridge) +{ + 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)); + } +} + +static void bridge_delif_menu(bridge_t *bridge) +{ + 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->disconnect_iface(bridge, iface)) + { + printf("failed to remove interface '%s' from bridge '%s'\n", ifname, + bridge->get_name(bridge)); + } +} + +static void bridge_menu(bridge_t *bridge) +{ + while (TRUE) + { + 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); + } +} + +static void bridge_create_menu() +{ + char *name; + bridge_t *bridge; + + name = get_line("bridge name: "); + + bridge = dumm->create_bridge(dumm, name); + if (bridge) + { + printf("bridge '%s' created\n", bridge->get_name(bridge)); + bridge_menu(bridge); + } + else + { + printf("failed to create bridge '%s'\n", name); + } +} + +static void bridge_list_menu() +{ + while (TRUE) + { + iterator_t *iterator; + bridge_t *bridge; + char *line = get_line("bridge# "); + + if (streq(line, "back")) + { + free(line); + break; + } + else if (streq(line, "list")) + { + 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|\n"); + } + } + free(line); + } } /** @@ -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("# "); + if (streq(line, "quit")) + { + free(line); + break; + } + else if (streq(line, "guest")) + { + guest_list_menu(); + } + else if (streq(line, "bridge")) + { + bridge_list_menu(); + } + else + { + printf("quit|guest|bridge\n"); + } free(line); - line = readline("dumm# "); - if (line == NULL || *line == '\0') - { - continue; - } - - add_history(line); - pos = line; - while (*pos != '\0') - { - if (*pos == ' ') - { - *pos = ','; - } - pos++; - } - pos = line; - switch (getsubopt(&pos, opts, &value)) - { - 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; - } - break; } dumm->destroy(dumm); clear_history();