summaryrefslogtreecommitdiff
path: root/src/dumm
diff options
context:
space:
mode:
Diffstat (limited to 'src/dumm')
-rw-r--r--src/dumm/Makefile.am14
-rw-r--r--src/dumm/Makefile.in78
-rw-r--r--src/dumm/bridge.c31
-rw-r--r--src/dumm/bridge.h18
-rw-r--r--src/dumm/dumm.c207
-rw-r--r--src/dumm/dumm.h32
-rw-r--r--src/dumm/guest.c162
-rw-r--r--src/dumm/guest.h61
-rw-r--r--src/dumm/iface.c46
-rw-r--r--src/dumm/iface.h6
-rw-r--r--src/dumm/main.c953
-rw-r--r--src/dumm/mconsole.c102
-rw-r--r--src/dumm/mconsole.h11
-rw-r--r--src/dumm/testing.c171
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**)&current))
+ enumerator = this->ifaces->create_enumerator(this->ifaces);
+ while (enumerator->enumerate(enumerator, (void**)&current))
{
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**)&current))
- {
- 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**)&current))
+ {
+ 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, &notify, sizeof(notify), 0, NULL, 0);
- } while (len < 0 && errno == EINTR);
+ if (this->idle)
+ {
+ this->idle();
+ }
+ len = recvfrom(this->notify, &notify, 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;
+}