]> xenbits.xensource.com Git - rumpuser-xen.git/commitdiff
Configure rumprun-xen application stacks from Xenstore
authorMartin Lucina <martin@lucina.net>
Thu, 13 Nov 2014 10:40:08 +0000 (11:40 +0100)
committerMartin Lucina <martin@lucina.net>
Thu, 13 Nov 2014 10:40:08 +0000 (11:40 +0100)
In order to run rumprun-xen applications that are actually useful, we
need to be able to configure block devices and network interfaces.
These changes implement a basic mechanism to do this using Xenstore.

Conceptually the changes consist of the following parts which work
together:

- The rumpconfig module provides _rumprun_config() and
  _rumprun_deconfig() functions. These are called before and after the
  application main() function, and also in the case of deconfig when
  _exit() is called.

- These functions rely on keys like the following being present in
  Xenstore at the time the domain is started:

  /local/domain/<domid>/rumprun/net/0/... (first network interface)
  /local/domain/<domid>/rumprun/net/1/... (second network interface)
  /local/domain/<domid>/rumprun/blk/0/... (first block device)
  /local/domain/<domid>/rumprun/blk/1/... (second block device)

- The "xr" driver script, currently located in app-tools/. The
  motivation for this script is twofold:

  Firstly, in order to write the configuration to Xenstore the domain
  must be created in a paused state so that we can retrieve its unique
  <domid>. Only then do we know where in Xenstore to write the
  configuration data.

  Secondly, it is my intention with this work to provide a
  "docker-alike" interface for running rumprun applications. The "xr"
  script is therefore the CLI for running such applications.

Note that in this initial version, only configuring IPv4 network
interfaces with DHCP is supported, and only using image files with ffs
or cd9660 filesystems for block devices is supported.

Signed-off-by: Martin Lucina <martin@lucina.net>
Makefile
app-tools/xr [new file with mode: 0755]
callmain.c
lib/emul.c
rumpconfig.c [new file with mode: 0644]
rumpconfig.h [new file with mode: 0644]

index c4beecc8960ab6761fc385e940036b87c1315c5c..d9eb1bd96f66e1999d6c09c07df3734de821a579 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -38,7 +38,7 @@ ifeq ($(CONFIG_PCI),y)
 RUMP_LIBS_PCI = -lrumpdev_pci -lrumpdev_pci_if_wm -lrumpdev_miiphy
 endif
 
-RUMP_LIBS_FS = -lrumpfs_ffs -lrumpdev_disk -lrumpdev -lrumpvfs
+RUMP_LIBS_FS = -lrumpfs_ffs -lrumpfs_cd9660 -lrumpdev_disk -lrumpdev -lrumpvfs
 RUMP_LIBS_NET = -lrumpnet_config -lrumpdev_bpf -lrumpnet_xenif -lrumpnet_netinet
 RUMP_LIBS_NET+= -lrumpnet_net -lrumpxen_xendev -lrumpnet
 
@@ -89,6 +89,7 @@ rump-src-y += rumphyper_stubs.c
 
 rump-src-y += callmain.c
 rump-src-y += netbsd_init.c
+rump-src-y += rumpconfig.c
 
 # The common mini-os objects to build.
 OBJS := $(patsubst %.c,$(OBJ_DIR)/%.o,$(src-y))
