diff options
Diffstat (limited to 'src/dumm')
-rw-r--r-- | src/dumm/Makefile.in | 20 | ||||
-rw-r--r-- | src/dumm/cowfs.c | 256 | ||||
-rw-r--r-- | src/dumm/cowfs.h | 24 | ||||
-rw-r--r-- | src/dumm/dumm.c | 157 | ||||
-rw-r--r-- | src/dumm/dumm.h | 41 | ||||
-rw-r--r-- | src/dumm/ext/dumm.c | 152 | ||||
-rw-r--r-- | src/dumm/ext/lib/dumm.rb | 6 | ||||
-rw-r--r-- | src/dumm/ext/lib/dumm/guest.rb | 21 | ||||
-rw-r--r-- | src/dumm/guest.c | 47 | ||||
-rw-r--r-- | src/dumm/guest.h | 25 |
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**)¤t, &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. |