diff options
Diffstat (limited to 'src/dumm')
-rw-r--r-- | src/dumm/Makefile.am | 14 | ||||
-rw-r--r-- | src/dumm/Makefile.in | 78 | ||||
-rw-r--r-- | src/dumm/bridge.c | 31 | ||||
-rw-r--r-- | src/dumm/bridge.h | 18 | ||||
-rw-r--r-- | src/dumm/dumm.c | 207 | ||||
-rw-r--r-- | src/dumm/dumm.h | 32 | ||||
-rw-r--r-- | src/dumm/guest.c | 162 | ||||
-rw-r--r-- | src/dumm/guest.h | 61 | ||||
-rw-r--r-- | src/dumm/iface.c | 46 | ||||
-rw-r--r-- | src/dumm/iface.h | 6 | ||||
-rw-r--r-- | src/dumm/main.c | 953 | ||||
-rw-r--r-- | src/dumm/mconsole.c | 102 | ||||
-rw-r--r-- | src/dumm/mconsole.h | 11 | ||||
-rw-r--r-- | src/dumm/testing.c | 171 |
14 files changed, 1053 insertions, 839 deletions
diff --git a/src/dumm/Makefile.am b/src/dumm/Makefile.am index 3356e7a57..1e47e8907 100644 --- a/src/dumm/Makefile.am +++ b/src/dumm/Makefile.am @@ -1,12 +1,14 @@ lib_LTLIBRARIES = libdumm.la -ipsec_PROGRAMS = dumm +ipsec_PROGRAMS = dumm testing -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 +testing_SOURCES = testing.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} +testing_LDADD = -ldumm +INCLUDES = -I$(top_srcdir)/src/libstrongswan ${gtk_CFLAGS} AM_CFLAGS = -D_FILE_OFFSET_BITS=64 diff --git a/src/dumm/Makefile.in b/src/dumm/Makefile.in index 3431641d5..7dc53b8c0 100644 --- a/src/dumm/Makefile.in +++ b/src/dumm/Makefile.in @@ -1,8 +1,8 @@ -# Makefile.in generated by automake 1.10 from Makefile.am. +# Makefile.in generated by automake 1.10.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -33,7 +33,7 @@ PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ -ipsec_PROGRAMS = dumm$(EXEEXT) +ipsec_PROGRAMS = dumm$(EXEEXT) testing$(EXEEXT) subdir = src/dumm DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 @@ -51,10 +51,8 @@ am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(ipsecdir)" libLTLIBRARIES_INSTALL = $(INSTALL) LTLIBRARIES = $(lib_LTLIBRARIES) -am__DEPENDENCIES_1 = libdumm_la_DEPENDENCIES = \ - $(top_builddir)/src/libstrongswan/libstrongswan.la \ - $(am__DEPENDENCIES_1) + $(top_builddir)/src/libstrongswan/libstrongswan.la am_libdumm_la_OBJECTS = dumm.lo guest.lo iface.lo bridge.lo \ mconsole.lo cowfs.lo libdumm_la_OBJECTS = $(am_libdumm_la_OBJECTS) @@ -62,7 +60,11 @@ ipsecPROGRAMS_INSTALL = $(INSTALL_PROGRAM) PROGRAMS = $(ipsec_PROGRAMS) am_dumm_OBJECTS = main.$(OBJEXT) dumm_OBJECTS = $(am_dumm_OBJECTS) -dumm_DEPENDENCIES = +am__DEPENDENCIES_1 = +dumm_DEPENDENCIES = $(am__DEPENDENCIES_1) +am_testing_OBJECTS = testing.$(OBJEXT) +testing_OBJECTS = $(am_testing_OBJECTS) +testing_DEPENDENCIES = DEFAULT_INCLUDES = -I.@am__isrc@ depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles @@ -75,8 +77,9 @@ CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ -SOURCES = $(libdumm_la_SOURCES) $(dumm_SOURCES) -DIST_SOURCES = $(libdumm_la_SOURCES) $(dumm_SOURCES) +SOURCES = $(libdumm_la_SOURCES) $(dumm_SOURCES) $(testing_SOURCES) +DIST_SOURCES = $(libdumm_la_SOURCES) $(dumm_SOURCES) \ + $(testing_SOURCES) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) @@ -99,6 +102,7 @@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ ECHO = @ECHO@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ @@ -128,6 +132,7 @@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ +NMEDIT = @NMEDIT@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ @@ -158,7 +163,6 @@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ -backenddir = @backenddir@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ @@ -169,12 +173,11 @@ builddir = @builddir@ confdir = @confdir@ datadir = @datadir@ datarootdir = @datarootdir@ -dbus_CFLAGS = @dbus_CFLAGS@ -dbus_LIBS = @dbus_LIBS@ docdir = @docdir@ dvidir = @dvidir@ -eapdir = @eapdir@ exec_prefix = @exec_prefix@ +gtk_CFLAGS = @gtk_CFLAGS@ +gtk_LIBS = @gtk_LIBS@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ @@ -184,12 +187,12 @@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ -interfacedir = @interfacedir@ ipsecdir = @ipsecdir@ -ipsecgid = @ipsecgid@ -ipsecuid = @ipsecuid@ +ipsecgroup = @ipsecgroup@ +ipsecuser = @ipsecuser@ libdir = @libdir@ libexecdir = @libexecdir@ +libstrongswan_plugins = @libstrongswan_plugins@ linuxdir = @linuxdir@ localedir = @localedir@ localstatedir = @localstatedir@ @@ -202,10 +205,12 @@ plugindir = @plugindir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +resolv_conf = @resolv_conf@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ simreader = @simreader@ srcdir = @srcdir@ +strongswan_conf = @strongswan_conf@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_builddir = @top_builddir@ @@ -213,11 +218,15 @@ top_srcdir = @top_srcdir@ xml_CFLAGS = @xml_CFLAGS@ xml_LIBS = @xml_LIBS@ lib_LTLIBRARIES = libdumm.la -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} +testing_SOURCES = testing.c +libdumm_la_LIBADD = $(top_builddir)/src/libstrongswan/libstrongswan.la -lbridge -lfuse -lutil +dumm_LDADD = -ldumm ${gtk_LIBS} +testing_LDADD = -ldumm +INCLUDES = -I$(top_srcdir)/src/libstrongswan ${gtk_CFLAGS} AM_CFLAGS = -D_FILE_OFFSET_BITS=64 all: all-am @@ -258,8 +267,8 @@ install-libLTLIBRARIES: $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ if test -f $$p; then \ f=$(am__strip_dir) \ - echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ - $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ else :; fi; \ done @@ -267,8 +276,8 @@ uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ p=$(am__strip_dir) \ - echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \ - $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \ done clean-libLTLIBRARIES: @@ -290,8 +299,8 @@ install-ipsecPROGRAMS: $(ipsec_PROGRAMS) || test -f $$p1 \ ; then \ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ - echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(ipsecPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(ipsecdir)/$$f'"; \ - $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(ipsecPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(ipsecdir)/$$f" || exit 1; \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(ipsecPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(ipsecdir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(ipsecPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(ipsecdir)/$$f" || exit 1; \ else :; fi; \ done @@ -312,6 +321,9 @@ clean-ipsecPROGRAMS: dumm$(EXEEXT): $(dumm_OBJECTS) $(dumm_DEPENDENCIES) @rm -f dumm$(EXEEXT) $(LINK) $(dumm_OBJECTS) $(dumm_LDADD) $(LIBS) +testing$(EXEEXT): $(testing_OBJECTS) $(testing_DEPENDENCIES) + @rm -f testing$(EXEEXT) + $(LINK) $(testing_OBJECTS) $(testing_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) @@ -326,6 +338,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iface.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mconsole.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testing.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @@ -359,8 +372,8 @@ ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ - $(AWK) ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS @@ -372,8 +385,8 @@ TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ - $(AWK) ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ @@ -383,13 +396,12 @@ ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ - here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ - $(AWK) ' { files[$$0] = 1; } \ - END { for (i in files) print i; }'`; \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$tags$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$tags $$unique diff --git a/src/dumm/bridge.c b/src/dumm/bridge.c index c6068e60c..cb8017c78 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; - iface_t *current; + enumerator_t *enumerator; + iface_t *current = NULL; 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) { @@ -70,6 +75,7 @@ static bool disconnect_iface(private_bridge_t *this, iface_t *iface) else { iface->set_bridge(iface, NULL); + this->ifaces->remove_at(this->ifaces, enumerator); good = TRUE; } break; @@ -80,7 +86,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; } @@ -118,8 +124,9 @@ static void unregister(iface_t *iface) */ static void destroy(private_bridge_t *this) { - this->ifaces->invoke_function(this->ifaces, (void(*)(void*))unregister); + 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 +157,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 +168,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 <library.h> -#include <utils/iterator.h> +#include <utils/enumerator.h> 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 <errno.h> #include <debug.h> +#include <utils/linked_list.h> #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 enumerator_t* create_guest_enumerator(private_dumm_t *this) +{ + return this->guests->create_enumerator(this->guests); +} + +/** + * Implementation of dumm_t.delete_guest. */ -static iterator_t* create_guest_iterator(private_dumm_t *this) +static void delete_guest(private_dumm_t *this, guest_t *guest) { - return this->guests->create_iterator(this->guests, TRUE); + 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 enumerator_t* create_bridge_enumerator(private_dumm_t *this) +{ + return this->bridges->create_enumerator(this->bridges); +} + +/** + * Implementation of dumm_t.delete_bridge. */ -static iterator_t* create_bridge_iterator(private_dumm_t *this) +static void delete_bridge(private_dumm_t *this, bridge_t *bridge) { - return this->bridges->create_iterator(this->bridges, TRUE); + 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 <signal.h> #include <library.h> -#include <utils/linked_list.h> +#include <utils/enumerator.h> #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 enumerator over bridge_t's + */ + enumerator_t* (*create_bridge_enumerator)(dumm_t *this); + + /** + * @brief Delete a bridge. * - * @return iterator over bridge_t's + * @param bridge bridge to destroy */ - iterator_t* (*create_bridge_iterator)(dumm_t *this); + 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..4b2652688 100644 --- a/src/dumm/guest.c +++ b/src/dumm/guest.c @@ -41,6 +41,7 @@ #define DIFF_DIR "diff" #define UNION_DIR "union" #define MEMORY_FILE "mem" +#define PID_FILE "pid" #define KERNEL_FILE "linux" #define LOG_FILE "boot.log" #define NOTIFY_FILE "notify" @@ -63,8 +64,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 +93,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 +102,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 +123,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); } /** @@ -170,45 +190,62 @@ static char* write_arg(char **pos, size_t *left, char *format, ...) } /** - * Implementation of get_t.close_console. + * Implementation of guest_t.stop. */ -static char* get_console(private_guest_t *this, int console) +static void stop(private_guest_t *this, idle_function_t idle) { - if (this->state == GUEST_RUNNING) + if (this->state != GUEST_STOPPED) { - return this->mconsole->get_console_pts(this->mconsole, console); + this->state = GUEST_STOPPING; + this->ifaces->destroy_offset(this->ifaces, offsetof(iface_t, destroy)); + this->ifaces = linked_list_create(); + kill(this->pid, SIGINT); + while (this->state != GUEST_STOPPED) + { + if (idle) + { + idle(); + } + else + { + usleep(50000); + } + } + unlinkat(this->dir, PID_FILE, 0); } - return NULL; } /** - * Implementation of guest_t.stop. + * save pid in file */ -static void stop(private_guest_t *this) +void savepid(private_guest_t *this) { - if (this->state != GUEST_STOPPED) + FILE *file; + + file = fdopen(openat(this->dir, PID_FILE, O_RDWR | O_CREAT | O_TRUNC, + PERM), "w"); + if (file) { - this->state = GUEST_STOPPING; - 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; + fprintf(file, "%d", this->pid); + fclose(file); } } /** * 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 +263,22 @@ 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) - { - 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->pid = invoke(data, &this->public, args, i); + if (!this->pid) + { + this->state = GUEST_STOPPED; + return FALSE; } + savepid(this); + /* 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 +293,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 +313,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 +329,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; @@ -341,22 +373,6 @@ static bool mount_unionfs(private_guest_t *this) } /** - * 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 */ int loadmem(private_guest_t *this) @@ -402,12 +418,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 +442,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; @@ -458,13 +470,11 @@ static private_guest_t *guest_create_generic(char *parent, char *name, free(this); return NULL; } - this->pid = 0; this->state = GUEST_STOPPED; 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 <library.h> -#include <utils/iterator.h> +#include <utils/enumerator.h> #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. + * + * @param iface interface to destroy + */ + void (*destroy_iface)(guest_t *this, iface_t *iface); + + /** + * @brief Create an enumerator over all guest interfaces. * - * @return iterator over iface_t's + * @return enumerator over iface_t's */ - iterator_t* (*create_iface_iterator)(guest_t *this); + 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 @@ -44,6 +44,42 @@ struct private_iface_t { }; /** + * 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. */ static char* get_guestif(private_iface_t *this) @@ -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 <library.h> -#include <utils/iterator.h> +#include <utils/enumerator.h> #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 d6e142e24..d4f2c5176 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 "dumm.h" + +#include <utils/linked_list.h> -#include <stdio.h> +#include <sys/types.h> #include <unistd.h> -#include <getopt.h> -#include <library.h> -#include <readline/readline.h> -#include <readline/history.h> -#include <dlfcn.h> -#include <dirent.h> -#include "dumm.h" +#include <glib.h> +#include <gtk/gtk.h> +#include <vte/vte.h> +#include <vte/reaper.h> /** - * global set of UMLs guests + * notebook page with vte and guest */ -dumm_t *dumm; +typedef struct { + gint num; + GtkWidget *vte; + guest_t *guest; +} page_t; /** - * show usage information (program arguments) + * Main window */ -static void usage() -{ - printf("Usage:\n"); - printf(" --dir|-d <path> set working dir to <path>\n"); - printf(" --help|-h show this help\n"); -} +GtkWidget *window; /** - * readline() wrapper + * notebook with guests, vtes */ -static char* get_line(char *format, ...) -{ - char *line = NULL; - char *prompt = ""; - va_list args; - - va_start(args, format); - vasprintf(&prompt, format, args); - va_end(args); - - while (TRUE) - { - 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; - } - free(prompt); - return line; -} +GtkWidget *notebook; + +/** + * dumm context + */ +dumm_t *dumm; + +/** + * pages in notebook, page_t + */ +linked_list_t *pages; /** - * get a guest by name + * handle guest termination, SIGCHILD */ -static guest_t* get_guest(char *name) +static void child_exited(VteReaper *vtereaper, gint pid, gint status) { - iterator_t *iterator; - guest_t *guest = NULL; + enumerator_t *enumerator; + page_t *page; - iterator = dumm->create_guest_iterator(dumm); - while (iterator->iterate(iterator, (void**)&guest)) + enumerator = pages->create_enumerator(pages); + while (enumerator->enumerate(enumerator, (void**)&page)) { - if (streq(guest->get_name(guest), name)) + 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; } - guest = NULL; } - iterator->destroy(iterator); - return guest; + enumerator->destroy(enumerator); } -/** - * get a bridge by name - */ -static bridge_t* get_bridge(char *name) +static page_t* get_page(int num) { - iterator_t *iterator; - bridge_t *bridge = NULL; + enumerator_t *enumerator; + page_t *page, *found = NULL; - iterator = dumm->create_bridge_iterator(dumm); - while (iterator->iterate(iterator, (void**)&bridge)) + enumerator = pages->create_enumerator(pages); + while (enumerator->enumerate(enumerator, (void**)&page)) { - if (streq(bridge->get_name(bridge), name)) + if (page->num == num) { + found = page; break; } - bridge = NULL; } - iterator->destroy(iterator); - return bridge; + enumerator->destroy(enumerator); + return found; } /** - * get an interface by guest name + * Guest invocation callback */ -static iface_t* get_iface(char *name, char *ifname) +static pid_t invoke(void *vte, guest_t *guest, + char *args[], int argc) { - 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; + args[argc] = "con0=fd:0,fd:1"; + return vte_terminal_fork_command(VTE_TERMINAL(vte), args[0], args, NULL, + NULL, FALSE, FALSE, FALSE); } -static void guest_addif_menu(guest_t *guest) +void idle(void) { - char *name; - - name = get_line("interface name: "); + gtk_main_iteration_do(FALSE); + sched_yield(); +} + +static void start_guest() +{ + page_t *page; - if (!guest->create_iface(guest, name)) + page = get_page(gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook))); + if (page && page->guest->get_state(page->guest) == GUEST_STOPPED) { - printf("creating interface failed\n"); + vte_terminal_feed(VTE_TERMINAL(page->vte), + "--- starting guest ---\n\r", -1); + page->guest->start(page->guest, invoke, VTE_TERMINAL(page->vte), idle); } - free(name); } -static void guest_delif_menu(guest_t *guest) +static void start_all_guests() { - char *name; - iface_t *iface; - iterator_t *iterator; - bool found = FALSE; - - name = get_line("interface name: "); + enumerator_t *enumerator; + page_t *page; - iterator = guest->create_iface_iterator(guest); - while (iterator->iterate(iterator, (void**)&iface)) + enumerator = pages->create_enumerator(pages); + while (enumerator->enumerate(enumerator, (void**)&page)) { - if (streq(iface->get_guestif(iface), name)) + if (page->guest->get_state(page->guest) == GUEST_STOPPED) { - iterator->remove(iterator); - iface->destroy(iface); - found = TRUE; - break; + vte_terminal_feed(VTE_TERMINAL(page->vte), + "--- starting all guests ---\n\r", -1); + page->guest->start(page->guest, invoke, + VTE_TERMINAL(page->vte), idle); } } - iterator->destroy(iterator); - - if (!found) - { - printf("interface '%s' not found\n"); - } - free(name); + enumerator->destroy(enumerator); } -static void guest_console(guest_t *guest) +static void stop_guest() { - int con; + page_t *page; - for (con = 1; con <= 6; con++) + page = get_page(gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook))); + if (page && page->guest->get_state(page->guest) == GUEST_RUNNING) { - char *pts = guest->get_console(guest, con); - if (pts) - { - printf("%d: %s\n", con, pts); - free(pts); - } + page->guest->stop(page->guest, idle); } } -static void guest_menu(guest_t *guest) +/** + * quit signal handler + */ +static void quit() { - while (TRUE) + enumerator_t *enumerator; + page_t *page; + + dumm->load_template(dumm, NULL); + + enumerator = pages->create_enumerator(pages); + while (enumerator->enumerate(enumerator, &page)) { - char *line = get_line("guest/%s# ", guest->get_name(guest)); - - if (streq(line, "back")) - { - free(line); - break; + if (page->guest->get_state(page->guest) != GUEST_STOPPED) + { + page->guest->stop(page->guest, idle); } - 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); } + enumerator->destroy(enumerator); + gtk_main_quit(); } -static void guest_create_menu() +static void error_dialog(char *msg) { - 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); + 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); } -static void guest_list_menu() +static void create_switch() { + GtkWidget *dialog, *table, *label, *name; + bridge_t *bridge; + + 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); + 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 + switch (gtk_dialog_run(GTK_DIALOG(dialog))) { - guest = get_guest(line); - if (guest) - { - guest_menu(guest); - } - else - { - printf("back|list|create|<guest>\n"); + 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; } + default: + break; } - free(line); + break; } + gtk_widget_destroy(dialog); } -static void bridge_addif_menu(bridge_t *bridge) +static void delete_switch() { - 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) +static void connect_guest() { - char *name, *ifname; + page_t *page; + GtkWidget *dialog, *table, *label, *name, *box; + bridge_t *bridge; iface_t *iface; + enumerator_t *enumerator; - name = get_line("guest name: "); - ifname = get_line("interface name: "); - - iface = get_iface(name, ifname); - if (!iface) + page = get_page(gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook))); + if (!page || page->guest->get_state(page->guest) != GUEST_RUNNING) { - printf("guest '%s' has no interface named '%s'\n", name, ifname); + return; } - else if (!bridge->disconnect_iface(bridge, iface)) + + 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)) { - printf("failed to remove interface '%s' from bridge '%s'\n", ifname, - bridge->get_name(bridge)); + gtk_combo_box_append_text(GTK_COMBO_BOX(box), bridge->get_name(bridge)); } - free(name); - free(ifname); -} - -static void bridge_menu(bridge_t *bridge) -{ + enumerator->destroy(enumerator); + gtk_widget_show(box); + + gtk_widget_show(table); + while (TRUE) { - char *line = get_line("bridge/%s# ", bridge->get_name(bridge)); - - if (streq(line, "back")) - { - free(line); - break; - } - else if (streq(line, "list")) + switch (gtk_dialog_run(GTK_DIALOG(dialog))) { - 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)); + 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; } - 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"); + default: + break; } - free(line); + break; } + gtk_widget_destroy(dialog); } -static void bridge_create_menu() +static void disconnect_guest() { - 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); - } - free(name); + } -static void bridge_list_menu() +static void delete_guest() { - while (TRUE) + page_t *page; + + page = get_page(gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook))); + if (page) { - 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|<bridge>\n"); - } - } - free(line); + 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); } } -static void template_menu() +/** + * create a new page for a guest + */ +static page_t* create_page(guest_t *guest) { - char *name; - - name = get_line("template name (or 'none'): "); + GtkWidget *label; + page_t *page; - dumm->load_template(dumm, streq(name, "none") ? NULL : name); - - free(name); + 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; } -typedef bool (*uml_test_t)(dumm_t *dumm); - -static void test_menu() +/** + * create a new guest + */ +static void create_guest() { - char *name; - void *handle; - struct dirent *ent; - DIR *dir; - uml_test_t test; + 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); - name = get_line("test name: "); + 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); - dir = opendir("tests"); - if (dir) + gtk_widget_show(table); + + while (TRUE) { - while ((ent = readdir(dir))) + switch (gtk_dialog_run(GTK_DIALOG(dialog))) { - 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")) + case GTK_RESPONSE_ACCEPT: { - continue; - } + 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)); - 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)) + if (!sname[0] || !skernel || !smaster) { - printf("success\n"); + continue; } - else + guest = dumm->create_guest(dumm, sname, skernel, smaster, + gtk_spin_button_get_value(GTK_SPIN_BUTTON(memory))); + if (!guest) { - printf("failed\n"); + error_dialog("creating guest failed!"); + continue; } + page = create_page(guest); + gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), page->num); + break; } - else - { - printf("failed to open test %s\n", ent->d_name); - } - dlclose(handle); + default: + break; } + break; } - free(name); -} - -/** - * Signal handler - */ -void signal_action(int sig, siginfo_t *info, void *ucontext) -{ - dumm->destroy(dumm); - clear_history(); - exit(0); + gtk_widget_destroy(dialog); } /** @@ -553,80 +466,156 @@ 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(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_set_sensitive(menuitem, FALSE); + 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_set_sensitive(menuitem, FALSE); + 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); - clear_history(); + pages->destroy_function(pages, g_free); + + library_deinit(); return 0; } diff --git a/src/dumm/mconsole.c b/src/dumm/mconsole.c index 25cb84621..d9864f676 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,58 +193,39 @@ 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 */ static bool wait_bootup(private_mconsole_t *this) { - char *cmd, buf[128]; + char buf[128]; int len, res; - cmd = "config con0"; while (TRUE) { len = sizeof(buf); - res = request(this, cmd, buf, &len); + res = request(this, "config eth9=mcast", buf, &len); if (res < 0) { return FALSE; } if (res == 0) { + while (request(this, "remove eth9", buf, &len) != 0) + { + usleep(50000); + } return TRUE; } - usleep(50000); + if (this->idle) + { + this->idle(); + } + else + { + usleep(50000); + } } } @@ -241,7 +246,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 +263,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 +329,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 @@ -43,14 +43,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 */ void (*destroy) (mconsole_t *this); @@ -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 */ diff --git a/src/dumm/testing.c b/src/dumm/testing.c new file mode 100644 index 000000000..c0d23296b --- /dev/null +++ b/src/dumm/testing.c @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <stdio.h> +#include <signal.h> +#include <unistd.h> +#include <fcntl.h> + +#include <library.h> +#include <dumm.h> + +/** + * number of running guests + */ +static int running = 0; + +/** + * Guest invocation callback + */ +static pid_t invoke(void *vte, guest_t *guest, + char *args[], int argc) +{ + pid_t pid; + + args[argc] = "con0=xterm"; + + pid = fork(); + switch (pid) + { + case 0: /* child */ + dup2(open("/dev/null", 0), 1); + dup2(open("/dev/null", 0), 2); + execvp(args[0], args); + exit(-1); + case -1: + fprintf(stderr, "starting guest '%s' failed\n", guest->get_name(guest)); + return 0; + default: + printf("started guest '%s', pid: %d\n", guest->get_name(guest), pid); + running++; + return pid; + } +} + +/** + * main routine, parses args and reads from console + */ +int main(int argc, char *argv[]) +{ + dumm_t *dumm; + enumerator_t *enumerator; + guest_t *guest; + bridge_t *switch0, *switch1, *switch2; + iface_t *iface; + sigset_t set; + siginfo_t info; + + library_init(NULL); + + dumm = dumm_create(NULL); + + switch0 = dumm->create_bridge(dumm, "switch0"); + switch1 = dumm->create_bridge(dumm, "switch1"); + switch2 = dumm->create_bridge(dumm, "switch2"); + + if (switch0 && switch1 && switch2) + { + enumerator = dumm->create_guest_enumerator(dumm); + while (enumerator->enumerate(enumerator, &guest)) + { + if (!guest->start(guest, invoke, NULL, NULL)) + { + continue; + } + if (streq(guest->get_name(guest), "alice")) + { + iface = guest->create_iface(guest, "eth0"); + if (iface) + { + switch1->connect_iface(switch1, iface); + } + iface = guest->create_iface(guest, "eth1"); + if (iface) + { + switch0->connect_iface(switch0, iface); + } + } + else if (streq(guest->get_name(guest), "moon") || + streq(guest->get_name(guest), "sun")) + { + iface = guest->create_iface(guest, "eth0"); + if (iface) + { + switch0->connect_iface(switch0, iface); + } + iface = guest->create_iface(guest, "eth1"); + if (iface) + { + switch1->connect_iface(switch1, iface); + } + } + else if (streq(guest->get_name(guest), "bob")) + { + iface = guest->create_iface(guest, "eth0"); + if (iface) + { + switch2->connect_iface(switch2, iface); + } + } + else if (streq(guest->get_name(guest), "venus")) + { + iface = guest->create_iface(guest, "eth0"); + if (iface) + { + switch1->connect_iface(switch1, iface); + } + } + else if (streq(guest->get_name(guest), "carol") || + streq(guest->get_name(guest), "winnetou") || + streq(guest->get_name(guest), "dave")) + { + iface = guest->create_iface(guest, "eth0"); + if (iface) + { + switch0->connect_iface(switch0, iface); + } + } + } + enumerator->destroy(enumerator); + + sigemptyset(&set); + sigaddset(&set, SIGINT); + sigaddset(&set, SIGHUP); + sigaddset(&set, SIGTERM); + sigaddset(&set, SIGCHLD); + sigprocmask(SIG_SETMASK, &set, NULL); + while (running) + { + if (sigwaitinfo(&set, &info) == SIGCHLD) + { + enumerator = dumm->create_guest_enumerator(dumm); + while (enumerator->enumerate(enumerator, &guest)) + { + if (guest->get_pid(guest) == info.si_pid) + { + running--; + guest->sigchild(guest); + break; + } + } + enumerator->destroy(enumerator); + } + } + } + dumm->destroy(dumm); + + library_deinit(); + return 0; +} |