[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] 1) More testing: include tests which I forgot in previous patch, remove



# HG changeset patch
# User kaf24@xxxxxxxxxxxxxxxxxxxx
# Node ID a9ee400a5da98acc8da566a24ecae05902b2bed2
# Parent  b60643391488ccc7b3d0c304c1a3a522a18671eb
1) More testing: include tests which I forgot in previous patch, remove
xs_watch_stress, reduce cycles in "make check" random test.
2) xs_crashme: corrupt random packets going to xenstored, watch it
crash.
3) Handle second input from before we finished output on first one.
4) Fix bug where one-arg operations are given zero args.
5) Fix bug where SET_PERMS fails after blocking on transaction.
6) Fix memory leak when DIRECTORY op given no argument.
7) Fail on first memory leak, for better testing.
8) Fix missing waiting_for_ack initialization for new connections.
9) Ensure all input and output is handled for domains so we don't stall.
10) Fix overrun bug in xs_count_strings on non-nul-terminated strings.
11) New test for clients which write without waiting for response.

Signed-off-by: Rusty Russell <rusty@xxxxxxxxxxxxxxx>

diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/Makefile
--- a/tools/xenstore/Makefile   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/Makefile   Mon Aug  8 09:13:19 2005
@@ -41,9 +41,9 @@
 xs_test: xs_test.o xs_lib.o utils.o
 xs_random: xs_random.o xs_test_lib.o xs_lib.o talloc.o utils.o
 xs_stress: xs_stress.o xs_test_lib.o xs_lib.o talloc.o utils.o
-xs_watch_stress: xs_watch_stress.o xs_test_lib.o xs_lib.o talloc.o utils.o
+xs_crashme: xs_crashme.o xs_lib.o talloc.o utils.o
 
-xs_test.o xs_stress.o xs_watch_stress.o xenstored_core_test.o 
xenstored_watch_test.o xenstored_transaction_test.o xenstored_domain_test.o 
xs_random.o xs_test_lib.o talloc_test.o fake_libxc.o: CFLAGS=$(BASECFLAGS) 
$(TESTFLAGS)
+xs_test.o xs_stress.o xenstored_core_test.o xenstored_watch_test.o 
xenstored_transaction_test.o xenstored_domain_test.o xs_random.o xs_test_lib.o 
talloc_test.o fake_libxc.o xs_crashme.o: CFLAGS=$(BASECFLAGS) $(TESTFLAGS)
 
 xenstored_%_test.o: xenstored_%.c
        $(COMPILE.c) -o $@ $<
@@ -65,7 +65,7 @@
 
 clean: testsuite-clean
        rm -f *.o *.opic *.a
-       rm -f xen xenstored xs_random xs_stress xs_watch_stress
+       rm -f xen xenstored xs_random xs_stress xs_crashme
        rm -f xs_test xenstored_test xs_dom0_test
        -$(RM) $(PROG_DEP)
 
@@ -96,14 +96,18 @@
        $(TESTENV) ./xs_random --fast /tmp/xs_random 100000 $(RANDSEED) && echo
        $(TESTENV) ./xs_random --fail /tmp/xs_random 10000 $(RANDSEED)
 
+crashme:  xs_crashme xenstored_test
+       rm -rf $(TESTDIR)/store $(TESTDIR)/transactions /tmp/xs_crashme.vglog* 
/tmp/trace
+       export $(TESTENV); ./xs_crashme 5000 $(RANDSEED) 2>/dev/null
+       if [ -n "`cat /tmp/xs_crashme.vglog*`" ]; then echo Valgrind 
complained; cat /tmp/xs_crashme.vglog*; exit 1; fi
+       rm -rf $(TESTDIR)/store $(TESTDIR)/transactions /tmp/xs_crashme.vglog* 
/tmp/trace
+
 randomcheck-fast: xs_random xenstored_test
-       @$(TESTENV) ./xs_random --fast /tmp/xs_random 10000 $(RANDSEED)
+       @$(TESTENV) ./xs_random --fast /tmp/xs_random 2000 $(RANDSEED)
 
-stresstest: xs_stress xs_watch_stress xenstored_test
+stresstest: xs_stress xenstored_test
        rm -rf $(TESTDIR)/store $(TESTDIR)/transactions
        export $(TESTENV); PID=`./xenstored_test --output-pid 
--trace-file=/tmp/trace`; ./xs_stress 5000; ret=$$?; kill $$PID; exit $$ret
-       rm -rf $(TESTDIR)/store $(TESTDIR)/transactions
-       export $(TESTENV); PID=`./xenstored_test --output-pid`; 
./xs_watch_stress; ret=$$?; kill $$PID; exit $$ret
 
 xs_dom0_test: xs_dom0_test.o utils.o
        $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -lxc -o $@
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/utils.c
--- a/tools/xenstore/utils.c    Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/utils.c    Mon Aug  8 09:13:19 2005
@@ -84,9 +84,6 @@
 void daemonize(void)
 {
        pid_t pid;
-       int fd;
-       size_t len;
-       char buf[100];
 
        /* Separate from our parent via fork, so init inherits us. */
        if ((pid = fork()) < 0)
@@ -104,18 +101,6 @@
        chdir("/");
        /* Discard our parent's old-fashioned umask prejudices. */
        umask(0);
-
-       fd = open("/var/run/xenstored.pid", O_RDWR | O_CREAT);
-       if (fd == -1) {
-               exit(1);
-       }
-
-       if (lockf(fd, F_TLOCK, 0) == -1) {
-               exit(1);
-       }
-
-       len = sprintf(buf, "%d\n", getpid());
-       write(fd, buf, len);
 }
 
 
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/xenstored_core.c
--- a/tools/xenstore/xenstored_core.c   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/xenstored_core.c   Mon Aug  8 09:13:19 2005
@@ -252,6 +252,7 @@
        int ret;
        struct buffered_data *out = conn->out;
 
+       assert(conn->state != BLOCKED);
        if (out->inhdr) {
                if (verbose)
                        xprintf("Writing msg %s (%s) out to %p\n",
@@ -289,6 +290,10 @@
        talloc_free(out);
 
        queue_next_event(conn);
+
+       /* No longer busy? */
+       if (!conn->out)
+               conn->state = OK;
        return true;
 }
 
@@ -492,6 +497,8 @@
                conn->waiting_reply = bdata;
        } else
                conn->out = bdata;
+       assert(conn->state != BLOCKED);
+       conn->state = BUSY;
 }
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
@@ -544,7 +551,7 @@
 /* We expect one arg in the input: return NULL otherwise. */
 static const char *onearg(struct buffered_data *in)
 {
-       if (get_string(in, 0) != in->used)
+       if (!in->used || get_string(in, 0) != in->used)
                return NULL;
        return in->buffer;
 }
@@ -807,7 +814,7 @@
 
 static void send_directory(struct connection *conn, const char *node)
 {
-       char *path, *reply = talloc_strdup(node, "");
+       char *path, *reply;
        unsigned int reply_len = 0;
        DIR **dir;
        struct dirent *dirent;
@@ -825,6 +832,7 @@
                return;
        }
 
