diff options
author | Martin Willi <martin@strongswan.org> | 2007-07-30 13:20:35 +0000 |
---|---|---|
committer | Martin Willi <martin@strongswan.org> | 2007-07-30 13:20:35 +0000 |
commit | 725e263ff319be1003a538a02c6cba185bbcb48c (patch) | |
tree | 6c8f364cdf2ad22c6f03f934764db727944ec6c5 | |
parent | 70c5c34da74d144d948a0ed059d9e515fd737664 (diff) | |
download | strongswan-725e263ff319be1003a538a02c6cba185bbcb48c.tar.bz2 strongswan-725e263ff319be1003a538a02c6cba185bbcb48c.tar.xz |
bridging using libbridge
rewrite of guest, does not change cwd anymore
loading of created scenarios
-rw-r--r-- | src/dumm/Makefile | 4 | ||||
-rw-r--r-- | src/dumm/bridge.c | 160 | ||||
-rw-r--r-- | src/dumm/bridge.h | 76 | ||||
-rw-r--r-- | src/dumm/dumm.c | 119 | ||||
-rw-r--r-- | src/dumm/dumm.h | 32 | ||||
-rw-r--r-- | src/dumm/guest.c | 326 | ||||
-rw-r--r-- | src/dumm/guest.h | 23 | ||||
-rw-r--r-- | src/dumm/main.c | 42 |
8 files changed, 639 insertions, 143 deletions
diff --git a/src/dumm/Makefile b/src/dumm/Makefile index 62aa92913..85bcad69f 100644 --- a/src/dumm/Makefile +++ b/src/dumm/Makefile @@ -1,3 +1,3 @@ -dumm: dumm.c dumm.h guest.c guest.h iface.c iface.h mconsole.c mconsole.h main.c - gcc -o dumm dumm.c guest.c iface.c mconsole.c main.c -lreadline -lstrongswan -I../libstrongswan/ -g -O2 -Wall -Wno-format -Wno-strict-aliasing +dumm: dumm.c dumm.h guest.c guest.h iface.c iface.h bridge.c bridge.h mconsole.c mconsole.h main.c + gcc -o dumm dumm.c guest.c iface.c bridge.c mconsole.c main.c -lreadline -lbridge -lstrongswan -I../libstrongswan/ -g -O2 -Wall -Wno-format -Wno-strict-aliasing diff --git a/src/dumm/bridge.c b/src/dumm/bridge.c new file mode 100644 index 000000000..fa30ab6e9 --- /dev/null +++ b/src/dumm/bridge.c @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2007 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 <sys/types.h> +#include <libbridge.h> + +#include <debug.h> +#include <utils/linked_list.h> + +#include "bridge.h" + +typedef struct private_bridge_t private_bridge_t; + +struct private_bridge_t { + /** public interface */ + bridge_t public; + /** device name */ + char *name; + /** list of attached interfaces */ + linked_list_t *ifaces; +}; + +/** + * Implementation of bridge_t.get_name. + */ +static char* get_name(private_bridge_t *this) +{ + return this->name; +} + +/** + * Implementation of bridge_t.create_iface_iterator. + */ +static iterator_t* create_iface_iterator(private_bridge_t *this) +{ + return this->ifaces->create_iterator(this->ifaces, TRUE); +} + +/** + * Implementation of bridge_t.del_iface. + */ +static bool del_iface(private_bridge_t *this, iface_t *iface) +{ + iterator_t *iterator; + iface_t *current; + bool good = FALSE; + + iterator = this->ifaces->create_iterator(this->ifaces, TRUE); + while (iterator->iterate(iterator, (void**)¤t)) + { + if (current == iface) + { + if (br_del_interface(this->name, iface->get_hostif(iface)) != 0) + { + DBG1("removing iface '%s' from bridge '%s' in kernel failed: %m", + iface->get_hostif(iface), this->name); + } + else + { + good = TRUE; + } + break; + } + } + if (iface != current) + { + DBG1("iface '%s' not found on bridge '%s'", iface->get_hostif(iface), + this->name); + } + iterator->destroy(iterator); + return good; +} + +/** + * Implementation of bridge_t.add_iface. + */ +static bool add_iface(private_bridge_t *this, iface_t *iface) +{ + if (br_add_interface(this->name, iface->get_hostif(iface)) != 0) + { + DBG1("adding iface '%s' to bridge '%s' failed: %m", + iface->get_hostif(iface), this->name); + return FALSE; + } + this->ifaces->insert_last(this->ifaces, iface); + return TRUE; +} + +/** + * instance counter to (de-)initialize libbridge + */ +static int instances = 0; + +/** + * Implementation of bridge_t.destroy. + */ +static void destroy(private_bridge_t *this) +{ + this->ifaces->destroy(this->ifaces); + if (br_del_bridge(this->name) != 0) + { + DBG1("deleting bridge '%s' from kernel failed: %m", this->name); + } + free(this->name); + free(this); + if (--instances == 0) + { + br_shutdown(); + } +} + +/** + * create the bridge instance + */ +bridge_t *bridge_create(char *name) +{ + private_bridge_t *this; + + if (instances == 0) + { + if (br_init() != 0) + { + DBG1("libbridge initialization failed: %m"); + return NULL; + } + } + + this = malloc_thing(private_bridge_t); + this->public.get_name = (char*(*)(bridge_t*))get_name; + this->public.create_iface_iterator = (iterator_t*(*)(bridge_t*))create_iface_iterator; + this->public.del_iface = (bool(*)(bridge_t*, iface_t *iface))del_iface; + this->public.add_iface = (bool(*)(bridge_t*, iface_t *iface))add_iface; + this->public.destroy = (void*)destroy; + + if (br_add_bridge(name) != 0) + { + DBG1("creating bridge '%s' failed: %m", name); + free(this); + return NULL; + } + + this->name = strdup(name); + this->ifaces = linked_list_create(); + + instances++; + return &this->public; +} + diff --git a/src/dumm/bridge.h b/src/dumm/bridge.h new file mode 100644 index 000000000..d47f7ee54 --- /dev/null +++ b/src/dumm/bridge.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2007 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. + */ + +#ifndef BRIDGE_H +#define BRIDGE_H + +#include <library.h> +#include <utils/iterator.h> + +#include "iface.h" + +typedef struct bridge_t bridge_t; + +/** + * @brief Interface in a guest, connected to a tap device on the host. + */ +struct bridge_t { + + /** + * @brief Get the name of the bridge. + * + * @return name of the bridge + */ + char* (*get_name)(bridge_t *this); + + /** + * @brief Add an interface to a bridge. + * + * @param iface interface to add + * @return TRUE if interface added + */ + bool (*add_iface)(bridge_t *this, iface_t *iface); + + /** + * @brief Remove an interface from a bridge. + * + * @param iface interface to remove + * @return TRUE ifinterface removed + */ + bool (*del_iface)(bridge_t *this, iface_t *iface); + + /** + * @brief Create an iterator over all interfaces. + * + * @return iterator over iface_t's + */ + iterator_t* (*create_iface_iterator)(bridge_t *this); + + /** + * @brief Destroy a bridge + */ + void (*destroy) (bridge_t *this); +}; + +/** + * @brief Create a new bridge. + * + * @param name name of the bridge to create + * @return bridge, NULL if failed + */ +bridge_t *bridge_create(char *name); + +#endif /* BRIDGE_H */ + diff --git a/src/dumm/dumm.c b/src/dumm/dumm.c index 6432e74a7..b8211ff9e 100644 --- a/src/dumm/dumm.c +++ b/src/dumm/dumm.c @@ -13,7 +13,12 @@ * for more details. */ -#include <sys/stat.h> +#define _GNU_SOURCE + +#include <sys/types.h> +#include <unistd.h> +#include <stdio.h> +#include <dirent.h> #include <debug.h> @@ -22,16 +27,27 @@ typedef struct private_dumm_t private_dumm_t; struct private_dumm_t { + /** public dumm interface */ dumm_t public; + /** working dir */ + char *dir; + /** 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; }; -static guest_t* create_guest(private_dumm_t *this, char *name, char *master, int mem) +/** + * Implementation of dumm_t.create_guest. + */ +static guest_t* create_guest(private_dumm_t *this, char *name, char *kernel, + char *master, int mem) { guest_t *guest; - guest = guest_create(name, master, mem); + guest = guest_create(this->dir, name, kernel, master, mem); if (guest) { this->guests->insert_last(this->guests, guest); @@ -39,11 +55,37 @@ static guest_t* create_guest(private_dumm_t *this, char *name, char *master, int return guest; } +/** + * Implementation of dumm_t.create_guest_iterator. + */ static iterator_t* create_guest_iterator(private_dumm_t *this) { return this->guests->create_iterator(this->guests, TRUE); -} +} + +/** + * Implementation of dumm_t.create_bridge. + */ +static bridge_t* create_bridge(private_dumm_t *this, char *name) +{ + bridge_t *bridge; + bridge = bridge_create(name); + if (bridge) + { + this->bridges->insert_last(this->bridges, bridge); + } + return bridge; +} + +/** + * Implementation of dumm_t.create_bridge_iterator. + */ +static iterator_t* create_bridge_iterator(private_dumm_t *this) +{ + return this->bridges->create_iterator(this->bridges, TRUE); +} + /** * Implementation of dumm_t.sigchild_handler. */ @@ -53,13 +95,11 @@ static void sigchild_handler(private_dumm_t *this, siginfo_t *info) { return; } - switch (info->si_code) { case CLD_EXITED: case CLD_KILLED: case CLD_DUMPED: - case CLD_STOPPED: { iterator_t *iterator; guest_t *guest; @@ -81,11 +121,16 @@ static void sigchild_handler(private_dumm_t *this, siginfo_t *info) } } +/** + * Implementation of dumm_t.destroy + */ static void destroy(private_dumm_t *this) { iterator_t *iterator; guest_t *guest; + this->bridges->destroy_offset(this->bridges, offsetof(bridge_t, destroy)); + iterator = this->guests->create_iterator(this->guests, TRUE); while (iterator->iterate(iterator, (void**)&guest)) { @@ -95,40 +140,72 @@ static void destroy(private_dumm_t *this) this->destroying = TRUE; this->guests->destroy_offset(this->guests, offsetof(guest_t, destroy)); + free(this->dir); free(this); } /** - * check for a directory, create if it does not exist + * load all guests in our working dir */ -static bool makedir(char *dir) +static void load_guests(private_dumm_t *this) { - struct stat st; + DIR *dir; + struct dirent *ent; + guest_t *guest; - if (stat(dir, &st) != 0) + dir = opendir(this->dir); + if (dir == NULL) { - return mkdir(dir, S_IRWXU) == 0; + return; } - return S_ISDIR(st.st_mode); + + while ((ent = readdir(dir))) + { + if (streq(ent->d_name, ".") || streq(ent->d_name, "..")) + { + continue; + } + guest = guest_load(this->dir, ent->d_name); + if (guest) + { + this->guests->insert_last(this->guests, guest); + } + else + { + DBG1("loading guest in directory '%s' failed, skipped", ent->d_name); + } + } + closedir(dir); } -dumm_t *dumm_create() +/** + * create a dumm instance + */ +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_iterator = (iterator_t*(*)(dumm_t*))create_guest_iterator; + this->public.create_bridge = (bridge_t*(*)(dumm_t*, char *name))create_bridge; + this->public.create_bridge_iterator = (iterator_t*(*)(dumm_t*))create_bridge_iterator; this->public.sigchild_handler = (void(*)(dumm_t*, siginfo_t *info))sigchild_handler; - this->public.create_guest = (void*)create_guest; - this->public.create_guest_iterator = (void*)create_guest_iterator; - this->public.destroy = (void*)destroy; + this->public.destroy = (void(*)(dumm_t*))destroy; - if (!makedir(HOST_DIR) || !makedir(MOUNT_DIR) || !makedir(RUN_DIR)) + this->destroying = FALSE; + if (*dir == '/' || getcwd(cwd, sizeof(cwd)) == 0) { - free(this); - return NULL; + this->dir = strdup(dir); + } + else + { + asprintf(&this->dir, "%s/%s", cwd, dir); } - - this->destroying = FALSE; this->guests = linked_list_create(); + this->bridges = linked_list_create(); + + load_guests(this); return &this->public; } diff --git a/src/dumm/dumm.h b/src/dumm/dumm.h index fe4f9ca4e..cb68fdb1e 100644 --- a/src/dumm/dumm.h +++ b/src/dumm/dumm.h @@ -22,11 +22,7 @@ #include <utils/linked_list.h> #include "guest.h" - -#define HOST_DIR "host" -#define MOUNT_DIR "mount" -#define RUN_DIR "run" - +#include "bridge.h" typedef struct dumm_t dumm_t; @@ -41,11 +37,13 @@ struct dumm_t { * @brief Starts a new UML guest * * @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 * @return guest if started, NULL if failed */ - guest_t* (*create_guest) (dumm_t *this, char *name, char *master, int mem); + guest_t* (*create_guest) (dumm_t *this, char *name, char *kernel, + char *master, int mem); /** * @brief Create an iterator over all guests. @@ -55,6 +53,21 @@ struct dumm_t { iterator_t* (*create_guest_iterator) (dumm_t *this); /** + * @brief Create a new bridge. + * + * @param name name of the bridge to create + * @return created bridge + */ + bridge_t* (*create_bridge)(dumm_t *this, char *name); + + /** + * @brief Create an iterator over all bridges. + * + * @return iterator over bridge_t's + */ + iterator_t* (*create_bridge_iterator)(dumm_t *this); + + /** * @brief Handler for received SIG_CHILD signals. * * Dumm spans children, UML kernels. To track and cleanup these kernel @@ -73,13 +86,12 @@ struct dumm_t { }; /** - * @brief Create a new group of UML hosts and networks. - * - * Dumm uses its working dir to create folders and files it works with. + * @brief Create a group of UML hosts and networks. * + * @param dir directory to create guests/load from * @return created UML group, or NULL if failed. */ -dumm_t *dumm_create(); +dumm_t *dumm_create(char *dir); #endif /* DUMM_H */ diff --git a/src/dumm/guest.c b/src/dumm/guest.c index 784891835..533599bf5 100644 --- a/src/dumm/guest.c +++ b/src/dumm/guest.c @@ -17,12 +17,13 @@ #include <sys/types.h> #include <sys/stat.h> +#include <sys/wait.h> +#include <sys/uio.h> #include <unistd.h> #include <stdio.h> -#include <sys/uio.h> -#include <sys/types.h> #include <fcntl.h> #include <signal.h> +#include <dirent.h> #include <debug.h> #include <utils/linked_list.h> @@ -31,6 +32,9 @@ #include "guest.h" #include "mconsole.h" +#define PERME (S_IRWXU | S_IRWXG) +#define PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) + typedef struct private_guest_t private_guest_t; struct private_guest_t { @@ -38,8 +42,10 @@ struct private_guest_t { guest_t public; /** name of the guest */ char *name; - /** read only master filesystem guest uses */ - char *master; + /** directory of guest */ + int dir; + /** directory name of guest */ + char *dirname; /** amount of memory for guest, in MB */ int mem; /** pid of guest child process */ @@ -48,6 +54,8 @@ struct private_guest_t { guest_state_t state; /** log file for console 0 */ int bootlog; + /** has the unionfs been mounted */ + bool mounted; /** mconsole to control running UML */ mconsole_t *mconsole; /** list of interfaces attached to the guest */ @@ -151,12 +159,29 @@ static char* write_arg(char **pos, size_t *left, char *format, ...) } /** + * Implementation of guest_t.stop. + */ +static void stop(private_guest_t *this) +{ + if (this->state != GUEST_STOPPED) + { + this->state = GUEST_STOPPING; + this->ifaces->destroy_offset(this->ifaces, offsetof(iface_t, destroy)); + this->ifaces = linked_list_create(); + kill(this->pid, SIGINT); + while (this->state == GUEST_STOPPING) + { + sched_yield(); + } + } +} + +/** * Implementation of guest_t.start. */ static bool start(private_guest_t *this, char *kernel) { - char buf[1024]; - char cwd[512]; + char buf[2048]; char *notify; char *pos = buf; char *args[16]; @@ -170,14 +195,13 @@ static bool start(private_guest_t *this, char *kernel) } this->state = GUEST_STARTING; - notify = write_arg(&pos, &left, "%s/%s/notify", RUN_DIR, this->name); + notify = write_arg(&pos, &left, "%s/%s", this->dirname, NOTIFY_FILE); - args[i++] = kernel; + 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/%s", - getcwd(cwd, sizeof(cwd)), MOUNT_DIR, this->name); - args[i++] = write_arg(&pos, &left, "uml_dir=%s/%s", RUN_DIR, this->name); + 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); @@ -199,10 +223,10 @@ static bool start(private_guest_t *this, char *kernel) dup2(open("/dev/null", 0), 1); dup2(open("/dev/null", 0), 2); execvp(args[0], args); - DBG1("starting UML kernel '%s' failed", args[0]); + DBG1("starting UML kernel '%s' failed: %m", args[0]); exit(1); case -1: - this->pid = 0; + this->state = GUEST_STOPPED; return FALSE; default: break; @@ -212,8 +236,7 @@ static bool start(private_guest_t *this, char *kernel) if (this->mconsole == NULL) { DBG1("opening mconsole at '%s' failed, stopping guest", buf); - kill(this->pid, SIGINT); - this->pid = 0; + stop(this); return FALSE; } this->state = GUEST_RUNNING; @@ -221,72 +244,34 @@ static bool start(private_guest_t *this, char *kernel) } /** - * Implementation of guest_t.stop. - */ -static void stop(private_guest_t *this) -{ - if (this->state != GUEST_STOPPED) - { - this->state = GUEST_STOPPING; - this->ifaces->destroy_offset(this->ifaces, offsetof(iface_t, destroy)); - this->ifaces = linked_list_create(); - kill(this->pid, SIGINT); - while (this->state == GUEST_STOPPING) - { - sched_yield(); - } - } -} - -/** * Implementation of guest_t.sigchild. */ static void sigchild(private_guest_t *this) { + waitpid(this->pid, NULL, WNOHANG); DESTROY_IF(this->mconsole); this->mconsole = NULL; this->state = GUEST_STOPPED; - this->pid = 0; -} - -/** - * Check if directory exists, create otherwise - */ -static bool makedir(char *dir, char *name) -{ - struct stat st; - char buf[256]; - size_t len; - - len = snprintf(buf, sizeof(buf), "%s/%s", dir, name); - if (len < 0 || len >= sizeof(buf)) - { - return FALSE; - } - if (stat(buf, &st) != 0) - { - return mkdir(buf, S_IRWXU) == 0; - } - return S_ISDIR(st.st_mode); } /** * umount the union filesystem */ -static bool umount_unionfs(char *name) +static bool umount_unionfs(private_guest_t *this) { char cmd[128]; size_t len; - len = snprintf(cmd, sizeof(cmd), "fusermount -u %s/%s", MOUNT_DIR, name); - if (len < 0 || len >= sizeof(cmd)) - { - return FALSE; - } - if (system(cmd) != 0) + if (this->mounted) { - DBG1("unmounting guest unionfs for %s failed", name); - return FALSE; + len = snprintf(cmd, sizeof(cmd), "fusermount -u %s/%s", + this->dirname, UNION_DIR); + if (len < 0 || len >= sizeof(cmd) || system(cmd) != 0) + { + DBG1("unmounting guest unionfs failed"); + return FALSE; + } + this->mounted = FALSE; } return TRUE; } @@ -294,21 +279,22 @@ static bool umount_unionfs(char *name) /** * mount the union filesystem */ -static bool mount_unionfs(char *name, char *master) +static bool mount_unionfs(private_guest_t *this) { char cmd[256]; size_t len; - len = snprintf(cmd, sizeof(cmd), "unionfs %s/%s:%s %s/%s", - HOST_DIR, name, master, MOUNT_DIR, name); - if (len < 0 || len >= sizeof(cmd)) + if (!this->mounted) { - return FALSE; - } - if (system(cmd) != 0) - { - DBG1("mounting guest unionfs for %s using '%s' failed", name, cmd); - return FALSE; + len = snprintf(cmd, sizeof(cmd), "unionfs %s/%s:%s/%s %s/%s", + this->dirname, MASTER_DIR, this->dirname, DIFF_DIR, + this->dirname, UNION_DIR); + if (len < 0 || len >= sizeof(cmd) || system(cmd) != 0) + { + DBG1("mounting guest unionfs failed"); + return FALSE; + } + this->mounted = TRUE; } return TRUE; } @@ -316,43 +302,87 @@ static bool mount_unionfs(char *name, char *master) /** * open logfile for boot messages */ -static int open_bootlog(char *name) +static int open_bootlog(private_guest_t *this) { - char blg[256]; - size_t len; int fd; - len = snprintf(blg, sizeof(blg), "%s/%s/boot.log", RUN_DIR, name); - if (len < 0 || len >= sizeof(blg)) - { - return 1; - } - fd = open(blg, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); + fd = openat(this->dir, LOG_FILE, O_WRONLY | O_CREAT, PERM); if (fd == -1) { - DBG1("opening bootlog '%s' for %s failed, using stdout", blg, name); + DBG1("opening bootlog failed, using stdout"); return 1; } return fd; } /** + * load memory configuration from file + */ +int loadmem(private_guest_t *this) +{ + FILE *file; + int mem = 0; + + file = fdopen(openat(this->dir, MEMORY_FILE, O_RDONLY, PERM), "r"); + if (file) + { + if (fscanf(file, "%d", &mem) <= 0) + { + mem = 0; + } + fclose(file); + } + return mem; +} + +/** + * save memory configuration to file + */ +bool savemem(private_guest_t *this, int mem) +{ + FILE *file; + bool retval = FALSE; + + file = fdopen(openat(this->dir, MEMORY_FILE, O_RDWR | O_CREAT | O_TRUNC, + PERM), "w"); + if (file) + { + if (fprintf(file, "%d", mem) > 0) + { + retval = TRUE; + } + fclose(file); + } + return retval; +} + +/** * Implementation of guest_t.destroy. */ static void destroy(private_guest_t *this) { stop(this); - umount_unionfs(this->name); + umount_unionfs(this); + if (this->bootlog > 1) + { + close(this->bootlog); + } + if (this->dir > 0) + { + close(this->dir); + } + free(this->dirname); free(this->name); - free(this->master); free(this); } /** - * create the guest instance, including required dirs and mounts + * generic guest constructor */ -guest_t *guest_create(char *name, char *master, int mem) +static private_guest_t *guest_create_generic(char *parent, char *name, + bool create) { + char cwd[PATH_MAX]; private_guest_t *this = malloc_thing(private_guest_t); this->public.get_name = (void*)get_name; @@ -365,22 +395,130 @@ guest_t *guest_create(char *name, char *master, int mem) this->public.sigchild = (void(*)(guest_t*))sigchild; this->public.destroy = (void*)destroy; - if (!makedir(HOST_DIR, name) || !makedir(MOUNT_DIR, name) || - !makedir(RUN_DIR, name) || !mount_unionfs(name, master)) + if (*parent == '/' || getcwd(cwd, sizeof(cwd)) == NULL) + { + asprintf(&this->dirname, "%s/%s", parent, name); + } + else + { + asprintf(&this->dirname, "%s/%s/%s", cwd, parent, name); + } + if (create) + { + mkdir(this->dirname, PERME); + } + this->dir = open(this->dirname, O_DIRECTORY, PERME); + if (this->dir < 0) { + DBG1("opening guest directory '%s' failed: %m", this->dirname); + free(this->dirname); free(this); return NULL; } - this->name = strdup(name); - this->master = strdup(master); - this->mem = mem; this->pid = 0; this->state = GUEST_STOPPED; - this->bootlog = open_bootlog(name); this->mconsole = NULL; this->ifaces = linked_list_create(); + this->mem = 0; + this->bootlog = open_bootlog(this); + this->name = strdup(name); + this->mounted = FALSE; + + return this; +} + +/** + * create a symlink to old called new in our working dir + */ +static bool make_symlink(private_guest_t *this, char *old, char *new) +{ + char cwd[PATH_MAX]; + char buf[PATH_MAX]; + + if (*old == '/' || getcwd(cwd, sizeof(cwd)) == NULL) + { + snprintf(buf, sizeof(buf), "%s", old); + } + else + { + snprintf(buf, sizeof(buf), "%s/%s", cwd, old); + } + return symlinkat(buf, this->dir, new) == 0; +} + + +/** + * create the guest instance, including required dirs and mounts + */ +guest_t *guest_create(char *parent, char *name, char *kernel, + char *master, int mem) +{ + private_guest_t *this = guest_create_generic(parent, name, TRUE); + + if (this == NULL) + { + return NULL; + } + + if (!make_symlink(this, master, MASTER_DIR) || + !make_symlink(this, kernel, KERNEL_FILE)) + { + DBG1("creating master/kernel symlink failed: %m"); + destroy(this); + return NULL; + } + + if (mkdirat(this->dir, UNION_DIR, PERME) != 0 || + mkdirat(this->dir, DIFF_DIR, PERME) != 0) + { + DBG1("unable to create directories for '%s': %m", name); + destroy(this); + return NULL; + } + + this->mem = mem; + if (!savemem(this, mem)) + { + destroy(this); + return NULL; + } + + if (!mount_unionfs(this)) + { + destroy(this); + return NULL; + } return &this->public; } +/** + * load an already created guest + */ +guest_t *guest_load(char *parent, char *name) +{ + private_guest_t *this = guest_create_generic(parent, name, FALSE); + + if (this == NULL) + { + return NULL; + } + + this->mem = loadmem(this); + if (this->mem == 0) + { + DBG1("unable to open memory configuration file: %m", name); + destroy(this); + return NULL; + } + + if (!mount_unionfs(this)) + { + destroy(this); + return NULL; + } + + return &this->public; +} + diff --git a/src/dumm/guest.h b/src/dumm/guest.h index 48cfbf240..d9845e8a8 100644 --- a/src/dumm/guest.h +++ b/src/dumm/guest.h @@ -21,6 +21,14 @@ #include "iface.h" +#define MASTER_DIR "master" +#define DIFF_DIR "diff" +#define UNION_DIR "union" +#define MEMORY_FILE "mem" +#define KERNEL_FILE "linux" +#define LOG_FILE "boot.log" +#define NOTIFY_FILE "notify" + typedef enum guest_state_t guest_state_t; /** @@ -115,11 +123,22 @@ struct guest_t { /** * @brief Create a new, unstarted guest. * - * @param name name of the guest + * @param parent parent directory to create the guest in + * @param name name of the guest to create + * @param kernel kernel this guest uses * @param master read-only master filesystem for guest * @param mem amount of memory to give the guest */ -guest_t *guest_create(char *name, char *master, int mem); +guest_t *guest_create(char *parent, char *name, char *kernel, + char *master, int mem); + +/** + * @brief Load a guest created with guest_create(). + * + * @param parent parent directory to look for a guest + * @param name name of the guest directory + */ +guest_t *guest_load(char *parent, char *name); #endif /* GUEST_H */ diff --git a/src/dumm/main.c b/src/dumm/main.c index 8d4c3e688..bd764017a 100644 --- a/src/dumm/main.c +++ b/src/dumm/main.c @@ -292,6 +292,16 @@ static void guest(char *name) } } + +/** + * create an bridge + */ +static void create_bridge(char *name) +{ + dumm->create_bridge(dumm, name); + +} + /** * create an UML guest */ @@ -299,11 +309,13 @@ static void create_guest(char *line) { enum { NAME = 0, + KERNEL, MASTER, MEMORY, }; char *const opts[] = { [NAME] = "name", + [KERNEL] = "kernel", [MASTER] = "master", [MEMORY] = "memory", NULL @@ -311,7 +323,8 @@ static void create_guest(char *line) char *value; char *name = NULL; char *master = NULL; - int mem = 0; + char *kernel = NULL; + int mem = 128; while (TRUE) { @@ -320,6 +333,9 @@ static void create_guest(char *line) case NAME: name = value; continue; + case KERNEL: + kernel = value; + continue; case MASTER: master = value; continue; @@ -334,21 +350,17 @@ static void create_guest(char *line) } break; } - if (name == NULL) + if (name == NULL || master == NULL || kernel == NULL) { - printf("option 'name' is required.\n"); + printf("too few arguments!\n"); help(); return; } - if (master == NULL) - { - master = "master"; - } if (mem == 0) { mem = 128; } - if (dumm->create_guest(dumm, name, master, mem)) + if (dumm->create_guest(dumm, name, kernel, master, mem)) { printf("guest '%s' created\n", name); guest(name); @@ -406,6 +418,7 @@ int main(int argc, char *argv[]) { char *line = NULL; struct sigaction action; + char *dir = "."; while (TRUE) { @@ -420,11 +433,7 @@ int main(int argc, char *argv[]) case -1: break; case 'd': - if (chdir(optarg)) - { - printf("changing to directory '%s' failed.\n", optarg); - return 1; - } + dir = optarg; continue; case 'h': usage(); @@ -436,7 +445,7 @@ int main(int argc, char *argv[]) break; } - dumm = dumm_create(); + dumm = dumm_create(dir); memset(&action, 0, sizeof(action)); action.sa_sigaction = signal_action; @@ -456,6 +465,7 @@ int main(int argc, char *argv[]) QUIT = 0, HELP, CREATE, + BRIDGE, LIST, GUEST, }; @@ -463,6 +473,7 @@ int main(int argc, char *argv[]) [QUIT] = "quit", [HELP] = "help", [CREATE] = "create", + [BRIDGE] = "bridge", [LIST] = "list", [GUEST] = "guest", NULL @@ -498,6 +509,9 @@ int main(int argc, char *argv[]) case CREATE: create_guest(pos); continue; + case BRIDGE: + create_bridge(pos); + continue; case LIST: list(); continue; |