summaryrefslogtreecommitdiff
path: root/src/dumm
diff options
context:
space:
mode:
authorRene Mayrhofer <rene@mayrhofer.eu.org>2008-10-29 11:11:01 +0000
committerRene Mayrhofer <rene@mayrhofer.eu.org>2008-10-29 11:11:01 +0000
commit8b80ab5a6950ce6515f477624794defd7531642a (patch)
treeaa8303f3806c5615fbeafc4dc82febe3cd7c24dc /src/dumm
parentdb67c87db3c9089ea8d2e14f617bf3d9e2af261f (diff)
downloadvyos-strongswan-8b80ab5a6950ce6515f477624794defd7531642a.tar.gz
vyos-strongswan-8b80ab5a6950ce6515f477624794defd7531642a.zip
[svn-upgrade] Integrating new upstream version, strongswan (4.2.8)
Diffstat (limited to 'src/dumm')
-rw-r--r--src/dumm/Makefile.am15
-rw-r--r--src/dumm/Makefile.in38
-rw-r--r--src/dumm/bridge.c22
-rw-r--r--src/dumm/cowfs.c9
-rw-r--r--src/dumm/dumm.c55
-rw-r--r--src/dumm/dumm.h9
-rw-r--r--src/dumm/ext/README8
-rw-r--r--src/dumm/ext/dumm.c633
-rw-r--r--src/dumm/ext/extconf.rb21
-rw-r--r--src/dumm/ext/lib/dumm.rb21
-rw-r--r--src/dumm/ext/lib/dumm/guest.rb40
-rw-r--r--src/dumm/guest.c174
-rw-r--r--src/dumm/guest.h41
-rw-r--r--src/dumm/iface.c112
-rw-r--r--src/dumm/iface.h48
-rw-r--r--src/dumm/irdumm.c60
-rw-r--r--src/dumm/main.c18
-rw-r--r--src/dumm/mconsole.c110
-rw-r--r--src/dumm/mconsole.h11
-rw-r--r--src/dumm/testing.c171
20 files changed, 1251 insertions, 365 deletions
diff --git a/src/dumm/Makefile.am b/src/dumm/Makefile.am
index 1e47e8907..11d65bba9 100644
--- a/src/dumm/Makefile.am
+++ b/src/dumm/Makefile.am
@@ -1,14 +1,19 @@
+EXTRA_DIST = ext/dumm.c ext/extconf.rb ext/README \
+ ext/lib/dumm.rb ext/lib/dumm/guest.rb
+
lib_LTLIBRARIES = libdumm.la
-ipsec_PROGRAMS = dumm testing
+ipsec_PROGRAMS = dumm irdumm
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
+irdumm_SOURCES = irdumm.c
-libdumm_la_LIBADD = $(top_builddir)/src/libstrongswan/libstrongswan.la -lbridge -lfuse -lutil
+libdumm_la_LIBADD = $(top_builddir)/src/libstrongswan/libstrongswan.la \
+ -lbridge -lfuse -lutil
dumm_LDADD = -ldumm ${gtk_LIBS}
-testing_LDADD = -ldumm
+irdumm_LDADD = -ldumm -lruby1.8
-INCLUDES = -I$(top_srcdir)/src/libstrongswan ${gtk_CFLAGS}
+INCLUDES = -I$(top_srcdir)/src/libstrongswan ${gtk_CFLAGS} \
+ -I/usr/lib/ruby/1.8/i486-linux/
AM_CFLAGS = -D_FILE_OFFSET_BITS=64
diff --git a/src/dumm/Makefile.in b/src/dumm/Makefile.in
index 7dc53b8c0..333e616d3 100644
--- a/src/dumm/Makefile.in
+++ b/src/dumm/Makefile.in
@@ -33,7 +33,7 @@ PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
-ipsec_PROGRAMS = dumm$(EXEEXT) testing$(EXEEXT)
+ipsec_PROGRAMS = dumm$(EXEEXT) irdumm$(EXEEXT)
subdir = src/dumm
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@@ -62,9 +62,9 @@ am_dumm_OBJECTS = main.$(OBJEXT)
dumm_OBJECTS = $(am_dumm_OBJECTS)
am__DEPENDENCIES_1 =
dumm_DEPENDENCIES = $(am__DEPENDENCIES_1)
-am_testing_OBJECTS = testing.$(OBJEXT)
-testing_OBJECTS = $(am_testing_OBJECTS)
-testing_DEPENDENCIES =
+am_irdumm_OBJECTS = irdumm.$(OBJEXT)
+irdumm_OBJECTS = $(am_irdumm_OBJECTS)
+irdumm_DEPENDENCIES =
DEFAULT_INCLUDES = -I.@am__isrc@
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
@@ -77,9 +77,8 @@ 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) $(testing_SOURCES)
-DIST_SOURCES = $(libdumm_la_SOURCES) $(dumm_SOURCES) \
- $(testing_SOURCES)
+SOURCES = $(libdumm_la_SOURCES) $(dumm_SOURCES) $(irdumm_SOURCES)
+DIST_SOURCES = $(libdumm_la_SOURCES) $(dumm_SOURCES) $(irdumm_SOURCES)
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@@ -198,6 +197,8 @@ localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
+nm_CFLAGS = @nm_CFLAGS@
+nm_LIBS = @nm_LIBS@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
piddir = @piddir@
@@ -217,16 +218,23 @@ top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
xml_CFLAGS = @xml_CFLAGS@
xml_LIBS = @xml_LIBS@
+EXTRA_DIST = ext/dumm.c ext/extconf.rb ext/README \
+ ext/lib/dumm.rb ext/lib/dumm/guest.rb
+
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
dumm_SOURCES = main.c
-testing_SOURCES = testing.c
-libdumm_la_LIBADD = $(top_builddir)/src/libstrongswan/libstrongswan.la -lbridge -lfuse -lutil
+irdumm_SOURCES = irdumm.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}
+irdumm_LDADD = -ldumm -lruby1.8
+INCLUDES = -I$(top_srcdir)/src/libstrongswan ${gtk_CFLAGS} \
+ -I/usr/lib/ruby/1.8/i486-linux/
+
AM_CFLAGS = -D_FILE_OFFSET_BITS=64
all: all-am
@@ -321,9 +329,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)
+irdumm$(EXEEXT): $(irdumm_OBJECTS) $(irdumm_DEPENDENCIES)
+ @rm -f irdumm$(EXEEXT)
+ $(LINK) $(irdumm_OBJECTS) $(irdumm_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
@@ -336,9 +344,9 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dumm.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/guest.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iface.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/irdumm.Po@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 $@ $<
diff --git a/src/dumm/bridge.c b/src/dumm/bridge.c
index cb8017c78..209e54fc1 100644
--- a/src/dumm/bridge.c
+++ b/src/dumm/bridge.c
@@ -112,19 +112,23 @@ static bool connect_iface(private_bridge_t *this, iface_t *iface)
static int instances = 0;
/**
- * unregister an interface from bridge
- */
-static void unregister(iface_t *iface)
-{
- iface->set_bridge(iface, NULL);
-}
-
-/**
* Implementation of bridge_t.destroy.
*/
static void destroy(private_bridge_t *this)
{
- this->ifaces->invoke_function(this->ifaces, (linked_list_invoke_t)unregister);
+ enumerator_t *enumerator;
+ iface_t *iface;
+
+ enumerator = this->ifaces->create_enumerator(this->ifaces);
+ while (enumerator->enumerate(enumerator, (void**)&iface))
+ {
+ if (br_del_interface(this->name, iface->get_hostif(iface)) != 0)
+ {
+ DBG1("disconnecting iface '%s' failed: %m", iface->get_hostif(iface));
+ }
+ iface->set_bridge(iface, NULL);
+ }
+ enumerator->destroy(enumerator);
this->ifaces->destroy(this->ifaces);
iface_control(this->name, FALSE);
if (br_del_bridge(this->name) != 0)
diff --git a/src/dumm/cowfs.c b/src/dumm/cowfs.c
index 4c16c7c5d..88041811e 100644
--- a/src/dumm/cowfs.c
+++ b/src/dumm/cowfs.c
@@ -709,8 +709,9 @@ static int cowfs_write(const char *path, const char *buf, size_t size,
rel(&path);
- fd = get_rd(path);
- if (fd == this->master_fd)
+ fd = get_wr(path);
+ if (fd == this->master_fd ||
+ (this->over_fd > 0 && fd == this->host_fd))
{
fd = copy(path);
if (fd < 0)
@@ -858,13 +859,15 @@ cowfs_t *cowfs_create(char *master, char *host, char *mount)
{
DBG1("failed to open master filesystem '%s'", master);
free(this);
+ return NULL;
}
this->host_fd = open(host, O_RDONLY | O_DIRECTORY);
- if (this->master_fd < 0)
+ if (this->host_fd < 0)
{
DBG1("failed to open host filesystem '%s'", host);
close(this->master_fd);
free(this);
+ return NULL;
}
this->over_fd = -1;
diff --git a/src/dumm/dumm.c b/src/dumm/dumm.c
index 5db8eaee0..eaefddb60 100644
--- a/src/dumm/dumm.c
+++ b/src/dumm/dumm.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2008 Tobias Brunner
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -29,8 +30,6 @@
#define PERME (S_IRWXU | S_IRWXG)
#define GUEST_DIR "guests"
-#define TEMPLATE_DIR "templates"
-#define TEMPLATE_DIR_DIR "diff"
typedef struct private_dumm_t private_dumm_t;
@@ -41,27 +40,23 @@ struct private_dumm_t {
char *dir;
/** directory of guests */
char *guest_dir;
- /** directory of templates */
- char *template_dir;
/** directory of loaded template */
char *template;
/** list of managed guests */
linked_list_t *guests;
/** list of managed bridges */
linked_list_t *bridges;
- /** do not catch signals if we are destroying */
- bool destroying;
};
/**
* Implementation of dumm_t.create_guest.
*/
static guest_t* create_guest(private_dumm_t *this, char *name, char *kernel,
- char *master, int mem)
+ char *master, char *args)
{
guest_t *guest;
- guest = guest_create(this->guest_dir, name, kernel, master, mem);
+ guest = guest_create(this->guest_dir, name, kernel, master, args);
if (guest)
{
this->guests->insert_last(this->guests, guest);
@@ -153,45 +148,36 @@ static void clear_template(private_dumm_t *this)
/**
* Implementation of dumm_t.load_template.
*/
-static bool load_template(private_dumm_t *this, char *name)
+static bool load_template(private_dumm_t *this, char *dir)
{
enumerator_t *enumerator;
guest_t *guest;
- char dir[PATH_MAX];
- size_t len;
clear_template(this);
- if (name == NULL)
+ if (dir == NULL)
{
return TRUE;
}
-
- free(this->template);
- asprintf(&this->template, "%s/%s", this->template_dir, name);
- len = snprintf(dir, sizeof(dir), "%s/%s", this->template, TEMPLATE_DIR_DIR);
- if (len < 0 || len >= sizeof(dir))
+ if (strlen(dir) > PATH_MAX)
{
+ DBG1("template directory string '%s' is too long", dir);
return FALSE;
}
+ this->template = strdup(dir);
if (access(this->template, F_OK) != 0)
{ /* does not exist, create template */
- if (mkdir(this->template, PERME) != 0)
+ if (!mkdir_p(this->template, PERME))
{
DBG1("creating template directory '%s' failed: %m", this->template);
return FALSE;
}
- if (mkdir(dir, PERME) != 0)
- {
- DBG1("creating template overlay directory '%s' failed: %m", dir);
- return FALSE;
- }
}
enumerator = this->guests->create_enumerator(this->guests);
while (enumerator->enumerate(enumerator, (void**)&guest))
{
- if (!guest->load_template(guest, dir))
+ if (!guest->load_template(guest, this->template))
{
enumerator->destroy(enumerator);
clear_template(this);
@@ -219,10 +205,12 @@ static void destroy(private_dumm_t *this)
}
enumerator->destroy(enumerator);
- this->destroying = TRUE;
- this->guests->destroy_offset(this->guests, offsetof(guest_t, destroy));
+ while (this->guests->remove_last(this->guests, (void**)&guest) == SUCCESS)
+ {
+ guest->destroy(guest);
+ }
+ this->guests->destroy(this->guests);
free(this->guest_dir);
- free(this->template_dir);
free(this->template);
free(this->dir);
free(this);
@@ -270,7 +258,7 @@ dumm_t *dumm_create(char *dir)
char cwd[PATH_MAX];
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 = (guest_t*(*)(dumm_t*,char*,char*,char*,char*))create_guest;
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;
@@ -279,8 +267,6 @@ dumm_t *dumm_create(char *dir)
this->public.load_template = (bool(*)(dumm_t*, char *name))load_template;
this->public.destroy = (void(*)(dumm_t*))destroy;
- this->destroying = FALSE;
-
if (dir && *dir == '/')
{
this->dir = strdup(dir);
@@ -303,7 +289,6 @@ dumm_t *dumm_create(char *dir)
}
this->template = NULL;
asprintf(&this->guest_dir, "%s/%s", this->dir, GUEST_DIR);
- asprintf(&this->template_dir, "%s/%s", this->dir, TEMPLATE_DIR);
this->guests = linked_list_create();
this->bridges = linked_list_create();
@@ -313,13 +298,7 @@ dumm_t *dumm_create(char *dir)
destroy(this);
return NULL;
}
- if (mkdir(this->template_dir, PERME) < 0 && errno != EEXIST)
- {
- DBG1("creating template directory '%s' failed: %m", this->template_dir);
- destroy(this);
- return NULL;
- }
-
+
load_guests(this);
return &this->public;
}
diff --git a/src/dumm/dumm.h b/src/dumm/dumm.h
index 6abf4fc92..f5db0e45b 100644
--- a/src/dumm/dumm.h
+++ b/src/dumm/dumm.h
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2008 Tobias Brunner
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -39,11 +40,11 @@ struct dumm_t {
* @param name name of the guest
* @param kernel UML kernel to use for guest
* @param master mounted read only master filesystem
- * @param mem amount of memory for guest, in MB
+ * @param args additional args to pass to kernel
* @return guest if started, NULL if failed
*/
guest_t* (*create_guest) (dumm_t *this, char *name, char *kernel,
- char *master, int mem);
+ char *master, char *args);
/**
* @brief Create an enumerator over all guests.
@@ -84,10 +85,10 @@ struct dumm_t {
/**
* @brief Loads a template, create a new one if it does not exist.
*
- * @param name name of the template, NULL to close
+ * @param name dir to the template, NULL to close
* @return FALSE if load/create failed
*/
- bool (*load_template)(dumm_t *this, char *name);
+ bool (*load_template)(dumm_t *this, char *dir);
/**
* @brief stop all guests and destroy the modeler
diff --git a/src/dumm/ext/README b/src/dumm/ext/README
new file mode 100644
index 000000000..270d9d59d
--- /dev/null
+++ b/src/dumm/ext/README
@@ -0,0 +1,8 @@
+DUMM Ruby Extension
+===================
+
+Build and Install
+
+ $ ruby extconf.rb
+ $ make
+ # make install
diff --git a/src/dumm/ext/dumm.c b/src/dumm/ext/dumm.c
new file mode 100644
index 000000000..97f14ef85
--- /dev/null
+++ b/src/dumm/ext/dumm.c
@@ -0,0 +1,633 @@
+/*
+ * Copyright (C) 2008 Tobias Brunner
+ * 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.
+ *
+ * $Id: dumm.c 4410 2008-10-10 11:20:04Z martin $
+ */
+
+#include <stdio.h>
+#include <signal.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <library.h>
+#include <dumm.h>
+#include <debug.h>
+
+#undef PACKAGE_NAME
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+#undef PACKAGE_STRING
+#include <ruby.h>
+
+static dumm_t *dumm;
+
+static VALUE rbm_dumm;
+static VALUE rbc_guest;
+static VALUE rbc_bridge;
+static VALUE rbc_iface;
+static VALUE rbc_template;
+
+/**
+ * Guest invocation callback
+ */
+static pid_t invoke(void *null, guest_t *guest, char *args[], int argc)
+{
+ pid_t pid;
+
+ pid = fork();
+ switch (pid)
+ {
+ case 0: /* child */
+ /* create a new process group in order to prevent signals (e.g.
+ * SIGINT) sent to the parent from terminating the child */
+ setpgid(0, 0);
+ dup2(open("/dev/null", 0), 1);
+ dup2(open("/dev/null", 0), 2);
+ execvp(args[0], args);
+ /* FALL */
+ case -1:
+ return 0;
+ default:
+ return pid;
+ }
+}
+
+/**
+ * SIGCHLD signal handler
+ */
+static void sigchld_handler(int signal, siginfo_t *info, void* ptr)
+{
+ enumerator_t *enumerator;
+ guest_t *guest;
+
+ enumerator = dumm->create_guest_enumerator(dumm);
+ while (enumerator->enumerate(enumerator, &guest))
+ {
+ if (guest->get_pid(guest) == info->si_pid)
+ {
+ guest->sigchild(guest);
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+}
+
+
+
+/**
+ * Guest bindings
+ */
+static VALUE guest_find(VALUE class, VALUE key)
+{
+ enumerator_t *enumerator;
+ guest_t *guest, *found = NULL;
+ if (TYPE(key) == T_SYMBOL) {
+ key = rb_convert_type(key, T_STRING, "String", "to_s");
+ }
+ enumerator = dumm->create_guest_enumerator(dumm);
+ while (enumerator->enumerate(enumerator, &guest))
+ {
+ if (streq(guest->get_name(guest), StringValuePtr(key)))
+ {
+ found = guest;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ if (!found)
+ {
+ return Qnil;
+ }
+ return Data_Wrap_Struct(class, NULL, NULL, found);
+}
+
+static VALUE guest_get(VALUE class, VALUE key)
+{
+ VALUE guest = guest_find(class, key);
+ if (NIL_P(guest))
+ {
+ rb_raise(rb_eRuntimeError, "guest not found");
+ }
+ return guest;
+}
+
+static VALUE guest_each(int argc, VALUE *argv, VALUE class)
+{
+ enumerator_t *enumerator;
+ guest_t *guest;
+
+ if (!rb_block_given_p())
+ {
+ rb_raise(rb_eArgError, "must be called with a block");
+ }
+ enumerator = dumm->create_guest_enumerator(dumm);
+ while (enumerator->enumerate(enumerator, &guest))
+ {
+ rb_yield(Data_Wrap_Struct(class, NULL, NULL, guest));
+ }
+ enumerator->destroy(enumerator);
+ return class;
+}
+
+static VALUE guest_new(VALUE class, VALUE name, VALUE kernel,
+ VALUE master, VALUE args)
+{
+ guest_t *guest;
+
+ guest = dumm->create_guest(dumm, StringValuePtr(name), StringValuePtr(kernel),
+ StringValuePtr(master), StringValuePtr(args));
+ if (!guest)
+ {
+ rb_raise(rb_eRuntimeError, "creating guest failed");
+ }
+ return Data_Wrap_Struct(class, NULL, NULL, guest);
+}
+
+static VALUE guest_to_s(VALUE self)
+{
+ guest_t *guest;
+
+ Data_Get_Struct(self, guest_t, guest);
+ return rb_str_new2(guest->get_name(guest));
+}
+
+static VALUE guest_start(VALUE self)
+{
+ guest_t *guest;
+
+ Data_Get_Struct(self, guest_t, guest);
+
+ if (!guest->start(guest, invoke, NULL, NULL))
+ {
+ rb_raise(rb_eRuntimeError, "starting guest failed");
+ }
+ return self;
+}
+
+static VALUE guest_stop(VALUE self)
+{
+ guest_t *guest;
+
+ Data_Get_Struct(self, guest_t, guest);
+ guest->stop(guest, NULL);
+ return self;
+}
+
+static VALUE guest_running(VALUE self)
+{
+ guest_t *guest;
+
+ Data_Get_Struct(self, guest_t, guest);
+ return guest->get_pid(guest) ? Qtrue : Qfalse;
+}
+
+static void exec_cb(void *data, char *buf)
+{
+ rb_yield(rb_str_new2(buf));
+}
+
+static VALUE guest_exec(VALUE self, VALUE cmd)
+{
+ guest_t *guest;
+ bool block;
+ int ret;
+
+ block = rb_block_given_p();
+ Data_Get_Struct(self, guest_t, guest);
+ if ((ret = guest->exec_str(guest, block ? (void*)exec_cb : NULL, TRUE, NULL,
+ "%s", StringValuePtr(cmd))) != 0)
+ {
+ rb_raise(rb_eRuntimeError, "executing command failed (%d)", ret);
+ }
+ return self;
+}
+
+static VALUE guest_add_iface(VALUE self, VALUE name)
+{
+ guest_t *guest;
+ iface_t *iface;
+
+ Data_Get_Struct(self, guest_t, guest);
+ iface = guest->create_iface(guest, StringValuePtr(name));
+ if (!iface)
+ {
+ rb_raise(rb_eRuntimeError, "adding interface failed");
+ }
+ return Data_Wrap_Struct(rbc_iface, NULL, NULL, iface);
+}
+
+static VALUE guest_find_iface(VALUE self, VALUE key)
+{
+ enumerator_t *enumerator;
+ iface_t *iface, *found = NULL;
+ guest_t *guest;
+ if (TYPE(key) == T_SYMBOL) {
+ key = rb_convert_type(key, T_STRING, "String", "to_s");
+ }
+ Data_Get_Struct(self, guest_t, guest);
+ enumerator = guest->create_iface_enumerator(guest);
+ while (enumerator->enumerate(enumerator, &iface))
+ {
+ if (streq(iface->get_guestif(iface), StringValuePtr(key)))
+ {
+ found = iface;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ if (!found)
+ {
+ return Qnil;
+ }
+ return Data_Wrap_Struct(rbc_iface, NULL, NULL, iface);
+}
+
+static VALUE guest_get_iface(VALUE self, VALUE key)
+{
+ VALUE iface = guest_find_iface(self, key);
+ if (NIL_P(iface))
+ {
+ rb_raise(rb_eRuntimeError, "interface not found");
+ }
+ return iface;
+}
+
+static VALUE guest_each_iface(int argc, VALUE *argv, VALUE self)
+{
+ enumerator_t *enumerator;
+ guest_t *guest;
+ iface_t *iface;
+
+ if (!rb_block_given_p())
+ {
+ rb_raise(rb_eArgError, "must be called with a block");
+ }
+ Data_Get_Struct(self, guest_t, guest);
+ enumerator = guest->create_iface_enumerator(guest);
+ while (enumerator->enumerate(enumerator, &iface))
+ {
+ rb_yield(Data_Wrap_Struct(rbc_iface, NULL, NULL, iface));
+ }
+ enumerator->destroy(enumerator);
+ return self;
+}
+
+static VALUE guest_delete(VALUE self)
+{
+ guest_t *guest;
+
+ Data_Get_Struct(self, guest_t, guest);
+ dumm->delete_guest(dumm, guest);
+ return Qnil;
+}
+
+static void guest_init()
+{
+ rbc_guest = rb_define_class_under(rbm_dumm , "Guest", rb_cObject);
+ rb_include_module(rb_class_of(rbc_guest), rb_mEnumerable);
+ rb_include_module(rbc_guest, rb_mEnumerable);
+
+ rb_define_singleton_method(rbc_guest, "[]", guest_get, 1);
+ rb_define_singleton_method(rbc_guest, "each", guest_each, -1);
+ rb_define_singleton_method(rbc_guest, "new", guest_new, 4);
+ rb_define_singleton_method(rbc_guest, "include?", guest_find, 1);
+ rb_define_singleton_method(rbc_guest, "guest?", guest_find, 1);
+
+ rb_define_method(rbc_guest, "to_s", guest_to_s, 0);
+ rb_define_method(rbc_guest, "start", guest_start, 0);
+ rb_define_method(rbc_guest, "stop", guest_stop, 0);
+ rb_define_method(rbc_guest, "running?", guest_running, 0);
+ rb_define_method(rbc_guest, "exec", guest_exec, 1);
+ rb_define_method(rbc_guest, "add", guest_add_iface, 1);
+ rb_define_method(rbc_guest, "[]", guest_get_iface, 1);
+ rb_define_method(rbc_guest, "each", guest_each_iface, -1);
+ rb_define_method(rbc_guest, "include?", guest_find_iface, 1);
+ rb_define_method(rbc_guest, "iface?", guest_find_iface, 1);
+ rb_define_method(rbc_guest, "delete", guest_delete, 0);
+}
+
+/**
+ * Bridge binding
+ */
+static VALUE bridge_get(VALUE class, VALUE key)
+{
+ enumerator_t *enumerator;
+ bridge_t *bridge, *found = NULL;
+
+ enumerator = dumm->create_bridge_enumerator(dumm);
+ while (enumerator->enumerate(enumerator, &bridge))
+ {
+ if (streq(bridge->get_name(bridge), StringValuePtr(key)))
+ {
+ found = bridge;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ if (!found)
+ {
+ rb_raise(rb_eRuntimeError, "bridge not found");
+ }
+ return Data_Wrap_Struct(class, NULL, NULL, found);
+}
+
+static VALUE bridge_each(int argc, VALUE *argv, VALUE class)
+{
+ enumerator_t *enumerator;
+ bridge_t *bridge;
+
+ if (!rb_block_given_p())
+ {
+ rb_raise(rb_eArgError, "must be called with a block");
+ }
+ enumerator = dumm->create_bridge_enumerator(dumm);
+ while (enumerator->enumerate(enumerator, &bridge))
+ {
+ rb_yield(Data_Wrap_Struct(class, NULL, NULL, bridge));
+ }
+ enumerator->destroy(enumerator);
+ return class;
+}
+
+static VALUE bridge_new(VALUE class, VALUE name)
+
+{
+ bridge_t *bridge;
+
+ bridge = dumm->create_bridge(dumm, StringValuePtr(name));
+ if (!bridge)
+ {
+ rb_raise(rb_eRuntimeError, "creating bridge failed");
+ }
+ return Data_Wrap_Struct(class, NULL, NULL, bridge);
+}
+
+static VALUE bridge_to_s(VALUE self)
+{
+ bridge_t *bridge;
+
+ Data_Get_Struct(self, bridge_t, bridge);
+ return rb_str_new2(bridge->get_name(bridge));
+}
+
+static VALUE bridge_each_iface(int argc, VALUE *argv, VALUE self)
+{
+ enumerator_t *enumerator;
+ bridge_t *bridge;
+ iface_t *iface;
+
+ if (!rb_block_given_p())
+ {
+ rb_raise(rb_eArgError, "must be called with a block");
+ }
+ Data_Get_Struct(self, bridge_t, bridge);
+ enumerator = bridge->create_iface_enumerator(bridge);
+ while (enumerator->enumerate(enumerator, &iface))
+ {
+ rb_yield(Data_Wrap_Struct(rbc_iface, NULL, NULL, iface));
+ }
+ enumerator->destroy(enumerator);
+ return self;
+}
+
+static VALUE bridge_delete(VALUE self)
+{
+ bridge_t *bridge;
+
+ Data_Get_Struct(self, bridge_t, bridge);
+ dumm->delete_bridge(dumm, bridge);
+ return Qnil;
+}
+
+static void bridge_init()
+{
+ rbc_bridge = rb_define_class_under(rbm_dumm , "Bridge", rb_cObject);
+ rb_include_module(rb_class_of(rbc_bridge), rb_mEnumerable);
+ rb_include_module(rbc_bridge, rb_mEnumerable);
+
+ rb_define_singleton_method(rbc_bridge, "[]", bridge_get, 1);
+ rb_define_singleton_method(rbc_bridge, "each", bridge_each, -1);
+ rb_define_singleton_method(rbc_bridge, "new", bridge_new, 1);
+
+ rb_define_method(rbc_bridge, "to_s", bridge_to_s, 0);
+ rb_define_method(rbc_bridge, "each", bridge_each_iface, -1);
+ rb_define_method(rbc_bridge, "delete", bridge_delete, 0);
+}
+
+/**
+ * Iface wrapper
+ */
+static VALUE iface_to_s(VALUE self)
+{
+ iface_t *iface;
+
+ Data_Get_Struct(self, iface_t, iface);
+ return rb_str_new2(iface->get_hostif(iface));
+}
+
+static VALUE iface_connect(VALUE self, VALUE vbridge)
+{
+ iface_t *iface;
+ bridge_t *bridge;
+
+ Data_Get_Struct(self, iface_t, iface);
+ Data_Get_Struct(vbridge, bridge_t, bridge);
+ if (!bridge->connect_iface(bridge, iface))
+ {
+ rb_raise(rb_eRuntimeError, "connecting iface failed");
+ }
+ return self;
+}
+
+static VALUE iface_disconnect(VALUE self)
+{
+ iface_t *iface;
+ bridge_t *bridge;
+
+ Data_Get_Struct(self, iface_t, iface);
+ bridge = iface->get_bridge(iface);
+ if (!bridge || !bridge->disconnect_iface(bridge, iface))
+ {
+ rb_raise(rb_eRuntimeError, "disconnecting iface failed");
+ }
+ return self;
+}
+
+static VALUE iface_add_addr(VALUE self, VALUE name)
+{
+ iface_t *iface;
+ host_t *addr;
+
+ addr = host_create_from_string(StringValuePtr(name), 0);
+ if (!addr)
+ {
+ rb_raise(rb_eArgError, "invalid IP address");
+ }
+ Data_Get_Struct(self, iface_t, iface);
+ if (!iface->add_address(iface, addr))
+ {
+ addr->destroy(addr);
+ rb_raise(rb_eRuntimeError, "adding address failed");
+ }
+ if (rb_block_given_p()) {
+ rb_yield(self);
+ iface->delete_address(iface, addr);
+ }
+ addr->destroy(addr);
+ return self;
+}
+
+static VALUE iface_each_addr(int argc, VALUE *argv, VALUE self)
+{
+ enumerator_t *enumerator;
+ iface_t *iface;
+ host_t *addr;
+ char buf[64];
+
+ if (!rb_block_given_p())
+ {
+ rb_raise(rb_eArgError, "must be called with a block");
+ }
+ Data_Get_Struct(self, iface_t, iface);
+ enumerator = iface->create_address_enumerator(iface);
+ while (enumerator->enumerate(enumerator, &addr))
+ {
+ snprintf(buf, sizeof(buf), "%H", addr);
+ rb_yield(rb_str_new2(buf));
+ }
+ enumerator->destroy(enumerator);
+ return self;
+}
+
+static VALUE iface_del_addr(VALUE self, VALUE vaddr)
+{
+ iface_t *iface;
+ host_t *addr;
+
+ addr = host_create_from_string(StringValuePtr(vaddr), 0);
+ if (!addr)
+ {
+ rb_raise(rb_eArgError, "invalid IP address");
+ }
+ Data_Get_Struct(self, iface_t, iface);
+ if (!iface->delete_address(iface, addr))
+ {
+ addr->destroy(addr);
+ rb_raise(rb_eRuntimeError, "address not found");
+ }
+ if (rb_block_given_p()) {
+ rb_yield(self);
+ iface->add_address(iface, addr);
+ }
+ addr->destroy(addr);
+ return self;
+}
+
+static VALUE iface_delete(VALUE self)
+{
+ guest_t *guest;
+ iface_t *iface;
+
+ Data_Get_Struct(self, iface_t, iface);
+ guest = iface->get_guest(iface);
+ guest->destroy_iface(guest, iface);
+ return Qnil;
+}
+
+static void iface_init()
+{
+ rbc_iface = rb_define_class_under(rbm_dumm , "Iface", rb_cObject);
+ rb_include_module(rbc_iface, rb_mEnumerable);
+
+ rb_define_method(rbc_iface, "to_s", iface_to_s, 0);
+ rb_define_method(rbc_iface, "connect", iface_connect, 1);
+ rb_define_method(rbc_iface, "disconnect", iface_disconnect, 0);
+ rb_define_method(rbc_iface, "add", iface_add_addr, 1);
+ rb_define_method(rbc_iface, "del", iface_del_addr, 1);
+ rb_define_method(rbc_iface, "each", iface_each_addr, -1);
+ rb_define_method(rbc_iface, "delete", iface_delete, 0);
+}
+
+static VALUE template_load(VALUE class, VALUE dir)
+{
+ if (!dumm->load_template(dumm, StringValuePtr(dir)))
+ {
+ rb_raise(rb_eRuntimeError, "loading template failed");
+ }
+ return class;
+}
+
+static VALUE template_unload(VALUE class)
+{
+ if (!dumm->load_template(dumm, NULL))
+ {
+ rb_raise(rb_eRuntimeError, "unloading template failed");
+ }
+ return class;
+}
+
+static void template_init()
+{
+ rbc_template = rb_define_class_under(rbm_dumm , "Template", rb_cObject);
+
+ rb_define_singleton_method(rbc_template, "load", template_load, 1);
+ rb_define_singleton_method(rbc_template, "unload", template_unload, 0);
+}
+
+/**
+ * extension finalization
+ */
+void Final_dumm()
+{
+ struct sigaction action;
+
+ dumm->destroy(dumm);
+
+ sigemptyset(&action.sa_mask);
+ action.sa_handler = SIG_DFL;
+ action.sa_flags = 0;
+ sigaction(SIGCHLD, &action, NULL);
+
+ library_deinit();
+}
+
+/**
+ * extension initialization
+ */
+void Init_dumm()
+{
+ struct sigaction action;
+
+ /* there are too many to report, rubyruby... */
+ setenv("LEAK_DETECTIVE_DISABLE", "1", 1);
+
+ library_init(NULL);
+
+ dumm = dumm_create(NULL);
+
+ rbm_dumm = rb_define_module("Dumm");
+
+ guest_init();
+ bridge_init();
+ iface_init();
+ template_init();
+
+ sigemptyset(&action.sa_mask);
+ action.sa_sigaction = sigchld_handler;
+ action.sa_flags = SA_SIGINFO;
+ sigaction(SIGCHLD, &action, NULL);
+
+ rb_set_end_proc(Final_dumm, 0);
+}
diff --git a/src/dumm/ext/extconf.rb b/src/dumm/ext/extconf.rb
new file mode 100644
index 000000000..136be5c2c
--- /dev/null
+++ b/src/dumm/ext/extconf.rb
@@ -0,0 +1,21 @@
+#
+# DUMM for Ruby
+#
+
+require "mkmf"
+
+dir_config("dumm")
+
+unless find_header('library.h', '../../libstrongswan') and
+ find_header('dumm.h', '..')
+ puts "... failed: one or more header files not found!"
+ exit
+end
+
+unless find_library('dumm', 'dumm_create')
+ puts "... failed: 'libdumm' not found!"
+ exit
+end
+
+create_makefile("dumm")
+
diff --git a/src/dumm/ext/lib/dumm.rb b/src/dumm/ext/lib/dumm.rb
new file mode 100644
index 000000000..2e860ae9f
--- /dev/null
+++ b/src/dumm/ext/lib/dumm.rb
@@ -0,0 +1,21 @@
+=begin
+ Copyright (C) 2008 Tobias Brunner
+ 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.
+
+ $Id: dumm.rb 4295 2008-08-27 07:35:20Z tobias $
+=end
+
+require 'dumm.so'
+require 'dumm/guest'
+
+# vim:sw=2 ts=2 et
diff --git a/src/dumm/ext/lib/dumm/guest.rb b/src/dumm/ext/lib/dumm/guest.rb
new file mode 100644
index 000000000..bdd0c33d8
--- /dev/null
+++ b/src/dumm/ext/lib/dumm/guest.rb
@@ -0,0 +1,40 @@
+=begin
+ Copyright (C) 2008 Tobias Brunner
+ 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.
+
+ $Id: guest.rb 4295 2008-08-27 07:35:20Z tobias $
+=end
+
+module Dumm
+ class Guest
+ # accessor for guests
+ # e.g. Guest.sun instead of Guest["sun"]
+ def self.method_missing(id, *args)
+ unless guest? id
+ super(id, *args)
+ end
+ Guest[id]
+ end
+
+ # accessor for interfaces
+ # e.g. guest.eth0 instead of guest["eth0"]
+ def method_missing(id, *args)
+ unless iface? id
+ super(id, *args)
+ end
+ self[id]
+ end
+ end
+end
+
+# vim:sw=2 ts=2 et
diff --git a/src/dumm/guest.c b/src/dumm/guest.c
index 4b2652688..aed2a3e18 100644
--- a/src/dumm/guest.c
+++ b/src/dumm/guest.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2008 Tobias Brunner
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -25,6 +26,7 @@
#include <signal.h>
#include <dirent.h>
#include <termios.h>
+#include <stdarg.h>
#include <debug.h>
#include <utils/linked_list.h>
@@ -40,7 +42,7 @@
#define MASTER_DIR "master"
#define DIFF_DIR "diff"
#define UNION_DIR "union"
-#define MEMORY_FILE "mem"
+#define ARGS_FILE "args"
#define PID_FILE "pid"
#define KERNEL_FILE "linux"
#define LOG_FILE "boot.log"
@@ -58,8 +60,8 @@ struct private_guest_t {
int dir;
/** directory name of guest */
char *dirname;
- /** amount of memory for guest, in MB */
- int mem;
+ /** additional args to pass to guest */
+ char *args;
/** pid of guest child process */
int pid;
/** state of guest */
@@ -114,7 +116,7 @@ static iface_t* create_iface(private_guest_t *this, char *name)
}
enumerator->destroy(enumerator);
- iface = iface_create(this->name, name, this->mconsole);
+ iface = iface_create(name, &this->public, this->mconsole);
if (iface)
{
this->ifaces->insert_last(this->ifaces, iface);
@@ -212,6 +214,7 @@ static void stop(private_guest_t *this, idle_function_t idle)
}
}
unlinkat(this->dir, PID_FILE, 0);
+ this->pid = 0;
}
}
@@ -255,15 +258,19 @@ static bool start(private_guest_t *this, invoke_function_t invoke, void* data,
notify = write_arg(&pos, &left, "%s/%s", this->dirname, NOTIFY_FILE);
+ args[i++] = write_arg(&pos, &left, "nice");
args[i++] = write_arg(&pos, &left, "%s/%s", this->dirname, KERNEL_FILE);
args[i++] = write_arg(&pos, &left, "root=/dev/root");
args[i++] = write_arg(&pos, &left, "rootfstype=hostfs");
args[i++] = write_arg(&pos, &left, "rootflags=%s/%s", this->dirname, UNION_DIR);
args[i++] = write_arg(&pos, &left, "uml_dir=%s", this->dirname);
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=null");
+ if (this->args)
+ {
+ args[i++] = this->args;
+ }
this->pid = invoke(data, &this->public, args, i);
if (!this->pid)
@@ -307,7 +314,7 @@ static bool load_template(private_guest_t *this, char *path)
}
if (access(dir, F_OK) != 0)
{
- if (mkdir(dir, PERME) != 0)
+ if (!mkdir_p(dir, PERME))
{
DBG1("creating overlay for guest '%s' failed: %m", this->name);
return FALSE;
@@ -325,6 +332,119 @@ static bool load_template(private_guest_t *this, char *path)
}
/**
+ * Variadic version of the exec function
+ */
+static int vexec(private_guest_t *this, void(*cb)(void*,char*,size_t), void *data,
+ char *cmd, va_list args)
+{
+ char buf[1024];
+ size_t len;
+
+ if (this->mconsole)
+ {
+ len = vsnprintf(buf, sizeof(buf), cmd, args);
+
+ if (len > 0 && len < sizeof(buf))
+ {
+ return this->mconsole->exec(this->mconsole, cb, data, buf);
+ }
+ }
+ return -1;
+}
+
+/**
+ * Implementation of guest_t.exec
+ */
+static int exec(private_guest_t *this, void(*cb)(void*,char*,size_t), void *data,
+ char *cmd, ...)
+{
+ int res;
+ va_list args;
+ va_start(args, cmd);
+ res = vexec(this, cb, data, cmd, args);
+ va_end(args);
+ return res;
+}
+
+typedef struct {
+ chunk_t buf;
+ void (*cb)(void*,char*);
+ void *data;
+} exec_str_t;
+
+/**
+ * callback that combines chunks to a string. if a callback is given, the string
+ * is split at newlines and the callback is called for each line.
+ */
+static void exec_str_cb(exec_str_t *data, char *buf, size_t len)
+{
+ if (!data->buf.ptr)
+ {
+ data->buf = chunk_alloc(len + 1);
+ memcpy(data->buf.ptr, buf, len);
+ data->buf.ptr[len] = '\0';
+ }
+ else
+ {
+ size_t newlen = strlen(data->buf.ptr) + len + 1;
+ if (newlen > data->buf.len)
+ {
+ data->buf.ptr = realloc(data->buf.ptr, newlen);
+ data->buf.len = newlen;
+ }
+ strncat(data->buf.ptr, buf, len);
+ }
+
+ if (data->cb)
+ {
+ char *nl;
+ while ((nl = strchr(data->buf.ptr, '\n')) != NULL)
+ {
+ *nl++ = '\0';
+ data->cb(data->data, data->buf.ptr);
+ memmove(data->buf.ptr, nl, strlen(nl) + 1);
+ }
+ }
+}
+
+/**
+ * Implementation of guest_t.exec_str
+ */
+static int exec_str(private_guest_t *this, void(*cb)(void*,char*), bool lines,
+ void *data, char *cmd, ...)
+{
+ int res;
+ va_list args;
+ va_start(args, cmd);
+ if (cb)
+ {
+ exec_str_t exec = { chunk_empty, NULL, NULL };
+ if (lines)
+ {
+ exec.cb = cb;
+ exec.data = data;
+ }
+ res = vexec(this, (void(*)(void*,char*,size_t))exec_str_cb, &exec, cmd, args);
+ if (exec.buf.ptr)
+ {
+ if (!lines || strlen(exec.buf.ptr) > 0)
+ {
+ /* return the complete string or the remaining stuff in the
+ * buffer (i.e. when there was no newline at the end) */
+ cb(data, exec.buf.ptr);
+ }
+ chunk_free(&exec.buf);
+ }
+ }
+ else
+ {
+ res = vexec(this, NULL, NULL, cmd, args);
+ }
+ va_end(args);
+ return res;
+}
+
+/**
* Implementation of guest_t.sigchild.
*/
static void sigchild(private_guest_t *this)
@@ -373,38 +493,38 @@ static bool mount_unionfs(private_guest_t *this)
}
/**
- * load memory configuration from file
+ * load args configuration from file
*/
-int loadmem(private_guest_t *this)
+char *loadargs(private_guest_t *this)
{
FILE *file;
- int mem = 0;
+ char buf[512], *args = NULL;
- file = fdopen(openat(this->dir, MEMORY_FILE, O_RDONLY, PERM), "r");
+ file = fdopen(openat(this->dir, ARGS_FILE, O_RDONLY, PERM), "r");
if (file)
{
- if (fscanf(file, "%d", &mem) <= 0)
+ if (fgets(buf, sizeof(buf), file))
{
- mem = 0;
+ args = strdup(buf);
}
fclose(file);
}
- return mem;
+ return args;
}
/**
- * save memory configuration to file
+ * save args configuration to file
*/
-bool savemem(private_guest_t *this, int mem)
+bool saveargs(private_guest_t *this, char *args)
{
FILE *file;
bool retval = FALSE;
- file = fdopen(openat(this->dir, MEMORY_FILE, O_RDWR | O_CREAT | O_TRUNC,
+ file = fdopen(openat(this->dir, ARGS_FILE, O_RDWR | O_CREAT | O_TRUNC,
PERM), "w");
if (file)
{
- if (fprintf(file, "%d", mem) > 0)
+ if (fprintf(file, "%s", args) > 0)
{
retval = TRUE;
}
@@ -424,7 +544,9 @@ static void destroy(private_guest_t *this)
{
close(this->dir);
}
+ this->ifaces->destroy(this->ifaces);
free(this->dirname);
+ free(this->args);
free(this->name);
free(this);
}
@@ -447,6 +569,8 @@ static private_guest_t *guest_create_generic(char *parent, char *name,
this->public.start = (void*)start;
this->public.stop = (void*)stop;
this->public.load_template = (bool(*)(guest_t*, char *path))load_template;
+ this->public.exec = (int(*)(guest_t*, void(*cb)(void*,char*,size_t),void*,char*,...))exec;
+ this->public.exec_str = (int(*)(guest_t*, void(*cb)(void*,char*),bool,void*,char*,...))exec_str;
this->public.sigchild = (void(*)(guest_t*))sigchild;
this->public.destroy = (void*)destroy;
@@ -474,7 +598,7 @@ static private_guest_t *guest_create_generic(char *parent, char *name,
this->state = GUEST_STOPPED;
this->mconsole = NULL;
this->ifaces = linked_list_create();
- this->mem = 0;
+ this->args = NULL;
this->name = strdup(name);
this->cowfs = NULL;
@@ -505,7 +629,7 @@ static bool make_symlink(private_guest_t *this, char *old, char *new)
* create the guest instance, including required dirs and mounts
*/
guest_t *guest_create(char *parent, char *name, char *kernel,
- char *master, int mem)
+ char *master, char *args)
{
private_guest_t *this = guest_create_generic(parent, name, TRUE);
@@ -530,8 +654,8 @@ guest_t *guest_create(char *parent, char *name, char *kernel,
return NULL;
}
- this->mem = mem;
- if (!savemem(this, mem))
+ this->args = args;
+ if (args && !saveargs(this, args))
{
destroy(this);
return NULL;
@@ -558,13 +682,7 @@ guest_t *guest_load(char *parent, char *name)
return NULL;
}
- this->mem = loadmem(this);
- if (this->mem == 0)
- {
- DBG1("unable to open memory configuration file: %m", name);
- destroy(this);
- return NULL;
- }
+ this->args = loadargs(this);
if (!mount_unionfs(this))
{
diff --git a/src/dumm/guest.h b/src/dumm/guest.h
index 79a47fa62..0e48b1d06 100644
--- a/src/dumm/guest.h
+++ b/src/dumm/guest.h
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2008 Tobias Brunner
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -19,11 +20,11 @@
#include <library.h>
#include <utils/enumerator.h>
-#include "iface.h"
-
typedef enum guest_state_t guest_state_t;
typedef struct guest_t guest_t;
+#include "iface.h"
+
/**
* @brief State of a guest (started, stopped, ...)
*/
@@ -107,9 +108,8 @@ struct guest_t {
* @brief Kill the guest.
*
* @param idle idle function to call while waiting to termination
- * @return TRUE if guest was running and killed
*/
- bool (*stop) (guest_t *this, idle_function_t idle);
+ void (*stop) (guest_t *this, idle_function_t idle);
/**
* @brief Create a new interface in the current scenario.
@@ -140,7 +140,35 @@ struct guest_t {
* @return FALSE if failed
*/
bool (*load_template)(guest_t *this, char *parent);
-
+
+ /**
+ * Execute a command in the guest.
+ *
+ * @param cb callback to call for each read block
+ * @param data data to pass to callback
+ * @param cmd command to execute
+ * @param ... printf style argument list for cmd
+ * @return return value
+ */
+ int (*exec)(guest_t *this, void(*cb)(void*,char*,size_t), void *data,
+ char *cmd, ...);
+
+ /**
+ * Execute a command in the guest and return the output by lines or as combined
+ * string.
+ *
+ * @note This function does not work with binary output (i.e. containing 0 bytes).
+ *
+ * @param cb callback to call for each line or for the complete output
+ * @param lines TRUE if the callback should be called for each line (instead of for the combined output)
+ * @param data data to pass to callback
+ * @param cmd command to execute
+ * @param ... printf style argument list for cmd
+ * @return return value
+ */
+ int (*exec_str)(guest_t *this, void(*cb)(void*,char*), bool lines,
+ void *data, char *cmd, ...);
+
/**
* @brief Called whenever a SIGCHILD for the guests PID is received.
*/
@@ -159,10 +187,11 @@ struct guest_t {
* @param name name of the guest to create
* @param kernel kernel this guest uses
* @param master read-only master filesystem for guest
+ * @param args additional args to pass to kernel
* @param mem amount of memory to give the guest
*/
guest_t *guest_create(char *parent, char *name, char *kernel,
- char *master, int mem);
+ char *master, char *args);
/**
* @brief Load a guest created with guest_create().
diff --git a/src/dumm/iface.c b/src/dumm/iface.c
index b78c10bec..78c6c7c92 100644
--- a/src/dumm/iface.c
+++ b/src/dumm/iface.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2008 Tobias Brunner
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
* Copyright (C) 2002 Jeff Dike
@@ -25,6 +26,7 @@
#include <linux/if_tun.h>
#include <debug.h>
+#include <utils/linked_list.h>
#include "iface.h"
@@ -39,12 +41,14 @@ struct private_iface_t {
char *hostif;
/** bridge this interface is attached to */
bridge_t *bridge;
+ /** guest this interface is attached to */
+ guest_t *guest;
/** mconsole for guest */
mconsole_t *mconsole;
};
/**
- * bring an interface up or down
+ * bring an interface up or down (host side)
*/
bool iface_control(char *name, bool up)
{
@@ -96,14 +100,93 @@ static char* get_hostif(private_iface_t *this)
}
/**
+ * Implementation of iface_t.add_address
+ */
+static bool add_address(private_iface_t *this, host_t *addr)
+{
+ return (this->guest->exec(this->guest, NULL, NULL, "ip addr add %H dev %s",
+ addr, this->guestif) == 0);
+}
+
+/**
+ * compile a list of the addresses of an interface
+ */
+static void compile_address_list(linked_list_t *list, char *address)
+{
+ host_t *host = host_create_from_string(address, 0);
+ if (host)
+ {
+ list->insert_last(list, host);
+ }
+}
+
+/**
+ * delete the list of addresses
+ */
+static void destroy_address_list(linked_list_t *list)
+{
+ list->destroy_offset(list, offsetof(host_t, destroy));
+}
+
+/**
+ * Implementation of iface_t.create_address_enumerator
+ */
+static enumerator_t* create_address_enumerator(private_iface_t *this)
+{
+ linked_list_t *addresses = linked_list_create();
+ this->guest->exec_str(this->guest, (void(*)(void*,char*))compile_address_list,
+ TRUE, addresses,
+ "ip addr list dev %s scope global | "
+ "grep '^ \\+\\(inet6\\? \\)' | "
+ "awk -F '( +|/)' '{ print $3 }'", this->guestif);
+ return enumerator_create_cleaner(addresses->create_enumerator(addresses),
+ (void(*)(void*))destroy_address_list, addresses);
+}
+
+/**
+ * Implementation of iface_t.delete_address
+ */
+static bool delete_address(private_iface_t *this, host_t *addr)
+{
+ return (this->guest->exec(this->guest, NULL, NULL,
+ "ip addr del %H dev %s", addr, this->guestif) == 0);
+}
+
+/**
* Implementation of iface_t.set_bridge.
*/
static void set_bridge(private_iface_t *this, bridge_t *bridge)
{
+ if (this->bridge == NULL && bridge)
+ {
+ this->guest->exec(this->guest, NULL, NULL,
+ "ip link set %s up", this->guestif);
+ }
+ else if (this->bridge && bridge == NULL)
+ {
+ this->guest->exec(this->guest, NULL, NULL,
+ "ip link set %s down", this->guestif);
+ }
this->bridge = bridge;
}
/**
+ * Implementation of iface_t.get_bridge
+ */
+static bridge_t *get_bridge(private_iface_t *this)
+{
+ return this->bridge;
+}
+
+/**
+ * Implementation of iface_t.get_guest
+ */
+static guest_t* get_guest(private_iface_t *this)
+{
+ return this->guest;
+}
+
+/**
* destroy the tap device
*/
static bool destroy_tap(private_iface_t *this)
@@ -139,14 +222,15 @@ static bool destroy_tap(private_iface_t *this)
/**
* create the tap device
*/
-static char* create_tap(private_iface_t *this, char *guest)
+static char* create_tap(private_iface_t *this)
{
struct ifreq ifr;
int tap;
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
- snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s-%s", guest, this->guestif);
+ snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s-%s",
+ this->guest->get_name(this->guest), this->guestif);
tap = open(TAP_DEVICE, O_RDWR);
if (tap < 0)
@@ -175,6 +259,8 @@ static void destroy(private_iface_t *this)
{
this->bridge->disconnect_iface(this->bridge, &this->public);
}
+ /* TODO: iface mgmt is not blocking yet, so wait some ticks */
+ usleep(50000);
this->mconsole->del_iface(this->mconsole, this->guestif);
destroy_tap(this);
free(this->guestif);
@@ -185,18 +271,24 @@ static void destroy(private_iface_t *this)
/**
* create the iface instance
*/
-iface_t *iface_create(char *guest, char *guestif, mconsole_t *mconsole)
+iface_t *iface_create(char *name, guest_t *guest, mconsole_t *mconsole)
{
private_iface_t *this = malloc_thing(private_iface_t);
this->public.get_hostif = (char*(*)(iface_t*))get_hostif;
this->public.get_guestif = (char*(*)(iface_t*))get_guestif;
+ this->public.add_address = (bool(*)(iface_t*, host_t *addr))add_address;
+ this->public.create_address_enumerator = (enumerator_t*(*)(iface_t*))create_address_enumerator;
+ this->public.delete_address = (bool(*)(iface_t*, host_t *addr))delete_address;
this->public.set_bridge = (void(*)(iface_t*, bridge_t*))set_bridge;
+ this->public.get_bridge = (bridge_t*(*)(iface_t*))get_bridge;
+ this->public.get_guest = (guest_t*(*)(iface_t*))get_guest;
this->public.destroy = (void*)destroy;
this->mconsole = mconsole;
- this->guestif = strdup(guestif);
- this->hostif = create_tap(this, guest);
+ this->guestif = strdup(name);
+ this->guest = guest;
+ this->hostif = create_tap(this);
this->bridge = NULL;
if (this->hostif == NULL)
{
@@ -205,10 +297,6 @@ 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);
@@ -218,6 +306,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);
+ }
return &this->public;
}
diff --git a/src/dumm/iface.h b/src/dumm/iface.h
index e04fe4ed1..54a0554c0 100644
--- a/src/dumm/iface.h
+++ b/src/dumm/iface.h
@@ -18,6 +18,7 @@
#include <library.h>
#include <utils/enumerator.h>
+#include <utils/host.h>
#define TAP_DEVICE "/dev/net/tun"
@@ -25,6 +26,7 @@ typedef struct iface_t iface_t;
#include "mconsole.h"
#include "bridge.h"
+#include "guest.h"
/**
* @brief Interface in a guest, connected to a tap device on the host.
@@ -46,16 +48,48 @@ struct iface_t {
char* (*get_hostif)(iface_t *this);
/**
+ * Add an address to the interface.
+ *
+ * @param addr address to add to interface
+ * @return TRUE if address added
+ */
+ bool (*add_address)(iface_t *this, host_t *addr);
+
+ /**
+ * Create an enumerator over all installed addresses.
+ *
+ * @return enumerator over host_t*
+ */
+ enumerator_t* (*create_address_enumerator)(iface_t *this);
+
+ /**
+ * Remove an address from an interface.
+ *
+ * @param addr address to remove
+ * @return TRUE if address removed
+ */
+ bool (*delete_address)(iface_t *this, host_t *addr);
+
+ /**
* @brief Set the bridge this interface is attached to.
*
* @param bridge assigned bridge, or NULL for none
*/
void (*set_bridge)(iface_t *this, bridge_t *bridge);
- /*
- bool (*add_addr) (iface_t *this, host_t *addr);
- enumerator_t* (*create_addr_enumerator) (iface_t *this);
- */
+ /**
+ * @brief Get the bridge this iface is connected, or NULL.
+ *
+ * @return connected bridge, or NULL
+ */
+ bridge_t* (*get_bridge)(iface_t *this);
+
+ /**
+ * @brief Get the guest this iface belongs to.
+ *
+ * @return guest of this iface
+ */
+ guest_t* (*get_guest)(iface_t *this);
/**
* @brief Destroy an interface
@@ -66,12 +100,12 @@ struct iface_t {
/**
* @brief Create a new interface for a guest
*
- * @param guest name of the guest for this interface
- * @param guestif name of the interface in the guest
+ * @param name name of the interface in the guest
+ * @param guest guest this iface is connecting
* @param mconsole mconsole of guest
* @return interface descriptor, or NULL if failed
*/
-iface_t *iface_create(char *guest, char *guestif, mconsole_t *mconsole);
+iface_t *iface_create(char *name, guest_t *guest, mconsole_t *mconsole);
#endif /* IFACE_H */
diff --git a/src/dumm/irdumm.c b/src/dumm/irdumm.c
new file mode 100644
index 000000000..bca8ce1db
--- /dev/null
+++ b/src/dumm/irdumm.c
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+#undef PACKAGE_NAME
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+#undef PACKAGE_STRING
+#include <ruby.h>
+
+/**
+ * main routine, parses args and reads from console
+ */
+int main(int argc, char *argv[])
+{
+ int state, i;
+ char buf[512];
+
+ ruby_init();
+ ruby_init_loadpath();
+
+ rb_eval_string_protect("require 'dumm' and include Dumm", &state);
+ if (state)
+ {
+ rb_p(ruby_errinfo);
+ printf("Please install the ruby extension first!\n");
+ }
+ for (i = 1; i < argc; i++)
+ {
+ snprintf(buf, sizeof(buf), "load \"%s\"", argv[i]);
+ printf("%s\n", buf);
+ rb_eval_string_protect(buf, &state);
+ if (state)
+ {
+ rb_p(ruby_errinfo);
+ }
+ }
+ rb_require("irb");
+ rb_require("irb/completion");
+ rb_eval_string_protect("IRB.start", &state);
+ if (state)
+ {
+ rb_p(ruby_errinfo);
+ }
+
+ ruby_finalize();
+ return 0;
+}
+
diff --git a/src/dumm/main.c b/src/dumm/main.c
index d4f2c5176..e2f2fc255 100644
--- a/src/dumm/main.c
+++ b/src/dumm/main.c
@@ -100,7 +100,6 @@ static page_t* get_page(int num)
static pid_t invoke(void *vte, guest_t *guest,
char *args[], int argc)
{
- args[argc] = "con0=fd:0,fd:1";
return vte_terminal_fork_command(VTE_TERMINAL(vte), args[0], args, NULL,
NULL, FALSE, FALSE, FALSE);
}
@@ -374,7 +373,7 @@ static page_t* create_page(guest_t *guest)
static void create_guest()
{
guest_t *guest;
- GtkWidget *dialog, *table, *label, *name, *kernel, *master, *memory;
+ GtkWidget *dialog, *table, *label, *name, *kernel, *master, *args;
dialog = gtk_dialog_new_with_buttons("Create new guest", GTK_WINDOW(window),
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
@@ -396,7 +395,7 @@ static void create_guest()
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)");
+ label = gtk_label_new("Kernel arguments");
gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, 0, 0, 0, 0);
gtk_widget_show(label);
@@ -417,11 +416,10 @@ static void create_guest()
GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0);
gtk_widget_show(master);
- memory = gtk_spin_button_new_with_range(1, 4096, 1);
- gtk_spin_button_set_digits(GTK_SPIN_BUTTON(memory), 0);
- gtk_table_attach(GTK_TABLE(table), memory, 1, 2, 3, 4,
+ args = gtk_entry_new();
+ gtk_table_attach(GTK_TABLE(table), args, 1, 2, 3, 4,
GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0);
- gtk_widget_show(memory);
+ gtk_widget_show(args);
gtk_widget_show(table);
@@ -431,19 +429,19 @@ static void create_guest()
{
case GTK_RESPONSE_ACCEPT:
{
- char *sname, *skernel, *smaster;
+ char *sname, *skernel, *smaster, *sargs;
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));
+ sargs = (char*)gtk_entry_get_text(GTK_ENTRY(args));
if (!sname[0] || !skernel || !smaster)
{
continue;
}
- guest = dumm->create_guest(dumm, sname, skernel, smaster,
- gtk_spin_button_get_value(GTK_SPIN_BUTTON(memory)));
+ guest = dumm->create_guest(dumm, sname, skernel, smaster, sargs);
if (!guest)
{
error_dialog("creating guest failed!");
diff --git a/src/dumm/mconsole.c b/src/dumm/mconsole.c
index d9864f676..c6e0c2f08 100644
--- a/src/dumm/mconsole.c
+++ b/src/dumm/mconsole.c
@@ -88,21 +88,21 @@ struct mconsole_notify {
/**
* send a request to UML using mconsole
*/
-static int request(private_mconsole_t *this, char *command,
- char buf[], size_t *size)
+static int request(private_mconsole_t *this, void(*cb)(void*,char*,size_t),
+ void *data, char *command, ...)
{
mconsole_request request;
mconsole_reply reply;
- int len, total = 0, flags = 0;
+ int len, flags = 0;
+ va_list args;
memset(&request, 0, sizeof(request));
request.magic = MCONSOLE_MAGIC;
request.version = MCONSOLE_VERSION;
- request.len = min(strlen(command), sizeof(reply.data) - 1);
- strncpy(request.data, command, request.len);
- *buf = '\0';
- (*size)--;
-
+ va_start(args, command);
+ request.len = vsnprintf(request.data, sizeof(request.data), command, args);
+ va_end(args);
+
if (this->idle)
{
flags = MSG_DONTWAIT;
@@ -120,7 +120,7 @@ static int request(private_mconsole_t *this, char *command,
if (len < 0)
{
- snprintf(buf, *size, "sending mconsole command to UML failed: %m");
+ DBG1("sending mconsole command to UML failed: %m");
return -1;
}
do
@@ -136,96 +136,87 @@ static int request(private_mconsole_t *this, char *command,
}
if (len < 0)
{
- snprintf(buf, *size, "receiving from mconsole failed: %m");
+ DBG1("receiving from mconsole failed: %m");
return -1;
}
if (len > 0)
{
- strncat(buf, reply.data, min(reply.len, *size - total));
- total += reply.len;
+ if (cb)
+ {
+ cb(data, reply.data, reply.len);
+ }
+ else if (reply.err)
+ {
+ DBG1("received mconsole error %d: %*.s",
+ reply.err, reply.len, reply.data);
+ break;
+ }
}
}
while (reply.more);
- *size = total;
return reply.err;
}
/**
+ * ignore error message
+ */
+static void ignore(void *data, char *buf, size_t len)
+{
+}
+
+/**
* Implementation of mconsole_t.add_iface.
*/
static bool add_iface(private_mconsole_t *this, char *guest, char *host)
{
- char buf[128];
- int len;
+ int tries = 0;
- len = snprintf(buf, sizeof(buf), "config %s=tuntap,%s", guest, host);
- if (len < 0 || len >= sizeof(buf))
- {
- return FALSE;
- }
- len = sizeof(buf);
- if (request(this, buf, buf, &len) != 0)
+ while (tries++ < 5)
{
- DBG1("adding interface failed: %.*s", len, buf);
- return FALSE;
+ if (request(this, ignore, NULL, "config %s=tuntap,%s", guest, host) == 0)
+ {
+ return TRUE;
+ }
+ usleep(10000 * tries * tries);
}
- return TRUE;
+ return FALSE;
}
/**
* Implementation of mconsole_t.del_iface.
*/
static bool del_iface(private_mconsole_t *this, char *guest)
-{
- char buf[128];
- int len;
-
- len = snprintf(buf, sizeof(buf), "remove %s", guest);
- if (len < 0 || len >= sizeof(buf))
- {
- return FALSE;
- }
- if (request(this, buf, buf, &len) != 0)
+{
+ if (request(this, NULL, NULL, "remove %s", guest) != 0)
{
- DBG1("removing interface failed: %.*s", len, buf);
return FALSE;
}
return TRUE;
}
/**
+ * Implementation of mconsole_t.exec
+ */
+static int exec(private_mconsole_t *this, void(*cb)(void*,char*,size_t),
+ void *data, char *cmd)
+{
+ return request(this, cb, data, "exec %s", cmd);
+}
+
+/**
* Poll until guest is ready
*/
static bool wait_bootup(private_mconsole_t *this)
{
- char buf[128];
- int len, res;
-
- while (TRUE)
+ /* wait for init process to appear */
+ while (request(this, ignore, NULL, "exec ps -p 1 > /dev/null"))
{
- len = sizeof(buf);
- 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;
- }
if (this->idle)
{
this->idle();
}
- else
- {
- usleep(50000);
- }
+ usleep(100000);
}
}
@@ -240,7 +231,7 @@ static void destroy(private_mconsole_t *this)
}
/**
- * setup the mconsole notify connection and wait for its readyness
+ * setup the mconsole notify connection and wait for its readiness
*/
static bool wait_for_notify(private_mconsole_t *this, char *nsock)
{
@@ -335,6 +326,7 @@ mconsole_t *mconsole_create(char *notify, void(*idle)(void))
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.exec = (int(*)(mconsole_t*, void(*cb)(void*,char*,size_t), void *data, char *cmd))exec;
this->public.destroy = (void*)destroy;
this->idle = idle;
diff --git a/src/dumm/mconsole.h b/src/dumm/mconsole.h
index 55ce15dda..329c40c06 100644
--- a/src/dumm/mconsole.h
+++ b/src/dumm/mconsole.h
@@ -43,6 +43,17 @@ struct mconsole_t {
bool (*del_iface)(mconsole_t *this, char *guest);
/**
+ * Execute a command in the UML host.
+ *
+ * @param cb callback function to invoke for each line
+ * @param data data to pass to callback
+ * @param cmd command to invoke
+ * @return return value of command
+ */
+ int (*exec)(mconsole_t *this, void(*cb)(void*,char*,size_t), void *data,
+ char *cmd);
+
+ /**
* @brief Destroy the mconsole instance
*/
void (*destroy) (mconsole_t *this);
diff --git a/src/dumm/testing.c b/src/dumm/testing.c
deleted file mode 100644
index c0d23296b..000000000
--- a/src/dumm/testing.c
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * 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;
-}