+       reply = talloc_strdup(node, "");
        while ((dirent = readdir(*dir)) != NULL) {
                int len = strlen(dirent->d_name) + 1;
 
@@ -1082,7 +1090,7 @@
 static void do_set_perms(struct connection *conn, struct buffered_data *in)
 {
        unsigned int num;
-       char *node;
+       char *node, *permstr;
        struct xs_permissions *perms;
 
        num = xs_count_strings(in->buffer, in->used);
@@ -1093,7 +1101,7 @@
 
        /* First arg is node name. */
        node = canonicalize(conn, in->buffer);
-       in->buffer += strlen(in->buffer) + 1;
+       permstr = in->buffer + strlen(in->buffer) + 1;
        num--;
 
        if (!within_transaction(conn->transaction, node)) {
@@ -1111,7 +1119,7 @@
        }
 
        perms = talloc_array(node, struct xs_permissions, num);
-       if (!xs_strings_to_perms(perms, num, in->buffer)) {
+       if (!xs_strings_to_perms(perms, num, permstr)) {
                send_error(conn, errno);
                return;
        }
@@ -1280,8 +1288,10 @@
        talloc_free(in);
        talloc_set_fail_handler(NULL, NULL);
        if (talloc_total_blocks(NULL)
-           != talloc_total_blocks(talloc_autofree_context()) + 1)
+           != talloc_total_blocks(talloc_autofree_context()) + 1) {
                talloc_report_full(NULL, stderr);
+               abort();
+       }
 }
 
 /* Errors in reading or allocating here mean we get out of sync, so we
@@ -1305,8 +1315,10 @@
                        return;
 
                if (in->hdr.msg.len > PATH_MAX) {
+#ifndef TESTING
                        syslog(LOG_DAEMON, "Client tried to feed us %i",
                               in->hdr.msg.len);
+#endif
                        goto bad_client;
                }
 
@@ -1357,6 +1369,7 @@
                                consider_message(i);
                        }
                        break;
+               case BUSY:
                case OK:
                        break;
                }
@@ -1382,6 +1395,7 @@
        new->state = OK;
        new->blocked_by = NULL;
        new->out = new->waiting_reply = NULL;
+       new->waiting_for_ack = NULL;
        new->fd = -1;
        new->id = 0;
        new->domain = NULL;
@@ -1461,6 +1475,7 @@
                printf("    state = %s\n",
                       i->state == OK ? "OK"
                       : i->state == BLOCKED ? "BLOCKED"
+                      : i->state == BUSY ? "BUSY"
                       : "INVALID");
                if (i->id)
                        printf("    id = %i\n", i->id);
@@ -1631,6 +1646,7 @@
        max = initialize_set(&inset, &outset, *sock, *ro_sock, event_fd);
 
        /* Main loop. */
+       /* FIXME: Rewrite so noone can starve. */
        for (;;) {
                struct connection *i;
                struct timeval *tvp = NULL, tv;
@@ -1675,10 +1691,22 @@
                        }
                }
 
-               /* Flush output for domain connections,  */
-               list_for_each_entry(i, &connections, list)
-                       if (i->domain && i->out)
+               /* Handle all possible I/O for domain connections. */
+       more:
+               list_for_each_entry(i, &connections, list) {
+                       if (!i->domain)
+                               continue;
+
+                       if (domain_can_read(i)) {
+                               handle_input(i);
+                               goto more;
+                       }
+
+                       if (domain_can_write(i)) {
                                handle_output(i);
+                               goto more;
+                       }
+               }
 
                if (tvp) {
                        check_transaction_timeout();
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/xenstored_core.h
--- a/tools/xenstore/xenstored_core.h   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/xenstored_core.h   Mon Aug  8 09:13:19 2005
@@ -51,6 +51,8 @@
 {
        /* Blocked by transaction. */
        BLOCKED,
+       /* Doing action, not listening */
+       BUSY,
        /* Completed */
        OK,
 };
@@ -65,7 +67,7 @@
        /* Who am I?  0 for socket connections. */
        domid_t id;
 
-       /* Blocked on transaction? */
+       /* Blocked on transaction?  Busy? */
        enum state state;
 
        /* Node we are waiting for (if state == BLOCKED) */
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/xenstored_domain.c
--- a/tools/xenstore/xenstored_domain.c Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/xenstored_domain.c Mon Aug  8 09:13:19 2005
@@ -227,32 +227,27 @@
        return NULL;
 }
 
+/* We scan all domains rather than use the information given here. */
 void handle_event(int event_fd)
 {
        u16 port;
-       struct domain *domain;
 
        if (read(event_fd, &port, sizeof(port)) != sizeof(port))
                barf_perror("Failed to read from event fd");
-
-       /* We have to handle *all* the data available before we ack:
-        * careful that handle_input/handle_output can destroy conn.
-        */
-       while ((domain = find_domain(port)) != NULL) {
-               if (domain->conn->state == OK
-                   && buffer_has_input(domain->input))
-                       handle_input(domain->conn);
-               else if (domain->conn->out
-                        && buffer_has_output_room(domain->output))
-                       handle_output(domain->conn);
-               else
-                       break;
-       }
-
 #ifndef TESTING
        if (write(event_fd, &port, sizeof(port)) != sizeof(port))
                barf_perror("Failed to write to event fd");
 #endif
+}
+
+bool domain_can_read(struct connection *conn)
+{
+       return conn->state == OK && buffer_has_input(conn->domain->input);
+}
+
+bool domain_can_write(struct connection *conn)
+{
+       return conn->out && buffer_has_output_room(conn->domain->output);
 }
 
 static struct domain *new_domain(void *context, domid_t domid,
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/xenstored_domain.h
--- a/tools/xenstore/xenstored_domain.h Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/xenstored_domain.h Mon Aug  8 09:13:19 2005
@@ -40,4 +40,8 @@
 /* Read existing connection information from store. */
 void restore_existing_connections(void);
 
+/* Can connection attached to domain read/write. */
+bool domain_can_read(struct connection *conn);
+bool domain_can_write(struct connection *conn);
+
 #endif /* _XENSTORED_DOMAIN_H */
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/xs.c
--- a/tools/xenstore/xs.c       Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/xs.c       Mon Aug  8 09:13:19 2005
@@ -204,13 +204,19 @@
                return NULL;
        }
 
-       assert(msg.type == type);
+       if (msg.type != type) {
+               free(ret);
+               saved_errno = EBADF;
+               goto close_fd;
+               
+       }
        return ret;
 
 fail:
        /* We're in a bad state, so close fd. */
        saved_errno = errno;
        sigaction(SIGPIPE, &oldact, NULL);
+close_fd:
        close(h->fd);
        h->fd = -1;
        errno = saved_errno;
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/xs_lib.c
--- a/tools/xenstore/xs_lib.c   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/xs_lib.c   Mon Aug  8 09:13:19 2005
@@ -152,8 +152,9 @@
        unsigned int num;
        const char *p;
 
-       for (p = strings, num = 0; p < strings + len; p += strlen(p) + 1)
-               num++;
+       for (p = strings, num = 0; p < strings + len; p++)
+               if (*p == '\0')
+                       num++;
 
        return num;
 }
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/xs_random.c
--- a/tools/xenstore/xs_random.c        Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/xs_random.c        Mon Aug  8 09:13:19 2005
@@ -349,19 +349,12 @@
 {
        char *dirname = path_to_name(info, path);
 
-       /* Same effective order as daemon, so error returns are right. */
-       if (mkdir(dirname, 0700) != 0) {
-               if (errno != ENOENT && errno != ENOTDIR)
-                       write_ok(info, path);
-               return false;
-       }
-
-       if (!write_ok(info, path)) {
-               int saved_errno = errno;
-               rmdir(dirname);
-               errno = saved_errno;
-               return false;
-       }
+       if (!write_ok(info, path))
+               return false;
+
+       if (mkdir(dirname, 0700) != 0)
+               return false;
+
        init_perms(dirname);
        return true;
 }