diff --git a/app-tools/xr b/app-tools/xr
new file mode 100755 (executable)
index 0000000..3d34679
--- /dev/null
@@ -0,0 +1,197 @@
+#!/bin/sh
+#
+# Copyright (c) 2014 Martin Lucina.  All Rights Reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+
+#
+# xr: rumprun-xen stack "driver" script for running application stacks
+#
+
+err() {
+       echo xr: error: "$@" 1>&2
+       exit 1
+}
+
+usage() {
+       cat <<EOM
+usage: xr COMMAND [ args ]
+
+  supported COMMANDs:
+
+  run [ -ipd ] [ -b BLKSPEC ] [ -n NETSPEC ] [ -- ] APP [ args ]
+    APP is the rumprun-xen application to start
+    args will be passed to the application command line
+    -b BLKSPEC configures a block device as hostpath:mountpoint
+    -n NETSPEC configures a network interface as type:method
+    -i attaches to domain console on startup
+    -p creates the domain but leaves it paused
+    -d destroys the domain on poweroff
+    
+    When run without -i the local domain id is printed to standard output
+EOM
+       exit 1
+}
+
+# Detect the filesystem type of the image at $1.
+detect_fstype() {
+       ftype=$(file -b $1)
+       case $ftype in
+               "Unix Fast File system"*)
+                       echo ffs
+                       return 0
+                       ;;
+               "ISO 9660"*)
+                       echo cd9660
+                       return 0
+                       ;;
+               *)
+                       echo unknown
+                       return 1
+                       ;;
+       esac
+}
+
+# xr run: Generate configuration and run application stack.
+xr_run() {
+       conf=/tmp/xr.conf.$$
+       xenstore=/tmp/xr.store.$$
+       >${conf}
+       >${xenstore}
+       OPTIND=1
+       nindex=0
+       bindex=0
+       conf_disk=
+       conf_vif=
+       opt_pause=
+       opt_interactive=
+       opt_destroy='on_poweroff="preserve"'
+       while getopts "n:b:pid" opt; do
+               case "$opt" in
+                       # -n: NETSPEC: type:method
+                       n)
+                               iftype=${OPTARG%:*}
+                               ifmethod=${OPTARG#*:}
+                               [ "$iftype" != "inet" ] && usage
+                               [ "$ifmethod" != "dhcp" ] && usage
+                               conf_vif="${conf_vif}'',"
+                               echo net/${nindex}/type inet >>${xenstore}
+                               echo net/${nindex}/method dhcp >>${xenstore}
+                               nindex=$(expr $nindex + 1)
+                               ;;
+                       # -b: BLKSPEC: hostpath:mountpoint
+                       b)
+                               image=${OPTARG%:*}
+                               mountpoint=${OPTARG#*:}
+                               [ -n "$image" ] || usage
+                               [ -n "$mountpoint" ] || usage
+                               [ -f "$image" ] || err File $image does not exist
+                               fstype=$(detect_fstype $image)
+                               [ $? -ne 0 ] && err File $image: unknown fstype
+                               vdev=hd$(echo $bindex | tr '[0-9]' '[a-j]')
+                               conf_disk="${conf_disk}'file:$image,$vdev,rw',"
+                               echo blk/${bindex}/type etfs >>${xenstore}
+                               echo blk/${bindex}/fstype $fstype >>${xenstore}
+                               echo blk/${bindex}/mountpoint $mountpoint\
+                                       >>${xenstore}
+                               bindex=$(expr $bindex + 1)
+                               ;;
+                       # -p: Leave the domain paused after creation.
+                       p)
+                               opt_pause=1
+                               ;;
+                       # -i: Attach to domain console on startup.
+                       i)
+                               opt_interactive=1
+                               ;;
+                       # -d: Destroy domain on poweroff instead of preserving it.
+                       d)
+                               opt_destroy='on_poweroff="destroy"'
+                               ;;
+                       *)
+                               usage
+                               ;;
+               esac
+       done
+       # Clean up vif and disk, xl does not like trailing commas.
+       conf_vif=$(echo ${conf_vif} | sed -e s/,\$//)
+       [ -n ${conf_vif} ] && conf_vif="vif=[${conf_vif}]"
+       conf_disk=$(echo ${conf_disk} | sed -e s/,\$//)
+       [ -n ${conf_disk} ] && conf_disk="disk=[${conf_disk}]"
+       # Remaining arguments belong to the application.
+       shift $((OPTIND-1))
+       [ "$1" = "--" ] && shift
+       name=rumprun-$(basename $1)
+       app=$(realpath $1)
+       shift
+       # Generate xl configuration file.
+       cat <<EOM >/tmp/xr.conf.$$
+kernel="${app}"
+name="${name}"
+vcpus=1
+memory=16
+on_crash="preserve"
+${opt_destroy}
+extra="$@"
+${conf_vif}
+${conf_disk}
+EOM
+       # Create the domain and leave it paused so that we can get its domid.
+       if ! xl create -p ${conf} >/dev/null; then
+               err xl create failed
+       fi
+       rm ${conf}
+       domid=$(xl domid ${name})
+       # Write provisioning information for domain to xenstore.
+       prefix=/local/domain/${domid}/rumprun
+       cat ${xenstore} | while read line; do
+               xenstore-write ${prefix}/${line}
+       done
+       rm ${xenstore}
+       # Go go go!
+       [ -z "$opt_pause" ] && xl unpause ${domid}
+       if [ -n "$opt_interactive" ]; then
+               exec xl console $domid
+       else
+               echo ${domid}
+       fi
+}
+
+if [ $# -lt 2 ]; then
+       usage
+fi
+if [ $(id -u) -ne 0 ]; then
+       err Must be root
+fi
+
+cmd="$1"
+shift
+case "$cmd" in
+       run)
+               xr_run "$@"
+               ;;
+       *)
+               usage
+               ;;
+esac
+
index 7ded920cf98e964150a3f16730338b7b64cab033..34f3d3a6fd8795e6b1935ab8822e77ca638c976d 100644 (file)
@@ -29,6 +29,8 @@
 
 #include <xen/xen.h>
 
