diff options
author | Martin Willi <martin@strongswan.org> | 2008-07-08 14:58:20 +0000 |
---|---|---|
committer | Martin Willi <martin@strongswan.org> | 2008-07-08 14:58:20 +0000 |
commit | bf44108019e4a9c04057871184db5eb54af352a9 (patch) | |
tree | c6fab24e56bb9a04351e63948e660a94cf81de6c /src/dumm | |
parent | 02a608363393df08a3153ac779e08ab903ce27c4 (diff) | |
download | strongswan-bf44108019e4a9c04057871184db5eb54af352a9.tar.bz2 strongswan-bf44108019e4a9c04057871184db5eb54af352a9.tar.xz |
uml "exec" writes stdout/stderr back to mconsole
guest->exec() accepts a callback for output
sligtly refactored mconsole.c
Diffstat (limited to 'src/dumm')
-rw-r--r-- | src/dumm/guest.c | 11 | ||||
-rw-r--r-- | src/dumm/guest.h | 7 | ||||
-rw-r--r-- | src/dumm/iface.c | 14 | ||||
-rw-r--r-- | src/dumm/irdumm.c | 8 | ||||
-rw-r--r-- | src/dumm/mconsole.c | 94 | ||||
-rw-r--r-- | src/dumm/mconsole.h | 8 | ||||
-rw-r--r-- | src/dumm/patches/mconsole-exec-2.6.26.patch | 174 |
7 files changed, 230 insertions, 86 deletions
diff --git a/src/dumm/guest.c b/src/dumm/guest.c index 6aad15058..c4cc7f1fe 100644 --- a/src/dumm/guest.c +++ b/src/dumm/guest.c @@ -328,9 +328,10 @@ static bool load_template(private_guest_t *this, char *path) /** * Implementation of gues_t.exec */ -static int exec(private_guest_t *this, char *cmd, ...) +static int exec(private_guest_t *this, void(*cb)(void*,char*), void *data, + char *cmd, ...) { - char buf[512]; + char buf[1024]; size_t len; va_list args; @@ -342,10 +343,10 @@ static int exec(private_guest_t *this, char *cmd, ...) if (len > 0 && len < sizeof(buf)) { - return this->mconsole->exec(this->mconsole, buf); + return this->mconsole->exec(this->mconsole, cb, data, buf); } } - return FALSE; + return -1; } /** @@ -472,7 +473,7 @@ 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 = (bool(*)(guest_t*, char *cmd, ...))exec; + this->public.exec = (int(*)(guest_t*, void(*cb)(void*,char*,size_t), void *data, char *cmd, ...))exec; this->public.sigchild = (void(*)(guest_t*))sigchild; this->public.destroy = (void*)destroy; diff --git a/src/dumm/guest.h b/src/dumm/guest.h index c9406e11d..1109622f9 100644 --- a/src/dumm/guest.h +++ b/src/dumm/guest.h @@ -144,11 +144,14 @@ struct guest_t { /** * Execute a command in the guest. * + * @param cb callback to call for each read block + * @param data data to pass to callback * @param cmd command to execute * @param ... printf style argument list for cmd - * @return TRUE if command executed + * @return return value */ - bool (*exec)(guest_t *this, char *cmd, ...); + int (*exec)(guest_t *this, void(*cb)(void*,char*,size_t), void *data, + char *cmd, ...); /** * @brief Called whenever a SIGCHILD for the guests PID is received. diff --git a/src/dumm/iface.c b/src/dumm/iface.c index fdfe50d3b..20a71f4c0 100644 --- a/src/dumm/iface.c +++ b/src/dumm/iface.c @@ -105,8 +105,8 @@ static char* get_hostif(private_iface_t *this) */ static bool add_address(private_iface_t *this, host_t *addr) { - if (this->guest->exec(this->guest, "ip addr add %H dev %s", - addr, this->guestif)) + if (this->guest->exec(this->guest, NULL, NULL, "ip addr add %H dev %s", + addr, this->guestif) == 0) { this->addresses->insert_last(this->addresses, addr); return TRUE; @@ -137,8 +137,8 @@ static bool delete_address(private_iface_t *this, host_t *addr) { if (current->ip_equals(current, addr)) { - if (this->guest->exec(this->guest, "ip addr del %H dev %s", - current, this->guestif)) + if (this->guest->exec(this->guest, NULL, NULL, + "ip addr del %H dev %s", current, this->guestif) == 0) { this->addresses->remove_at(this->addresses, enumerator); success = TRUE; @@ -157,11 +157,13 @@ static void set_bridge(private_iface_t *this, bridge_t *bridge) { if (this->bridge == NULL && bridge) { - this->guest->exec(this->guest, "ip link set %s up", this->guestif); + this->guest->exec(this->guest, NULL, NULL, + "ip link set %s up", this->guestif); } else if (this->bridge && bridge == NULL) { - this->guest->exec(this->guest, "ip link set %s down", this->guestif); + this->guest->exec(this->guest, NULL, NULL, + "ip link set %s down", this->guestif); } this->bridge = bridge; } diff --git a/src/dumm/irdumm.c b/src/dumm/irdumm.c index e8cc12d12..53443bf27 100644 --- a/src/dumm/irdumm.c +++ b/src/dumm/irdumm.c @@ -123,7 +123,6 @@ static VALUE guest_each(int argc, VALUE *argv, VALUE class) static VALUE guest_new(VALUE class, VALUE name, VALUE kernel, VALUE master, VALUE mem) - { guest_t *guest; @@ -170,12 +169,17 @@ static VALUE guest_stop(VALUE self) return self; } +static void cb(void *data, char *buf, size_t len) +{ + printf("%.*s", len, buf); +} + static VALUE guest_exec(VALUE self, VALUE cmd) { guest_t *guest; Data_Get_Struct(self, guest_t, guest); - if (!guest->exec(guest, StringValuePtr(cmd))) + if (guest->exec(guest, cb, NULL, "%s", StringValuePtr(cmd)) != 0) { rb_raise(rb_eRuntimeError, "executing command failed"); } diff --git a/src/dumm/mconsole.c b/src/dumm/mconsole.c index 63e15c75a..b44a8e5e2 100644 --- a/src/dumm/mconsole.c +++ b/src/dumm/mconsole.c @@ -88,21 +88,21 @@ struct mconsole_notify { /** * send a request to UML using mconsole */ -static int request(private_mconsole_t *this, char *command, - char buf[], size_t *size) +static int request(private_mconsole_t *this, void(*cb)(void*,char*,size_t), + void *data, char *command, ...) { mconsole_request request; mconsole_reply reply; - int len, total = 0, flags = 0; + int len, flags = 0; + va_list args; memset(&request, 0, sizeof(request)); request.magic = MCONSOLE_MAGIC; request.version = MCONSOLE_VERSION; - request.len = min(strlen(command), sizeof(reply.data) - 1); - strncpy(request.data, command, request.len); - *buf = '\0'; - (*size)--; - + va_start(args, command); + request.len = vsnprintf(request.data, sizeof(request.data), command, args); + va_end(args); + if (this->idle) { flags = MSG_DONTWAIT; @@ -120,7 +120,7 @@ static int request(private_mconsole_t *this, char *command, if (len < 0) { - snprintf(buf, *size, "sending mconsole command to UML failed: %m"); + DBG1("sending mconsole command to UML failed: %m"); return -1; } do @@ -136,44 +136,50 @@ static int request(private_mconsole_t *this, char *command, } if (len < 0) { - snprintf(buf, *size, "receiving from mconsole failed: %m"); + DBG1("receiving from mconsole failed: %m"); return -1; } if (len > 0) { - strncat(buf, reply.data, min(reply.len, *size - total)); - total += reply.len; + if (cb) + { + cb(data, reply.data, reply.len); + } + else if (reply.err) + { + DBG1("received mconsole error %d: %*.s", + reply.err, reply.len, reply.data); + break; + } } } while (reply.more); - *size = total; return reply.err; } /** + * ignore error message + */ +static void ignore(void *data, char *buf, size_t len) +{ +} + +/** * Implementation of mconsole_t.add_iface. */ static bool add_iface(private_mconsole_t *this, char *guest, char *host) { - char in[128], out[128]; - int len, tries = 0; + int tries = 0; - len = snprintf(in, sizeof(in), "config %s=tuntap,%s", guest, host); - if (len < 0 || len >= sizeof(in)) + while (tries++ < 5) { - return FALSE; - } - while (tries++ < 10) - { - len = sizeof(in); - if (request(this, in, out, &len) == 0) + if (request(this, ignore, NULL, "config %s=tuntap,%s", guest, host) == 0) { return TRUE; } - usleep(10000 * tries); + usleep(10000 * tries * tries); } - DBG1("adding interface failed: %.*s", len, out); return FALSE; } @@ -181,16 +187,8 @@ static bool add_iface(private_mconsole_t *this, char *guest, char *host) * Implementation of mconsole_t.del_iface. */ static bool del_iface(private_mconsole_t *this, char *guest) -{ - char buf[128]; - int len; - - len = snprintf(buf, sizeof(buf), "remove %s", guest); - if (len < 0 || len >= sizeof(buf)) - { - return FALSE; - } - if (request(this, buf, buf, &len) != 0) +{ + if (request(this, NULL, NULL, "remove %s", guest) != 0) { return FALSE; } @@ -200,22 +198,14 @@ static bool del_iface(private_mconsole_t *this, char *guest) /** * Implementation of mconsole_t.exec */ -static bool exec(private_mconsole_t *this, char *cmd) +static int exec(private_mconsole_t *this, void(*cb)(void*,char*,size_t), + void *data, char *cmd) { - char buf[512]; - int len; - - len = snprintf(buf, sizeof(buf), "exec %s", cmd); - if (len < 0 || len >= sizeof(buf)) + if (request(this, cb, data, "exec %s", cmd) != 0) { return -1; } - if (request(this, buf, buf, &len) != 0) - { - DBG1("exec failed: %.*s", len, buf); - return FALSE; - } - return TRUE; + return 0; } /** @@ -223,20 +213,18 @@ static bool exec(private_mconsole_t *this, char *cmd) */ static bool wait_bootup(private_mconsole_t *this) { - char buf[128]; - int len, res; + int res; while (TRUE) { - len = sizeof(buf); - res = request(this, "config eth9=mcast", buf, &len); + res = request(this, ignore, NULL, "config eth9=mcast"); if (res < 0) { return FALSE; } if (res == 0) { - while (request(this, "remove eth9", buf, &len) != 0) + while (request(this, ignore, NULL, "remove eth9") != 0) { usleep(50000); } @@ -359,7 +347,7 @@ mconsole_t *mconsole_create(char *notify, void(*idle)(void)) this->public.add_iface = (bool(*)(mconsole_t*, char *guest, char *host))add_iface; this->public.del_iface = (bool(*)(mconsole_t*, char *guest))del_iface; - this->public.exec = (bool(*)(mconsole_t*, char *cmd))exec; + this->public.exec = (int(*)(mconsole_t*, void(*cb)(void*,char*,size_t), void *data, char *cmd))exec; this->public.destroy = (void*)destroy; this->idle = idle; diff --git a/src/dumm/mconsole.h b/src/dumm/mconsole.h index a26e094e8..329c40c06 100644 --- a/src/dumm/mconsole.h +++ b/src/dumm/mconsole.h @@ -44,8 +44,14 @@ struct mconsole_t { /** * Execute a command in the UML host. + * + * @param cb callback function to invoke for each line + * @param data data to pass to callback + * @param cmd command to invoke + * @return return value of command */ - bool (*exec)(mconsole_t *this, char *cmd); + int (*exec)(mconsole_t *this, void(*cb)(void*,char*,size_t), void *data, + char *cmd); /** * @brief Destroy the mconsole instance diff --git a/src/dumm/patches/mconsole-exec-2.6.26.patch b/src/dumm/patches/mconsole-exec-2.6.26.patch index 0ab47aaf1..6f9dcbf99 100644 --- a/src/dumm/patches/mconsole-exec-2.6.26.patch +++ b/src/dumm/patches/mconsole-exec-2.6.26.patch @@ -1,5 +1,5 @@ ---- a/arch/um/drivers/mconsole_kern.c 2008-04-17 04:49:44.000000000 +0200 -+++ b/arch/um/drivers/mconsole_kern.c 2008-07-07 13:55:48.000000000 +0200 +--- linux-2.6.26rc5-orig/arch/um/drivers/mconsole_kern.c 2008-04-17 04:49:44.000000000 +0200 ++++ uml-2.6.26rc5/arch/um/drivers/mconsole_kern.c 2008-07-08 16:00:07.000000000 +0200 @@ -4,6 +4,7 @@ * Licensed under the GPL */ @@ -8,41 +8,61 @@ #include <linux/console.h> #include <linux/ctype.h> #include <linux/interrupt.h> -@@ -199,6 +200,24 @@ +@@ -18,6 +19,7 @@ + #include <linux/utsname.h> + #include <linux/workqueue.h> + #include <linux/mutex.h> ++#include <linux/file.h> + #include <asm/uaccess.h> + + #include "init.h" +@@ -199,6 +201,36 @@ } #endif +void mconsole_exec(struct mc_request *req) +{ -+ int res; ++ int res, len; ++ struct file *out; ++ char buf[MCONSOLE_MAX_DATA]; + + char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; + char *argv[] = { "/bin/sh", "-c", req->request.data + strlen("exec "), NULL }; -+ res = call_usermodehelper("/bin/sh", argv, envp, 0); -+ ++ res = call_usermodehelper_pipe("/bin/sh", argv, envp, NULL, &out); ++ + if (res < 0) { -+ char buf[60]; -+ snprintf(buf, 60, "call_usermodehelper failed in mconsole_exec with error code: %d", -res); -+ mconsole_reply(req, buf, 1, 0); ++ mconsole_reply(req, "call_usermodehelper_pipe failed", 1, 0); + return; + } -+ -+ mconsole_reply(req, "The command has been started successfully.", 0, 0); ++ ++ for (;;) { ++ len = out->f_op->read(out, buf, sizeof(buf), 0); ++ if (len < 0) { ++ mconsole_reply(req, "reading output failed", 1, 0); ++ break; ++ } ++ if (len == 0) { ++ mconsole_reply_len(req, buf, len, 0, 0); ++ break; ++ } ++ mconsole_reply_len(req, buf, len, 0, 1); ++ } ++ fput(out); +} + void mconsole_proc(struct mc_request *req) { char path[64]; -@@ -270,6 +289,7 @@ +@@ -270,6 +302,7 @@ stop - pause the UML; it will do nothing until it receives a 'go' \n\ go - continue the UML after a 'stop' \n\ log <string> - make UML enter <string> into the kernel log\n\ -+ exec <string> - pass <string> to /bin/sh -c in guest\n\ ++ exec <string> - pass <string> to /bin/sh -c synchronously\n\ proc <file> - returns the contents of the UML's /proc/<file>\n\ stack <pid> - returns the stack of the specified pid\n\ " ---- a/arch/um/drivers/mconsole_user.c 2008-05-21 18:34:47.000000000 +0200 -+++ b/arch/um/drivers/mconsole_user.c 2008-07-07 13:47:13.000000000 +0200 +--- linux-2.6.26rc5-orig/arch/um/drivers/mconsole_user.c 2008-05-21 18:34:47.000000000 +0200 ++++ uml-2.6.26rc5/arch/um/drivers/mconsole_user.c 2008-07-07 13:47:13.000000000 +0200 @@ -32,6 +32,7 @@ { "stop", mconsole_stop, MCONSOLE_PROC }, { "go", mconsole_go, MCONSOLE_INTR }, @@ -51,8 +71,8 @@ { "proc", mconsole_proc, MCONSOLE_PROC }, { "stack", mconsole_stack, MCONSOLE_INTR }, }; ---- a/arch/um/include/mconsole.h 2008-04-17 04:49:44.000000000 +0200 -+++ b/arch/um/include/mconsole.h 2008-07-07 13:46:56.000000000 +0200 +--- linux-2.6.26rc5-orig/arch/um/include/mconsole.h 2008-04-17 04:49:44.000000000 +0200 ++++ uml-2.6.26rc5/arch/um/include/mconsole.h 2008-07-07 13:46:56.000000000 +0200 @@ -85,6 +85,7 @@ extern void mconsole_stop(struct mc_request *req); extern void mconsole_go(struct mc_request *req); @@ -61,3 +81,123 @@ extern void mconsole_proc(struct mc_request *req); extern void mconsole_stack(struct mc_request *req); +--- linux-2.6.26rc5-orig/kernel/kmod.c 2008-05-21 18:34:56.000000000 +0200 ++++ uml-2.6.26rc5/kernel/kmod.c 2008-07-08 13:50:37.000000000 +0200 +@@ -125,6 +125,7 @@ + enum umh_wait wait; + int retval; + struct file *stdin; ++ struct file *stdout; + void (*cleanup)(char **argv, char **envp); + }; + +@@ -160,8 +161,26 @@ + FD_SET(0, fdt->open_fds); + FD_CLR(0, fdt->close_on_exec); + spin_unlock(&f->file_lock); +- +- /* and disallow core files too */ ++ } ++ if (sub_info->stdout) { ++ struct files_struct *f = current->files; ++ struct fdtable *fdt; ++ ++ sys_close(1); ++ sys_close(2); ++ get_file(sub_info->stdout); ++ fd_install(1, sub_info->stdout); ++ fd_install(2, sub_info->stdout); ++ spin_lock(&f->file_lock); ++ fdt = files_fdtable(f); ++ FD_SET(1, fdt->open_fds); ++ FD_CLR(1, fdt->close_on_exec); ++ FD_SET(2, fdt->open_fds); ++ FD_CLR(2, fdt->close_on_exec); ++ spin_unlock(&f->file_lock); ++ } ++ if (sub_info->stdin || sub_info->stdout) { ++ /* disallow core files */ + current->signal->rlim[RLIMIT_CORE] = (struct rlimit){0, 0}; + } + +@@ -433,6 +452,29 @@ + } + EXPORT_SYMBOL(call_usermodehelper_stdinpipe); + ++int call_usermodehelper_stdoutpipe(struct subprocess_info *sub_info, ++ struct file **filp) ++{ ++ struct file *f; ++ ++ f = create_write_pipe(); ++ if (IS_ERR(f)) ++ return PTR_ERR(f); ++ sub_info->stdout = f; ++ ++ f = create_read_pipe(f); ++ if (IS_ERR(f)) { ++ free_write_pipe(sub_info->stdout); ++ sub_info->stdout = NULL; ++ return PTR_ERR(f); ++ } ++ *filp = f; ++ ++ return 0; ++} ++EXPORT_SYMBOL(call_usermodehelper_stdoutpipe); ++ ++ + /** + * call_usermodehelper_exec - start a usermode application + * @sub_info: information about the subprocessa +@@ -489,7 +531,7 @@ + * lower-level call_usermodehelper_* functions. + */ + int call_usermodehelper_pipe(char *path, char **argv, char **envp, +- struct file **filp) ++ struct file **in, struct file **out) + { + struct subprocess_info *sub_info; + int ret; +@@ -498,9 +540,17 @@ + if (sub_info == NULL) + return -ENOMEM; + +- ret = call_usermodehelper_stdinpipe(sub_info, filp); +- if (ret < 0) +- goto out; ++ if (in) { ++ ret = call_usermodehelper_stdinpipe(sub_info, in); ++ if (ret < 0) ++ goto out; ++ } ++ ++ if (out) { ++ ret = call_usermodehelper_stdoutpipe(sub_info, out); ++ if (ret < 0) ++ goto out; ++ } + + return call_usermodehelper_exec(sub_info, UMH_WAIT_EXEC); + +--- linux-2.6.26rc5-orig/include/linux/kmod.h 2008-04-17 04:49:44.000000000 +0200 ++++ uml-2.6.26rc5/include/linux/kmod.h 2008-07-08 10:29:29.000000000 +0200 +@@ -93,6 +93,6 @@ + + struct file; + extern int call_usermodehelper_pipe(char *path, char *argv[], char *envp[], +- struct file **filp); ++ struct file **in, struct file **out); + + #endif /* __LINUX_KMOD_H__ */ +--- linux-2.6.26rc5-orig/fs/exec.c 2008-06-05 14:00:42.000000000 +0200 ++++ uml-2.6.26rc5/fs/exec.c 2008-07-08 10:28:33.000000000 +0200 +@@ -1737,7 +1737,7 @@ + + /* SIGPIPE can happen, but it's just never processed */ + if (call_usermodehelper_pipe(corename+1, helper_argv, NULL, +- &file)) { ++ &file, NULL)) { + printk(KERN_INFO "Core dump to %s pipe failed\n", + corename); + goto fail_unlock; |