[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] xenstore: Remove broken and unmaintained test code.
# HG changeset patch # User kfraser@xxxxxxxxxxxxxxxxxxxxx # Date 1183474319 -3600 # Node ID eb71f258e8551858ff11d2331f008539cf399a55 # Parent 0528bc25c4042188bf25f5f0c365f7849d63a684 xenstore: Remove broken and unmaintained test code. Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx> --- tools/xenstore/fake_libxc.c | 143 -- tools/xenstore/speedtest.c | 130 - tools/xenstore/testsuite/01simple.test | 4 tools/xenstore/testsuite/02directory.test | 45 tools/xenstore/testsuite/03write.test | 28 tools/xenstore/testsuite/04rm.test | 20 tools/xenstore/testsuite/05filepermissions.test | 81 - tools/xenstore/testsuite/06dirpermissions.test | 119 - tools/xenstore/testsuite/07watch.test | 176 -- tools/xenstore/testsuite/08transaction.slowtest | 43 tools/xenstore/testsuite/08transaction.test | 92 - tools/xenstore/testsuite/09domain.test | 19 tools/xenstore/testsuite/10domain-homedir.test | 18 tools/xenstore/testsuite/11domain-watch.test | 50 tools/xenstore/testsuite/12readonly.test | 38 tools/xenstore/testsuite/13watch-ack.test | 21 tools/xenstore/testsuite/14complexperms.test | 68 - tools/xenstore/testsuite/test.sh | 64 tools/xenstore/testsuite/vg-suppressions | 9 tools/xenstore/xenstored_test.h | 37 tools/xenstore/xs_crashme.c | 393 ----- tools/xenstore/xs_random.c | 1590 ------------------------ tools/xenstore/xs_stress.c | 207 --- tools/xenstore/xs_test.c | 812 ------------ tools/xenstore/Makefile | 94 - tools/xenstore/xenstored_core.c | 105 - tools/xenstore/xenstored_domain.c | 4 tools/xenstore/xenstored_transaction.c | 1 tools/xenstore/xenstored_watch.c | 12 29 files changed, 5 insertions(+), 4418 deletions(-) diff -r 0528bc25c404 -r eb71f258e855 tools/xenstore/Makefile --- a/tools/xenstore/Makefile Tue Jul 03 15:49:16 2007 +0100 +++ b/tools/xenstore/Makefile Tue Jul 03 15:51:59 2007 +0100 @@ -11,15 +11,11 @@ BASECFLAGS += -Wp,-MD,.$(@F).d BASECFLAGS += -Wp,-MD,.$(@F).d PROG_DEP = .*.d BASECFLAGS+= $(PROFILE) -#BASECFLAGS+= -I$(XEN_ROOT)/tools BASECFLAGS+= -I$(XEN_ROOT)/tools/libxc BASECFLAGS+= -I. CFLAGS += $(BASECFLAGS) LDFLAGS += $(PROFILE) -L$(XEN_LIBXC) -TESTDIR = testsuite/tmp -TESTFLAGS= -DTESTING -TESTENV = XENSTORED_ROOTDIR=$(TESTDIR) XENSTORED_RUNDIR=$(TESTDIR) CLIENTS := xenstore-exists xenstore-list xenstore-read xenstore-rm xenstore-chmod CLIENTS += xenstore-write @@ -34,12 +30,6 @@ XENSTORED_OBJS += $(XENSTORED_OBJS_y) .PHONY: all all: libxenstore.so libxenstore.a xenstored $(CLIENTS) xs_tdb_dump xenstore-control xenstore-ls - -test_interleaved_transactions: test_interleaved_transactions.o - $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -L. -lxenstore -o $@ - -.PHONY: testcode -testcode: xs_test xenstored_test xs_random xenstored: $(XENSTORED_OBJS) $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -lxenctrl $(SOCKET_LIBS) -o $@ @@ -56,34 +46,8 @@ xenstore-ls: xsls.o libxenstore.so xenstore-ls: xsls.o libxenstore.so $(CC) $(CFLAGS) $(LDFLAGS) $< $(LOADLIBES) $(LDLIBS) -L. -lxenstore $(SOCKET_LIBS) -o $@ -xenstored_test: xenstored_core_test.o xenstored_watch_test.o xenstored_domain_test.o xenstored_transaction_test.o xs_lib.o talloc_test.o fake_libxc.o utils.o tdb.o - $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@ - xs_tdb_dump: xs_tdb_dump.o utils.o tdb.o talloc.o $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@ - -xs_test xs_random xs_stress xs_crashme: LDFLAGS+=-lpthread -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_crashme: xs_crashme.o xs_lib.o talloc.o utils.o - -speedtest: speedtest.o xs.o xs_lib.o utils.o talloc.o - -.PHONY: check-speed -check-speed: speedtest xenstored_test $(TESTDIR) - $(TESTENV) time ./speedtest 100 - -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 $@ $< - -xs_test_lib.o: xs.c - $(COMPILE.c) -o $@ $< - -talloc_test.o: talloc.c - $(COMPILE.c) -o $@ $< libxenstore.so: libxenstore.so.$(MAJOR) ln -sf $< $@ @@ -97,66 +61,12 @@ libxenstore.a: xs.o xs_lib.o $(AR) rcs libxenstore.a $^ .PHONY: clean -clean: testsuite-clean +clean: rm -f *.a *.o *.opic *.so* rm -f xenstored xs_random xs_stress xs_crashme - rm -f xs_test xenstored_test xs_tdb_dump xenstore-control xenstore-ls + rm -f xs_tdb_dump xenstore-control xenstore-ls rm -f $(CLIENTS) $(RM) $(PROG_DEP) - -.PHONY: print-dir -print-dir: - @echo -n tools/xenstore: - -.PHONY: print-end -print-end: - @echo - -.PHONY: check -check: print-dir testsuite-fast randomcheck-fast print-end - -.PHONY: fullcheck -fullcheck: testsuite-run randomcheck stresstest - -$(TESTDIR): - mkdir $@ - -.PHONY: testsuite-run -testsuite-run: xenstored_test xs_test $(TESTDIR) - $(TESTENV) testsuite/test.sh && echo - -.PHONY: testsuite-fast -testsuite-fast: xenstored_test xs_test $(TESTDIR) - @$(TESTENV) testsuite/test.sh --fast - -.PHONY: testsuite-clean -testsuite-clean: - rm -rf $(TESTDIR) - -# Make this visible so they can see repeat tests without --fast if they -# fail. -RANDSEED=$(shell date +%s) -.PHONY: randomcheck -randomcheck: xs_random xenstored_test $(TESTDIR) - $(TESTENV) ./xs_random --simple --fast /tmp/xs_random 200000 $(RANDSEED) && echo - $(TESTENV) ./xs_random --fast /tmp/xs_random 100000 $(RANDSEED) && echo -# $(TESTENV) ./xs_random --fail /tmp/xs_random 10000 $(RANDSEED) - -.PHONY: crashme -crashme: xs_crashme xenstored_test $(TESTDIR) - 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 - -.PHONY: randomcheck-fast -randomcheck-fast: xs_random xenstored_test $(TESTDIR) - @$(TESTENV) ./xs_random --fast /tmp/xs_random 2000 $(RANDSEED) - -.PHONY: stresstest -stresstest: xs_stress xenstored_test $(TESTDIR) - 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 .PHONY: TAGS TAGS: diff -r 0528bc25c404 -r eb71f258e855 tools/xenstore/fake_libxc.c --- a/tools/xenstore/fake_libxc.c Tue Jul 03 15:49:16 2007 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,143 +0,0 @@ -/* - Fake libxc which doesn't require hypervisor but talks to xs_test. - 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 <stdio.h> -#include <stdlib.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <sys/mman.h> -#include <unistd.h> -#include <assert.h> -#include <signal.h> -#include "utils.h" -#include "xenstored_core.h" -#include "xenstored_domain.h" -#include "xenstored_test.h" -#include <xenctrl.h> - -static int sigfd; -static int xs_test_pid; -static evtchn_port_t port; - -/* The event channel maps to a signal, shared page to an mmapped file. */ -void xc_evtchn_notify(int xce_handle, int local_port) -{ - assert(local_port == port); - if (kill(xs_test_pid, SIGUSR2) != 0) - barf_perror("fake event channel failed"); -} - -void *xc_map_foreign_range(int xc_handle, uint32_t dom __attribute__((unused)), - int size, int prot, - unsigned long mfn __attribute__((unused))) -{ - void *ret; - - ret = mmap(NULL, size, prot, MAP_SHARED, xc_handle, 0); - if (ret == MAP_FAILED) - return NULL; - - /* xs_test tells us pid and port by putting it in buffer, we reply. */ - xs_test_pid = *(int *)(ret + 32); - port = *(int *)(ret + 36); - *(int *)(ret + 32) = getpid(); - return ret; -} - -int xc_interface_open(void) -{ - int fd; - char page[getpagesize()]; - - fd = open("/tmp/xcmap", O_RDWR|O_CREAT|O_TRUNC, 0600); - if (fd < 0) - return fd; - - memset(page, 0, sizeof(page)); - if (!xs_write_all(fd, page, sizeof(page))) - barf_perror("Failed to write /tmp/xcmap page"); - - return fd; -} - -int xc_interface_close(int xc_handle) -{ - close(xc_handle); - return 0; -} - -int xc_domain_getinfo(int xc_handle __attribute__((unused)), - uint32_t first_domid, unsigned int max_doms, - xc_dominfo_t *info) -{ - assert(max_doms == 1); - info->domid = first_domid; - - info->dying = 0; - info->shutdown = 0; - info->paused = 0; - info->blocked = 0; - info->running = 1; - - info->shutdown_reason = 0; - - if ( info->shutdown && (info->shutdown_reason == SHUTDOWN_crash) ) - { - info->shutdown = 0; - info->crashed = 1; - } - - return 1; -} - -static void send_to_fd(int signo __attribute__((unused))) -{ - int saved_errno = errno; - write(sigfd, &port, sizeof(port)); - errno = saved_errno; -} - -void fake_block_events(void) -{ - signal(SIGUSR2, SIG_IGN); -} - -void fake_ack_event(void) -{ - signal(SIGUSR2, send_to_fd); -} - -int xc_evtchn_open(void) -{ - int fds[2]; - - if (pipe(fds) != 0) - return -1; - - if (signal(SIGUSR2, send_to_fd) == SIG_ERR) { - int saved_errno = errno; - close(fds[0]); - close(fds[1]); - errno = saved_errno; - return -1; - } - sigfd = fds[1]; - return fds[0]; -} diff -r 0528bc25c404 -r eb71f258e855 tools/xenstore/speedtest.c --- a/tools/xenstore/speedtest.c Tue Jul 03 15:49:16 2007 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,130 +0,0 @@ -/* - Xen Store Daemon Speed test - 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 <stdlib.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <stdio.h> -#include <stdarg.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> -#include "utils.h" -#include "xs.h" -#include "list.h" -#include "talloc.h" - -static void do_command(const char *cmd) -{ - int ret; - - ret = system(cmd); - if (ret == -1 || !WIFEXITED(ret) || WEXITSTATUS(ret) != 0) - barf_perror("Failed '%s': %i", cmd, ret); -} - -static int start_daemon(void) -{ - int fds[2], pid; - - do_command(talloc_asprintf(NULL, "rm -rf testsuite/tmp/*")); - - /* Start daemon. */ - pipe(fds); - if ((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]); - } else { - dup2(fds[1], STDOUT_FILENO); - close(fds[0]); -#if 0 - execlp("valgrind", "valgrind", "-q", "--suppressions=testsuite/vg-suppressions", "xenstored_test", "--output-pid", - "--no-fork", "--trace-file=/tmp/trace", NULL); -#else - execlp("./xenstored_test", "xenstored_test", "--output-pid", "--no-fork", NULL); -// execlp("strace", "strace", "-o", "/tmp/out", "./xenstored_test", "--output-pid", "--no-fork", NULL); -#endif - exit(1); - } - return pid; -} - -static void kill_daemon(int pid) -{ - int saved_errno = errno; - kill(pid, SIGTERM); - errno = saved_errno; -} - -#define NUM_ENTRIES 50 - -/* We create the given number of trees, each with NUM_ENTRIES, using - * transactions. */ -int main(int argc, char *argv[]) -{ - int i, j, pid, print; - struct xs_handle *h; - - if (argc != 2) - barf("Usage: speedtest <numdomains>"); - - pid = start_daemon(); - h = xs_daemon_open(); - print = atoi(argv[1]) / 76; - if (!print) - print = 1; - for (i = 0; i < atoi(argv[1]); i ++) { - char name[64]; - - if (i % print == 0) - write(1, ".", 1); - if (!xs_transaction_start(h)) { - kill_daemon(pid); - barf_perror("Starting transaction"); - } - sprintf(name, "/%i", i); - if (!xs_mkdir(h, name)) { - kill_daemon(pid); - barf_perror("Making directory %s", name); - } - - for (j = 0; j < NUM_ENTRIES; j++) { - sprintf(name, "/%i/%i", i, j); - if (!xs_write(h, name, name, strlen(name))) { - kill_daemon(pid); - barf_perror("Making directory %s", name); - } - } - if (!xs_transaction_end(h, false)) { - kill_daemon(pid); - barf_perror("Ending transaction"); - } - } - write(1, "\n", 1); - - kill_daemon(pid); - wait(NULL); - return 0; -} - - diff -r 0528bc25c404 -r eb71f258e855 tools/xenstore/testsuite/01simple.test --- a/tools/xenstore/testsuite/01simple.test Tue Jul 03 15:49:16 2007 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -# Create an entry, read it. -write /test contents -expect contents -read /test diff -r 0528bc25c404 -r eb71f258e855 tools/xenstore/testsuite/02directory.test --- a/tools/xenstore/testsuite/02directory.test Tue Jul 03 15:49:16 2007 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -# Root directory has only tool dir in it. -expect tool -dir / - -# Create a file. -write /test 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 contents2 -expect test2 -dir /dir -expect contents2 -read /dir/test2 - -# Creating dir over the top should succeed. -mkdir /dir -mkdir /dir/test2 - -# Mkdir implicitly creates directories. -mkdir /dir/1/2/3/4 -expect test2 -expect 1 -dir /dir -expect 2 -dir /dir/1 -expect 3 -dir /dir/1/2 -expect 4 -dir /dir/1/2/3 -dir /dir/1/2/3/4 diff -r 0528bc25c404 -r eb71f258e855 tools/xenstore/testsuite/03write.test --- a/tools/xenstore/testsuite/03write.test Tue Jul 03 15:49:16 2007 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -# Write succeeds -write /test contents -expect contents -read /test - -# Overwrite succeeds. -write /test contents2 -expect contents2 -read /test - -# Write should implicitly create directories -write /dir/test contents -expect test -dir /dir -expect contents -read /dir/test -write /dir/1/2/3/4 contents4 -expect test -expect 1 -dir /dir -expect 2 -dir /dir/1 -expect 3 -dir /dir/1/2 -expect 4 -dir /dir/1/2/3 -expect contents4 -read /dir/1/2/3/4 diff -r 0528bc25c404 -r eb71f258e855 tools/xenstore/testsuite/04rm.test --- a/tools/xenstore/testsuite/04rm.test Tue Jul 03 15:49:16 2007 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -# Remove non-existant is OK, as long as parent exists -rm /test -expect rm failed: No such file or directory -rm /dir/test - -# Create file and remove it -write /test contents -rm /test -expect tool -dir / - -# Create directory and remove it. -mkdir /dir -rm /dir - -# Create directory, create file, remove all. -mkdir /dir -write /dir/test contents -rm /dir - diff -r 0528bc25c404 -r eb71f258e855 tools/xenstore/testsuite/05filepermissions.test --- a/tools/xenstore/testsuite/05filepermissions.test Tue Jul 03 15:49:16 2007 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -# 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 contents -expect 0 READ -getperm /test -setid 1 -expect 0 READ -getperm /test -expect contents -read /test -expect write failed: Permission denied -write /test 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 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 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 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 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 contents4 - -# Tools can always access things. -setid 0 -expect 1 NONE -getperm /test -expect contents4 -read /test -write /test contents5 diff -r 0528bc25c404 -r eb71f258e855 tools/xenstore/testsuite/06dirpermissions.test --- a/tools/xenstore/testsuite/06dirpermissions.test Tue Jul 03 15:49:16 2007 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,119 +0,0 @@ -# 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 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 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 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 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 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 contents -expect write failed: Permission denied -write /dir/test4 contents - -# Tools can always access things. -setid 0 -expect 1 NONE -getperm /dir -expect test -expect test2 -expect test3 -dir /dir -write /dir/test4 contents - -# Inherited by child. -mkdir /dir/subdir -expect 1 NONE -getperm /dir/subdir -write /dir/subfile 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 contents -expect 3 READ/WRITE -getperm /dir/subdir/subfile - -# Inheritence works through multiple directories, too. -write /dir/subdir/1/2/3/4 contents -expect 3 READ/WRITE -getperm /dir/subdir/1/2/3/4 -mkdir /dir/subdir/a/b/c/d -expect 3 READ/WRITE -getperm /dir/subdir/a/b/c/d diff -r 0528bc25c404 -r eb71f258e855 tools/xenstore/testsuite/07watch.test --- a/tools/xenstore/testsuite/07watch.test Tue Jul 03 15:49:16 2007 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,176 +0,0 @@ -# Watch something, write to it, check watch has fired. -write /test contents - -1 watch /test token -2 write /test contents2 -expect 1:/test:token -1 waitwatch -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 -2 setperm /dir/newdir 0 READ -expect 1:/dir/newdir:token -1 waitwatch -2 rm /dir/newdir -expect 1:/dir/newdir:token -1 waitwatch -1 close -2 close - -# Changed in b594bb976a743d509f1ffabb5bc698874ab90d8f -## 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 contents -expect contents -read /dir/test -expect /dir/test:token -waitwatch -close - -# watch priority test: all simultaneous -1 watch /dir token1 -3 watch /dir token3 -2 watch /dir token2 -write /dir/test contents -expect 3:/dir/test:token3 -3 waitwatch -expect 2:/dir/test:token2 -2 waitwatch -expect 1:/dir/test:token1 -1 waitwatch -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 contents -expect 2:/dir/test:token2 -2 waitwatch -2 close -expect 1:/dir/test:token1 -1 waitwatch -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 contents -2 close -expect 1:/dir/test:token1 -1 waitwatch -1 close -2 close - -# unwatch -1 watch /dir token1 -1 unwatch /dir token1 -1 watch /dir token2 -2 write /dir/test2 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 contents -2 unwatch /dir token2 -expect 1:/dir/test:token1 -1 waitwatch -1 close -2 close - -# unwatch while watch pending. Should clear this so we get next event. -1 watch /dir token1 -write /dir/test contents -1 unwatch /dir token1 -1 watch /dir/test token2 -write /dir/test contents2 -expect 1:/dir/test:token2 -1 waitwatch - -# check we only get notified once. -1 watch /test token -2 write /test contents2 -expect 1:/test:token -1 waitwatch -expect 1: waitwatch failed: Connection timed out -1 waitwatch -1 close - -# watches are queued in order. -1 watch / token -2 write /test1 contents -2 write /test2 contents -2 write /test3 contents -expect 1:/test1:token -1 waitwatch -expect 1:/test2:token -1 waitwatch -expect 1:/test3:token -1 waitwatch -1 close - -# Creation of subpaths should be covered correctly. -1 watch / token -2 write /test/subnode contents2 -2 write /test/subnode/subnode contents2 -expect 1:/test/subnode:token -1 waitwatch -expect 1:/test/subnode/subnode:token -1 waitwatch -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 contents2 -1 watchnoack / token2 0 -expect 1:/test/subnode:token -1 waitwatch -expect 1:/:token2 -1 waitwatch -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 - -# Watch should not double-send after we ack, even if we did something in between. -1 watch /test2 token -2 write /test2/foo contents2 -expect 1:/test2/foo:token -1 waitwatch -expect 1:contents2 -1 read /test2/foo -expect 1: waitwatch failed: Connection timed out -1 waitwatch diff -r 0528bc25c404 -r eb71f258e855 tools/xenstore/testsuite/08transaction.slowtest --- a/tools/xenstore/testsuite/08transaction.slowtest Tue Jul 03 15:49:16 2007 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -# Test transaction clashes. - -mkdir /test -write /test/entry1 contents - -# Start transaction, do read-only op, transaction succeeds -1 start -1 write /test/entry1 contents2 -expect contents -read /test/entry1 -1 commit -expect contents2 -read /test/entry1 - -# Start transaction, abort other transaction, transaction succeeds. -1 start -1 write /test/entry1 contents3 -start -write /test/entry1 contents -abort -1 commit -expect contents3 -read /test/entry1 - -# Start transaction, do write op, transaction fails -1 start -1 write /test/entry1 contents4 -write /test/entry1 contents -expect 1: commit failed: Resource temporarily unavailable -1 commit -expect contents -read /test/entry1 - -# Start transaction, do other transaction, transaction fails -1 start -1 write /test/entry1 contents4 -start -write /test/entry1 contents5 -commit -expect 1: commit failed: Resource temporarily unavailable -1 commit -expect contents5 -read /test/entry1 diff -r 0528bc25c404 -r eb71f258e855 tools/xenstore/testsuite/08transaction.test --- a/tools/xenstore/testsuite/08transaction.test Tue Jul 03 15:49:16 2007 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,92 +0,0 @@ -# Test transactions. - -mkdir /test - -# Simple transaction: create a file inside transaction. -1 start -1 write /test/entry1 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 -1 write /test/entry1 contents -2 dir /test -expect 1:entry1 -1 dir /test -1 abort -2 dir /test - -write /test/entry1 contents -# Delete in transaction, commit -1 start -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 contents -1 start -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 -2 mkdir /test/dir/sub -expect 1: waitwatch failed: Connection timed out -1 waitwatch -2 close -1 close - -1 watch /test token -2 start -2 mkdir /test/dir/sub -2 abort -expect 1: waitwatch failed: Connection timed out -1 waitwatch -1 close - -1 watch /test token -2 start -2 mkdir /test/dir/sub -2 commit -expect 1:/test/dir/sub:token -1 waitwatch -1 close - -# Rm inside transaction works like rm outside: children get notified. -1 watch /test/dir/sub token -2 start -2 rm /test/dir -2 commit -expect 1:/test/dir/sub:token -1 waitwatch -1 close - -# Multiple events from single transaction don't trigger assert -1 watch /test token -2 start -2 write /test/1 contents -2 write /test/2 contents -2 commit -expect 1:/test/1:token -1 waitwatch -expect 1:/test/2:token -1 waitwatch -1 close diff -r 0528bc25c404 -r eb71f258e855 tools/xenstore/testsuite/09domain.test --- a/tools/xenstore/testsuite/09domain.test Tue Jul 03 15:49:16 2007 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -# Test domain communication. - -# Create a domain, write an entry. -expect handle is 1 -introduce 1 100 7 /my/home -1 write /entry1 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 0528bc25c404 -r eb71f258e855 tools/xenstore/testsuite/10domain-homedir.test --- a/tools/xenstore/testsuite/10domain-homedir.test Tue Jul 03 15:49:16 2007 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ -# 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 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 contents -expect 1:foo/bar:token -1 waitwatch diff -r 0528bc25c404 -r eb71f258e855 tools/xenstore/testsuite/11domain-watch.test --- a/tools/xenstore/testsuite/11domain-watch.test Tue Jul 03 15:49:16 2007 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -# Test watching from a domain. - -# Watch something, write to it, check watch has fired. -write /test contents -mkdir /dir - -expect handle is 1 -introduce 1 100 7 /my/home -1 watch /test token -write /test contents2 -expect 1:/test:token -1 waitwatch -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 contents -1 write /dir/test2 contents2 -1 write /dir/test3 contents3 -1 write /dir/test4 contents4 -expect 1:/dir/test:token -1 waitwatch -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 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 contents -1 unwatch /dir token1 -release 1 -1 close diff -r 0528bc25c404 -r eb71f258e855 tools/xenstore/testsuite/12readonly.test --- a/tools/xenstore/testsuite/12readonly.test Tue Jul 03 15:49:16 2007 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -# Test that read only connection can't alter store. - -write /test 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: Permission denied -write /test2 contents -expect write failed: Permission denied -write /test contents -expect setperm failed: Permission denied -setperm /test 100 NONE -expect setperm failed: Permission denied -setperm /test 100 NONE -expect introduce failed: Permission denied -introduce 1 100 7 /home - -# Check that watches work like normal. -watch / token -1 readwrite -1 write /test contents -expect /test:token -waitwatch diff -r 0528bc25c404 -r eb71f258e855 tools/xenstore/testsuite/13watch-ack.test --- a/tools/xenstore/testsuite/13watch-ack.test Tue Jul 03 15:49:16 2007 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,21 +0,0 @@ -# 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 contents2 -expect 1:/test/2:token2 -1 waitwatch -3 write /test/1 contents1 -4 write /test/3 contents3 -1 close diff -r 0528bc25c404 -r eb71f258e855 tools/xenstore/testsuite/14complexperms.test --- a/tools/xenstore/testsuite/14complexperms.test Tue Jul 03 15:49:16 2007 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -# 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 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 -# We get no watch event when there's no permission. It's a corner case. -watchnoack /dir/file token -1 write /dir/file contents -1 rm /dir/file -expect waitwatch failed: Connection timed out -waitwatch -unwatch /dir/file token -expect *No such file or directory -unwatch /dir/file token -expect *Permission denied -introduce 2 100 7 /dir/file - -# Now it exists -setid 0 -write /dir/file contents - -setid 1 -expect *Permission denied -dir /dir/file -expect *Permission denied -read /dir/file -expect *Permission denied -write /dir/file 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 -watchnoack /dir/file token -1 write /dir/file contents -1 rm /dir/file -expect waitwatch failed: Connection timed out -waitwatch -unwatch /dir/file token -expect *No such file or directory -unwatch /dir/file token -expect *Permission denied -introduce 2 100 7 /dir/file diff -r 0528bc25c404 -r eb71f258e855 tools/xenstore/testsuite/test.sh --- a/tools/xenstore/testsuite/test.sh Tue Jul 03 15:49:16 2007 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -#! /bin/sh - -set -e -set -m - -run_test() -{ - rm -rf $XENSTORED_ROOTDIR - mkdir $XENSTORED_ROOTDIR - if [ $VALGRIND -eq 1 ]; then - valgrind --suppressions=testsuite/vg-suppressions -q ./xenstored_test --output-pid --trace-file=testsuite/tmp/trace --no-fork > /tmp/pid 2> testsuite/tmp/xenstored_errors & - while [ ! -s /tmp/pid ]; do sleep 0; done - PID=`cat /tmp/pid` - rm /tmp/pid - else - # We don't get error messages from this, though. - PID=`./xenstored_test --output-pid --trace-file=testsuite/tmp/trace` - fi - if ./xs_test $2 $1; then - if [ -s testsuite/tmp/xenstored_errors ]; then - kill $PID - echo Errors: - cat testsuite/tmp/xenstored_errors - return 1 - fi - kill $PID - sleep 1 - return 0 - else - # In case daemon is wedged. - kill $PID - sleep 1 - return 1 - fi -} - -if [ x$1 = x--fast ]; then - VALGRIND=0 - SLOWTESTS="" - shift -else - if type valgrind >/dev/null 2>&1; then - VALGRIND=1 - else - echo "WARNING: valgrind not available" >&2 - VALGRIND=0 - fi - SLOWTESTS=testsuite/[0-9]*.slowtest -fi - -MATCH=${1:-"*"} -for f in testsuite/[0-9]*.test $SLOWTESTS; do - case `basename $f` in $MATCH) RUN=1;; esac - [ -n "$RUN" ] || continue - - if run_test $f -x >/tmp/out; then - echo -n . - else - cat /tmp/out - # That will have filled the screen, repeat message. - echo Test $f failed - exit 1 - fi -done diff -r 0528bc25c404 -r eb71f258e855 tools/xenstore/testsuite/vg-suppressions --- a/tools/xenstore/testsuite/vg-suppressions Tue Jul 03 15:49:16 2007 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -{ - Glibc goes boom from _start (Debian glibc 2.3.5-3) - Memcheck:Cond - obj:/lib/ld-2.3.5.so - obj:/lib/ld-2.3.5.so - obj:/lib/ld-2.3.5.so - obj:/lib/ld-2.3.5.so - obj:/lib/ld-2.3.5.so -} diff -r 0528bc25c404 -r eb71f258e855 tools/xenstore/xenstored_core.c --- a/tools/xenstore/xenstored_core.c Tue Jul 03 15:49:16 2007 +0100 +++ b/tools/xenstore/xenstored_core.c Tue Jul 03 15:51:59 2007 +0100 @@ -39,7 +39,6 @@ #include <assert.h> #include <setjmp.h> -//#define DEBUG #include "utils.h" #include "list.h" #include "talloc.h" @@ -53,7 +52,6 @@ #include "hashtable.h" - extern int xce_handle; /* in xenstored_domain.c */ static bool verbose = false; @@ -81,50 +79,6 @@ int quota_nb_watch_per_domain = 128; int quota_nb_watch_per_domain = 128; int quota_max_entry_size = 2048; /* 2K */ int quota_max_transaction = 10; - -#ifdef TESTING -static bool failtest = false; - -/* We override talloc's malloc. */ -void *test_malloc(size_t size) -{ - /* 1 in 20 means only about 50% of connections establish. */ - if (failtest && (random() % 32) == 0) - return NULL; - return malloc(size); -} - -static void stop_failtest(int signum __attribute__((unused))) -{ - failtest = false; -} - -/* Need these before we #define away write_all/mkdir in testing.h */ -bool test_write_all(int fd, void *contents, unsigned int len); -bool test_write_all(int fd, void *contents, unsigned int len) -{ - if (failtest && (random() % 8) == 0) { - if (len) - len = random() % len; - write(fd, contents, len); - errno = ENOSPC; - return false; - } - return xs_write_all(fd, contents, len); -} - -int test_mkdir(const char *dir, int perms); -int test_mkdir(const char *dir, int perms) -{ - if (failtest && (random() % 8) == 0) { - errno = ENOSPC; - return -1; - } - return mkdir(dir, perms); -} -#endif /* TESTING */ - -#include "xenstored_test.h" TDB_CONTEXT *tdb_context(struct connection *conn) { @@ -1163,12 +1117,10 @@ static void do_debug(struct connection * { int num; -#ifndef TESTING if (conn->id != 0) { send_error(conn, EACCES); return; } -#endif num = xs_count_strings(in->buffer, in->used); @@ -1179,18 +1131,10 @@ static void do_debug(struct connection * } xprintf("debug: %s", in->buffer + get_string(in, 0)); } + if (streq(in->buffer, "check")) check_store(); -#ifdef TESTING - /* For testing, we allow them to set id. */ - if (streq(in->buffer, "setid")) { - conn->id = atoi(in->buffer + get_string(in, 0)); - } else if (streq(in->buffer, "failtest")) { - if (get_string(in, 0) < in->used) - srandom(atoi(in->buffer + get_string(in, 0))); - failtest = true; - } -#endif /* TESTING */ + send_ack(conn, XS_DEBUG); } @@ -1319,10 +1263,8 @@ static void handle_input(struct connecti return; if (in->hdr.msg.len > PATH_MAX) { -#ifndef TESTING syslog(LOG_ERR, "Client tried to feed us %i", in->hdr.msg.len); -#endif goto bad_client; } @@ -1414,39 +1356,7 @@ static void accept_connection(int sock, close(fd); } -#ifdef TESTING -/* Valgrind can check our writes better if we don't use mmap */ -#define TDB_FLAGS TDB_NOMMAP -/* Useful for running under debugger. */ -void dump_connection(void) -{ - struct connection *i; - - list_for_each_entry(i, &connections, list) { - printf("Connection %p:\n", i); - printf(" state = %s\n", - list_empty(&i->out_list) ? "OK" : "BUSY"); - if (i->id) - printf(" id = %i\n", i->id); - if (!i->in->inhdr || i->in->used) - printf(" got %i bytes of %s\n", - i->in->used, i->in->inhdr ? "header" : "data"); -#if 0 - if (i->out) - printf(" sending message %s (%s) out\n", - sockmsg_string(i->out->hdr.msg.type), - i->out->buffer); - if (i->transaction) - dump_transaction(i); - if (i->domain) - dump_domain(i); -#endif - dump_watches(i); - } -} -#else #define TDB_FLAGS 0 -#endif /* We create initial nodes manually. */ static void manual_node(const char *name, const char *child) @@ -1693,10 +1603,6 @@ static void corrupt(struct connection *c log("corruption detected by connection %i: err %s: %s", conn ? (int)conn->id : -1, strerror(saved_errno), str); -#ifdef TESTING - /* Allow them to attach debugger. */ - sleep(30); -#endif check_store(); } @@ -1740,11 +1646,10 @@ static void daemonize(void) if (pid != 0) exit(0); -#ifndef TESTING /* Relative paths for socket names */ /* Move off any mount points we might be in. */ if (chdir("/") == -1) barf_perror("Failed to chdir"); -#endif + /* Discard our parent's old-fashioned umask prejudices. */ umask(0); } @@ -1941,10 +1846,6 @@ int main(int argc, char *argv[]) signal(SIGHUP, trigger_reopen_log); -#ifdef TESTING - signal(SIGUSR1, stop_failtest); -#endif - if (xce_handle != -1) evtchn_fd = xc_evtchn_fd(xce_handle); diff -r 0528bc25c404 -r eb71f258e855 tools/xenstore/xenstored_domain.c --- a/tools/xenstore/xenstored_domain.c Tue Jul 03 15:49:16 2007 +0100 +++ b/tools/xenstore/xenstored_domain.c Tue Jul 03 15:51:59 2007 +0100 @@ -23,14 +23,12 @@ #include <stdlib.h> #include <stdarg.h> -//#define DEBUG #include "utils.h" #include "talloc.h" #include "xenstored_core.h" #include "xenstored_domain.h" #include "xenstored_transaction.h" #include "xenstored_watch.h" -#include "xenstored_test.h" #include <xenctrl.h> @@ -217,10 +215,8 @@ void handle_event(void) if (port == virq_port) domain_cleanup(); -#ifndef TESTING if (xc_evtchn_unmask(xce_handle, port) == -1) barf_perror("Failed to write to event fd"); -#endif } bool domain_can_read(struct connection *conn) diff -r 0528bc25c404 -r eb71f258e855 tools/xenstore/xenstored_test.h --- a/tools/xenstore/xenstored_test.h Tue Jul 03 15:49:16 2007 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -/* - Testing replcements for Xen Store 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 -*/ -#ifndef _XENSTORED_TEST_H -#define _XENSTORED_TEST_H - -#ifdef TESTING -bool test_write_all(int fd, void *contents, unsigned int len); -#define xs_write_all test_write_all - -int test_mkdir(const char *dir, int perms); -#define mkdir test_mkdir - -int fake_open_eventchn(void); -void fake_block_events(void); -void fake_ack_event(void); - -#define ioctl(a,b,c) 0 - -#endif - -#endif /* _XENSTORED_INTERNAL_H */ diff -r 0528bc25c404 -r eb71f258e855 tools/xenstore/xenstored_transaction.c --- a/tools/xenstore/xenstored_transaction.c Tue Jul 03 15:49:16 2007 +0100 +++ b/tools/xenstore/xenstored_transaction.c Tue Jul 03 15:51:59 2007 +0100 @@ -35,7 +35,6 @@ #include "xenstored_domain.h" #include "xs_lib.h" #include "utils.h" -#include "xenstored_test.h" struct changed_node { diff -r 0528bc25c404 -r eb71f258e855 tools/xenstore/xenstored_watch.c --- a/tools/xenstore/xenstored_watch.c Tue Jul 03 15:49:16 2007 +0100 +++ b/tools/xenstore/xenstored_watch.c Tue Jul 03 15:51:59 2007 +0100 @@ -29,7 +29,6 @@ #include "xenstored_watch.h" #include "xs_lib.h" #include "utils.h" -#include "xenstored_test.h" #include "xenstored_domain.h" extern int quota_nb_watch_per_domain; @@ -195,17 +194,6 @@ void conn_delete_all_watches(struct conn domain_watch_dec(conn); } } - -#ifdef TESTING -void dump_watches(struct connection *conn) -{ - struct watch *watch; - - list_for_each_entry(watch, &conn->watches, list) - printf(" watch on %s token %s\n", - watch->node, watch->token); -} -#endif /* * Local variables: diff -r 0528bc25c404 -r eb71f258e855 tools/xenstore/xs_crashme.c --- a/tools/xenstore/xs_crashme.c Tue Jul 03 15:49:16 2007 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,393 +0,0 @@ -/* 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> - -#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 uint32_t jhash(const void *key, uint32_t length, uint32_t initval) -{ - uint32_t a, b, c, len; - const uint8_t *k = key; - - len = length; - a = b = JHASH_GOLDEN_RATIO; - c = initval; - - while (len >= 12) { - a += (k[0] +((uint32_t)k[1]<<8) +((uint32_t)k[2]<<16) +((uint32_t)k[3]<<24)); - b += (k[4] +((uint32_t)k[5]<<8) +((uint32_t)k[6]<<16) +((uint32_t)k[7]<<24)); - c += (k[8] +((uint32_t)k[9]<<8) +((uint32_t)k[10]<<16)+((uint32_t)k[11]<<24)); - - __jhash_mix(a,b,c); - - k += 12; - len -= 12; - } - - c += length; - switch (len) { - case 11: c += ((uint32_t)k[10]<<24); - case 10: c += ((uint32_t)k[9]<<16); - case 9 : c += ((uint32_t)k[8]<<8); - case 8 : b += ((uint32_t)k[7]<<24); - case 7 : b += ((uint32_t)k[6]<<16); - case 6 : b += ((uint32_t)k[5]<<8); - case 5 : b += k[4]; - case 4 : a += ((uint32_t)k[3]<<24); - case 3 : a += ((uint32_t)k[2]<<16); - case 2 : a += ((uint32_t)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 uint32_ts. - * The length parameter here is the number of uint32_ts in the key. - */ -static inline uint32_t jhash2(uint32_t *k, uint32_t length, uint32_t initval) -{ - uint32_t 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 uint32_t jhash_3words(uint32_t a, uint32_t b, uint32_t c, uint32_t initval) -{ - a += JHASH_GOLDEN_RATIO; - b += JHASH_GOLDEN_RATIO; - c += initval; - - __jhash_mix(a, b, c); - - return c; -} - -static inline uint32_t jhash_2words(uint32_t a, uint32_t b, uint32_t initval) -{ - return jhash_3words(a, b, 0, initval); -} - -static inline uint32_t jhash_1word(uint32_t a, uint32_t 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; -} - -/* 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: { - char *contents = talloc_asprintf(NULL, "%i", - get_randomness(&state)); - unsigned int len = get_randomness(&state)%(strlen(contents)+1); - if (verbose) - printf("WRITE %s %.*s\n", name, len, contents); - xs_write(h, name, contents, len); - 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); - 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; -} - diff -r 0528bc25c404 -r eb71f258e855 tools/xenstore/xs_random.c --- a/tools/xenstore/xs_random.c Tue Jul 03 15:49:16 2007 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1590 +0,0 @@ -/* Random tests. - - We check that the results from a real filesystem are the same. -*/ -#include <sys/types.h> -#include <stdio.h> -#include <stdarg.h> -#include <stdlib.h> -#include <dirent.h> -#include <errno.h> -#include <sys/stat.h> -#include <unistd.h> -#include <fcntl.h> -#include <signal.h> -#include <sys/wait.h> -#include "xs.h" -#include "talloc.h" -#include "utils.h" - -struct ops -{ - char *name; - - char **(*dir)(void *h, const char *path, unsigned int *num); - - void *(*read)(void *h, const char *path, unsigned int *len); - - bool (*write)(void *h, const char *path, const void *data, - unsigned int len); - - bool (*mkdir)(void *h, const char *path); - - bool (*rm)(void *h, const char *path); - - struct xs_permissions *(*get_perms)(void *h, - const char *path, - unsigned int *num); - - bool (*set_perms)(void *h, - const char *path, - struct xs_permissions *perms, - unsigned int num); - - bool (*transaction_start)(void *h); - bool (*transaction_end)(void *h, bool abort); - - /* Create and destroy a new handle. */ - void *(*handle)(const char *path); - void (*close)(void *); -}; - -struct file_ops_info -{ - const char *base; - char *transact_base; -}; - -static void convert_to_dir(const char *dirname) -{ - char *tmpname = talloc_asprintf(dirname, "%s.tmp", dirname); - if (rename(dirname, tmpname) != 0) - barf_perror("Failed to rename %s to %s", dirname, tmpname); - if (mkdir(dirname, 0700) != 0) - barf_perror("Failed to mkdir %s", dirname); - if (rename(tmpname,talloc_asprintf(dirname, "%s/.DATA", dirname)) != 0) - barf_perror("Failed to rename into %s", dirname); - /* If perms exists, move it in. */ - rename(talloc_asprintf(dirname, "%s.perms", dirname), - talloc_asprintf(dirname, "%s/.perms", dirname)); -} - -/* Files can be used as dirs, too. Convert them when they are. */ -static void maybe_convert_to_directory(const char *filename) -{ - struct stat st; - char *dirname = talloc_asprintf( - filename, "%.*s", - (int)(strrchr(filename, '/') - filename), filename); - if (lstat(dirname, &st) == 0 && S_ISREG(st.st_mode)) - convert_to_dir(dirname); -} - -static char *get_name(struct file_ops_info *info, const char *path) -{ - if (info->transact_base) - return talloc_asprintf(path, "%s%s", info->transact_base, - path); - return talloc_asprintf(path, "%s%s", info->base, path); -} - -static char *path_to_name(struct file_ops_info *info, const char *path) -{ - char *filename = get_name(info, path); - maybe_convert_to_directory(filename); - return filename; -} - -static char **file_directory(struct file_ops_info *info, - const char *path, unsigned int *num) -{ - char **ret; - DIR *dir; - struct dirent *dirent; - char *p, *dirname = path_to_name(info, path); - unsigned int i, len = 0; - struct stat st; - - /* If it exists, but isn't a directory, we convert it. */ - if (lstat(dirname, &st) == 0 && !S_ISDIR(st.st_mode)) - convert_to_dir(dirname); - - *num = 0; - dir = opendir(dirname); - if (!dir) - return NULL;; - - /* Once to count them. */ - while ((dirent = readdir(dir)) != NULL) { - if (strchr(dirent->d_name, '.')) - continue; - len += strlen(dirent->d_name) + 1; - (*num)++; - } - rewinddir(dir); - - /* Now allocate and fill in. */ - ret = malloc(sizeof(char *) * *num + len); - p = (char *)&ret[*num]; - i = 0; - while ((dirent = readdir(dir)) != NULL) { - if (strchr(dirent->d_name, '.')) - continue; - ret[i] = p; - strcpy(p, dirent->d_name); - p += strlen(p) + 1; - i++; - } - closedir(dir); - - return ret; -} - -static char *filename_to_data(const char *filename) -{ - struct stat st; - - if (lstat(filename, &st) == 0 && S_ISDIR(st.st_mode)) - return talloc_asprintf(filename, "%s/.DATA", filename); - return (char *)filename; -} - -static void *file_read(struct file_ops_info *info, - const char *path, unsigned int *len) -{ - void *ret; - char *filename = filename_to_data(path_to_name(info, path)); - unsigned long size; - - ret = grab_file(filename, &size); - /* Directory exists, .DATA doesn't. */ - if (!ret && errno == ENOENT && strends(filename, ".DATA")) { - ret = strdup(""); - size = 0; - } - *len = size; - return ret; -} - -static struct xs_permissions *file_get_perms(struct file_ops_info *info, - const char *path, - unsigned int *num) -{ - void *perms; - struct xs_permissions *ret; - char *filename = path_to_name(info, path); - char *permfile; - unsigned long size; - struct stat st; - - if (lstat(filename, &st) != 0) - return NULL; - - if (S_ISDIR(st.st_mode)) - permfile = talloc_asprintf(path, "%s/.perms", filename); - else - permfile = talloc_asprintf(path, "%s.perms", filename); - - perms = grab_file(permfile, &size); - if (!perms) - barf("Grabbing permissions for %s", permfile); - *num = xs_count_strings(perms, size); - - ret = new_array(struct xs_permissions, *num); - if (!xs_strings_to_perms(ret, *num, perms)) - barf("Reading permissions from %s", permfile); - release_file(perms, size); - return ret; -} - -static void do_command(const char *cmd) -{ - int ret; - - ret = system(cmd); - if (ret == -1 || !WIFEXITED(ret) || WEXITSTATUS(ret) != 0) - barf_perror("Failed '%s': %i", cmd, ret); -} - -static void init_perms(const char *filename) -{ - struct stat st; - char *permfile, *command; - - if (lstat(filename, &st) != 0) - barf_perror("Failed to stat %s", filename); - - if (S_ISDIR(st.st_mode)) - permfile = talloc_asprintf(filename, "%s/.perms", filename); - else - permfile = talloc_asprintf(filename, "%s.perms", filename); - - /* Leave permfile if it already exists. */ - if (lstat(permfile, &st) == 0) - return; - - /* Copy permissions from parent */ - command = talloc_asprintf(filename, "cp %.*s/.perms %s", - (int)(strrchr(filename, '/') - filename), - filename, permfile); - do_command(command); -} - -static bool file_set_perms(struct file_ops_info *info, - const char *path, - struct xs_permissions *perms, - unsigned int num) -{ - unsigned int i; - char *filename = path_to_name(info, path); - char *permfile; - int fd; - struct stat st; - - if (num < 1) { - errno = EINVAL; - return false; - } - - /* Check non-perm file exists/ */ - if (lstat(filename, &st) != 0) - return false; - - if (S_ISDIR(st.st_mode)) - permfile = talloc_asprintf(path, "%s/.perms", filename); - else - permfile = talloc_asprintf(path, "%s.perms", filename); - - fd = open(permfile, O_WRONLY|O_CREAT|O_TRUNC, 0600); - if (fd < 0) - return false; - - for (i = 0; i < num; i++) { - char buffer[100]; - - if (!xs_perm_to_string(&perms[i], buffer)) { - int saved_errno = errno; - close(fd); - errno = saved_errno; - return false; - } - if (write(fd, buffer, strlen(buffer) + 1) - != (int)strlen(buffer) + 1) - barf_perror("Failed to write perm"); - } - close(fd); - return true; -} - -static char *parent_filename(const char *name) -{ - char *slash = strrchr(name + 1, '/'); - if (!slash) - return talloc_strdup(name, "/"); - return talloc_asprintf(name, "%.*s", (int)(slash-name), name); -} - -static void make_dirs(const char *filename) -{ - struct stat st; - - if (lstat(filename, &st) == 0 && S_ISREG(st.st_mode)) - convert_to_dir(filename); - - if (mkdir(filename, 0700) == 0) { - init_perms(filename); - return; - } - if (errno == EEXIST) - return; - - make_dirs(parent_filename(filename)); - if (mkdir(filename, 0700) != 0) - barf_perror("Failed to mkdir %s", filename); - init_perms(filename); -} - -static bool file_write(struct file_ops_info *info, - const char *path, const void *data, - unsigned int len) -{ - char *filename = filename_to_data(path_to_name(info, path)); - int fd; - - make_dirs(parent_filename(filename)); - fd = open(filename, O_CREAT|O_TRUNC|O_WRONLY, 0600); - if (fd < 0) - return false; - - if (write(fd, data, len) != (int)len) - barf_perror("Bad write to %s", filename); - - init_perms(filename); - close(fd); - return true; -} - -static bool file_mkdir(struct file_ops_info *info, const char *path) -{ - char *dirname = path_to_name(info, path); - - make_dirs(parent_filename(dirname)); - if (mkdir(dirname, 0700) != 0) - return (errno == EEXIST); - - init_perms(dirname); - return true; -} - -static bool file_rm(struct file_ops_info *info, const char *path) -{ - char *filename = path_to_name(info, path); - struct stat st; - - if (lstat(filename, &st) != 0) { - if (lstat(parent_filename(filename), &st) != 0) - return false; - return true; - } - - if (streq(path, "/")) { - errno = EINVAL; - return false; - } - - do_command(talloc_asprintf(path, "rm -f %s.perms; rm -r %s", - filename, filename)); - return true; -} - -static bool file_transaction_start(struct file_ops_info *info) -{ - char *cmd; - - if (info->transact_base) { - errno = EBUSY; - return false; - } - - info->transact_base = talloc_asprintf(NULL, "%s.transact", info->base); - cmd = talloc_asprintf(NULL, "cp -r %s %s", - info->base, info->transact_base); - do_command(cmd); - talloc_free(cmd); - return true; -} - -static bool file_transaction_end(struct file_ops_info *info, bool abort) -{ - char *old, *cmd; - - if (!info->transact_base) { - errno = ENOENT; - return false; - } - - if (abort) { - cmd = talloc_asprintf(NULL, "rm -rf %s", info->transact_base); - do_command(cmd); - goto success; - } - - old = talloc_asprintf(NULL, "rm -rf %s", info->base); - do_command(old); - talloc_free(old); - - cmd = talloc_asprintf(NULL, "mv %s %s", - info->transact_base, info->base); - do_command(cmd); - -success: - talloc_free(cmd); - talloc_free(info->transact_base); - info->transact_base = NULL; - return true; -} - -static struct file_ops_info *file_handle(const char *dir) -{ - struct file_ops_info *info = talloc(NULL, struct file_ops_info); - - info->base = dir; - info->transact_base = NULL; - return info; -} - -static void file_close(struct file_ops_info *handle) -{ - talloc_free(handle); -} - -static struct xs_handle *xs_handle(const char *dir __attribute__((unused))) -{ - struct xs_handle *h; - - h = xs_daemon_open(); - if (!h) - barf_perror("Connecting to xs daemon"); - return h; -} - -static void xs_close(struct xs_handle *handle) -{ - xs_daemon_close(handle); -} - -struct ops file_ops = { - .name = "FILE", - .dir = (void *)file_directory, - .read = (void *)file_read, - .write = (void *)file_write, - .mkdir = (void *)file_mkdir, - .rm = (void *)file_rm, - .get_perms = (void *)file_get_perms, - .set_perms = (void *)file_set_perms, - .transaction_start = (void *)file_transaction_start, - .transaction_end = (void *)file_transaction_end, - .handle = (void *)file_handle, - .close = (void *)file_close, -}; - -struct ops xs_ops = { - .name = "XS", - .dir = (void *)xs_directory, - .read = (void *)xs_read, - .write = (void *)xs_write, - .mkdir = (void *)xs_mkdir, - .rm = (void *)xs_rm, - .get_perms = (void *)xs_get_permissions, - .set_perms = (void *)xs_set_permissions, - .transaction_start = (void *)xs_transaction_start, - .transaction_end = (void *)xs_transaction_end, - .handle = (void *)xs_handle, - .close = (void *)xs_close, -}; - -static int strptrcmp(const void *a, const void *b) -{ - return strcmp(*(char **)a, *(char **)b); -} - -static void sort_dir(char **dir, unsigned int num) -{ - qsort(dir, num, sizeof(char *), strptrcmp); -} - -static char *dump_dir(struct ops *ops, - void *h, - const char *node, - char **dir, - unsigned int numdirs, - unsigned int depth) -{ - char *ret = talloc_strdup(node, ""); - unsigned int i; - char spacing[depth+1]; - - memset(spacing, ' ', depth); - spacing[depth] = '\0'; - - sort_dir(dir, numdirs); - - for (i = 0; i < numdirs; i++) { - struct xs_permissions *perms; - unsigned int j, numperms; - unsigned int len; - char *contents; - unsigned int subnum; - char **subdirs; - char *subret; - char *subnode = talloc_asprintf(node, "%s/%s", node, dir[i]); - - perms = ops->get_perms(h, subnode, &numperms); - if (!perms) - return NULL; - ret = talloc_asprintf_append(ret, "%s%s: ", spacing, dir[i]); - for (j = 0; j < numperms; j++) { - char buffer[100]; - if (!xs_perm_to_string(&perms[j], buffer)) - barf("perm to string"); - ret = talloc_asprintf_append(ret, "%s ", buffer); - } - free(perms); - ret = talloc_asprintf_append(ret, "\n"); - - /* Even directories can have contents. */ - contents = ops->read(h, subnode, &len); - if (!contents) { - if (errno != EISDIR) - return NULL; - } else { - ret = talloc_asprintf_append(ret, " %s(%.*s)\n", - spacing, len, contents); - free(contents); - } - - /* Every node is a directory. */ - subdirs = ops->dir(h, subnode, &subnum); - if (!subdirs) - return NULL; - subret = dump_dir(ops, h, subnode, subdirs, subnum, depth+1); - if (!subret) - return NULL; - ret = talloc_asprintf_append(ret, "%s", subret); - free(subdirs); - } - return ret; -} - -static char *dump(struct ops *ops, void *h) -{ - char **subdirs; - unsigned int subnum; - char *ret = NULL, *root = talloc_strdup(NULL, "/"); - - subdirs = ops->dir(h, root, &subnum); - if (subdirs) { - ret = dump_dir(ops, h, talloc_strdup(root, ""), subdirs, - subnum, 0); - free(subdirs); - if (ret) - talloc_steal(NULL, ret); - } - talloc_free(root); - return ret; -} - -/* 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 uint32_t jhash(const void *key, uint32_t length, uint32_t initval) -{ - uint32_t a, b, c, len; - const uint8_t *k = key; - - len = length; - a = b = JHASH_GOLDEN_RATIO; - c = initval; - - while (len >= 12) { - a += (k[0] +((uint32_t)k[1]<<8) +((uint32_t)k[2]<<16) +((uint32_t)k[3]<<24)); - b += (k[4] +((uint32_t)k[5]<<8) +((uint32_t)k[6]<<16) +((uint32_t)k[7]<<24)); - c += (k[8] +((uint32_t)k[9]<<8) +((uint32_t)k[10]<<16)+((uint32_t)k[11]<<24)); - - __jhash_mix(a,b,c); - - k += 12; - len -= 12; - } - - c += length; - switch (len) { - case 11: c += ((uint32_t)k[10]<<24); - case 10: c += ((uint32_t)k[9]<<16); - case 9 : c += ((uint32_t)k[8]<<8); - case 8 : b += ((uint32_t)k[7]<<24); - case 7 : b += ((uint32_t)k[6]<<16); - case 6 : b += ((uint32_t)k[5]<<8); - case 5 : b += k[4]; - case 4 : a += ((uint32_t)k[3]<<24); - case 3 : a += ((uint32_t)k[2]<<16); - case 2 : a += ((uint32_t)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 uint32_ts. - * The length parameter here is the number of uint32_ts in the key. - */ -static inline uint32_t jhash2(uint32_t *k, uint32_t length, uint32_t initval) -{ - uint32_t 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 uint32_t jhash_3words(uint32_t a, uint32_t b, uint32_t c, uint32_t initval) -{ - a += JHASH_GOLDEN_RATIO; - b += JHASH_GOLDEN_RATIO; - c += initval; - - __jhash_mix(a, b, c); - - return c; -} - -static inline uint32_t jhash_2words(uint32_t a, uint32_t b, uint32_t initval) -{ - return jhash_3words(a, b, 0, initval); -} - -static inline uint32_t jhash_1word(uint32_t a, uint32_t initval) -{ - return jhash_3words(a, 0, 0, initval); -} - -static unsigned int get_randomness(int *state) -{ - return jhash_1word((*state)++, *state * 1103515243); -} - -static char *random_path(int *state) -{ - 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 char *bool_to_errstring(bool result) -{ - if (result) - return talloc_strdup(NULL, "OK"); - - /* Real daemon can never return this. */ - if (errno == ENOTDIR) - errno = ENOENT; - return talloc_asprintf(NULL, "FAILED:%s", strerror(errno)); -} - -static char *linearize_dir(char **dir, unsigned int *num) -{ - char *result = NULL; - unsigned int i; - - if (!dir) - return bool_to_errstring(false); - - if (!*num) { - free(dir); - return talloc_strdup(NULL, ""); - } - - sort_dir(dir, *num); - for (i = 0; i < *num; i++) - result = talloc_asprintf_append(result, "%s\n", dir[i]); - free(dir); - return result; -} - -static char *linearize_read(char *read, unsigned int *size) -{ - char *ret; - - if (!read) - return bool_to_errstring(false); - - ret = talloc_asprintf(NULL, "%i:%.*s", *size, *size, read); - free(read); - return ret; -} - -static char *linearize_perms(struct xs_permissions *perms, unsigned int *size) -{ - char *ret = NULL; - unsigned int i; - - if (!perms) - return bool_to_errstring(false); - - for (i = 0; i < *size; i++) - ret = talloc_asprintf_append(ret, "(%u %u)", - perms[i].id, perms[i].perms); - - free(perms); - return ret; -} - -/* Do the next operation, return the results. */ -static char *do_next_op(struct ops *ops, void *h, int state, bool verbose) -{ - char *name; - unsigned int num; - char *ret; - - if (verbose) - printf("State %i: ", state); - - name = random_path(&state); - switch (get_randomness(&state) % 9) { - case 0: - if (verbose) - printf("DIR %s\n", name); - ret = linearize_dir(ops->dir(h, name, &num), &num); - break; - case 1: - if (verbose) - printf("READ %s\n", name); - ret = linearize_read(ops->read(h, name, &num), &num); - break; - case 2: { - char *contents = talloc_asprintf(NULL, "%i", - get_randomness(&state)); - unsigned int len = get_randomness(&state)%(strlen(contents)+1); - if (verbose) - printf("WRITE %s %.*s\n", name, len, contents); - ret = bool_to_errstring(ops->write(h, name, contents, len)); - talloc_steal(ret, contents); - break; - } - case 3: - if (verbose) - printf("MKDIR %s\n", name); - ret = bool_to_errstring(ops->mkdir(h, name)); - break; - case 4: - if (verbose) - printf("RM %s\n", name); - ret = bool_to_errstring(ops->rm(h, name)); - break; - case 5: - if (verbose) - printf("GETPERMS %s\n", name); - ret = linearize_perms(ops->get_perms(h, name, &num), - &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"); - ret = bool_to_errstring(ops->set_perms(h, name, perms, - num)); - break; - } - case 7: { - if (verbose) - printf("START %s\n", name); - ret = bool_to_errstring(ops->transaction_start(h)); - if (streq(ret, "OK")) { - talloc_free(ret); - ret = talloc_asprintf(NULL, "OK:START-TRANSACT"); - } - - break; - } - case 8: { - bool abort = (get_randomness(&state) % 2); - - if (verbose) - printf("STOP %s\n", abort ? "ABORT" : "COMMIT"); - ret = bool_to_errstring(ops->transaction_end(h, abort)); - if (streq(ret, "OK")) { - talloc_free(ret); - ret = talloc_strdup(NULL, "OK:STOP-TRANSACT"); - } - break; - } - default: - barf("Impossible randomness"); - } - - talloc_steal(ret, name); - return ret; -} - -static int daemon_pid; - -static void cleanup_xs_ops(void) -{ - char *cmd; - - if (daemon_pid) { - kill(daemon_pid, SIGTERM); - waitpid(daemon_pid, NULL, 0); - daemon_pid = 0; - } - - cmd = talloc_asprintf(NULL, "rm -rf testsuite/tmp/*"); - do_command(cmd); - talloc_free(cmd); -} - -static void cleanup_file_ops(const char *dir) -{ - char *cmd; - - cmd = talloc_asprintf(NULL, "rm -rf %s %s.transact", dir, dir); - do_command(cmd); - talloc_free(cmd); -} - -static void cleanup(const char *dir) -{ - cleanup_xs_ops(); - cleanup_file_ops(dir); -} - -static void setup_file_ops(const char *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(h, "%s/tool", dir), 0700) != 0) - barf_perror("Creating directory %s/tool", dir); - if (!file_set_perms(h, talloc_strdup(h, "/"), &perm, 1)) - barf_perror("Setting root perms in %s", dir); - if (!file_set_perms(h, talloc_strdup(h, "/tool"), &perm, 1)) - barf_perror("Setting root perms in %s/tool", dir); - file_close(h); -} - -static void setup_xs_ops(void) -{ - int fds[2]; - - /* 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]); - } else { - dup2(fds[1], STDOUT_FILENO); - close(fds[0]); -#if 1 - execlp("valgrind", "valgrind", "-q", "--suppressions=testsuite/vg-suppressions", "xenstored_test", "--output-pid", - "--no-fork", NULL); -#else - execlp("./xenstored_test", "xenstored_test", "--output-pid", - "--no-fork", NULL); -#endif - exit(1); - } -} - -static void setup(const char *dir) -{ - setup_file_ops(dir); - setup_xs_ops(); -}; - -struct simple_data -{ - unsigned int seed; - bool print_progress; - bool fast; - struct ops *ops; - const char *dir; -}; - -/* Just a random test. Don't care about results, just that it doesn't - * go boom. */ -static unsigned int try_simple(const bool *trymap, - unsigned int number, - bool verbose, - void *_data) -{ - unsigned int i, print; - void *h; - char *snapshot = NULL; - struct simple_data *data = _data; - - if (data->ops == &xs_ops) { - cleanup_xs_ops(); - setup_xs_ops(); - } else { - cleanup_file_ops(data->dir); - setup_file_ops(data->dir); - } - h = data->ops->handle(data->dir); - - print = number / 76; - if (!print) - print = 1; - - for (i = 0; i < number; i++) { - char *ret; - - if (data->print_progress) { - if (i % print == 0) { - printf("."); - fflush(stdout); - } - } - - if (trymap && !trymap[i]) - continue; - - ret = do_next_op(data->ops, h, i + data->seed, verbose); - if (verbose) - printf("-> %.*s\n", - (int)(strchr(ret, '\n') - ret), ret); - if (streq(ret, "FAILED:Bad file descriptor")) - goto out; - if (kill(daemon_pid, 0) != 0) - goto out; - - if (!data->fast) { - if (streq(ret, "OK:START-TRANSACT")) { - void *pre = data->ops->handle(data->dir); - - snapshot = dump(data->ops, pre); - if (!snapshot) - goto out; - data->ops->close(pre); - } else if (streq(ret, "OK:STOP-TRANSACT")) { - talloc_free(snapshot); - snapshot = NULL; - } - } - - talloc_free(ret); - - if (snapshot) { - void *pre = data->ops->handle(data->dir); - char *contents; - - contents = dump(data->ops, pre); - if (!contents) - goto out; - - if (!streq(contents, snapshot)) - goto out; - - talloc_free(contents); - data->ops->close(pre); - } - } -out: - data->ops->close(h); - return i; -} - -/* Binary elimination: try eliminating all of them, then reduce. */ -static void reduce(bool *map, - unsigned int number, - unsigned int try_start, unsigned int try_num, - unsigned int (*try)(const bool *map, - unsigned int number, - bool verbose, - void *), - void *data) -{ - bool newmap[number]; - - if (try_num == 0) - return; - - /* Try skipping everything between start and end. */ - memcpy(newmap, map, sizeof(newmap)); - memset(newmap + try_start, 0, try_num * sizeof(bool)); - - /* We want the *same* failure: must fail at "number-1". */ - if (try(newmap, number, false, data) == number - 1) { - memset(map + try_start, 0, try_num * sizeof(bool)); - return; - } - - if (try_num == 1) - return; - - /* Try each half... */ - reduce(map, number, try_start, try_num/2, try, data); - reduce(map, number, try_start + try_num/2, try_num - try_num/2, - try, data); -} - -static void reduce_problem(unsigned int failed, - unsigned int (*try)(const bool *map, - unsigned int number, - bool verbose, - void *data), - void *data) -{ - bool map[failed]; - - memset(map, 1, sizeof(map)); - reduce(map, failed, 0, failed-1, try, data); - - printf("Cut down:\n"); - if (try(map, failed, true, data) != failed - 1) { - printf("Except, that didn't actually fail. Bugger!"); - exit(2); - } - exit(1); -} - -/* Just a random test. Don't care about results, just that it doesn't - * go boom. */ -static void simple_test(const char *dir, - unsigned int iters, unsigned int seed, - bool fast, bool verbose) -{ - struct simple_data data; - unsigned int try; - - data.seed = seed; - data.print_progress = !verbose; - data.fast = fast; - data.ops = &xs_ops; - data.dir = dir; - - try = try_simple(NULL, iters, verbose, &data); - if (try == iters) { - cleanup_xs_ops(); - exit(0); - } - printf("Failed on iteration %u of seed %u\n", try + 1, seed); - data.print_progress = false; - reduce_problem(try + 1, try_simple, &data); -} - -static bool ops_equal(struct ops *a, void *ah, - struct ops *b, void *bh, - const char *node, - struct ops **fail) -{ - char **dira = NULL, **dirb = NULL; - char *dataa = NULL, *datab = NULL; - unsigned int i, numa, numb, lena, lenb; - struct xs_permissions *permsa = NULL, *permsb = NULL; - unsigned int numpermsa, numpermsb; - char *nodename; - bool ret = false; - - /* Ignore tool/ dir. */ - if (streq(node, "/tool")) - return true; - - /* FILE backend expects talloc'ed pointer. */ - nodename = talloc_strdup(NULL, node); - permsa = a->get_perms(ah, nodename, &numpermsa); - if (!permsa) { - *fail = a; - goto out; - } - permsb = b->get_perms(bh, nodename, &numpermsb); - if (!permsb) { - *fail = b; - goto out; - } - if (numpermsa != numpermsb) - goto out; - for (i = 0; i < numpermsa; i++) { - if (permsa[i].perms != permsb[i].perms) - goto out; - if (permsa[i].id != permsb[i].id) - goto out; - } - - /* Non-pure-directory nodes contain data. */ - dataa = a->read(ah, nodename, &lena); - if (!dataa && errno != EISDIR) { - *fail = a; - goto out; - } - datab = b->read(bh, nodename, &lenb); - if (!datab && errno != EISDIR) { - *fail = b; - goto out; - } - - if (dataa) { - if (!datab) - goto out; - if (lena != lenb) - goto out; - - if (memcmp(dataa, datab, lena) != 0) - goto out; - } else - if (datab) - goto out; - - /* Everything is a directory. */ - dira = a->dir(ah, nodename, &numa); - if (!dira) { - *fail = a; - goto out; - } - dirb = b->dir(bh, nodename, &numb); - if (!dirb) { - *fail = b; - goto out; - } - if (numa != numb) - goto out; - sort_dir(dira, numa); - sort_dir(dirb, numb); - for (i = 0; i < numa; i++) { - char subnode[strlen(node) + 1 + strlen(dira[i]) + 1]; - - if (!streq(dira[i], dirb[i])) - goto out; - - strcpy(subnode, node); - if (!streq(node, "/")) - strcat(subnode, "/"); - strcat(subnode, dira[i]); - if (!ops_equal(a, ah, b, bh, subnode, fail)) - goto out; - } - - ret = true; -out: - free(permsa); - free(permsb); - free(dataa); - free(datab); - free(dira); - free(dirb); - talloc_free(nodename); - return ret; -} - -struct diff_data -{ - unsigned int seed; - bool print_progress; - bool fast; - const char *dir; -}; - -/* Differential: try both file and xs backend, watch for differences. */ -static unsigned int try_diff(const bool *trymap, - unsigned int number, - bool verbose, - void *_data) -{ - void *fileh, *xsh; - bool transact = false; - struct ops *fail; - struct diff_data *data = _data; - unsigned int i, print; - - cleanup(data->dir); - setup(data->dir); - - fileh = file_handle(data->dir); - xsh = xs_handle(data->dir); - - print = number / 76; - if (!print) - print = 1; - - for (i = 0; i < number; i++) { - char *file, *xs; - - if (data->print_progress) { - if (i % print == 0) { - printf("."); - fflush(stdout); - } - } - if (trymap && !trymap[i]) - continue; - - if (verbose) - printf("FILE: "); - - file = do_next_op(&file_ops, fileh, i+data->seed, verbose); - if (verbose) - printf("-> %.*s\n", - (int)(strchr(file, '/') - file), file); - - if (verbose) - printf("XS: "); - xs = do_next_op(&xs_ops, xsh, i+data->seed, verbose); - if (verbose) - printf("-> %.*s\n", (int)(strchr(xs, '/') - xs), xs); - - if (!streq(file, xs)) - goto out; - - if (strstarts(file, "OK:START-TRANSACT:")) - transact = true; - else if (streq(file, "OK:STOP-TRANSACT")) - transact = false; - - talloc_free(file); - talloc_free(xs); - - if (data->fast) - continue; - - fail = NULL; - if (!ops_equal(&xs_ops, xsh, &file_ops, fileh, "/", &fail)) { - if (fail) - barf("%s failed during test\n", fail->name); - if (verbose) - printf("Trees differ:\nXS:%s\nFILE%s\n", - dump(&xs_ops, xsh), - dump(&file_ops, fileh)); - goto out; - } - - if (transact) { - void *fileh_pre = file_handle(data->dir); - void *xsh_pre = xs_handle(data->dir); - - fail = NULL; - if (!ops_equal(&xs_ops, xsh_pre, &file_ops, fileh_pre, - "/", &fail)) { - if (fail) - barf("%s failed during transact\n", - fail->name); - - xs_daemon_close(xsh_pre); - talloc_free(fileh_pre); - goto out; - } - xs_daemon_close(xsh_pre); - talloc_free(fileh_pre); - } - } - - fail = NULL; - if (data->fast) - if (!ops_equal(&xs_ops, xsh, &file_ops, fileh, "/", &fail)) - barf("Final result not the same: try without --fast"); -out: - file_ops.close(fileh); - xs_ops.close(xsh); - return i; -} - -/* Differential random test: compare results against file backend. */ -static void diff_test(const char *dir, - unsigned int iters, unsigned int seed, bool fast, - bool verbose) -{ - struct diff_data data; - unsigned int try; - - data.seed = seed; - data.print_progress = !verbose; - data.fast = fast; - data.dir = dir; - - try = try_diff(NULL, iters, verbose, &data); - if (try == iters) { - cleanup_xs_ops(); - exit(0); - } - printf("Failed on iteration %u of seed %u\n", try + 1, seed); - data.print_progress = false; - reduce_problem(try + 1, try_diff, &data); -} - -struct fail_data -{ - unsigned int seed; - bool print_progress; - const char *dir; -}; - -/* Try xs with inserted failures: every op should either succeed or fail. */ -static unsigned int try_fail(const bool *trymap, - unsigned int number, - bool verbose, - void *_data) -{ - unsigned int i, print, tried = 0, aborted = 0; - struct fail_data *data = _data; - struct xs_handle *tmpxsh; - struct file_ops_info *tmpfileh; - void *fileh, *xsh; - struct ops *fail; - char seed[20]; - - /* Make sure failures off to shut down. */ - if (daemon_pid) - kill(daemon_pid, SIGUSR1); - cleanup(data->dir); - setup(data->dir); - - fileh = file_handle(data->dir); - xsh = xs_handle(data->dir); - - print = number / 76; - if (!print) - print = 1; - - for (i = 0; i < number; i++) { - unsigned int limit, failed; - char *ret; - - /* A few times we fail due to other end OOM. */ - limit = 0; - while (!xsh) { - xsh = xs_handle(data->dir); - if (!xsh && errno == ECONNREFUSED) { - if (verbose) - printf("Daemon refused connection\n"); - goto out; - } - if (!xsh && limit++ == 5) { - printf("Daemon failed conn 5 times\n"); - goto out; - } - } - - if (data->print_progress) { - if (i % print == 0) { - printf("."); - fflush(stdout); - } - } - if (trymap && !trymap[i]) - continue; - - /* Turn on failure. */ - sprintf(seed, "%i", data->seed + i); - free(xs_debug_command(xsh, "failtest",seed,strlen(seed)+1)); - - if (verbose) - printf("(%i) seed %s ", i, seed); - ret = do_next_op(&xs_ops, xsh, i + data->seed, verbose); - if (streq(ret, "FAILED:Connection reset by peer") - || streq(ret, "FAILED:Bad file descriptor") - || streq(ret, "FAILED:Broken pipe")) { - xs_close(xsh); - xsh = NULL; - failed = 2; - } else if (strstarts(ret, "OK")) - failed = 0; - else - failed = 1; - - tried++; - if (xsh) - aborted++; - - if (verbose) - printf("-> %.*s\n", - (int)(strchr(ret, '\n') - ret), ret); - - talloc_free(ret); - - /* Turn off failures using signal. */ - if (kill(daemon_pid, SIGUSR1) != 0) { - if (verbose) - printf("Failed to signal daemon\n"); - goto out; - } - - if (failed == 0) { - /* Succeeded? Do same thing to file backend - * to compare */ - try_applying: - ret = do_next_op(&file_ops, fileh, i + data->seed, - false); - if (!strstarts(ret, "OK")) { - if (!verbose) - printf("File op failed on %i\n", - i + data->seed); - talloc_free(ret); - goto out; - } - talloc_free(ret); - } - - tmpxsh = xs_handle(data->dir); - if (!tmpxsh) { - if (verbose) - printf("Failed to open signalled daemon"); - goto out; - } - tmpfileh = file_handle(data->dir); - - fail = NULL; - if (!ops_equal(&xs_ops, tmpxsh, &file_ops, tmpfileh, "/", - &fail)) { - if (fail) { - if (verbose) - printf("%s failed\n", fail->name); - goto out; - } - /* Maybe op succeeded: try comparing after local op? */ - if (failed == 2) { - failed = 0; - if (verbose) - printf("(Looks like it succeeded)\n"); - xs_close(tmpxsh); - file_close(tmpfileh); - goto try_applying; - } - if (verbose) - printf("Trees differ:\nXS:%s\nFILE:%s\n", - dump(&xs_ops, tmpxsh), - dump(&file_ops, tmpfileh)); - xs_close(tmpxsh); - file_close(tmpfileh); - goto out; - } - - /* If we lost the xs handle, that ended the transaction */ - if (!xsh) - file_transaction_end(fileh, true); - - xs_close(tmpxsh); - file_close(tmpfileh); - } -out: - if (xsh) - xs_close(xsh); - return i; -} - -static void fail_test(const char *dir, - unsigned int iters, unsigned int seed, - bool fast __attribute__((unused)), bool verbose) -{ - struct fail_data data; - unsigned int try; - - data.seed = seed; - data.print_progress = !verbose; - data.dir = dir; - - try = try_fail(NULL, iters, verbose, &data); - if (try == iters) { - cleanup_xs_ops(); - exit(0); - } - printf("Failed on iteration %u of seed %u\n", try + 1, seed); - fflush(stdout); - data.print_progress = false; - reduce_problem(try + 1, try_fail, &data); -} - -int main(int argc, char *argv[]) -{ - bool verbose = false; - bool simple = false; - bool fast = false; - bool fail = false; - - if (argv[1] && streq(argv[1], "--fail")) { - fail = true; - argv++; - argc--; - } - - if (argv[1] && streq(argv[1], "--simple")) { - simple = true; - argv++; - argc--; - } - - if (argv[1] && streq(argv[1], "--fast")) { - fast = true; - argv++; - argc--; - } - - if (argv[1] && streq(argv[1], "--verbose")) { - verbose = true; - argv++; - argc--; - } - - if (argc != 4) - barf("Usage: xs_random [--fail|--simple] [--fast] [--verbose] <directory> <iterations> <seed>"); - - talloc_enable_null_tracking(); - - if (fail) - fail_test(argv[1], atoi(argv[2]), atoi(argv[3]), fast, verbose); - else if (simple) - simple_test(argv[1], atoi(argv[2]), atoi(argv[3]), fast, verbose); - else - diff_test(argv[1], atoi(argv[2]), atoi(argv[3]), fast, verbose); - exit(2); -} diff -r 0528bc25c404 -r eb71f258e855 tools/xenstore/xs_stress.c --- a/tools/xenstore/xs_stress.c Tue Jul 03 15:49:16 2007 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,207 +0,0 @@ -/* Stress test for Xen Store: multiple people hammering transactions */ -#include "xs.h" -#include "utils.h" -#include <stdlib.h> -#include <stdio.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> -#include <errno.h> - -#define NUM_HANDLES 2 -#define DIR_FANOUT 3 -#define DIR_DEPTH 3 - -/* How often to print progress */ -static int print; - -/* Layout looks like /<num>/<num>/count. */ -static void work(unsigned int cycles, unsigned int childnum) -{ - unsigned int i; - struct xs_handle *handles[NUM_HANDLES]; - char id; - - if (childnum < 10) - id = '0' + childnum; - else - id = 'A' + childnum - 10; - - for (i = 0; i < NUM_HANDLES; i++) { - handles[i] = xs_daemon_open(); - if (!handles[i]) - barf_perror("Opening handle %i", i); - } - - srandom(childnum); - for (i = 0; i < cycles; i++) { - unsigned int j, len; - char file[100] = ""; - char *contents, tmp[100]; - struct xs_handle *h = handles[random() % NUM_HANDLES]; - - for (j = 0; j < DIR_DEPTH; j++) - sprintf(file + strlen(file), "/%li", - random()%DIR_FANOUT); - - if (!xs_transaction_start(h)) - barf_perror("%i: starting transaction %i", - childnum, i); - - sprintf(file + strlen(file), "/count"); - contents = xs_read(h, file, &len); - if (!contents) - barf_perror("%i: can't read %s iter %i", - childnum, file, i); - sprintf(tmp, "%i", atoi(contents) + 1); - if (!xs_write(h, file, tmp, strlen(tmp)+1)) - barf_perror("%i: can't write %s iter %i", - childnum, file, i); - - /* Abandon 1 in 10 */ - if (random() % 10 == 0) { - if (!xs_transaction_end(h, true)) - barf_perror("%i: can't abort transact", - childnum); - i--; - } else { - if (!xs_transaction_end(h, false)) { - if (errno == EAGAIN) { - write(STDOUT_FILENO, "!", 1); - i--; - } else - barf_perror("%i: can't commit trans", - childnum); - } else { - /* Offset when we print . so kids don't all - * print at once. */ - if ((i + print/(childnum+1)) % print == 0) - write(STDOUT_FILENO, &id, 1); - } - } - } -} - -static void create_dirs(struct xs_handle *h, const char *base, int togo) -{ - unsigned int i; - char filename[100]; - - if (togo == 0) { - sprintf(filename, "%s/count", base); - if (!xs_write(h, filename, "0", 1)) - barf_perror("Writing to %s", filename); - return; - } - - for (i = 0; i < DIR_FANOUT; i++) { - sprintf(filename, "%s/%i", base, i); - if (!xs_mkdir(h, filename)) - barf_perror("xs_mkdir %s", filename); - create_dirs(h, filename, togo-1); - } -} - -static unsigned int add_count(struct xs_handle *h, const char *base, int togo) -{ - unsigned int i, count; - char filename[100]; - - if (togo == 0) { - char *answer; - unsigned int len; - - sprintf(filename, "%s/count", base); - answer = xs_read(h, filename, &len); - if (!answer) - barf_perror("Reading %s", filename); - count = atoi(answer); - free(answer); - return count; - } - - count = 0; - for (i = 0; i < DIR_FANOUT; i++) { - sprintf(filename, "%s/%i", base, i); - count += add_count(h, filename, togo-1); - } - return count; -} - -static void setup(void) -{ - struct xs_handle *h; - - /* Do setup. */ - h = xs_daemon_open(); - if (!h) - barf_perror("Contacting daemon"); - create_dirs(h, "", DIR_DEPTH); - xs_daemon_close(h); -} - -static unsigned int tally_counts(void) -{ - struct xs_handle *h; - unsigned int ret; - - h = xs_daemon_open(); - if (!h) - barf_perror("Contacting daemon"); - - ret = add_count(h, "", DIR_DEPTH); - xs_daemon_close(h); - return ret; -} - -int main(int argc, char *argv[]) -{ - unsigned int i; - bool failed = false; - int kids[10]; - - if (argc != 2) - barf("Usage: xs_stress <iterations>"); - - printf("Setting up directories...\n"); - setup(); - - print = atoi(argv[1]) / 76; - if (!print) - print = 1; - - printf("Running %i children...\n", ARRAY_SIZE(kids)); - for (i = 0; i < ARRAY_SIZE(kids); i++) { - kids[i] = fork(); - if (kids[i] == -1) - barf_perror("fork"); - if (kids[i] == 0) { - work(atoi(argv[1]) / ARRAY_SIZE(kids), i); - exit(0); - } - } - - for (i = 0; i < ARRAY_SIZE(kids); i++) { - int status; - if (waitpid(kids[i], &status, 0) == -1) - barf_perror("waitpid"); - if (!WIFEXITED(status)) - barf("Kid %i died via signal %i\n", - i, WTERMSIG(status)); - if (WEXITSTATUS(status) != 0) { - printf("Child %i exited %i\n", i, WEXITSTATUS(status)); - failed = true; - } - } - if (failed) - exit(1); - - printf("\nCounting results...\n"); - i = tally_counts(); - if (i != (unsigned)atoi(argv[1])) - barf("Total counts %i not %s", i, argv[1]); - printf("Success!\n"); - exit(0); -} diff -r 0528bc25c404 -r eb71f258e855 tools/xenstore/xs_test.c --- a/tools/xenstore/xs_test.c Tue Jul 03 15:49:16 2007 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,812 +0,0 @@ -/* - Xen Store Daemon Test tool - 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 -*/ - -#define _GNU_SOURCE -#include <stdio.h> -#include <stdlib.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <signal.h> -#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 "utils.h" -#include "xs_lib.h" -#include "xs.h" -#include "list.h" - -#define XSTEST - -static struct xs_handle *handles[10] = { NULL }; -static xs_transaction_t txh[10] = { XBT_NULL }; - -static unsigned int timeout_ms = 500; -static bool timeout_suppressed = true; -static bool readonly = false; -static bool print_input = false; -static unsigned int linenum = 0; - -static int daemon_pid; -static struct xenstore_domain_interface *interface; - -/* FIXME: Mark connection as broken (close it?) when this happens. */ -static bool check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod) -{ - return ((prod - cons) <= XENSTORE_RING_SIZE); -} - -static void *get_output_chunk(XENSTORE_RING_IDX cons, - XENSTORE_RING_IDX prod, - char *buf, uint32_t *len) -{ - *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod); - if ((XENSTORE_RING_SIZE - (prod - cons)) < *len) - *len = XENSTORE_RING_SIZE - (prod - cons); - return buf + MASK_XENSTORE_IDX(prod); -} - -static const void *get_input_chunk(XENSTORE_RING_IDX cons, - XENSTORE_RING_IDX prod, - const char *buf, uint32_t *len) -{ - *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons); - if ((prod - cons) < *len) - *len = prod - cons; - return buf + MASK_XENSTORE_IDX(cons); -} - -/* FIXME: We spin, and we're sloppy. */ -static bool read_all_shmem(int fd __attribute__((unused)), - void *data, unsigned int len) -{ - unsigned int avail; - struct xenstore_domain_interface *intf = interface; - XENSTORE_RING_IDX cons, prod; - const void *src; - - while (len) { - cons = intf->rsp_cons; - prod = intf->rsp_prod; - if (!check_indexes(cons, prod)) - barf("Corrupt buffer"); - - src = get_input_chunk(cons, prod, intf->rsp, &avail); - if (avail > len) - avail = len; - memcpy(data, src, avail); - data += avail; - len -= avail; - intf->rsp_cons += avail; - } - - /* Tell other end we read something. */ - kill(daemon_pid, SIGUSR2); - - return true; -} - -static bool write_all_shmem(int fd __attribute__((unused)), - const void *data, unsigned int len) -{ - uint32_t avail; - struct xenstore_domain_interface *intf = interface; - XENSTORE_RING_IDX cons, prod; - void *dst; - - while (len) { - cons = intf->req_cons; - prod = intf->req_prod; - if (!check_indexes(cons, prod)) - barf("Corrupt buffer"); - - dst = get_output_chunk(cons, prod, intf->req, &avail); - if (avail > len) - avail = len; - memcpy(dst, data, avail); - data += avail; - len -= avail; - intf->req_prod += avail; - } - - /* Tell other end we wrote something. */ - kill(daemon_pid, SIGUSR2); - - return true; -} - -static bool read_all(int fd, void *data, unsigned int len); -static bool read_all_choice(int fd, void *data, unsigned int len) -{ - if (fd == -2) - return read_all_shmem(fd, data, len); - return read_all(fd, data, len); -} - -static bool write_all_choice(int fd, const void *data, unsigned int len) -{ - if (fd == -2) - return write_all_shmem(fd, data, len); - return xs_write_all(fd, data, len); -} - -/* We want access to internal functions. */ -#include "xs.c" - -static void __attribute__((noreturn)) usage(void) -{ - barf("Usage:\n" - " xs_test [--readonly] [--no-timeout] [-x]\n" - "Reads commands from stdin, one per line:" - " dir <path>\n" - " read <path>\n" - " write <path> <value>...\n" - " setid <id>\n" - " mkdir <path>\n" - " rm <path>\n" - " getperm <path>\n" - " setperm <path> <id> <flags> ...\n" - " watch <path> <token>\n" - " watchnoack <path> <token>\n" - " waitwatch\n" - " unwatch <path> <token>\n" - " close\n" - " start <node>\n" - " abort\n" - " introduce <domid> <mfn> <eventchn> <path>\n" - " commit\n" - " sleep <milliseconds>\n" - " expect <pattern>\n" - " notimeout\n" - " readonly\n" - " readwrite\n" - " dump\n"); -} - -static int argpos(const char *line, unsigned int num) -{ - unsigned int i, len = 0, off = 0; - - for (i = 0; i <= num; i++) { - off += len; - off += strspn(line + off, " \t\n"); - len = strcspn(line + off, " \t\n"); - if (!len) - return off; - } - return off; -} - -static char *arg(const char *line, unsigned int num) -{ - static char *args[10]; - unsigned int off, len; - - off = argpos(line, num); - len = strcspn(line + off, " \t\n"); - - if (!len) - barf("Can't get arg %u", num); - - free(args[num]); - args[num] = malloc(len + 1); - memcpy(args[num], line+off, len); - args[num][len] = '\0'; - return args[num]; -} - -struct expect -{ - struct list_head list; - char *pattern; -}; -static LIST_HEAD(expects); - -static char *command; - -/* Trim leading and trailing whitespace */ -static void trim(char *str) -{ - while (isspace(str[0])) - memmove(str, str+1, strlen(str)); - - while (strlen(str) && isspace(str[strlen(str)-1])) - str[strlen(str)-1] = '\0'; -} - -static void output(const char *fmt, ...) -{ - char *str; - struct expect *i; - va_list arglist; - - va_start(arglist, fmt); - vasprintf(&str, fmt, arglist); - va_end(arglist); - - printf("%s", str); - fflush(stdout); - trim(str); - list_for_each_entry(i, &expects, list) { - if (fnmatch(i->pattern, str, 0) == 0) { - list_del(&i->list); - free(i); - return; - } - } - barf("Unexpected output %s\n", str); -} - -static void failed(int handle) -{ - if (handle) - output("%i: %s failed: %s\n", - handle, command, strerror(errno)); - else - output("%s failed: %s\n", command, strerror(errno)); -} - -static void expect(const char *line) -{ - struct expect *e = malloc(sizeof(*e)); - - e->pattern = strdup(line + argpos(line, 1)); - trim(e->pattern); - list_add(&e->list, &expects); -} - -static void do_dir(unsigned int handle, char *path) -{ - char **entries; - unsigned int i, num; - - entries = xs_directory(handles[handle], txh[handle], path, &num); - if (!entries) { - failed(handle); - return; - } - - for (i = 0; i < num; i++) - if (handle) - output("%i:%s\n", handle, entries[i]); - else - output("%s\n", entries[i]); - free(entries); -} - -static void do_read(unsigned int handle, char *path) -{ - char *value; - unsigned int len; - - value = xs_read(handles[handle], txh[handle], path, &len); - if (!value) { - failed(handle); - return; - } - - /* It's supposed to nul terminate for us. */ - assert(value[len] == '\0'); - if (handle) - output("%i:%.*s\n", handle, len, value); - else - output("%.*s\n", len, value); -} - -static void do_write(unsigned int handle, char *path, char *data) -{ - if (!xs_write(handles[handle], txh[handle], path, data, strlen(data))) - failed(handle); -} - -static void do_setid(unsigned int handle, char *id) -{ - if (!xs_bool(xs_debug_command(handles[handle], "setid", id, - strlen(id)+1))) - failed(handle); -} - -static void do_mkdir(unsigned int handle, char *path) -{ - if (!xs_mkdir(handles[handle], txh[handle], path)) - failed(handle); -} - -static void do_rm(unsigned int handle, char *path) -{ - if (!xs_rm(handles[handle], txh[handle], path)) - failed(handle); -} - -static void do_getperm(unsigned int handle, char *path) -{ - unsigned int i, num; - struct xs_permissions *perms; - - perms = xs_get_permissions(handles[handle], txh[handle], path, &num); - if (!perms) { - failed(handle); - return; - } - - for (i = 0; i < num; i++) { - char *permstring; - - switch (perms[i].perms) { - case XS_PERM_NONE: - permstring = "NONE"; - break; - case XS_PERM_WRITE: - permstring = "WRITE"; - break; - case XS_PERM_READ: - permstring = "READ"; - break; - case XS_PERM_READ|XS_PERM_WRITE: - permstring = "READ/WRITE"; - break; - default: - barf("bad perm value %i", perms[i].perms); - } - - if (handle) - output("%i:%i %s\n", handle, perms[i].id, permstring); - else - output("%i %s\n", perms[i].id, permstring); - } - free(perms); -} - -static void do_setperm(unsigned int handle, char *path, char *line) -{ - unsigned int i; - struct xs_permissions perms[100]; - - strtok(line, " \t\n"); - strtok(NULL, " \t\n"); - for (i = 0; ; i++) { - char *arg = strtok(NULL, " \t\n"); - if (!arg) - break; - perms[i].id = atoi(arg); - arg = strtok(NULL, " \t\n"); - if (!arg) - break; - if (streq(arg, "WRITE")) - perms[i].perms = XS_PERM_WRITE; - else if (streq(arg, "READ")) - perms[i].perms = XS_PERM_READ; - else if (streq(arg, "READ/WRITE")) - perms[i].perms = XS_PERM_READ|XS_PERM_WRITE; - else if (streq(arg, "NONE")) - perms[i].perms = XS_PERM_NONE; - else - barf("bad flags %s\n", arg); - } - - if (!xs_set_permissions(handles[handle], txh[handle], path, perms, i)) - failed(handle); -} - -static void do_watch(unsigned int handle, const char *node, const char *token, - bool swallow_event) -{ - if (!xs_watch(handles[handle], node, token)) - failed(handle); - - /* Convenient for testing... */ - if (swallow_event) { - unsigned int num; - char **vec = xs_read_watch(handles[handle], &num); - if (!vec || - !streq(vec[XS_WATCH_PATH], node) || - !streq(vec[XS_WATCH_TOKEN], token)) - 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; - struct timeval tv = {.tv_sec = timeout_ms/1000, - .tv_usec = (timeout_ms*1000)%1000000 }; - fd_set set; - unsigned int num; - - 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], &num); - if (!vec) { - failed(handle); - return; - } - - if (handle) - output("%i:%s:%s\n", handle, - vec[XS_WATCH_PATH], vec[XS_WATCH_TOKEN]); - else - output("%s:%s\n", vec[XS_WATCH_PATH], vec[XS_WATCH_TOKEN]); - free(vec); -} - -static void do_unwatch(unsigned int handle, const char *node, const char *token) -{ - if (!xs_unwatch(handles[handle], node, token)) - failed(handle); -} - -static void do_start(unsigned int handle) -{ - txh[handle] = xs_transaction_start(handles[handle]); - if (txh[handle] == XBT_NULL) - failed(handle); -} - -static void do_end(unsigned int handle, bool abort) -{ - if (!xs_transaction_end(handles[handle], txh[handle], abort)) - failed(handle); - txh[handle] = XBT_NULL; -} - -static void do_introduce(unsigned int handle, - const char *domid, - const char *mfn, - const char *eventchn, - const char *path) -{ - 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); - for (i = 0; i < ARRAY_SIZE(handles); i++) - if (!handles[i]) - break; - - fd = open("/tmp/xcmap", O_RDWR); - /* Set shared comms page. */ - interface = mmap(NULL, getpagesize(), PROT_WRITE|PROT_READ, - MAP_SHARED,fd,0); - if (interface == MAP_FAILED) - barf_perror("Failed to map /tmp/xcmap page"); - close(fd); - - /* Tell them the event channel and our PID. */ - *(int *)((void *)interface + 32) = getpid(); - *(uint16_t *)((void *)interface + 36) = atoi(eventchn); - - if (!xs_introduce_domain(handles[handle], atoi(domid), - atol(mfn), atoi(eventchn))) { - failed(handle); - munmap(interface, getpagesize()); - return; - } - output("handle is %i\n", i); - - /* Create new handle. */ - handles[i] = new(struct xs_handle); - handles[i]->fd = -2; - - /* Read in daemon pid. */ - daemon_pid = *(int *)((void *)interface + 32); -} - -static void do_release(unsigned int handle, const char *domid) -{ - if (!xs_release_domain(handles[handle], atoi(domid))) - failed(handle); -} - -static int strptrcmp(const void *a, const void *b) -{ - return strcmp(*(char **)a, *(char **)b); -} - -static void sort_dir(char **dir, unsigned int num) -{ - qsort(dir, num, sizeof(char *), strptrcmp); -} - -static void dump_dir(unsigned int handle, - const char *node, - char **dir, - unsigned int numdirs, - unsigned int depth) -{ - unsigned int i; - char spacing[depth+1]; - - memset(spacing, ' ', depth); - spacing[depth] = '\0'; - - sort_dir(dir, numdirs); - - for (i = 0; i < numdirs; i++) { - struct xs_permissions *perms; - unsigned int j, numperms; - unsigned int len; - char *contents; - unsigned int subnum; - char **subdirs; - char subnode[strlen(node) + 1 + strlen(dir[i]) + 1]; - - sprintf(subnode, "%s/%s", node, dir[i]); - - perms = xs_get_permissions(handles[handle], txh[handle], - subnode,&numperms); - if (!perms) { - failed(handle); - return; - } - - output("%s%s: ", spacing, dir[i]); - for (j = 0; j < numperms; j++) { - char buffer[100]; - if (!xs_perm_to_string(&perms[j], buffer)) - barf("perm to string"); - output("%s ", buffer); - } - free(perms); - output("\n"); - - /* Even directories can have contents. */ - contents = xs_read(handles[handle], txh[handle], - subnode, &len); - if (!contents) { - if (errno != EISDIR) - failed(handle); - } else { - output(" %s(%.*s)\n", spacing, len, contents); - free(contents); - } - - /* Every node is a directory. */ - subdirs = xs_directory(handles[handle], txh[handle], - subnode, &subnum); - if (!subdirs) { - failed(handle); - return; - } - dump_dir(handle, subnode, subdirs, subnum, depth+1); - free(subdirs); - } -} - -static void dump(int handle) -{ - char **subdirs; - unsigned int subnum; - - subdirs = xs_directory(handles[handle], txh[handle], "/", &subnum); - if (!subdirs) { - failed(handle); - return; - } - - dump_dir(handle, "", subdirs, subnum, 0); - free(subdirs); -} - -static int handle; - -static void alarmed(int sig __attribute__((unused))) -{ - if (handle) { - char handlename[10]; - sprintf(handlename, "%u:", handle); - write(STDOUT_FILENO, handlename, strlen(handlename)); - } - write(STDOUT_FILENO, command, strlen(command)); - write(STDOUT_FILENO, " timeout\n", strlen(" timeout\n")); - exit(1); -} - -static void do_command(unsigned int default_handle, char *line) -{ - char *endp; - - if (print_input) - printf("%i> %s", ++linenum, line); - - if (strspn(line, " \n") == strlen(line)) - return; - if (strstarts(line, "#")) - return; - - handle = strtoul(line, &endp, 10); - if (endp != line) - memmove(line, endp+1, strlen(endp)); - else - handle = default_handle; - - command = arg(line, 0); - if (!handles[handle]) { - if (readonly) - handles[handle] = xs_daemon_open_readonly(); - else - handles[handle] = xs_daemon_open(); - if (!handles[handle]) - barf_perror("Opening connection to daemon"); - } - - if (!timeout_suppressed) - set_timeout(); - timeout_suppressed = false; - - if (streq(command, "dir")) - do_dir(handle, arg(line, 1)); - else if (streq(command, "read")) - do_read(handle, arg(line, 1)); - else if (streq(command, "write")) - do_write(handle, arg(line, 1), arg(line, 2)); - else if (streq(command, "setid")) - do_setid(handle, arg(line, 1)); - else if (streq(command, "mkdir")) - do_mkdir(handle, arg(line, 1)); - else if (streq(command, "rm")) - do_rm(handle, arg(line, 1)); - else if (streq(command, "getperm")) - do_getperm(handle, arg(line, 1)); - else if (streq(command, "setperm")) - do_setperm(handle, arg(line, 1), line); - else if (streq(command, "watch")) - do_watch(handle, arg(line, 1), arg(line, 2), true); - else if (streq(command, "watchnoack")) - do_watch(handle, arg(line, 1), arg(line, 2), false); - else if (streq(command, "waitwatch")) - do_waitwatch(handle); - else if (streq(command, "unwatch")) - do_unwatch(handle, arg(line, 1), arg(line, 2)); - else if (streq(command, "close")) { - xs_daemon_close(handles[handle]); - handles[handle] = NULL; - txh[handle] = XBT_NULL; - } else if (streq(command, "start")) - do_start(handle); - else if (streq(command, "commit")) - do_end(handle, false); - else if (streq(command, "abort")) - do_end(handle, true); - else if (streq(command, "introduce")) - do_introduce(handle, arg(line, 1), arg(line, 2), - arg(line, 3), arg(line, 4)); - else if (streq(command, "release")) - do_release(handle, arg(line, 1)); - else if (streq(command, "dump")) - dump(handle); - else if (streq(command, "sleep")) { - disarm_timeout(); - usleep(atoi(arg(line, 1)) * 1000); - } else if (streq(command, "expect")) - expect(line); - else if (streq(command, "notimeout")) - timeout_suppressed = true; - else if (streq(command, "readonly")) { - readonly = true; - xs_daemon_close(handles[handle]); - handles[handle] = NULL; - } else if (streq(command, "readwrite")) { - readonly = false; - xs_daemon_close(handles[handle]); - handles[handle] = NULL; - } else - barf("Unknown command %s", command); - fflush(stdout); - disarm_timeout(); - - /* Check expectations. */ - if (!streq(command, "expect")) { - struct expect *i = list_top(&expects, struct expect, list); - - if (i) - barf("Expected '%s', didn't happen\n", i->pattern); - } -} - -static struct option options[] = { { "readonly", 0, NULL, 'r' }, - { "no-timeout", 0, NULL, 't' }, - { NULL, 0, NULL, 0 } }; - -int main(int argc, char *argv[]) -{ - int opt; - char line[1024]; - - while ((opt = getopt_long(argc, argv, "xrt", options, NULL)) != -1) { - switch (opt) { - case 'r': - readonly = true; - break; - case 't': - timeout_ms = 0; - break; - case 'x': - print_input = true; - break; - } - } - - if (optind + 1 == argc) { - int fd = open(argv[optind], O_RDONLY); - if (!fd) - barf_perror("Opening %s", argv[optind]); - dup2(fd, STDIN_FILENO); - } else if (optind != argc) - usage(); - - - signal(SIGALRM, alarmed); - while (fgets(line, sizeof(line), stdin)) - do_command(0, line); - - return 0; -} - -/* - * Local variables: - * c-file-style: "linux" - * indent-tabs-mode: t - * c-indent-level: 8 - * c-basic-offset: 8 - * tab-width: 8 - * End: - */ _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |