ARG_DISBL_SET([charon], [disable the IKEv1/IKEv2 keying daemon charon.])
ARG_ENABL_SET([cmd], [enable the command line IKE client charon-cmd.])
ARG_ENABL_SET([conftest], [enforce Suite B conformance test framework.])
-ARG_ENABL_SET([dumm], [enable the DUMM UML test framework.])
ARG_ENABL_SET([fast], [enable libfast (FastCGI Application Server w/ templates.])
ARG_ENABL_SET([fuzzing], [enable fuzzing scripts (found in directory fuzz).])
ARG_ENABL_SET([libipsec], [enable user space IPsec implementation.])
AC_SUBST(json_LIBS)
fi
-if test x$dumm = xtrue; then
- PKG_CHECK_MODULES(gtk, [gtk+-2.0 vte])
- AC_SUBST(gtk_CFLAGS)
- AC_SUBST(gtk_LIBS)
- AC_CHECK_PROGS(RUBY, ruby)
- PKG_CHECK_MODULES(ruby, [ruby])
- saved_LIBS=$LIBS
- LIBS=$ruby_LIBS
- AC_CHECK_FUNCS(rb_errinfo)
- LIBS=$saved_LIBS
-fi
-
if test x$fast = xtrue; then
AC_CHECK_LIB([neo_utl],[hdf_init],[LIBS="$LIBS"],[AC_MSG_ERROR([ClearSilver library neo_utl not found!])],[])
AC_MSG_CHECKING([for -lneo_cgi and dependencies])
# ---------------
AM_CONDITIONAL(USE_LEAK_DETECTIVE, test x$leak_detective = xtrue)
AM_CONDITIONAL(USE_LOCK_PROFILER, test x$lock_profiler = xtrue)
-AM_CONDITIONAL(USE_DUMM, test x$dumm = xtrue)
AM_CONDITIONAL(USE_FAST, test x$fast = xtrue)
AM_CONDITIONAL(USE_MANAGER, test x$manager = xtrue)
AM_CONDITIONAL(USE_ME, test x$mediation = xtrue)
src/pki/Makefile
src/pki/man/Makefile
src/pool/Makefile
- src/dumm/Makefile
- src/dumm/ext/extconf.rb
src/libfast/Makefile
src/manager/Makefile
src/medsrv/Makefile
;;
all|coverage|sonarcloud)
CONFIG="--enable-all --disable-android-dns --disable-android-log
- --disable-dumm --disable-kernel-pfroute --disable-keychain
+ --disable-kernel-pfroute --disable-keychain
--disable-lock-profiler --disable-padlock --disable-fuzzing
--disable-osx-attr --disable-tkm --disable-uci
--disable-systemd --disable-soup --disable-unwind-backtraces
SUBDIRS += conftest
endif
-if USE_DUMM
- SUBDIRS += dumm
-endif
-
if USE_FAST
SUBDIRS += libfast
endif
+++ /dev/null
-dumm
-irdumm
+++ /dev/null
-EXTRA_DIST = ext/dumm.c ext/README \
- ext/lib/dumm.rb ext/lib/dumm/guest.rb
-
-ipseclib_LTLIBRARIES = libdumm.la
-ipsec_PROGRAMS = dumm irdumm
-
-libdumm_la_SOURCES = dumm.c dumm.h guest.c guest.h iface.c iface.h \
- bridge.c bridge.h mconsole.c mconsole.h cowfs.h cowfs.c
-dumm_SOURCES = main.c
-irdumm_SOURCES = irdumm.c
-
-libdumm_la_LIBADD = -lbridge -lfuse -lutil $(top_builddir)/src/libstrongswan/libstrongswan.la
-dumm_LDADD = libdumm.la ${gtk_LIBS} $(top_builddir)/src/libstrongswan/libstrongswan.la
-irdumm_LDADD = libdumm.la ${ruby_LIBS} $(top_builddir)/src/libstrongswan/libstrongswan.la
-
-AM_CPPFLAGS = \
- -D_FILE_OFFSET_BITS=64 \
- -I$(top_srcdir)/src/libstrongswan
-
-dumm_CFLAGS = ${gtk_CFLAGS}
-irdumm_CFLAGS = ${ruby_CFLAGS}
-
-all-local: ext
-
-clean-local:
- (test -f ext/Makefile && cd ext && $(MAKE) clean && rm Makefile || true)
-
-install-data-local:
- (test -f ext/Makefile && cd ext && $(MAKE) install)
-
-ext: libdumm.la
- (cd ext && $(RUBY) extconf.rb && $(MAKE))
-
-.PHONY: ext
+++ /dev/null
-/*
- * Copyright (C) 2007 Martin Willi
- * HSR 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 <netinet/in.h>
-#include <libbridge.h>
-
-#include <utils/debug.h>
-#include <collections/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;
-};
-
-/**
- * defined in iface.c
- */
-bool iface_control(char *name, bool up);
-
-METHOD(bridge_t, get_name, char*,
- private_bridge_t *this)
-{
- return this->name;
-}
-
-METHOD(bridge_t, create_iface_enumerator, enumerator_t*,
- private_bridge_t *this)
-{
- return this->ifaces->create_enumerator(this->ifaces);
-}
-
-METHOD(bridge_t, disconnect_iface, bool,
- private_bridge_t *this, iface_t *iface)
-{
- enumerator_t *enumerator;
- iface_t *current = NULL;
- bool good = FALSE;
-
- enumerator = this->ifaces->create_enumerator(this->ifaces);
- while (enumerator->enumerate(enumerator, (void**)¤t))
- {
- if (current == iface)
- {
- if (br_del_interface(this->name, iface->get_hostif(iface)) != 0)
- {
- DBG1(DBG_LIB, "removing iface '%s' from bridge '%s' in kernel"
- " failed: %m", iface->get_hostif(iface), this->name);
- }
- else
- {
- iface->set_bridge(iface, NULL);
- this->ifaces->remove_at(this->ifaces, enumerator);
- good = TRUE;
- }
- break;
- }
- }
- if (iface != current)
- {
- DBG1(DBG_LIB, "iface '%s' not found on bridge '%s'",
- iface->get_hostif(iface), this->name);
- }
- enumerator->destroy(enumerator);
- return good;
-}
-
-METHOD(bridge_t, connect_iface, bool,
- private_bridge_t *this, iface_t *iface)
-{
- if (br_add_interface(this->name, iface->get_hostif(iface)) != 0)
- {
- DBG1(DBG_LIB, "adding iface '%s' to bridge '%s' failed: %m",
- iface->get_hostif(iface), this->name);
- return FALSE;
- }
- iface->set_bridge(iface, &this->public);
- this->ifaces->insert_last(this->ifaces, iface);
- return TRUE;
-}
-
-/**
- * instance counter to (de-)initialize libbridge
- */
-static int instances = 0;
-
-METHOD(bridge_t, destroy, void,
- private_bridge_t *this)
-{
- enumerator_t *enumerator;
- iface_t *iface;
-
- enumerator = this->ifaces->create_enumerator(this->ifaces);
- while (enumerator->enumerate(enumerator, (void**)&iface))
- {
- if (br_del_interface(this->name, iface->get_hostif(iface)) != 0)
- {
- DBG1(DBG_LIB, "disconnecting iface '%s' failed: %m",
- iface->get_hostif(iface));
- }
- iface->set_bridge(iface, NULL);
- }
- enumerator->destroy(enumerator);
- this->ifaces->destroy(this->ifaces);
- iface_control(this->name, FALSE);
- if (br_del_bridge(this->name) != 0)
- {
- DBG1(DBG_LIB, "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(DBG_LIB, "libbridge initialization failed: %m");
- return NULL;
- }
- }
-
- INIT(this,
- .public = {
- .get_name = _get_name,
- .create_iface_enumerator = _create_iface_enumerator,
- .disconnect_iface = _disconnect_iface,
- .connect_iface = _connect_iface,
- .destroy = _destroy,
- }
- );
-
- if (br_add_bridge(name) != 0)
- {
- DBG1(DBG_LIB, "creating bridge '%s' failed: %m", name);
- free(this);
- return NULL;
- }
- if (!iface_control(name, TRUE))
- {
- DBG1(DBG_LIB, "bringing bridge '%s' up failed: %m", name);
- }
-
- this->name = strdup(name);
- this->ifaces = linked_list_create();
-
- instances++;
- return &this->public;
-}
+++ /dev/null
-/*
- * Copyright (C) 2007 Martin Willi
- * HSR 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 <collections/enumerator.h>
-
-typedef struct bridge_t bridge_t;
-
-#include "iface.h"
-
-/**
- * Interface in a guest, connected to a tap device on the host.
- */
-struct bridge_t {
-
- /**
- * Get the name of the bridge.
- *
- * @return name of the bridge
- */
- char* (*get_name)(bridge_t *this);
-
- /**
- * Add an interface to a bridge.
- *
- * @param iface interface to add
- * @return TRUE if interface added
- */
- bool (*connect_iface)(bridge_t *this, iface_t *iface);
-
- /**
- * Remove an interface from a bridge.
- *
- * @param iface interface to remove
- * @return TRUE if interface removed
- */
- bool (*disconnect_iface)(bridge_t *this, iface_t *iface);
-
- /**
- * Create an enumerator over all interfaces.
- *
- * @return enumerator over iface_t's
- */
- enumerator_t* (*create_iface_enumerator)(bridge_t *this);
-
- /**
- * Destroy a bridge
- */
- void (*destroy) (bridge_t *this);
-};
-
-/**
- * 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 */
-
+++ /dev/null
-/*
- * Copyright (C) 2009 Tobias Brunner
- * Copyright (C) 2007 Martin Willi
- * HSR Hochschule fuer Technik Rapperswil
- * Copyright (C) 2001-2007 Miklos Szeredi
- *
- * Based on example shipped with FUSE.
- *
- * 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.
- */
-
-
-#define FUSE_USE_VERSION 26
-#define _GNU_SOURCE
-
-#include <fuse.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <errno.h>
-#include <sys/time.h>
-
-#include "cowfs.h"
-
-#include <library.h>
-#include <utils/debug.h>
-#include <threading/thread.h>
-#include <threading/rwlock.h>
-#include <collections/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);
-extern ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
-
-typedef struct private_cowfs_t private_cowfs_t;
-
-struct private_cowfs_t {
- /** public cowfs interface */
- cowfs_t public;
- /** fuse channel to mountpoint */
- struct fuse_chan *chan;
- /** fuse handle */
- struct fuse *fuse;
- /** mountpoint of cowfs FUSE */
- char *mount;
- /** master filesystem path */
- char *master;
- /** host filesystem path */
- char *host;
- /** 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;
- /** 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);
-}
-
-CALLBACK(overlay_equals, bool,
- overlay_t *this, va_list args)
-{
- overlay_t *other;
-
- VA_ARGS_VGET(args, 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, overlay_equals,
- (void**)¤t, &over))
- {
- return FALSE;
- }
- this->overlays->remove(this->overlays, current, NULL);
- overlay_destroy(current);
- return TRUE;
-}
-
-/**
- * get this pointer stored in fuse context
- */
-static private_cowfs_t *get_this()
-{
- return (fuse_get_context())->private_data;
-}
-
-/**
- * make a path relative
- */
-static void rel(const char **path)
-{
- if (**path == '/')
- {
- (*path)++;
- }
- if (**path == '\0')
- {
- *path = ".";
- }
-}
-
-/**
- * get the highest overlay in which path exists
- */
-static int get_rd(const char *path)
-{
- overlay_t *over;
- enumerator_t *enumerator;
- private_cowfs_t *this = get_this();
-
- this->lock->read_lock(this->lock);
- enumerator = this->overlays->create_enumerator(this->overlays);
- while (enumerator->enumerate(enumerator, (void**)&over))
- {
- 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;
- }
- return this->master_fd;
-}
-
-/**
- * get the highest overlay available, to write something
- */
-static int get_wr(const char *path)
-{
- overlay_t *over;
- private_cowfs_t *this = get_this();
- int fd = this->host_fd;
- this->lock->read_lock(this->lock);
- if (this->overlays->get_first(this->overlays, (void**)&over) == SUCCESS)
- {
- fd = over->fd;
- }
- this->lock->unlock(this->lock);
- return fd;
-}
-
-/**
- * create full "path" at "wr" the same way they exist at "rd"
- */
-static bool clone_path(int rd, int wr, const char *path)
-{
- char *pos, *full;
- struct stat st;
- full = strdupa(path);
- pos = full;
-
- while ((pos = strchr(pos, '/')))
- {
- *pos = '\0';
- if (fstatat(wr, full, &st, 0) < 0)
- {
- /* TODO: handle symlinks!? */
- if (fstatat(rd, full, &st, 0) < 0)
- {
- return FALSE;
- }
- if (mkdirat(wr, full, st.st_mode) < 0)
- {
- return FALSE;
- }
- }
- *pos = '/';
- pos++;
- }
- return TRUE;
-}
-
-/**
- * copy a (special) file from a readonly to a read-write overlay
- */
-static int copy(const char *path)
-{
- char *buf[4096];
- int len;
- int rd, wr;
- int from, to;
- struct stat st;
-
- rd = get_rd(path);
- wr = get_wr(path);
-
- if (rd == wr)
- {
- /* already writeable */
- return wr;
- }
- if (fstatat(rd, path, &st, 0) < 0)
- {
- return -1;
- }
- if (!clone_path(rd, wr, path))
- {
- return -1;
- }
- if (mknodat(wr, path, st.st_mode, st.st_rdev) < 0)
- {
- return -1;
- }
- /* copy if no special file */
- if (st.st_size)
- {
- from = openat(rd, path, O_RDONLY, st.st_mode);
- if (from < 0)
- {
- return -1;
- }
- to = openat(wr, path, O_WRONLY , st.st_mode);
- if (to < 0)
- {
- close(from);
- return -1;
- }
- while ((len = read(from, buf, sizeof(buf))) > 0)
- {
- if (write(to, buf, len) < len)
- {
- /* TODO: only on len < 0 ? */
- close(from);
- close(to);
- return -1;
- }
- }
- close(from);
- close(to);
- if (len < 0)
- {
- return -1;
- }
- }
- return wr;
-}
-
-/**
- * FUSE getattr method
- */
-static int cowfs_getattr(const char *path, struct stat *stbuf)
-{
- rel(&path);
-
- if (fstatat(get_rd(path), path, stbuf, AT_SYMLINK_NOFOLLOW) < 0)
- {
- return -errno;
- }
- return 0;
-}
-
-/**
- * FUSE access method
- */
-static int cowfs_access(const char *path, int mask)
-{
- rel(&path);
-
- if (faccessat(get_rd(path), path, mask, 0) < 0)
- {
- return -errno;
- }
- return 0;
-}
-
-/**
- * FUSE readlink method
- */
-static int cowfs_readlink(const char *path, char *buf, size_t size)
-{
- int res;
-
- rel(&path);
-
- res = readlinkat(get_rd(path), path, buf, size - 1);
- if (res < 0)
- {
- return -errno;
- }
- buf[res] = '\0';
- return 0;
-}
-
-/**
- * get a directory stream of two concatenated paths
- */
-static DIR* get_dir(char *dir, const char *subdir)
-{
- char *full;
-
- if (dir == NULL)
- {
- return NULL;
- }
-
- full = alloca(strlen(dir) + strlen(subdir) + 1);
- strcpy(full, dir);
- strcat(full, subdir);
-
- return opendir(full);
-}
-
-/**
- * check if a directory stream contains a directory
- */
-static bool contains_dir(DIR *d, char *dirname)
-{
- struct dirent *ent;
-
- rewinddir(d);
- while ((ent = readdir(d)))
- {
- if (streq(ent->d_name, dirname))
- {
- return TRUE;
- }
- }
- return FALSE;
-}
-
-/**
- * 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))
- {
- return TRUE;
- }
- }
- return FALSE;
-}
-
-/**
- * FUSE readdir method
- */
-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();
- int count;
- DIR **d, **overlays;
- struct stat st;
- struct dirent *ent;
- overlay_t *over;
- enumerator_t *enumerator;
-
- memset(&st, 0, sizeof(st));
-
- 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];
-
- enumerator = this->overlays->create_enumerator(this->overlays);
- while (enumerator->enumerate(enumerator, (void**)&over))
- {
- ADD_DIR(d, over->path, path);
- }
- enumerator->destroy(enumerator);
- this->lock->unlock(this->lock);
-
- ADD_DIR(d, this->host, path);
- ADD_DIR(d, this->master, path);
-
- for (; *d; ++d)
- {
- rewinddir(*d);
- while((ent = readdir(*d)))
- {
- 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(*d);
- }
-
- free(overlays);
- return 0;
-}
-
-/**
- * FUSE mknod method
- */
-static int cowfs_mknod(const char *path, mode_t mode, dev_t rdev)
-{
- int fd;
- rel(&path);
-
- fd = get_wr(path);
- if (!clone_path(get_rd(path), fd, path))
- {
- return -errno;
- }
-
- if (mknodat(fd, path, mode, rdev) < 0)
- {
- return -errno;
- }
- return 0;
-}
-
-/**
- * FUSE mkdir method
- */
-static int cowfs_mkdir(const char *path, mode_t mode)
-{
- int fd;
- rel(&path);
-
- fd = get_wr(path);
- if (!clone_path(get_rd(path), fd, path))
- {
- return -errno;
- }
- if (mkdirat(fd, path, mode) < 0)
- {
- return -errno;
- }
- return 0;
-}
-
-/**
- * FUSE unlink method
- */
-static int cowfs_unlink(const char *path)
-{
- rel(&path);
-
- /* TODO: whiteout master */
- if (unlinkat(get_wr(path), path, 0) < 0)
- {
- return -errno;
- }
- return 0;
-}
-
-/**
- * FUSE rmdir method
- */
-static int cowfs_rmdir(const char *path)
-{
- rel(&path);
-
- /* TODO: whiteout master */
- if (unlinkat(get_wr(path), path, AT_REMOVEDIR) < 0)
- {
- return -errno;
- }
- return 0;
-}
-
-/**
- * FUSE symlink method
- */
-static int cowfs_symlink(const char *from, const char *to)
-{
- int fd;
- const char *fromrel = from;
-
- rel(&to);
- rel(&fromrel);
-
- fd = get_wr(to);
- if (!clone_path(get_rd(fromrel), fd, fromrel))
- {
- return -errno;
- }
- if (symlinkat(from, fd, to) < 0)
- {
- return -errno;
- }
- return 0;
-}
-
-/**
- * FUSE rename method
- */
-static int cowfs_rename(const char *from, const char *to)
-{
- int fd;
-
- rel(&from);
- rel(&to);
-
- fd = copy(from);
- if (fd < 0)
- {
- return -errno;
- }
- if (renameat(fd, from, get_wr(to), to) < 0)
- {
- return -errno;
- }
- return 0;
-}
-
-/**
- * FUSE link method
- */
-static int cowfs_link(const char *from, const char *to)
-{
- int rd, wr;
-
- rel(&from);
- rel(&to);
-
- rd = get_rd(from);
- wr = get_wr(to);
-
- if (!clone_path(rd, wr, to))
- {
- DBG1(DBG_LIB, "cloning path '%s' failed", to);
- return -errno;
- }
- if (linkat(rd, from, wr, to, 0) < 0)
- {
- DBG1(DBG_LIB, "linking '%s' to '%s' failed", from, to);
- return -errno;
- }
- return 0;
-}
-
-/**
- * FUSE chmod method
- */
-static int cowfs_chmod(const char *path, mode_t mode)
-{
- int fd;
- struct stat st;
-
- rel(&path);
- fd = get_rd(path);
- if (fstatat(fd, path, &st, 0) < 0)
- {
- return -errno;
- }
- if (st.st_mode == mode)
- {
- return 0;
- }
- fd = copy(path);
- if (fd < 0)
- {
- return -errno;
- }
- if (fchmodat(fd, path, mode, 0) < 0)
- {
- return -errno;
- }
- return 0;
-}
-
-/**
- * FUSE chown method
- */
-static int cowfs_chown(const char *path, uid_t uid, gid_t gid)
-{
- int fd;
- struct stat st;
-
- rel(&path);
- fd = get_rd(path);
- if (fstatat(fd, path, &st, 0) < 0)
- {
- return -errno;
- }
- if (st.st_uid == uid && st.st_gid == gid)
- {
- return 0;
- }
- fd = copy(path);
- if (fd < 0)
- {
- return -errno;
- }
- if (fchownat(fd, path, uid, gid, AT_SYMLINK_NOFOLLOW) < 0)
- {
- return -errno;
- }
- return 0;
-}
-
-/**
- * FUSE truncate method
- */
-static int cowfs_truncate(const char *path, off_t size)
-{
- int fd;
- struct stat st;
-
- rel(&path);
- fd = get_rd(path);
- if (fstatat(fd, path, &st, 0) < 0)
- {
- return -errno;
- }
- if (st.st_size == size)
- {
- return 0;
- }
- fd = copy(path);
- if (fd < 0)
- {
- return -errno;
- }
- fd = openat(fd, path, O_WRONLY);
- if (fd < 0)
- {
- return -errno;
- }
- if (ftruncate(fd, size) < 0)
- {
- close(fd);
- return -errno;
- }
- close(fd);
- return 0;
-}
-
-/**
- * FUSE utimens method
- */
-static int cowfs_utimens(const char *path, const struct timespec ts[2])
-{
- struct timeval tv[2];
- int fd;
-
- rel(&path);
- fd = copy(path);
- if (fd < 0)
- {
- return -errno;
- }
-
- tv[0].tv_sec = ts[0].tv_sec;
- tv[0].tv_usec = ts[0].tv_nsec / 1000;
- tv[1].tv_sec = ts[1].tv_sec;
- tv[1].tv_usec = ts[1].tv_nsec / 1000;
-
- if (futimesat(fd, path, tv) < 0)
- {
- return -errno;
- }
- return 0;
-}
-
-/**
- * FUSE open method
- */
-static int cowfs_open(const char *path, struct fuse_file_info *fi)
-{
- int fd;
-
- rel(&path);
- fd = get_rd(path);
-
- fd = openat(fd, path, fi->flags);
- if (fd < 0)
- {
- return -errno;
- }
- close(fd);
- return 0;
-}
-
-/**
- * FUSE read method
- */
-static int cowfs_read(const char *path, char *buf, size_t size, off_t offset,
- struct fuse_file_info *fi)
-{
- int file, fd, res;
-
- rel(&path);
-
- fd = get_rd(path);
-
- file = openat(fd, path, O_RDONLY);
- if (file < 0)
- {
- return -errno;
- }
-
- res = pread(file, buf, size, offset);
- if (res < 0)
- {
- res = -errno;
- }
- close(file);
- return res;
-}
-
-/**
- * FUSE write method
- */
-static int cowfs_write(const char *path, const char *buf, size_t size,
- off_t offset, struct fuse_file_info *fi)
-{
- int file, fd, res;
-
- rel(&path);
-
- fd = copy(path);
- if (fd < 0)
- {
- return -errno;
- }
- file = openat(fd, path, O_WRONLY);
- if (file < 0)
- {
- return -errno;
- }
- res = pwrite(file, buf, size, offset);
- if (res < 0)
- {
- res = -errno;
- }
- close(file);
- return res;
-}
-
-/**
- * FUSE statfs method
- */
-static int cowfs_statfs(const char *path, struct statvfs *stbuf)
-{
- int fd;
-
- fd = get_rd(path);
- if (fstatvfs(fd, stbuf) < 0)
- {
- return -errno;
- }
-
- return 0;
-}
-
-/**
- * FUSE init method
- */
-static void *cowfs_init(struct fuse_conn_info *conn)
-{
- struct fuse_context *ctx;
-
- ctx = fuse_get_context();
-
- return ctx->private_data;
-}
-
-/**
- * FUSE method vectors
- */
-static struct fuse_operations cowfs_operations = {
- .getattr = cowfs_getattr,
- .access = cowfs_access,
- .readlink = cowfs_readlink,
- .readdir = cowfs_readdir,
- .mknod = cowfs_mknod,
- .mkdir = cowfs_mkdir,
- .symlink = cowfs_symlink,
- .unlink = cowfs_unlink,
- .rmdir = cowfs_rmdir,
- .rename = cowfs_rename,
- .link = cowfs_link,
- .chmod = cowfs_chmod,
- .chown = cowfs_chown,
- .truncate = cowfs_truncate,
- .utimens = cowfs_utimens,
- .open = cowfs_open,
- .read = cowfs_read,
- .write = cowfs_write,
- .statfs = cowfs_statfs,
- .init = cowfs_init,
-};
-
-METHOD(cowfs_t, add_overlay, bool,
- private_cowfs_t *this, char *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;
-}
-
-METHOD(cowfs_t, del_overlay, bool,
- 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;
-}
-
-METHOD(cowfs_t, pop_overlay, bool,
- private_cowfs_t *this)
-{
- overlay_t *over;
- this->lock->write_lock(this->lock);
- if (this->overlays->remove_first(this->overlays, (void**)&over) != SUCCESS)
- {
- this->lock->unlock(this->lock);
- return FALSE;
- }
- this->lock->unlock(this->lock);
- overlay_destroy(over);
- return TRUE;
-}
-
-METHOD(cowfs_t, destroy, void,
- private_cowfs_t *this)
-{
- fuse_exit(this->fuse);
- 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);
- close(this->master_fd);
- close(this->host_fd);
- free(this);
-}
-
-/**
- * creates a new cowfs fuse instance
- */
-cowfs_t *cowfs_create(char *master, char *host, char *mount)
-{
- struct fuse_args args = {0, NULL, 0};
- private_cowfs_t *this;
-
- INIT(this,
- .public = {
- .add_overlay = _add_overlay,
- .del_overlay = _del_overlay,
- .pop_overlay = _pop_overlay,
- .destroy = _destroy,
- }
- );
-
- this->master_fd = open(master, O_RDONLY | O_DIRECTORY);
- if (this->master_fd < 0)
- {
- DBG1(DBG_LIB, "failed to open master filesystem '%s'", master);
- free(this);
- return NULL;
- }
- this->host_fd = open(host, O_RDONLY | O_DIRECTORY);
- if (this->host_fd < 0)
- {
- DBG1(DBG_LIB, "failed to open host filesystem '%s'", host);
- close(this->master_fd);
- free(this);
- return NULL;
- }
-
- this->chan = fuse_mount(mount, &args);
- if (this->chan == NULL)
- {
- DBG1(DBG_LIB, "mounting cowfs FUSE on '%s' failed", mount);
- close(this->master_fd);
- close(this->host_fd);
- free(this);
- return NULL;
- }
-
- this->fuse = fuse_new(this->chan, &args, &cowfs_operations,
- sizeof(cowfs_operations), this);
- if (this->fuse == NULL)
- {
- DBG1(DBG_LIB, "creating cowfs FUSE handle failed");
- close(this->master_fd);
- close(this->host_fd);
- fuse_unmount(mount, this->chan);
- free(this);
- return NULL;
- }
-
- this->mount = strdup(mount);
- this->master = strdup(master);
- this->host = strdup(host);
- 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);
- close(this->master_fd);
- close(this->host_fd);
- free(this);
- return NULL;
- }
-
- return &this->public;
-}
-
+++ /dev/null
-/*
- * Copyright (C) 2009 Tobias Brunner
- * Copyright (C) 2007 Martin Willi
- * HSR 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 COWFS_H
-#define COWFS_H
-
-#include <library.h>
-
-typedef struct cowfs_t cowfs_t;
-
-/**
- * cowfs - Copy on write FUSE filesystem.
- *
- */
-struct cowfs_t {
-
- /**
- * 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 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 (*pop_overlay)(cowfs_t *this);
-
- /**
- * Stop, umount and destroy a cowfs FUSE filesystem.
- */
- void (*destroy) (cowfs_t *this);
-};
-
-/**
- * Mount a cowfs FUSE filesystem.
- *
- * @param master read only master file system directory
- * @param host copy on write host directory
- * @param mount mountpoint where union is mounted
- * @return instance, or NULL if FUSE initialization failed
- */
-cowfs_t *cowfs_create(char *master, char *host, char *mount);
-
-#endif /* COWFS_H */
-
+++ /dev/null
-/*
- * Copyright (C) 2008-2009 Tobias Brunner
- * Copyright (C) 2007 Martin Willi
- * HSR 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.
- */
-
-#define _GNU_SOURCE
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <dirent.h>
-#include <errno.h>
-
-#include <utils/debug.h>
-#include <collections/linked_list.h>
-
-#include "dumm.h"
-
-#define PERME (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)
-#define GUEST_DIR "guests"
-#define TEMPLATE_DIR "templates"
-
-typedef struct private_dumm_t private_dumm_t;
-
-struct private_dumm_t {
- /** public dumm interface */
- dumm_t public;
- /** working dir */
- char *dir;
- /** directory of guests */
- char *guest_dir;
- /** directory of loaded template */
- char *template;
- /** list of managed guests */
- linked_list_t *guests;
- /** list of managed bridges */
- linked_list_t *bridges;
-};
-
-METHOD(dumm_t, create_guest, guest_t*,
- private_dumm_t *this, char *name, char *kernel, char *master, char *args)
-{
- guest_t *guest;
-
- guest = guest_create(this->guest_dir, name, kernel, master, args);
- if (guest)
- {
- this->guests->insert_last(this->guests, guest);
- }
- return guest;
-}
-
-METHOD(dumm_t, create_guest_enumerator, enumerator_t*,
- private_dumm_t *this)
-{
- return this->guests->create_enumerator(this->guests);
-}
-
-METHOD(dumm_t, delete_guest, void,
- private_dumm_t *this, guest_t *guest)
-{
- if (this->guests->remove(this->guests, guest, NULL))
- {
- char buf[512];
- int len;
-
- len = snprintf(buf, sizeof(buf), "rm -Rf %s/%s",
- this->guest_dir, guest->get_name(guest));
- guest->destroy(guest);
- if (len > 8 && len < 512)
- {
- ignore_result(system(buf));
- }
- }
-}
-
-METHOD(dumm_t, create_bridge, bridge_t*,
- private_dumm_t *this, char *name)
-{
- bridge_t *bridge;
-
- bridge = bridge_create(name);
- if (bridge)
- {
- this->bridges->insert_last(this->bridges, bridge);
- }
- return bridge;
-}
-
-METHOD(dumm_t, create_bridge_enumerator, enumerator_t*,
- private_dumm_t *this)
-{
- return this->bridges->create_enumerator(this->bridges);
-}
-
-METHOD(dumm_t, delete_bridge, void,
- private_dumm_t *this, bridge_t *bridge)
-{
- if (this->bridges->remove(this->bridges, bridge, NULL))
- {
- bridge->destroy(bridge);
- }
-}
-
-METHOD(dumm_t, add_overlay, bool,
- private_dumm_t *this, char *dir)
-{
- enumerator_t *enumerator;
- guest_t *guest;
-
- 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;
-}
-
-METHOD(dumm_t, del_overlay, bool,
- 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))
- {
- 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;
-}
-
-METHOD(dumm_t, pop_overlay, bool,
- private_dumm_t *this)
-{
- bool ret = FALSE;
- enumerator_t *enumerator;
- guest_t *guest;
-
- enumerator = this->guests->create_enumerator(this->guests);
- while (enumerator->enumerate(enumerator, (void**)&guest))
- {
- ret = guest->pop_overlay(guest) || ret;
- }
- enumerator->destroy(enumerator);
- return ret;
-}
-
-/**
- * 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;
- }
-}
-
-METHOD(dumm_t, load_template, bool,
- private_dumm_t *this, char *name)
-{
- clear_template(this);
- if (name == NULL)
- {
- return TRUE;
- }
- if (strlen(name) > PATH_MAX)
- {
- DBG1(DBG_LIB, "template name '%s' is too long", name);
- return FALSE;
- }
- 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)
- {
- if (!mkdir_p(this->template, PERME))
- {
- DBG1(DBG_LIB, "creating template directory '%s' failed: %m",
- this->template);
- return FALSE;
- }
- }
- return add_overlay(this, this->template);
-}
-
-/**
- * Template directory enumerator
- */
-typedef struct {
- /** implements enumerator_t */
- enumerator_t public;
- /** directory enumerator */
- enumerator_t *inner;
-} template_enumerator_t;
-
-METHOD(enumerator_t, template_enumerate, bool,
- template_enumerator_t *this, va_list args)
-{
- struct stat st;
- char *rel, **template;
-
- VA_ARGS_VGET(args, template);
-
- while (this->inner->enumerate(this->inner, &rel, NULL, &st))
- {
- if (S_ISDIR(st.st_mode) && *rel != '.')
- {
- *template = rel;
- return TRUE;
- }
- }
- return FALSE;
-}
-
-METHOD(enumerator_t, template_enumerator_destroy, void,
- template_enumerator_t *this)
-{
- this->inner->destroy(this->inner);
- free(this);
-}
-
-METHOD(dumm_t, create_template_enumerator, enumerator_t*,
- private_dumm_t *this)
-{
- template_enumerator_t *enumerator;
- INIT(enumerator,
- .public = {
- .enumerate = enumerator_enumerate_default,
- .venumerate = _template_enumerate,
- .destroy = (void*)_template_enumerator_destroy,
- },
- .inner = enumerator_create_directory(TEMPLATE_DIR),
- );
- if (!enumerator->inner)
- {
- free(enumerator);
- return enumerator_create_empty();
- }
- return &enumerator->public;
-}
-
-METHOD(dumm_t, destroy, void,
- private_dumm_t *this)
-{
- enumerator_t *enumerator;
- guest_t *guest;
-
- this->bridges->destroy_offset(this->bridges, offsetof(bridge_t, destroy));
-
- enumerator = this->guests->create_enumerator(this->guests);
- while (enumerator->enumerate(enumerator, (void**)&guest))
- {
- guest->stop(guest, NULL);
- }
- enumerator->destroy(enumerator);
-
- while (this->guests->remove_last(this->guests, (void**)&guest) == SUCCESS)
- {
- guest->destroy(guest);
- }
- this->guests->destroy(this->guests);
- free(this->guest_dir);
- free(this->template);
- free(this->dir);
- free(this);
-}
-
-/**
- * load all guests in our working dir
- */
-static void load_guests(private_dumm_t *this)
-{
- DIR *dir;
- struct dirent *ent;
- guest_t *guest;
-
- dir = opendir(this->guest_dir);
- if (dir == NULL)
- {
- return;
- }
-
- while ((ent = readdir(dir)))
- {
- if (*ent->d_name == '.')
- { /* skip ".", ".." and hidden files (such as ".svn") */
- continue;
- }
- guest = guest_load(this->guest_dir, ent->d_name);
- if (guest)
- {
- this->guests->insert_last(this->guests, guest);
- }
- else
- {
- DBG1(DBG_LIB, "loading guest in directory '%s' failed, skipped",
- ent->d_name);
- }
- }
- closedir(dir);
-}
-
-/**
- * create a dumm instance
- */
-dumm_t *dumm_create(char *dir)
-{
- char cwd[PATH_MAX];
- private_dumm_t *this;
-
- INIT(this,
- .public = {
- .create_guest = _create_guest,
- .create_guest_enumerator = _create_guest_enumerator,
- .delete_guest = _delete_guest,
- .create_bridge = _create_bridge,
- .create_bridge_enumerator = _create_bridge_enumerator,
- .delete_bridge = _delete_bridge,
- .add_overlay = _add_overlay,
- .del_overlay = _del_overlay,
- .pop_overlay = _pop_overlay,
- .load_template = _load_template,
- .create_template_enumerator = _create_template_enumerator,
- .destroy = _destroy,
- },
- );
-
- if (dir && *dir == '/')
- {
- this->dir = strdup(dir);
- }
- else
- {
- if (getcwd(cwd, sizeof(cwd)) == NULL)
- {
- free(this);
- return NULL;
- }
- if (dir)
- {
- if (asprintf(&this->dir, "%s/%s", cwd, dir) < 0)
- {
- this->dir = NULL;
- }
- }
- else
- {
- this->dir = strdup(cwd);
- }
- }
- if (asprintf(&this->guest_dir, "%s/%s", this->dir, GUEST_DIR) < 0)
- {
- this->guest_dir = NULL;
- }
-
- this->guests = linked_list_create();
- this->bridges = linked_list_create();
-
- if (this->dir == NULL || this->guest_dir == NULL ||
- (mkdir(this->guest_dir, PERME) < 0 && errno != EEXIST))
- {
- DBG1(DBG_LIB, "creating guest directory '%s' failed: %m",
- this->guest_dir);
- destroy(this);
- return NULL;
- }
-
- load_guests(this);
- return &this->public;
-}
-
+++ /dev/null
-/*
- * Copyright (C) 2008-2009 Tobias Brunner
- * Copyright (C) 2007 Martin Willi
- * HSR 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 DUMM_H
-#define DUMM_H
-
-#include <signal.h>
-
-#include <library.h>
-#include <collections/enumerator.h>
-
-#include "guest.h"
-#include "bridge.h"
-
-typedef struct dumm_t dumm_t;
-
-/**
- * dumm - Dynamic Uml Mesh Modeler
- *
- * Controls a group of UML guests and their networks.
- */
-struct dumm_t {
-
- /**
- * 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 args additional args to pass to kernel
- * @return guest if started, NULL if failed
- */
- guest_t* (*create_guest) (dumm_t *this, char *name, char *kernel,
- char *master, char *args);
-
- /**
- * Create an enumerator over all guests.
- *
- * @return enumerator over guest_t's
- */
- enumerator_t* (*create_guest_enumerator) (dumm_t *this);
-
- /**
- * Delete a guest from disk.
- *
- * @param guest guest to destroy
- */
- void (*delete_guest) (dumm_t *this, guest_t *guest);
-
- /**
- * Create a new bridge.
- *
- * @param name name of the bridge to create
- * @return created bridge
- */
- bridge_t* (*create_bridge)(dumm_t *this, char *name);
-
- /**
- * Create an enumerator over all bridges.
- *
- * @return enumerator over bridge_t's
- */
- enumerator_t* (*create_bridge_enumerator)(dumm_t *this);
-
- /**
- * Delete a bridge.
- *
- * @param bridge bridge to destroy
- */
- 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.
- *
- * 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 *name);
-
- /**
- * Create an enumerator over all available templates.
- *
- * @return enumerator over char*
- */
- enumerator_t* (*create_template_enumerator)(dumm_t *this);
-
- /**
- * stop all guests and destroy the modeler
- */
- void (*destroy) (dumm_t *this);
-};
-
-/**
- * Create a group of UML hosts and networks.
- *
- * @param dir directory to create guests/load from, NULL for cwd
- * @return created UML group, or NULL if failed.
- */
-dumm_t *dumm_create(char *dir);
-
-#endif /* DUMM_H */
-
+++ /dev/null
-dumm.so
-mkmf.log
-extconf.rb
+++ /dev/null
-DUMM Ruby Extension
-===================
-
-Build and Install
-
- $ ruby extconf.rb
- $ make
- # make install
+++ /dev/null
-/*
- * Copyright (C) 2008-2010 Tobias Brunner
- * Copyright (C) 2008 Martin Willi
- * HSR 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 <stdio.h>
-#include <signal.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#include <library.h>
-#include <dumm.h>
-#include <utils/debug.h>
-#include <collections/linked_list.h>
-
-#undef PACKAGE_NAME
-#undef PACKAGE_TARNAME
-#undef PACKAGE_VERSION
-#undef PACKAGE_STRING
-#undef PACKAGE_BUGREPORT
-#undef PACKAGE_URL
-#undef HAVE_DLADDR
-#undef HAVE_QSORT_R
-/* avoid redefintiion of snprintf etc. */
-#define RUBY_DONT_SUBST
-/* undef our _GNU_SOURCE, as it gets redefined by <ruby.h> */
-#undef _GNU_SOURCE
-#include <ruby.h>
-
-static dumm_t *dumm;
-
-static VALUE rbm_dumm;
-static VALUE rbc_guest;
-static VALUE rbc_bridge;
-static VALUE rbc_iface;
-static VALUE rbc_template;
-
-/**
- * Guest invocation callback
- */
-static pid_t invoke(void *null, guest_t *guest, char *args[], int argc)
-{
- pid_t pid;
-
- pid = fork();
- switch (pid)
- {
- case 0: /* child */
- /* create a new process group in order to prevent signals (e.g.
- * SIGINT) sent to the parent from terminating the child */
- setpgid(0, 0);
- dup2(open("/dev/null", 0), 1);
- dup2(open("/dev/null", 0), 2);
- execvp(args[0], args);
- /* FALL */
- case -1:
- return 0;
- default:
- return pid;
- }
-}
-
-/**
- * SIGCHLD signal handler
- */
-static void sigchld_handler(int signal, siginfo_t *info, void* ptr)
-{
- enumerator_t *enumerator;
- guest_t *guest;
-
- enumerator = dumm->create_guest_enumerator(dumm);
- while (enumerator->enumerate(enumerator, &guest))
- {
- if (guest->get_pid(guest) == info->si_pid)
- {
- guest->sigchild(guest);
- break;
- }
- }
- enumerator->destroy(enumerator);
-}
-
-
-/**
- * Global Dumm bindings
- */
-static VALUE dumm_add_overlay(VALUE class, VALUE dir)
-{
- if (!dumm->add_overlay(dumm, StringValuePtr(dir)))
- {
- 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))
- {
- rb_hash_aset(hash, rb_str_new2(guest->get_name(guest)),
- Data_Wrap_Struct(class, NULL, NULL, guest));
- }
- enumerator->destroy(enumerator);
- return hash;
-}
-
-static VALUE guest_hash(VALUE class)
-{
- ID id = rb_intern("@@guests");
- if (!rb_cvar_defined(class, id))
- {
- VALUE hash = guest_hash_create(class);
-#ifdef RB_CVAR_SET_4_ARGS
- rb_cvar_set(class, id, hash, 0);
-#else
- rb_cvar_set(class, id, hash);
-#endif
- return hash;
- }
- return rb_cvar_get(class, id);
-}
-
-static VALUE guest_find(VALUE class, VALUE key)
-{
- if (TYPE(key) != T_STRING)
- {
- key = rb_convert_type(key, T_STRING, "String", "to_s");
- }
- return rb_hash_aref(guest_hash(class), key);
-}
-
-static VALUE guest_get(VALUE class, VALUE key)
-{
- 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");
- }
- 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));
- if (!guest)
- {
- rb_raise(rb_eRuntimeError, "creating guest failed");
- }
- 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)
-{
- guest_t *guest;
-
- Data_Get_Struct(self, guest_t, guest);
- return rb_str_new2(guest->get_name(guest));
-}
-
-static VALUE guest_start(VALUE self)
-{
- guest_t *guest;
-
- Data_Get_Struct(self, guest_t, guest);
-
- if (!guest->start(guest, invoke, NULL, NULL))
- {
- rb_raise(rb_eRuntimeError, "starting guest failed");
- }
- return self;
-}
-
-static VALUE guest_stop(VALUE self)
-{
- guest_t *guest;
-
- Data_Get_Struct(self, guest_t, guest);
- guest->stop(guest, NULL);
- return self;
-}
-
-static VALUE guest_running(VALUE self)
-{
- guest_t *guest;
-
- Data_Get_Struct(self, guest_t, guest);
- return guest->get_pid(guest) ? Qtrue : Qfalse;
-}
-
-static void exec_cb(void *data, char *buf)
-{
- rb_yield(rb_str_new2(buf));
-}
-
-static VALUE guest_exec(VALUE self, VALUE cmd)
-{
- guest_t *guest;
- bool block;
- int ret;
-
- block = rb_block_given_p();
- Data_Get_Struct(self, guest_t, guest);
- 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;
-}
-
-static VALUE guest_mconsole(VALUE self, VALUE cmd)
-{
- guest_t *guest;
- bool block;
- int ret;
-
- 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,
- "%s", StringValuePtr(cmd))) != 0)
- {
- rb_raise(rb_eRuntimeError, "executing command failed (%d)", ret);
- }
- return self;
-}
-
-static VALUE guest_add_iface(VALUE self, VALUE name)
-{
- guest_t *guest;
- iface_t *iface;
-
- Data_Get_Struct(self, guest_t, guest);
- iface = guest->create_iface(guest, StringValuePtr(name));
- if (!iface)
- {
- rb_raise(rb_eRuntimeError, "adding interface failed");
- }
- return Data_Wrap_Struct(rbc_iface, NULL, NULL, iface);
-}
-
-static VALUE guest_find_iface(VALUE self, VALUE key)
-{
- enumerator_t *enumerator;
- iface_t *iface, *found = NULL;
- guest_t *guest;
-
- if (TYPE(key) == T_SYMBOL)
- {
- key = rb_convert_type(key, T_STRING, "String", "to_s");
- }
- Data_Get_Struct(self, guest_t, guest);
- enumerator = guest->create_iface_enumerator(guest);
- while (enumerator->enumerate(enumerator, &iface))
- {
- if (streq(iface->get_guestif(iface), StringValuePtr(key)))
- {
- found = iface;
- break;
- }
- }
- enumerator->destroy(enumerator);
- if (!found)
- {
- return Qnil;
- }
- return Data_Wrap_Struct(rbc_iface, NULL, NULL, iface);
-}
-
-static VALUE guest_get_iface(VALUE self, VALUE key)
-{
- VALUE iface = guest_find_iface(self, key);
- if (NIL_P(iface))
- {
- rb_raise(rb_eRuntimeError, "interface not found");
- }
- return iface;
-}
-
-static VALUE guest_each_iface(int argc, VALUE *argv, VALUE self)
-{
- enumerator_t *enumerator;
- linked_list_t *list;
- guest_t *guest;
- iface_t *iface;
-
- if (!rb_block_given_p())
- {
- rb_raise(rb_eArgError, "must be called with a block");
- }
- Data_Get_Struct(self, guest_t, guest);
- list = linked_list_create();
- enumerator = guest->create_iface_enumerator(guest);
- while (enumerator->enumerate(enumerator, &iface))
- {
- list->insert_last(list, iface);
- }
- enumerator->destroy(enumerator);
- while (list->remove_first(list, (void**)&iface) == SUCCESS)
- {
- rb_yield(Data_Wrap_Struct(rbc_iface, NULL, NULL, iface));
- }
- list->destroy(list);
- return self;
-}
-
-static VALUE guest_delete(VALUE self)
-{
- guest_t *guest;
-
- Data_Get_Struct(self, guest_t, guest);
- if (guest->get_pid(guest))
- {
- rb_raise(rb_eRuntimeError, "guest is running");
- }
- dumm->delete_guest(dumm, guest);
- 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);
- rb_include_module(rb_class_of(rbc_guest), rb_mEnumerable);
- rb_include_module(rbc_guest, rb_mEnumerable);
-
- rb_define_singleton_method(rbc_guest, "[]", guest_get, 1);
- rb_define_singleton_method(rbc_guest, "each", guest_each, -1);
- rb_define_singleton_method(rbc_guest, "new", guest_new, 4);
- rb_define_singleton_method(rbc_guest, "include?", guest_find, 1);
- rb_define_singleton_method(rbc_guest, "guest?", guest_find, 1);
-
- rb_define_method(rbc_guest, "to_s", guest_to_s, 0);
- rb_define_method(rbc_guest, "start", guest_start, 0);
- rb_define_method(rbc_guest, "stop", guest_stop, 0);
- rb_define_method(rbc_guest, "running?", guest_running, 0);
- rb_define_method(rbc_guest, "exec", guest_exec, 1);
- rb_define_method(rbc_guest, "mconsole", guest_mconsole, 1);
- rb_define_method(rbc_guest, "add", guest_add_iface, 1);
- rb_define_method(rbc_guest, "[]", guest_get_iface, 1);
- rb_define_method(rbc_guest, "each", guest_each_iface, -1);
- 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);
-}
-
-/**
- * Bridge binding
- */
-static VALUE bridge_find(VALUE class, VALUE key)
-{
- enumerator_t *enumerator;
- bridge_t *bridge, *found = NULL;
-
- if (TYPE(key) == T_SYMBOL)
- {
- key = rb_convert_type(key, T_STRING, "String", "to_s");
- }
- enumerator = dumm->create_bridge_enumerator(dumm);
- while (enumerator->enumerate(enumerator, &bridge))
- {
- if (streq(bridge->get_name(bridge), StringValuePtr(key)))
- {
- found = bridge;
- break;
- }
- }
- enumerator->destroy(enumerator);
- if (!found)
- {
- return Qnil;
- }
- return Data_Wrap_Struct(class, NULL, NULL, found);
-}
-
-static VALUE bridge_get(VALUE class, VALUE key)
-{
- VALUE bridge = bridge_find(class, key);
- if (NIL_P(bridge))
- {
- rb_raise(rb_eRuntimeError, "bridge not found");
- }
- return bridge;
-}
-
-static VALUE bridge_each(int argc, VALUE *argv, VALUE class)
-{
- enumerator_t *enumerator;
- linked_list_t *list;
- bridge_t *bridge;
-
- if (!rb_block_given_p())
- {
- rb_raise(rb_eArgError, "must be called with a block");
- }
- list = linked_list_create();
- enumerator = dumm->create_bridge_enumerator(dumm);
- while (enumerator->enumerate(enumerator, &bridge))
- {
- list->insert_last(list, bridge);
- }
- enumerator->destroy(enumerator);
- while (list->remove_first(list, (void**)&bridge) == SUCCESS)
- {
- rb_yield(Data_Wrap_Struct(class, NULL, NULL, bridge));
- }
- list->destroy(list);
- return class;
-}
-
-static VALUE bridge_new(VALUE class, VALUE name)
-
-{
- bridge_t *bridge;
-
- bridge = dumm->create_bridge(dumm, StringValuePtr(name));
- if (!bridge)
- {
- rb_raise(rb_eRuntimeError, "creating bridge failed");
- }
- return Data_Wrap_Struct(class, NULL, NULL, bridge);
-}
-
-static VALUE bridge_to_s(VALUE self)
-{
- bridge_t *bridge;
-
- Data_Get_Struct(self, bridge_t, bridge);
- return rb_str_new2(bridge->get_name(bridge));
-}
-
-static VALUE bridge_each_iface(int argc, VALUE *argv, VALUE self)
-{
- enumerator_t *enumerator;
- linked_list_t *list;
- bridge_t *bridge;
- iface_t *iface;
-
- if (!rb_block_given_p())
- {
- rb_raise(rb_eArgError, "must be called with a block");
- }
- Data_Get_Struct(self, bridge_t, bridge);
- list = linked_list_create();
- enumerator = bridge->create_iface_enumerator(bridge);
- while (enumerator->enumerate(enumerator, &iface))
- {
- list->insert_last(list, iface);
- }
- enumerator->destroy(enumerator);
- while (list->remove_first(list, (void**)&iface) == SUCCESS)
- {
- rb_yield(Data_Wrap_Struct(rbc_iface, NULL, NULL, iface));
- }
- list->destroy(list);
- return self;
-}
-
-static VALUE bridge_delete(VALUE self)
-{
- bridge_t *bridge;
-
- Data_Get_Struct(self, bridge_t, bridge);
- dumm->delete_bridge(dumm, bridge);
- return Qnil;
-}
-
-static void bridge_init()
-{
- rbc_bridge = rb_define_class_under(rbm_dumm , "Bridge", rb_cObject);
- rb_include_module(rb_class_of(rbc_bridge), rb_mEnumerable);
- rb_include_module(rbc_bridge, rb_mEnumerable);
-
- rb_define_singleton_method(rbc_bridge, "[]", bridge_get, 1);
- rb_define_singleton_method(rbc_bridge, "each", bridge_each, -1);
- rb_define_singleton_method(rbc_bridge, "new", bridge_new, 1);
- rb_define_singleton_method(rbc_bridge, "include?", bridge_find, 1);
- rb_define_singleton_method(rbc_bridge, "bridge?", bridge_find, 1);
-
- rb_define_method(rbc_bridge, "to_s", bridge_to_s, 0);
- rb_define_method(rbc_bridge, "each", bridge_each_iface, -1);
- rb_define_method(rbc_bridge, "delete", bridge_delete, 0);
-}
-
-/**
- * Iface wrapper
- */
-static VALUE iface_to_s(VALUE self)
-{
- iface_t *iface;
-
- Data_Get_Struct(self, iface_t, iface);
- return rb_str_new2(iface->get_hostif(iface));
-}
-
-static VALUE iface_connect(VALUE self, VALUE vbridge)
-{
- iface_t *iface;
- bridge_t *bridge;
-
- Data_Get_Struct(self, iface_t, iface);
- Data_Get_Struct(vbridge, bridge_t, bridge);
- if (!bridge->connect_iface(bridge, iface))
- {
- rb_raise(rb_eRuntimeError, "connecting iface failed");
- }
- return self;
-}
-
-static VALUE iface_disconnect(VALUE self)
-{
- iface_t *iface;
- bridge_t *bridge;
-
- Data_Get_Struct(self, iface_t, iface);
- bridge = iface->get_bridge(iface);
- if (!bridge || !bridge->disconnect_iface(bridge, iface))
- {
- rb_raise(rb_eRuntimeError, "disconnecting iface failed");
- }
- return self;
-}
-
-static VALUE iface_add_addr(VALUE self, VALUE name)
-{
- iface_t *iface;
- host_t *addr;
- int bits;
-
- addr = host_create_from_subnet(StringValuePtr(name), &bits);
- if (!addr)
- {
- rb_raise(rb_eArgError, "invalid IP address");
- }
- Data_Get_Struct(self, iface_t, iface);
- if (!iface->add_address(iface, addr, bits))
- {
- addr->destroy(addr);
- rb_raise(rb_eRuntimeError, "adding address failed");
- }
- if (rb_block_given_p()) {
- rb_yield(self);
- iface->delete_address(iface, addr, bits);
- }
- addr->destroy(addr);
- return self;
-}
-
-static VALUE iface_each_addr(int argc, VALUE *argv, VALUE self)
-{
- enumerator_t *enumerator;
- linked_list_t *list;
- iface_t *iface;
- host_t *addr;
- char buf[64], *fmt = "%H";
-
- if (!rb_block_given_p())
- {
- rb_raise(rb_eArgError, "must be called with a block");
- }
- list = linked_list_create();
- Data_Get_Struct(self, iface_t, iface);
- enumerator = iface->create_address_enumerator(iface);
- while (enumerator->enumerate(enumerator, &addr))
- {
- list->insert_last(list, addr->clone(addr));
- }
- enumerator->destroy(enumerator);
- while (list->remove_first(list, (void**)&addr) == SUCCESS)
- {
- snprintf(buf, sizeof(buf), fmt, addr);
- addr->destroy(addr);
- rb_yield(rb_str_new2(buf));
- }
- list->destroy(list);
- return self;
-}
-
-static VALUE iface_del_addr(VALUE self, VALUE vaddr)
-{
- iface_t *iface;
- host_t *addr;
- int bits;
-
- addr = host_create_from_subnet(StringValuePtr(vaddr), &bits);
- if (!addr)
- {
- rb_raise(rb_eArgError, "invalid IP address");
- }
- Data_Get_Struct(self, iface_t, iface);
- if (!iface->delete_address(iface, addr, bits))
- {
- addr->destroy(addr);
- rb_raise(rb_eRuntimeError, "address not found");
- }
- if (rb_block_given_p()) {
- rb_yield(self);
- iface->add_address(iface, addr, bits);
- }
- addr->destroy(addr);
- return self;
-}
-
-static VALUE iface_delete(VALUE self)
-{
- guest_t *guest;
- iface_t *iface;
-
- Data_Get_Struct(self, iface_t, iface);
- guest = iface->get_guest(iface);
- guest->destroy_iface(guest, iface);
- return Qnil;
-}
-
-static void iface_init()
-{
- rbc_iface = rb_define_class_under(rbm_dumm , "Iface", rb_cObject);
- rb_include_module(rbc_iface, rb_mEnumerable);
-
- rb_define_method(rbc_iface, "to_s", iface_to_s, 0);
- rb_define_method(rbc_iface, "connect", iface_connect, 1);
- rb_define_method(rbc_iface, "disconnect", iface_disconnect, 0);
- rb_define_method(rbc_iface, "add", iface_add_addr, 1);
- rb_define_method(rbc_iface, "del", iface_del_addr, 1);
- rb_define_method(rbc_iface, "each", iface_each_addr, -1);
- rb_define_method(rbc_iface, "delete", iface_delete, 0);
-}
-
-static VALUE template_load(VALUE class, VALUE dir)
-{
- if (!dumm->load_template(dumm, StringValuePtr(dir)))
- {
- rb_raise(rb_eRuntimeError, "loading template failed");
- }
- return class;
-}
-
-static VALUE template_unload(VALUE class)
-{
- if (!dumm->load_template(dumm, NULL))
- {
- rb_raise(rb_eRuntimeError, "unloading template failed");
- }
- return class;
-}
-
-static VALUE template_each(int argc, VALUE *argv, VALUE class)
-{
- enumerator_t *enumerator;
- char *template;
-
- if (!rb_block_given_p())
- {
- rb_raise(rb_eArgError, "must be called with a block");
- }
- enumerator = dumm->create_template_enumerator(dumm);
- while (enumerator->enumerate(enumerator, &template))
- {
- rb_yield(rb_str_new2(template));
- }
- enumerator->destroy(enumerator);
- return class;
-}
-
-static void template_init()
-{
- rbc_template = rb_define_class_under(rbm_dumm , "Template", rb_cObject);
- rb_include_module(rb_class_of(rbc_template), rb_mEnumerable);
-
- rb_define_singleton_method(rbc_template, "load", template_load, 1);
- rb_define_singleton_method(rbc_template, "unload", template_unload, 0);
- rb_define_singleton_method(rbc_template, "each", template_each, -1);
-}
-
-/**
- * extension finalization
- */
-void Final_dumm()
-{
- struct sigaction action;
-
- dumm->destroy(dumm);
-
- sigemptyset(&action.sa_mask);
- action.sa_handler = SIG_DFL;
- action.sa_flags = 0;
- sigaction(SIGCHLD, &action, NULL);
-
- library_deinit();
-}
-
-/**
- * extension initialization
- */
-void Init_dumm()
-{
- struct sigaction action;
-
- /* there are too many to report, rubyruby... */
- setenv("LEAK_DETECTIVE_DISABLE", "1", 1);
-
- library_init(NULL, "dumm");
-
- dumm = dumm_create(NULL);
-
- dumm_init();
- guest_init();
- bridge_init();
- iface_init();
- template_init();
-
- sigemptyset(&action.sa_mask);
- action.sa_sigaction = sigchld_handler;
- action.sa_flags = SA_SIGINFO;
- sigaction(SIGCHLD, &action, NULL);
-
- rb_set_end_proc(Final_dumm, 0);
-}
+++ /dev/null
-#
-# DUMM for Ruby
-#
-
-require 'mkmf'
-
-$defs << " @DEFS@"
-$CFLAGS << " -Wno-format -include \"@top_builddir@/config.h\""
-
-dir_config('dumm', '@top_srcdir@/src/dumm', '../.libs')
-dir_config('strongswan', '@top_srcdir@/src/libstrongswan', '../../libstrongswan/.libs')
-
-unless find_library('dumm', 'dumm_create')
- puts "... failed: 'libdumm' not found!"
- exit
-end
-
-create_makefile('dumm', '@top_srcdir@/src/dumm/ext')
-
+++ /dev/null
-=begin
- Copyright (C) 2008-2009 Tobias Brunner
- HSR 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.
-=end
-
-require 'dumm.so'
-require 'dumm/guest'
-
-module Dumm
-
- # use guest/bridge indentifiers directly
- def method_missing(id, *args)
- if Guest.guest? id
- return Guest[id]
- end
- if Bridge.bridge? id
- return Bridge[id]
- end
- super(id, *args)
- end
-
- # shortcut for Template loading
- def template(name = nil)
- if name
- Template.load name
- else
- Template.sort.each {|t| puts t }
- end
- return Dumm
- end
-
- # unload template/overlays, reset all guests and delete bridges
- def reset
- Template.unload
- Guest.each { |guest|
- guest.reset
- }
- Bridge.each { |bridge|
- bridge.delete
- }
- return Dumm
- end
-
- # wait until all running guests have booted up
- def boot
- Guest.each {|g|
- g.boot if g.running?
- }
- return Dumm
- end
-end
-
-# vim:sw=2 ts=2 et
+++ /dev/null
-=begin
- Copyright (C) 2008-2010 Tobias Brunner
- HSR 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.
-=end
-
-module Dumm
- class Guest
- # accessor for guests
- # e.g. Guest.sun instead of Guest["sun"]
- def self.method_missing(id, *args)
- unless guest? id
- super(id, *args)
- end
- Guest[id]
- end
-
- # accessor for interfaces
- # e.g. guest.eth0 instead of guest["eth0"]
- def method_missing(id, *args)
- unless iface? id
- super(id, *args)
- end
- self[id]
- end
-
- # remove all overlays, delete all interfaces
- def reset
- while pop_overlay; end
- each {|i|
- i.delete
- }
- end
-
- # has the guest booted up?
- def booted?
- exec("pgrep getty")
- execstatus == 0
- end
-
- # wait until the guest has booted
- def boot
- while not booted?
- sleep(1)
- end
- end
- end
-end
-
-# vim:sw=2 ts=2 et
+++ /dev/null
-/*
- * Copyright (C) 2008-2009 Tobias Brunner
- * Copyright (C) 2007 Martin Willi
- * HSR 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.
- */
-
-#define _GNU_SOURCE
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <sys/uio.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <dirent.h>
-#include <termios.h>
-#include <stdarg.h>
-
-#include <utils/debug.h>
-#include <collections/linked_list.h>
-
-#include "dumm.h"
-#include "guest.h"
-#include "mconsole.h"
-#include "cowfs.h"
-
-#define PERME (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)
-#define PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH)
-
-#define MASTER_DIR "master"
-#define DIFF_DIR "diff"
-#define UNION_DIR "union"
-#define ARGS_FILE "args"
-#define PID_FILE "pid"
-#define KERNEL_FILE "linux"
-#define LOG_FILE "boot.log"
-#define NOTIFY_FILE "notify"
-#define PTYS 0
-
-typedef struct private_guest_t private_guest_t;
-
-struct private_guest_t {
- /** implemented public interface */
- guest_t public;
- /** name of the guest */
- char *name;
- /** directory of guest */
- int dir;
- /** directory name of guest */
- char *dirname;
- /** additional args to pass to guest */
- char *args;
- /** pid of guest child process */
- int pid;
- /** state of guest */
- guest_state_t state;
- /** FUSE cowfs instance */
- cowfs_t *cowfs;
- /** mconsole to control running UML */
- mconsole_t *mconsole;
- /** list of interfaces attached to the guest */
- linked_list_t *ifaces;
-};
-
-ENUM(guest_state_names, GUEST_STOPPED, GUEST_STOPPING,
- "STOPPED",
- "STARTING",
- "RUNNING",
- "PAUSED",
- "STOPPING",
-);
-
-METHOD(guest_t, get_name, char*,
- private_guest_t *this)
-{
- return this->name;
-}
-
-METHOD(guest_t, create_iface, iface_t*,
- private_guest_t *this, char *name)
-{
- enumerator_t *enumerator;
- iface_t *iface;
-
- if (this->state != GUEST_RUNNING)
- {
- DBG1(DBG_LIB, "guest '%s' not running, unable to add interface",
- this->name);
- return NULL;
- }
-
- enumerator = this->ifaces->create_enumerator(this->ifaces);
- while (enumerator->enumerate(enumerator, (void**)&iface))
- {
- if (streq(name, iface->get_guestif(iface)))
- {
- DBG1(DBG_LIB, "guest '%s' already has an interface '%s'",
- this->name, name);
- enumerator->destroy(enumerator);
- return NULL;
- }
- }
- enumerator->destroy(enumerator);
-
- iface = iface_create(name, &this->public, this->mconsole);
- if (iface)
- {
- this->ifaces->insert_last(this->ifaces, iface);
- }
- return iface;
-}
-
-METHOD(guest_t, destroy_iface, void,
- private_guest_t *this, iface_t *iface)
-{
- enumerator_t *enumerator;
- iface_t *current;
-
- enumerator = this->ifaces->create_enumerator(this->ifaces);
- while (enumerator->enumerate(enumerator, (void**)¤t))
- {
- if (current == iface)
- {
- this->ifaces->remove_at(this->ifaces, enumerator);
- current->destroy(current);
- break;
- }
- }
- enumerator->destroy(enumerator);
-}
-
-METHOD(guest_t, create_iface_enumerator, enumerator_t*,
- private_guest_t *this)
-{
- return this->ifaces->create_enumerator(this->ifaces);
-}
-
-METHOD(guest_t, get_state, guest_state_t,
- private_guest_t *this)
-{
- return this->state;
-}
-
-METHOD(guest_t, get_pid, pid_t,
- private_guest_t *this)
-{
- return this->pid;
-}
-
-/**
- * write format string to a buffer, and advance buffer position
- */
-static char* write_arg(char **pos, size_t *left, char *format, ...)
-{
- size_t len;
- char *res = NULL;
- va_list args;
-
- va_start(args, format);
- len = vsnprintf(*pos, *left, format, args);
- va_end(args);
- if (len < *left)
- {
- res = *pos;
- len++;
- *pos += len + 1;
- *left -= len + 1;
- }
- return res;
-}
-
-METHOD(guest_t, stop, void,
- private_guest_t *this, idle_function_t idle)
-{
- 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_STOPPED)
- {
- if (idle)
- {
- idle();
- }
- else
- {
- usleep(50000);
- }
- }
- unlinkat(this->dir, PID_FILE, 0);
- this->pid = 0;
- }
-}
-
-/**
- * save pid in file
- */
-void savepid(private_guest_t *this)
-{
- FILE *file;
-
- file = fdopen(openat(this->dir, PID_FILE, O_RDWR | O_CREAT | O_TRUNC,
- PERM), "w");
- if (file)
- {
- fprintf(file, "%d", this->pid);
- fclose(file);
- }
-}
-
-METHOD(guest_t, start, bool,
- private_guest_t *this, invoke_function_t invoke, void* data,
- idle_function_t idle)
-{
- char buf[2048];
- char *notify;
- char *pos = buf;
- char *args[32];
- int i = 0;
- size_t left = sizeof(buf);
-
- memset(args, 0, sizeof(args));
-
- if (this->state != GUEST_STOPPED)
- {
- DBG1(DBG_LIB, "unable to start guest in state %N", guest_state_names,
- this->state);
- return FALSE;
- }
- this->state = GUEST_STARTING;
-
- 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, "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)
- {
- this->state = GUEST_STOPPED;
- return FALSE;
- }
- savepid(this);
-
- /* open mconsole */
- this->mconsole = mconsole_create(notify, idle);
- if (this->mconsole == NULL)
- {
- DBG1(DBG_LIB, "opening mconsole at '%s' failed, stopping guest", buf);
- stop(this, NULL);
- return FALSE;
- }
-
- this->state = GUEST_RUNNING;
- return TRUE;
-}
-
-METHOD(guest_t, add_overlay, bool,
- private_guest_t *this, char *path)
-{
- if (path == NULL)
- {
- return FALSE;
- }
-
- if (access(path, F_OK) != 0)
- {
- if (!mkdir_p(path, PERME))
- {
- DBG1(DBG_LIB, "creating overlay for guest '%s' failed: %m",
- this->name);
- return FALSE;
- }
- }
-
- return this->cowfs->add_overlay(this->cowfs, path);
-}
-
-METHOD(guest_t, del_overlay, bool,
- private_guest_t *this, char *path)
-{
- return this->cowfs->del_overlay(this->cowfs, path);
-}
-
-METHOD(guest_t, pop_overlay, bool,
- private_guest_t *this)
-{
- return this->cowfs->pop_overlay(this->cowfs);
-}
-
-/**
- * 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;
-}
-
-METHOD(guest_t, exec, int,
- 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);
- }
- }
-}
-
-METHOD(guest_t, exec_str, int,
- 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;
-}
-
-METHOD(guest_t, sigchild, void,
- private_guest_t *this)
-{
- DESTROY_IF(this->mconsole);
- this->mconsole = NULL;
- this->state = GUEST_STOPPED;
-}
-
-/**
- * umount the union filesystem
- */
-static bool umount_unionfs(private_guest_t *this)
-{
- if (this->cowfs)
- {
- this->cowfs->destroy(this->cowfs);
- this->cowfs = NULL;
- return TRUE;
- }
- return FALSE;
-}
-
-/**
- * mount the union filesystem
- */
-static bool mount_unionfs(private_guest_t *this)
-{
- char master[PATH_MAX];
- char diff[PATH_MAX];
- char mount[PATH_MAX];
-
- if (this->cowfs == NULL)
- {
- snprintf(master, sizeof(master), "%s/%s", this->dirname, MASTER_DIR);
- snprintf(diff, sizeof(diff), "%s/%s", this->dirname, DIFF_DIR);
- snprintf(mount, sizeof(mount), "%s/%s", this->dirname, UNION_DIR);
-
- this->cowfs = cowfs_create(master, diff, mount);
- if (this->cowfs)
- {
- return TRUE;
- }
- }
- return FALSE;
-}
-
-/**
- * load args configuration from file
- */
-char *loadargs(private_guest_t *this)
-{
- FILE *file;
- char buf[512], *args = NULL;
-
- file = fdopen(openat(this->dir, ARGS_FILE, O_RDONLY, PERM), "r");
- if (file)
- {
- if (fgets(buf, sizeof(buf), file))
- {
- args = strdup(buf);
- }
- fclose(file);
- }
- return args;
-}
-
-/**
- * save args configuration to file
- */
-bool saveargs(private_guest_t *this, char *args)
-{
- FILE *file;
- bool retval = FALSE;
-
- file = fdopen(openat(this->dir, ARGS_FILE, O_RDWR | O_CREAT | O_TRUNC,
- PERM), "w");
- if (file)
- {
- if (fprintf(file, "%s", args) > 0)
- {
- retval = TRUE;
- }
- fclose(file);
- }
- return retval;
-}
-
-METHOD(guest_t, destroy, void,
- private_guest_t *this)
-{
- stop(this, NULL);
- umount_unionfs(this);
- if (this->dir > 0)
- {
- close(this->dir);
- }
- this->ifaces->destroy(this->ifaces);
- free(this->dirname);
- free(this->args);
- free(this->name);
- free(this);
-}
-
-/**
- * generic guest constructor
- */
-static private_guest_t *guest_create_generic(char *parent, char *name,
- bool create)
-{
- char cwd[PATH_MAX];
- private_guest_t *this;
-
- INIT(this,
- .public = {
- .get_name = _get_name,
- .get_pid = _get_pid,
- .get_state = _get_state,
- .create_iface = _create_iface,
- .destroy_iface = _destroy_iface,
- .create_iface_enumerator = _create_iface_enumerator,
- .start = _start,
- .stop = _stop,
- .add_overlay = _add_overlay,
- .del_overlay = _del_overlay,
- .pop_overlay = _pop_overlay,
- .exec = _exec,
- .exec_str = _exec_str,
- .sigchild = _sigchild,
- .destroy = _destroy,
- }
- );
-
- if (*parent == '/' || getcwd(cwd, sizeof(cwd)) == NULL)
- {
- if (asprintf(&this->dirname, "%s/%s", parent, name) < 0)
- {
- this->dirname = NULL;
- }
- }
- else
- {
- if (asprintf(&this->dirname, "%s/%s/%s", cwd, parent, name) < 0)
- {
- this->dirname = NULL;
- }
- }
- if (this->dirname == NULL)
- {
- free(this);
- return NULL;
- }
- if (create)
- {
- mkdir(this->dirname, PERME);
- }
- this->dir = open(this->dirname, O_DIRECTORY, PERME);
- if (this->dir < 0)
- {
- DBG1(DBG_LIB, "opening guest directory '%s' failed: %m", this->dirname);
- free(this->dirname);
- free(this);
- return NULL;
- }
- this->state = GUEST_STOPPED;
- this->ifaces = linked_list_create();
- this->name = strdup(name);
-
- 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, char *args)
-{
- 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(DBG_LIB, "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(DBG_LIB, "unable to create directories for '%s': %m", name);
- destroy(this);
- return NULL;
- }
-
- this->args = args;
- if (args && !saveargs(this, args))
- {
- 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->args = loadargs(this);
-
- if (!mount_unionfs(this))
- {
- destroy(this);
- return NULL;
- }
-
- return &this->public;
-}
-
+++ /dev/null
-/*
- * Copyright (C) 2008-2009 Tobias Brunner
- * Copyright (C) 2007 Martin Willi
- * HSR 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 GUEST_H
-#define GUEST_H
-
-#include <library.h>
-#include <collections/enumerator.h>
-
-typedef enum guest_state_t guest_state_t;
-typedef struct guest_t guest_t;
-
-#include "iface.h"
-
-/**
- * State of a guest (started, stopped, ...)
- */
-enum guest_state_t {
- /** guest kernel not running at all */
- GUEST_STOPPED,
- /** kernel started, but not yet available */
- GUEST_STARTING,
- /** guest is up and running */
- GUEST_RUNNING,
- /** guest has been paused */
- GUEST_PAUSED,
- /** guest is stopping (shutting down) */
- GUEST_STOPPING,
-};
-
-/**
- * string mappings for guest_state_t
- */
-extern enum_name_t *guest_state_names;
-
-/**
- * Invoke function which launches the UML guest.
- *
- * Consoles are all set to NULL, you may change them by adding additional UML
- * options to args before invocation.
- *
- * @param data callback data
- * @param guest guest to start
- * @param args args to use for guest invocation, args[0] is kernel
- * @param argc number of elements in args
- * @param idle
- * @return PID of child, 0 if failed
- */
-typedef pid_t (*invoke_function_t)(void *data, guest_t *guest,
- char *args[], int argc);
-
-/**
- * Idle function to pass to start().
- */
-typedef void (*idle_function_t)(void);
-
-/**
- * A guest is a UML instance running on the host.
- **/
-struct guest_t {
-
- /**
- * Get the name of this guest.
- *
- * @return name of the guest
- */
- char* (*get_name) (guest_t *this);
-
- /**
- * Get the process ID of the guest child process.
- *
- * @return name of the guest
- */
- pid_t (*get_pid) (guest_t *this);
-
- /**
- * Get the state of the guest (stopped, started, etc.).
- *
- * @return guests state
- */
- guest_state_t (*get_state)(guest_t *this);
-
- /**
- * Start the guest.
- *
- * @param invoke UML guest invocation function
- * @param data data to pass back to invoke function
- * @param idle idle function to call while waiting on child
- * @return TRUE if guest successfully started
- */
- bool (*start) (guest_t *this, invoke_function_t invoke, void *data,
- idle_function_t idle);
-
- /**
- * Kill the guest.
- *
- * @param idle idle function to call while waiting to termination
- */
- void (*stop) (guest_t *this, idle_function_t idle);
-
- /**
- * Create a new interface in the current scenario.
- *
- * @param name name of the interface in the guest
- * @return created interface, or NULL if failed
- */
- iface_t* (*create_iface)(guest_t *this, char *name);
-
- /**
- * Destroy an interface on guest.
- *
- * @param iface interface to destroy
- */
- void (*destroy_iface)(guest_t *this, iface_t *iface);
-
- /**
- * Create an enumerator over all guest interfaces.
- *
- * @return enumerator over iface_t's
- */
- enumerator_t* (*create_iface_enumerator)(guest_t *this);
-
- /**
- * Adds a COWFS overlay. The directory is created if it does not exist.
- *
- * @param dir directory where overlay diff should point to
- * @return FALSE, if failed
- */
- 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.
- *
- * @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 return value
- */
- int (*exec)(guest_t *this, void(*cb)(void*,char*,size_t), void *data,
- char *cmd, ...);
-
- /**
- * Execute a command on the guests mconsole, with output formatter.
- *
- * If lines is TRUE, callback is invoked for each output line. Otherwise
- * the full result is returned in one callback invocation.
- *
- * @note This function does not work with binary output.
- *
- * @param cb callback to call for each line or for the complete output
- * @param lines TRUE if the callback should be called for each line
- * @param data data to pass to callback
- * @param cmd command to execute
- * @param ... printf style argument list for cmd
- * @return return value
- */
- int (*exec_str)(guest_t *this, void(*cb)(void*,char*), bool lines,
- void *data, char *cmd, ...);
-
- /**
- * Called whenever a SIGCHILD for the guests PID is received.
- */
- void (*sigchild)(guest_t *this);
-
- /**
- * Close and destroy a guest with all interfaces
- */
- void (*destroy) (guest_t *this);
-};
-
-/**
- * Create a new, unstarted 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 args additional args to pass to kernel
- * @param mem amount of memory to give the guest
- */
-guest_t *guest_create(char *parent, char *name, char *kernel,
- char *master, char *args);
-
-/**
- * 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 */
-
+++ /dev/null
-/*
- * Copyright (C) 2008 Tobias Brunner
- * Copyright (C) 2007 Martin Willi
- * HSR Hochschule fuer Technik Rapperswil
- * Copyright (C) 2002 Jeff Dike
- *
- * Based on the "tunctl" utility from Jeff Dike.
- *
- * 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 <fcntl.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <net/if.h>
-#include <sys/ioctl.h>
-#include <linux/if_tun.h>
-
-#include <utils/debug.h>
-#include <collections/linked_list.h>
-
-#include "iface.h"
-
-typedef struct private_iface_t private_iface_t;
-
-struct private_iface_t {
- /** public interface */
- iface_t public;
- /** device name in guest (eth0) */
- char *guestif;
- /** device name at host (tap0) */
- char *hostif;
- /** bridge this interface is attached to */
- bridge_t *bridge;
- /** guest this interface is attached to */
- guest_t *guest;
- /** mconsole for guest */
- mconsole_t *mconsole;
-};
-
-/**
- * bring an interface up or down (host side)
- */
-bool iface_control(char *name, bool up)
-{
- int s;
- bool good = FALSE;
- struct ifreq ifr;
-
- memset(&ifr, 0, sizeof(struct ifreq));
- strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
-
- s = socket(AF_INET, SOCK_DGRAM, 0);
- if (!s)
- {
- return FALSE;
- }
- if (ioctl(s, SIOCGIFFLAGS, &ifr) == 0)
- {
- if (up)
- {
- ifr.ifr_flags |= IFF_UP;
- }
- else
- {
- ifr.ifr_flags &= ~IFF_UP;
- }
- if (ioctl(s, SIOCSIFFLAGS, &ifr) == 0)
- {
- good = TRUE;
- }
- }
- close(s);
- return good;
-}
-
-METHOD(iface_t, get_guestif, char*,
- private_iface_t *this)
-{
- return this->guestif;
-}
-
-METHOD(iface_t, get_hostif, char*,
- private_iface_t *this)
-{
- return this->hostif;
-}
-
-METHOD(iface_t, add_address, bool,
- private_iface_t *this, host_t *addr, int bits)
-{
- return (this->guest->exec(this->guest, NULL, NULL,
- "exec ip addr add %H/%d dev %s", addr, bits, this->guestif) == 0);
-}
-
-/**
- * compile a list of the addresses of an interface
- */
-static void compile_address_list(linked_list_t *list, char *address)
-{
- host_t *host = host_create_from_string(address, 0);
- if (host)
- {
- list->insert_last(list, host);
- }
-}
-
-/**
- * delete the list of addresses
- */
-static void destroy_address_list(linked_list_t *list)
-{
- list->destroy_offset(list, offsetof(host_t, destroy));
-}
-
-METHOD(iface_t, create_address_enumerator, enumerator_t*,
- private_iface_t *this)
-{
- linked_list_t *addresses = linked_list_create();
- this->guest->exec_str(this->guest, (void(*)(void*,char*))compile_address_list,
- TRUE, addresses,
- "exec ip addr list dev %s scope global | "
- "grep '^ \\+\\(inet6\\? \\)' | "
- "awk -F '( +|/)' '{ print $3 }'", this->guestif);
- return enumerator_create_cleaner(addresses->create_enumerator(addresses),
- (void(*)(void*))destroy_address_list, addresses);
-}
-
-METHOD(iface_t, delete_address, bool,
- private_iface_t *this, host_t *addr, int bits)
-{
- return (this->guest->exec(this->guest, NULL, NULL,
- "exec ip addr del %H/%d dev %s", addr, bits, this->guestif) == 0);
-}
-
-METHOD(iface_t, set_bridge, void,
- private_iface_t *this, bridge_t *bridge)
-{
- if (this->bridge == NULL && bridge)
- {
- this->guest->exec(this->guest, NULL, NULL,
- "exec ip link set %s up", this->guestif);
- }
- else if (this->bridge && bridge == NULL)
- {
- this->guest->exec(this->guest, NULL, NULL,
- "exec ip link set %s down", this->guestif);
- }
- this->bridge = bridge;
-}
-
-METHOD(iface_t, get_bridge, bridge_t*,
- private_iface_t *this)
-{
- return this->bridge;
-}
-
-METHOD(iface_t, get_guest, guest_t*,
- private_iface_t *this)
-{
- return this->guest;
-}
-
-/**
- * destroy the tap device
- */
-static bool destroy_tap(private_iface_t *this)
-{
- struct ifreq ifr;
- int tap;
-
- if (!iface_control(this->hostif, FALSE))
- {
- DBG1(DBG_LIB, "bringing iface down failed: %m");
- }
- memset(&ifr, 0, sizeof(ifr));
- ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
- strncpy(ifr.ifr_name, this->hostif, sizeof(ifr.ifr_name) - 1);
-
- tap = open(TAP_DEVICE, O_RDWR);
- if (tap < 0)
- {
- DBG1(DBG_LIB, "unable to open tap device %s: %m", TAP_DEVICE);
- return FALSE;
- }
- if (ioctl(tap, TUNSETIFF, &ifr) < 0 ||
- ioctl(tap, TUNSETPERSIST, 0) < 0)
- {
- DBG1(DBG_LIB, "removing %s failed: %m", this->hostif);
- close(tap);
- return FALSE;
- }
- close(tap);
- return TRUE;
-}
-
-/**
- * create the tap device
- */
-static char* create_tap(private_iface_t *this)
-{
- struct ifreq ifr;
- int tap;
-
- memset(&ifr, 0, sizeof(ifr));
- ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
- snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s-%s",
- this->guest->get_name(this->guest), this->guestif);
-
- tap = open(TAP_DEVICE, O_RDWR);
- if (tap < 0)
- {
- DBG1(DBG_LIB, "unable to open tap device %s: %m", TAP_DEVICE);
- return NULL;
- }
- if (ioctl(tap, TUNSETIFF, &ifr) < 0 ||
- ioctl(tap, TUNSETPERSIST, 1) < 0 ||
- ioctl(tap, TUNSETOWNER, 0))
- {
- DBG1(DBG_LIB, "creating new tap device failed: %m");
- close(tap);
- return NULL;
- }
- close(tap);
- return strdup(ifr.ifr_name);
-}
-
-METHOD(iface_t, destroy, void,
- private_iface_t *this)
-{
- if (this->bridge)
- {
- this->bridge->disconnect_iface(this->bridge, &this->public);
- }
- /* TODO: iface mgmt is not blocking yet, so wait some ticks */
- usleep(50000);
- this->mconsole->del_iface(this->mconsole, this->guestif);
- destroy_tap(this);
- free(this->guestif);
- free(this->hostif);
- free(this);
-}
-
-/**
- * create the iface instance
- */
-iface_t *iface_create(char *name, guest_t *guest, mconsole_t *mconsole)
-{
- private_iface_t *this;
-
- INIT(this,
- .public = {
- .get_hostif = _get_hostif,
- .get_guestif = _get_guestif,
- .add_address = _add_address,
- .create_address_enumerator = _create_address_enumerator,
- .delete_address = _delete_address,
- .set_bridge = _set_bridge,
- .get_bridge = _get_bridge,
- .get_guest = _get_guest,
- .destroy = _destroy,
- },
- .mconsole = mconsole,
- .guestif = strdup(name),
- .guest = guest,
- );
- this->hostif = create_tap(this);
- if (this->hostif == NULL)
- {
- destroy_tap(this);
- free(this->guestif);
- free(this);
- return NULL;
- }
- if (!this->mconsole->add_iface(this->mconsole, this->guestif, this->hostif))
- {
- DBG1(DBG_LIB, "creating interface '%s' in guest failed", this->guestif);
- destroy_tap(this);
- free(this->guestif);
- free(this->hostif);
- free(this);
- return NULL;
- }
- if (!iface_control(this->hostif, TRUE))
- {
- DBG1(DBG_LIB, "bringing iface '%s' up failed: %m", this->hostif);
- }
- return &this->public;
-}
-
+++ /dev/null
-/*
- * Copyright (C) 2007 Martin Willi
- * HSR 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 IFACE_H
-#define IFACE_H
-
-#include <library.h>
-#include <collections/enumerator.h>
-#include <networking/host.h>
-
-#define TAP_DEVICE "/dev/net/tun"
-
-typedef struct iface_t iface_t;
-
-#include "mconsole.h"
-#include "bridge.h"
-#include "guest.h"
-
-/**
- * Interface in a guest, connected to a tap device on the host.
- */
-struct iface_t {
-
- /**
- * Get the interface name in the guest (e.g. eth0).
- *
- * @return guest interface name
- */
- char* (*get_guestif)(iface_t *this);
-
- /**
- * Get the interface name at the host (e.g. tap0).
- *
- * @return host interface (tap device) name
- */
- char* (*get_hostif)(iface_t *this);
-
- /**
- * Add an address to the interface.
- *
- * @param addr address to add to the interface
- * @param bits network prefix length in bits
- * @return TRUE if address added
- */
- bool (*add_address)(iface_t *this, host_t *addr, int bits);
-
- /**
- * Create an enumerator over all installed addresses.
- *
- * @return enumerator over host_t*
- */
- enumerator_t* (*create_address_enumerator)(iface_t *this);
-
- /**
- * Remove an address from an interface.
- *
- * @note The network prefix length has to be the same as used in add_address
- *
- * @param addr address to remove
- * @param bits network prefix length in bits
- * @return TRUE if address removed
- */
- bool (*delete_address)(iface_t *this, host_t *addr, int bits);
-
- /**
- * Set the bridge this interface is attached to.
- *
- * @param bridge assigned bridge, or NULL for none
- */
- void (*set_bridge)(iface_t *this, bridge_t *bridge);
-
- /**
- * Get the bridge this iface is connected, or NULL.
- *
- * @return connected bridge, or NULL
- */
- bridge_t* (*get_bridge)(iface_t *this);
-
- /**
- * Get the guest this iface belongs to.
- *
- * @return guest of this iface
- */
- guest_t* (*get_guest)(iface_t *this);
-
- /**
- * Destroy an interface
- */
- void (*destroy) (iface_t *this);
-};
-
-/**
- * Create a new interface for a guest
- *
- * @param name name of the interface in the guest
- * @param guest guest this iface is connecting
- * @param mconsole mconsole of guest
- * @return interface descriptor, or NULL if failed
- */
-iface_t *iface_create(char *name, guest_t *guest, mconsole_t *mconsole);
-
-#endif /* IFACE_H */
-
+++ /dev/null
-/*
- * Copyright (C) 2008 Martin Willi
- * HSR 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.
- */
-
-#undef PACKAGE_NAME
-#undef PACKAGE_TARNAME
-#undef PACKAGE_VERSION
-#undef PACKAGE_STRING
-#undef PACKAGE_BUGREPORT
-#undef PACKAGE_URL
-#undef HAVE_DLADDR
-#undef HAVE_QSORT_R
-#include <ruby.h>
-
-#ifdef HAVE_RB_ERRINFO
-#define ruby_errinfo rb_errinfo()
-#endif
-
-/**
- * main routine, parses args and reads from console
- */
-int main(int argc, char *argv[])
-{
- int state, i;
- char buf[512];
-
- ruby_init();
- ruby_init_loadpath();
-
- rb_eval_string_protect("require 'dumm' and include Dumm", &state);
- if (state)
- {
- rb_p(ruby_errinfo);
- printf("Please install the ruby extension first!\n");
- }
- for (i = 1; i < argc; i++)
- {
- snprintf(buf, sizeof(buf), "load \"%s\"", argv[i]);
- printf("%s\n", buf);
- rb_eval_string_protect(buf, &state);
- if (state)
- {
- rb_p(ruby_errinfo);
- }
- }
- rb_require("irb");
- rb_require("irb/completion");
- rb_eval_string_protect("IRB.start", &state);
- if (state)
- {
- rb_p(ruby_errinfo);
- }
-
- ruby_finalize();
- return 0;
-}
-
+++ /dev/null
-/*
- * Copyright (C) 2008 Martin Willi
- * HSR 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 "dumm.h"
-
-#include <collections/linked_list.h>
-
-#include <sys/types.h>
-#include <unistd.h>
-#include <sched.h>
-
-#include <glib.h>
-#include <gtk/gtk.h>
-#include <vte/vte.h>
-#include <vte/reaper.h>
-
-/**
- * notebook page with vte and guest
- */
-typedef struct {
- gint num;
- GtkWidget *vte;
- guest_t *guest;
-} page_t;
-
-/**
- * Main window
- */
-GtkWidget *window;
-
-/**
- * notebook with guests, vtes
- */
-GtkWidget *notebook;
-
-/**
- * dumm context
- */
-dumm_t *dumm;
-
-/**
- * pages in notebook, page_t
- */
-linked_list_t *pages;
-
-/**
- * handle guest termination, SIGCHILD
- */
-static void child_exited(VteReaper *vtereaper, gint pid, gint status)
-{
- enumerator_t *enumerator;
- page_t *page;
-
- enumerator = pages->create_enumerator(pages);
- while (enumerator->enumerate(enumerator, (void**)&page))
- {
- if (page->guest->get_pid(page->guest) == pid)
- {
- page->guest->sigchild(page->guest);
- vte_terminal_feed(VTE_TERMINAL(page->vte),
- "\n\r--- guest terminated ---\n\r", -1);
- break;
- }
- }
- enumerator->destroy(enumerator);
-}
-
-static page_t* get_page(int num)
-{
- enumerator_t *enumerator;
- page_t *page, *found = NULL;
-
- enumerator = pages->create_enumerator(pages);
- while (enumerator->enumerate(enumerator, (void**)&page))
- {
- if (page->num == num)
- {
- found = page;
- break;
- }
- }
- enumerator->destroy(enumerator);
- return found;
-}
-
-/**
- * Guest invocation callback
- */
-static pid_t invoke(void *vte, guest_t *guest,
- char *args[], int argc)
-{
- GPid pid;
-
- if (vte_terminal_fork_command_full(VTE_TERMINAL(vte),
- VTE_PTY_NO_LASTLOG | VTE_PTY_NO_UTMP | VTE_PTY_NO_WTMP,
- NULL, args, NULL,
- G_SPAWN_CHILD_INHERITS_STDIN | G_SPAWN_SEARCH_PATH,
- NULL, NULL, &pid, NULL))
- {
- return pid;
- }
- return 0;
-}
-
-void idle(void)
-{
- gtk_main_iteration_do(FALSE);
- sched_yield();
-}
-
-static void start_guest()
-{
- page_t *page;
-
- page = get_page(gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)));
- if (page && page->guest->get_state(page->guest) == GUEST_STOPPED)
- {
- vte_terminal_feed(VTE_TERMINAL(page->vte),
- "--- starting guest ---\n\r", -1);
- page->guest->start(page->guest, invoke, VTE_TERMINAL(page->vte), idle);
- }
-}
-
-static void start_all_guests()
-{
- enumerator_t *enumerator;
- page_t *page;
-
- enumerator = pages->create_enumerator(pages);
- while (enumerator->enumerate(enumerator, (void**)&page))
- {
- if (page->guest->get_state(page->guest) == GUEST_STOPPED)
- {
- vte_terminal_feed(VTE_TERMINAL(page->vte),
- "--- starting all guests ---\n\r", -1);
- page->guest->start(page->guest, invoke,
- VTE_TERMINAL(page->vte), idle);
- }
- }
- enumerator->destroy(enumerator);
-}
-
-static void stop_guest()
-{
- page_t *page;
-
- page = get_page(gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)));
- if (page && page->guest->get_state(page->guest) == GUEST_RUNNING)
- {
- page->guest->stop(page->guest, idle);
- }
-}
-
-/**
- * quit signal handler
- */
-static void quit()
-{
- enumerator_t *enumerator;
- page_t *page;
-
- dumm->load_template(dumm, NULL);
-
- enumerator = pages->create_enumerator(pages);
- while (enumerator->enumerate(enumerator, &page))
- {
- if (page->guest->get_state(page->guest) != GUEST_STOPPED)
- {
- page->guest->stop(page->guest, idle);
- }
- }
- enumerator->destroy(enumerator);
- gtk_main_quit();
-}
-
-static void error_dialog(char *msg)
-{
- GtkWidget *error;
-
- error = gtk_message_dialog_new(GTK_WINDOW(window),
- GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,
- GTK_BUTTONS_CLOSE, msg);
- gtk_dialog_run(GTK_DIALOG(error));
- gtk_widget_destroy(error);
-}
-
-static void create_switch()
-{
- GtkWidget *dialog, *table, *label, *name;
- bridge_t *bridge;
-
- dialog = gtk_dialog_new_with_buttons("Create new switch", GTK_WINDOW(window),
- GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
- GTK_STOCK_NEW, GTK_RESPONSE_ACCEPT, NULL);
-
- table = gtk_table_new(1, 2, TRUE);
- gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table);
-
- label = gtk_label_new("Switch name");
- gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, 0, 0, 0, 0);
- gtk_widget_show(label);
-
- name = gtk_entry_new();
- gtk_table_attach(GTK_TABLE(table), name, 1, 2, 0, 1,
- GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0);
- gtk_widget_show(name);
-
- gtk_widget_show(table);
-
- while (TRUE)
- {
- switch (gtk_dialog_run(GTK_DIALOG(dialog)))
- {
- case GTK_RESPONSE_ACCEPT:
- {
- if (streq(gtk_entry_get_text(GTK_ENTRY(name)), ""))
- {
- continue;
- }
- bridge = dumm->create_bridge(dumm,
- (char*)gtk_entry_get_text(GTK_ENTRY(name)));
- if (!bridge)
- {
- error_dialog("creating bridge failed!");
- continue;
- }
- break;
- }
- default:
- break;
- }
- break;
- }
- gtk_widget_destroy(dialog);
-}
-
-static void delete_switch()
-{
-
-}
-
-static void connect_guest()
-{
- page_t *page;
- GtkWidget *dialog, *table, *label, *name, *box;
- bridge_t *bridge;
- iface_t *iface;
- enumerator_t *enumerator;
-
- page = get_page(gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)));
- if (!page || page->guest->get_state(page->guest) != GUEST_RUNNING)
- {
- return;
- }
-
- dialog = gtk_dialog_new_with_buttons("Connect guest", GTK_WINDOW(window),
- GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
- GTK_STOCK_NEW, GTK_RESPONSE_ACCEPT, NULL);
-
- table = gtk_table_new(2, 2, TRUE);
- gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table);
-
- label = gtk_label_new("Interface name");
- gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, 0, 0, 0, 0);
- gtk_widget_show(label);
-
- name = gtk_entry_new();
- gtk_table_attach(GTK_TABLE(table), name, 1, 2, 0, 1,
- GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0);
- gtk_widget_show(name);
-
- label = gtk_label_new("Connected switch");
- gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, 0, 0, 0, 0);
- gtk_widget_show(label);
-
- box = gtk_combo_box_new_text();
- gtk_table_attach(GTK_TABLE(table), box, 1, 2, 1, 2,
- GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0);
- enumerator = dumm->create_bridge_enumerator(dumm);
- while (enumerator->enumerate(enumerator, &bridge))
- {
- gtk_combo_box_append_text(GTK_COMBO_BOX(box), bridge->get_name(bridge));
- }
- enumerator->destroy(enumerator);
- gtk_widget_show(box);
-
- gtk_widget_show(table);
-
- while (TRUE)
- {
- switch (gtk_dialog_run(GTK_DIALOG(dialog)))
- {
- case GTK_RESPONSE_ACCEPT:
- {
- if (streq(gtk_entry_get_text(GTK_ENTRY(name)), ""))
- {
- continue;
- }
-
- iface = page->guest->create_iface(page->guest,
- (char*)gtk_entry_get_text(GTK_ENTRY(name)));
- if (!iface)
- {
- error_dialog("creating interface failed!");
- continue;
- }
- enumerator = dumm->create_bridge_enumerator(dumm);
- while (enumerator->enumerate(enumerator, &bridge))
- {
- if (!bridge->connect_iface(bridge, iface))
- {
- error_dialog("connecting interface failed!");
- }
- break;
- }
- enumerator->destroy(enumerator);
- break;
- }
- default:
- break;
- }
- break;
- }
- gtk_widget_destroy(dialog);
-}
-
-static void disconnect_guest()
-{
-
-}
-
-static void delete_guest()
-{
- page_t *page;
-
- page = get_page(gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)));
- if (page)
- {
- page->guest->stop(page->guest, idle);
- dumm->delete_guest(dumm, page->guest);
- gtk_notebook_remove_page(GTK_NOTEBOOK(notebook), page->num);
- pages->remove(pages, page, NULL);
- g_free(page);
- }
-}
-
-/**
- * create a new page for a guest
- */
-static page_t* create_page(guest_t *guest)
-{
- GtkWidget *label;
- page_t *page;
-
- page = g_new(page_t, 1);
- page->guest = guest;
- page->vte = vte_terminal_new();
- label = gtk_label_new(guest->get_name(guest));
- page->num = gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
- page->vte, label);
- gtk_widget_show(page->vte);
- pages->insert_last(pages, page);
- return page;
-}
-
-/**
- * create a new guest
- */
-static void create_guest()
-{
- guest_t *guest;
- GtkWidget *dialog, *table, *label, *name, *kernel, *master, *args;
-
- dialog = gtk_dialog_new_with_buttons("Create new guest", GTK_WINDOW(window),
- GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
- GTK_STOCK_NEW, GTK_RESPONSE_ACCEPT, NULL);
-
- table = gtk_table_new(4, 2, TRUE);
- gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table);
-
- label = gtk_label_new("Guest name");
- gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, 0, 0, 0, 0);
- gtk_widget_show(label);
-
- label = gtk_label_new("UML kernel");
- gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, 0, 0, 0, 0);
- gtk_widget_show(label);
-
- label = gtk_label_new("Master filesystem");
- gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, 0, 0, 0, 0);
- gtk_widget_show(label);
-
- label = gtk_label_new("Kernel arguments");
- gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, 0, 0, 0, 0);
- gtk_widget_show(label);
-
- name = gtk_entry_new();
- gtk_table_attach(GTK_TABLE(table), name, 1, 2, 0, 1,
- GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0);
- gtk_widget_show(name);
-
- kernel = gtk_file_chooser_button_new("Select UML kernel image",
- GTK_FILE_CHOOSER_ACTION_OPEN);
- gtk_table_attach(GTK_TABLE(table), kernel, 1, 2, 1, 2,
- GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0);
- gtk_widget_show(kernel);
-
- master = gtk_file_chooser_button_new("Select master filesystem",
- GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
- gtk_table_attach(GTK_TABLE(table), master, 1, 2, 2, 3,
- GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0);
- gtk_widget_show(master);
-
- args = gtk_entry_new();
- gtk_table_attach(GTK_TABLE(table), args, 1, 2, 3, 4,
- GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0, 0);
- gtk_widget_show(args);
-
- gtk_widget_show(table);
-
- while (TRUE)
- {
- switch (gtk_dialog_run(GTK_DIALOG(dialog)))
- {
- case GTK_RESPONSE_ACCEPT:
- {
- char *sname, *skernel, *smaster, *sargs;
- page_t *page;
-
- sname = (char*)gtk_entry_get_text(GTK_ENTRY(name));
- skernel = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(kernel));
- smaster = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(master));
- sargs = (char*)gtk_entry_get_text(GTK_ENTRY(args));
-
- if (!sname[0] || !skernel || !smaster)
- {
- continue;
- }
- guest = dumm->create_guest(dumm, sname, skernel, smaster, sargs);
- if (!guest)
- {
- error_dialog("creating guest failed!");
- continue;
- }
- page = create_page(guest);
- gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), page->num);
- break;
- }
- default:
- break;
- }
- break;
- }
- gtk_widget_destroy(dialog);
-}
-
-/**
- * main routine, parses args and reads from console
- */
-int main(int argc, char *argv[])
-{
- GtkWidget *menubar, *menu, *menuitem, *vbox;
- GtkWidget *dummMenu, *guestMenu, *switchMenu;
- enumerator_t *enumerator;
- guest_t *guest;
-
- library_init(NULL, "dumm");
- gtk_init(&argc, &argv);
-
- pages = linked_list_create();
- dumm = dumm_create(NULL);
-
- /* setup window */
- window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(quit), NULL);
- gtk_window_set_title(GTK_WINDOW (window), "Dumm");
- gtk_window_set_default_size(GTK_WINDOW (window), 1000, 500);
- g_signal_connect(G_OBJECT(vte_reaper_get()), "child-exited",
- G_CALLBACK(child_exited), NULL);
-
- /* add vbox with menubar, notebook */
- vbox = gtk_vbox_new(FALSE, 0);
- gtk_container_add(GTK_CONTAINER(window), vbox);
- menubar = gtk_menu_bar_new();
- gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
- notebook = gtk_notebook_new();
- g_object_set(G_OBJECT(notebook), "homogeneous", TRUE, NULL);
- gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_BOTTOM);
- gtk_container_add(GTK_CONTAINER(vbox), notebook);
-
- /* Dumm menu */
- menu = gtk_menu_new();
- dummMenu = gtk_menu_item_new_with_mnemonic("_Dumm");
- gtk_menu_bar_append(GTK_MENU_BAR(menubar), dummMenu);
- gtk_widget_show(dummMenu);
- gtk_menu_item_set_submenu(GTK_MENU_ITEM(dummMenu), menu);
-
- /* Dumm -> exit */
- menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL);
- g_signal_connect(G_OBJECT(menuitem), "activate",
- G_CALLBACK(quit), NULL);
- gtk_menu_append(GTK_MENU(menu), menuitem);
- gtk_widget_show(menuitem);
-
- /* Guest menu */
- menu = gtk_menu_new();
- guestMenu = gtk_menu_item_new_with_mnemonic("_Guest");
- gtk_menu_bar_append(GTK_MENU_BAR(menubar), guestMenu);
- gtk_widget_show(guestMenu);
- gtk_menu_item_set_submenu(GTK_MENU_ITEM(guestMenu), menu);
-
- /* Guest -> new */
- menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_NEW, NULL);
- g_signal_connect(G_OBJECT(menuitem), "activate",
- G_CALLBACK(create_guest), NULL);
- gtk_menu_append(GTK_MENU(menu), menuitem);
- gtk_widget_show(menuitem);
-
- /* Guest -> delete */
- menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_DELETE, NULL);
- g_signal_connect(G_OBJECT(menuitem), "activate",
- G_CALLBACK(delete_guest), NULL);
- gtk_menu_append(GTK_MENU(menu), menuitem);
- gtk_widget_show(menuitem);
-
- menuitem = gtk_separator_menu_item_new();
- gtk_menu_append(GTK_MENU(menu), menuitem);
- gtk_widget_show(menuitem);
-
- /* Guest -> start */
- menuitem = gtk_menu_item_new_with_mnemonic("_Start");
- g_signal_connect(G_OBJECT(menuitem), "activate",
- G_CALLBACK(start_guest), NULL);
- gtk_menu_append(GTK_MENU(menu), menuitem);
- gtk_widget_show(menuitem);
-
- /* Guest -> startall */
- menuitem = gtk_menu_item_new_with_mnemonic("Start _all");
- g_signal_connect(G_OBJECT(menuitem), "activate",
- G_CALLBACK(start_all_guests), NULL);
- gtk_menu_append(GTK_MENU(menu), menuitem);
- gtk_widget_show(menuitem);
-
- /* Guest -> stop */
- menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_STOP, NULL);
- g_signal_connect(G_OBJECT(menuitem), "activate",
- G_CALLBACK(stop_guest), NULL);
- gtk_menu_append(GTK_MENU(menu), menuitem);
- gtk_widget_show(menuitem);
-
- menuitem = gtk_separator_menu_item_new();
- gtk_menu_append(GTK_MENU(menu), menuitem);
- gtk_widget_show(menuitem);
-
- /* Guest -> connect */
- menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_CONNECT, NULL);
- g_signal_connect(G_OBJECT(menuitem), "activate",
- G_CALLBACK(connect_guest), NULL);
- gtk_menu_append(GTK_MENU(menu), menuitem);
- gtk_widget_show(menuitem);
-
- /* Guest -> disconnect */
- menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_DISCONNECT, NULL);
- g_signal_connect(G_OBJECT(menuitem), "activate",
- G_CALLBACK(disconnect_guest), NULL);
- gtk_menu_append(GTK_MENU(menu), menuitem);
- gtk_widget_set_sensitive(menuitem, FALSE);
- gtk_widget_show(menuitem);
-
- /* Switch menu */
- menu = gtk_menu_new();
- switchMenu = gtk_menu_item_new_with_mnemonic("_Switch");
- gtk_menu_bar_append(GTK_MENU_BAR(menubar), switchMenu);
- gtk_widget_show(switchMenu);
- gtk_menu_item_set_submenu(GTK_MENU_ITEM(switchMenu), menu);
-
- /* Switch -> new */
- menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_NEW, NULL);
- g_signal_connect(G_OBJECT(menuitem), "activate",
- G_CALLBACK(create_switch), NULL);
- gtk_menu_append(GTK_MENU(menu), menuitem);
- gtk_widget_show(menuitem);
-
- /* Switch -> delete */
- menuitem = gtk_image_menu_item_new_from_stock(GTK_STOCK_DELETE, NULL);
- g_signal_connect(G_OBJECT(menuitem), "activate",
- G_CALLBACK(delete_switch), NULL);
- gtk_menu_append(GTK_MENU(menu), menuitem);
- gtk_widget_set_sensitive(menuitem, FALSE);
- gtk_widget_show(menuitem);
-
- /* show widgets */
- gtk_widget_show(menubar);
- gtk_widget_show(notebook);
- gtk_widget_show(vbox);
- gtk_widget_show(window);
-
- /* fill notebook with guests */
- enumerator = dumm->create_guest_enumerator(dumm);
- while (enumerator->enumerate(enumerator, (void**)&guest))
- {
- create_page(guest);
- }
- enumerator->destroy(enumerator);
-
- gtk_main();
-
- dumm->destroy(dumm);
- pages->destroy_function(pages, g_free);
-
- library_deinit();
- return 0;
-}
-
+++ /dev/null
-/*
- * Copyright (C) 2007 Martin Willi
- * HSR Hochschule fuer Technik Rapperswil
- * Copyright (C) 2001-2004 Jeff Dike
- *
- * Based on the "uml_mconsole" utility from Jeff Dike.
- *
- * 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.
- */
-
-#define _GNU_SOURCE
-
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <sys/socket.h>
-#include <errno.h>
-#include <sys/un.h>
-
-#include <utils/debug.h>
-
-#include "mconsole.h"
-
-#define MCONSOLE_MAGIC 0xcafebabe
-#define MCONSOLE_VERSION 2
-#define MCONSOLE_MAX_DATA 512
-
-typedef struct private_mconsole_t private_mconsole_t;
-
-struct private_mconsole_t {
- /** public interface */
- mconsole_t public;
- /** mconsole socket */
- int console;
- /** notify socket */
- int notify;
- /** address of uml socket */
- struct sockaddr_un uml;
- /** idle function */
- void (*idle)(void);
-};
-
-/**
- * mconsole message format from "arch/um/include/mconsole.h"
- */
-typedef struct mconsole_request mconsole_request;
-/** mconsole request message */
-struct mconsole_request {
- uint32_t magic;
- uint32_t version;
- uint32_t len;
- char data[MCONSOLE_MAX_DATA];
-};
-
-
-typedef struct mconsole_reply mconsole_reply;
-/** mconsole reply message */
-struct mconsole_reply {
- uint32_t err;
- uint32_t more;
- uint32_t len;
- char data[MCONSOLE_MAX_DATA];
-};
-
-typedef struct mconsole_notify mconsole_notify;
-/** mconsole notify message */
-struct mconsole_notify {
- uint32_t magic;
- uint32_t version;
- enum {
- MCONSOLE_SOCKET,
- MCONSOLE_PANIC,
- MCONSOLE_HANG,
- MCONSOLE_USER_NOTIFY,
- } type;
- uint32_t len;
- char data[MCONSOLE_MAX_DATA];
-};
-
-/**
- * send a request to UML using mconsole
- */
-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, flags = 0;
- va_list args;
-
- memset(&request, 0, sizeof(request));
- request.magic = MCONSOLE_MAGIC;
- request.version = MCONSOLE_VERSION;
- va_start(args, command);
- request.len = vsnprintf(request.data, sizeof(request.data), command, args);
- va_end(args);
-
- if (this->idle)
- {
- flags = MSG_DONTWAIT;
- }
- do
- {
- if (this->idle)
- {
- this->idle();
- }
- len = sendto(this->console, &request, sizeof(request), flags,
- (struct sockaddr*)&this->uml, sizeof(this->uml));
- }
- while (len < 0 && (errno == EINTR || errno == EAGAIN));
-
- if (len < 0)
- {
- DBG1(DBG_LIB, "sending mconsole command to UML failed: %m");
- return -1;
- }
- do
- {
- len = recv(this->console, &reply, sizeof(reply), flags);
- if (len < 0 && (errno == EINTR || errno == EAGAIN))
- {
- if (this->idle)
- {
- this->idle();
- }
- continue;
- }
- if (len < 0)
- {
- DBG1(DBG_LIB, "receiving from mconsole failed: %m");
- return -1;
- }
- if (len > 0)
- {
- if (cb)
- {
- cb(data, reply.data, reply.len);
- }
- else if (reply.err)
- {
- if (reply.len && *reply.data)
- {
- DBG1(DBG_LIB, "received mconsole error %d: %.*s",
- reply.err, (int)reply.len, reply.data);
- }
- break;
- }
- }
- }
- while (reply.more);
-
- return reply.err;
-}
-
-/**
- * ignore error message
- */
-static void ignore(void *data, char *buf, size_t len)
-{
-}
-
-METHOD(mconsole_t, add_iface, bool,
- private_mconsole_t *this, char *guest, char *host)
-{
- int tries = 0;
-
- while (tries++ < 5)
- {
- if (request(this, ignore, NULL, "config %s=tuntap,%s", guest, host) == 0)
- {
- return TRUE;
- }
- usleep(10000 * tries * tries);
- }
- return FALSE;
-}
-
-METHOD(mconsole_t, del_iface, bool,
- private_mconsole_t *this, char *guest)
-{
- if (request(this, NULL, NULL, "remove %s", guest) != 0)
- {
- return FALSE;
- }
- return TRUE;
-}
-
-METHOD(mconsole_t, exec, int,
- private_mconsole_t *this, void(*cb)(void*,char*,size_t), void *data,
- char *cmd)
-{
- return request(this, cb, data, "%s", cmd);
-}
-
-/**
- * Poll until guest is ready
- */
-static void wait_bootup(private_mconsole_t *this)
-{
- /* wait for init process to appear */
- while (request(this, ignore, NULL, "exec ps -p 1 > /dev/null"))
- {
- if (this->idle)
- {
- this->idle();
- }
- usleep(100000);
- }
-}
-
-METHOD(mconsole_t, destroy, void,
- private_mconsole_t *this)
-{
- close(this->console);
- close(this->notify);
- free(this);
-}
-
-/**
- * setup the mconsole notify connection and wait for its readiness
- */
-static bool wait_for_notify(private_mconsole_t *this, char *nsock)
-{
- struct sockaddr_un addr;
- mconsole_notify notify;
- int len, flags = 0;
-
- this->notify = socket(AF_UNIX, SOCK_DGRAM, 0);
- if (this->notify < 0)
- {
- DBG1(DBG_LIB, "opening mconsole notify socket failed: %m");
- return FALSE;
- }
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- strncpy(addr.sun_path, nsock, sizeof(addr.sun_path));
- if (bind(this->notify, (struct sockaddr*)&addr, sizeof(addr)) < 0)
- {
- DBG1(DBG_LIB, "binding mconsole notify socket to '%s' failed: %m",
- nsock);
- close(this->notify);
- return FALSE;
- }
- if (this->idle)
- {
- flags = MSG_DONTWAIT;
- }
- do
- {
- if (this->idle)
- {
- this->idle();
- }
- len = recvfrom(this->notify, ¬ify, sizeof(notify), flags, NULL, 0);
- }
- while (len < 0 && (errno == EINTR || errno == EAGAIN));
-
- if (len < 0 || len >= sizeof(notify))
- {
- DBG1(DBG_LIB, "reading from mconsole notify socket failed: %m");
- close(this->notify);
- unlink(nsock);
- return FALSE;
- }
- if (notify.magic != MCONSOLE_MAGIC ||
- notify.version != MCONSOLE_VERSION ||
- notify.type != MCONSOLE_SOCKET)
- {
- DBG1(DBG_LIB, "received unexpected message from mconsole notify"
- " socket: %b", ¬ify, sizeof(notify));
- close(this->notify);
- unlink(nsock);
- return FALSE;
- }
- memset(&this->uml, 0, sizeof(this->uml));
- this->uml.sun_family = AF_UNIX;
- strncpy(this->uml.sun_path, (char*)¬ify.data, sizeof(this->uml.sun_path));
- return TRUE;
-}
-
-/**
- * setup the mconsole console connection
- */
-static bool setup_console(private_mconsole_t *this)
-{
- struct sockaddr_un addr;
-
- this->console = socket(AF_UNIX, SOCK_DGRAM, 0);
- if (this->console < 0)
- {
- DBG1(DBG_LIB, "opening mconsole socket failed: %m");
- return FALSE;
- }
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- snprintf(&addr.sun_path[1], sizeof(addr.sun_path)-1, "%5d-%d",
- getpid(), this->console);
- if (bind(this->console, (struct sockaddr*)&addr, sizeof(addr)) < 0)
- {
- DBG1(DBG_LIB, "binding mconsole socket to '%s' failed: %m",
- &addr.sun_path[1]);
- close(this->console);
- return FALSE;
- }
- return TRUE;
-}
-
-/**
- * create the mconsole instance
- */
-mconsole_t *mconsole_create(char *notify, void(*idle)(void))
-{
- private_mconsole_t *this;
-
- INIT(this,
- .public = {
- .add_iface = _add_iface,
- .del_iface = _del_iface,
- .exec = _exec,
- .destroy = _destroy,
- },
- .idle = idle,
- );
-
- if (!wait_for_notify(this, notify))
- {
- free(this);
- return NULL;
- }
-
- if (!setup_console(this))
- {
- close(this->notify);
- unlink(notify);
- free(this);
- return NULL;
- }
- unlink(notify);
-
- wait_bootup(this);
-
- return &this->public;
-}
-
+++ /dev/null
-/*
- * Copyright (C) 2007 Martin Willi
- * HSR 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 MCONSOLE_H
-#define MCONSOLE_H
-
-#include <library.h>
-
-typedef struct mconsole_t mconsole_t;
-
-/**
- * UML mconsole, change running UML configuration using mconsole.
- */
-struct mconsole_t {
-
- /**
- * Create a guest interface and connect it to tap host interface.
- *
- * @param guest name of the interface to create in the guest
- * @param host name of the tap device to connect guest to
- * @return TRUE if interface created
- */
- bool (*add_iface)(mconsole_t *this, char *guest, char *host);
-
- /**
- * Delete a guest interface.
- *
- * @param guest name of the interface to delete on the guest
- * @return TRUE if interface deleted
- */
- bool (*del_iface)(mconsole_t *this, char *guest);
-
- /**
- * Execute a command on the mconsole.
- *
- * @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
- */
- int (*exec)(mconsole_t *this, void(*cb)(void*,char*,size_t), void *data,
- char *cmd);
-
- /**
- * Destroy the mconsole instance
- */
- void (*destroy) (mconsole_t *this);
-};
-
-/**
- * Create a new mconsole connection to a guest.
- *
- * Waits for a notification from the guest through the notify socket and tries
- * to connect to the mconsole socket supplied in the received notification.
- *
- * @param notify unix notify socket path
- * @param idle idle function to call while waiting for responses
- * @return mconsole instance, or NULL if failed
- */
-mconsole_t *mconsole_create(char *notify, void(*idle)(void));
-
-#endif /* MCONSOLE_H */
-
+++ /dev/null
---- a/arch/um/drivers/mconsole_kern.c 2008-07-13 23:51:29.000000000 +0200
-+++ b/arch/um/drivers/mconsole_kern.c 2008-08-06 09:32:52.000000000 +0200
-@@ -4,6 +4,7 @@
- * Licensed under the GPL
- */
-
-+#include "linux/kmod.h"
- #include <linux/console.h>
- #include <linux/ctype.h>
- #include <linux/interrupt.h>
-@@ -18,6 +19,8 @@
- #include <linux/utsname.h>
- #include <linux/workqueue.h>
- #include <linux/mutex.h>
-+#include <linux/completion.h>
-+#include <linux/file.h>
- #include <asm/uaccess.h>
-
- #include "init.h"
-@@ -199,6 +202,65 @@
- }
- #endif
-
-+void mconsole_exec(struct mc_request *req)
-+{
-+ DECLARE_COMPLETION_ONSTACK(done);
-+ struct subprocess_info *sub_info;
-+ int res, len;
-+ struct file *out;
-+ char buf[MCONSOLE_MAX_DATA];
-+
-+ char *envp[] = {
-+ "HOME=/", "TERM=linux",
-+ "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin",
-+ NULL
-+ };
-+ char *argv[] = {
-+ "/bin/sh", "-c",
-+ req->request.data + strlen("exec "),
-+ NULL
-+ };
-+
-+ sub_info = call_usermodehelper_setup("/bin/sh", argv, envp);
-+ if (sub_info == NULL) {
-+ mconsole_reply(req, "call_usermodehelper_setup failed", 1, 0);
-+ return;
-+ }
-+ res = call_usermodehelper_stdoutpipe(sub_info, &out);
-+ if (res < 0) {
-+ call_usermodehelper_freeinfo(sub_info);
-+ mconsole_reply(req, "call_usermodehelper_stdoutpipe failed", 1, 0);
-+ return;
-+ }
-+
-+ call_usermodehelper_setcomplete(sub_info, &done);
-+
-+ res = call_usermodehelper_exec(sub_info, UMH_WAIT_EXT);
-+ if (res < 0) {
-+ call_usermodehelper_freeinfo(sub_info);
-+ mconsole_reply(req, "call_usermodehelper_exec failed", 1, 0);
-+ return;
-+ }
-+
-+ 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)
-+ break;
-+ mconsole_reply_len(req, buf, len, 0, 1);
-+ }
-+ fput(out);
-+
-+ wait_for_completion(&done);
-+ res = call_usermodehelper_getretval(sub_info) >> 8;
-+ call_usermodehelper_freeinfo(sub_info);
-+
-+ mconsole_reply_len(req, buf, len, res, 0);
-+}
-+
- void mconsole_proc(struct mc_request *req)
- {
- char path[64];
-@@ -270,6 +332,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 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-07-13 23:51:29.000000000 +0200
-+++ b/arch/um/drivers/mconsole_user.c 2008-07-15 15:41:54.000000000 +0200
-@@ -32,6 +32,7 @@
- { "stop", mconsole_stop, MCONSOLE_PROC },
- { "go", mconsole_go, MCONSOLE_INTR },
- { "log", mconsole_log, MCONSOLE_INTR },
-+ { "exec", mconsole_exec, MCONSOLE_PROC },
- { "proc", mconsole_proc, MCONSOLE_PROC },
- { "stack", mconsole_stack, MCONSOLE_INTR },
- };
---- a/arch/um/include/mconsole.h 2008-07-13 23:51:29.000000000 +0200
-+++ b/arch/um/include/mconsole.h 2008-07-15 15:41:54.000000000 +0200
-@@ -85,6 +85,7 @@
- extern void mconsole_stop(struct mc_request *req);
- extern void mconsole_go(struct mc_request *req);
- extern void mconsole_log(struct mc_request *req);
-+extern void mconsole_exec(struct mc_request *req);
- extern void mconsole_proc(struct mc_request *req);
- extern void mconsole_stack(struct mc_request *req);
-
---- a/kernel/kmod.c 2008-07-13 23:51:29.000000000 +0200
-+++ b/kernel/kmod.c 2008-07-31 14:46:31.000000000 +0200
-@@ -118,6 +118,7 @@
- struct subprocess_info {
- struct work_struct work;
- struct completion *complete;
-+ struct completion *executed;
- char *path;
- char **argv;
- char **envp;
-@@ -125,6 +126,7 @@
- enum umh_wait wait;
- int retval;
- struct file *stdin;
-+ struct file *stdout;
- void (*cleanup)(char **argv, char **envp);
- };
-
-@@ -160,8 +162,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};
- }
-
-@@ -243,7 +263,7 @@
- /* CLONE_VFORK: wait until the usermode helper has execve'd
- * successfully We need the data structures to stay around
- * until that is done. */
-- if (wait == UMH_WAIT_PROC || wait == UMH_NO_WAIT)
-+ if (wait == UMH_WAIT_PROC || wait == UMH_NO_WAIT || wait == UMH_WAIT_EXT)
- pid = kernel_thread(wait_for_helper, sub_info,
- CLONE_FS | CLONE_FILES | SIGCHLD);
- else
-@@ -254,6 +274,16 @@
- case UMH_NO_WAIT:
- break;
-
-+ case UMH_WAIT_EXT:
-+ if (pid > 0) {
-+ complete(sub_info->executed);
-+ break;
-+ }
-+ sub_info->retval = pid;
-+ complete(sub_info->executed);
-+ complete(sub_info->complete);
-+ break;
-+
- case UMH_WAIT_PROC:
- if (pid > 0)
- break;
-@@ -404,6 +434,19 @@
- }
- EXPORT_SYMBOL(call_usermodehelper_setcleanup);
-
-+void call_usermodehelper_setcomplete(struct subprocess_info *info,
-+ struct completion* complete)
-+{
-+ info->complete = complete;
-+}
-+EXPORT_SYMBOL(call_usermodehelper_setcomplete);
-+
-+int call_usermodehelper_getretval(struct subprocess_info *info)
-+{
-+ return info->retval;
-+}
-+EXPORT_SYMBOL(call_usermodehelper_getretval);
-+
- /**
- * call_usermodehelper_stdinpipe - set up a pipe to be used for stdin
- * @sub_info: a subprocess_info returned by call_usermodehelper_setup
-@@ -433,6 +476,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
-@@ -460,15 +526,22 @@
- goto out;
- }
-
-- sub_info->complete = &done;
-+ if (wait == UMH_WAIT_EXT)
-+ sub_info->executed = &done;
-+ else
-+ sub_info->complete = &done;
-+
- sub_info->wait = wait;
-
- queue_work(khelper_wq, &sub_info->work);
- if (wait == UMH_NO_WAIT) /* task has freed sub_info */
- goto unlock;
-+
- wait_for_completion(&done);
-- retval = sub_info->retval;
-
-+ retval = sub_info->retval;
-+ if (wait == UMH_WAIT_EXT) /* caller will free sub_info */
-+ goto unlock;
- out:
- call_usermodehelper_freeinfo(sub_info);
- unlock:
---- a/include/linux/kmod.h 2008-07-13 23:51:29.000000000 +0200
-+++ b/include/linux/kmod.h 2008-07-31 14:43:33.000000000 +0200
-@@ -38,6 +38,7 @@
- struct key;
- struct file;
- struct subprocess_info;
-+struct completion;
-
- /* Allocate a subprocess_info structure */
- struct subprocess_info *call_usermodehelper_setup(char *path,
-@@ -48,13 +49,20 @@
- struct key *session_keyring);
- int call_usermodehelper_stdinpipe(struct subprocess_info *sub_info,
- struct file **filp);
-+int call_usermodehelper_stdoutpipe(struct subprocess_info *sub_info,
-+ struct file **filp);
-+void call_usermodehelper_setcomplete(struct subprocess_info *sub_info,
-+ struct completion *complete);
- void call_usermodehelper_setcleanup(struct subprocess_info *info,
- void (*cleanup)(char **argv, char **envp));
-+int call_usermodehelper_getretval(struct subprocess_info *sub_info);
-
- enum umh_wait {
- UMH_NO_WAIT = -1, /* don't wait at all */
- UMH_WAIT_EXEC = 0, /* wait for the exec, but not the process */
- UMH_WAIT_PROC = 1, /* wait for the process to complete */
-+ UMH_WAIT_EXT = 2, /* wait for the exec then return and signal
-+ when the process is complete */
- };
-
- /* Actually execute the sub-process */
---- a/arch/um/Makefile 2008-07-13 23:51:29.000000000 +0200
-+++ b/arch/um/Makefile 2008-07-15 16:27:02.000000000 +0200
-@@ -77,6 +77,7 @@
- KERNEL_DEFINES = $(strip -Derrno=kernel_errno -Dsigprocmask=kernel_sigprocmask \
- -Dmktime=kernel_mktime $(ARCH_KERNEL_DEFINES))
- KBUILD_CFLAGS += $(KERNEL_DEFINES)
-+KBUILD_CFLAGS += $(call cc-option,-fno-unit-at-a-time,)
-
- PHONY += linux
-
---- a/arch/um/Makefile-i386 2008-07-13 23:51:29.000000000 +0200
-+++ b/arch/um/Makefile-i386 2008-07-15 16:23:57.000000000 +0200
-@@ -32,11 +32,4 @@
- # an unresolved reference.
- cflags-y += -ffreestanding
-
--# Disable unit-at-a-time mode on pre-gcc-4.0 compilers, it makes gcc use
--# a lot more stack due to the lack of sharing of stacklots. Also, gcc
--# 4.3.0 needs -funit-at-a-time for extern inline functions.
--KBUILD_CFLAGS += $(shell if [ $(call cc-version) -lt 0400 ] ; then \
-- echo $(call cc-option,-fno-unit-at-a-time); \
-- else echo $(call cc-option,-funit-at-a-time); fi ;)
--
- KBUILD_CFLAGS += $(cflags-y)
---- a/arch/um/Makefile-x86_64 2008-07-13 23:51:29.000000000 +0200
-+++ b/arch/um/Makefile-x86_64 2008-07-15 16:24:20.000000000 +0200
-@@ -21,6 +21,3 @@
-
- LINK-$(CONFIG_LD_SCRIPT_DYN) += -Wl,-rpath,/lib64
- LINK-y += -m64
--
--# Do unit-at-a-time unconditionally on x86_64, following the host
--KBUILD_CFLAGS += $(call cc-option,-funit-at-a-time)
---- a/arch/um/drivers/line.c 2008-07-13 23:51:29.000000000 +0200
-+++ b/arch/um/drivers/line.c 2008-07-28 15:13:19.000000000 +0200
-@@ -876,6 +876,6 @@
- return base;
- }
-
-- snprintf(title, len, "%s (%s)", base, umid);
-+ snprintf(title, len, "%s (%s)", umid, base);
- return title;
- }
+++ /dev/null
---- a/arch/um/drivers/mconsole_kern.c 2008-07-13 23:51:29.000000000 +0200
-+++ b/arch/um/drivers/mconsole_kern.c 2008-10-07 11:03:31.000000000 +0200
-@@ -4,6 +4,7 @@
- * Licensed under the GPL
- */
-
-+#include "linux/kmod.h"
- #include <linux/console.h>
- #include <linux/ctype.h>
- #include <linux/interrupt.h>
-@@ -18,6 +19,8 @@
- #include <linux/utsname.h>
- #include <linux/workqueue.h>
- #include <linux/mutex.h>
-+#include <linux/completion.h>
-+#include <linux/file.h>
- #include <asm/uaccess.h>
-
- #include "init.h"
-@@ -199,6 +202,65 @@
- }
- #endif
-
-+void mconsole_exec(struct mc_request *req)
-+{
-+ DECLARE_COMPLETION_ONSTACK(done);
-+ struct subprocess_info *sub_info;
-+ int res, len;
-+ struct file *out;
-+ char buf[MCONSOLE_MAX_DATA];
-+
-+ char *envp[] = {
-+ "HOME=/", "TERM=linux",
-+ "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin",
-+ NULL
-+ };
-+ char *argv[] = {
-+ "/bin/sh", "-c",
-+ req->request.data + strlen("exec "),
-+ NULL
-+ };
-+
-+ sub_info = call_usermodehelper_setup("/bin/sh", argv, envp, GFP_ATOMIC);
-+ if (sub_info == NULL) {
-+ mconsole_reply(req, "call_usermodehelper_setup failed", 1, 0);
-+ return;
-+ }
-+ res = call_usermodehelper_stdoutpipe(sub_info, &out);
-+ if (res < 0) {
-+ call_usermodehelper_freeinfo(sub_info);
-+ mconsole_reply(req, "call_usermodehelper_stdoutpipe failed", 1, 0);
-+ return;
-+ }
-+
-+ call_usermodehelper_setcomplete(sub_info, &done);
-+
-+ res = call_usermodehelper_exec(sub_info, UMH_WAIT_EXT);
-+ if (res < 0) {
-+ call_usermodehelper_freeinfo(sub_info);
-+ mconsole_reply(req, "call_usermodehelper_exec failed", 1, 0);
-+ return;
-+ }
-+
-+ 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)
-+ break;
-+ mconsole_reply_len(req, buf, len, 0, 1);
-+ }
-+ fput(out);
-+
-+ wait_for_completion(&done);
-+ res = call_usermodehelper_getretval(sub_info) >> 8;
-+ call_usermodehelper_freeinfo(sub_info);
-+
-+ mconsole_reply_len(req, buf, len, res, 0);
-+}
-+
- void mconsole_proc(struct mc_request *req)
- {
- char path[64];
-@@ -270,6 +332,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 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-07-13 23:51:29.000000000 +0200
-+++ b/arch/um/drivers/mconsole_user.c 2008-10-07 11:00:55.000000000 +0200
-@@ -32,6 +32,7 @@
- { "stop", mconsole_stop, MCONSOLE_PROC },
- { "go", mconsole_go, MCONSOLE_INTR },
- { "log", mconsole_log, MCONSOLE_INTR },
-+ { "exec", mconsole_exec, MCONSOLE_PROC },
- { "proc", mconsole_proc, MCONSOLE_PROC },
- { "stack", mconsole_stack, MCONSOLE_INTR },
- };
---- a/arch/um/include/mconsole.h 2008-07-13 23:51:29.000000000 +0200
-+++ b/arch/um/include/mconsole.h 2008-10-07 11:00:55.000000000 +0200
-@@ -85,6 +85,7 @@
- extern void mconsole_stop(struct mc_request *req);
- extern void mconsole_go(struct mc_request *req);
- extern void mconsole_log(struct mc_request *req);
-+extern void mconsole_exec(struct mc_request *req);
- extern void mconsole_proc(struct mc_request *req);
- extern void mconsole_stack(struct mc_request *req);
-
---- a/kernel/kmod.c 2008-10-07 10:31:12.000000000 +0200
-+++ b/kernel/kmod.c 2008-10-07 11:07:37.000000000 +0200
-@@ -118,6 +118,7 @@
- struct subprocess_info {
- struct work_struct work;
- struct completion *complete;
-+ struct completion *executed;
- char *path;
- char **argv;
- char **envp;
-@@ -125,6 +126,7 @@
- enum umh_wait wait;
- int retval;
- struct file *stdin;
-+ struct file *stdout;
- void (*cleanup)(char **argv, char **envp);
- };
-
-@@ -160,8 +162,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};
- }
-
-@@ -243,7 +263,7 @@
- /* CLONE_VFORK: wait until the usermode helper has execve'd
- * successfully We need the data structures to stay around
- * until that is done. */
-- if (wait == UMH_WAIT_PROC || wait == UMH_NO_WAIT)
-+ if (wait == UMH_WAIT_PROC || wait == UMH_NO_WAIT || wait == UMH_WAIT_EXT)
- pid = kernel_thread(wait_for_helper, sub_info,
- CLONE_FS | CLONE_FILES | SIGCHLD);
- else
-@@ -254,6 +274,16 @@
- case UMH_NO_WAIT:
- break;
-
-+ case UMH_WAIT_EXT:
-+ if (pid > 0) {
-+ complete(sub_info->executed);
-+ break;
-+ }
-+ sub_info->retval = pid;
-+ complete(sub_info->executed);
-+ complete(sub_info->complete);
-+ break;
-+
- case UMH_WAIT_PROC:
- if (pid > 0)
- break;
-@@ -405,6 +435,19 @@
- }
- EXPORT_SYMBOL(call_usermodehelper_setcleanup);
-
-+void call_usermodehelper_setcomplete(struct subprocess_info *info,
-+ struct completion* complete)
-+{
-+ info->complete = complete;
-+}
-+EXPORT_SYMBOL(call_usermodehelper_setcomplete);
-+
-+int call_usermodehelper_getretval(struct subprocess_info *info)
-+{
-+ return info->retval;
-+}
-+EXPORT_SYMBOL(call_usermodehelper_getretval);
-+
- /**
- * call_usermodehelper_stdinpipe - set up a pipe to be used for stdin
- * @sub_info: a subprocess_info returned by call_usermodehelper_setup
-@@ -434,6 +477,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(0);
-+ if (IS_ERR(f))
-+ return PTR_ERR(f);
-+ sub_info->stdout = f;
-+
-+ f = create_read_pipe(f, 0);
-+ 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
-@@ -461,15 +527,22 @@
- goto out;
- }
-
-- sub_info->complete = &done;
-+ if (wait == UMH_WAIT_EXT)
-+ sub_info->executed = &done;
-+ else
-+ sub_info->complete = &done;
-+
- sub_info->wait = wait;
-
- queue_work(khelper_wq, &sub_info->work);
- if (wait == UMH_NO_WAIT) /* task has freed sub_info */
- goto unlock;
-+
- wait_for_completion(&done);
-- retval = sub_info->retval;
-
-+ retval = sub_info->retval;
-+ if (wait == UMH_WAIT_EXT) /* caller will free sub_info */
-+ goto unlock;
- out:
- call_usermodehelper_freeinfo(sub_info);
- unlock:
---- a/include/linux/kmod.h 2008-10-07 10:31:11.000000000 +0200
-+++ b/include/linux/kmod.h 2008-10-07 11:00:55.000000000 +0200
-@@ -40,6 +40,7 @@
- struct key;
- struct file;
- struct subprocess_info;
-+struct completion;
-
- /* Allocate a subprocess_info structure */
- struct subprocess_info *call_usermodehelper_setup(char *path, char **argv,
-@@ -50,13 +51,20 @@
- struct key *session_keyring);
- int call_usermodehelper_stdinpipe(struct subprocess_info *sub_info,
- struct file **filp);
-+int call_usermodehelper_stdoutpipe(struct subprocess_info *sub_info,
-+ struct file **filp);
-+void call_usermodehelper_setcomplete(struct subprocess_info *sub_info,
-+ struct completion *complete);
- void call_usermodehelper_setcleanup(struct subprocess_info *info,
- void (*cleanup)(char **argv, char **envp));
-+int call_usermodehelper_getretval(struct subprocess_info *sub_info);
-
- enum umh_wait {
- UMH_NO_WAIT = -1, /* don't wait at all */
- UMH_WAIT_EXEC = 0, /* wait for the exec, but not the process */
- UMH_WAIT_PROC = 1, /* wait for the process to complete */
-+ UMH_WAIT_EXT = 2, /* wait for the exec then return and signal
-+ when the process is complete */
- };
-
- /* Actually execute the sub-process */
---- a/arch/um/Makefile 2008-07-13 23:51:29.000000000 +0200
-+++ b/arch/um/Makefile 2008-10-07 11:00:55.000000000 +0200
-@@ -77,6 +77,7 @@
- KERNEL_DEFINES = $(strip -Derrno=kernel_errno -Dsigprocmask=kernel_sigprocmask \
- -Dmktime=kernel_mktime $(ARCH_KERNEL_DEFINES))
- KBUILD_CFLAGS += $(KERNEL_DEFINES)
-+KBUILD_CFLAGS += $(call cc-option,-fno-unit-at-a-time,)
-
- PHONY += linux
-
---- a/arch/um/Makefile-i386 2008-07-13 23:51:29.000000000 +0200
-+++ b/arch/um/Makefile-i386 2008-10-07 11:00:55.000000000 +0200
-@@ -32,11 +32,4 @@
- # an unresolved reference.
- cflags-y += -ffreestanding
-
--# Disable unit-at-a-time mode on pre-gcc-4.0 compilers, it makes gcc use
--# a lot more stack due to the lack of sharing of stacklots. Also, gcc
--# 4.3.0 needs -funit-at-a-time for extern inline functions.
--KBUILD_CFLAGS += $(shell if [ $(call cc-version) -lt 0400 ] ; then \
-- echo $(call cc-option,-fno-unit-at-a-time); \
-- else echo $(call cc-option,-funit-at-a-time); fi ;)
--
- KBUILD_CFLAGS += $(cflags-y)
---- a/arch/um/Makefile-x86_64 2008-07-13 23:51:29.000000000 +0200
-+++ b/arch/um/Makefile-x86_64 2008-10-07 11:00:55.000000000 +0200
-@@ -21,6 +21,3 @@
-
- LINK-$(CONFIG_LD_SCRIPT_DYN) += -Wl,-rpath,/lib64
- LINK-y += -m64
--
--# Do unit-at-a-time unconditionally on x86_64, following the host
--KBUILD_CFLAGS += $(call cc-option,-funit-at-a-time)
---- a/arch/um/drivers/line.c 2008-10-07 10:31:00.000000000 +0200
-+++ b/arch/um/drivers/line.c 2008-10-07 11:00:55.000000000 +0200
-@@ -864,6 +864,6 @@
- return base;
- }
-
-- snprintf(title, len, "%s (%s)", base, umid);
-+ snprintf(title, len, "%s (%s)", umid, base);
- return title;
- }
+++ /dev/null
---- a/arch/um/drivers/line.c
-+++ b/arch/um/drivers/line.c
-@@ -866,6 +866,6 @@ char *add_xterm_umid(char *base)
- return base;
- }
-
-- snprintf(title, len, "%s (%s)", base, umid);
-+ snprintf(title, len, "%s (%s)", umid, base);
- return title;
- }
---- a/arch/um/drivers/mconsole_kern.c
-+++ b/arch/um/drivers/mconsole_kern.c
-@@ -4,6 +4,7 @@
- * Licensed under the GPL
- */
-
-+#include "linux/kmod.h"
- #include <linux/console.h>
- #include <linux/ctype.h>
- #include <linux/interrupt.h>
-@@ -20,6 +21,8 @@
- #include <linux/un.h>
- #include <linux/workqueue.h>
- #include <linux/mutex.h>
-+#include <linux/completion.h>
-+#include <linux/file.h>
- #include <asm/uaccess.h>
-
- #include "init.h"
-@@ -201,6 +204,65 @@ void mconsole_proc(struct mc_request *req)
- }
- #endif
-
-+void mconsole_exec(struct mc_request *req)
-+{
-+ DECLARE_COMPLETION_ONSTACK(done);
-+ struct subprocess_info *sub_info;
-+ int res, len;
-+ struct file *out;
-+ char buf[MCONSOLE_MAX_DATA];
-+
-+ char *envp[] = {
-+ "HOME=/", "TERM=linux",
-+ "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin",
-+ NULL
-+ };
-+ char *argv[] = {
-+ "/bin/sh", "-c",
-+ req->request.data + strlen("exec "),
-+ NULL
-+ };
-+
-+ sub_info = call_usermodehelper_setup("/bin/sh", argv, envp, GFP_ATOMIC);
-+ if (sub_info == NULL) {
-+ mconsole_reply(req, "call_usermodehelper_setup failed", 1, 0);
-+ return;
-+ }
-+ res = call_usermodehelper_stdoutpipe(sub_info, &out);
-+ if (res < 0) {
-+ call_usermodehelper_freeinfo(sub_info);
-+ mconsole_reply(req, "call_usermodehelper_stdoutpipe failed", 1, 0);
-+ return;
-+ }
-+
-+ call_usermodehelper_setcomplete(sub_info, &done);
-+
-+ res = call_usermodehelper_exec(sub_info, UMH_WAIT_EXT);
-+ if (res < 0) {
-+ call_usermodehelper_freeinfo(sub_info);
-+ mconsole_reply(req, "call_usermodehelper_exec failed", 1, 0);
-+ return;
-+ }
-+
-+ 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)
-+ break;
-+ mconsole_reply_len(req, buf, len, 0, 1);
-+ }
-+ fput(out);
-+
-+ wait_for_completion(&done);
-+ res = call_usermodehelper_getretval(sub_info) >> 8;
-+ call_usermodehelper_freeinfo(sub_info);
-+
-+ mconsole_reply_len(req, buf, len, res, 0);
-+}
-+
- void mconsole_proc(struct mc_request *req)
- {
- char path[64];
-@@ -272,6 +334,7 @@ void mconsole_proc(struct mc_request *req)
- 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 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
-+++ b/arch/um/drivers/mconsole_user.c
-@@ -32,6 +32,7 @@ static struct mconsole_command commands[] = {
- { "stop", mconsole_stop, MCONSOLE_PROC },
- { "go", mconsole_go, MCONSOLE_INTR },
- { "log", mconsole_log, MCONSOLE_INTR },
-+ { "exec", mconsole_exec, MCONSOLE_PROC },
- { "proc", mconsole_proc, MCONSOLE_PROC },
- { "stack", mconsole_stack, MCONSOLE_INTR },
- };
---- a/arch/um/include/shared/mconsole.h
-+++ b/arch/um/include/shared/mconsole.h
-@@ -85,6 +85,7 @@ extern void mconsole_cad(struct mc_request *req);
- extern void mconsole_stop(struct mc_request *req);
- extern void mconsole_go(struct mc_request *req);
- extern void mconsole_log(struct mc_request *req);
-+extern void mconsole_exec(struct mc_request *req);
- extern void mconsole_proc(struct mc_request *req);
- extern void mconsole_stack(struct mc_request *req);
-
---- a/include/linux/kmod.h
-+++ b/include/linux/kmod.h
-@@ -40,6 +40,7 @@ static inline int request_module(const char * name, ...) { return -ENOSYS; }
- struct key;
- struct file;
- struct subprocess_info;
-+struct completion;
-
- /* Allocate a subprocess_info structure */
- struct subprocess_info *call_usermodehelper_setup(char *path, char **argv,
-@@ -50,13 +51,20 @@ void call_usermodehelper_setkeys(struct subprocess_info *info,
- struct key *session_keyring);
- int call_usermodehelper_stdinpipe(struct subprocess_info *sub_info,
- struct file **filp);
-+int call_usermodehelper_stdoutpipe(struct subprocess_info *sub_info,
-+ struct file **filp);
-+void call_usermodehelper_setcomplete(struct subprocess_info *sub_info,
-+ struct completion *complete);
- void call_usermodehelper_setcleanup(struct subprocess_info *info,
- void (*cleanup)(char **argv, char **envp));
-+int call_usermodehelper_getretval(struct subprocess_info *sub_info);
-
- enum umh_wait {
- UMH_NO_WAIT = -1, /* don't wait at all */
- UMH_WAIT_EXEC = 0, /* wait for the exec, but not the process */
- UMH_WAIT_PROC = 1, /* wait for the process to complete */
-+ UMH_WAIT_EXT = 2, /* wait for the exec then return and signal
-+ when the process is complete */
- };
-
- /* Actually execute the sub-process */
---- a/kernel/kmod.c
-+++ b/kernel/kmod.c
-@@ -118,6 +118,7 @@ EXPORT_SYMBOL(request_module);
- struct subprocess_info {
- struct work_struct work;
- struct completion *complete;
-+ struct completion *executed;
- char *path;
- char **argv;
- char **envp;
-@@ -125,6 +126,7 @@ struct subprocess_info {
- enum umh_wait wait;
- int retval;
- struct file *stdin;
-+ struct file *stdout;
- void (*cleanup)(char **argv, char **envp);
- };
-
-@@ -160,8 +162,26 @@ static int ____call_usermodehelper(void *data)
- 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};
- }
-
-@@ -243,7 +263,7 @@ static void __call_usermodehelper(struct work_struct *work)
- /* CLONE_VFORK: wait until the usermode helper has execve'd
- * successfully We need the data structures to stay around
- * until that is done. */
-- if (wait == UMH_WAIT_PROC || wait == UMH_NO_WAIT)
-+ if (wait == UMH_WAIT_PROC || wait == UMH_NO_WAIT || wait == UMH_WAIT_EXT)
- pid = kernel_thread(wait_for_helper, sub_info,
- CLONE_FS | CLONE_FILES | SIGCHLD);
- else
-@@ -254,6 +274,16 @@ static void __call_usermodehelper(struct work_struct *work)
- case UMH_NO_WAIT:
- break;
-
-+ case UMH_WAIT_EXT:
-+ if (pid > 0) {
-+ complete(sub_info->executed);
-+ break;
-+ }
-+ sub_info->retval = pid;
-+ complete(sub_info->executed);
-+ complete(sub_info->complete);
-+ break;
-+
- case UMH_WAIT_PROC:
- if (pid > 0)
- break;
-@@ -397,6 +427,19 @@ void call_usermodehelper_setcleanup(struct subprocess_info *info,
- }
- EXPORT_SYMBOL(call_usermodehelper_setcleanup);
-
-+void call_usermodehelper_setcomplete(struct subprocess_info *info,
-+ struct completion* complete)
-+{
-+ info->complete = complete;
-+}
-+EXPORT_SYMBOL(call_usermodehelper_setcomplete);
-+
-+int call_usermodehelper_getretval(struct subprocess_info *info)
-+{
-+ return info->retval;
-+}
-+EXPORT_SYMBOL(call_usermodehelper_getretval);
-+
- /**
- * call_usermodehelper_stdinpipe - set up a pipe to be used for stdin
- * @sub_info: a subprocess_info returned by call_usermodehelper_setup
-@@ -426,6 +469,29 @@ int call_usermodehelper_stdinpipe(struct subprocess_info *sub_info,
- }
- EXPORT_SYMBOL(call_usermodehelper_stdinpipe);
-
-+int call_usermodehelper_stdoutpipe(struct subprocess_info *sub_info,
-+ struct file **filp)
-+{
-+ struct file *f;
-+
-+ f = create_write_pipe(0);
-+ if (IS_ERR(f))
-+ return PTR_ERR(f);
-+ sub_info->stdout = f;
-+
-+ f = create_read_pipe(f, 0);
-+ 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
-@@ -453,15 +519,22 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info,
- goto out;
- }
-
-- sub_info->complete = &done;
-+ if (wait == UMH_WAIT_EXT)
-+ sub_info->executed = &done;
-+ else
-+ sub_info->complete = &done;
-+
- sub_info->wait = wait;
-
- queue_work(khelper_wq, &sub_info->work);
- if (wait == UMH_NO_WAIT) /* task has freed sub_info */
- goto unlock;
-+
- wait_for_completion(&done);
-- retval = sub_info->retval;
-
-+ retval = sub_info->retval;
-+ if (wait == UMH_WAIT_EXT) /* caller will free sub_info */
-+ goto unlock;
- out:
- call_usermodehelper_freeinfo(sub_info);
- unlock:
+++ /dev/null
-diff --git a/.gitignore b/.gitignore
-index 869e1a3..978e430 100644
---- a/.gitignore
-+++ b/.gitignore
-@@ -32,6 +32,7 @@
- tags
- TAGS
- vmlinux
-+linux
- System.map
- Module.markers
- Module.symvers
-diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
-index 14a102e..0acfaeb 100644
---- a/arch/um/drivers/line.c
-+++ b/arch/um/drivers/line.c
-@@ -866,6 +866,6 @@ char *add_xterm_umid(char *base)
- return base;
- }
-
-- snprintf(title, len, "%s (%s)", base, umid);
-+ snprintf(title, len, "%s (%s)", umid, base);
- return title;
- }
-diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c
-index e14629c..c488930 100644
---- a/arch/um/drivers/mconsole_kern.c
-+++ b/arch/um/drivers/mconsole_kern.c
-@@ -4,6 +4,7 @@
- * Licensed under the GPL
- */
-
-+#include "linux/kmod.h"
- #include <linux/console.h>
- #include <linux/ctype.h>
- #include <linux/interrupt.h>
-@@ -20,6 +21,8 @@
- #include <linux/un.h>
- #include <linux/workqueue.h>
- #include <linux/mutex.h>
-+#include <linux/completion.h>
-+#include <linux/file.h>
- #include <asm/uaccess.h>
-
- #include "init.h"
-@@ -202,6 +205,65 @@ void mconsole_proc(struct mc_request *req)
- }
- #endif
-
-+void mconsole_exec(struct mc_request *req)
-+{
-+ DECLARE_COMPLETION_ONSTACK(done);
-+ struct subprocess_info *sub_info;
-+ int res, len;
-+ struct file *out;
-+ char buf[MCONSOLE_MAX_DATA];
-+
-+ char *envp[] = {
-+ "HOME=/", "TERM=linux",
-+ "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin",
-+ NULL
-+ };
-+ char *argv[] = {
-+ "/bin/sh", "-c",
-+ req->request.data + strlen("exec "),
-+ NULL
-+ };
-+
-+ sub_info = call_usermodehelper_setup("/bin/sh", argv, envp, GFP_ATOMIC);
-+ if (sub_info == NULL) {
-+ mconsole_reply(req, "call_usermodehelper_setup failed", 1, 0);
-+ return;
-+ }
-+ res = call_usermodehelper_stdoutpipe(sub_info, &out);
-+ if (res < 0) {
-+ call_usermodehelper_freeinfo(sub_info);
-+ mconsole_reply(req, "call_usermodehelper_stdoutpipe failed", 1, 0);
-+ return;
-+ }
-+
-+ call_usermodehelper_setcomplete(sub_info, &done);
-+
-+ res = call_usermodehelper_exec(sub_info, UMH_WAIT_EXT);
-+ if (res < 0) {
-+ call_usermodehelper_freeinfo(sub_info);
-+ mconsole_reply(req, "call_usermodehelper_exec failed", 1, 0);
-+ return;
-+ }
-+
-+ for (;;) {
-+ len = out->f_op->read(out, buf, sizeof(buf), &out->f_pos);
-+ if (len < 0) {
-+ mconsole_reply(req, "reading output failed", 1, 0);
-+ break;
-+ }
-+ if (len == 0)
-+ break;
-+ mconsole_reply_len(req, buf, len, 0, 1);
-+ }
-+ fput(out);
-+
-+ wait_for_completion(&done);
-+ res = call_usermodehelper_getretval(sub_info) >> 8;
-+ call_usermodehelper_freeinfo(sub_info);
-+
-+ mconsole_reply_len(req, buf, len, res, 0);
-+}
-+
- void mconsole_proc(struct mc_request *req)
- {
- char path[64];
-@@ -273,6 +335,7 @@ void mconsole_proc(struct mc_request *req)
- 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 synchronously\n\
- proc <file> - returns the contents of the UML's /proc/<file>\n\
- stack <pid> - returns the stack of the specified pid\n\
- "
-diff --git a/arch/um/drivers/mconsole_user.c b/arch/um/drivers/mconsole_user.c
-index f8cf4c8..019d89f 100644
---- a/arch/um/drivers/mconsole_user.c
-+++ b/arch/um/drivers/mconsole_user.c
-@@ -32,6 +32,7 @@ static struct mconsole_command commands[] = {
- { "stop", mconsole_stop, MCONSOLE_PROC },
- { "go", mconsole_go, MCONSOLE_INTR },
- { "log", mconsole_log, MCONSOLE_INTR },
-+ { "exec", mconsole_exec, MCONSOLE_PROC },
- { "proc", mconsole_proc, MCONSOLE_PROC },
- { "stack", mconsole_stack, MCONSOLE_INTR },
- };
-diff --git a/arch/um/include/.gitignore b/arch/um/include/.gitignore
-new file mode 100644
-index 0000000..4c14eba
---- /dev/null
-+++ b/arch/um/include/.gitignore
-@@ -0,0 +1,2 @@
-+shared/kern_constants.h
-+shared/user_constants.h
-diff --git a/arch/um/include/shared/mconsole.h b/arch/um/include/shared/mconsole.h
-index c139ae1..dfb83b1 100644
---- a/arch/um/include/shared/mconsole.h
-+++ b/arch/um/include/shared/mconsole.h
-@@ -85,6 +85,7 @@ extern void mconsole_cad(struct mc_request *req);
- extern void mconsole_stop(struct mc_request *req);
- extern void mconsole_go(struct mc_request *req);
- extern void mconsole_log(struct mc_request *req);
-+extern void mconsole_exec(struct mc_request *req);
- extern void mconsole_proc(struct mc_request *req);
- extern void mconsole_stack(struct mc_request *req);
-
-diff --git a/arch/um/kernel/.gitignore b/arch/um/kernel/.gitignore
-new file mode 100644
-index 0000000..803397e
---- /dev/null
-+++ b/arch/um/kernel/.gitignore
-@@ -0,0 +1,3 @@
-+config.c
-+config.tmp
-+vmlinux.lds
-diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c
-index b5afcfd..b598128 100644
---- a/arch/um/os-Linux/file.c
-+++ b/arch/um/os-Linux/file.c
-@@ -521,6 +521,8 @@ int os_create_unix_socket(const char *file, int len, int close_on_exec)
-
- addr.sun_family = AF_UNIX;
-
-+ if (len > sizeof(addr.sun_path))
-+ len = sizeof(addr.sun_path);
- snprintf(addr.sun_path, len, "%s", file);
-
- err = bind(sock, (struct sockaddr *) &addr, sizeof(addr));
-diff --git a/include/linux/kmod.h b/include/linux/kmod.h
-index 92213a9..db07018 100644
---- a/include/linux/kmod.h
-+++ b/include/linux/kmod.h
-@@ -40,6 +40,7 @@ static inline int request_module(const char * name, ...) { return -ENOSYS; }
- struct key;
- struct file;
- struct subprocess_info;
-+struct completion;
-
- /* Allocate a subprocess_info structure */
- struct subprocess_info *call_usermodehelper_setup(char *path, char **argv,
-@@ -50,13 +51,20 @@ void call_usermodehelper_setkeys(struct subprocess_info *info,
- struct key *session_keyring);
- int call_usermodehelper_stdinpipe(struct subprocess_info *sub_info,
- struct file **filp);
-+int call_usermodehelper_stdoutpipe(struct subprocess_info *sub_info,
-+ struct file **filp);
-+void call_usermodehelper_setcomplete(struct subprocess_info *sub_info,
-+ struct completion *complete);
- void call_usermodehelper_setcleanup(struct subprocess_info *info,
- void (*cleanup)(char **argv, char **envp));
-+int call_usermodehelper_getretval(struct subprocess_info *sub_info);
-
- enum umh_wait {
- UMH_NO_WAIT = -1, /* don't wait at all */
- UMH_WAIT_EXEC = 0, /* wait for the exec, but not the process */
- UMH_WAIT_PROC = 1, /* wait for the process to complete */
-+ UMH_WAIT_EXT = 2, /* wait for the exec then return and signal
-+ when the process is complete */
- };
-
- /* Actually execute the sub-process */
-diff --git a/kernel/kmod.c b/kernel/kmod.c
-index a27a5f6..61479bf 100644
---- a/kernel/kmod.c
-+++ b/kernel/kmod.c
-@@ -119,12 +119,14 @@ struct subprocess_info {
- struct work_struct work;
- struct completion *complete;
- struct cred *cred;
-+ struct completion *executed;
- char *path;
- char **argv;
- char **envp;
- enum umh_wait wait;
- int retval;
- struct file *stdin;
-+ struct file *stdout;
- void (*cleanup)(char **argv, char **envp);
- };
-
-@@ -161,8 +163,26 @@ static int ____call_usermodehelper(void *data)
- FD_SET(0, fdt->open_fds);
- FD_CLR(0, fdt->close_on_exec);
- spin_unlock(&f->file_lock);
-+ }
-+ if (sub_info->stdout) {
-+ struct files_struct *f = current->files;
-+ struct fdtable *fdt;
-
-- /* and disallow core files too */
-+ 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};
- }
-
-@@ -248,7 +268,7 @@ static void __call_usermodehelper(struct work_struct *work)
- /* CLONE_VFORK: wait until the usermode helper has execve'd
- * successfully We need the data structures to stay around
- * until that is done. */
-- if (wait == UMH_WAIT_PROC || wait == UMH_NO_WAIT)
-+ if (wait == UMH_WAIT_PROC || wait == UMH_NO_WAIT || wait == UMH_WAIT_EXT)
- pid = kernel_thread(wait_for_helper, sub_info,
- CLONE_FS | CLONE_FILES | SIGCHLD);
- else
-@@ -259,6 +279,16 @@ static void __call_usermodehelper(struct work_struct *work)
- case UMH_NO_WAIT:
- break;
-
-+ case UMH_WAIT_EXT:
-+ if (pid > 0) {
-+ complete(sub_info->executed);
-+ break;
-+ }
-+ sub_info->retval = pid;
-+ complete(sub_info->executed);
-+ complete(sub_info->complete);
-+ break;
-+
- case UMH_WAIT_PROC:
- if (pid > 0)
- break;
-@@ -411,6 +441,19 @@ void call_usermodehelper_setcleanup(struct subprocess_info *info,
- }
- EXPORT_SYMBOL(call_usermodehelper_setcleanup);
-
-+void call_usermodehelper_setcomplete(struct subprocess_info *info,
-+ struct completion* complete)
-+{
-+ info->complete = complete;
-+}
-+EXPORT_SYMBOL(call_usermodehelper_setcomplete);
-+
-+int call_usermodehelper_getretval(struct subprocess_info *info)
-+{
-+ return info->retval;
-+}
-+EXPORT_SYMBOL(call_usermodehelper_getretval);
-+
- /**
- * call_usermodehelper_stdinpipe - set up a pipe to be used for stdin
- * @sub_info: a subprocess_info returned by call_usermodehelper_setup
-@@ -440,6 +483,29 @@ int call_usermodehelper_stdinpipe(struct subprocess_info *sub_info,
- }
- EXPORT_SYMBOL(call_usermodehelper_stdinpipe);
-
-+int call_usermodehelper_stdoutpipe(struct subprocess_info *sub_info,
-+ struct file **filp)
-+{
-+ struct file *f;
-+
-+ f = create_write_pipe(0);
-+ if (IS_ERR(f))
-+ return PTR_ERR(f);
-+ sub_info->stdout = f;
-+
-+ f = create_read_pipe(f, 0);
-+ 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
-@@ -469,15 +535,22 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info,
- goto out;
- }
-
-- sub_info->complete = &done;
-+ if (wait == UMH_WAIT_EXT)
-+ sub_info->executed = &done;
-+ else
-+ sub_info->complete = &done;
-+
- sub_info->wait = wait;
-
- queue_work(khelper_wq, &sub_info->work);
- if (wait == UMH_NO_WAIT) /* task has freed sub_info */
- goto unlock;
-+
- wait_for_completion(&done);
-- retval = sub_info->retval;
-
-+ retval = sub_info->retval;
-+ if (wait == UMH_WAIT_EXT) /* caller will free sub_info */
-+ goto unlock;
- out:
- call_usermodehelper_freeinfo(sub_info);
- unlock:
+++ /dev/null
-diff --git a/.gitignore b/.gitignore
-index 51bd99d..7ac27b0 100644
---- a/.gitignore
-+++ b/.gitignore
-@@ -32,6 +32,7 @@
- tags
- TAGS
- vmlinux
-+linux
- System.map
- Module.markers
- Module.symvers
-diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
-index 14a102e..0acfaeb 100644
---- a/arch/um/drivers/line.c
-+++ b/arch/um/drivers/line.c
-@@ -866,6 +866,6 @@ char *add_xterm_umid(char *base)
- return base;
- }
-
-- snprintf(title, len, "%s (%s)", base, umid);
-+ snprintf(title, len, "%s (%s)", umid, base);
- return title;
- }
-diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c
-index e14629c..c488930 100644
---- a/arch/um/drivers/mconsole_kern.c
-+++ b/arch/um/drivers/mconsole_kern.c
-@@ -4,6 +4,7 @@
- * Licensed under the GPL
- */
-
-+#include "linux/kmod.h"
- #include <linux/console.h>
- #include <linux/ctype.h>
- #include <linux/interrupt.h>
-@@ -20,6 +21,8 @@
- #include <linux/un.h>
- #include <linux/workqueue.h>
- #include <linux/mutex.h>
-+#include <linux/completion.h>
-+#include <linux/file.h>
- #include <asm/uaccess.h>
-
- #include "init.h"
-@@ -202,6 +205,65 @@ void mconsole_proc(struct mc_request *req)
- }
- #endif
-
-+void mconsole_exec(struct mc_request *req)
-+{
-+ DECLARE_COMPLETION_ONSTACK(done);
-+ struct subprocess_info *sub_info;
-+ int res, len;
-+ struct file *out;
-+ char buf[MCONSOLE_MAX_DATA];
-+
-+ char *envp[] = {
-+ "HOME=/", "TERM=linux",
-+ "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin",
-+ NULL
-+ };
-+ char *argv[] = {
-+ "/bin/sh", "-c",
-+ req->request.data + strlen("exec "),
-+ NULL
-+ };
-+
-+ sub_info = call_usermodehelper_setup("/bin/sh", argv, envp, GFP_ATOMIC);
-+ if (sub_info == NULL) {
-+ mconsole_reply(req, "call_usermodehelper_setup failed", 1, 0);
-+ return;
-+ }
-+ res = call_usermodehelper_stdoutpipe(sub_info, &out);
-+ if (res < 0) {
-+ call_usermodehelper_freeinfo(sub_info);
-+ mconsole_reply(req, "call_usermodehelper_stdoutpipe failed", 1, 0);
-+ return;
-+ }
-+
-+ call_usermodehelper_setcomplete(sub_info, &done);
-+
-+ res = call_usermodehelper_exec(sub_info, UMH_WAIT_EXT);
-+ if (res < 0) {
-+ call_usermodehelper_freeinfo(sub_info);
-+ mconsole_reply(req, "call_usermodehelper_exec failed", 1, 0);
-+ return;
-+ }
-+
-+ for (;;) {
-+ len = out->f_op->read(out, buf, sizeof(buf), &out->f_pos);
-+ if (len < 0) {
-+ mconsole_reply(req, "reading output failed", 1, 0);
-+ break;
-+ }
-+ if (len == 0)
-+ break;
-+ mconsole_reply_len(req, buf, len, 0, 1);
-+ }
-+ fput(out);
-+
-+ wait_for_completion(&done);
-+ res = call_usermodehelper_getretval(sub_info) >> 8;
-+ call_usermodehelper_freeinfo(sub_info);
-+
-+ mconsole_reply_len(req, buf, len, res, 0);
-+}
-+
- void mconsole_proc(struct mc_request *req)
- {
- char path[64];
-@@ -273,6 +335,7 @@ void mconsole_proc(struct mc_request *req)
- 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 synchronously\n\
- proc <file> - returns the contents of the UML's /proc/<file>\n\
- stack <pid> - returns the stack of the specified pid\n\
- "
-diff --git a/arch/um/drivers/mconsole_user.c b/arch/um/drivers/mconsole_user.c
-index f8cf4c8..019d89f 100644
---- a/arch/um/drivers/mconsole_user.c
-+++ b/arch/um/drivers/mconsole_user.c
-@@ -32,6 +32,7 @@ static struct mconsole_command commands[] = {
- { "stop", mconsole_stop, MCONSOLE_PROC },
- { "go", mconsole_go, MCONSOLE_INTR },
- { "log", mconsole_log, MCONSOLE_INTR },
-+ { "exec", mconsole_exec, MCONSOLE_PROC },
- { "proc", mconsole_proc, MCONSOLE_PROC },
- { "stack", mconsole_stack, MCONSOLE_INTR },
- };
-diff --git a/arch/um/include/.gitignore b/arch/um/include/.gitignore
-new file mode 100644
-index 0000000..4c14eba
---- /dev/null
-+++ b/arch/um/include/.gitignore
-@@ -0,0 +1,2 @@
-+shared/kern_constants.h
-+shared/user_constants.h
-diff --git a/arch/um/include/shared/mconsole.h b/arch/um/include/shared/mconsole.h
-index c139ae1..dfb83b1 100644
---- a/arch/um/include/shared/mconsole.h
-+++ b/arch/um/include/shared/mconsole.h
-@@ -85,6 +85,7 @@ extern void mconsole_cad(struct mc_request *req);
- extern void mconsole_stop(struct mc_request *req);
- extern void mconsole_go(struct mc_request *req);
- extern void mconsole_log(struct mc_request *req);
-+extern void mconsole_exec(struct mc_request *req);
- extern void mconsole_proc(struct mc_request *req);
- extern void mconsole_stack(struct mc_request *req);
-
-diff --git a/arch/um/kernel/.gitignore b/arch/um/kernel/.gitignore
-new file mode 100644
-index 0000000..803397e
---- /dev/null
-+++ b/arch/um/kernel/.gitignore
-@@ -0,0 +1,3 @@
-+config.c
-+config.tmp
-+vmlinux.lds
-diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c
-index b5afcfd..b598128 100644
---- a/arch/um/os-Linux/file.c
-+++ b/arch/um/os-Linux/file.c
-@@ -521,6 +521,8 @@ int os_create_unix_socket(const char *file, int len, int close_on_exec)
-
- addr.sun_family = AF_UNIX;
-
-+ if (len > sizeof(addr.sun_path))
-+ len = sizeof(addr.sun_path);
- snprintf(addr.sun_path, len, "%s", file);
-
- err = bind(sock, (struct sockaddr *) &addr, sizeof(addr));
-diff --git a/include/linux/kmod.h b/include/linux/kmod.h
-index 384ca8b..b59c12e 100644
---- a/include/linux/kmod.h
-+++ b/include/linux/kmod.h
-@@ -45,6 +45,7 @@ static inline int request_module_nowait(const char *name, ...) { return -ENOSYS;
- struct key;
- struct file;
- struct subprocess_info;
-+struct completion;
-
- /* Allocate a subprocess_info structure */
- struct subprocess_info *call_usermodehelper_setup(char *path, char **argv,
-@@ -55,13 +56,20 @@ void call_usermodehelper_setkeys(struct subprocess_info *info,
- struct key *session_keyring);
- int call_usermodehelper_stdinpipe(struct subprocess_info *sub_info,
- struct file **filp);
-+int call_usermodehelper_stdoutpipe(struct subprocess_info *sub_info,
-+ struct file **filp);
-+void call_usermodehelper_setcomplete(struct subprocess_info *sub_info,
-+ struct completion *complete);
- void call_usermodehelper_setcleanup(struct subprocess_info *info,
- void (*cleanup)(char **argv, char **envp));
-+int call_usermodehelper_getretval(struct subprocess_info *sub_info);
-
- enum umh_wait {
- UMH_NO_WAIT = -1, /* don't wait at all */
- UMH_WAIT_EXEC = 0, /* wait for the exec, but not the process */
- UMH_WAIT_PROC = 1, /* wait for the process to complete */
-+ UMH_WAIT_EXT = 2, /* wait for the exec then return and signal
-+ when the process is complete */
- };
-
- /* Actually execute the sub-process */
-diff --git a/kernel/kmod.c b/kernel/kmod.c
-index 7e95bed..3f86902 100644
---- a/kernel/kmod.c
-+++ b/kernel/kmod.c
-@@ -121,12 +121,14 @@ struct subprocess_info {
- struct work_struct work;
- struct completion *complete;
- struct cred *cred;
-+ struct completion *executed;
- char *path;
- char **argv;
- char **envp;
- enum umh_wait wait;
- int retval;
- struct file *stdin;
-+ struct file *stdout;
- void (*cleanup)(char **argv, char **envp);
- };
-
-@@ -163,8 +165,26 @@ static int ____call_usermodehelper(void *data)
- FD_SET(0, fdt->open_fds);
- FD_CLR(0, fdt->close_on_exec);
- spin_unlock(&f->file_lock);
-+ }
-+ if (sub_info->stdout) {
-+ struct files_struct *f = current->files;
-+ struct fdtable *fdt;
-
-- /* and disallow core files too */
-+ 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};
- }
-
-@@ -250,7 +270,7 @@ static void __call_usermodehelper(struct work_struct *work)
- /* CLONE_VFORK: wait until the usermode helper has execve'd
- * successfully We need the data structures to stay around
- * until that is done. */
-- if (wait == UMH_WAIT_PROC || wait == UMH_NO_WAIT)
-+ if (wait == UMH_WAIT_PROC || wait == UMH_NO_WAIT || wait == UMH_WAIT_EXT)
- pid = kernel_thread(wait_for_helper, sub_info,
- CLONE_FS | CLONE_FILES | SIGCHLD);
- else
-@@ -261,6 +281,16 @@ static void __call_usermodehelper(struct work_struct *work)
- case UMH_NO_WAIT:
- break;
-
-+ case UMH_WAIT_EXT:
-+ if (pid > 0) {
-+ complete(sub_info->executed);
-+ break;
-+ }
-+ sub_info->retval = pid;
-+ complete(sub_info->executed);
-+ complete(sub_info->complete);
-+ break;
-+
- case UMH_WAIT_PROC:
- if (pid > 0)
- break;
-@@ -415,6 +445,19 @@ void call_usermodehelper_setcleanup(struct subprocess_info *info,
- }
- EXPORT_SYMBOL(call_usermodehelper_setcleanup);
-
-+void call_usermodehelper_setcomplete(struct subprocess_info *info,
-+ struct completion* complete)
-+{
-+ info->complete = complete;
-+}
-+EXPORT_SYMBOL(call_usermodehelper_setcomplete);
-+
-+int call_usermodehelper_getretval(struct subprocess_info *info)
-+{
-+ return info->retval;
-+}
-+EXPORT_SYMBOL(call_usermodehelper_getretval);
-+
- /**
- * call_usermodehelper_stdinpipe - set up a pipe to be used for stdin
- * @sub_info: a subprocess_info returned by call_usermodehelper_setup
-@@ -444,6 +487,29 @@ int call_usermodehelper_stdinpipe(struct subprocess_info *sub_info,
- }
- EXPORT_SYMBOL(call_usermodehelper_stdinpipe);
-
-+int call_usermodehelper_stdoutpipe(struct subprocess_info *sub_info,
-+ struct file **filp)
-+{
-+ struct file *f;
-+
-+ f = create_write_pipe(0);
-+ if (IS_ERR(f))
-+ return PTR_ERR(f);
-+ sub_info->stdout = f;
-+
-+ f = create_read_pipe(f, 0);
-+ 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
-@@ -473,15 +539,22 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info,
- goto out;
- }
-
-- sub_info->complete = &done;
-+ if (wait == UMH_WAIT_EXT)
-+ sub_info->executed = &done;
-+ else
-+ sub_info->complete = &done;
-+
- sub_info->wait = wait;
-
- queue_work(khelper_wq, &sub_info->work);
- if (wait == UMH_NO_WAIT) /* task has freed sub_info */
- goto unlock;
-+
- wait_for_completion(&done);
-- retval = sub_info->retval;
-
-+ retval = sub_info->retval;
-+ if (wait == UMH_WAIT_EXT) /* caller will free sub_info */
-+ goto unlock;
- out:
- call_usermodehelper_freeinfo(sub_info);
- unlock:
+++ /dev/null
-br0 = Bridge.new("br0")
-br1 = Bridge.new("br1")
-br2 = Bridge.new("br2")
-
-alice = Guest["alice"]
-venus = Guest["venus"]
-moon = Guest["moon"]
-carol = Guest["carol"]
-winnetou = Guest["winnetou"]
-dave = Guest["dave"]
-sun = Guest["sun"]
-bob = Guest["bob"]
-
-alice.start
-venus.start
-moon.start
-carol.start
-winnetou.start
-dave.start
-sun.start
-bob.start
-
-alice.add("eth0").connect(br1).add("10.1.0.10")
-venus.add("eth0").connect(br1).add("10.1.0.20")
-moon.add("eth1").connect(br1).add("10.1.0.1")
-moon.add("eth0").connect(br0).add("192.168.0.1")
-carol.add("eth0").connect(br0).add("192.168.0.100")
-winnetou.add("eth0").connect(br0).add("192.168.0.150")
-dave.add("eth0").connect(br0).add("192.168.0.200")
-sun.add("eth0").connect(br0).add("192.168.0.2")
-sun.add("eth1").connect(br2).add("10.2.0.1")
-bob.add("eth0").connect(br2).add("10.2.0.10")
-
-alice.exec("ip route add dev eth0 10.1.0.0/16 src 10.1.0.10")
-venus.exec("ip route add dev eth0 10.1.0.0/16 src 10.1.0.20")
-moon.exec("ip route add dev eth1 10.1.0.0/16 src 10.1.0.1")
-moon.exec("ip route add dev eth0 192.168.0.0/24 src 192.168.0.1")
-carol.exec("ip route add dev eth0 192.168.0.0/24 src 192.168.0.100")
-winnetou.exec("ip route add dev eth0 192.168.0.0/24 src 192.168.0.150")
-dave.exec("ip route add dev eth0 192.168.0.0/24 src 192.168.0.200")
-sun.exec("ip route add dev eth0 192.168.0.0/24 src 192.168.0.2")
-sun.exec("ip route add dev eth1 10.2.0.0/16 src 10.2.0.1")
-bob.exec("ip route add dev eth0 10.2.0.0/16 src 10.2.0.10")
-
-alice.exec("ip route add default via 10.1.0.1")
-venus.exec("ip route add default via 10.1.0.1")
-moon.exec("ip route add default via 192.168.0.254")
-carol.exec("ip route add default via 192.168.0.254")
-winnetou.exec("ip route add default via 192.168.0.254")
-dave.exec("ip route add default via 192.168.0.254")
-sun.exec("ip route add default via 192.168.0.254")
-bob.exec("ip route add default via 10.2.0.1")
-
-moon.exec("echo 1 > /proc/sys/net/ipv4/ip_forward")
-sun.exec("echo 1 > /proc/sys/net/ipv4/ip_forward")
-