summaryrefslogtreecommitdiff
path: root/src/dumm/guest.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dumm/guest.c')
-rw-r--r--src/dumm/guest.c174
1 files changed, 146 insertions, 28 deletions
diff --git a/src/dumm/guest.c b/src/dumm/guest.c
index 4b2652688..aed2a3e18 100644
--- a/src/dumm/guest.c
+++ b/src/dumm/guest.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2008 Tobias Brunner
* Copyright (C) 2007 Martin Willi
* Hochschule fuer Technik Rapperswil
*
@@ -25,6 +26,7 @@
#include <signal.h>
#include <dirent.h>
#include <termios.h>
+#include <stdarg.h>
#include <debug.h>
#include <utils/linked_list.h>
@@ -40,7 +42,7 @@
#define MASTER_DIR "master"
#define DIFF_DIR "diff"
#define UNION_DIR "union"
-#define MEMORY_FILE "mem"
+#define ARGS_FILE "args"
#define PID_FILE "pid"
#define KERNEL_FILE "linux"
#define LOG_FILE "boot.log"
@@ -58,8 +60,8 @@ struct private_guest_t {
int dir;
/** directory name of guest */
char *dirname;
- /** amount of memory for guest, in MB */
- int mem;
+ /** additional args to pass to guest */
+ char *args;
/** pid of guest child process */
int pid;
/** state of guest */
@@ -114,7 +116,7 @@ static iface_t* create_iface(private_guest_t *this, char *name)
}
enumerator->destroy(enumerator);
- iface = iface_create(this->name, name, this->mconsole);
+ iface = iface_create(name, &this->public, this->mconsole);
if (iface)
{
this->ifaces->insert_last(this->ifaces, iface);
@@ -212,6 +214,7 @@ static void stop(private_guest_t *this, idle_function_t idle)
}
}
unlinkat(this->dir, PID_FILE, 0);
+ this->pid = 0;
}
}
@@ -255,15 +258,19 @@ static bool start(private_guest_t *this, invoke_function_t invoke, void* data,
notify = write_arg(&pos, &left, "%s/%s", this->dirname, NOTIFY_FILE);
+ args[i++] = write_arg(&pos, &left, "nice");
args[i++] = write_arg(&pos, &left, "%s/%s", this->dirname, KERNEL_FILE);
args[i++] = write_arg(&pos, &left, "root=/dev/root");
args[i++] = write_arg(&pos, &left, "rootfstype=hostfs");
args[i++] = write_arg(&pos, &left, "rootflags=%s/%s", this->dirname, UNION_DIR);
args[i++] = write_arg(&pos, &left, "uml_dir=%s", this->dirname);
args[i++] = write_arg(&pos, &left, "umid=%s", this->name);
- args[i++] = write_arg(&pos, &left, "mem=%dM", this->mem);
args[i++] = write_arg(&pos, &left, "mconsole=notify:%s", notify);
args[i++] = write_arg(&pos, &left, "con=null");
+ if (this->args)
+ {
+ args[i++] = this->args;
+ }
this->pid = invoke(data, &this->public, args, i);
if (!this->pid)
@@ -307,7 +314,7 @@ static bool load_template(private_guest_t *this, char *path)
}
if (access(dir, F_OK) != 0)
{
- if (mkdir(dir, PERME) != 0)
+ if (!mkdir_p(dir, PERME))
{
DBG1("creating overlay for guest '%s' failed: %m", this->name);
return FALSE;
@@ -325,6 +332,119 @@ static bool load_template(private_guest_t *this, char *path)
}
/**
+ * Variadic version of the exec function
+ */
+static int vexec(private_guest_t *this, void(*cb)(void*,char*,size_t), void *data,
+ char *cmd, va_list args)
+{
+ char buf[1024];
+ size_t len;
+
+ if (this->mconsole)
+ {
+ len = vsnprintf(buf, sizeof(buf), cmd, args);
+
+ if (len > 0 && len < sizeof(buf))
+ {
+ return this->mconsole->exec(this->mconsole, cb, data, buf);
+ }
+ }
+ return -1;
+}
+
+/**
+ * Implementation of guest_t.exec
+ */
+static int exec(private_guest_t *this, void(*cb)(void*,char*,size_t), void *data,
+ char *cmd, ...)
+{
+ int res;
+ va_list args;
+ va_start(args, cmd);
+ res = vexec(this, cb, data, cmd, args);
+ va_end(args);
+ return res;
+}
+
+typedef struct {
+ chunk_t buf;
+ void (*cb)(void*,char*);
+ void *data;
+} exec_str_t;
+
+/**
+ * callback that combines chunks to a string. if a callback is given, the string
+ * is split at newlines and the callback is called for each line.
+ */
+static void exec_str_cb(exec_str_t *data, char *buf, size_t len)
+{
+ if (!data->buf.ptr)
+ {
+ data->buf = chunk_alloc(len + 1);
+ memcpy(data->buf.ptr, buf, len);
+ data->buf.ptr[len] = '\0';
+ }
+ else
+ {
+ size_t newlen = strlen(data->buf.ptr) + len + 1;
+ if (newlen > data->buf.len)
+ {
+ data->buf.ptr = realloc(data->buf.ptr, newlen);
+ data->buf.len = newlen;
+ }
+ strncat(data->buf.ptr, buf, len);
+ }
+
+ if (data->cb)
+ {
+ char *nl;
+ while ((nl = strchr(data->buf.ptr, '\n')) != NULL)
+ {
+ *nl++ = '\0';
+ data->cb(data->data, data->buf.ptr);
+ memmove(data->buf.ptr, nl, strlen(nl) + 1);
+ }
+ }
+}
+
+/**
+ * Implementation of guest_t.exec_str
+ */
+static int exec_str(private_guest_t *this, void(*cb)(void*,char*), bool lines,
+ void *data, char *cmd, ...)
+{
+ int res;
+ va_list args;
+ va_start(args, cmd);
+ if (cb)
+ {
+ exec_str_t exec = { chunk_empty, NULL, NULL };
+ if (lines)
+ {
+ exec.cb = cb;
+ exec.data = data;
+ }
+ res = vexec(this, (void(*)(void*,char*,size_t))exec_str_cb, &exec, cmd, args);
+ if (exec.buf.ptr)
+ {
+ if (!lines || strlen(exec.buf.ptr) > 0)
+ {
+ /* return the complete string or the remaining stuff in the
+ * buffer (i.e. when there was no newline at the end) */
+ cb(data, exec.buf.ptr);
+ }
+ chunk_free(&exec.buf);
+ }
+ }
+ else
+ {
+ res = vexec(this, NULL, NULL, cmd, args);
+ }
+ va_end(args);
+ return res;
+}
+
+/**
* Implementation of guest_t.sigchild.
*/
static void sigchild(private_guest_t *this)
@@ -373,38 +493,38 @@ static bool mount_unionfs(private_guest_t *this)
}
/**
- * load memory configuration from file
+ * load args configuration from file
*/
-int loadmem(private_guest_t *this)
+char *loadargs(private_guest_t *this)
{
FILE *file;
- int mem = 0;
+ char buf[512], *args = NULL;
- file = fdopen(openat(this->dir, MEMORY_FILE, O_RDONLY, PERM), "r");
+ file = fdopen(openat(this->dir, ARGS_FILE, O_RDONLY, PERM), "r");
if (file)
{
- if (fscanf(file, "%d", &mem) <= 0)
+ if (fgets(buf, sizeof(buf), file))
{
- mem = 0;
+ args = strdup(buf);
}
fclose(file);
}
- return mem;
+ return args;
}
/**
- * save memory configuration to file
+ * save args configuration to file
*/
-bool savemem(private_guest_t *this, int mem)
+bool saveargs(private_guest_t *this, char *args)
{
FILE *file;
bool retval = FALSE;
- file = fdopen(openat(this->dir, MEMORY_FILE, O_RDWR | O_CREAT | O_TRUNC,
+ file = fdopen(openat(this->dir, ARGS_FILE, O_RDWR | O_CREAT | O_TRUNC,
PERM), "w");
if (file)
{
- if (fprintf(file, "%d", mem) > 0)
+ if (fprintf(file, "%s", args) > 0)
{
retval = TRUE;
}
@@ -424,7 +544,9 @@ static void destroy(private_guest_t *this)
{
close(this->dir);
}
+ this->ifaces->destroy(this->ifaces);
free(this->dirname);
+ free(this->args);
free(this->name);
free(this);
}
@@ -447,6 +569,8 @@ static private_guest_t *guest_create_generic(char *parent, char *name,
this->public.start = (void*)start;
this->public.stop = (void*)stop;
this->public.load_template = (bool(*)(guest_t*, char *path))load_template;
+ this->public.exec = (int(*)(guest_t*, void(*cb)(void*,char*,size_t),void*,char*,...))exec;
+ this->public.exec_str = (int(*)(guest_t*, void(*cb)(void*,char*),bool,void*,char*,...))exec_str;
this->public.sigchild = (void(*)(guest_t*))sigchild;
this->public.destroy = (void*)destroy;
@@ -474,7 +598,7 @@ static private_guest_t *guest_create_generic(char *parent, char *name,
this->state = GUEST_STOPPED;
this->mconsole = NULL;
this->ifaces = linked_list_create();
- this->mem = 0;
+ this->args = NULL;
this->name = strdup(name);
this->cowfs = NULL;
@@ -505,7 +629,7 @@ static bool make_symlink(private_guest_t *this, char *old, char *new)
* create the guest instance, including required dirs and mounts
*/
guest_t *guest_create(char *parent, char *name, char *kernel,
- char *master, int mem)
+ char *master, char *args)
{
private_guest_t *this = guest_create_generic(parent, name, TRUE);
@@ -530,8 +654,8 @@ guest_t *guest_create(char *parent, char *name, char *kernel,
return NULL;
}
- this->mem = mem;
- if (!savemem(this, mem))
+ this->args = args;
+ if (args && !saveargs(this, args))
{
destroy(this);
return NULL;
@@ -558,13 +682,7 @@ guest_t *guest_load(char *parent, char *name)
return NULL;
}
- this->mem = loadmem(this);
- if (this->mem == 0)
- {
- DBG1("unable to open memory configuration file: %m", name);
- destroy(this);
- return NULL;
- }
+ this->args = loadargs(this);
if (!mount_unionfs(this))
{