aboutsummaryrefslogtreecommitdiffstats
path: root/tools/blktap2/control
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2010-06-08 08:05:09 +0100
committerKeir Fraser <keir.fraser@citrix.com>2010-06-08 08:05:09 +0100
commit4b1af8b188ccf532742ed5f2a49f480d9a702333 (patch)
treea34e14bc4e972f3ec7af5870b6a7ed634cd3282b /tools/blktap2/control
parentc6913b5aaf48107f7bb9fb4e01c7f74c863b3713 (diff)
downloadxen-4b1af8b188ccf532742ed5f2a49f480d9a702333.tar.gz
xen-4b1af8b188ccf532742ed5f2a49f480d9a702333.tar.bz2
xen-4b1af8b188ccf532742ed5f2a49f480d9a702333.zip
blktap2: The tap-ctl userspace control utility and library.
Tapdisk control in userspace, a replacement for the original blktap2 control stack, which had to pass a kernel space interface based on sysfs nodes. All tapdisk processes listen for commands on a unix stream socket. The control library supports scanning the socket namespace for running tapdisks, VBD minors allocated, associated images and state inquiry. Control operations include allocating/releasing devices, spawning tapdisks, opening/closing images, attaching disk images to devices. disk pause/resume operations and runtime switching of disk images. Signed-off-by: Jake Wires <jake.wires@citrix.com> Signed-off-by: Daniel Stodden <daniel.stodden@citrix.com>
Diffstat (limited to 'tools/blktap2/control')
-rw-r--r--tools/blktap2/control/Makefile57
-rw-r--r--tools/blktap2/control/tap-ctl-allocate.c242
-rw-r--r--tools/blktap2/control/tap-ctl-attach.c61
-rw-r--r--tools/blktap2/control/tap-ctl-check.c79
-rw-r--r--tools/blktap2/control/tap-ctl-close.c87
-rw-r--r--tools/blktap2/control/tap-ctl-create.c65
-rw-r--r--tools/blktap2/control/tap-ctl-destroy.c56
-rw-r--r--tools/blktap2/control/tap-ctl-detach.c61
-rw-r--r--tools/blktap2/control/tap-ctl-free.c54
-rw-r--r--tools/blktap2/control/tap-ctl-ipc.c237
-rw-r--r--tools/blktap2/control/tap-ctl-list.c506
-rw-r--r--tools/blktap2/control/tap-ctl-major.c69
-rw-r--r--tools/blktap2/control/tap-ctl-open.c75
-rw-r--r--tools/blktap2/control/tap-ctl-pause.c59
-rw-r--r--tools/blktap2/control/tap-ctl-spawn.c174
-rw-r--r--tools/blktap2/control/tap-ctl-unpause.c64
-rw-r--r--tools/blktap2/control/tap-ctl.c815
-rw-r--r--tools/blktap2/control/tap-ctl.h101
18 files changed, 2862 insertions, 0 deletions
diff --git a/tools/blktap2/control/Makefile b/tools/blktap2/control/Makefile
new file mode 100644
index 0000000000..68b4285ba8
--- /dev/null
+++ b/tools/blktap2/control/Makefile
@@ -0,0 +1,57 @@
+XEN_ROOT := ../../../
+include $(XEN_ROOT)/tools/Rules.mk
+
+IBIN = tap-ctl
+INST_DIR = /usr/sbin
+
+CFLAGS += -Werror
+CFLAGS += -Wno-unused
+CFLAGS += -I../include -I../drivers
+CFLAGS += -I$(XEN_INCLUDE) -I$(XEN_LIBXC)
+CFLAGS += -D_GNU_SOURCE
+CFLAGS += -DTAPCTL
+
+# Get gcc to generate the dependencies for us.
+CFLAGS += -Wp,-MD,.$(@F).d
+DEPS = .*.d
+
+CTL_OBJS := tap-ctl-ipc.o
+CTL_OBJS += tap-ctl-list.o
+CTL_OBJS += tap-ctl-allocate.o
+CTL_OBJS += tap-ctl-free.o
+CTL_OBJS += tap-ctl-create.o
+CTL_OBJS += tap-ctl-destroy.o
+CTL_OBJS += tap-ctl-spawn.o
+CTL_OBJS += tap-ctl-attach.o
+CTL_OBJS += tap-ctl-detach.o
+CTL_OBJS += tap-ctl-open.o
+CTL_OBJS += tap-ctl-close.o
+CTL_OBJS += tap-ctl-pause.o
+CTL_OBJS += tap-ctl-unpause.o
+CTL_OBJS += tap-ctl-major.o
+CTL_OBJS += tap-ctl-check.o
+
+OBJS = $(CTL_OBJS)
+LIBS = libblktapctl.a
+
+all: build
+
+build: $(IBIN)
+
+tap-ctl: tap-ctl.o libblktapctl.a
+ $(CC) $(CFLAGS) -o $@ $^
+
+libblktapctl.a: $(CTL_OBJS)
+ ar r $@ $^
+
+install: all
+ $(INSTALL_DIR) -p $(DESTDIR)$(INST_DIR)
+ $(INSTALL_PROG) $(IBIN) $(DESTDIR)$(INST_DIR)
+
+clean:
+ rm -f $(OBJS) $(DEPS) $(IBIN) $(LIBS)
+ rm -f *~
+
+.PHONY: all build clean install
+
+-include $(DEPS)
diff --git a/tools/blktap2/control/tap-ctl-allocate.c b/tools/blktap2/control/tap-ctl-allocate.c
new file mode 100644
index 0000000000..8a6471e987
--- /dev/null
+++ b/tools/blktap2/control/tap-ctl-allocate.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 COPYRIGHT OWNER
+ * 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 <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <getopt.h>
+#include <libgen.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <linux/major.h>
+
+#include "tap-ctl.h"
+#include "blktap2.h"
+
+static int
+tap_ctl_prepare_directory(const char *dir)
+{
+ int err;
+ char *ptr, *name, *start;
+
+ err = access(dir, W_OK | R_OK);
+ if (!err)
+ return 0;
+
+ name = strdup(dir);
+ if (!name)
+ return ENOMEM;
+
+ start = name;
+
+ for (;;) {
+ ptr = strchr(start + 1, '/');
+ if (ptr)
+ *ptr = '\0';
+
+ err = mkdir(name, 0755);
+ if (err && errno != EEXIST) {
+ PERROR("mkdir %s", name);
+ err = errno;
+ break;
+ }
+
+ if (!ptr)
+ break;
+ else {
+ *ptr = '/';
+ start = ptr + 1;
+ }
+ }
+
+ free(name);
+ return err;
+}
+
+static int
+tap_ctl_make_device(const char *devname, const int major,
+ const int minor, const int perm)
+{
+ int err;
+ char *copy, *dir;
+
+ copy = strdup(devname);
+ if (!copy)
+ return ENOMEM;
+
+ dir = dirname(copy);
+
+ err = tap_ctl_prepare_directory(dir);
+ free(copy);
+
+ if (err)
+ return err;
+
+ if (!access(devname, F_OK))
+ if (unlink(devname)) {
+ PERROR("unlink %s", devname);
+ return errno;
+ }
+
+ err = mknod(devname, perm, makedev(major, minor));
+ if (err) {
+ PERROR("mknod %s", devname);
+ return errno;
+ }
+
+ return 0;
+}
+
+static int
+tap_ctl_check_environment(void)
+{
+ FILE *f;
+ int err, minor;
+ char name[256];
+
+ err = tap_ctl_prepare_directory(BLKTAP2_CONTROL_DIR);
+ if (err)
+ return err;
+
+ if (!access(BLKTAP2_CONTROL_DEVICE, R_OK | W_OK))
+ return 0;
+
+ memset(name, 0, sizeof(name));
+
+ f = fopen("/proc/misc", "r");
+ if (!f) {
+ EPRINTF("failed to open /proc/misc: %d\n", errno);
+ return errno;
+ }
+
+ while (fscanf(f, "%d %256s", &minor, name) == 2)
+ if (!strcmp(name, BLKTAP2_CONTROL_NAME)) {
+ err = tap_ctl_make_device(BLKTAP2_CONTROL_DEVICE,
+ MISC_MAJOR,
+ minor, S_IFCHR | 0600);
+ goto out;
+ }
+
+ err = ENOSYS;
+ EPRINTF("didn't find %s in /proc/misc\n", BLKTAP2_CONTROL_NAME);
+
+out:
+ fclose(f);
+ return err;
+}
+
+static int
+tap_ctl_allocate_device(int *minor, char **devname)
+{
+ char *name;
+ int fd, err;
+ struct blktap2_handle handle;
+
+ *minor = -1;
+ if (!devname)
+ return EINVAL;
+
+ fd = open(BLKTAP2_CONTROL_DEVICE, O_RDONLY);
+ if (fd == -1) {
+ EPRINTF("failed to open control device: %d\n", errno);
+ return errno;
+ }
+
+ err = ioctl(fd, BLKTAP2_IOCTL_ALLOC_TAP, &handle);
+ close(fd);
+ if (err == -1) {
+ EPRINTF("failed to allocate new device: %d\n", errno);
+ return errno;
+ }
+
+ err = asprintf(&name, "%s%d", BLKTAP2_RING_DEVICE, handle.minor);
+ if (err == -1) {
+ err = ENOMEM;
+ goto fail;
+ }
+
+ err = tap_ctl_make_device(name, handle.ring,
+ handle.minor, S_IFCHR | 0600);
+ free(name);
+ if (err) {
+ EPRINTF("creating ring device for %d failed: %d\n",
+ handle.minor, err);
+ goto fail;
+ }
+
+ if (*devname)
+ name = *devname;
+ else {
+ err = asprintf(&name, "%s%d",
+ BLKTAP2_IO_DEVICE, handle.minor);
+ if (err == -1) {
+ err = ENOMEM;
+ goto fail;
+ }
+ *devname = name;
+ }
+
+ err = tap_ctl_make_device(name, handle.device,
+ handle.minor, S_IFBLK | 0600);
+ if (err) {
+ EPRINTF("creating IO device for %d failed: %d\n",
+ handle.minor, err);
+ goto fail;
+ }
+
+ DBG("new interface: ring: %u, device: %u, minor: %u\n",
+ handle.ring, handle.device, handle.minor);
+
+ *minor = handle.minor;
+ return 0;
+
+fail:
+ tap_ctl_free(handle.minor);
+ return err;
+}
+
+int
+tap_ctl_allocate(int *minor, char **devname)
+{
+ int err;
+
+ *minor = -1;
+
+ err = tap_ctl_check_environment();
+ if (err)
+ return err;
+
+ err = tap_ctl_allocate_device(minor, devname);
+ if (err)
+ return err;
+
+ return 0;
+}
diff --git a/tools/blktap2/control/tap-ctl-attach.c b/tools/blktap2/control/tap-ctl-attach.c
new file mode 100644
index 0000000000..3cb933cec8
--- /dev/null
+++ b/tools/blktap2/control/tap-ctl-attach.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 COPYRIGHT OWNER
+ * 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 <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+
+#include "tap-ctl.h"
+
+int
+tap_ctl_attach(const int id, const int minor)
+{
+ int err;
+ tapdisk_message_t message;
+
+ memset(&message, 0, sizeof(message));
+ message.type = TAPDISK_MESSAGE_ATTACH;
+ message.cookie = minor;
+
+ err = tap_ctl_connect_send_and_receive(id, &message, 5);
+ if (err)
+ return err;
+
+ if (message.type == TAPDISK_MESSAGE_ATTACH_RSP) {
+ err = message.u.response.error;
+ if (err)
+ EPRINTF("attach failed: %d\n", err);
+ } else {
+ EPRINTF("got unexpected result '%s' from %d\n",
+ tapdisk_message_name(message.type), id);
+ err = EINVAL;
+ }
+
+ return err;
+}
diff --git a/tools/blktap2/control/tap-ctl-check.c b/tools/blktap2/control/tap-ctl-check.c
new file mode 100644
index 0000000000..e98583a73b
--- /dev/null
+++ b/tools/blktap2/control/tap-ctl-check.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 COPYRIGHT OWNER
+ * 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 <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "tap-ctl.h"
+#include "blktap2.h"
+
+int
+tap_ctl_check_blktap(const char **msg)
+{
+ FILE *f;
+ int err = 0, minor;
+ char name[32];
+
+ memset(name, 0, sizeof(name));
+
+ f = fopen("/proc/misc", "r");
+ if (!f) {
+ *msg = "failed to open /proc/misc";
+ return -errno;
+ }
+
+ while (fscanf(f, "%d %32s", &minor, name) == 2) {
+ if (!strcmp(name, BLKTAP2_CONTROL_NAME))
+ goto out;
+ }
+
+ err = -ENOSYS;
+ *msg = "blktap kernel module not installed";
+
+out:
+ fclose(f);
+ return err;
+}
+
+int
+tap_ctl_check(const char **msg)
+{
+ int err;
+ uid_t uid;
+
+ err = tap_ctl_check_blktap(msg);
+ if (err)
+ goto out;
+
+ err = 0;
+ *msg = "ok";
+
+out:
+ return err;
+}
diff --git a/tools/blktap2/control/tap-ctl-close.c b/tools/blktap2/control/tap-ctl-close.c
new file mode 100644
index 0000000000..2e5f80b29d
--- /dev/null
+++ b/tools/blktap2/control/tap-ctl-close.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 COPYRIGHT OWNER
+ * 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 <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <getopt.h>
+
+#include "tap-ctl.h"
+
+static int
+__tap_ctl_close(const int id, const int minor, const int force)
+{
+ int err;
+ tapdisk_message_t message;
+
+ memset(&message, 0, sizeof(message));
+ message.type = TAPDISK_MESSAGE_CLOSE;
+ if (force)
+ message.type = TAPDISK_MESSAGE_FORCE_SHUTDOWN;
+ message.cookie = minor;
+
+ err = tap_ctl_connect_send_and_receive(id, &message, 5);
+ if (err)
+ return err;
+
+ if (message.type == TAPDISK_MESSAGE_CLOSE_RSP) {
+ err = message.u.response.error;
+ if (err)
+ EPRINTF("close failed: %d\n", err);
+ } else {
+ EPRINTF("got unexpected result '%s' from %d\n",
+ tapdisk_message_name(message.type), id);
+ err = EINVAL;
+ }
+
+ return err;
+}
+
+int
+tap_ctl_close(const int id, const int minor, const int force)
+{
+ int i, err;
+
+ for (i = 0; i < 20; i++) {
+ err = __tap_ctl_close(id, minor, force);
+ if (!err)
+ return 0;
+
+ err = (err < 0 ? -err : err);
+ if (err != EAGAIN) {
+ EPRINTF("close failed: %d\n", err);
+ return err;
+ }
+
+ usleep(1000);
+ }
+
+ EPRINTF("close timed out\n");
+ return EIO;
+}
diff --git a/tools/blktap2/control/tap-ctl-create.c b/tools/blktap2/control/tap-ctl-create.c
new file mode 100644
index 0000000000..46d135e93c
--- /dev/null
+++ b/tools/blktap2/control/tap-ctl-create.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 COPYRIGHT OWNER
+ * 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 <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+
+#include "tap-ctl.h"
+#include "blktap2.h"
+
+int
+tap_ctl_create(const char *params, char **devname)
+{
+ int err, id, minor;
+
+ err = tap_ctl_allocate(&minor, devname);
+ if (err)
+ return err;
+
+ id = tap_ctl_spawn();
+ if (id < 0)
+ goto destroy;
+
+ err = tap_ctl_attach(id, minor);
+ if (err)
+ goto destroy;
+
+ err = tap_ctl_open(id, minor, params);
+ if (err)
+ goto detach;
+
+ return 0;
+
+detach:
+ tap_ctl_detach(id, minor);
+destroy:
+ tap_ctl_free(minor);
+ return err;
+}
diff --git a/tools/blktap2/control/tap-ctl-destroy.c b/tools/blktap2/control/tap-ctl-destroy.c
new file mode 100644
index 0000000000..dc5dbaa1a2
--- /dev/null
+++ b/tools/blktap2/control/tap-ctl-destroy.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 COPYRIGHT OWNER
+ * 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 <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+
+#include "tap-ctl.h"
+#include "blktap2.h"
+
+int
+tap_ctl_destroy(const int id, const int minor)
+{
+ int err;
+
+ err = tap_ctl_close(id, minor, 0);
+ if (err)
+ return err;
+
+ err = tap_ctl_detach(id, minor);
+ if (err)
+ return err;
+
+ err = tap_ctl_free(minor);
+ if (err)
+ return err;
+
+ return 0;
+}
diff --git a/tools/blktap2/control/tap-ctl-detach.c b/tools/blktap2/control/tap-ctl-detach.c
new file mode 100644
index 0000000000..7d7bbf30d3
--- /dev/null
+++ b/tools/blktap2/control/tap-ctl-detach.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 COPYRIGHT OWNER
+ * 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 <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+
+#include "tap-ctl.h"
+
+int
+tap_ctl_detach(const int id, const int minor)
+{
+ int err;
+ tapdisk_message_t message;
+
+ memset(&message, 0, sizeof(message));
+ message.type = TAPDISK_MESSAGE_DETACH;
+ message.cookie = minor;
+
+ err = tap_ctl_connect_send_and_receive(id, &message, 5);
+ if (err)
+ return err;
+
+ if (message.type == TAPDISK_MESSAGE_DETACH_RSP) {
+ err = message.u.response.error;
+ if (err < 0)
+ printf("detach failed: %d\n", err);
+ } else {
+ printf("got unexpected result '%s' from %d\n",
+ tapdisk_message_name(message.type), id);
+ err = EINVAL;
+ }
+
+ return err;
+}
diff --git a/tools/blktap2/control/tap-ctl-free.c b/tools/blktap2/control/tap-ctl-free.c
new file mode 100644
index 0000000000..9ae7295747
--- /dev/null
+++ b/tools/blktap2/control/tap-ctl-free.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 COPYRIGHT OWNER
+ * 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 <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <sys/ioctl.h>
+
+#include "tap-ctl.h"
+#include "blktap2.h"
+
+int
+tap_ctl_free(const int minor)
+{
+ int fd, err;
+
+ fd = open(BLKTAP2_CONTROL_DEVICE, O_RDONLY);
+ if (fd == -1) {
+ EPRINTF("failed to open control device: %d\n", errno);
+ return errno;
+ }
+
+ err = ioctl(fd, BLKTAP2_IOCTL_FREE_TAP, minor);
+ close(fd);
+
+ return err;
+}
diff --git a/tools/blktap2/control/tap-ctl-ipc.c b/tools/blktap2/control/tap-ctl-ipc.c
new file mode 100644
index 0000000000..cc6160e9da
--- /dev/null
+++ b/tools/blktap2/control/tap-ctl-ipc.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 COPYRIGHT OWNER
+ * 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 <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "tap-ctl.h"
+#include "blktap2.h"
+
+int tap_ctl_debug = 0;
+
+int
+tap_ctl_read_message(int fd, tapdisk_message_t *message, int timeout)
+{
+ fd_set readfds;
+ int ret, len, offset;
+ struct timeval tv, *t;
+
+ t = NULL;
+ offset = 0;
+ len = sizeof(tapdisk_message_t);
+
+ if (timeout) {
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+ t = &tv;
+ }
+
+ memset(message, 0, sizeof(tapdisk_message_t));
+
+ while (offset < len) {
+ FD_ZERO(&readfds);
+ FD_SET(fd, &readfds);
+
+ ret = select(fd + 1, &readfds, NULL, NULL, t);
+ if (ret == -1)
+ break;
+ else if (FD_ISSET(fd, &readfds)) {
+ ret = read(fd, message + offset, len - offset);
+ if (ret <= 0)
+ break;
+ offset += ret;
+ } else
+ break;
+ }
+
+ if (offset != len) {
+ EPRINTF("failure reading message\n");
+ return -EIO;
+ }
+
+ DBG("received '%s' message (uuid = %u)\n",
+ tapdisk_message_name(message->type), message->cookie);
+
+ return 0;
+}
+
+int
+tap_ctl_write_message(int fd, tapdisk_message_t *message, int timeout)
+{
+ fd_set writefds;
+ int ret, len, offset;
+ struct timeval tv, *t;
+
+ t = NULL;
+ offset = 0;
+ len = sizeof(tapdisk_message_t);
+
+ if (timeout) {
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+ t = &tv;
+ }
+
+ DBG("sending '%s' message (uuid = %u)\n",
+ tapdisk_message_name(message->type), message->cookie);
+
+ while (offset < len) {
+ FD_ZERO(&writefds);
+ FD_SET(fd, &writefds);
+
+ /* we don't bother reinitializing tv. at worst, it will wait a
+ * bit more time than expected. */
+
+ ret = select(fd + 1, NULL, &writefds, NULL, t);
+ if (ret == -1)
+ break;
+ else if (FD_ISSET(fd, &writefds)) {
+ ret = write(fd, message + offset, len - offset);
+ if (ret <= 0)
+ break;
+ offset += ret;
+ } else
+ break;
+ }
+
+ if (offset != len) {
+ EPRINTF("failure writing message\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int
+tap_ctl_send_and_receive(int sfd, tapdisk_message_t *message, int timeout)
+{
+ int err;
+
+ err = tap_ctl_write_message(sfd, message, timeout);
+ if (err) {
+ EPRINTF("failed to send '%s' message\n",
+ tapdisk_message_name(message->type));
+ return err;
+ }
+
+ err = tap_ctl_read_message(sfd, message, timeout);
+ if (err) {
+ EPRINTF("failed to receive '%s' message\n",
+ tapdisk_message_name(message->type));
+ return err;
+ }
+
+ return 0;
+}
+
+char *
+tap_ctl_socket_name(int id)
+{
+ char *name;
+
+ if (asprintf(&name, "%s/%s%d",
+ BLKTAP2_CONTROL_DIR, BLKTAP2_CONTROL_SOCKET, id) == -1)
+ return NULL;
+
+ return name;
+}
+
+int
+tap_ctl_connect(const char *name, int *sfd)
+{
+ int fd, err;
+ struct sockaddr_un saddr;
+
+ *sfd = -1;
+
+ fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd == -1) {
+ EPRINTF("couldn't create socket for %s: %d\n", name, errno);
+ return -errno;
+ }
+
+ memset(&saddr, 0, sizeof(saddr));
+ saddr.sun_family = AF_UNIX;
+ strcpy(saddr.sun_path, name);
+
+ err = connect(fd, (const struct sockaddr *)&saddr, sizeof(saddr));
+ if (err) {
+ EPRINTF("couldn't connect to %s: %d\n", name, errno);
+ close(fd);
+ return -errno;
+ }
+
+ *sfd = fd;
+ return 0;
+}
+
+int
+tap_ctl_connect_id(int id, int *sfd)
+{
+ int err;
+ char *name;
+
+ *sfd = -1;
+
+ if (id < 0) {
+ EPRINTF("invalid id %d\n", id);
+ return -EINVAL;
+ }
+
+ name = tap_ctl_socket_name(id);
+ if (!name) {
+ EPRINTF("couldn't name socket for %d\n", id);
+ return -ENOMEM;
+ }
+
+ err = tap_ctl_connect(name, sfd);
+ free(name);
+
+ return err;
+}
+
+int
+tap_ctl_connect_send_and_receive(int id, tapdisk_message_t *message, int timeout)
+{
+ int err, sfd;
+
+ err = tap_ctl_connect_id(id, &sfd);
+ if (err)
+ return err;
+
+ err = tap_ctl_send_and_receive(sfd, message, timeout);
+
+ close(sfd);
+ return err;
+}
diff --git a/tools/blktap2/control/tap-ctl-list.c b/tools/blktap2/control/tap-ctl-list.c
new file mode 100644
index 0000000000..af5922772c
--- /dev/null
+++ b/tools/blktap2/control/tap-ctl-list.c
@@ -0,0 +1,506 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 COPYRIGHT OWNER
+ * 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 <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <glob.h>
+
+#include "tap-ctl.h"
+#include "blktap2.h"
+#include "list.h"
+
+static void
+free_list(tap_list_t *entry)
+{
+ if (entry->type) {
+ free(entry->type);
+ entry->type = NULL;
+ }
+
+ if (entry->path) {
+ free(entry->path);
+ entry->path = NULL;
+ }
+
+ free(entry);
+}
+
+int
+_parse_params(const char *params, char **type, char **path)
+{
+ char *ptr;
+ size_t len;
+
+ ptr = strchr(params, ':');
+ if (!ptr)
+ return -EINVAL;
+
+ len = ptr - params;
+
+ *type = strndup(params, len);
+ *path = strdup(params + len + 1);
+
+ if (!*type || !*path) {
+ free(*type);
+ *type = NULL;
+
+ free(*path);
+ *path = NULL;
+
+ return -errno;
+ }
+
+ return 0;
+}
+
+static int
+init_list(tap_list_t *entry,
+ int tap_id, pid_t tap_pid, int vbd_minor, int vbd_state,
+ const char *params)
+{
+ int err = 0;
+
+ entry->id = tap_id;
+ entry->pid = tap_pid;
+ entry->minor = vbd_minor;
+ entry->state = vbd_state;
+
+ if (params)
+ err = _parse_params(params, &entry->type, &entry->path);
+
+ return err;
+}
+
+void
+tap_ctl_free_list(tap_list_t **list)
+{
+ tap_list_t **_entry;
+
+ for (_entry = list; *_entry != NULL; ++_entry)
+ free_list(*_entry);
+
+ free(list);
+}
+
+static tap_list_t**
+tap_ctl_alloc_list(int n)
+{
+ tap_list_t **list, *entry;
+ size_t size;
+ int i;
+
+ size = sizeof(tap_list_t*) * (n+1);
+ list = malloc(size);
+ if (!list)
+ goto fail;
+
+ memset(list, 0, size);
+
+ for (i = 0; i < n; ++i) {
+ tap_list_t *entry;
+
+ entry = malloc(sizeof(tap_list_t));
+ if (!entry)
+ goto fail;
+
+ memset(entry, 0, sizeof(tap_list_t));
+
+ list[i] = entry;
+ }
+
+ return list;
+
+fail:
+ if (list)
+ tap_ctl_free_list(list);
+
+ return NULL;
+}
+
+static int
+tap_ctl_list_length(const tap_list_t **list)
+{
+ const tap_list_t **_entry;
+ int n;
+
+ n = 0;
+ for (_entry = list; *_entry != NULL; ++_entry)
+ n++;
+
+ return n;
+}
+
+static int
+_tap_minor_cmp(const void *a, const void *b)
+{
+ return *(int*)a - *(int*)b;
+}
+
+int
+_tap_ctl_find_minors(int **_minorv)
+{
+ glob_t glbuf = { 0 };
+ const char *pattern, *format;
+ int *minorv = NULL, n_minors = 0;
+ int err, i;
+
+ pattern = BLKTAP2_SYSFS_DIR"/blktap*";
+ format = BLKTAP2_SYSFS_DIR"/blktap%d";
+
+ n_minors = 0;
+ minorv = NULL;
+
+ err = glob(pattern, 0, NULL, &glbuf);
+ switch (err) {
+ case GLOB_NOMATCH:
+ goto done;
+
+ case GLOB_ABORTED:
+ case GLOB_NOSPACE:
+ err = -errno;
+ EPRINTF("%s: glob failed, err %d", pattern, err);
+ goto fail;
+ }
+
+ minorv = malloc(sizeof(int) * glbuf.gl_pathc);
+ if (!minorv) {
+ err = -errno;
+ goto fail;
+ }
+
+ for (i = 0; i < glbuf.gl_pathc; ++i) {
+ int n;
+
+ n = sscanf(glbuf.gl_pathv[i], format, &minorv[n_minors]);
+ if (n != 1)
+ continue;
+
+ n_minors++;
+ }
+
+ qsort(minorv, n_minors, sizeof(int), _tap_minor_cmp);
+
+done:
+ *_minorv = minorv;
+ err = 0;
+
+out:
+ if (glbuf.gl_pathv)
+ globfree(&glbuf);
+
+ return err ? : n_minors;
+
+fail:
+ if (minorv)
+ free(minorv);
+
+ goto out;
+}
+
+struct tapdisk {
+ int id;
+ pid_t pid;
+ struct list_head list;
+};
+
+static int
+_tap_tapdisk_cmp(const void *a, const void *b)
+{
+ return ((struct tapdisk*)a)->id - ((struct tapdisk*)b)->id;
+}
+
+int
+_tap_ctl_find_tapdisks(struct tapdisk **_tapv)
+{
+ glob_t glbuf = { 0 };
+ const char *pattern, *format;
+ struct tapdisk *tapv = NULL;
+ int err, i, n_taps = 0;
+
+ pattern = BLKTAP2_CONTROL_DIR"/"BLKTAP2_CONTROL_SOCKET"*";
+ format = BLKTAP2_CONTROL_DIR"/"BLKTAP2_CONTROL_SOCKET"%d";
+
+ n_taps = 0;
+ tapv = NULL;
+
+ err = glob(pattern, 0, NULL, &glbuf);
+ switch (err) {
+ case GLOB_NOMATCH:
+ goto done;
+
+ case GLOB_ABORTED:
+ case GLOB_NOSPACE:
+ err = -errno;
+ EPRINTF("%s: glob failed, err %d", pattern, err);
+ goto fail;
+ }
+
+ tapv = malloc(sizeof(struct tapdisk) * glbuf.gl_pathc);
+ if (!tapv) {
+ err = -errno;
+ goto fail;
+ }
+
+ for (i = 0; i < glbuf.gl_pathc; ++i) {
+ struct tapdisk *tap;
+ int n;
+
+ tap = &tapv[n_taps];
+
+ err = sscanf(glbuf.gl_pathv[i], format, &tap->id);
+ if (err != 1)
+ continue;
+
+ tap->pid = tap_ctl_get_pid(tap->id);
+ if (tap->pid < 0)
+ continue;
+
+ n_taps++;
+ }
+
+ qsort(tapv, n_taps, sizeof(struct tapdisk), _tap_tapdisk_cmp);
+
+ for (i = 0; i < n_taps; ++i)
+ INIT_LIST_HEAD(&tapv[i].list);
+
+done:
+ *_tapv = tapv;
+ err = 0;
+
+out:
+ if (glbuf.gl_pathv)
+ globfree(&glbuf);
+
+ return err ? : n_taps;
+
+fail:
+ if (tapv)
+ free(tapv);
+
+ goto out;
+}
+
+struct tapdisk_list {
+ int minor;
+ int state;
+ char *params;
+ struct list_head entry;
+};
+
+int
+_tap_ctl_list_tapdisk(int id, struct list_head *_list)
+{
+ tapdisk_message_t message;
+ struct list_head list;
+ struct tapdisk_list *tl, *next;
+ int err, sfd;
+
+ err = tap_ctl_connect_id(id, &sfd);
+ if (err)
+ return err;
+
+ memset(&message, 0, sizeof(message));
+ message.type = TAPDISK_MESSAGE_LIST;
+ message.cookie = -1;
+
+ err = tap_ctl_write_message(sfd, &message, 2);
+ if (err)
+ return err;
+
+ INIT_LIST_HEAD(&list);
+ do {
+ err = tap_ctl_read_message(sfd, &message, 2);
+ if (err) {
+ err = -EPROTO;
+ break;
+ }
+
+ if (message.u.list.count == 0)
+ break;
+
+ tl = malloc(sizeof(struct tapdisk_list));
+ if (!tl) {
+ err = -ENOMEM;
+ break;
+ }
+
+ tl->minor = message.u.list.minor;
+ tl->state = message.u.list.state;
+ if (message.u.list.path[0] != 0) {
+ tl->params = strndup(message.u.list.path,
+ sizeof(message.u.list.path));
+ if (!tl->params) {
+ err = -errno;
+ break;
+ }
+ } else
+ tl->params = NULL;
+
+ list_add(&tl->entry, &list);
+ } while (1);
+
+ if (err)
+ list_for_each_entry_safe(tl, next, &list, entry) {
+ list_del(&tl->entry);
+ free(tl->params);
+ free(tl);
+ }
+
+ close(sfd);
+ list_splice(&list, _list);
+ return err;
+}
+
+void
+_tap_ctl_free_tapdisks(struct tapdisk *tapv, int n_taps)
+{
+ struct tapdisk *tap;
+
+ for (tap = tapv; tap < &tapv[n_taps]; ++tap) {
+ struct tapdisk_list *tl;
+
+ list_for_each_entry(tl, &tap->list, entry) {
+ free(tl->params);
+ free(tl);
+ }
+ }
+
+ free(tapv);
+}
+
+int
+_tap_list_join3(int n_minors, int *minorv, int n_taps, struct tapdisk *tapv,
+ tap_list_t ***_list)
+{
+ tap_list_t **list, **_entry, *entry;
+ int i, _m, err;
+
+ list = tap_ctl_alloc_list(n_minors + n_taps);
+ if (!list) {
+ err = -ENOMEM;
+ goto fail;
+ }
+
+ _entry = list;
+
+ for (i = 0; i < n_taps; ++i) {
+ struct tapdisk *tap = &tapv[i];
+ struct tapdisk_list *tl;
+
+ /* orphaned tapdisk */
+ if (list_empty(&tap->list)) {
+ err = init_list(*_entry++, tap->id, tap->pid, -1, -1, NULL);
+ if (err)
+ goto fail;
+ continue;
+ }
+
+ list_for_each_entry(tl, &tap->list, entry) {
+
+ err = init_list(*_entry++,
+ tap->id, tap->pid,
+ tl->minor, tl->state, tl->params);
+ if (err)
+ goto fail;
+
+ if (tl->minor >= 0) {
+ /* clear minor */
+ for (_m = 0; _m < n_minors; ++_m) {
+ if (minorv[_m] == tl->minor) {
+ minorv[_m] = -1;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* orphaned minors */
+ for (_m = 0; _m < n_minors; ++_m) {
+ int minor = minorv[_m];
+ if (minor >= 0) {
+ err = init_list(*_entry++, -1, -1, minor, -1, NULL);
+ if (err)
+ goto fail;
+ }
+ }
+
+ /* free extraneous list entries */
+ for (; *_entry != NULL; ++entry) {
+ free_list(*_entry);
+ *_entry = NULL;
+ }
+
+ *_list = list;
+
+ return 0;
+
+fail:
+ if (list)
+ tap_ctl_free_list(list);
+
+ return err;
+}
+
+int
+tap_ctl_list(tap_list_t ***list)
+{
+ int n_taps, n_minors, err, *minorv;
+ struct tapdisk *tapv, *tap;
+
+ n_taps = -1;
+ n_minors = -1;
+
+ err = n_minors = _tap_ctl_find_minors(&minorv);
+ if (err < 0)
+ goto out;
+
+ err = n_taps = _tap_ctl_find_tapdisks(&tapv);
+ if (err < 0)
+ goto out;
+
+ for (tap = tapv; tap < &tapv[n_taps]; ++tap) {
+ err = _tap_ctl_list_tapdisk(tap->id, &tap->list);
+ if (err)
+ goto out;
+ }
+
+ err = _tap_list_join3(n_minors, minorv, n_taps, tapv, list);
+
+out:
+ if (n_taps > 0)
+ _tap_ctl_free_tapdisks(tapv, n_taps);
+
+ if (n_minors > 0)
+ free(minorv);
+
+ return err;
+}
diff --git a/tools/blktap2/control/tap-ctl-major.c b/tools/blktap2/control/tap-ctl-major.c
new file mode 100644
index 0000000000..847af28708
--- /dev/null
+++ b/tools/blktap2/control/tap-ctl-major.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 COPYRIGHT OWNER
+ * 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 <stdio.h>
+#include <errno.h>
+
+#include "tap-ctl.h"
+
+int
+tap_ctl_blk_major(void)
+{
+ FILE *devices;
+ int rv, major;
+
+ devices = fopen("/proc/devices", "r");
+ if (!devices) {
+ rv = -errno;
+ goto out;
+ }
+
+ do {
+ char buf[32], *s;
+ int n, offset;
+
+ s = fgets(buf, sizeof(buf), devices);
+ if (!s)
+ break;
+
+ major = -ENODEV;
+ offset = 0;
+
+ n = sscanf(buf, "%d tapdev%n", &major, &offset);
+ if (n == 1 && offset)
+ break;
+ } while (1);
+
+ rv = major;
+
+out:
+ if (devices)
+ fclose(devices);
+
+ return rv;
+}
diff --git a/tools/blktap2/control/tap-ctl-open.c b/tools/blktap2/control/tap-ctl-open.c
new file mode 100644
index 0000000000..5961c99183
--- /dev/null
+++ b/tools/blktap2/control/tap-ctl-open.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 COPYRIGHT OWNER
+ * 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 <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <getopt.h>
+
+#include "tap-ctl.h"
+#include "blktaplib.h"
+
+int
+tap_ctl_open(const int id, const int minor, const char *params)
+{
+ int err;
+ tapdisk_message_t message;
+
+ memset(&message, 0, sizeof(message));
+ message.type = TAPDISK_MESSAGE_OPEN;
+ message.cookie = minor;
+ message.u.params.storage = TAPDISK_STORAGE_TYPE_DEFAULT;
+ message.u.params.devnum = minor;
+
+ err = snprintf(message.u.params.path,
+ sizeof(message.u.params.path) - 1, "%s", params);
+ if (err >= sizeof(message.u.params.path)) {
+ EPRINTF("name too long\n");
+ return ENAMETOOLONG;
+ }
+
+ err = tap_ctl_connect_send_and_receive(id, &message, 5);
+ if (err)
+ return err;
+
+ switch (message.type) {
+ case TAPDISK_MESSAGE_OPEN_RSP:
+ break;
+ case TAPDISK_MESSAGE_ERROR:
+ err = -message.u.response.error;
+ EPRINTF("open failed, err %d\n", err);
+ break;
+ default:
+ EPRINTF("got unexpected result '%s' from %d\n",
+ tapdisk_message_name(message.type), id);
+ err = EINVAL;
+ }
+
+ return err;
+}
diff --git a/tools/blktap2/control/tap-ctl-pause.c b/tools/blktap2/control/tap-ctl-pause.c
new file mode 100644
index 0000000000..5e31a5866d
--- /dev/null
+++ b/tools/blktap2/control/tap-ctl-pause.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 COPYRIGHT OWNER
+ * 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 <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "tap-ctl.h"
+
+int
+tap_ctl_pause(const int id, const int minor)
+{
+ int err;
+ tapdisk_message_t message;
+
+ memset(&message, 0, sizeof(message));
+ message.type = TAPDISK_MESSAGE_PAUSE;
+ message.cookie = minor;
+
+ err = tap_ctl_connect_send_and_receive(id, &message, 5);
+ if (err)
+ return err;
+
+ if (message.type == TAPDISK_MESSAGE_PAUSE_RSP)
+ err = message.u.response.error;
+ else {
+ err = EINVAL;
+ EPRINTF("got unexpected result '%s' from %d\n",
+ tapdisk_message_name(message.type), id);
+ }
+
+ return err;
+}
diff --git a/tools/blktap2/control/tap-ctl-spawn.c b/tools/blktap2/control/tap-ctl-spawn.c
new file mode 100644
index 0000000000..31a651ec38
--- /dev/null
+++ b/tools/blktap2/control/tap-ctl-spawn.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 COPYRIGHT OWNER
+ * 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 <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/wait.h>
+
+#include "tap-ctl.h"
+#include "blktap2.h"
+
+static pid_t
+__tap_ctl_spawn(int *readfd)
+{
+ int err, child, channel[2];
+ char *tapdisk;
+
+ if (pipe(channel)) {
+ EPRINTF("pipe failed: %d\n", errno);
+ return -errno;
+ }
+
+ if ((child = fork()) == -1) {
+ EPRINTF("fork failed: %d\n", errno);
+ return -errno;
+ }
+
+ if (child) {
+ close(channel[1]);
+ *readfd = channel[0];
+ return child;
+ }
+
+ if (dup2(channel[1], STDOUT_FILENO) == -1) {
+ EPRINTF("dup2 failed: %d\n", errno);
+ exit(errno);
+ }
+
+ if (dup2(channel[1], STDERR_FILENO) == -1) {
+ EPRINTF("dup2 failed: %d\n", errno);
+ exit(errno);
+ }
+
+ close(channel[0]);
+ close(channel[1]);
+
+ tapdisk = getenv("TAPDISK2");
+ if (!tapdisk)
+ tapdisk = "tapdisk2";
+
+ execlp(tapdisk, tapdisk, NULL);
+
+ EPRINTF("exec failed\n");
+ exit(1);
+}
+
+pid_t
+tap_ctl_get_pid(const int id)
+{
+ int err;
+ tapdisk_message_t message;
+
+ memset(&message, 0, sizeof(message));
+ message.type = TAPDISK_MESSAGE_PID;
+
+ err = tap_ctl_connect_send_and_receive(id, &message, 2);
+ if (err)
+ return err;
+
+ return message.u.tapdisk_pid;
+}
+
+static int
+tap_ctl_wait(pid_t child)
+{
+ pid_t pid;
+ int status;
+
+ pid = waitpid(child, &status, 0);
+ if (pid < 0) {
+ EPRINTF("wait(%d) failed, err %d\n", child, errno);
+ return -errno;
+ }
+
+ if (WIFEXITED(status)) {
+ int code = WEXITSTATUS(status);
+ if (code)
+ EPRINTF("tapdisk2[%d] failed, status %d\n", child, code);
+ return -code;
+ }
+
+ if (WIFSIGNALED(status)) {
+ int signo = WTERMSIG(status);
+ EPRINTF("tapdisk2[%d] killed by signal %d\n", child, signo);
+ return -EINTR;
+ }
+
+ EPRINTF("tapdisk2[%d]: unexpected status %#x\n", child, status);
+ return -EAGAIN;
+}
+
+static int
+tap_ctl_get_child_id(int readfd)
+{
+ int id;
+ FILE *f;
+
+ f = fdopen(readfd, "r");
+ if (!f) {
+ EPRINTF("fdopen failed: %d\n", errno);
+ return -1;
+ }
+
+ errno = 0;
+ if (fscanf(f, BLKTAP2_CONTROL_DIR"/"
+ BLKTAP2_CONTROL_SOCKET"%d", &id) != 1) {
+ errno = (errno ? : EINVAL);
+ EPRINTF("parsing id failed: %d\n", errno);
+ id = -1;
+ }
+
+ fclose(f);
+ return id;
+}
+
+int
+tap_ctl_spawn(void)
+{
+ pid_t child;
+ int err, id, readfd;
+
+ readfd = -1;
+
+ child = __tap_ctl_spawn(&readfd);
+ if (child < 0)
+ return child;
+
+ err = tap_ctl_wait(child);
+ if (err)
+ return err;
+
+ id = tap_ctl_get_child_id(readfd);
+ if (id < 0)
+ EPRINTF("get_id failed, child %d err %d\n", child, errno);
+
+ return id;
+}
diff --git a/tools/blktap2/control/tap-ctl-unpause.c b/tools/blktap2/control/tap-ctl-unpause.c
new file mode 100644
index 0000000000..dfb7450226
--- /dev/null
+++ b/tools/blktap2/control/tap-ctl-unpause.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 COPYRIGHT OWNER
+ * 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 <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <getopt.h>
+
+#include "tap-ctl.h"
+
+int
+tap_ctl_unpause(const int id, const int minor, const char *params)
+{
+ int err;
+ tapdisk_message_t message;
+
+ memset(&message, 0, sizeof(message));
+ message.type = TAPDISK_MESSAGE_RESUME;
+ message.cookie = minor;
+
+ if (params)
+ strncpy(message.u.params.path, params,
+ sizeof(message.u.params.path) - 1);
+
+ err = tap_ctl_connect_send_and_receive(id, &message, 15);
+ if (err)
+ return err;
+
+ if (message.type == TAPDISK_MESSAGE_RESUME_RSP)
+ err = message.u.response.error;
+ else {
+ err = EINVAL;
+ EPRINTF("got unexpected result '%s' from %d\n",
+ tapdisk_message_name(message.type), id);
+ }
+
+ return err;
+}
diff --git a/tools/blktap2/control/tap-ctl.c b/tools/blktap2/control/tap-ctl.c
new file mode 100644
index 0000000000..80fc933a89
--- /dev/null
+++ b/tools/blktap2/control/tap-ctl.c
@@ -0,0 +1,815 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 COPYRIGHT OWNER
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+
+#include "tap-ctl.h"
+
+typedef int (*tap_ctl_func_t) (int, char **);
+
+struct command {
+ char *name;
+ tap_ctl_func_t func;
+};
+
+static void
+tap_cli_list_usage(FILE *stream)
+{
+ fprintf(stream,
+ "usage: list [-h] [-p pid] [-m minor] [-t type] [-f file]\n");
+}
+
+static void
+tap_ctl_list_row(tap_list_t *entry)
+{
+ char minor_str[10] = "-";
+ char state_str[10] = "-";
+ char pid_str[10] = "-";
+
+ if (entry->pid != -1)
+ sprintf(pid_str, "%d", entry->pid);
+
+ if (entry->minor != -1)
+ sprintf(minor_str, "%d", entry->minor);
+
+ if (entry->state != -1)
+ sprintf(state_str, "%x", entry->state);
+
+ printf("%8s %2s %4s %10s %s\n",
+ pid_str, minor_str, state_str,
+ entry->type ? : "-", entry->path ? : "-");
+}
+
+static void
+tap_ctl_list_dict(tap_list_t *entry)
+{
+ int d = 0;
+
+ if (entry->pid != -1) {
+ if (d) putc(' ', stdout);
+ d = printf("pid=%d", entry->pid);
+ }
+
+ if (entry->minor != -1) {
+ if (d) putc(' ', stdout);
+ d = printf("minor=%d", entry->minor);
+ }
+
+ if (entry->state != -1) {
+ if (d) putc(' ', stdout);
+ d = printf("state=%d", entry->state);
+ }
+
+ if (entry->type && entry->path) {
+ if (d) putc(' ', stdout);
+ d = printf("args=%s:%s", entry->type, entry->path);
+ }
+
+ putc('\n', stdout);
+}
+
+int
+tap_cli_list(int argc, char **argv)
+{
+ tap_list_t **list, **_entry;
+ int c, minor, tty, err;
+ const char *type, *file;
+ pid_t pid;
+
+ err = tap_ctl_list(&list);
+ if (err)
+ return -err;
+
+ pid = -1;
+ minor = -1;
+ type = NULL;
+ file = NULL;
+
+ while ((c = getopt(argc, argv, "m:p:t:f:h")) != -1) {
+ switch (c) {
+ case 'm':
+ minor = atoi(optarg);
+ break;
+ case 'p':
+ pid = atoi(optarg);
+ break;
+ case 't':
+ type = optarg;
+ break;
+ case 'f':
+ file = optarg;
+ break;
+ case '?':
+ goto usage;
+ case 'h':
+ tap_cli_list_usage(stdout);
+ return 0;
+ }
+ }
+
+ tty = isatty(STDOUT_FILENO);
+
+ for (_entry = list; *_entry != NULL; ++_entry) {
+ tap_list_t *entry = *_entry;
+
+ if (minor >= 0 && entry->minor != minor)
+ continue;
+
+ if (pid >= 0 && entry->pid != pid)
+ continue;
+
+ if (type && entry->type && strcmp(entry->type, type))
+ continue;
+
+ if (file && entry->path && strcmp(entry->path, file))
+ continue;
+
+ if (tty)
+ tap_ctl_list_row(entry);
+ else
+ tap_ctl_list_dict(entry);
+ }
+
+ tap_ctl_free_list(list);
+
+ return 0;
+
+usage:
+ tap_cli_list_usage(stderr);
+ return EINVAL;
+}
+
+static void
+tap_cli_allocate_usage(FILE *stream)
+{
+ fprintf(stream, "usage: allocate [-d device name]>\n");
+}
+
+static int
+tap_cli_allocate(int argc, char **argv)
+{
+ char *devname;
+ int c, minor, err;
+
+ devname = NULL;
+
+ optind = 0;
+ while ((c = getopt(argc, argv, "d:h")) != -1) {
+ switch (c) {
+ case 'd':
+ devname = optarg;
+ break;
+ case '?':
+ goto usage;
+ case 'h':
+ tap_cli_allocate_usage(stdout);
+ return 0;
+ }
+ }
+
+ err = tap_ctl_allocate(&minor, &devname);
+ if (!err)
+ printf("%s\n", devname);
+
+ return err;
+
+usage:
+ tap_cli_allocate_usage(stderr);
+ return EINVAL;
+}
+
+static void
+tap_cli_free_usage(FILE *stream)
+{
+ fprintf(stream, "usage: free <-m minor>\n");
+}
+
+static int
+tap_cli_free(int argc, char **argv)
+{
+ int c, minor;
+
+ minor = -1;
+
+ optind = 0;
+ while ((c = getopt(argc, argv, "m:h")) != -1) {
+ switch (c) {
+ case 'm':
+ minor = atoi(optarg);
+ break;
+ case '?':
+ goto usage;
+ case 'h':
+ tap_cli_free_usage(stdout);
+ return 0;
+ }
+ }
+
+ if (minor == -1)
+ goto usage;
+
+ return tap_ctl_free(minor);
+
+usage:
+ tap_cli_free_usage(stderr);
+ return EINVAL;
+}
+
+static void
+tap_cli_create_usage(FILE *stream)
+{
+ fprintf(stream, "usage: create <-a args> [-d device name]\n");
+}
+
+static int
+tap_cli_create(int argc, char **argv)
+{
+ int c, err;
+ char *args, *devname;
+
+ args = NULL;
+ devname = NULL;
+
+ optind = 0;
+ while ((c = getopt(argc, argv, "a:d:h")) != -1) {
+ switch (c) {
+ case 'a':
+ args = optarg;
+ break;
+ case 'd':
+ devname = optarg;
+ break;
+ case '?':
+ goto usage;
+ case 'h':
+ tap_cli_create_usage(stdout);
+ return 0;
+ }
+ }
+
+ if (!args)
+ goto usage;
+
+ err = tap_ctl_create(args, &devname);
+ if (!err)
+ printf("%s\n", devname);
+
+ return err;
+
+usage:
+ tap_cli_create_usage(stderr);
+ return EINVAL;
+}
+
+static void
+tap_cli_destroy_usage(FILE *stream)
+{
+ fprintf(stream, "usage: destroy <-p pid> <-m minor>\n");
+}
+
+static int
+tap_cli_destroy(int argc, char **argv)
+{
+ int c, pid, minor;
+
+ pid = -1;
+ minor = -1;
+
+ optind = 0;
+ while ((c = getopt(argc, argv, "p:m:h")) != -1) {
+ switch (c) {
+ case 'p':
+ pid = atoi(optarg);
+ break;
+ case 'm':
+ minor = atoi(optarg);
+ break;
+ case '?':
+ goto usage;
+ case 'h':
+ tap_cli_destroy_usage(stdout);
+ return 0;
+ }
+ }
+
+ if (pid == -1 || minor == -1)
+ goto usage;
+
+ return tap_ctl_destroy(pid, minor);
+
+usage:
+ tap_cli_destroy_usage(stderr);
+ return EINVAL;
+}
+
+static void
+tap_cli_spawn_usage(FILE *stream)
+{
+ fprintf(stream, "usage: spawn\n");
+}
+
+static int
+tap_cli_spawn(int argc, char **argv)
+{
+ int c;
+ pid_t task;
+
+ optind = 0;
+ while ((c = getopt(argc, argv, "h")) != -1) {
+ switch (c) {
+ case '?':
+ goto usage;
+ case 'h':
+ tap_cli_spawn_usage(stdout);
+ return 0;
+ }
+ }
+
+ task = tap_ctl_spawn();
+ if (task < 0) {
+ printf("spawn failed: %d\n", errno);
+ return task;
+ }
+
+ printf("tapdisk spawned with pid %d\n", task);
+ return 0;
+
+usage:
+ tap_cli_spawn_usage(stderr);
+ return EINVAL;
+}
+
+static void
+tap_cli_attach_usage(FILE *stream)
+{
+ fprintf(stream, "usage: attach <-p pid> <-m minor>\n");
+}
+
+static int
+tap_cli_attach(int argc, char **argv)
+{
+ int c, pid, minor;
+
+ pid = -1;
+ minor = -1;
+
+ optind = 0;
+ while ((c = getopt(argc, argv, "p:m:h")) != -1) {
+ switch (c) {
+ case 'p':
+ pid = atoi(optarg);
+ break;
+ case 'm':
+ minor = atoi(optarg);
+ break;
+ case '?':
+ goto usage;
+ case 'h':
+ tap_cli_attach_usage(stderr);
+ return 0;
+ }
+ }
+
+ if (pid == -1 || minor == -1)
+ goto usage;
+
+ return tap_ctl_attach(pid, minor);
+
+usage:
+ tap_cli_attach_usage(stderr);
+ return EINVAL;
+}
+
+static void
+tap_cli_detach_usage(FILE *stream)
+{
+ fprintf(stream, "usage: detach <-p pid> <-m minor>\n");
+}
+
+static int
+tap_cli_detach(int argc, char **argv)
+{
+ int c, pid, minor;
+
+ pid = -1;
+ minor = -1;
+
+ optind = 0;
+ while ((c = getopt(argc, argv, "p:m:h")) != -1) {
+ switch (c) {
+ case 'p':
+ pid = atoi(optarg);
+ break;
+ case 'm':
+ minor = atoi(optarg);
+ break;
+ case '?':
+ goto usage;
+ case 'h':
+ tap_cli_detach_usage(stdout);
+ return 0;
+ }
+ }
+
+ if (pid == -1 || minor == -1)
+ goto usage;
+
+ return tap_ctl_detach(pid, minor);
+
+usage:
+ tap_cli_detach_usage(stderr);
+ return EINVAL;
+}
+
+static void
+tap_cli_close_usage(FILE *stream)
+{
+ fprintf(stream, "usage: close <-p pid> <-m minor> [-f force]\n");
+}
+
+static int
+tap_cli_close(int argc, char **argv)
+{
+ int c, pid, minor, force;
+
+ pid = -1;
+ minor = -1;
+ force = 0;
+
+ optind = 0;
+ while ((c = getopt(argc, argv, "p:m:fh")) != -1) {
+ switch (c) {
+ case 'p':
+ pid = atoi(optarg);
+ break;
+ case 'm':
+ minor = atoi(optarg);
+ break;
+ case 'f':
+ force = -1;
+ break;
+ case '?':
+ goto usage;
+ case 'h':
+ tap_cli_close_usage(stdout);
+ return 0;
+ }
+ }
+
+ if (pid == -1 || minor == -1)
+ goto usage;
+
+ return tap_ctl_close(pid, minor, force);
+
+usage:
+ tap_cli_close_usage(stderr);
+ return EINVAL;
+}
+
+static void
+tap_cli_pause_usage(FILE *stream)
+{
+ fprintf(stream, "usage: pause <-p pid> <-m minor>\n");
+}
+
+static int
+tap_cli_pause(int argc, char **argv)
+{
+ int c, pid, minor;
+
+ pid = -1;
+ minor = -1;
+
+ optind = 0;
+ while ((c = getopt(argc, argv, "p:m:h")) != -1) {
+ switch (c) {
+ case 'p':
+ pid = atoi(optarg);
+ break;
+ case 'm':
+ minor = atoi(optarg);
+ break;
+ case '?':
+ goto usage;
+ case 'h':
+ tap_cli_pause_usage(stdout);
+ return 0;
+ }
+ }
+
+ if (pid == -1 || minor == -1)
+ goto usage;
+
+ return tap_ctl_pause(pid, minor);
+
+usage:
+ tap_cli_pause_usage(stderr);
+ return EINVAL;
+}
+
+static void
+tap_cli_unpause_usage(FILE *stream)
+{
+ fprintf(stream, "usage: unpause <-p pid> <-m minor> [-a args]\n");
+}
+
+int
+tap_cli_unpause(int argc, char **argv)
+{
+ const char *args;
+ int c, pid, minor;
+
+ pid = -1;
+ minor = -1;
+ args = NULL;
+
+ optind = 0;
+ while ((c = getopt(argc, argv, "p:m:a:h")) != -1) {
+ switch (c) {
+ case 'p':
+ pid = atoi(optarg);
+ break;
+ case 'm':
+ minor = atoi(optarg);
+ break;
+ case 'a':
+ args = optarg;
+ break;
+ case '?':
+ goto usage;
+ case 'h':
+ tap_cli_unpause_usage(stdout);
+ return 0;
+ }
+ }
+
+ if (pid == -1 || minor == -1)
+ goto usage;
+
+ return tap_ctl_unpause(pid, minor, args);
+
+usage:
+ tap_cli_unpause_usage(stderr);
+ return EINVAL;
+}
+
+static void
+tap_cli_major_usage(FILE *stream)
+{
+ fprintf(stream, "usage: major [-h]\n");
+}
+
+static int
+tap_cli_major(int argc, char **argv)
+{
+ int c, chr, major;
+
+ chr = 0;
+
+ while ((c = getopt(argc, argv, "bch")) != -1) {
+ switch (c) {
+ case 'b':
+ chr = 0;
+ break;
+ case 'c':
+ chr = 1;
+ break;
+ case '?':
+ goto usage;
+ case 'h':
+ tap_cli_major_usage(stdout);
+ return 0;
+ default:
+ goto usage;
+ }
+ }
+
+ if (chr)
+ major = -EINVAL;
+ else
+ major = tap_ctl_blk_major();
+
+ if (major < 0)
+ return -major;
+
+ printf("%d\n", major);
+
+ return 0;
+
+usage:
+ tap_cli_major_usage(stderr);
+ return EINVAL;
+}
+
+static void
+tap_cli_open_usage(FILE *stream)
+{
+ fprintf(stream, "usage: open <-p pid> <-m minor> <-a args>\n");
+}
+
+static int
+tap_cli_open(int argc, char **argv)
+{
+ const char *args;
+ int c, pid, minor;
+
+ pid = -1;
+ minor = -1;
+ args = NULL;
+
+ optind = 0;
+ while ((c = getopt(argc, argv, "a:m:p:h")) != -1) {
+ switch (c) {
+ case 'p':
+ pid = atoi(optarg);
+ break;
+ case 'm':
+ minor = atoi(optarg);
+ break;
+ case 'a':
+ args = optarg;
+ break;
+ case '?':
+ goto usage;
+ case 'h':
+ tap_cli_open_usage(stdout);
+ return 0;
+ }
+ }
+
+ if (pid == -1 || minor == -1 || !args)
+ goto usage;
+
+ return tap_ctl_open(pid, minor, args);
+
+usage:
+ tap_cli_open_usage(stderr);
+ return EINVAL;
+}
+
+static void
+tap_cli_check_usage(FILE *stream)
+{
+ fprintf(stream, "usage: check\n"
+ "(checks whether environment is suitable for tapdisk2)\n");
+}
+
+static int
+tap_cli_check(int argc, char **argv)
+{
+ int err;
+ const char *msg;
+
+ if (argc != 1)
+ goto usage;
+
+ err = tap_ctl_check(&msg);
+ printf("%s\n", msg);
+
+ return err;
+
+usage:
+ tap_cli_check_usage(stderr);
+ return EINVAL;
+}
+
+struct command commands[] = {
+ { .name = "list", .func = tap_cli_list },
+ { .name = "allocate", .func = tap_cli_allocate },
+ { .name = "free", .func = tap_cli_free },
+ { .name = "create", .func = tap_cli_create },
+ { .name = "destroy", .func = tap_cli_destroy },
+ { .name = "spawn", .func = tap_cli_spawn },
+ { .name = "attach", .func = tap_cli_attach },
+ { .name = "detach", .func = tap_cli_detach },
+ { .name = "open", .func = tap_cli_open },
+ { .name = "close", .func = tap_cli_close },
+ { .name = "pause", .func = tap_cli_pause },
+ { .name = "unpause", .func = tap_cli_unpause },
+ { .name = "major", .func = tap_cli_major },
+ { .name = "check", .func = tap_cli_check },
+};
+
+#define print_commands() \
+ do { \
+ int i, n; \
+ n = sizeof(commands) / sizeof(struct command); \
+ printf("COMMAND := { "); \
+ printf("%s", commands[0].name); \
+ for (i = 1; i < n; i++) \
+ printf(" | %s", commands[i].name); \
+ printf(" }\n"); \
+ } while (0)
+
+void
+help(void)
+{
+ printf("usage: tap-ctl COMMAND [OPTIONS]\n");
+ print_commands();
+ exit(0);
+}
+
+struct command *
+get_command(char *command)
+{
+ int i, n;
+
+ if (strnlen(command, 25) >= 25)
+ return NULL;
+
+ n = sizeof(commands) / sizeof (struct command);
+
+ for (i = 0; i < n; i++)
+ if (!strcmp(command, commands[i].name))
+ return &commands[i];
+
+ return NULL;
+}
+
+int
+main(int argc, char *argv[])
+{
+ char **cargv;
+ const char *msg;
+ struct command *cmd;
+ int cargc, i, cnt, ret;
+
+#ifdef CORE_DUMP
+ #include <sys/resource.h>
+ struct rlimit rlim;
+ rlim.rlim_cur = RLIM_INFINITY;
+ rlim.rlim_max = RLIM_INFINITY;
+ if (setrlimit(RLIMIT_CORE, &rlim) < 0)
+ PERROR("setrlimit failed");
+#endif
+
+ ret = 0;
+
+ if (argc < 2)
+ help();
+
+ cargc = argc - 1;
+ cmd = get_command(argv[1]);
+ if (!cmd) {
+ EPRINTF("invalid COMMAND %s", argv[1]);
+ help();
+ }
+
+ ret = tap_ctl_check(&msg);
+ if (ret) {
+ printf("%s\n", msg);
+ return ret;
+ }
+
+ cargv = malloc(sizeof(char *) * cargc);
+ if (!cargv)
+ exit(ENOMEM);
+
+ cnt = 1;
+ cargv[0] = cmd->name;
+ for (i = 1; i < cargc; i++) {
+ char *arg = argv[i + (argc - cargc)];
+
+ if (!strcmp(arg, "--debug")) {
+ tap_ctl_debug = 1;
+ continue;
+ }
+
+ cargv[cnt++] = arg;
+ }
+
+ ret = cmd->func(cnt, cargv);
+
+ free(cargv);
+
+ return (ret >= 0 ? ret : -ret);
+}
diff --git a/tools/blktap2/control/tap-ctl.h b/tools/blktap2/control/tap-ctl.h
new file mode 100644
index 0000000000..850f9f024b
--- /dev/null
+++ b/tools/blktap2/control/tap-ctl.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "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 COPYRIGHT OWNER
+ * 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.
+ */
+#ifndef __TAP_CTL_H__
+#define __TAP_CTL_H__
+
+#include <syslog.h>
+#include <errno.h>
+
+#include "tapdisk-message.h"
+
+extern int tap_ctl_debug;
+
+#ifdef TAPCTL
+#define DBG(_f, _a...) \
+ do { \
+ if (tap_ctl_debug) \
+ printf(_f, ##_a); \
+ } while (0)
+
+#define DPRINTF(_f, _a...) syslog(LOG_INFO, _f, ##_a)
+#define EPRINTF(_f, _a...) syslog(LOG_ERR, "tap-err:%s: " _f, __func__, ##_a)
+#define PERROR(_f, _a...) syslog(LOG_ERR, "tap-err:%s: " _f ": %s", __func__, ##_a, \
+ strerror(errno))
+#endif
+
+void tap_ctl_version(int *major, int *minor);
+int tap_ctl_kernel_version(int *major, int *minor);
+
+int tap_ctl_check_blktap(const char **message);
+int tap_ctl_check_version(const char **message);
+int tap_ctl_check(const char **message);
+
+int tap_ctl_connect(const char *path, int *socket);
+int tap_ctl_connect_id(int id, int *socket);
+int tap_ctl_read_message(int fd, tapdisk_message_t *message, int timeout);
+int tap_ctl_write_message(int fd, tapdisk_message_t *message, int timeout);
+int tap_ctl_send_and_receive(int fd, tapdisk_message_t *message, int timeout);
+int tap_ctl_connect_send_and_receive(int id,
+ tapdisk_message_t *message, int timeout);
+char *tap_ctl_socket_name(int id);
+
+typedef struct {
+ int id;
+ pid_t pid;
+ int minor;
+ int state;
+ char *type;
+ char *path;
+} tap_list_t;
+
+int tap_ctl_get_driver_id(const char *handle);
+
+int tap_ctl_list(tap_list_t ***list);
+void tap_ctl_free_list(tap_list_t **list);
+
+int tap_ctl_allocate(int *minor, char **devname);
+int tap_ctl_free(const int minor);
+
+int tap_ctl_create(const char *params, char **devname);
+int tap_ctl_destroy(const int id, const int minor);
+
+int tap_ctl_spawn(void);
+pid_t tap_ctl_get_pid(const int id);
+
+int tap_ctl_attach(const int id, const int minor);
+int tap_ctl_detach(const int id, const int minor);
+
+int tap_ctl_open(const int id, const int minor, const char *params);
+int tap_ctl_close(const int id, const int minor, const int force);
+
+int tap_ctl_pause(const int id, const int minor);
+int tap_ctl_unpause(const int id, const int minor, const char *params);
+
+int tap_ctl_blk_major(void);
+
+#endif