@@ -984,13 +977,15 @@
 
 static void setup_file_ops(const char *dir)
 {
-       char *cmd = talloc_asprintf(NULL, "echo -n r0 > %s/.perms", dir);
+       struct xs_permissions perm = { .id = 0, .perms = XS_PERM_READ };
+       struct file_ops_info *h = file_handle(dir);
        if (mkdir(dir, 0700) != 0)
                barf_perror("Creating directory %s", dir);
-       if (mkdir(talloc_asprintf(cmd, "%s/tool", dir), 0700) != 0)
+       if (mkdir(talloc_asprintf(h, "%s/tool", dir), 0700) != 0)
                barf_perror("Creating directory %s/tool", dir);
-       do_command(cmd);
-       talloc_free(cmd);
+       if (!file_set_perms(h, talloc_strdup(h, "/"), &perm, 1))
+               barf_perror("Setting root perms in %s", dir);
+       file_close(h);
 }
 
 static void setup_xs_ops(void)
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/xs_test.c
--- a/tools/xenstore/xs_test.c  Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/xs_test.c  Mon Aug  8 09:13:19 2005
@@ -28,13 +28,13 @@
 #include <stdint.h>
 #include <stdbool.h>
 #include <stdlib.h>
+#include <sys/mman.h>
 #include <fnmatch.h>
 #include <stdarg.h>
 #include <string.h>
 #include <getopt.h>
 #include <ctype.h>
 #include <sys/time.h>
-#include <sys/mman.h>
 #include "utils.h"
 #include "xs_lib.h"
 #include "list.h"
@@ -43,7 +43,7 @@
 
 static struct xs_handle *handles[10] = { NULL };
 
-static unsigned int timeout_ms = 50;
+static unsigned int timeout_ms = 200;
 static bool timeout_suppressed = true;
 static bool readonly = false;
 static bool print_input = false;
@@ -213,6 +213,8 @@
             "  notimeout\n"
             "  readonly\n"
             "  readwrite\n"
+            "  noackwrite <path> <flags> <value>...\n"
+            "  readack\n"
             "  dump\n");
 }
 
@@ -365,6 +367,45 @@
                failed(handle);
 }
 
