summaryrefslogtreecommitdiff
path: root/src/dumm
diff options
context:
space:
mode:
Diffstat (limited to 'src/dumm')
-rw-r--r--src/dumm/Makefile.in20
-rw-r--r--src/dumm/cowfs.c256
-rw-r--r--src/dumm/cowfs.h24
-rw-r--r--src/dumm/dumm.c157
-rw-r--r--src/dumm/dumm.h41
-rw-r--r--src/dumm/ext/dumm.c152
-rw-r--r--src/dumm/ext/lib/dumm.rb6
-rw-r--r--src/dumm/ext/lib/dumm/guest.rb21
-rw-r--r--src/dumm/guest.c47
-rw-r--r--src/dumm/guest.h25
10 files changed, 542 insertions, 207 deletions
diff --git a/src/dumm/Makefile.in b/src/dumm/Makefile.in
index 37751b856..7c22f5ec5 100644
--- a/src/dumm/Makefile.in
+++ b/src/dumm/Makefile.in
@@ -46,6 +46,7 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/config/libtool.m4 \
$(top_srcdir)/m4/config/lt~obsolete.m4 \
$(top_srcdir)/m4/macros/with.m4 \
$(top_srcdir)/m4/macros/enable-disable.m4 \
+ $(top_srcdir)/m4/macros/add-plugin.m4 \
$(top_srcdir)/configure.in
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
@@ -171,6 +172,8 @@ PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
PERL = @PERL@
PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
PTHREADLIB = @PTHREADLIB@
RANLIB = @RANLIB@
RTLIB = @RTLIB@
@@ -202,14 +205,17 @@ build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
+c_plugins = @c_plugins@
datadir = @datadir@
datarootdir = @datarootdir@
+dbusservicedir = @dbusservicedir@
default_pkcs11 = @default_pkcs11@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
gtk_CFLAGS = @gtk_CFLAGS@
gtk_LIBS = @gtk_LIBS@
+h_plugins = @h_plugins@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
@@ -224,24 +230,31 @@ ipsecgid = @ipsecgid@
ipsecgroup = @ipsecgroup@
ipsecuid = @ipsecuid@
ipsecuser = @ipsecuser@
+libcharon_plugins = @libcharon_plugins@
libdir = @libdir@
libexecdir = @libexecdir@
-libhydra_plugins = @libhydra_plugins@
-libstrongswan_plugins = @libstrongswan_plugins@
linux_headers = @linux_headers@
localedir = @localedir@
localstatedir = @localstatedir@
lt_ECHO = @lt_ECHO@
+maemo_CFLAGS = @maemo_CFLAGS@
+maemo_LIBS = @maemo_LIBS@
+manager_plugins = @manager_plugins@
mandir = @mandir@
+medsrv_plugins = @medsrv_plugins@
mkdir_p = @mkdir_p@
nm_CFLAGS = @nm_CFLAGS@
nm_LIBS = @nm_LIBS@
nm_ca_dir = @nm_ca_dir@
oldincludedir = @oldincludedir@
+openac_plugins = @openac_plugins@
+p_plugins = @p_plugins@
pdfdir = @pdfdir@
piddir = @piddir@
+pki_plugins = @pki_plugins@
plugindir = @plugindir@
pluto_plugins = @pluto_plugins@
+pool_plugins = @pool_plugins@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
@@ -249,7 +262,10 @@ random_device = @random_device@
resolv_conf = @resolv_conf@
routing_table = @routing_table@
routing_table_prio = @routing_table_prio@
+s_plugins = @s_plugins@
sbindir = @sbindir@
+scepclient_plugins = @scepclient_plugins@
+scripts_plugins = @scripts_plugins@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
strongswan_conf = @strongswan_conf@
diff --git a/src/dumm/cowfs.c b/src/dumm/cowfs.c
index 70767890b..b92be53e0 100644
--- a/src/dumm/cowfs.c
+++ b/src/dumm/cowfs.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2009 Tobias Brunner
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
* Copyright (C) 2001-2007 Miklos Szeredi
@@ -35,6 +36,8 @@
#include <library.h>
#include <debug.h>
#include <threading/thread.h>
+#include <threading/rwlock.h>
+#include <utils/linked_list.h>
/** define _XOPEN_SOURCE 500 fails when using libstrongswan, define popen */
extern ssize_t pread(int fd, void *buf, size_t count, off_t offset);
@@ -55,18 +58,66 @@ struct private_cowfs_t {
char *master;
/** host filesystem path */
char *host;
- /** overlay filesystem path */
- char *over;
+ /** overlay filesystems */
+ linked_list_t *overlays;
+ /** lock for overlays */
+ rwlock_t *lock;
/** fd of read only master filesystem */
int master_fd;
/** copy on write overlay to master */
int host_fd;
- /** optional COW overlay */
- int over_fd;
/** thread processing FUSE */
thread_t *thread;
};
+typedef struct overlay_t overlay_t;
+
+/**
+ * data for overlay filesystems
+ */
+struct overlay_t {
+ /** path to overlay */
+ char *path;
+ /** overlay fd */
+ int fd;
+};
+
+/**
+ * destroy an overlay
+ */
+static void overlay_destroy(overlay_t *this)
+{
+ close(this->fd);
+ free(this->path);
+ free(this);
+}
+
+/**
+ * compare two overlays by path
+ */
+static bool overlay_equals(overlay_t *this, overlay_t *other)
+{
+ return streq(this->path, other->path);
+}
+
+/**
+ * remove and destroy the overlay with the given absolute path.
+ * returns FALSE, if not found.
+ */
+static bool overlay_remove(private_cowfs_t *this, char *path)
+{
+ overlay_t over, *current;
+ over.path = path;
+ if (this->overlays->find_first(this->overlays,
+ (linked_list_match_t)overlay_equals, (void**)&current, &over) != SUCCESS)
+ {
+ return FALSE;
+ }
+ this->overlays->remove(this->overlays, current, NULL);
+ overlay_destroy(current);
+ return TRUE;
+}
+
/**
* get this pointer stored in fuse context
*/
@@ -95,12 +146,25 @@ static void rel(const char **path)
*/
static int get_rd(const char *path)
{
+ overlay_t *over;
+ enumerator_t *enumerator;
private_cowfs_t *this = get_this();
- if (this->over_fd > 0 && faccessat(this->over_fd, path, F_OK, 0) == 0)
+ this->lock->read_lock(this->lock);
+ enumerator = this->overlays->create_enumerator(this->overlays);
+ while (enumerator->enumerate(enumerator, (void**)&over))
{
- return this->over_fd;
+ if (faccessat(over->fd, path, F_OK, 0) == 0)
+ {
+ int fd = over->fd;
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+ return fd;
+ }
}
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+
if (faccessat(this->host_fd, path, F_OK, 0) == 0)
{
return this->host_fd;
@@ -113,12 +177,16 @@ static int get_rd(const char *path)
*/
static int get_wr(const char *path)
{
+ overlay_t *over;
private_cowfs_t *this = get_this();
- if (this->over_fd > 0)
+ int fd = this->host_fd;
+ this->lock->read_lock(this->lock);
+ if (this->overlays->get_first(this->overlays, (void**)&over) == SUCCESS)
{
- return this->over_fd;
+ fd = over->fd;
}
- return this->host_fd;
+ this->lock->unlock(this->lock);
+ return fd;
}
/**
@@ -287,17 +355,29 @@ static DIR* get_dir(char *dir, const char *subdir)
*/
static bool contains_dir(DIR *d, char *dirname)
{
- if (d)
+ struct dirent *ent;
+
+ rewinddir(d);
+ while ((ent = readdir(d)))
{
- struct dirent *ent;
+ if (streq(ent->d_name, dirname))
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
- rewinddir(d);
- while ((ent = readdir(d)))
+/**
+ * check if one of the higher overlays contains a directory
+ */
+static bool overlays_contain_dir(DIR **d, char *dirname)
+{
+ for (; *d; ++d)
+ {
+ if (contains_dir(*d, dirname))
{
- if (streq(ent->d_name, dirname))
- {
- return TRUE;
- }
+ return TRUE;
}
}
return FALSE;
@@ -309,56 +389,54 @@ static bool contains_dir(DIR *d, char *dirname)
static int cowfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi)
{
+#define ADD_DIR(overlay, base, path) ({\
+ DIR *dir = get_dir(base, path);\
+ if (dir) { *(--overlay) = dir; }\
+})
private_cowfs_t *this = get_this();
- DIR *d1, *d2, *d3;
+ int count;
+ DIR **d, **overlays;
struct stat st;
struct dirent *ent;
+ overlay_t *over;
+ enumerator_t *enumerator;
memset(&st, 0, sizeof(st));
- d1 = get_dir(this->master, path);
- d2 = get_dir(this->host, path);
- d3 = get_dir(this->over, path);
+ this->lock->read_lock(this->lock);
+ /* create a null-terminated array of DIR objects for all overlays (including
+ * the master and host layer). the order is from bottom to top */
+ count = this->overlays->get_count(this->overlays) + 2;
+ overlays = calloc(count + 1, sizeof(DIR*));
+ d = &overlays[count];
- if (d1)
+ enumerator = this->overlays->create_enumerator(this->overlays);
+ while (enumerator->enumerate(enumerator, (void**)&over))
{
- while ((ent = readdir(d1)))
- {
- if (!contains_dir(d2, ent->d_name) &&
- !contains_dir(d3, ent->d_name))
- {
- st.st_ino = ent->d_ino;
- st.st_mode = ent->d_type << 12;
- filler(buf, ent->d_name, &st, 0);
- }
- }
- closedir(d1);
+ ADD_DIR(d, over->path, path);
}
- if (d2)
+ enumerator->destroy(enumerator);
+ this->lock->unlock(this->lock);
+
+ ADD_DIR(d, this->host, path);
+ ADD_DIR(d, this->master, path);
+
+ for (; *d; ++d)
{
- rewinddir(d2);
- while ((ent = readdir(d2)))
+ rewinddir(*d);
+ while((ent = readdir(*d)))
{
- if (!contains_dir(d3, ent->d_name))
+ if (!overlays_contain_dir(d + 1, ent->d_name))
{
st.st_ino = ent->d_ino;
st.st_mode = ent->d_type << 12;
filler(buf, ent->d_name, &st, 0);
}
}
- closedir(d2);
- }
- if (d3)
- {
- rewinddir(d3);
- while ((ent = readdir(d3)))
- {
- st.st_ino = ent->d_ino;
- st.st_mode = ent->d_type << 12;
- filler(buf, ent->d_name, &st, 0);
- }
- closedir(d3);
+ closedir(*d);
}
+
+ free(overlays);
return 0;
}
@@ -758,30 +836,53 @@ static struct fuse_operations cowfs_operations = {
};
/**
- * Implementation of cowfs_t.set_overlay.
+ * Implementation of cowfs_t.add_overlay.
*/
-static bool set_overlay(private_cowfs_t *this, char *path)
+static bool add_overlay(private_cowfs_t *this, char *path)
{
- if (this->over)
- {
- free(this->over);
- this->over = NULL;
- }
- if (this->over_fd > 0)
- {
- close(this->over_fd);
- this->over_fd = -1;
- }
- if (path)
+ overlay_t *over = malloc_thing(overlay_t);
+ over->fd = open(path, O_RDONLY | O_DIRECTORY);
+ if (over->fd < 0)
+ {
+ DBG1(DBG_LIB, "failed to open overlay directory '%s': %m", path);
+ free(over);
+ return FALSE;
+ }
+ over->path = realpath(path, NULL);
+ this->lock->write_lock(this->lock);
+ overlay_remove(this, over->path);
+ this->overlays->insert_first(this->overlays, over);
+ this->lock->unlock(this->lock);
+ return TRUE;
+}
+
+/**
+ * Implementation of cowfs_t.del_overlay.
+ */
+static bool del_overlay(private_cowfs_t *this, char *path)
+{
+ bool removed;
+ char real[PATH_MAX];
+ this->lock->write_lock(this->lock);
+ removed = overlay_remove(this, realpath(path, real));
+ this->lock->unlock(this->lock);
+ return removed;
+}
+
+/**
+ * Implementation of cowfs_t.pop_overlay.
+ */
+static bool pop_overlay(private_cowfs_t *this)
+{
+ overlay_t *over;
+ this->lock->write_lock(this->lock);
+ if (this->overlays->remove_first(this->overlays, (void**)&over) != SUCCESS)
{
- this->over_fd = open(path, O_RDONLY | O_DIRECTORY);
- if (this->over_fd < 0)
- {
- DBG1(DBG_LIB, "failed to open overlay directory '%s': %m", path);
- return FALSE;
- }
- this->over = strdup(path);
+ this->lock->unlock(this->lock);
+ return FALSE;
}
+ this->lock->unlock(this->lock);
+ overlay_destroy(over);
return TRUE;
}
@@ -794,16 +895,13 @@ static void destroy(private_cowfs_t *this)
fuse_unmount(this->mount, this->chan);
this->thread->join(this->thread);
fuse_destroy(this->fuse);
+ this->lock->destroy(this->lock);
+ this->overlays->destroy_function(this->overlays, (void*)overlay_destroy);
free(this->mount);
free(this->master);
free(this->host);
- free(this->over);
close(this->master_fd);
close(this->host_fd);
- if (this->over_fd > 0)
- {
- close(this->over_fd);
- }
free(this);
}
@@ -815,7 +913,9 @@ cowfs_t *cowfs_create(char *master, char *host, char *mount)
struct fuse_args args = {0, NULL, 0};
private_cowfs_t *this = malloc_thing(private_cowfs_t);
- this->public.set_overlay = (bool(*)(cowfs_t*, char *path))set_overlay;
+ this->public.add_overlay = (bool(*)(cowfs_t*, char *path))add_overlay;
+ this->public.del_overlay = (bool(*)(cowfs_t*, char *path))del_overlay;
+ this->public.pop_overlay = (bool(*)(cowfs_t*))pop_overlay;
this->public.destroy = (void(*)(cowfs_t*))destroy;
this->master_fd = open(master, O_RDONLY | O_DIRECTORY);
@@ -833,7 +933,6 @@ cowfs_t *cowfs_create(char *master, char *host, char *mount)
free(this);
return NULL;
}
- this->over_fd = -1;
this->chan = fuse_mount(mount, &args);
if (this->chan == NULL)
@@ -860,13 +959,16 @@ cowfs_t *cowfs_create(char *master, char *host, char *mount)
this->mount = strdup(mount);
this->master = strdup(master);
this->host = strdup(host);
- this->over = NULL;
+ this->overlays = linked_list_create();
+ this->lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
this->thread = thread_create((thread_main_t)fuse_loop, this->fuse);
if (!this->thread)
{
DBG1(DBG_LIB, "creating thread to handle FUSE failed");
fuse_unmount(mount, this->chan);
+ this->lock->destroy(this->lock);
+ this->overlays->destroy(this->overlays);
free(this->mount);
free(this->master);
free(this->host);
diff --git a/src/dumm/cowfs.h b/src/dumm/cowfs.h
index d430597a8..b9334dc96 100644
--- a/src/dumm/cowfs.h
+++ b/src/dumm/cowfs.h
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2009 Tobias Brunner
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -27,12 +28,29 @@ typedef struct cowfs_t cowfs_t;
struct cowfs_t {
/**
- * Set an additional copy on write overlay.
+ * Adds an additional copy on write overlay.
+ *
+ * If the path was already added as overlay, it is moved to the top.
+ *
+ * @param path path of the overlay
+ * @return FALSE, if failed
+ */
+ bool (*add_overlay)(cowfs_t *this, char *path);
+
+ /**
+ * Remove the specified copy on write overlay.
*
* @param path path of the overlay
- * @return FALSE if failed
+ * @return FALSE, if not found
+ */
+ bool (*del_overlay)(cowfs_t *this, char *path);
+
+ /**
+ * Remove the most recently added copy on write overlay.
+ *
+ * @return FALSE, if no overlay was found
*/
- bool (*set_overlay)(cowfs_t *this, char *path);
+ bool (*pop_overlay)(cowfs_t *this);
/**
* Stop, umount and destroy a cowfs FUSE filesystem.
diff --git a/src/dumm/dumm.c b/src/dumm/dumm.c
index 7ec340089..8cd413519 100644
--- a/src/dumm/dumm.c
+++ b/src/dumm/dumm.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Tobias Brunner
+ * Copyright (C) 2008-2009 Tobias Brunner
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -128,51 +128,145 @@ static void delete_bridge(private_dumm_t *this, bridge_t *bridge)
}
/**
- * disable the currently enabled template
+ * Implementation of dumm_t.add_overlay.
*/
-static void clear_template(private_dumm_t *this)
+static bool add_overlay(private_dumm_t *this, char *dir)
{
enumerator_t *enumerator;
guest_t *guest;
- free(this->template);
- this->template = NULL;
+ if (dir == NULL)
+ {
+ return TRUE;
+ }
+ if (strlen(dir) > PATH_MAX)
+ {
+ DBG1(DBG_LIB, "overlay directory string '%s' is too long", dir);
+ return FALSE;
+ }
+ if (access(dir, F_OK) != 0)
+ {
+ if (!mkdir_p(dir, PERME))
+ {
+ DBG1(DBG_LIB, "creating overlay directory '%s' failed: %m", dir);
+ return FALSE;
+ }
+ }
+ enumerator = this->guests->create_enumerator(this->guests);
+ while (enumerator->enumerate(enumerator, (void**)&guest))
+ {
+ char guest_dir[PATH_MAX];
+ int len = snprintf(guest_dir, sizeof(guest_dir), "%s/%s", dir,
+ guest->get_name(guest));
+ if (len < 0 || len >= sizeof(guest_dir))
+ {
+ goto error;
+ }
+ if (access(guest_dir, F_OK) != 0)
+ {
+ if (!mkdir_p(guest_dir, PERME))
+ {
+ DBG1(DBG_LIB, "creating overlay directory for guest '%s' failed: %m",
+ guest->get_name(guest));
+ goto error;
+ }
+ }
+ if (!guest->add_overlay(guest, guest_dir))
+ {
+ goto error;
+ }
+ }
+ enumerator->destroy(enumerator);
+ return TRUE;
+error:
+ enumerator->destroy(enumerator);
+ this->public.del_overlay(&this->public, dir);
+ return FALSE;
+}
+
+/**
+ * Implementation of dumm_t.del_overlay.
+ */
+static bool del_overlay(private_dumm_t *this, char *dir)
+{
+ bool ret = FALSE;
+ enumerator_t *enumerator;
+ guest_t *guest;
enumerator = this->guests->create_enumerator(this->guests);
while (enumerator->enumerate(enumerator, (void**)&guest))
{
- guest->load_template(guest, NULL);
+ char guest_dir[PATH_MAX];
+ int len = snprintf(guest_dir, sizeof(guest_dir), "%s/%s", dir,
+ guest->get_name(guest));
+ if (len < 0 || len >= sizeof(guest_dir))
+ {
+ continue;
+ }
+ ret = guest->del_overlay(guest, guest_dir) || ret;
}
enumerator->destroy(enumerator);
+ return ret;
}
/**
- * Implementation of dumm_t.load_template.
+ * Implementation of dumm_t.pop_overlay.
*/
-static bool load_template(private_dumm_t *this, char *dir)
+static bool pop_overlay(private_dumm_t *this)
{
+ bool ret = FALSE;
enumerator_t *enumerator;
guest_t *guest;
- clear_template(this);
+ enumerator = this->guests->create_enumerator(this->guests);
+ while (enumerator->enumerate(enumerator, (void**)&guest))
+ {
+ ret = guest->pop_overlay(guest) || ret;
+ }
+ enumerator->destroy(enumerator);
+ return ret;
+}
- if (dir == NULL)
+/**
+ * disable the currently enabled template
+ */
+static void clear_template(private_dumm_t *this)
+{
+ if (this->template)
+ {
+ del_overlay(this, this->template);
+ free(this->template);
+ this->template = NULL;
+ }
+}
+
+/**
+ * Implementation of dumm_t.load_template.
+ */
+static bool load_template(private_dumm_t *this, char *name)
+{
+ clear_template(this);
+ if (name == NULL)
{
return TRUE;
}
- if (strlen(dir) > PATH_MAX)
+ if (strlen(name) > PATH_MAX)
{
- DBG1(DBG_LIB, "template directory string '%s' is too long", dir);
+ DBG1(DBG_LIB, "template name '%s' is too long", name);
return FALSE;
}
-
- if (asprintf(&this->template, "%s/%s", TEMPLATE_DIR, dir) < 0)
+ if (strchr(name, '/') != NULL)
+ {
+ DBG1(DBG_LIB, "template name '%s' must not contain '/' characters", name);
+ return FALSE;
+ }
+ if (asprintf(&this->template, "%s/%s", TEMPLATE_DIR, name) < 0)
{
this->template = NULL;
return FALSE;
}
if (access(this->template, F_OK) != 0)
- { /* does not exist, create template */
+ {
if (!mkdir_p(this->template, PERME))
{
DBG1(DBG_LIB, "creating template directory '%s' failed: %m",
@@ -180,18 +274,7 @@ static bool load_template(private_dumm_t *this, char *dir)
return FALSE;
}
}
- enumerator = this->guests->create_enumerator(this->guests);
- while (enumerator->enumerate(enumerator, (void**)&guest))
- {
- if (!guest->load_template(guest, this->template))
- {
- enumerator->destroy(enumerator);
- clear_template(this);
- return FALSE;
- }
- }
- enumerator->destroy(enumerator);
- return TRUE;
+ return add_overlay(this, this->template);
}
/**
@@ -205,7 +288,7 @@ typedef struct {
} template_enumerator_t;
/**
- * Implementation of template_enumerator_t.enumerate
+ * Implementation of template_enumerator_t.enumerate.
*/
static bool template_enumerate(template_enumerator_t *this, char **template)
{
@@ -224,7 +307,7 @@ static bool template_enumerate(template_enumerator_t *this, char **template)
}
/**
- * Implementation of template_enumerator_t.destroy
+ * Implementation of template_enumerator_t.destroy.
*/
static void template_enumerator_destroy(template_enumerator_t *this)
{
@@ -233,22 +316,25 @@ static void template_enumerator_destroy(template_enumerator_t *this)
}
/**
- * Implementation of dumm_t.create_template_enumerator
+ * Implementation of dumm_t.create_template_enumerator.
*/
static enumerator_t* create_template_enumerator(private_dumm_t *this)
{
template_enumerator_t *enumerator;
-
enumerator = malloc_thing(template_enumerator_t);
enumerator->public.enumerate = (void*)template_enumerate;
enumerator->public.destroy = (void*)template_enumerator_destroy;
enumerator->inner = enumerator_create_directory(TEMPLATE_DIR);
-
+ if (!enumerator->inner)
+ {
+ free(enumerator);
+ return enumerator_create_empty();
+ }
return &enumerator->public;
}
/**
- * Implementation of dumm_t.destroy
+ * Implementation of dumm_t.destroy.
*/
static void destroy(private_dumm_t *this)
{
@@ -324,7 +410,10 @@ dumm_t *dumm_create(char *dir)
this->public.create_bridge = (bridge_t*(*)(dumm_t*, char *name))create_bridge;
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.add_overlay = (bool(*)(dumm_t*,char*))add_overlay;
+ this->public.del_overlay = (bool(*)(dumm_t*,char*))del_overlay;
+ this->public.pop_overlay = (bool(*)(dumm_t*))pop_overlay;
+ this->public.load_template = (bool(*)(dumm_t*,char*))load_template;
this->public.create_template_enumerator = (enumerator_t*(*)(dumm_t*))create_template_enumerator;
this->public.destroy = (void(*)(dumm_t*))destroy;
diff --git a/src/dumm/dumm.h b/src/dumm/dumm.h
index 54c3fbc03..4bd20808c 100644
--- a/src/dumm/dumm.h
+++ b/src/dumm/dumm.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Tobias Brunner
+ * Copyright (C) 2008-2009 Tobias Brunner
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -83,12 +83,47 @@ struct dumm_t {
void (*delete_bridge) (dumm_t *this, bridge_t *bridge);
/**
+ * Add an overlay to all guests.
+ *
+ * Directories named after the guests are created, if they do not exist
+ * in the given overlay directory.
+ *
+ * If adding the overlay on at lest one guest fails, FALSE is returned and
+ * the overlay is again removed from all guests.
+ *
+ * @param dir dir to the overlay
+ * @return FALSE, on failure
+ */
+ bool (*add_overlay)(dumm_t *this, char *dir);
+
+ /**
+ * Removes an overlay from all guests.
+ *
+ * @param dir dir to the overlay
+ * @return FALSE, if the overlay was not found on any guest
+ */
+ bool (*del_overlay)(dumm_t *this, char *dir);
+
+ /**
+ * Remove the latest overlay from all guests.
+ *
+ * @return FALSE, if no overlay was found on any guest
+ */
+ bool (*pop_overlay)(dumm_t *this);
+
+ /**
* Loads a template, create a new one if it does not exist.
*
- * @param name dir to the template, NULL to close
+ * This is basically a wrapper around add/del_overlay to simplify working
+ * with overlays. Templates are located in a predefined directory, so that
+ * only a name for the template has to be specified here. Only one template
+ * can be loaded at any one time (but other overlays can be added on top or
+ * below a template).
+ *
+ * @param name name of the template to load, NULL to unload
* @return FALSE if load/create failed
*/
- bool (*load_template)(dumm_t *this, char *dir);
+ bool (*load_template)(dumm_t *this, char *name);
/**
* Create an enumerator over all available templates.
diff --git a/src/dumm/ext/dumm.c b/src/dumm/ext/dumm.c
index 230e8ae68..a9c7cb8bd 100644
--- a/src/dumm/ext/dumm.c
+++ b/src/dumm/ext/dumm.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Tobias Brunner
+ * Copyright (C) 2008-2010 Tobias Brunner
* Copyright (C) 2008 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -85,82 +85,108 @@ static void sigchld_handler(int signal, siginfo_t *info, void* ptr)
enumerator->destroy(enumerator);
}
+
/**
- * Guest bindings
+ * Global Dumm bindings
*/
-static VALUE guest_find(VALUE class, VALUE key)
+static VALUE dumm_add_overlay(VALUE class, VALUE dir)
{
- enumerator_t *enumerator;
- guest_t *guest, *found = NULL;
-
- if (TYPE(key) == T_SYMBOL)
+ if (!dumm->add_overlay(dumm, StringValuePtr(dir)))
{
- key = rb_convert_type(key, T_STRING, "String", "to_s");
+ rb_raise(rb_eRuntimeError, "loading overlay failed");
}
+ return class;
+}
+
+static VALUE dumm_del_overlay(VALUE class, VALUE dir)
+{
+ return dumm->del_overlay(dumm, StringValuePtr(dir)) ? Qtrue : Qfalse;
+}
+
+static VALUE dumm_pop_overlay(VALUE class)
+{
+ return dumm->pop_overlay(dumm) ? Qtrue : Qfalse;
+}
+
+static void dumm_init()
+{
+ rbm_dumm = rb_define_module("Dumm");
+
+ rb_define_module_function(rbm_dumm, "add_overlay", dumm_add_overlay, 1);
+ rb_define_module_function(rbm_dumm, "del_overlay", dumm_del_overlay, 1);
+ rb_define_module_function(rbm_dumm, "pop_overlay", dumm_pop_overlay, 0);
+}
+
+/**
+ * Guest bindings
+ */
+static VALUE guest_hash_create(VALUE class)
+{
+ enumerator_t *enumerator;
+ guest_t *guest;
+ VALUE hash = rb_hash_new();
enumerator = dumm->create_guest_enumerator(dumm);
while (enumerator->enumerate(enumerator, &guest))
{
- if (streq(guest->get_name(guest), StringValuePtr(key)))
- {
- found = guest;
- break;
- }
+ rb_hash_aset(hash, rb_str_new2(guest->get_name(guest)),
+ Data_Wrap_Struct(class, NULL, NULL, guest));
}
enumerator->destroy(enumerator);
- if (!found)
+ return hash;
+}
+
+static VALUE guest_hash(VALUE class)
+{
+ ID id = rb_intern("@@guests");
+ if (!rb_cvar_defined(class, id))
{
- return Qnil;
+ VALUE hash = guest_hash_create(class);
+ rb_cvar_set(class, id, hash, 0);
+ return hash;
}
- return Data_Wrap_Struct(class, NULL, NULL, found);
+ return rb_cvar_get(class, id);
}
-static VALUE guest_get(VALUE class, VALUE key)
+static VALUE guest_find(VALUE class, VALUE key)
{
- VALUE guest = guest_find(class, key);
- if (NIL_P(guest))
+ if (TYPE(key) != T_STRING)
{
- rb_raise(rb_eRuntimeError, "guest not found");
+ key = rb_convert_type(key, T_STRING, "String", "to_s");
}
- return guest;
+ return rb_hash_aref(guest_hash(class), key);
}
-static VALUE guest_each(int argc, VALUE *argv, VALUE class)
+static VALUE guest_get(VALUE class, VALUE key)
{
- linked_list_t *list;
- enumerator_t *enumerator;
- guest_t *guest;
+ return guest_find(class, key);
+}
+static VALUE guest_each(int argc, VALUE *argv, VALUE class)
+{
if (!rb_block_given_p())
{
rb_raise(rb_eArgError, "must be called with a block");
}
- list = linked_list_create();
- enumerator = dumm->create_guest_enumerator(dumm);
- while (enumerator->enumerate(enumerator, &guest))
- {
- list->insert_last(list, guest);
- }
- enumerator->destroy(enumerator);
- while (list->remove_first(list, (void**)&guest) == SUCCESS)
- {
- rb_yield(Data_Wrap_Struct(class, NULL, NULL, guest));
- }
- list->destroy(list);
+ rb_block_call(guest_hash(class), rb_intern("each_value"), 0, 0,
+ rb_yield, 0);
return class;
}
static VALUE guest_new(VALUE class, VALUE name, VALUE kernel,
VALUE master, VALUE args)
{
+ VALUE self;
guest_t *guest;
-
- guest = dumm->create_guest(dumm, StringValuePtr(name), StringValuePtr(kernel),
- StringValuePtr(master), StringValuePtr(args));
+ 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);
+ self = Data_Wrap_Struct(class, NULL, NULL, guest);
+ rb_hash_aset(guest_hash(class), name, self);
+ return self;
}
static VALUE guest_to_s(VALUE self)
@@ -214,11 +240,9 @@ static VALUE guest_exec(VALUE self, VALUE cmd)
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,
- "exec %s", StringValuePtr(cmd))) != 0)
- {
- rb_raise(rb_eRuntimeError, "executing command failed (%d)", ret);
- }
+ ret = guest->exec_str(guest, block ? (void*)exec_cb : NULL, TRUE, NULL,
+ "exec %s", StringValuePtr(cmd));
+ rb_iv_set(self, "@execstatus", INT2NUM(ret));
return self;
}
@@ -330,6 +354,34 @@ static VALUE guest_delete(VALUE self)
return Qnil;
}
+static VALUE guest_add_overlay(VALUE self, VALUE dir)
+{
+ guest_t *guest;
+
+ Data_Get_Struct(self, guest_t, guest);
+ if (!guest->add_overlay(guest, StringValuePtr(dir)))
+ {
+ rb_raise(rb_eRuntimeError, "loading overlay failed");
+ }
+ return self;
+}
+
+static VALUE guest_del_overlay(VALUE self, VALUE dir)
+{
+ guest_t *guest;
+
+ Data_Get_Struct(self, guest_t, guest);
+ return guest->del_overlay(guest, StringValuePtr(dir)) ? Qtrue : Qfalse;
+}
+
+static VALUE guest_pop_overlay(VALUE self)
+{
+ guest_t *guest;
+
+ Data_Get_Struct(self, guest_t, guest);
+ return guest->pop_overlay(guest) ? Qtrue : Qfalse;
+}
+
static void guest_init()
{
rbc_guest = rb_define_class_under(rbm_dumm , "Guest", rb_cObject);
@@ -354,6 +406,11 @@ static void guest_init()
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);
+ rb_define_method(rbc_guest, "add_overlay", guest_add_overlay, 1);
+ rb_define_method(rbc_guest, "del_overlay", guest_del_overlay, 1);
+ rb_define_method(rbc_guest, "pop_overlay", guest_pop_overlay, 0);
+
+ rb_define_attr(rbc_guest, "execstatus", 1, 0);
}
/**
@@ -711,8 +768,7 @@ void Init_dumm()
dumm = dumm_create(NULL);
- rbm_dumm = rb_define_module("Dumm");
-
+ dumm_init();
guest_init();
bridge_init();
iface_init();
diff --git a/src/dumm/ext/lib/dumm.rb b/src/dumm/ext/lib/dumm.rb
index 25939e9f4..bb60aad8f 100644
--- a/src/dumm/ext/lib/dumm.rb
+++ b/src/dumm/ext/lib/dumm.rb
@@ -1,5 +1,5 @@
=begin
- Copyright (C) 2008 Tobias Brunner
+ Copyright (C) 2008-2009 Tobias Brunner
Hochschule fuer Technik Rapperswil
This program is free software; you can redistribute it and/or modify it
@@ -38,11 +38,11 @@ module Dumm
end
end
- # unload templates, reset all guests and delete bridges
+ # unload template/overlays, reset all guests and delete bridges
def reset
Template.unload
Guest.each { |guest|
- guest.reset if guest.running?
+ guest.reset
}
Bridge.each { |bridge|
bridge.delete
diff --git a/src/dumm/ext/lib/dumm/guest.rb b/src/dumm/ext/lib/dumm/guest.rb
index 936f512dd..7488f1358 100644
--- a/src/dumm/ext/lib/dumm/guest.rb
+++ b/src/dumm/ext/lib/dumm/guest.rb
@@ -1,5 +1,5 @@
=begin
- Copyright (C) 2008 Tobias Brunner
+ Copyright (C) 2008-2010 Tobias Brunner
Hochschule fuer Technik Rapperswil
This program is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@ module Dumm
end
Guest[id]
end
-
+
# accessor for interfaces
# e.g. guest.eth0 instead of guest["eth0"]
def method_missing(id, *args)
@@ -32,24 +32,21 @@ module Dumm
end
self[id]
end
-
- # delete all interfaces
+
+ # remove all overlays, delete all interfaces
def reset
+ while pop_overlay; end
each {|i|
i.delete
}
end
-
+
# has the guest booted up?
def booted?
- begin
- exec("pgrep getty")
- rescue
- return false
- end
- return true
+ exec("pgrep getty")
+ execstatus == 0
end
-
+
# wait until the guest has booted
def boot
while not booted?
diff --git a/src/dumm/guest.c b/src/dumm/guest.c
index ebd87769a..36d048dcf 100644
--- a/src/dumm/guest.c
+++ b/src/dumm/guest.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Tobias Brunner
+ * Copyright (C) 2008-2009 Tobias Brunner
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -297,37 +297,42 @@ static bool start(private_guest_t *this, invoke_function_t invoke, void* data,
}
/**
- * Implementation of guest_t.load_template.
+ * Implementation of guest_t.add_overlay.
*/
-static bool load_template(private_guest_t *this, char *path)
+static bool add_overlay(private_guest_t *this, char *path)
{
- char dir[PATH_MAX];
- size_t len;
-
if (path == NULL)
{
- return this->cowfs->set_overlay(this->cowfs, NULL);
- }
-
- len = snprintf(dir, sizeof(dir), "%s/%s", path, this->name);
- if (len < 0 || len >= sizeof(dir))
- {
return FALSE;
}
- if (access(dir, F_OK) != 0)
+
+ if (access(path, F_OK) != 0)
{
- if (!mkdir_p(dir, PERME))
+ if (!mkdir_p(path, PERME))
{
DBG1(DBG_LIB, "creating overlay for guest '%s' failed: %m",
this->name);
return FALSE;
}
}
- if (!this->cowfs->set_overlay(this->cowfs, dir))
- {
- return FALSE;
- }
- return TRUE;
+
+ return this->cowfs->add_overlay(this->cowfs, path);
+}
+
+/**
+ * Implementation of guest_t.del_overlay.
+ */
+static bool del_overlay(private_guest_t *this, char *path)
+{
+ return this->cowfs->del_overlay(this->cowfs, path);
+}
+
+/**
+ * Implementation of guest_t.pop_overlay.
+ */
+static bool pop_overlay(private_guest_t *this)
+{
+ return this->cowfs->pop_overlay(this->cowfs);
}
/**
@@ -567,7 +572,9 @@ static private_guest_t *guest_create_generic(char *parent, char *name,
this->public.create_iface_enumerator = (enumerator_t*(*)(guest_t*))create_iface_enumerator;
this->public.start = (void*)start;
this->public.stop = (void*)stop;
- this->public.load_template = (bool(*)(guest_t*, char *path))load_template;
+ this->public.add_overlay = (bool(*)(guest_t*,char*))add_overlay;
+ this->public.del_overlay = (bool(*)(guest_t*,char*))del_overlay;
+ this->public.pop_overlay = (bool(*)(guest_t*))pop_overlay;
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;
diff --git a/src/dumm/guest.h b/src/dumm/guest.h
index 5f812f8eb..789f2310e 100644
--- a/src/dumm/guest.h
+++ b/src/dumm/guest.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Tobias Brunner
+ * Copyright (C) 2008-2009 Tobias Brunner
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -134,12 +134,27 @@ struct guest_t {
enumerator_t* (*create_iface_enumerator)(guest_t *this);
/**
- * Set the template COWFS overlay to use.
+ * Adds a COWFS overlay. The directory is created if it does not exist.
*
- * @param parent parent directory where template diff should point to
- * @return FALSE if failed
+ * @param dir directory where overlay diff should point to
+ * @return FALSE, if failed
*/
- bool (*load_template)(guest_t *this, char *parent);
+ bool (*add_overlay)(guest_t *this, char *dir);
+
+ /**
+ * Removes the specified COWFS overlay.
+ *
+ * @param dir directory where overlay diff points to
+ * @return FALSE, if no found
+ */
+ bool (*del_overlay)(guest_t *this, char *dir);
+
+ /**
+ * Removes the latest COWFS overlay.
+ *
+ * @return FALSE, if no overlay was found
+ */
+ bool (*pop_overlay)(guest_t *this);
/**
* Execute a command on the guests mconsole.