+#include "rumpconfig.h"
+
 extern int main(int argc, char **argv);
 
 static void parseargs(void *cmdline, int *nargs, char **outarray) {
@@ -92,9 +94,11 @@ __default_app_main(start_info_t *si)
        argv[nargs+1] = 0;
        argv[nargs+2] = 0;
 
+       _rumprun_config();
        fprintf(stderr,"=== calling main() ===\n\n");
        r = main(nargs+1, argv);
        fprintf(stderr,"\n=== main() returned %d ===\n", r);
+       _rumprun_deconfig();
        return r;
 }
 
index 8852004da8a279cb4ac73b4b968add8c6f073509..fc4690949de0824e1326a85e26c5fdd586008888 100644 (file)
@@ -20,6 +20,9 @@
 #include <mini-os/os.h> /* for PAGE_SIZE */
 #include <mini-os/kernel.h>
 
+#include "netbsd_init.h"
+#include "rumpconfig.h"
+
 void *
 mmap(void *addr, size_t len, int prot, int flags, int fd, off_t off)
 {
@@ -77,6 +80,10 @@ munmap(void *addr, size_t len)
 void __dead
 _exit(int eval)
 {
+       /* XXX this duplicates _app_main / callmain cleanup */
+       minios_printk("\n=== _exit(%d) called ===\n", eval);
+       _rumprun_deconfig();
+       _netbsd_fini();
        minios_stop_kernel();
        minios_do_halt(MINIOS_HALT_POWEROFF);
 }
diff --git a/rumpconfig.c b/rumpconfig.c
new file mode 100644 (file)
index 0000000..40b47f0
--- /dev/null
@@ -0,0 +1,443 @@
+/*
+ * Copyright (c) 2014 Martin Lucina.  All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <err.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/mount.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rump/rump.h>
+#include <rump/rump_syscalls.h>
+#include <rump/netconfig.h>
+
+#include <mini-os/os.h>
+#include <mini-os/mm.h>
+#include <mini-os/xenbus.h>
+
+#include <ufs/ufs/ufsmount.h>
+#include <isofs/cd9660/cd9660_mount.h>
+
+#include "rumpconfig.h"
+
+static int
+xs_read_netconfig(const char *if_index, char **type, char **method)
+{
+       char *if_type = NULL;
+       char *if_method = NULL;
+       char buf[128];
+       char *xberr = NULL;
+       xenbus_transaction_t txn;
+       int xbretry = 0;
+
+       xberr = xenbus_transaction_start(&txn);
+       if (xberr) {
+               warnx("rumprun_config: xenbus_transaction_start() failed: %s",
+                       xberr);
+               return 1;
+       }
+       snprintf(buf, sizeof buf, "rumprun/net/%s/type", if_index);
+       xberr = xenbus_read(txn, buf, &if_type);
+       if (xberr) {
+               warnx("rumprun_config: xenif%s: read %s failed: %s",
+                       if_index, buf, xberr);
+               xenbus_transaction_end(txn, 0, &xbretry);
+               return 1;
+       }
+       if (strcmp(if_type, "inet") != 0) {
+               warnx("rumprun_config: xenif%s: unknown type '%s'",
+                       if_index, if_type);
+               xenbus_transaction_end(txn, 0, &xbretry);
+               free(if_type);
+               return 1;
+       }
+       snprintf(buf, sizeof buf, "rumprun/net/%s/method", if_index);
+       xberr = xenbus_read(txn, buf, &if_method);
+       if (xberr) {
+               warnx("rumprun_config: xenif%s: read %s failed: %s",
+                       if_index, buf, xberr);
+               xenbus_transaction_end(txn, 0, &xbretry);
+               free(if_type);
+               return 1;
+       }
+       if (strcmp(if_method, "dhcp") != 0) {
+               warnx("rumprun_config: xenif%s: unknown method '%s'",
+                       if_index, if_method);
+               xenbus_transaction_end(txn, 0, &xbretry);
+               free(if_type);
+               free(if_method);
+               return 1;
+       }
+       xberr = xenbus_transaction_end(txn, 0, &xbretry);
+       if (xberr) {
+               warnx("rumprun_config: xenbus_transaction_end() failed: %s",
+                       xberr);
+               free(if_type);
+               free(if_method);
+               return 1;
+       }
+       *type = if_type;
+       *method = if_method;
+       return 0;
+}
+
+static void
+rumprun_config_net(const char *if_index)
+{
+       char *if_type = NULL;
+       char *if_method = NULL;
+       char buf[128];
+       int rv;
+       
+       rv = xs_read_netconfig(if_index, &if_type, &if_method);
+       if (rv != 0)
+               return;
+       
+       printf("rumprun_config: configuring xenif%s as %s with %s\n",
+               if_index, if_type, if_method);
+       snprintf(buf, sizeof buf, "xenif%s", if_index);
+       if ((rv = rump_pub_netconfig_ifcreate(buf)) != 0) {
+               warnx("rumprun_config: creating %s failed: %d\n", buf, rv);
+               goto out;
+       }
+       if ((rv = rump_pub_netconfig_dhcp_ipv4_oneshot(buf)) != 0) {
+               printf("rumprun_config: dhcp for %s failed: %d\n", buf, rv);
+               goto out;
+       }
+
+out:
+       free(if_type);
+       free(if_method);
+}
+
+static void
+rumprun_deconfig_net(const char *if_index)
+{
+       char *if_type = NULL;
+       char *if_method = NULL;
+       int rv;
+
+       rv = xs_read_netconfig(if_index, &if_type, &if_method);
+       if (rv != 0)
+               return;
+
+       printf("rumprun_config: (not yet) deconfiguring xenif%s\n", if_index);
+#if 0 /* XXX causes dhcpcd from brlib to fall over */  
+       snprintf(buf, sizeof buf, "xenif%s", if_index);
+       if ((rv = rump_pub_netconfig_ifdown(buf)) != 0) {
+               warnx("rumprun_config: ifdown %s failed: %d\n", buf, rv);
+               return;
+       }
+       if ((rv = rump_pub_netconfig_ifdestroy(buf)) != 0) {
+               printf("rumprun_config: ifdestroy %s failed: %d\n", buf, rv);
+               return;
+       }
+#endif
+       free(if_type);
+       free(if_method);
+}
+
+static int
+xs_read_blkconfig(const char *blk_index, char **type, char **mountpoint,
+       char **fstype)
+{
+       char *blk_type = NULL;
+       char *blk_mountpoint = NULL;
+       char *blk_fstype = NULL;
+       char buf[128];
+       char *xberr = NULL;
+       xenbus_transaction_t txn;
+       int xbretry = 0;
+       
+       xberr = xenbus_transaction_start(&txn);
+       if (xberr) {
+               warnx("rumprun_config: xenbus_transaction_start() failed: %s",
+                       xberr);
+               return 1;
+       }
+       snprintf(buf, sizeof buf, "rumprun/blk/%s/type", blk_index);
+       xberr = xenbus_read(txn, buf, &blk_type);
+       if (xberr) {
+               warnx("rumprun_config: xenblk%s: read %s failed: %s",
+                       blk_index, buf, xberr);
+               xenbus_transaction_end(txn, 0, &xbretry);
+               return 1;
+       }
+       if (strcmp(blk_type, "etfs") != 0) {
+               warnx("rumprun_config: xenblk%s: unknown type '%s'",
+                       blk_index, blk_type);
+               xenbus_transaction_end(txn, 0, &xbretry);
+               free(blk_type);
+               return 1;
+       }
+       snprintf(buf, sizeof buf, "rumprun/blk/%s/mountpoint", blk_index);
+       xberr = xenbus_read(txn, buf, &blk_mountpoint);
+       if (xberr) {
+               warnx("rumprun_config: xenblk%s: read %s failed: %s",
+                       blk_index, buf, xberr);
+               xenbus_transaction_end(txn, 0, &xbretry);
+               free(blk_type);
+               return 1;
+       }
+       snprintf(buf, sizeof buf, "rumprun/blk/%s/fstype", blk_index);
+       xberr = xenbus_read(txn, buf, &blk_fstype);
+       if (xberr) {
+               warnx("rumprun_config: xenblk%s: read %s failed: %s",
+                       blk_index, buf, xberr);
+               xenbus_transaction_end(txn, 0, &xbretry);
+               free(blk_type);
+               free(blk_mountpoint);
+               return 1;
+       }
+       xberr = xenbus_transaction_end(txn, 0, &xbretry);
+       if (xberr) {
+               warnx("rumprun_config: xenbus_transaction_end() failed: %s",
+                       xberr);
+               free(blk_type);
+               free(blk_mountpoint);
+               free(blk_fstype);
+               return 1;
+       }
+       *type = blk_type;
+       *mountpoint = blk_mountpoint;
+       *fstype = blk_fstype;
+       return 0;
+}
+
+static void
+rumprun_config_blk(const char *blk_index)
+{
+       char *blk_type = NULL;
+       char *blk_mountpoint = NULL;
+       char *blk_fstype = NULL;
+       int rv;
+       char key[32],
+            hostpath[32];
+
+       rv = xs_read_blkconfig(blk_index, &blk_type, &blk_mountpoint,
+               &blk_fstype);
+       if (rv != 0)
+               return;
+       if ((strcmp(blk_fstype, "ffs") != 0) &&
+               (strcmp(blk_fstype, "cd9660") != 0)) {
+               warnx("rumprun_config: xenblk%s: unsupported fstype %s\n",
+                       blk_index, blk_fstype);
+               goto out;
+       }
+       
+       printf("rumprun_config: mounting xenblk%s on %s as %s\n",
+               blk_index, blk_mountpoint, blk_fstype);
+       if ((rv = mkdir(blk_mountpoint, 0777)) != 0) {
+               warnx("rumprun_config: mkdir failed: %d", errno);
+               goto out;
+       }
+       snprintf(key, sizeof key, "/dev/xenblk%s", blk_index);
+       snprintf(hostpath, sizeof hostpath, "blk%s", blk_index);
+       if ((rv = rump_pub_etfs_register(key, hostpath, RUMP_ETFS_BLK)) != 0) {
+               warnx("rumprun_config: etfs_register failed: %d", rv);
+               goto out;
+       }
+       if (strcmp(blk_fstype, "ffs") == 0) {
+               struct ufs_args mntargs = { .fspec = key };
+               if (mount(MOUNT_FFS, blk_mountpoint, 0, &mntargs, sizeof(mntargs)) != 0) {
+                       warn("rumprun_config: mount_ffs failed");
+                       goto out;
+               }
+       }
+       else if(strcmp(blk_fstype, "cd9660") == 0) {
+               struct iso_args mntargs = { .fspec = key };
+               if (mount(MOUNT_CD9660, blk_mountpoint, MNT_RDONLY, &mntargs, sizeof(mntargs)) != 0) {
+                       warn("rumprun_config: mount_cd9660 failed");
+                       goto out;
+               }
+       }
+
+out:
+       free(blk_type);
+       free(blk_mountpoint);
+       free(blk_fstype);
+}
+
+static void
+rumprun_deconfig_blk(const char *blk_index)
+{
+       char *blk_type = NULL;
+       char *blk_mountpoint = NULL;
+       char *blk_fstype = NULL;
+       char key[32];
+       int rv;
+       
+       rv = xs_read_blkconfig(blk_index, &blk_type, &blk_mountpoint,
+               &blk_fstype);
+       if (rv != 0)
+               return;
+       
+       printf("rumprun_config: unmounting xenblk%s from %s\n",
+               blk_index, blk_mountpoint);
+       if (unmount(blk_mountpoint, 0) != 0) {
+               warnx("rumprun_config: unmount failed: %d", errno);
+               /* Continue anyway, the initial mount may have failed. */
+       }
+       snprintf(key, sizeof key, "/dev/xenblk%s", blk_index);
+       if ((rv = rump_pub_etfs_remove(key)) != 0) {
+               warnx("rumprun_config: etfs_remove failed: %d", rv);
+               goto out;
+       }
+
+out:
+       free(blk_type);
+       free(blk_mountpoint);
+       free(blk_fstype);
+}
+
+void
+_rumprun_config(void)
+{
+       char *err = NULL;
+       xenbus_transaction_t txn;
+       char **netdevices = NULL,
+            **blkdevices = NULL;
+       int retry = 0,
+           i;
+
+       err = xenbus_transaction_start(&txn);
+       if (err) {
+               warnx("rumprun_config: xenbus_transaction_start() failed: %s",
+                       err);
+               goto out_err;
+       }
+       err = xenbus_ls(txn, "rumprun/net", &netdevices);
+       if (err && strcmp(err, "ENOENT") != 0) {
+               warnx("rumprun_config: xenbus_ls(rumprun/net) failed: %s", err);
+               xenbus_transaction_end(txn, 0, &retry);
+               goto out_err;
+       }
+       err = xenbus_ls(txn, "rumprun/blk", &blkdevices);
+       if (err && strcmp(err, "ENOENT") != 0) {
+               warnx("rumprun_config: xenbus_ls(rumprun/blk) failed: %s", err);
+               xenbus_transaction_end(txn, 0, &retry);
+               goto out_err;
+       }
+       err = xenbus_transaction_end(txn, 0, &retry);
+       if (err) {
+               warnx("rumprun_config: xenbus_transaction_end() failed: %s",
+                       err);
+               goto out_err;
+       }
+       if (netdevices) {
+               for(i = 0; netdevices[i]; i++) {
+                       rumprun_config_net(netdevices[i]);
+                       free(netdevices[i]);
+               }
+               free(netdevices);
+       }
+       if (blkdevices) {
+               for(i = 0; blkdevices[i]; i++) {
+                       rumprun_config_blk(blkdevices[i]);
+                       free(blkdevices[i]);
+               }
+               free(blkdevices);
+       }
+       return;
+
+out_err:
+       if (netdevices) {
+               for(i = 0; netdevices[i]; i++)
+                       free(netdevices[i]);
+               free(netdevices);
+       }
+       if (blkdevices) {
+               for(i = 0; blkdevices[i]; i++)
+                       free(blkdevices[i]);
+               free(blkdevices);
+       }
+}
+
+void
+_rumprun_deconfig(void)
+{
+       char *err = NULL;
+       xenbus_transaction_t txn;
+       char **netdevices = NULL,
+            **blkdevices = NULL;
+       int retry = 0,
+           i;
+
+       err = xenbus_transaction_start(&txn);
+       if (err) {
+               warnx("rumprun_config: xenbus_transaction_start() failed: %s",
+                       err);
+               goto out_err;
+       }
+       err = xenbus_ls(txn, "rumprun/net", &netdevices);
+       if (err && strcmp(err, "ENOENT") != 0) {
+               warnx("rumprun_config: xenbus_ls(rumprun/net) failed: %s", err);
+               xenbus_transaction_end(txn, 0, &retry);
+               goto out_err;
+       }
+       err = xenbus_ls(txn, "rumprun/blk", &blkdevices);
+       if (err && strcmp(err, "ENOENT") != 0) {
+               warnx("rumprun_config: xenbus_ls(rumprun/blk) failed: %s", err);
+               xenbus_transaction_end(txn, 0, &retry);
+               goto out_err;
+       }
+       err = xenbus_transaction_end(txn, 0, &retry);
+       if (err) {
+               warnx("rumprun_config: xenbus_transaction_end() failed: %s",
+                       err);
+               goto out_err;
+       }
+       if (netdevices) {
+               for(i = 0; netdevices[i]; i++) {
+                       rumprun_deconfig_net(netdevices[i]);
+                       free(netdevices[i]);
+               }
+               free(netdevices);
+       }
+       if (blkdevices) {
+               for(i = 0; blkdevices[i]; i++) {
+                       rumprun_deconfig_blk(blkdevices[i]);
+                       free(blkdevices[i]);
+               }
+               free(blkdevices);
+       }
+       return;
+
+out_err:
+       if (netdevices) {
+               for(i = 0; netdevices[i]; i++)
+                       free(netdevices[i]);
+               free(netdevices);
+       }
+       if (blkdevices) {
+               for(i = 0; blkdevices[i]; i++)
+                       free(blkdevices[i]);
+               free(blkdevices);
+       }
+}
diff --git a/rumpconfig.h b/rumpconfig.h
new file mode 100644 (file)
index 0000000..4f7cbd4
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2014 Martin Lucina.  All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+void _rumprun_config(void);
+void _rumprun_deconfig(void);