[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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |