From a47486b5e4386b85c0a01424ba83930af8593ccc Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 28 Apr 2008 16:43:30 +0000 Subject: [PATCH] prototype of dumm GUI --- configure.in | 9 +- src/dumm/Makefile.am | 10 +- src/dumm/bridge.c | 26 +- src/dumm/bridge.h | 18 +- src/dumm/dumm.c | 207 +++----- src/dumm/dumm.h | 32 +- src/dumm/guest.c | 141 +++--- src/dumm/guest.h | 61 ++- src/dumm/iface.c | 46 +- src/dumm/iface.h | 6 +- src/dumm/main.c | 1079 +++++++++++++++++++++--------------------- src/dumm/mconsole.c | 93 ++-- src/dumm/mconsole.h | 11 +- 13 files changed, 873 insertions(+), 866 deletions(-) diff --git a/configure.in b/configure.in index 30a9f282d..9751651c7 100644 --- a/configure.in +++ b/configure.in @@ -20,6 +20,7 @@ AC_INIT(strongSwan,4.2.2) AM_INIT_AUTOMAKE(tar-ustar) AC_C_BIGENDIAN AC_SUBST(confdir, '${sysconfdir}') +PKG_PROG_PKG_CONFIG dnl ================================= dnl check --enable-xxx & --with-xxx @@ -581,11 +582,17 @@ if test x$curl = xtrue; then fi if test x$xml = xtrue; then - PKG_CHECK_MODULES(xml, [libxml-2.0],, AC_MSG_ERROR([No libxml2 package information found])) + PKG_CHECK_MODULES(xml, [libxml-2.0]) AC_SUBST(xml_CFLAGS) AC_SUBST(xml_LIBS) fi +if test x$dumm = xtrue; then + PKG_CHECK_MODULES(gtk, [gtk+-2.0 vte]) + AC_SUBST(gtk_CFLAGS) + AC_SUBST(gtk_LIBS) +fi + if test x$fast = xtrue; then AC_HAVE_LIBRARY([neo_cgi],[LIBS="$LIBS"],[AC_MSG_ERROR([ClearSilver library neo_cgi not found!])]) AC_HAVE_LIBRARY([neo_utl],[LIBS="$LIBS"],[AC_MSG_ERROR([ClearSilver library neo_utl not found!])]) diff --git a/src/dumm/Makefile.am b/src/dumm/Makefile.am index 3356e7a57..58d19f5fd 100644 --- a/src/dumm/Makefile.am +++ b/src/dumm/Makefile.am @@ -1,12 +1,12 @@ lib_LTLIBRARIES = libdumm.la 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 +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 ${xml_LIBS} -dumm_LDADD = -ldumm -lreadline - -INCLUDES = -I$(top_srcdir)/src/libstrongswan ${xml_CFLAGS} +libdumm_la_LIBADD = $(top_builddir)/src/libstrongswan/libstrongswan.la -lbridge -lfuse -lutil +dumm_LDADD = -ldumm ${gtk_LIBS} +INCLUDES = -I$(top_srcdir)/src/libstrongswan ${gtk_CFLAGS} AM_CFLAGS = -D_FILE_OFFSET_BITS=64 diff --git a/src/dumm/bridge.c b/src/dumm/bridge.c index 1230dc0d0..73659ea1a 100644 --- a/src/dumm/bridge.c +++ b/src/dumm/bridge.c @@ -31,6 +31,11 @@ struct private_bridge_t { /** list of attached interfaces */ linked_list_t *ifaces; }; + +/** + * defined in iface.c + */ +bool iface_control(char *name, bool up); /** * Implementation of bridge_t.get_name. @@ -41,11 +46,11 @@ static char* get_name(private_bridge_t *this) } /** - * Implementation of bridge_t.create_iface_iterator. + * Implementation of bridge_t.create_iface_enumerator. */ -static iterator_t* create_iface_iterator(private_bridge_t *this) +static enumerator_t* create_iface_enumerator(private_bridge_t *this) { - return this->ifaces->create_iterator(this->ifaces, TRUE); + return this->ifaces->create_enumerator(this->ifaces); } /** @@ -53,12 +58,12 @@ static iterator_t* create_iface_iterator(private_bridge_t *this) */ static bool disconnect_iface(private_bridge_t *this, iface_t *iface) { - iterator_t *iterator; + enumerator_t *enumerator; iface_t *current; bool good = FALSE; - iterator = this->ifaces->create_iterator(this->ifaces, TRUE); - while (iterator->iterate(iterator, (void**)¤t)) + enumerator = this->ifaces->create_enumerator(this->ifaces); + while (enumerator->enumerate(enumerator, (void**)¤t)) { if (current == iface) { @@ -80,7 +85,7 @@ static bool disconnect_iface(private_bridge_t *this, iface_t *iface) DBG1("iface '%s' not found on bridge '%s'", iface->get_hostif(iface), this->name); } - iterator->destroy(iterator); + enumerator->destroy(enumerator); return good; } @@ -120,6 +125,7 @@ static void destroy(private_bridge_t *this) { this->ifaces->invoke_function(this->ifaces, (linked_list_invoke_t)unregister); this->ifaces->destroy(this->ifaces); + iface_control(this->name, FALSE); if (br_del_bridge(this->name) != 0) { DBG1("deleting bridge '%s' from kernel failed: %m", this->name); @@ -150,7 +156,7 @@ 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.create_iface_enumerator = (enumerator_t*(*)(bridge_t*))create_iface_enumerator; 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; @@ -161,6 +167,10 @@ bridge_t *bridge_create(char *name) free(this); return NULL; } + if (!iface_control(name, TRUE)) + { + DBG1("bringing bridge '%s' up failed: %m", name); + } this->name = strdup(name); this->ifaces = linked_list_create(); diff --git a/src/dumm/bridge.h b/src/dumm/bridge.h index 6d28ed376..79a0a3a72 100644 --- a/src/dumm/bridge.h +++ b/src/dumm/bridge.h @@ -17,7 +17,7 @@ #define BRIDGE_H #include -#include +#include typedef struct bridge_t bridge_t; @@ -31,32 +31,32 @@ struct bridge_t { /** * @brief Get the name of the bridge. * - * @return name of the bridge + * @return name of the bridge */ char* (*get_name)(bridge_t *this); /** * @brief Add an interface to a bridge. * - * @param iface interface to add - * @return TRUE if interface added + * @param iface interface to add + * @return TRUE if interface added */ bool (*connect_iface)(bridge_t *this, iface_t *iface); /** * @brief Remove an interface from a bridge. * - * @param iface interface to remove - * @return TRUE if interface removed + * @param iface interface to remove + * @return TRUE if interface removed */ bool (*disconnect_iface)(bridge_t *this, iface_t *iface); /** - * @brief Create an iterator over all interfaces. + * @brief Create an enumerator over all interfaces. * - * @return iterator over iface_t's + * @return enumerator over iface_t's */ - iterator_t* (*create_iface_iterator)(bridge_t *this); + enumerator_t* (*create_iface_enumerator)(bridge_t *this); /** * @brief Destroy a bridge diff --git a/src/dumm/dumm.c b/src/dumm/dumm.c index b9a2814e6..5db8eaee0 100644 --- a/src/dumm/dumm.c +++ b/src/dumm/dumm.c @@ -23,6 +23,7 @@ #include #include +#include #include "dumm.h" @@ -31,11 +32,6 @@ #define TEMPLATE_DIR "templates" #define TEMPLATE_DIR_DIR "diff" -/** - * instances of dumm, used to deliver signals - */ -static linked_list_t *instances = NULL; - typedef struct private_dumm_t private_dumm_t; struct private_dumm_t { @@ -74,11 +70,31 @@ static guest_t* create_guest(private_dumm_t *this, char *name, char *kernel, } /** - * Implementation of dumm_t.create_guest_iterator. + * Implementation of dumm_t.create_guest_enumerator. */ -static iterator_t* create_guest_iterator(private_dumm_t *this) +static enumerator_t* create_guest_enumerator(private_dumm_t *this) { - return this->guests->create_iterator(this->guests, TRUE); + return this->guests->create_enumerator(this->guests); +} + +/** + * Implementation of dumm_t.delete_guest. + */ +static void delete_guest(private_dumm_t *this, guest_t *guest) +{ + if (this->guests->remove(this->guests, guest, NULL)) + { + char buf[512]; + int len; + + len = snprintf(buf, sizeof(buf), "rm -Rf %s/%s", + this->guest_dir, guest->get_name(guest)); + guest->destroy(guest); + if (len > 8 && len < 512) + { + system(buf); + } + } } /** @@ -97,11 +113,22 @@ static bridge_t* create_bridge(private_dumm_t *this, char *name) } /** - * Implementation of dumm_t.create_bridge_iterator. + * Implementation of dumm_t.create_bridge_enumerator. */ -static iterator_t* create_bridge_iterator(private_dumm_t *this) +static enumerator_t* create_bridge_enumerator(private_dumm_t *this) { - return this->bridges->create_iterator(this->bridges, TRUE); + return this->bridges->create_enumerator(this->bridges); +} + +/** + * Implementation of dumm_t.delete_bridge. + */ +static void delete_bridge(private_dumm_t *this, bridge_t *bridge) +{ + if (this->bridges->remove(this->bridges, bridge, NULL)) + { + bridge->destroy(bridge); + } } /** @@ -109,26 +136,18 @@ static iterator_t* create_bridge_iterator(private_dumm_t *this) */ static void clear_template(private_dumm_t *this) { - iterator_t *iterator, *ifaces; + enumerator_t *enumerator; guest_t *guest; - iface_t *iface; free(this->template); this->template = NULL; - iterator = this->guests->create_iterator(this->guests, TRUE); - while (iterator->iterate(iterator, (void**)&guest)) + enumerator = this->guests->create_enumerator(this->guests); + while (enumerator->enumerate(enumerator, (void**)&guest)) { 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); + enumerator->destroy(enumerator); } /** @@ -136,7 +155,7 @@ static void clear_template(private_dumm_t *this) */ static bool load_template(private_dumm_t *this, char *name) { - iterator_t *iterator; + enumerator_t *enumerator; guest_t *guest; char dir[PATH_MAX]; size_t len; @@ -169,131 +188,36 @@ static bool load_template(private_dumm_t *this, char *name) return FALSE; } } - iterator = this->guests->create_iterator(this->guests, TRUE); - while (iterator->iterate(iterator, (void**)&guest)) + enumerator = this->guests->create_enumerator(this->guests); + while (enumerator->enumerate(enumerator, (void**)&guest)) { if (!guest->load_template(guest, dir)) { - iterator->destroy(iterator); + enumerator->destroy(enumerator); clear_template(this); return FALSE; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); return TRUE; } -/** - * signal handler - */ -void signal_handler(int sig, siginfo_t *info, void *ucontext) -{ - if (sig == SIGCHLD) - { - switch (info->si_code) - { - case CLD_EXITED: - case CLD_KILLED: - case CLD_DUMPED: - { - private_dumm_t *this; - guest_t *guest; - iterator_t *iterator, *guests; - - iterator = instances->create_iterator(instances, TRUE); - while (iterator->iterate(iterator, (void**)&this)) - { - if (this->destroying) - { - continue; - } - guests = this->guests->create_iterator(this->guests, TRUE); - while (guests->iterate(guests, (void**)&guest)) - { - if (guest->get_pid(guest) == info->si_pid) - { - guest->sigchild(guest); - break; - } - } - guests->destroy(guests); - } - iterator->destroy(iterator); - break; - } - default: - break; - } - - } - /* SIGHUP is currently just ignored */ -} - -/** - * add a dumm instance - */ -static void add_instance(private_dumm_t *this) -{ - if (instances == NULL) - { - struct sigaction action; - - instances = linked_list_create(); - - memset(&action, 0, sizeof(action)); - action.sa_sigaction = signal_handler; - action.sa_flags = SA_SIGINFO; - - if (sigaction(SIGCHLD, &action, NULL) != 0 || - sigaction(SIGHUP, &action, NULL) != 0) - { - DBG1("installing signal handler failed!"); - } - } - instances->insert_last(instances, this); -} - -/** - * remove a dumm instance - */ -static void remove_instance(private_dumm_t *this) -{ - iterator_t *iterator; - private_dumm_t *current; - - iterator = instances->create_iterator(instances, TRUE); - while (iterator->iterate(iterator, (void**)¤t)) - { - if (current == this) - { - iterator->remove(iterator); - break; - } - } - iterator->destroy(iterator); - if (instances->get_count(instances) == 0) - { - instances->destroy(instances); - instances = NULL; - } -} - /** * Implementation of dumm_t.destroy */ static void destroy(private_dumm_t *this) { - iterator_t *iterator; + enumerator_t *enumerator; guest_t *guest; this->bridges->destroy_offset(this->bridges, offsetof(bridge_t, destroy)); - iterator = this->guests->create_iterator(this->guests, TRUE); - while (iterator->iterate(iterator, (void**)&guest)) + enumerator = this->guests->create_enumerator(this->guests); + while (enumerator->enumerate(enumerator, (void**)&guest)) { - guest->stop(guest); + guest->stop(guest, NULL); } - iterator->destroy(iterator); + enumerator->destroy(enumerator); this->destroying = TRUE; this->guests->destroy_offset(this->guests, offsetof(guest_t, destroy)); @@ -301,7 +225,6 @@ static void destroy(private_dumm_t *this) free(this->template_dir); free(this->template); free(this->dir); - remove_instance(this); free(this); } @@ -329,7 +252,6 @@ static void load_guests(private_dumm_t *this) 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 @@ -349,20 +271,35 @@ dumm_t *dumm_create(char *dir) private_dumm_t *this = malloc_thing(private_dumm_t); this->public.create_guest = (guest_t*(*)(dumm_t*,char*,char*,char*,int))create_guest; - this->public.create_guest_iterator = (iterator_t*(*)(dumm_t*))create_guest_iterator; + this->public.create_guest_enumerator = (enumerator_t*(*)(dumm_t*))create_guest_enumerator; + this->public.delete_guest = (void(*)(dumm_t*,guest_t*))delete_guest; 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.create_bridge_enumerator = (enumerator_t*(*)(dumm_t*))create_bridge_enumerator; + this->public.delete_bridge = (void(*)(dumm_t*,bridge_t*))delete_bridge; this->public.load_template = (bool(*)(dumm_t*, char *name))load_template; this->public.destroy = (void(*)(dumm_t*))destroy; this->destroying = FALSE; - if (*dir == '/' || getcwd(cwd, sizeof(cwd)) == 0) + + if (dir && *dir == '/') { this->dir = strdup(dir); } else { - asprintf(&this->dir, "%s/%s", cwd, dir); + if (getcwd(cwd, sizeof(cwd)) == NULL) + { + free(this); + return NULL; + } + if (dir) + { + asprintf(&this->dir, "%s/%s", cwd, dir); + } + else + { + this->dir = strdup(cwd); + } } this->template = NULL; asprintf(&this->guest_dir, "%s/%s", this->dir, GUEST_DIR); @@ -370,8 +307,6 @@ dumm_t *dumm_create(char *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); diff --git a/src/dumm/dumm.h b/src/dumm/dumm.h index 5414f9993..6abf4fc92 100644 --- a/src/dumm/dumm.h +++ b/src/dumm/dumm.h @@ -19,7 +19,7 @@ #include #include -#include +#include #include "guest.h" #include "bridge.h" @@ -30,8 +30,6 @@ typedef struct dumm_t dumm_t; * @brief dumm - Dynamic Uml Mesh Modeler * * Controls a group of UML guests and their networks. - * Dumm catches SIGCHD and SIGHUP to trace UML child processes and the FUSE - * filesystem. Do not overwrite these signal handlers! */ struct dumm_t { @@ -48,11 +46,18 @@ struct dumm_t { char *master, int mem); /** - * @brief Create an iterator over all guests. + * @brief Create an enumerator over all guests. * - * @return iteraotor over guest_t's + * @return enumerator over guest_t's */ - iterator_t* (*create_guest_iterator) (dumm_t *this); + enumerator_t* (*create_guest_enumerator) (dumm_t *this); + + /** + * @brief Delete a guest from disk. + * + * @param guest guest to destroy + */ + void (*delete_guest) (dumm_t *this, guest_t *guest); /** * @brief Create a new bridge. @@ -63,11 +68,18 @@ struct dumm_t { bridge_t* (*create_bridge)(dumm_t *this, char *name); /** - * @brief Create an iterator over all bridges. + * @brief Create an enumerator over all bridges. * - * @return iterator over bridge_t's + * @return enumerator over bridge_t's */ - iterator_t* (*create_bridge_iterator)(dumm_t *this); + enumerator_t* (*create_bridge_enumerator)(dumm_t *this); + + /** + * @brief Delete a bridge. + * + * @param bridge bridge to destroy + */ + void (*delete_bridge) (dumm_t *this, bridge_t *bridge); /** * @brief Loads a template, create a new one if it does not exist. @@ -86,7 +98,7 @@ struct dumm_t { /** * @brief Create a group of UML hosts and networks. * - * @param dir directory to create guests/load from + * @param dir directory to create guests/load from, NULL for cwd * @return created UML group, or NULL if failed. */ dumm_t *dumm_create(char *dir); diff --git a/src/dumm/guest.c b/src/dumm/guest.c index bbb59f431..58539b751 100644 --- a/src/dumm/guest.c +++ b/src/dumm/guest.c @@ -63,8 +63,6 @@ struct private_guest_t { int pid; /** state of guest */ guest_state_t state; - /** log file for console 0 */ - int bootlog; /** FUSE cowfs instance */ cowfs_t *cowfs; /** mconsole to control running UML */ @@ -94,7 +92,7 @@ static char* get_name(private_guest_t *this) */ static iface_t* create_iface(private_guest_t *this, char *name) { - iterator_t *iterator; + enumerator_t *enumerator; iface_t *iface; if (this->state != GUEST_RUNNING) @@ -103,17 +101,17 @@ static iface_t* create_iface(private_guest_t *this, char *name) return NULL; } - iterator = this->ifaces->create_iterator(this->ifaces, TRUE); - while (iterator->iterate(iterator, (void**)&iface)) + enumerator = this->ifaces->create_enumerator(this->ifaces); + while (enumerator->enumerate(enumerator, (void**)&iface)) { if (streq(name, iface->get_guestif(iface))) { DBG1("guest '%s' already has an interface '%s'", this->name, name); - iterator->destroy(iterator); + enumerator->destroy(enumerator); return NULL; } } - iterator->destroy(iterator); + enumerator->destroy(enumerator); iface = iface_create(this->name, name, this->mconsole); if (iface) @@ -124,11 +122,32 @@ static iface_t* create_iface(private_guest_t *this, char *name) } /** - * Implementation of guest_t.create_iface_iterator. + * Implementation of guest_t.destroy_iface. */ -static iterator_t* create_iface_iterator(private_guest_t *this) +static void destroy_iface(private_guest_t *this, iface_t *iface) { - return this->ifaces->create_iterator(this->ifaces, TRUE); + enumerator_t *enumerator; + iface_t *current; + + enumerator = this->ifaces->create_enumerator(this->ifaces); + while (enumerator->enumerate(enumerator, (void**)¤t)) + { + if (current == iface) + { + this->ifaces->remove_at(this->ifaces, enumerator); + current->destroy(current); + break; + } + } + enumerator->destroy(enumerator); +} + +/** + * Implementation of guest_t.create_iface_enumerator. + */ +static enumerator_t* create_iface_enumerator(private_guest_t *this) +{ + return this->ifaces->create_enumerator(this->ifaces); } /** @@ -169,22 +188,10 @@ static char* write_arg(char **pos, size_t *left, char *format, ...) return res; } -/** - * Implementation of get_t.close_console. - */ -static char* get_console(private_guest_t *this, int console) -{ - if (this->state == GUEST_RUNNING) - { - return this->mconsole->get_console_pts(this->mconsole, console); - } - return NULL; -} - /** * Implementation of guest_t.stop. */ -static void stop(private_guest_t *this) +static void stop(private_guest_t *this, idle_function_t idle) { if (this->state != GUEST_STOPPED) { @@ -192,23 +199,35 @@ static void stop(private_guest_t *this) this->ifaces->destroy_offset(this->ifaces, offsetof(iface_t, destroy)); this->ifaces = linked_list_create(); kill(this->pid, SIGINT); - waitpid(this->pid, NULL, 0); - this->state = GUEST_STOPPED; + while (this->state != GUEST_STOPPED) + { + if (idle) + { + idle(); + } + else + { + usleep(50000); + } + } } } /** * Implementation of guest_t.start. */ -static bool start(private_guest_t *this) +static bool start(private_guest_t *this, invoke_function_t invoke, void* data, + idle_function_t idle) { char buf[2048]; char *notify; char *pos = buf; - char *args[16]; + char *args[32]; int i = 0; size_t left = sizeof(buf); + memset(args, 0, sizeof(args)); + if (this->state != GUEST_STOPPED) { DBG1("unable to start guest in state %N", guest_state_names, this->state); @@ -226,32 +245,20 @@ static bool start(private_guest_t *this) args[i++] = write_arg(&pos, &left, "umid=%s", this->name); args[i++] = write_arg(&pos, &left, "mem=%dM", this->mem); args[i++] = write_arg(&pos, &left, "mconsole=notify:%s", notify); - args[i++] = write_arg(&pos, &left, "con=pts"); - args[i++] = write_arg(&pos, &left, "con0=none,fd:%d", this->bootlog); - args[i++] = NULL; + args[i++] = write_arg(&pos, &left, "con=null"); - this->pid = fork(); - switch (this->pid) + this->pid = invoke(data, &this->public, args, i); + if (!this->pid) { - case 0: /* child, */ - dup2(open("/dev/null", 0), 0); - dup2(this->bootlog, 1); - dup2(this->bootlog, 2); - execvp(args[0], args); - DBG1("starting UML kernel '%s' failed: %m", args[0]); - exit(1); - case -1: - this->state = GUEST_STOPPED; - return FALSE; - default: - break; + this->state = GUEST_STOPPED; + return FALSE; } /* open mconsole */ - this->mconsole = mconsole_create(notify); + this->mconsole = mconsole_create(notify, idle); if (this->mconsole == NULL) { DBG1("opening mconsole at '%s' failed, stopping guest", buf); - stop(this); + stop(this, NULL); return FALSE; } @@ -266,6 +273,7 @@ static bool load_template(private_guest_t *this, char *path) { char dir[PATH_MAX]; size_t len; + iface_t *iface; if (path == NULL) { @@ -285,7 +293,15 @@ static bool load_template(private_guest_t *this, char *path) return FALSE; } } - return this->cowfs->set_overlay(this->cowfs, dir); + if (!this->cowfs->set_overlay(this->cowfs, dir)) + { + return FALSE; + } + while (this->ifaces->remove_last(this->ifaces, (void**)&iface) == SUCCESS) + { + iface->destroy(iface); + } + return TRUE; } /** @@ -293,10 +309,6 @@ static bool load_template(private_guest_t *this, char *path) */ static void sigchild(private_guest_t *this) { - if (this->state != GUEST_STOPPING) - { /* collect zombie if uml crashed */ - waitpid(this->pid, NULL, WNOHANG); - } DESTROY_IF(this->mconsole); this->mconsole = NULL; this->state = GUEST_STOPPED; @@ -340,22 +352,6 @@ static bool mount_unionfs(private_guest_t *this) return FALSE; } -/** - * open logfile for boot messages - */ -static int open_bootlog(private_guest_t *this) -{ - int fd; - - fd = openat(this->dir, LOG_FILE, O_WRONLY | O_CREAT, PERM); - if (fd == -1) - { - DBG1("opening bootlog failed, using stdout"); - return 1; - } - return fd; -} - /** * load memory configuration from file */ @@ -402,12 +398,8 @@ bool savemem(private_guest_t *this, int mem) */ static void destroy(private_guest_t *this) { - stop(this); + stop(this, NULL); umount_unionfs(this); - if (this->bootlog > 1) - { - close(this->bootlog); - } if (this->dir > 0) { close(this->dir); @@ -430,10 +422,10 @@ static private_guest_t *guest_create_generic(char *parent, char *name, this->public.get_pid = (pid_t(*)(guest_t*))get_pid; this->public.get_state = (guest_state_t(*)(guest_t*))get_state; this->public.create_iface = (iface_t*(*)(guest_t*,char*))create_iface; - this->public.create_iface_iterator = (iterator_t*(*)(guest_t*))create_iface_iterator; + this->public.destroy_iface = (void(*)(guest_t*,iface_t*))destroy_iface; + this->public.create_iface_enumerator = (enumerator_t*(*)(guest_t*))create_iface_enumerator; this->public.start = (void*)start; this->public.stop = (void*)stop; - this->public.get_console = (char*(*)(guest_t*,int))get_console; this->public.load_template = (bool(*)(guest_t*, char *path))load_template; this->public.sigchild = (void(*)(guest_t*))sigchild; this->public.destroy = (void*)destroy; @@ -464,7 +456,6 @@ static private_guest_t *guest_create_generic(char *parent, char *name, this->mconsole = NULL; this->ifaces = linked_list_create(); this->mem = 0; - this->bootlog = open_bootlog(this); this->name = strdup(name); this->cowfs = NULL; diff --git a/src/dumm/guest.h b/src/dumm/guest.h index 10b37aaa7..79a47fa62 100644 --- a/src/dumm/guest.h +++ b/src/dumm/guest.h @@ -17,11 +17,12 @@ #define GUEST_H #include -#include +#include #include "iface.h" typedef enum guest_state_t guest_state_t; +typedef struct guest_t guest_t; /** * @brief State of a guest (started, stopped, ...) @@ -44,7 +45,26 @@ enum guest_state_t { */ extern enum_name_t *guest_state_names; -typedef struct guest_t guest_t; +/** + * Invoke function which lauches the UML guest. + * + * Consoles are all set to NULL, you may change them by adding additional UML + * options to args before invocation. + * + * @param data callback data + * @param guest guest to start + * @param args args to use for guest invocation, args[0] is kernel + * @param argc number of elements in args + * @param idle + * @return PID of child, 0 if failed + */ +typedef pid_t (*invoke_function_t)(void *data, guest_t *guest, + char *args[], int argc); + +/** + * Idle function to pass to start(). + */ +typedef void (*idle_function_t)(void); /** * @brief A guest is a UML instance running on the host. @@ -75,27 +95,21 @@ struct guest_t { /** * @brief Start the guest. * - * @return TRUE if guest successfully started + * @param invoke UML guest invocation function + * @param data data to pass back to invoke function + * @param idle idle function to call while waiting on child + * @return TRUE if guest successfully started */ - bool (*start) (guest_t *this); + bool (*start) (guest_t *this, invoke_function_t invoke, void *data, + idle_function_t idle); /** * @brief Kill the guest. * - * @return TRUE if guest was running and killed + * @param idle idle function to call while waiting to termination + * @return TRUE if guest was running and killed */ - bool (*stop) (guest_t *this); - - /** - * @brief Get a console pts device. - * - * 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-5) - * @return pts device file name, NULL if failed - */ - char* (*get_console) (guest_t *this, int console); + bool (*stop) (guest_t *this, idle_function_t idle); /** * @brief Create a new interface in the current scenario. @@ -106,11 +120,18 @@ struct guest_t { iface_t* (*create_iface)(guest_t *this, char *name); /** - * @brief Create an iterator over all guest interfaces. + * @brief Destroy an interface on guest. * - * @return iterator over iface_t's + * @param iface interface to destroy */ - iterator_t* (*create_iface_iterator)(guest_t *this); + void (*destroy_iface)(guest_t *this, iface_t *iface); + + /** + * @brief Create an enumerator over all guest interfaces. + * + * @return enumerator over iface_t's + */ + enumerator_t* (*create_iface_enumerator)(guest_t *this); /** * @brief Set the template COWFS overlay to use. diff --git a/src/dumm/iface.c b/src/dumm/iface.c index 3c1bfc470..b78c10bec 100644 --- a/src/dumm/iface.c +++ b/src/dumm/iface.c @@ -43,6 +43,42 @@ struct private_iface_t { mconsole_t *mconsole; }; +/** + * bring an interface up or down + */ +bool iface_control(char *name, bool up) +{ + int s; + bool good = FALSE; + struct ifreq ifr; + + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + + s = socket(AF_INET, SOCK_DGRAM, 0); + if (!s) + { + return FALSE; + } + if (ioctl(s, SIOCGIFFLAGS, &ifr) == 0) + { + if (up) + { + ifr.ifr_flags |= IFF_UP; + } + else + { + ifr.ifr_flags &= ~IFF_UP; + } + if (ioctl(s, SIOCSIFFLAGS, &ifr) == 0) + { + good = TRUE; + } + } + close(s); + return good; +} + /** * Implementation of iface_t.get_guestif. */ @@ -74,7 +110,11 @@ static bool destroy_tap(private_iface_t *this) { struct ifreq ifr; int tap; - + + if (!iface_control(this->hostif, FALSE)) + { + DBG1("bringing iface down failed: %m"); + } memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TAP | IFF_NO_PI; strncpy(ifr.ifr_name, this->hostif, sizeof(ifr.ifr_name) - 1); @@ -165,6 +205,10 @@ iface_t *iface_create(char *guest, char *guestif, mconsole_t *mconsole) free(this); return NULL; } + if (!iface_control(this->hostif, TRUE)) + { + DBG1("bringing iface '%s' up failed: %m", this->hostif); + } if (!this->mconsole->add_iface(this->mconsole, this->guestif, this->hostif)) { DBG1("creating interface '%s' in guest failed", this->guestif); diff --git a/src/dumm/iface.h b/src/dumm/iface.h index 59de99f22..e04fe4ed1 100644 --- a/src/dumm/iface.h +++ b/src/dumm/iface.h @@ -17,7 +17,7 @@ #define IFACE_H #include -#include +#include #define TAP_DEVICE "/dev/net/tun" @@ -53,10 +53,8 @@ struct iface_t { 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); - iterator_t* (*create_addr_iterator) (iface_t *this); + enumerator_t* (*create_addr_enumerator) (iface_t *this); */ /** diff --git a/src/dumm/main.c b/src/dumm/main.c index b99602137..e8c7bf708 100644 --- a/src/dumm/main.c +++ b/src/dumm/main.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Martin Willi + * Copyright (C) 2008 Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -13,539 +13,452 @@ * for more details. */ -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include - #include "dumm.h" +#include + +#include +#include + +#include +#include +#include +#include + /** - * global set of UMLs guests + * notebook page with vte and guest + */ +typedef struct { + gint num; + GtkWidget *vte; + guest_t *guest; +} page_t; + +/** + * Main window + */ +GtkWidget *window; + +/** + * notebook with guests, vtes + */ +GtkWidget *notebook; + +/** + * dumm context */ dumm_t *dumm; /** - * show usage information (program arguments) + * pages in notebook, page_t */ -static void usage() +linked_list_t *pages; + +/** + * handle guest termination, SIGCHILD + */ +static void child_exited(VteReaper *vtereaper, gint pid, gint status) { - printf("Usage:\n"); - printf(" --dir|-d set working dir to \n"); - printf(" --help|-h show this help\n"); + enumerator_t *enumerator; + page_t *page; + + enumerator = pages->create_enumerator(pages); + while (enumerator->enumerate(enumerator, (void**)&page)) + { + if (page->guest->get_pid(page->guest) == pid) + { + page->guest->sigchild(page->guest); + vte_terminal_feed(VTE_TERMINAL(page->vte), + "\n\r--- guest terminated ---\n\r", -1); + break; + } + } + enumerator->destroy(enumerator); +} + +static page_t* get_page(int num) +{ + enumerator_t *enumerator; + page_t *page, *found = NULL; + + enumerator = pages->create_enumerator(pages); + while (enumerator->enumerate(enumerator, (void**)&page)) + { + if (page->num == num) + { + found = page; + break; + } + } + enumerator->destroy(enumerator); + return found; } /** - * readline() wrapper + * Guest invocation callback */ -static char* get_line(char *format, ...) +static pid_t invoke(void *vte, guest_t *guest, + char *args[], int argc) { - char *line = NULL; - char *prompt = ""; - va_list args; + args[argc] = "con0=fd:0,fd:1"; + return vte_terminal_fork_command(VTE_TERMINAL(vte), args[0], args, NULL, + NULL, FALSE, FALSE, FALSE); +} + +void idle(void) +{ + gtk_main_iteration_do(FALSE); + sched_yield(); +} + +static void start_guest() +{ + page_t *page; - va_start(args, format); - vasprintf(&prompt, format, args); - va_end(args); - - while (TRUE) + page = get_page(gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook))); + if (page && page->guest->get_state(page->guest) == GUEST_STOPPED) { - line = readline(prompt); - if (line == NULL) - { - printf("quit\n"); - dumm->destroy(dumm); - clear_history(); - exit(0); - } - if (*line == '\0') - { - free(line); - continue; - } - add_history(line); - break; + vte_terminal_feed(VTE_TERMINAL(page->vte), + "--- starting guest ---\n\r", -1); + page->guest->start(page->guest, invoke, VTE_TERMINAL(page->vte), idle); + } +} + +static void start_all_guests() +{ + enumerator_t *enumerator; + page_t *page; + + enumerator = pages->create_enumerator(pages); + while (enumerator->enumerate(enumerator, (void**)&page)) + { + if (page->guest->get_state(page->guest) == GUEST_STOPPED) + { + vte_terminal_feed(VTE_TERMINAL(page->vte), + "--- starting all guests ---\n\r", -1); + page->guest->start(page->guest, invoke, + VTE_TERMINAL(page->vte), idle); + } + } + enumerator->destroy(enumerator); +} + +static void stop_guest() +{ + page_t *page; + + page = get_page(gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook))); + if (page && page->guest->get_state(page->guest) == GUEST_RUNNING) + { + page->guest->stop(page->guest, idle); } - free(prompt); - return line; } /** - * get a guest by name + * quit signal handler */ -static guest_t* get_guest(char *name) +static void quit() { - iterator_t *iterator; - guest_t *guest = NULL; + enumerator_t *enumerator; + page_t *page; + + dumm->load_template(dumm, NULL); - iterator = dumm->create_guest_iterator(dumm); - while (iterator->iterate(iterator, (void**)&guest)) + enumerator = pages->create_enumerator(pages); + while (enumerator->enumerate(enumerator, &page)) { - if (streq(guest->get_name(guest), name)) - { - break; + if (page->guest->get_state(page->guest) != GUEST_STOPPED) + { + page->guest->stop(page->guest, idle); } - guest = NULL; } - iterator->destroy(iterator); - return guest; + enumerator->destroy(enumerator); + gtk_main_quit(); } -/** - * get a bridge by name - */ -static bridge_t* get_bridge(char *name) +static void error_dialog(char *msg) { - 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; + GtkWidget *error; + + error = gtk_message_dialog_new(GTK_WINDOW(window), + GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, msg); + gtk_dialog_run(GTK_DIALOG(error)); + gtk_widget_destroy(error); } -/** - * get an interface by guest name - */ -static iface_t* get_iface(char *name, char *ifname) +static void create_switch() { - 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"); - } - free(name); -} - -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"); - } - free(name); -} - -static void guest_console(guest_t *guest) -{ - int con; - - for (con = 1; con <= 6; con++) - { - char *pts = guest->get_console(guest, con); - if (pts) - { - printf("%d: %s\n", con, pts); - free(pts); - } - } -} - -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 running\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 if (streq(line, "console")) - { - guest_console(guest); - } - else - { - printf("back|start|stop|addif|delif|console\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); - } - free(name); - free(kernel); - free(master); - free(mem); -} - -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)); - } - free(name); - free(ifname); -} - -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)); - } - free(name); - free(ifname); -} - -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; + GtkWidget *dialog, *table, *label, *name; bridge_t *bridge; - name = get_line("bridge name: "); + dialog = gtk_dialog_new_with_buttons("Create new switch", GTK_WINDOW(window), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, + GTK_STOCK_NEW, GTK_RESPONSE_ACCEPT, NULL); + + table = gtk_table_new(1, 2, TRUE); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table); + + label = gtk_label_new("Switch name"); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, 0, 0, 0, 0); + gtk_widget_show(label); + + name = gtk_entry_new(); + gtk_table_attach(GTK_TABLE(table), name, 1, 2, 0, 1, + GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0); + gtk_widget_show(name); + + gtk_widget_show(table); - 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); - } - free(name); -} - -static void bridge_list_menu() -{ while (TRUE) { - iterator_t *iterator; - bridge_t *bridge; - char *line = get_line("bridge# "); - - if (streq(line, "back")) + switch (gtk_dialog_run(GTK_DIALOG(dialog))) { - 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)); + case GTK_RESPONSE_ACCEPT: + { + if (streq(gtk_entry_get_text(GTK_ENTRY(name)), "")) + { + continue; + } + bridge = dumm->create_bridge(dumm, + (char*)gtk_entry_get_text(GTK_ENTRY(name))); + if (!bridge) + { + error_dialog("creating bridge failed!"); + continue; + } + break; } - iterator->destroy(iterator); + default: + break; } - 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); + break; } + gtk_widget_destroy(dialog); } -static void template_menu() +static void delete_switch() { - char *name; - - name = get_line("template name (or 'none'): "); - - dumm->load_template(dumm, streq(name, "none") ? NULL : name); - - free(name); + } -typedef bool (*uml_test_t)(dumm_t *dumm); - -static void test_menu() +static void connect_guest() { - char *name; - void *handle; - struct dirent *ent; - DIR *dir; - uml_test_t test; + page_t *page; + GtkWidget *dialog, *table, *label, *name, *box; + bridge_t *bridge; + iface_t *iface; + enumerator_t *enumerator; - name = get_line("test name: "); - - dir = opendir("tests"); - if (dir) + page = get_page(gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook))); + if (!page || page->guest->get_state(page->guest) != GUEST_RUNNING) { - 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); - } + return; + } + + dialog = gtk_dialog_new_with_buttons("Connect guest", GTK_WINDOW(window), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, + GTK_STOCK_NEW, GTK_RESPONSE_ACCEPT, NULL); + + table = gtk_table_new(2, 2, TRUE); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table); + + label = gtk_label_new("Interface name"); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, 0, 0, 0, 0); + gtk_widget_show(label); + + name = gtk_entry_new(); + gtk_table_attach(GTK_TABLE(table), name, 1, 2, 0, 1, + GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0); + gtk_widget_show(name); + + label = gtk_label_new("Connected switch"); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, 0, 0, 0, 0); + gtk_widget_show(label); + + box = gtk_combo_box_new_text(); + gtk_table_attach(GTK_TABLE(table), box, 1, 2, 1, 2, + GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0); + enumerator = dumm->create_bridge_enumerator(dumm); + while (enumerator->enumerate(enumerator, &bridge)) + { + gtk_combo_box_append_text(GTK_COMBO_BOX(box), bridge->get_name(bridge)); + } + enumerator->destroy(enumerator); + gtk_widget_show(box); + + gtk_widget_show(table); + + while (TRUE) + { + switch (gtk_dialog_run(GTK_DIALOG(dialog))) + { + case GTK_RESPONSE_ACCEPT: + { + if (streq(gtk_entry_get_text(GTK_ENTRY(name)), "")) + { + continue; + } + + iface = page->guest->create_iface(page->guest, + (char*)gtk_entry_get_text(GTK_ENTRY(name))); + if (!iface) + { + error_dialog("creating interface failed!"); + continue; + } + enumerator = dumm->create_bridge_enumerator(dumm); + while (enumerator->enumerate(enumerator, &bridge)) + { + if (!bridge->connect_iface(bridge, iface)) + { + error_dialog("connecting interface failed!"); + } + break; + } + enumerator->destroy(enumerator); + break; + } + default: + break; + } + break; + } + gtk_widget_destroy(dialog); +} + +static void disconnect_guest() +{ + +} + +static void delete_guest() +{ + page_t *page; + + page = get_page(gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook))); + if (page) + { + page->guest->stop(page->guest, idle); + dumm->delete_guest(dumm, page->guest); + gtk_notebook_remove_page(GTK_NOTEBOOK(notebook), page->num); + pages->remove(pages, page, NULL); + g_free(page); } - free(name); } /** - * Signal handler + * create a new page for a guest */ -void signal_action(int sig, siginfo_t *info, void *ucontext) +static page_t* create_page(guest_t *guest) { - dumm->destroy(dumm); - clear_history(); - exit(0); + GtkWidget *label; + page_t *page; + + page = g_new(page_t, 1); + page->guest = guest; + page->vte = vte_terminal_new(); + label = gtk_label_new(guest->get_name(guest)); + page->num = gtk_notebook_append_page(GTK_NOTEBOOK(notebook), + page->vte, label); + gtk_widget_show(page->vte); + pages->insert_last(pages, page); + return page; +} + +/** + * create a new guest + */ +static void create_guest() +{ + guest_t *guest; + GtkWidget *dialog, *table, *label, *name, *kernel, *master, *memory; + + dialog = gtk_dialog_new_with_buttons("Create new guest", GTK_WINDOW(window), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, + GTK_STOCK_NEW, GTK_RESPONSE_ACCEPT, NULL); + + table = gtk_table_new(4, 2, TRUE); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table); + + label = gtk_label_new("Guest name"); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, 0, 0, 0, 0); + gtk_widget_show(label); + + label = gtk_label_new("UML kernel"); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, 0, 0, 0, 0); + gtk_widget_show(label); + + label = gtk_label_new("Master filesystem"); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, 0, 0, 0, 0); + gtk_widget_show(label); + + label = gtk_label_new("Memory (MB)"); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, 0, 0, 0, 0); + gtk_widget_show(label); + + name = gtk_entry_new(); + gtk_table_attach(GTK_TABLE(table), name, 1, 2, 0, 1, + GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0); + gtk_widget_show(name); + + kernel = gtk_file_chooser_button_new("Select UML kernel image", + GTK_FILE_CHOOSER_ACTION_OPEN); + gtk_table_attach(GTK_TABLE(table), kernel, 1, 2, 1, 2, + GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0); + gtk_widget_show(kernel); + + master = gtk_file_chooser_button_new("Select master filesystem", + GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER); + gtk_table_attach(GTK_TABLE(table), master, 1, 2, 2, 3, + GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0); + gtk_widget_show(master); + + memory = gtk_spin_button_new_with_range(1, 4096, 1); + gtk_spin_button_set_digits(GTK_SPIN_BUTTON(memory), 0); + gtk_table_attach(GTK_TABLE(table), memory, 1, 2, 3, 4, + GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0); + gtk_widget_show(memory); + + gtk_widget_show(table); + + while (TRUE) + { + switch (gtk_dialog_run(GTK_DIALOG(dialog))) + { + case GTK_RESPONSE_ACCEPT: + { + char *sname, *skernel, *smaster; + page_t *page; + + sname = (char*)gtk_entry_get_text(GTK_ENTRY(name)); + skernel = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(kernel)); + smaster = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(master)); + + if (!sname[0] || !skernel || !smaster) + { + continue; + } + guest = dumm->create_guest(dumm, sname, skernel, smaster, + gtk_spin_button_get_value(GTK_SPIN_BUTTON(memory))); + if (!guest) + { + error_dialog("creating guest failed!"); + continue; + } + page = create_page(guest); + gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), page->num); + break; + } + default: + break; + } + break; + } + gtk_widget_destroy(dialog); } /** @@ -553,84 +466,154 @@ void signal_action(int sig, siginfo_t *info, void *ucontext) */ int main(int argc, char *argv[]) { - struct sigaction action; - char *dir = "."; + GtkWidget *menubar, *menu, *menuitem, *vbox; + GtkWidget *dummMenu, *guestMenu, *switchMenu; + enumerator_t *enumerator; + guest_t *guest; - library_init(STRONGSWAN_CONF); + library_init(NULL); + gtk_init(&argc, &argv); + + pages = linked_list_create(); + dumm = dumm_create(NULL); - while (TRUE) - { - struct option options[] = { - {"dir", 1, 0, 0}, - {"help", 0, 0, 0}, - {0, 0, 0, 0} - }; - - switch (getopt_long(argc, argv, "d:h", options, NULL)) - { - case -1: - break; - case 'd': - dir = optarg; - continue; - case 'h': - usage(); - return 0; - default: - usage(); - return 1; - } - break; - } + /* setup window */ + window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(quit), NULL); + gtk_window_set_title(GTK_WINDOW (window), "Dumm"); + gtk_window_set_default_size(GTK_WINDOW (window), 1000, 500); + g_signal_connect(G_OBJECT(vte_reaper_get()), "child-exited", + G_CALLBACK(child_exited), NULL); - memset(&action, 0, sizeof(action)); - action.sa_sigaction = signal_action; - action.sa_flags = SA_SIGINFO; - if (sigaction(SIGINT, &action, NULL) != 0 || - sigaction(SIGQUIT, &action, NULL) != 0 || - sigaction(SIGTERM, &action, NULL) != 0) - { - printf("signal handler setup failed: %m.\n"); - return 1; - } + /* add vbox with menubar, notebook */ + vbox = gtk_vbox_new(FALSE, 0); + gtk_container_add(GTK_CONTAINER(window), vbox); + menubar = gtk_menu_bar_new(); + gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0); + notebook = gtk_notebook_new(); + g_object_set(G_OBJECT(notebook), "homogeneous", TRUE, NULL); + gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_BOTTOM); + gtk_container_add(GTK_CONTAINER(vbox), notebook); + + /* Dumm menu */ + menu = gtk_menu_new(); + dummMenu = gtk_menu_item_new_with_mnemonic("_Dumm"); + gtk_menu_bar_append(GTK_MENU_BAR(menubar), dummMenu); + gtk_widget_show(dummMenu); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(dummMenu), menu); - dumm = dumm_create(dir); - while (TRUE) + /* Dumm -> exit */ + menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL); + g_signal_connect(G_OBJECT(menuitem), "activate", + G_CALLBACK(quit), NULL); + gtk_menu_append(GTK_MENU(menu), menuitem); + gtk_widget_show(menuitem); + + /* Guest menu */ + menu = gtk_menu_new(); + guestMenu = gtk_menu_item_new_with_mnemonic("_Guest"); + gtk_menu_bar_append(GTK_MENU_BAR(menubar), guestMenu); + gtk_widget_show(guestMenu); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(guestMenu), menu); + + /* Guest -> new */ + menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_NEW, NULL); + g_signal_connect(G_OBJECT(menuitem), "activate", + G_CALLBACK(create_guest), NULL); + gtk_menu_append(GTK_MENU(menu), menuitem); + gtk_widget_show(menuitem); + + /* Guest -> delete */ + menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_DELETE, NULL); + g_signal_connect(G_OBJECT(menuitem), "activate", + G_CALLBACK(delete_guest), NULL); + gtk_menu_append(GTK_MENU(menu), menuitem); + gtk_widget_show(menuitem); + + menuitem = gtk_separator_menu_item_new(); + gtk_menu_append(GTK_MENU(menu), menuitem); + gtk_widget_show(menuitem); + + /* Guest -> start */ + menuitem = gtk_menu_item_new_with_mnemonic("_Start"); + g_signal_connect(G_OBJECT(menuitem), "activate", + G_CALLBACK(start_guest), NULL); + gtk_menu_append(GTK_MENU(menu), menuitem); + gtk_widget_show(menuitem); + + /* Guest -> startall */ + menuitem = gtk_menu_item_new_with_mnemonic("Start _all"); + g_signal_connect(G_OBJECT(menuitem), "activate", + G_CALLBACK(start_all_guests), NULL); + gtk_menu_append(GTK_MENU(menu), menuitem); + gtk_widget_show(menuitem); + + /* Guest -> stop */ + menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_STOP, NULL); + g_signal_connect(G_OBJECT(menuitem), "activate", + G_CALLBACK(stop_guest), NULL); + gtk_menu_append(GTK_MENU(menu), menuitem); + gtk_widget_show(menuitem); + + menuitem = gtk_separator_menu_item_new(); + gtk_menu_append(GTK_MENU(menu), menuitem); + gtk_widget_show(menuitem); + + /* Guest -> connect */ + menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_CONNECT, NULL); + g_signal_connect(G_OBJECT(menuitem), "activate", + G_CALLBACK(connect_guest), NULL); + gtk_menu_append(GTK_MENU(menu), menuitem); + gtk_widget_show(menuitem); + + /* Guest -> disconnect */ + menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_DISCONNECT, NULL); + g_signal_connect(G_OBJECT(menuitem), "activate", + G_CALLBACK(disconnect_guest), NULL); + gtk_menu_append(GTK_MENU(menu), menuitem); + gtk_widget_show(menuitem); + + /* Switch menu */ + menu = gtk_menu_new(); + switchMenu = gtk_menu_item_new_with_mnemonic("_Switch"); + gtk_menu_bar_append(GTK_MENU_BAR(menubar), switchMenu); + gtk_widget_show(switchMenu); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(switchMenu), menu); + + /* Switch -> new */ + menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_NEW, NULL); + g_signal_connect(G_OBJECT(menuitem), "activate", + G_CALLBACK(create_switch), NULL); + gtk_menu_append(GTK_MENU(menu), menuitem); + gtk_widget_show(menuitem); + + /* Switch -> delete */ + menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_DELETE, NULL); + g_signal_connect(G_OBJECT(menuitem), "activate", + G_CALLBACK(delete_switch), NULL); + gtk_menu_append(GTK_MENU(menu), menuitem); + gtk_widget_show(menuitem); + + /* show widgets */ + gtk_widget_show(menubar); + gtk_widget_show(notebook); + gtk_widget_show(vbox); + gtk_widget_show(window); + + /* fill notebook with guests */ + enumerator = dumm->create_guest_enumerator(dumm); + while (enumerator->enumerate(enumerator, (void**)&guest)) { - 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 if (streq(line, "template")) - { - template_menu(); - } - else if (streq(line, "test")) - { - test_menu(); - } - else - { - printf("quit|guest|bridge|template|test\n"); - } - free(line); + create_page(guest); } - dumm->load_template(dumm, NULL); + enumerator->destroy(enumerator); + + gtk_main(); + dumm->destroy(dumm); + pages->destroy_function(pages, g_free); library_deinit(); - clear_history(); return 0; } diff --git a/src/dumm/mconsole.c b/src/dumm/mconsole.c index 25cb84621..6d6d900f0 100644 --- a/src/dumm/mconsole.c +++ b/src/dumm/mconsole.c @@ -44,6 +44,8 @@ struct private_mconsole_t { int notify; /** address of uml socket */ struct sockaddr_un uml; + /** idle function */ + void (*idle)(void); }; /** @@ -91,7 +93,7 @@ static int request(private_mconsole_t *this, char *command, { mconsole_request request; mconsole_reply reply; - int len, total = 0; + int len, total = 0, flags = 0; memset(&request, 0, sizeof(request)); request.magic = MCONSOLE_MAGIC; @@ -101,19 +103,41 @@ static int request(private_mconsole_t *this, char *command, *buf = '\0'; (*size)--; - if (sendto(this->console, &request, sizeof(request), 0, - (struct sockaddr*)&this->uml, sizeof(this->uml)) < 0) + if (this->idle) + { + flags = MSG_DONTWAIT; + } + do + { + if (this->idle) + { + this->idle(); + } + len = sendto(this->console, &request, sizeof(request), flags, + (struct sockaddr*)&this->uml, sizeof(this->uml)); + } + while (len < 0 && (errno == EINTR || errno == EAGAIN)); + + if (len < 0) { snprintf(buf, *size, "sending mconsole command to UML failed: %m"); return -1; } do { - len = recv(this->console, &reply, sizeof(reply), 0); + len = recv(this->console, &reply, sizeof(reply), flags); + if (len < 0 && (errno == EINTR || errno == EAGAIN)) + { + if (this->idle) + { + this->idle(); + } + continue; + } if (len < 0) { snprintf(buf, *size, "receiving from mconsole failed: %m"); - return -1; + return -1; } if (len > 0) { @@ -169,35 +193,6 @@ static bool del_iface(private_mconsole_t *this, char *guest) } return TRUE; } - -/** - * Implementation of mconsole_t.get_console_pts. - */ -static char* get_console_pts(private_mconsole_t *this, int con) -{ - char buf[128]; - char *pos; - int len; - - len = snprintf(buf, sizeof(buf), "config con%d", con); - if (len < 0 || len >= sizeof(buf)) - { - return NULL; - } - len = sizeof(buf); - if (request(this, buf, buf, &len) != 0) - { - DBG1("getting console pts failed: %.*s", len, buf); - return NULL; - } - pos = memchr(buf, ':', len); - if (pos == NULL) - { - return NULL; - } - pos++; - return strndup(pos, len - (pos - buf)); -} /** * Poll until guest is ready @@ -220,7 +215,14 @@ static bool wait_bootup(private_mconsole_t *this) { return TRUE; } - usleep(50000); + if (this->idle) + { + this->idle(); + } + else + { + usleep(50000); + } } } @@ -241,7 +243,7 @@ static bool wait_for_notify(private_mconsole_t *this, char *nsock) { struct sockaddr_un addr; mconsole_notify notify; - int len; + int len, flags = 0; this->notify = socket(AF_UNIX, SOCK_DGRAM, 0); if (this->notify < 0) @@ -258,10 +260,20 @@ static bool wait_for_notify(private_mconsole_t *this, char *nsock) close(this->notify); return FALSE; } + if (this->idle) + { + flags = MSG_DONTWAIT; + } do { - len = recvfrom(this->notify, ¬ify, sizeof(notify), 0, NULL, 0); - } while (len < 0 && errno == EINTR); + if (this->idle) + { + this->idle(); + } + len = recvfrom(this->notify, ¬ify, sizeof(notify), flags, NULL, 0); + } + while (len < 0 && (errno == EINTR || errno == EAGAIN)); + if (len < 0 || len >= sizeof(notify)) { DBG1("reading from mconsole notify socket failed: %m"); @@ -314,15 +326,16 @@ static bool setup_console(private_mconsole_t *this) /** * create the mconsole instance */ -mconsole_t *mconsole_create(char *notify) +mconsole_t *mconsole_create(char *notify, void(*idle)(void)) { private_mconsole_t *this = malloc_thing(private_mconsole_t); this->public.add_iface = (bool(*)(mconsole_t*, char *guest, char *host))add_iface; this->public.del_iface = (bool(*)(mconsole_t*, char *guest))del_iface; - this->public.get_console_pts = (char*(*)(mconsole_t*, int con))get_console_pts; this->public.destroy = (void*)destroy; + this->idle = idle; + if (!wait_for_notify(this, notify)) { free(this); diff --git a/src/dumm/mconsole.h b/src/dumm/mconsole.h index 53aaa1b8b..55ce15dda 100644 --- a/src/dumm/mconsole.h +++ b/src/dumm/mconsole.h @@ -42,14 +42,6 @@ struct mconsole_t { */ bool (*del_iface)(mconsole_t *this, char *guest); - /** - * @brief Get the pts device file assigned to a console. - * - * @param con console number in guest - * @return allocated device string - */ - char* (*get_console_pts)(mconsole_t *this, int con); - /** * @brief Destroy the mconsole instance */ @@ -63,9 +55,10 @@ struct mconsole_t { * to connect to the mconsole socket supplied in the received notification. * * @param notify unix notify socket path + * @param idle idle function to call while waiting for responses * @return mconsole instance, or NULL if failed */ -mconsole_t *mconsole_create(char *notify); +mconsole_t *mconsole_create(char *notify, void(*idle)(void)); #endif /* MCONSOLE_H */