+static void do_noackwrite(unsigned int handle,
+                         char *path, const char *flags, char *data)
+{
+       struct xsd_sockmsg msg;
+
+       /* Format: Flags (as string), path, data. */
+       if (streq(flags, "none"))
+               flags = XS_WRITE_NONE;
+       else if (streq(flags, "create"))
+               flags = XS_WRITE_CREATE;
+       else if (streq(flags, "excl"))
+               flags = XS_WRITE_CREATE_EXCL;
+       else
+               barf("noackwrite flags 'none', 'create' or 'excl' only");
+
+       msg.len = strlen(path) + 1 + strlen(flags) + 1 + strlen(data);
+       msg.type = XS_WRITE;
+       if (!write_all_choice(handles[handle]->fd, &msg, sizeof(msg)))
+               failed(handle);
+       if (!write_all_choice(handles[handle]->fd, path, strlen(path) + 1))
+               failed(handle);
+       if (!write_all_choice(handles[handle]->fd, flags, strlen(flags) + 1))
+               failed(handle);
+       if (!write_all_choice(handles[handle]->fd, data, strlen(data)))
+               failed(handle);
+       /* Do not wait for ack. */
+}
+
+static void do_readack(unsigned int handle)
+{
+       enum xsd_sockmsg_type type;
+       char *ret;
+
+       ret = read_reply(handles[handle]->fd, &type, NULL);
+       if (!ret)
+               failed(handle);
+       free(ret);
+}
+
 static void do_setid(unsigned int handle, char *id)
 {
        if (!xs_bool(xs_debug_command(handles[handle], "setid", id,
@@ -466,6 +507,25 @@
                failed(handle);
 }
 
+static void set_timeout(void)
+{
+       struct itimerval timeout;
+
+       timeout.it_value.tv_sec = timeout_ms / 1000;
+       timeout.it_value.tv_usec = (timeout_ms * 1000) % 1000000;
+       timeout.it_interval.tv_sec = timeout.it_interval.tv_usec = 0;
+       setitimer(ITIMER_REAL, &timeout, NULL);
+}
+
+static void disarm_timeout(void)
+{
+       struct itimerval timeout;
+
+       timeout.it_value.tv_sec = 0;
+       timeout.it_value.tv_usec = 0;
+       setitimer(ITIMER_REAL, &timeout, NULL);
+}
+
 static void do_waitwatch(unsigned int handle)
 {
        char **vec;
@@ -474,14 +534,17 @@
        fd_set set;
 
        if (xs_fileno(handles[handle]) != -2) {
+               /* Manually select here so we can time out gracefully. */
                FD_ZERO(&set);
                FD_SET(xs_fileno(handles[handle]), &set);
+               disarm_timeout();
                if (select(xs_fileno(handles[handle])+1, &set,
                           NULL, NULL, &tv) == 0) {
                        errno = ETIMEDOUT;
                        failed(handle);
                        return;
                }
+               set_timeout();
        }
 
        vec = xs_read_watch(handles[handle]);
@@ -529,6 +592,9 @@
 {
        unsigned int i;
        int fd;
+
+       /* This mechanism is v. slow w. valgrind running. */
+       timeout_ms = 5000;
 
        /* We poll, so ignore signal */
        signal(SIGUSR2, SIG_IGN);
@@ -669,24 +735,6 @@
        write(STDOUT_FILENO, command, strlen(command));
        write(STDOUT_FILENO, " timeout\n", strlen(" timeout\n"));
        exit(1);
-}
-
-static void set_timeout(void)
-{
-       struct itimerval timeout;
-
-       timeout.it_interval.tv_sec = timeout_ms / 1000;
-       timeout.it_interval.tv_usec = (timeout_ms * 1000) % 1000000;
-       setitimer(ITIMER_REAL, &timeout, NULL);
-}
-
-static void disarm_timeout(void)
-{
-       struct itimerval timeout;
-
-       timeout.it_interval.tv_sec = 0;
-       timeout.it_interval.tv_usec = 0;
-       setitimer(ITIMER_REAL, &timeout, NULL);
 }
 
 static void do_command(unsigned int default_handle, char *line)
@@ -779,7 +827,11 @@
                readonly = false;
                xs_daemon_close(handles[handle]);
                handles[handle] = NULL;
-       } else
+       } else if (streq(command, "noackwrite"))
+               do_noackwrite(handle, arg(line,1), arg(line,2), arg(line,3));
+       else if (streq(command, "readack"))
+               do_readack(handle);
+       else
                barf("Unknown command %s", command);
        fflush(stdout);
        disarm_timeout();
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/testsuite/01simple.test
--- /dev/null   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/testsuite/01simple.test    Mon Aug  8 09:13:19 2005
@@ -0,0 +1,4 @@
+# Create an entry, read it.
+write /test create contents
+expect contents
+read /test
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/testsuite/02directory.test
--- /dev/null   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/testsuite/02directory.test Mon Aug  8 09:13:19 2005
@@ -0,0 +1,34 @@
+# Root directory has only tool dir in it.
+expect tool
+dir /
+
+# Create a file.
+write /test create contents
+
+# Directory shows it.
+expect test
+expect tool
+dir /
+
+# Make a new directory, check it's there
+mkdir /dir
+expect dir
+expect test
+expect tool
+dir /
+
+# Check it's empty.
+dir /dir
+
+# Create a file, check it exists.
+write /dir/test2 create contents2
+expect test2
+dir /dir
+expect contents2
+read /dir/test2
+
+# Creating dir over the top should fail.
+expect mkdir failed: File exists
+mkdir /dir
+expect mkdir failed: File exists
+mkdir /dir/test2
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/testsuite/03write.test
--- /dev/null   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/testsuite/03write.test     Mon Aug  8 09:13:19 2005
@@ -0,0 +1,20 @@
+# Write without create fails.
+expect write failed: No such file or directory
+write /test none contents
+
+# Exclusive write succeeds
+write /test excl contents
+expect contents
+read /test
+
+# Exclusive write fails to overwrite.
+expect write failed: File exists
+write /test excl contents
+
+# Non-exclusive overwrite succeeds.
+write /test none contents2
+expect contents2
+read /test
+write /test create contents3
+expect contents3
+read /test
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/testsuite/04rm.test
--- /dev/null   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/testsuite/04rm.test        Mon Aug  8 09:13:19 2005
@@ -0,0 +1,18 @@
+# Remove non-existant fails.
+expect rm failed: No such file or directory
+rm /test
+expect rm failed: No such file or directory
+rm /dir/test
+
+# Create file and remove it
+write /test excl contents
+rm /test
+
+# Create directory and remove it.
+mkdir /dir
+rm /dir
+
+# Create directory, create file, remove all.
+mkdir /dir
+write /dir/test excl contents
+rm /dir
diff -r b60643391488 -r a9ee400a5da9 
tools/xenstore/testsuite/05filepermissions.test
--- /dev/null   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/testsuite/05filepermissions.test   Mon Aug  8 09:13:19 2005
@@ -0,0 +1,81 @@
+# Fail to get perms on non-existent file.
+expect getperm failed: No such file or directory
+getperm /test
+expect getperm failed: No such file or directory
+getperm /dir/test
+
+# Create file: inherits from root (0 READ)
+write /test excl contents
+expect 0 READ
+getperm /test
+setid 1
+expect 0 READ
+getperm /test
+expect contents
+read /test
+expect write failed: Permission denied
+write /test none contents
+
+# Take away read access to file.
+setid 0
+setperm /test 0 NONE
+setid 1
+expect getperm failed: Permission denied
+getperm /test
+expect read failed: Permission denied
+read /test
+expect write failed: Permission denied
+write /test none contents
+
+# Grant everyone write access to file.
+setid 0
+setperm /test 0 WRITE
+setid 1
+expect getperm failed: Permission denied
+getperm /test
+expect read failed: Permission denied
+read /test
+write /test none contents2
+setid 0
+expect contents2
+read /test
+
+# Grant everyone both read and write access.
+setperm /test 0 READ/WRITE
+setid 1
+expect 0 READ/WRITE
+getperm /test
+expect contents2
+read /test
+write /test none contents3
+expect contents3
+read /test
+
+# Change so that user 1 owns it, noone else can do anything.
+setid 0
+setperm /test 1 NONE
+setid 1
+expect 1 NONE
+getperm /test
+expect contents3
+read /test
+write /test none contents4
+
+# User 2 can do nothing.
+setid 2
+expect setperm failed: Permission denied
+setperm /test 2 NONE
+expect getperm failed: Permission denied
+getperm /test
+expect read failed: Permission denied
+read /test
+expect write failed: Permission denied
+write /test none contents4
+
+# Tools can always access things.
+setid 0
+expect 1 NONE
+getperm /test
+expect contents4
+read /test
+write /test none contents5
diff -r b60643391488 -r a9ee400a5da9 
tools/xenstore/testsuite/06dirpermissions.test
--- /dev/null   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/testsuite/06dirpermissions.test    Mon Aug  8 09:13:19 2005
@@ -0,0 +1,119 @@
+# Root directory: owned by tool, everyone has read access.
+expect 0 READ
+getperm /
+
+# Create directory: inherits from root.
+mkdir /dir
+expect 0 READ
+getperm /dir
+setid 1
+expect 0 READ
+getperm /dir
+dir /dir
+expect write failed: Permission denied
+write /dir/test create contents2
+
+# Remove everyone's read access to directoy.
+setid 0
+setperm /dir 0 NONE
+setid 1
+expect dir failed: Permission denied
+dir /dir
+expect read failed: Permission denied
+read /dir/test create contents2
+expect write failed: Permission denied
+write /dir/test create contents2
+
+# Grant everyone write access to directory.
+setid 0
+setperm /dir 0 WRITE
+setid 1
+expect getperm failed: Permission denied
+getperm /dir
+expect dir failed: Permission denied
+dir /dir
+write /dir/test create contents
+setid 0
+expect 1 WRITE
+getperm /dir/test
+setperm /dir/test 0 NONE
+expect contents
+read /dir/test
+
+# Grant everyone both read and write access.
+setperm /dir 0 READ/WRITE
+setid 1
+expect 0 READ/WRITE
+getperm /dir
+expect test
+dir /dir
+write /dir/test2 create contents
+expect contents
+read /dir/test2
+setperm /dir/test2 1 NONE
+
+# Change so that user 1 owns it, noone else can do anything.
+setid 0
+setperm /dir 1 NONE
+expect 1 NONE
+getperm /dir
+expect test
+expect test2
+dir /dir
+write /dir/test3 create contents
+
+# User 2 can do nothing.  Can't even tell if file exists.
+setid 2
+expect setperm failed: Permission denied
+setperm /dir 2 NONE
+expect getperm failed: Permission denied
+getperm /dir
+expect dir failed: Permission denied
+dir /dir
+expect read failed: Permission denied
+read /dir/test
+expect read failed: Permission denied
+read /dir/test2
+expect read failed: Permission denied
+read /dir/test3
+expect read failed: Permission denied
+read /dir/test4
+expect write failed: Permission denied
+write /dir/test none contents
+expect write failed: Permission denied
+write /dir/test create contents
+expect write failed: Permission denied
+write /dir/test excl contents
+expect write failed: Permission denied
+write /dir/test4 none contents
+expect write failed: Permission denied
+write /dir/test4 create contents
+expect write failed: Permission denied
+write /dir/test4 excl contents
+
+# Tools can always access things.
+setid 0
+expect 1 NONE
+getperm /dir
+expect test
+expect test2
+expect test3
+dir /dir
+write /dir/test4 create contents
+
+# Inherited by child.
+mkdir /dir/subdir
+expect 1 NONE
+getperm /dir/subdir
+write /dir/subfile excl contents
+expect 1 NONE
+getperm /dir/subfile
+
+# But for domains, they own it.
+setperm /dir/subdir 2 READ/WRITE
+expect 2 READ/WRITE
+getperm /dir/subdir
+setid 3
+write /dir/subdir/subfile excl contents
+expect 3 READ/WRITE
+getperm /dir/subdir/subfile
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/testsuite/07watch.test
--- /dev/null   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/testsuite/07watch.test     Mon Aug  8 09:13:19 2005
@@ -0,0 +1,194 @@
+# Watch something, write to it, check watch has fired.
+write /test create contents
+
+1 watch /test token
+2 write /test create contents2
+expect 1:/test:token
+1 waitwatch
+1 ackwatch token
+1 close
+
+# Check that reads don't set it off.
+1 watch /test token
+expect 2:contents2
+2 read /test
+expect 1: waitwatch failed: Connection timed out
+1 waitwatch
+1 close
+
+# mkdir, setperm and rm should (also tests watching dirs)
+mkdir /dir
+1 watch /dir token
+2 mkdir /dir/newdir
+expect 1:/dir/newdir:token
+1 waitwatch
+1 ackwatch token
+2 setperm /dir/newdir 0 READ
+expect 1:/dir/newdir:token
+1 waitwatch
+1 ackwatch token
+2 rm /dir/newdir
+expect 1:/dir/newdir:token
+1 waitwatch
+1 ackwatch token
+1 close
+2 close
+
+# We don't get a watch from our own commands.
+watch /dir token
+mkdir /dir/newdir
+expect waitwatch failed: Connection timed out
+waitwatch
+close
+
+# ignore watches while doing commands, should work.
+watch /dir token
+1 write /dir/test create contents
+expect contents
+read /dir/test
+expect /dir/test:token
+waitwatch
+ackwatch token
+close
+
+# watch priority test: all simultaneous
+1 watch /dir token1
+3 watch /dir token3
+2 watch /dir token2
+write /dir/test create contents
+expect 3:/dir/test:token3
+3 waitwatch
+3 ackwatch token3
+expect 2:/dir/test:token2
+2 waitwatch
+2 ackwatch token2
+expect 1:/dir/test:token1
+1 waitwatch
+1 ackwatch token1
+1 close
+2 close
+3 close
+
+# If one dies (without acking), the other should still get ack.
+1 watch /dir token1
+2 watch /dir token2
+write /dir/test create contents
+expect 2:/dir/test:token2
+2 waitwatch
+2 close
+expect 1:/dir/test:token1
+1 waitwatch
+1 ackwatch token1
+1 close
+
+# If one dies (without reading at all), the other should still get ack.
+1 watch /dir token1
+2 watch /dir token2
+write /dir/test create contents
+2 close
+expect 1:/dir/test:token1
+1 waitwatch
+1 ackwatch token1
+1 close
+2 close
+
+# unwatch
+1 watch /dir token1
+1 unwatch /dir token1
+1 watch /dir token2
+2 write /dir/test2 create contents
+expect 1:/dir/test2:token2
+1 waitwatch
+1 unwatch /dir token2
+1 close
+2 close
+
+# unwatch while watch pending.  Other watcher still gets the event.
+1 watch /dir token1
+2 watch /dir token2
+write /dir/test create contents
+2 unwatch /dir token2
+expect 1:/dir/test:token1
+1 waitwatch
+1 ackwatch token1
+1 close
+2 close
+
+# unwatch while watch pending.  Should clear this so we get next event.
+1 watch /dir token1
+write /dir/test create contents
+1 unwatch /dir token1
+1 watch /dir/test token2
+write /dir/test none contents2
+expect 1:/dir/test:token2
+1 waitwatch
+1 ackwatch token2
+
+# check we only get notified once.
+1 watch /test token
+2 write /test create contents2
+expect 1:/test:token
+1 waitwatch
+1 ackwatch token
+expect 1: waitwatch failed: Connection timed out
+1 waitwatch
+1 close
+
+# watches are queued in order.
+1 watch / token
+2 write /test1 create contents
+2 write /test2 create contents
+2 write /test3 create contents
+expect 1:/test1:token
+1 waitwatch
+1 ackwatch token
+expect 1:/test2:token
+1 waitwatch
+1 ackwatch token
+expect 1:/test3:token
+1 waitwatch
+1 ackwatch token
+1 close
+
+# Creation of subpaths should be covered correctly.
+1 watch / token
+2 write /test/subnode create contents2
+2 write /test/subnode/subnode create contents2
+expect 1:/test/subnode:token
+1 waitwatch
+1 ackwatch token
+expect 1:/test/subnode/subnode:token
+1 waitwatch
+1 ackwatch token
+expect 1: waitwatch failed: Connection timed out
+1 waitwatch
+1 close
+
+# Watch event must have happened before we registered interest.
+1 watch / token
+2 write /test/subnode create contents2
+1 watch / token2 0
+expect 1:/test/subnode:token
+1 waitwatch
+1 ackwatch token
+expect 1: waitwatch failed: Connection timed out
+1 waitwatch
+1 close
+
+# Rm fires notification on child.
+1 watch /test/subnode token
+2 rm /test
+expect 1:/test/subnode:token
+1 waitwatch
+1 ackwatch token
+
+# Watch should not double-send after we ack, even if we did something in 
between.
+1 watch /test2 token
+2 write /test2/foo create contents2
+expect 1:/test2/foo:token
+1 waitwatch
+expect 1:contents2
+1 read /test2/foo
+1 ackwatch token
+expect 1: waitwatch failed: Connection timed out
+1 waitwatch
diff -r b60643391488 -r a9ee400a5da9 
tools/xenstore/testsuite/08transaction.slowtest
--- /dev/null   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/testsuite/08transaction.slowtest   Mon Aug  8 09:13:19 2005
@@ -0,0 +1,21 @@
+# Test transaction timeouts.  Take a second each.
+
+mkdir /test
+write /test/entry1 create contents
+
+# Transactions can take as long as the want...
+start /test
+sleep 1100
+rm /test/entry1
+commit
+dir /test
+
+# ... as long as noone is waiting.
+1 start /test
+notimeout
+2 mkdir /test/dir
+1 mkdir /test/dir
+expect 1:dir
+1 dir /test
+expect 1: commit failed: Connection timed out
+1 commit
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/testsuite/08transaction.test
--- /dev/null   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/testsuite/08transaction.test       Mon Aug  8 09:13:19 2005
@@ -0,0 +1,96 @@
+# Test transactions.
+
+mkdir /test
+
+# Simple transaction: create a file inside transaction.
+1 start /test
+1 write /test/entry1 create contents
+2 dir /test
+expect 1:entry1
+1 dir /test
+1 commit
+expect 2:contents
+2 read /test/entry1
+
+rm /test/entry1
+
+# Create a file and abort transaction.
+1 start /test
+1 write /test/entry1 create contents
+2 dir /test
+expect 1:entry1
+1 dir /test
+1 abort
+2 dir /test
+
+write /test/entry1 create contents
+# Delete in transaction, commit
+1 start /test
+1 rm /test/entry1
+expect 2:entry1
+2 dir /test
+1 dir /test
+1 commit
+2 dir /test
+
+# Delete in transaction, abort.
+write /test/entry1 create contents
+1 start /test
+1 rm /test/entry1
+expect 2:entry1
+2 dir /test
+1 dir /test
+1 abort
+expect 2:entry1
+2 dir /test
+
+# Events inside transactions don't trigger watches until (successful) commit.
+mkdir /test/dir
+1 watch /test token
+2 start /test
+2 mkdir /test/dir/sub
+expect 1: waitwatch failed: Connection timed out
+1 waitwatch
+2 close
+1 close
+
+1 watch /test token
+2 start /test
+2 mkdir /test/dir/sub
+2 abort
+expect 1: waitwatch failed: Connection timed out
+1 waitwatch
+1 close
+
+1 watch /test token
+2 start /test
+2 mkdir /test/dir/sub
+2 commit
+expect 1:/test/dir/sub:token
+1 waitwatch
+1 ackwatch token
+1 close
+
+# Rm inside transaction works like rm outside: children get notified.
+1 watch /test/dir/sub token
+2 start /test
+2 rm /test/dir
+2 commit
+expect 1:/test/dir/sub:token
+1 waitwatch
+1 ackwatch token
+1 close
+
+# Multiple events from single transaction don't trigger assert
+1 watch /test token
+2 start /test
+2 write /test/1 create contents
+2 write /test/2 create contents
+2 commit
+expect 1:/test/1:token
+1 waitwatch
+1 ackwatch token
+expect 1:/test/2:token
+1 waitwatch
+1 ackwatch token
+1 close
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/testsuite/09domain.test
--- /dev/null   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/testsuite/09domain.test    Mon Aug  8 09:13:19 2005
@@ -0,0 +1,19 @@
+# Test domain communication.
+
+# Create a domain, write an entry.
+expect handle is 1
+introduce 1 100 7 /my/home
+1 write /entry1 create contents
+expect entry1
+expect tool
+dir /
+close
+
+# Release that domain.
+release 1
+close
+
+# Introduce and release by same connection.
+expect handle is 2
+introduce 1 100 7 /my/home
+release 1
diff -r b60643391488 -r a9ee400a5da9 
tools/xenstore/testsuite/10domain-homedir.test
--- /dev/null   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/testsuite/10domain-homedir.test    Mon Aug  8 09:13:19 2005
@@ -0,0 +1,19 @@
+# Test domain "implicit" paths.
+
+# Create a domain, write an entry using implicit path, read using implicit
+mkdir /home
+expect handle is 1
+introduce 1 100 7 /home
+1 write entry1 create contents
+expect contents
+read /home/entry1
+expect entry1
+dir /home
+
+# Place a watch using a relative path: expect relative answer.
+1 mkdir foo
+1 watch foo token
+write /home/foo/bar create contents
+expect 1:foo/bar:token
+1 waitwatch
+1 ackwatch token
diff -r b60643391488 -r a9ee400a5da9 
tools/xenstore/testsuite/11domain-watch.test
--- /dev/null   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/testsuite/11domain-watch.test      Mon Aug  8 09:13:19 2005
@@ -0,0 +1,52 @@
+# Test watching from a domain.
+
+# Watch something, write to it, check watch has fired.
+write /test create contents
+mkdir /dir
+
+expect handle is 1
+introduce 1 100 7 /my/home
+1 watch /test token
+write /test create contents2
+expect 1:/test:token
+1 waitwatch
+1 ackwatch token
+1 unwatch /test token
+release 1
+1 close
+
+# ignore watches while doing commands, should work.
+expect handle is 1
+introduce 1 100 7 /my/home
+1 watch /dir token
+write /dir/test create contents
+1 write /dir/test2 create contents2
+1 write /dir/test3 create contents3
+1 write /dir/test4 create contents4
+expect 1:/dir/test:token
+1 waitwatch
+1 ackwatch token
+release 1
+1 close
+
+# unwatch
+expect handle is 1
+introduce 1 100 7 /my/home
+1 watch /dir token1
+1 unwatch /dir token1
+1 watch /dir token2
+write /dir/test2 create contents
+expect 1:/dir/test2:token2
+1 waitwatch
+1 unwatch /dir token2
+release 1
+1 close
+
+# unwatch while watch pending.
+expect handle is 1
+introduce 1 100 7 /my/home
+1 watch /dir token1
+write /dir/test2 create contents
+1 unwatch /dir token1
+release 1
+1 close
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/testsuite/12readonly.test
--- /dev/null   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/testsuite/12readonly.test  Mon Aug  8 09:13:19 2005
@@ -0,0 +1,41 @@
+# Test that read only connection can't alter store.
+
+write /test create contents
+
+readonly
+expect test
+expect tool
+dir /
+
+expect contents
+read /test
+expect 0 READ
+getperm /test
+watch /test token
+unwatch /test token 
+start /
+commit
+start /
+abort
+
+# These don't work
+expect write failed: Read-only file system
+write /test2 create contents
+expect write failed: Read-only file system
+write /test create contents
+expect setperm failed: Read-only file system
+setperm /test 100 NONE
+expect setperm failed: Read-only file system
+setperm /test 100 NONE
+expect shutdown failed: Read-only file system
+shutdown
+expect introduce failed: Read-only file system
+introduce 1 100 7 /home
+
+# Check that watches work like normal.
+watch / token
+1 readwrite
+1 write /test create contents
+expect /test:token
+waitwatch
+ackwatch token
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/testsuite/13watch-ack.test
--- /dev/null   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/testsuite/13watch-ack.test Mon Aug  8 09:13:19 2005
@@ -0,0 +1,22 @@
+# This demonstrates a bug where an xs_acknowledge_watch returns
+# EINVAL, because the daemon doesn't track what watch event it sent
+# and relies on it being the "first" watch which has an event.
+# Watches firing after the first event is sent out will change this.
+
+# Create three things to watch.
+mkdir /test
+mkdir /test/1
+mkdir /test/2
+mkdir /test/3
+
+# Watch all three, fire event on 2, read watch, fire event on 1 and 3, ack 2.
+1 watch /test/1 token1
+1 watch /test/2 token2
+1 watch /test/3 token3
+2 write /test/2 create contents2
+expect 1:/test/2:token2
+1 waitwatch
+3 write /test/1 create contents1
+4 write /test/3 create contents3
+1 ackwatch token2
+1 close
diff -r b60643391488 -r a9ee400a5da9 
tools/xenstore/testsuite/14complexperms.test
--- /dev/null   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/testsuite/14complexperms.test      Mon Aug  8 09:13:19 2005
@@ -0,0 +1,99 @@
+# We should not be able to tell the difference between a node which
+# doesn't exist, and a node we don't have permission on, if we don't
+# have permission on it directory.
+
+mkdir /dir
+setperm /dir 0 NONE
+
+# First when it doesn't exist
+setid 1
+expect *Permission denied
+dir /dir/file
+expect *Permission denied
+read /dir/file 
+expect *Permission denied
+write /dir/file none value 
+expect *Permission denied
+write /dir/file create value 
+expect *Permission denied
+write /dir/file excl value 
+expect write failed: Invalid argument
+write /dir/file crap value 
+expect *Permission denied
+mkdir /dir/file 
+expect *Permission denied
+rm /dir/file 
+expect *Permission denied
+rm /dir 
+expect *Permission denied
+getperm /dir/file 
+expect *Permission denied
+setperm /dir/file 0 NONE 
+watch /dir/file token 
+setid 0
+write /dir/file create contents
+rm /dir/file
+setid 1
+expect waitwatch failed: Connection timed out
+waitwatch
+unwatch /dir/file token 
+expect *No such file or directory
+unwatch /dir/file token 
+expect *Permission denied
+start /dir/file
+expect *No such file or directory
+abort
+expect *Permission denied
+start /dir/file
+expect *No such file or directory
+commit
+expect *Permission denied
+introduce 2 100 7 /dir/file
+
+# Now it exists
+setid 0
+write /dir/file create contents
+
+setid 1
+expect *Permission denied
+dir /dir/file
+expect *Permission denied
+read /dir/file 
+expect *Permission denied
+write /dir/file none value 
+expect *Permission denied
+write /dir/file create value 
+expect *Permission denied
+write /dir/file excl value 
+expect write failed: Invalid argument
+write /dir/file crap value 
+expect *Permission denied
+mkdir /dir/file 
+expect *Permission denied
+rm /dir/file 
+expect *Permission denied
+rm /dir 
+expect *Permission denied
+getperm /dir/file 
+expect *Permission denied
+setperm /dir/file 0 NONE 
+watch /dir/file token 
+setid 0
+write /dir/file create contents
+rm /dir/file
+setid 1
+expect waitwatch failed: Connection timed out
+waitwatch
+unwatch /dir/file token 
+expect *No such file or directory
+unwatch /dir/file token 
+expect *Permission denied
+start /dir/file
+expect *No such file or directory
+abort
+expect *Permission denied
+start /dir/file
+expect *No such file or directory
+commit
+expect *Permission denied
+introduce 2 100 7 /dir/file
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/testsuite/15nowait.test
--- /dev/null   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/testsuite/15nowait.test    Mon Aug  8 09:13:19 2005
@@ -0,0 +1,25 @@
+# If we don't wait for an ack, we can crash daemon as it never expects to be
+# sending out two replies on top of each other.
+noackwrite /1 create 1
+noackwrite /2 create 2
+noackwrite /3 create 3
+noackwrite /4 create 4
+noackwrite /5 create 5
+readack
+readack
+readack
+readack
+readack
+
+expect handle is 1
+introduce 1 100 7 /my/home
+1 noackwrite /1 create 1
+1 noackwrite /2 create 2
+1 noackwrite /3 create 3
+1 noackwrite /4 create 4
+1 noackwrite /5 create 5
+1 readack
+1 readack
+1 readack
+1 readack
+1 readack
diff -r b60643391488 -r a9ee400a5da9 tools/xenstore/xs_crashme.c
--- /dev/null   Mon Aug  8 09:12:22 2005
+++ b/tools/xenstore/xs_crashme.c       Mon Aug  8 09:13:19 2005
@@ -0,0 +1,413 @@
+/* Code which randomly corrupts bits going to the daemon.
+    Copyright (C) 2005 Rusty Russell IBM Corporation
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+#include <stdbool.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <stdarg.h>
+#include <string.h>
+#include <sys/time.h>
+#include "xs.h"
+#include "talloc.h"
+#include <errno.h>
+#include "xenstored.h"
+
+#define XSTEST
+#define RAND_FREQ 128          /* One char in 32 is corrupted. */
+
+/* jhash.h: Jenkins hash support.
+ *
+ * Copyright (C) 1996 Bob Jenkins (bob_jenkins@xxxxxxxxxxxxxxxx)
+ *
+ * http://burtleburtle.net/bob/hash/
+ *
+ * These are the credits from Bob's sources:
+ *
+ * lookup2.c, by Bob Jenkins, December 1996, Public Domain.
+ * hash(), hash2(), hash3, and mix() are externally useful functions.
+ * Routines to test the hash are included if SELF_TEST is defined.
+ * You can use this free for any purpose.  It has no warranty.
+ *
+ * Copyright (C) 2003 David S. Miller (davem@xxxxxxxxxx)
+ *
+ * I've modified Bob's hash to be useful in the Linux kernel, and
+ * any bugs present are surely my fault.  -DaveM
+ */
+
+/* NOTE: Arguments are modified. */
+#define __jhash_mix(a, b, c) \
+{ \
+  a -= b; a -= c; a ^= (c>>13); \
+  b -= c; b -= a; b ^= (a<<8); \
+  c -= a; c -= b; c ^= (b>>13); \
+  a -= b; a -= c; a ^= (c>>12);  \
+  b -= c; b -= a; b ^= (a<<16); \
+  c -= a; c -= b; c ^= (b>>5); \
+  a -= b; a -= c; a ^= (c>>3);  \
+  b -= c; b -= a; b ^= (a<<10); \
+  c -= a; c -= b; c ^= (b>>15); \
+}
+
+/* The golden ration: an arbitrary value */
+#define JHASH_GOLDEN_RATIO     0x9e3779b9
+
+/* The most generic version, hashes an arbitrary sequence
+ * of bytes.  No alignment or length assumptions are made about
+ * the input key.
+ */
+static inline u32 jhash(const void *key, u32 length, u32 initval)
+{
+       u32 a, b, c, len;
+       const u8 *k = key;
+
+       len = length;
+       a = b = JHASH_GOLDEN_RATIO;
+       c = initval;
+
+       while (len >= 12) {
+               a += (k[0] +((u32)k[1]<<8) +((u32)k[2]<<16) +((u32)k[3]<<24));
+               b += (k[4] +((u32)k[5]<<8) +((u32)k[6]<<16) +((u32)k[7]<<24));
+               c += (k[8] +((u32)k[9]<<8) +((u32)k[10]<<16)+((u32)k[11]<<24));
+
+               __jhash_mix(a,b,c);
+
+               k += 12;
+               len -= 12;
+       }
+
+       c += length;
+       switch (len) {
+       case 11: c += ((u32)k[10]<<24);
+       case 10: c += ((u32)k[9]<<16);
+       case 9 : c += ((u32)k[8]<<8);
+       case 8 : b += ((u32)k[7]<<24);
+       case 7 : b += ((u32)k[6]<<16);
+       case 6 : b += ((u32)k[5]<<8);
+       case 5 : b += k[4];
+       case 4 : a += ((u32)k[3]<<24);
+       case 3 : a += ((u32)k[2]<<16);
+       case 2 : a += ((u32)k[1]<<8);
+       case 1 : a += k[0];
+       };
+
+       __jhash_mix(a,b,c);
+
+       return c;
+}
+
+/* A special optimized version that handles 1 or more of u32s.
+ * The length parameter here is the number of u32s in the key.
+ */
+static inline u32 jhash2(u32 *k, u32 length, u32 initval)
+{
+       u32 a, b, c, len;
+
+       a = b = JHASH_GOLDEN_RATIO;
+       c = initval;
+       len = length;
+
+       while (len >= 3) {
+               a += k[0];
+               b += k[1];
+               c += k[2];
+               __jhash_mix(a, b, c);
+               k += 3; len -= 3;
+       }
+
+       c += length * 4;
+
+       switch (len) {
+       case 2 : b += k[1];
+       case 1 : a += k[0];
+       };
+
+       __jhash_mix(a,b,c);
+
+       return c;
+}
+
+
+/* A special ultra-optimized versions that knows they are hashing exactly
+ * 3, 2 or 1 word(s).
+ *
+ * NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally
+ *       done at the end is not done here.
+ */
+static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval)
+{
+       a += JHASH_GOLDEN_RATIO;
+       b += JHASH_GOLDEN_RATIO;
+       c += initval;
+
+       __jhash_mix(a, b, c);
+
+       return c;
+}
+
+static inline u32 jhash_2words(u32 a, u32 b, u32 initval)
+{
+       return jhash_3words(a, b, 0, initval);
+}
+
+static inline u32 jhash_1word(u32 a, u32 initval)
+{
+       return jhash_3words(a, 0, 0, initval);
+}
+
+static unsigned int get_randomness(int *state)
+{
+       return jhash_1word((*state)++, *state * 1103515243);
+}
+
+static int state;
+
+/* Lengthening headers is pointless: other end will just wait for more
+ * data and timeout.  We merely shorten the length. */
+static void corrupt_header(char *output, const struct xsd_sockmsg *msg,
+                          unsigned int *next_bit)
+{
+       struct xsd_sockmsg newmsg = *msg;
+
+       while (*next_bit < sizeof(*msg)) {
+               if (newmsg.len)
+                       newmsg.len = get_randomness(&state) % newmsg.len;
+               *next_bit += get_randomness(&state) % RAND_FREQ;
+       }
+       memcpy(output, &newmsg, sizeof(newmsg));
+}
+
+#define read_all_choice read_all
+static bool write_all_choice(int fd, const void *data, unsigned int len)
+{
+       char corrupt_data[len];
+       bool ret;
+       static unsigned int next_bit;
+
+       if (len == sizeof(struct xsd_sockmsg)
+           && ((unsigned long)data % __alignof__(struct xsd_sockmsg)) == 0)
+               corrupt_header(corrupt_data, data, &next_bit);
+       else {
+               memcpy(corrupt_data, data, len);
+               while (next_bit < len * CHAR_BIT) {
+                       corrupt_data[next_bit/CHAR_BIT]
+                               ^= (1 << (next_bit%CHAR_BIT));
+                       next_bit += get_randomness(&state) % RAND_FREQ;
+               }
+       }
+
+       ret = xs_write_all(fd, corrupt_data, len);
+       next_bit -= len * CHAR_BIT;
+       return ret;
+}
+
+#include "xs.c"
+
+static char *random_path(void)
+{
+       unsigned int i;
+       char *ret = NULL;
+
+       if (get_randomness(&state) % 20 == 0)
+               return talloc_strdup(NULL, "/");
+
+       for (i = 0; i < 1 || (get_randomness(&state) % 2); i++) {
+               ret = talloc_asprintf_append(ret, "/%i", 
+                                            get_randomness(&state) % 15);
+       }
+       return ret;
+}
+
+static int random_flags(int *state)
+{
+       switch (get_randomness(state) % 4) {
+       case 0:
+               return 0;
+       case 1:
+               return O_CREAT;
+       case 2:
+               return O_CREAT|O_EXCL;
+       default:
+               return get_randomness(state);
+       }
+}
+
+/* Do the next operation, return the results. */
+static void do_next_op(struct xs_handle *h, bool verbose)
+{
+       char *name;
+       unsigned int num;
+
+       if (verbose)
+               printf("State %i: ", state);
+
+       name = random_path();
+       switch (get_randomness(&state) % 9) {
+       case 0:
+               if (verbose)
+                       printf("DIR %s\n", name);
+               free(xs_directory(h, name, &num));
+               break;
+       case 1:
+               if (verbose)
+                       printf("READ %s\n", name);
+               free(xs_read(h, name, &num));
+               break;
+       case 2: {
+               int flags = random_flags(&state);
+               char *contents = talloc_asprintf(NULL, "%i",
+                                                get_randomness(&state));
+               unsigned int len = get_randomness(&state)%(strlen(contents)+1);
+               if (verbose)
+                       printf("WRITE %s %s %.*s\n", name,
+                              flags == O_CREAT ? "O_CREAT" 
+                              : flags == (O_CREAT|O_EXCL) ? "O_CREAT|O_EXCL"
+                              : flags == 0 ? "0" : "CRAPFLAGS",
+                              len, contents);
+               xs_write(h, name, contents, len, flags);
+               break;
+       }
+       case 3:
+               if (verbose)
+                       printf("MKDIR %s\n", name);
+               xs_mkdir(h, name);
+               break;
+       case 4:
+               if (verbose)
+                       printf("RM %s\n", name);
+               xs_rm(h, name);
+               break;
+       case 5:
+               if (verbose)
+                       printf("GETPERMS %s\n", name);
+               free(xs_get_permissions(h, name, &num));
+               break;
+       case 6: {
+               unsigned int i, num = get_randomness(&state)%8;
+               struct xs_permissions perms[num];
+
+               if (verbose)
+                       printf("SETPERMS %s: ", name);
+               for (i = 0; i < num; i++) {
+                       perms[i].id = get_randomness(&state)%8;
+                       perms[i].perms = get_randomness(&state)%4;
+                       if (verbose)
+                               printf("%i%c ", perms[i].id,
+                                      perms[i].perms == XS_PERM_WRITE ? 'W'
+                                      : perms[i].perms == XS_PERM_READ ? 'R'
+                                      : perms[i].perms == 
+                                      (XS_PERM_READ|XS_PERM_WRITE) ? 'B'
+                                      : 'N');
+               }
+               if (verbose)
+                       printf("\n");
+               xs_set_permissions(h, name, perms, num);
+               break;
+       }
+       case 7: {
+               if (verbose)
+                       printf("START %s\n", name);
+               xs_transaction_start(h, name);
+               break;
+       }
+       case 8: {
+               bool abort = (get_randomness(&state) % 2);
+
+               if (verbose)
+                       printf("STOP %s\n", abort ? "ABORT" : "COMMIT");
+               xs_transaction_end(h, abort);
+               break;
+       }
+       default:
+               barf("Impossible randomness");
+       }
+}
+
+static struct xs_handle *h;
+static void alarmed(int sig __attribute__((unused)))
+{
+       /* We force close on timeout. */
+       close(h->fd);
+}
+
+static int start_daemon(void)
+{
+       int fds[2];
+       int daemon_pid;
+
+       /* Start daemon. */
+       pipe(fds);
+       if ((daemon_pid = fork())) {
+               /* Child writes PID when its ready: we wait for that. */
+               char buffer[20];
+               close(fds[1]);
+               if (read(fds[0], buffer, sizeof(buffer)) < 0)
+                       barf("Failed to summon daemon");
+               close(fds[0]);
+               return daemon_pid;
+       } else {
+               dup2(fds[1], STDOUT_FILENO);
+               close(fds[0]);
+#if 1
+               execlp("valgrind", "valgrind", 
"--log-file=/tmp/xs_crashme.vglog", "-q", "./xenstored_test", "--output-pid",
+                      "--no-fork", "--trace-file=/tmp/trace", NULL);
+#else
+               execlp("./xenstored_test", "xenstored_test", "--output-pid",
+                      "--no-fork", NULL);
+#endif
+               exit(1);
+       }
+}
+
+
+int main(int argc, char **argv)
+{
+       unsigned int i;
+       int pid;
+
+       if (argc != 3 && argc != 4)
+               barf("Usage: xs_crashme <iterations> <seed> [pid]");
+
+       if (argc == 3)
+               pid = start_daemon();
+       else
+               pid = atoi(argv[3]);
+
+       state = atoi(argv[2]);
+       h = xs_daemon_open();
+       if (!h)
+               barf_perror("Opening connection to daemon");
+       signal(SIGALRM, alarmed);
+       for (i = 0; i < (unsigned)atoi(argv[1]); i++) {
+               alarm(1);
+               do_next_op(h, false);
+               if (i % (atoi(argv[1]) / 72 ?: 1) == 0) {
+                       printf(".");
+                       fflush(stdout);
+               }
+               if (kill(pid, 0) != 0)
+                       barf_perror("Pinging daemon on iteration %i", i);
+               if (h->fd < 0) {
+                       xs_daemon_close(h);
+                       h = xs_daemon_open();
+                       if (!h)
+                               barf_perror("Connecting on iteration %i", i);
+               }
+       }
+       kill(pid, SIGTERM);
+       return 0;
+}
+

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.