ia64/xen-unstable
changeset 5357:9ea2524b7d10
bitkeeper revision 1.1662.1.15 (42a5968eiZE_DjdIFPjxvzLw6ACvCQ)
Add xenstore daemon and library.
Makefile:
Add xenstore subdirectory.
Remove xs_stress on clean.
Many files:
new file
ignore:
Update ignore list for xenstore.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> (authored)
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
Add xenstore daemon and library.
Makefile:
Add xenstore subdirectory.
Remove xs_stress on clean.
Many files:
new file
ignore:
Update ignore list for xenstore.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> (authored)
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
line diff
1.1 --- a/.rootkeys Mon Jun 06 20:28:33 2005 +0000 1.2 +++ b/.rootkeys Tue Jun 07 12:43:58 2005 +0000 1.3 @@ -996,6 +996,43 @@ 41d58ba6ijEF6fedqRO5vFu7uCirZg tools/xcs 1.4 4292540couq-V0TPwyQ6bspNEWNcvw tools/xcutils/Makefile 1.5 42925407VysDb9O06OK_RUzTZxfLoA tools/xcutils/xc_restore.c 1.6 42936745WTLYamYsmXm_JGJ72JX-_Q tools/xcutils/xc_save.c 1.7 +42a57d97mxMTlPnxBKep6R4ViI5rjg tools/xenstore/.gdbinit 1.8 +42a57d97ZEoHuhMAFTuBMlLzA9v_ng tools/xenstore/Makefile 1.9 +42a57d97ccA4uY-RxONvIH0P8U0gqg tools/xenstore/TODO 1.10 +42a57d972RzmyLgsoH9b8qqk-UjcCA tools/xenstore/fake_libxc.c 1.11 +42a57d97IjoPvbIVc4BUzwoKyM0VSw tools/xenstore/list.h 1.12 +42a57d97fKgtf0HQLiQkAkVsOvuSyA tools/xenstore/talloc.c 1.13 +42a57d98U3p0XP6xzCybTuaVQscUdw tools/xenstore/talloc.h 1.14 +42a57d98LFN6Mug-uR4xgAxCE7lwUg tools/xenstore/talloc_guide.txt 1.15 +42a57d98S69vKJYwO_WUjoFQZ6KzQg tools/xenstore/testsuite/01simple.sh 1.16 +42a57d98BHcFpZz_fXHweylUEUU97Q tools/xenstore/testsuite/02directory.sh 1.17 +42a57d98ua4Xeb6pmtbFNTAI833dyw tools/xenstore/testsuite/03write.sh 1.18 +42a57d98nbuCUsVT0RJj1zA1JyMDsw tools/xenstore/testsuite/04rm.sh 1.19 +42a57d98_ULKHP3_uX1PK2nPMTzWSQ tools/xenstore/testsuite/05filepermissions.sh 1.20 +42a57d98YGCLyTDSGmoyFqRqQUlagQ tools/xenstore/testsuite/06dirpermissions.sh 1.21 +42a57d98fdO519YyATk4_Zwr1STNfQ tools/xenstore/testsuite/07watch.sh 1.22 +42a57d98zZUtvirUMjmHxFphJjmO7Q tools/xenstore/testsuite/08transaction.sh 1.23 +42a57d98sn9RbpBgHRv1D99Kt7LwYA tools/xenstore/testsuite/09domain.sh 1.24 +42a57d98tSuoFCHnnM2GgENXJrRQmw tools/xenstore/testsuite/test.sh 1.25 +42a57d98zxDP2Ti7dTznGROi66rUGw tools/xenstore/utils.c 1.26 +42a57d98SDvOYCEjmCjwHSk6390GLA tools/xenstore/utils.h 1.27 +42a57d98hFKbOY9D0mCE4H4NDoKr1w tools/xenstore/xenstored.h 1.28 +42a57d981KFHLmJ0CjKkn1_gZhYvdw tools/xenstore/xenstored_core.c 1.29 +42a57d98bcgE13vYaFxGTusmWbrFDA tools/xenstore/xenstored_core.h 1.30 +42a57d98cD9wOFyRYfaEP0QgtqL1Xw tools/xenstore/xenstored_domain.c 1.31 +42a57d98noLWvXU8ePbcqvvmu4p2Gw tools/xenstore/xenstored_domain.h 1.32 +42a57d98kxHaQ1ApS7RpqmFoEnDmbg tools/xenstore/xenstored_test.h 1.33 +42a57d981c9P3aFkWtxWEIRUapt_FQ tools/xenstore/xenstored_transaction.c 1.34 +42a57d99pVo__10bbckp_b_rm6i59A tools/xenstore/xenstored_transaction.h 1.35 +42a57d99izTIjWfG-IjQAPqYlDWJNg tools/xenstore/xenstored_watch.c 1.36 +42a57d99-zLxBjzC7rfj_perV-orUg tools/xenstore/xenstored_watch.h 1.37 +42a57d99BnkhISKgCCRcUqhteyuxCw tools/xenstore/xs.c 1.38 +42a57d99FyiYSz9AkKKROrRydnA-gQ tools/xenstore/xs.h 1.39 +42a57d99SrtsJCDUlKyRPf3EX86A1Q tools/xenstore/xs_lib.c 1.40 +42a57d99L2pYeMFyjQ_4Rnb17xTSMg tools/xenstore/xs_lib.h 1.41 +42a57d99Kl6Ba8oCHv2fggl7QN9QZA tools/xenstore/xs_random.c 1.42 +42a57d99SHYR1lQOD0shuErPDg9NKQ tools/xenstore/xs_stress.c 1.43 +42a57d996aBawpkQNOWkNWXD6LrhPg tools/xenstore/xs_test.c 1.44 403a3edbrr8RE34gkbR40zep98SXbg tools/xentrace/Makefile 1.45 40a107afN60pFdURgBv9KwEzgRl5mQ tools/xentrace/formats 1.46 420d52d2_znVbT4JAPIU36vQOme83g tools/xentrace/xenctx.c
2.1 --- a/BitKeeper/etc/ignore Mon Jun 06 20:28:33 2005 +0000 2.2 +++ b/BitKeeper/etc/ignore Tue Jun 07 12:43:58 2005 +0000 2.3 @@ -128,8 +128,13 @@ tools/xcs/xcs 2.4 tools/xcs/xcsdump 2.5 tools/xcutils/xc_restore 2.6 tools/xcutils/xc_save 2.7 +tools/xenstore/testsuite/tmp/* 2.8 +tools/xenstore/xen 2.9 +tools/xenstore/xenstored_test 2.10 +tools/xenstore/xs_random 2.11 +tools/xenstore/xs_stress 2.12 +tools/xenstore/xs_test 2.13 tools/xentrace/xentrace 2.14 -tools/xfrd/xfrd 2.15 xen/BLOG 2.16 xen/TAGS 2.17 xen/arch/x86/asm-offsets.s
3.1 --- a/tools/Makefile Mon Jun 06 20:28:33 2005 +0000 3.2 +++ b/tools/Makefile Tue Jun 07 12:43:58 2005 +0000 3.3 @@ -9,6 +9,7 @@ SUBDIRS += xentrace 3.4 SUBDIRS += python 3.5 SUBDIRS += xcs 3.6 SUBDIRS += xcutils 3.7 +SUBDIRS += xenstore 3.8 SUBDIRS += pygrub 3.9 3.10 .PHONY: all install clean check check_clean ioemu eioemuinstall ioemuclean
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/tools/xenstore/.gdbinit Tue Jun 07 12:43:58 2005 +0000 4.3 @@ -0,0 +1,4 @@ 4.4 +set environment XENSTORED_RUNDIR=testsuite/tmp 4.5 +set environment XENSTORED_ROOTDIR=testsuite/tmp 4.6 +handle SIGUSR1 noprint nostop 4.7 +handle SIGPIPE noprint nostop
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/tools/xenstore/Makefile Tue Jun 07 12:43:58 2005 +0000 5.3 @@ -0,0 +1,97 @@ 5.4 +XEN_ROOT=../.. 5.5 +# This does something wrong to TARGET_ARCH. 5.6 +#include $(XEN_ROOT)/tools/Rules.mk 5.7 +LIBDIR = lib 5.8 +XEN_LIBXC = $(XEN_ROOT)/tools/libxc 5.9 + 5.10 +INSTALL = install 5.11 +INSTALL_DATA = $(INSTALL) -m0644 5.12 +INSTALL_PROG = $(INSTALL) -m0755 5.13 +INSTALL_DIR = $(INSTALL) -d -m0755 5.14 + 5.15 +PROFILE=#-pg 5.16 +BASECFLAGS=-Wall -W -g 5.17 +# Make gcc generate dependencies. 5.18 +BASECFLAGS += -Wp,-MD,.$(@F).d 5.19 +PROG_DEP = .*.d 5.20 +#BASECFLAGS+= -O3 $(PROFILE) 5.21 +#BASECFLAGS+= -I$(XEN_ROOT)/tools 5.22 +BASECFLAGS+= -I$(XEN_ROOT)/tools/libxc 5.23 +BASECFLAGS+= -I$(XEN_ROOT)/xen/include/public 5.24 +BASECFLAGS+= -I. 5.25 + 5.26 +CFLAGS+=$(BASECFLAGS) 5.27 +LDFLAGS=$(PROFILE) -L$(XEN_LIBXC) 5.28 +TESTDIR=`pwd`/testsuite/tmp 5.29 +TESTFLAGS=-DTESTING 5.30 +TESTENV=XENSTORED_ROOTDIR=$(TESTDIR) XENSTORED_RUNDIR=$(TESTDIR) 5.31 + 5.32 +all: xen xenstored libxenstore.a 5.33 + 5.34 +testcode: xen xs_test xenstored_test xs_random 5.35 + 5.36 +xen: 5.37 + ln -sf $(XEN_ROOT)/xen/include/public $@ 5.38 + 5.39 +xenstored: xenstored_core.o xenstored_watch.o xenstored_domain.o xenstored_transaction.o xs_lib.o talloc.o utils.o 5.40 + $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -lxc -o $@ 5.41 + 5.42 +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 5.43 + $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ 5.44 + 5.45 +xs_test: xs_test.o xs_lib.o utils.o 5.46 +xs_random: xs_random.o xs_test_lib.o xs_lib.o talloc.o utils.o 5.47 +xs_stress: xs_stress.o xs_test_lib.o xs_lib.o talloc.o utils.o 5.48 + 5.49 +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: CFLAGS=$(BASECFLAGS) $(TESTFLAGS) 5.50 + 5.51 +xenstored_%_test.o: xenstored_%.c 5.52 + $(COMPILE.c) -o $@ $< 5.53 + 5.54 +xs_test_lib.o: xs.c 5.55 + $(COMPILE.c) -o $@ $< 5.56 + 5.57 +talloc_test.o: talloc.c 5.58 + $(COMPILE.c) -o $@ $< 5.59 + 5.60 +libxenstore.a: libxenstore.a(xs.o) libxenstore.a(xs_lib.o) 5.61 + 5.62 +clean: testsuite-clean 5.63 + rm -f *.o *.a xs_test xenstored xenstored_test xs_random xs_stress xen 5.64 + -$(RM) $(PROG_DEP) 5.65 + 5.66 +check: testsuite-run randomcheck stresstest 5.67 + 5.68 +testsuite-run: xen xenstored_test xs_test 5.69 + $(TESTENV) testsuite/test.sh 5.70 + 5.71 +testsuite-clean: 5.72 + rm -rf $(TESTDIR) 5.73 + 5.74 +# Make this visible so they can see repeat tests without --fast if they 5.75 +# fail. 5.76 +RANDSEED=$(shell date +%s) 5.77 +randomcheck: xs_random xenstored_test 5.78 + $(TESTENV) ./xs_random --simple --fast /tmp/xs_random 200000 $(RANDSEED) 5.79 + $(TESTENV) ./xs_random --fast /tmp/xs_random 100000 $(RANDSEED) 5.80 + $(TESTENV) ./xs_random --fail /tmp/xs_random 10000 $(RANDSEED) 5.81 + 5.82 +stresstest: xs_stress xenstored_test 5.83 + rm -rf $(TESTDIR)/store 5.84 + export $(TESTENV); PID=`./xenstored_test --output-pid`; ./xs_stress 10000; ret=$$?; kill $$PID; exit $$ret 5.85 + 5.86 +TAGS: 5.87 + etags `find . -name '*.[ch]'` 5.88 + 5.89 +tarball: clean 5.90 + cd .. && tar -c -j -v -h -f xenstore.tar.bz2 xenstore/ 5.91 + 5.92 +install: xenstored libxenstore.a 5.93 + $(INSTALL_DIR) -p $(DESTDIR)/var/run/xenstored 5.94 + $(INSTALL_DIR) -p $(DESTDIR)/var/lib/xenstored 5.95 + $(INSTALL_DIR) -p $(DESTDIR)/usr/sbin 5.96 + $(INSTALL_PROG) xenstored $(DESTDIR)/usr/sbin 5.97 + $(INSTALL_DIR) -p $(DESTDIR)/usr/$(LIBDIR) 5.98 + $(INSTALL_DATA) libxenstore.a $(DESTDIR)/usr/$(LIBDIR) 5.99 + 5.100 +-include $(PROG_DEP)
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/tools/xenstore/TODO Tue Jun 07 12:43:58 2005 +0000 6.3 @@ -0,0 +1,7 @@ 6.4 +TODO in no particular order. Some of these will never be done. There 6.5 +are omissions of important but necessary things. It is up to the 6.6 +reader to fill in the blanks. 6.7 + 6.8 +- Remove calls to system() from daemon 6.9 +- Timeout failed watch responses 6.10 +- Timeout blocking transactions
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/tools/xenstore/fake_libxc.c Tue Jun 07 12:43:58 2005 +0000 7.3 @@ -0,0 +1,119 @@ 7.4 +/* 7.5 + Fake libxc which doesn't require hypervisor but talks to xs_test. 7.6 + Copyright (C) 2005 Rusty Russell IBM Corporation 7.7 + 7.8 + This program is free software; you can redistribute it and/or modify 7.9 + it under the terms of the GNU General Public License as published by 7.10 + the Free Software Foundation; either version 2 of the License, or 7.11 + (at your option) any later version. 7.12 + 7.13 + This program is distributed in the hope that it will be useful, 7.14 + but WITHOUT ANY WARRANTY; without even the implied warranty of 7.15 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 7.16 + GNU General Public License for more details. 7.17 + 7.18 + You should have received a copy of the GNU General Public License 7.19 + along with this program; if not, write to the Free Software 7.20 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 7.21 +*/ 7.22 + 7.23 +#include <stdio.h> 7.24 +#include <stdlib.h> 7.25 +#include <sys/types.h> 7.26 +#include <sys/stat.h> 7.27 +#include <fcntl.h> 7.28 +#include <sys/mman.h> 7.29 +#include <unistd.h> 7.30 +#include <assert.h> 7.31 +#include <signal.h> 7.32 +#include "utils.h" 7.33 +#include "xenstored_core.h" 7.34 +#include "xenstored_domain.h" 7.35 +#include "xenstored_test.h" 7.36 + 7.37 +static int sigfd; 7.38 +static int xs_test_pid; 7.39 +static u16 port; 7.40 + 7.41 +/* The event channel maps to a signal, shared page to an mmapped file. */ 7.42 +int xc_evtchn_send(int xc_handle __attribute__((unused)), int local_port) 7.43 +{ 7.44 + assert(local_port == port); 7.45 + if (kill(xs_test_pid, SIGUSR2) != 0) 7.46 + barf_perror("fake event channel failed"); 7.47 + return 0; 7.48 +} 7.49 + 7.50 +void *xc_map_foreign_range(int xc_handle, u32 dom __attribute__((unused)), 7.51 + int size, int prot, 7.52 + unsigned long mfn __attribute__((unused))) 7.53 +{ 7.54 + void *ret; 7.55 + 7.56 + ret = mmap(NULL, size, prot, MAP_SHARED, xc_handle, 0); 7.57 + if (ret == MAP_FAILED) 7.58 + return NULL; 7.59 + 7.60 + /* xs_test tells us pid and port by putting it in buffer, we reply. */ 7.61 + xs_test_pid = *(int *)(ret + 32); 7.62 + port = *(int *)(ret + 36); 7.63 + *(int *)(ret + 32) = getpid(); 7.64 + return ret; 7.65 +} 7.66 + 7.67 +int xc_interface_open(void) 7.68 +{ 7.69 + int fd; 7.70 + char page[getpagesize()]; 7.71 + 7.72 + fd = open("/tmp/xcmap", O_RDWR|O_CREAT|O_TRUNC, 0600); 7.73 + if (fd < 0) 7.74 + return fd; 7.75 + 7.76 + memset(page, 0, sizeof(page)); 7.77 + if (!write_all(fd, page, sizeof(page))) 7.78 + barf_perror("Failed to write /tmp/xcmap page"); 7.79 + 7.80 + return fd; 7.81 +} 7.82 + 7.83 +int xc_interface_close(int xc_handle) 7.84 +{ 7.85 + close(xc_handle); 7.86 + return 0; 7.87 +} 7.88 + 7.89 +static void send_to_fd(int signo __attribute__((unused))) 7.90 +{ 7.91 + int saved_errno = errno; 7.92 + write(sigfd, &port, sizeof(port)); 7.93 + errno = saved_errno; 7.94 +} 7.95 + 7.96 +void fake_block_events(void) 7.97 +{ 7.98 + signal(SIGUSR2, SIG_IGN); 7.99 +} 7.100 + 7.101 +void fake_ack_event(void) 7.102 +{ 7.103 + signal(SIGUSR2, send_to_fd); 7.104 +} 7.105 + 7.106 +int fake_open_eventchn(void) 7.107 +{ 7.108 + int fds[2]; 7.109 + 7.110 + if (pipe(fds) != 0) 7.111 + return -1; 7.112 + 7.113 + if (signal(SIGUSR2, send_to_fd) == SIG_ERR) { 7.114 + int saved_errno = errno; 7.115 + close(fds[0]); 7.116 + close(fds[1]); 7.117 + errno = saved_errno; 7.118 + return -1; 7.119 + } 7.120 + sigfd = fds[1]; 7.121 + return fds[0]; 7.122 +}
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/tools/xenstore/list.h Tue Jun 07 12:43:58 2005 +0000 8.3 @@ -0,0 +1,508 @@ 8.4 +#ifndef _LINUX_LIST_H 8.5 +#define _LINUX_LIST_H 8.6 +/* Taken from Linux kernel code, but de-kernelized for userspace. */ 8.7 +#include <stddef.h> 8.8 + 8.9 +/* 8.10 + * These are non-NULL pointers that will result in page faults 8.11 + * under normal circumstances, used to verify that nobody uses 8.12 + * non-initialized list entries. 8.13 + */ 8.14 +#define LIST_POISON1 ((void *) 0x00100100) 8.15 +#define LIST_POISON2 ((void *) 0x00200200) 8.16 + 8.17 +#define container_of(ptr, type, member) ({ \ 8.18 + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ 8.19 + (type *)( (char *)__mptr - offsetof(type,member) );}) 8.20 + 8.21 +/* 8.22 + * Simple doubly linked list implementation. 8.23 + * 8.24 + * Some of the internal functions ("__xxx") are useful when 8.25 + * manipulating whole lists rather than single entries, as 8.26 + * sometimes we already know the next/prev entries and we can 8.27 + * generate better code by using them directly rather than 8.28 + * using the generic single-entry routines. 8.29 + */ 8.30 + 8.31 +struct list_head { 8.32 + struct list_head *next, *prev; 8.33 +}; 8.34 + 8.35 +#define LIST_HEAD_INIT(name) { &(name), &(name) } 8.36 + 8.37 +#define LIST_HEAD(name) \ 8.38 + struct list_head name = LIST_HEAD_INIT(name) 8.39 + 8.40 +#define INIT_LIST_HEAD(ptr) do { \ 8.41 + (ptr)->next = (ptr); (ptr)->prev = (ptr); \ 8.42 +} while (0) 8.43 + 8.44 +#define list_top(head, type, member) \ 8.45 +({ \ 8.46 + struct list_head *_head = (head); \ 8.47 + list_empty(_head) ? NULL : list_entry(_head->next, type, member); \ 8.48 +}) 8.49 + 8.50 +/* 8.51 + * Insert a new entry between two known consecutive entries. 8.52 + * 8.53 + * This is only for internal list manipulation where we know 8.54 + * the prev/next entries already! 8.55 + */ 8.56 +static inline void __list_add(struct list_head *new, 8.57 + struct list_head *prev, 8.58 + struct list_head *next) 8.59 +{ 8.60 + next->prev = new; 8.61 + new->next = next; 8.62 + new->prev = prev; 8.63 + prev->next = new; 8.64 +} 8.65 + 8.66 +/** 8.67 + * list_add - add a new entry 8.68 + * @new: new entry to be added 8.69 + * @head: list head to add it after 8.70 + * 8.71 + * Insert a new entry after the specified head. 8.72 + * This is good for implementing stacks. 8.73 + */ 8.74 +static inline void list_add(struct list_head *new, struct list_head *head) 8.75 +{ 8.76 + __list_add(new, head, head->next); 8.77 +} 8.78 + 8.79 +/** 8.80 + * list_add_tail - add a new entry 8.81 + * @new: new entry to be added 8.82 + * @head: list head to add it before 8.83 + * 8.84 + * Insert a new entry before the specified head. 8.85 + * This is useful for implementing queues. 8.86 + */ 8.87 +static inline void list_add_tail(struct list_head *new, struct list_head *head) 8.88 +{ 8.89 + __list_add(new, head->prev, head); 8.90 +} 8.91 + 8.92 +/* 8.93 + * Insert a new entry between two known consecutive entries. 8.94 + * 8.95 + * This is only for internal list manipulation where we know 8.96 + * the prev/next entries already! 8.97 + */ 8.98 +static __inline__ void __list_add_rcu(struct list_head * new, 8.99 + struct list_head * prev, 8.100 + struct list_head * next) 8.101 +{ 8.102 + new->next = next; 8.103 + new->prev = prev; 8.104 + next->prev = new; 8.105 + prev->next = new; 8.106 +} 8.107 + 8.108 +/** 8.109 + * list_add_rcu - add a new entry to rcu-protected list 8.110 + * @new: new entry to be added 8.111 + * @head: list head to add it after 8.112 + * 8.113 + * Insert a new entry after the specified head. 8.114 + * This is good for implementing stacks. 8.115 + */ 8.116 +static __inline__ void list_add_rcu(struct list_head *new, struct list_head *head) 8.117 +{ 8.118 + __list_add_rcu(new, head, head->next); 8.119 +} 8.120 + 8.121 +/** 8.122 + * list_add_tail_rcu - add a new entry to rcu-protected list 8.123 + * @new: new entry to be added 8.124 + * @head: list head to add it before 8.125 + * 8.126 + * Insert a new entry before the specified head. 8.127 + * This is useful for implementing queues. 8.128 + */ 8.129 +static __inline__ void list_add_tail_rcu(struct list_head *new, struct list_head *head) 8.130 +{ 8.131 + __list_add_rcu(new, head->prev, head); 8.132 +} 8.133 + 8.134 +/* 8.135 + * Delete a list entry by making the prev/next entries 8.136 + * point to each other. 8.137 + * 8.138 + * This is only for internal list manipulation where we know 8.139 + * the prev/next entries already! 8.140 + */ 8.141 +static inline void __list_del(struct list_head * prev, struct list_head * next) 8.142 +{ 8.143 + next->prev = prev; 8.144 + prev->next = next; 8.145 +} 8.146 + 8.147 +/** 8.148 + * list_del - deletes entry from list. 8.149 + * @entry: the element to delete from the list. 8.150 + * Note: list_empty on entry does not return true after this, the entry is 8.151 + * in an undefined state. 8.152 + */ 8.153 +static inline void list_del(struct list_head *entry) 8.154 +{ 8.155 + __list_del(entry->prev, entry->next); 8.156 + entry->next = LIST_POISON1; 8.157 + entry->prev = LIST_POISON2; 8.158 +} 8.159 + 8.160 +/** 8.161 + * list_del_rcu - deletes entry from list without re-initialization 8.162 + * @entry: the element to delete from the list. 8.163 + * 8.164 + * Note: list_empty on entry does not return true after this, 8.165 + * the entry is in an undefined state. It is useful for RCU based 8.166 + * lockfree traversal. 8.167 + * 8.168 + * In particular, it means that we can not poison the forward 8.169 + * pointers that may still be used for walking the list. 8.170 + */ 8.171 +static inline void list_del_rcu(struct list_head *entry) 8.172 +{ 8.173 + __list_del(entry->prev, entry->next); 8.174 + entry->prev = LIST_POISON2; 8.175 +} 8.176 + 8.177 +/** 8.178 + * list_del_init - deletes entry from list and reinitialize it. 8.179 + * @entry: the element to delete from the list. 8.180 + */ 8.181 +static inline void list_del_init(struct list_head *entry) 8.182 +{ 8.183 + __list_del(entry->prev, entry->next); 8.184 + INIT_LIST_HEAD(entry); 8.185 +} 8.186 + 8.187 +/** 8.188 + * list_move - delete from one list and add as another's head 8.189 + * @list: the entry to move 8.190 + * @head: the head that will precede our entry 8.191 + */ 8.192 +static inline void list_move(struct list_head *list, struct list_head *head) 8.193 +{ 8.194 + __list_del(list->prev, list->next); 8.195 + list_add(list, head); 8.196 +} 8.197 + 8.198 +/** 8.199 + * list_move_tail - delete from one list and add as another's tail 8.200 + * @list: the entry to move 8.201 + * @head: the head that will follow our entry 8.202 + */ 8.203 +static inline void list_move_tail(struct list_head *list, 8.204 + struct list_head *head) 8.205 +{ 8.206 + __list_del(list->prev, list->next); 8.207 + list_add_tail(list, head); 8.208 +} 8.209 + 8.210 +/** 8.211 + * list_empty - tests whether a list is empty 8.212 + * @head: the list to test. 8.213 + */ 8.214 +static inline int list_empty(struct list_head *head) 8.215 +{ 8.216 + return head->next == head; 8.217 +} 8.218 + 8.219 +static inline void __list_splice(struct list_head *list, 8.220 + struct list_head *head) 8.221 +{ 8.222 + struct list_head *first = list->next; 8.223 + struct list_head *last = list->prev; 8.224 + struct list_head *at = head->next; 8.225 + 8.226 + first->prev = head; 8.227 + head->next = first; 8.228 + 8.229 + last->next = at; 8.230 + at->prev = last; 8.231 +} 8.232 + 8.233 +/** 8.234 + * list_splice - join two lists 8.235 + * @list: the new list to add. 8.236 + * @head: the place to add it in the first list. 8.237 + */ 8.238 +static inline void list_splice(struct list_head *list, struct list_head *head) 8.239 +{ 8.240 + if (!list_empty(list)) 8.241 + __list_splice(list, head); 8.242 +} 8.243 + 8.244 +/** 8.245 + * list_splice_init - join two lists and reinitialise the emptied list. 8.246 + * @list: the new list to add. 8.247 + * @head: the place to add it in the first list. 8.248 + * 8.249 + * The list at @list is reinitialised 8.250 + */ 8.251 +static inline void list_splice_init(struct list_head *list, 8.252 + struct list_head *head) 8.253 +{ 8.254 + if (!list_empty(list)) { 8.255 + __list_splice(list, head); 8.256 + INIT_LIST_HEAD(list); 8.257 + } 8.258 +} 8.259 + 8.260 +/** 8.261 + * list_entry - get the struct for this entry 8.262 + * @ptr: the &struct list_head pointer. 8.263 + * @type: the type of the struct this is embedded in. 8.264 + * @member: the name of the list_struct within the struct. 8.265 + */ 8.266 +#define list_entry(ptr, type, member) \ 8.267 + container_of(ptr, type, member) 8.268 + 8.269 +/** 8.270 + * list_for_each - iterate over a list 8.271 + * @pos: the &struct list_head to use as a loop counter. 8.272 + * @head: the head for your list. 8.273 + */ 8.274 +#define list_for_each(pos, head) \ 8.275 + for (pos = (head)->next; pos != (head); pos = pos->next) 8.276 + 8.277 +/** 8.278 + * list_for_each_prev - iterate over a list backwards 8.279 + * @pos: the &struct list_head to use as a loop counter. 8.280 + * @head: the head for your list. 8.281 + */ 8.282 +#define list_for_each_prev(pos, head) \ 8.283 + for (pos = (head)->prev; pos != (head); pos = pos->prev) 8.284 + 8.285 +/** 8.286 + * list_for_each_safe - iterate over a list safe against removal of list entry 8.287 + * @pos: the &struct list_head to use as a loop counter. 8.288 + * @n: another &struct list_head to use as temporary storage 8.289 + * @head: the head for your list. 8.290 + */ 8.291 +#define list_for_each_safe(pos, n, head) \ 8.292 + for (pos = (head)->next, n = pos->next; pos != (head); \ 8.293 + pos = n, n = pos->next) 8.294 + 8.295 +/** 8.296 + * list_for_each_entry - iterate over list of given type 8.297 + * @pos: the type * to use as a loop counter. 8.298 + * @head: the head for your list. 8.299 + * @member: the name of the list_struct within the struct. 8.300 + */ 8.301 +#define list_for_each_entry(pos, head, member) \ 8.302 + for (pos = list_entry((head)->next, typeof(*pos), member); \ 8.303 + &pos->member != (head); \ 8.304 + pos = list_entry(pos->member.next, typeof(*pos), member)) 8.305 + 8.306 +/** 8.307 + * list_for_each_entry_reverse - iterate backwards over list of given type. 8.308 + * @pos: the type * to use as a loop counter. 8.309 + * @head: the head for your list. 8.310 + * @member: the name of the list_struct within the struct. 8.311 + */ 8.312 +#define list_for_each_entry_reverse(pos, head, member) \ 8.313 + for (pos = list_entry((head)->prev, typeof(*pos), member); \ 8.314 + &pos->member != (head); \ 8.315 + pos = list_entry(pos->member.prev, typeof(*pos), member)) 8.316 + 8.317 + 8.318 +/** 8.319 + * list_for_each_entry_continue - iterate over list of given type 8.320 + * continuing after existing point 8.321 + * @pos: the type * to use as a loop counter. 8.322 + * @head: the head for your list. 8.323 + * @member: the name of the list_struct within the struct. 8.324 + */ 8.325 +#define list_for_each_entry_continue(pos, head, member) \ 8.326 + for (pos = list_entry(pos->member.next, typeof(*pos), member); \ 8.327 + &pos->member != (head); \ 8.328 + pos = list_entry(pos->member.next, typeof(*pos), member)) 8.329 + 8.330 +/** 8.331 + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry 8.332 + * @pos: the type * to use as a loop counter. 8.333 + * @n: another type * to use as temporary storage 8.334 + * @head: the head for your list. 8.335 + * @member: the name of the list_struct within the struct. 8.336 + */ 8.337 +#define list_for_each_entry_safe(pos, n, head, member) \ 8.338 + for (pos = list_entry((head)->next, typeof(*pos), member), \ 8.339 + n = list_entry(pos->member.next, typeof(*pos), member); \ 8.340 + &pos->member != (head); \ 8.341 + pos = n, n = list_entry(n->member.next, typeof(*n), member)) 8.342 + 8.343 + 8.344 +/* 8.345 + * Double linked lists with a single pointer list head. 8.346 + * Mostly useful for hash tables where the two pointer list head is 8.347 + * too wasteful. 8.348 + * You lose the ability to access the tail in O(1). 8.349 + */ 8.350 + 8.351 +struct hlist_head { 8.352 + struct hlist_node *first; 8.353 +}; 8.354 + 8.355 +struct hlist_node { 8.356 + struct hlist_node *next, **pprev; 8.357 +}; 8.358 + 8.359 +#define HLIST_HEAD_INIT { .first = NULL } 8.360 +#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } 8.361 +#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) 8.362 +#define INIT_HLIST_NODE(ptr) ((ptr)->next = NULL, (ptr)->pprev = NULL) 8.363 + 8.364 +static __inline__ int hlist_unhashed(struct hlist_node *h) 8.365 +{ 8.366 + return !h->pprev; 8.367 +} 8.368 + 8.369 +static __inline__ int hlist_empty(struct hlist_head *h) 8.370 +{ 8.371 + return !h->first; 8.372 +} 8.373 + 8.374 +static __inline__ void __hlist_del(struct hlist_node *n) 8.375 +{ 8.376 + struct hlist_node *next = n->next; 8.377 + struct hlist_node **pprev = n->pprev; 8.378 + *pprev = next; 8.379 + if (next) 8.380 + next->pprev = pprev; 8.381 +} 8.382 + 8.383 +static __inline__ void hlist_del(struct hlist_node *n) 8.384 +{ 8.385 + __hlist_del(n); 8.386 + n->next = LIST_POISON1; 8.387 + n->pprev = LIST_POISON2; 8.388 +} 8.389 + 8.390 +/** 8.391 + * hlist_del_rcu - deletes entry from hash list without re-initialization 8.392 + * @entry: the element to delete from the hash list. 8.393 + * 8.394 + * Note: list_unhashed() on entry does not return true after this, 8.395 + * the entry is in an undefined state. It is useful for RCU based 8.396 + * lockfree traversal. 8.397 + * 8.398 + * In particular, it means that we can not poison the forward 8.399 + * pointers that may still be used for walking the hash list. 8.400 + */ 8.401 +static inline void hlist_del_rcu(struct hlist_node *n) 8.402 +{ 8.403 + __hlist_del(n); 8.404 + n->pprev = LIST_POISON2; 8.405 +} 8.406 + 8.407 +static __inline__ void hlist_del_init(struct hlist_node *n) 8.408 +{ 8.409 + if (n->pprev) { 8.410 + __hlist_del(n); 8.411 + INIT_HLIST_NODE(n); 8.412 + } 8.413 +} 8.414 + 8.415 +#define hlist_del_rcu_init hlist_del_init 8.416 + 8.417 +static __inline__ void hlist_add_head(struct hlist_node *n, struct hlist_head *h) 8.418 +{ 8.419 + struct hlist_node *first = h->first; 8.420 + n->next = first; 8.421 + if (first) 8.422 + first->pprev = &n->next; 8.423 + h->first = n; 8.424 + n->pprev = &h->first; 8.425 +} 8.426 + 8.427 +static __inline__ void hlist_add_head_rcu(struct hlist_node *n, struct hlist_head *h) 8.428 +{ 8.429 + struct hlist_node *first = h->first; 8.430 + n->next = first; 8.431 + n->pprev = &h->first; 8.432 + if (first) 8.433 + first->pprev = &n->next; 8.434 + h->first = n; 8.435 +} 8.436 + 8.437 +/* next must be != NULL */ 8.438 +static __inline__ void hlist_add_before(struct hlist_node *n, struct hlist_node *next) 8.439 +{ 8.440 + n->pprev = next->pprev; 8.441 + n->next = next; 8.442 + next->pprev = &n->next; 8.443 + *(n->pprev) = n; 8.444 +} 8.445 + 8.446 +static __inline__ void hlist_add_after(struct hlist_node *n, 8.447 + struct hlist_node *next) 8.448 +{ 8.449 + next->next = n->next; 8.450 + *(next->pprev) = n; 8.451 + n->next = next; 8.452 +} 8.453 + 8.454 +#define hlist_entry(ptr, type, member) container_of(ptr,type,member) 8.455 + 8.456 +/* Cannot easily do prefetch unfortunately */ 8.457 +#define hlist_for_each(pos, head) \ 8.458 + for (pos = (head)->first; pos; pos = pos->next) 8.459 + 8.460 +#define hlist_for_each_safe(pos, n, head) \ 8.461 + for (pos = (head)->first; n = pos ? pos->next : 0, pos; \ 8.462 + pos = n) 8.463 + 8.464 +/** 8.465 + * hlist_for_each_entry - iterate over list of given type 8.466 + * @tpos: the type * to use as a loop counter. 8.467 + * @pos: the &struct hlist_node to use as a loop counter. 8.468 + * @head: the head for your list. 8.469 + * @member: the name of the hlist_node within the struct. 8.470 + */ 8.471 +#define hlist_for_each_entry(tpos, pos, head, member) \ 8.472 + for (pos = (head)->first; \ 8.473 + pos && ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ 8.474 + pos = pos->next) 8.475 + 8.476 +/** 8.477 + * hlist_for_each_entry_continue - iterate over a hlist continuing after existing point 8.478 + * @tpos: the type * to use as a loop counter. 8.479 + * @pos: the &struct hlist_node to use as a loop counter. 8.480 + * @member: the name of the hlist_node within the struct. 8.481 + */ 8.482 +#define hlist_for_each_entry_continue(tpos, pos, member) \ 8.483 + for (pos = (pos)->next; \ 8.484 + pos && ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ 8.485 + pos = pos->next) 8.486 + 8.487 +/** 8.488 + * hlist_for_each_entry_from - iterate over a hlist continuing from existing point 8.489 + * @tpos: the type * to use as a loop counter. 8.490 + * @pos: the &struct hlist_node to use as a loop counter. 8.491 + * @member: the name of the hlist_node within the struct. 8.492 + */ 8.493 +#define hlist_for_each_entry_from(tpos, pos, member) \ 8.494 + for (; pos && ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ 8.495 + pos = pos->next) 8.496 + 8.497 +/** 8.498 + * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry 8.499 + * @tpos: the type * to use as a loop counter. 8.500 + * @pos: the &struct hlist_node to use as a loop counter. 8.501 + * @n: another &struct hlist_node to use as temporary storage 8.502 + * @head: the head for your list. 8.503 + * @member: the name of the hlist_node within the struct. 8.504 + */ 8.505 +#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ 8.506 + for (pos = (head)->first; \ 8.507 + pos && ({ n = pos->next; 1; }) && \ 8.508 + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ 8.509 + pos = n) 8.510 + 8.511 +#endif
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 9.2 +++ b/tools/xenstore/talloc.c Tue Jun 07 12:43:58 2005 +0000 9.3 @@ -0,0 +1,1143 @@ 9.4 +/* 9.5 + Samba Unix SMB/CIFS implementation. 9.6 + 9.7 + Samba trivial allocation library - new interface 9.8 + 9.9 + NOTE: Please read talloc_guide.txt for full documentation 9.10 + 9.11 + Copyright (C) Andrew Tridgell 2004 9.12 + 9.13 + This program is free software; you can redistribute it and/or modify 9.14 + it under the terms of the GNU General Public License as published by 9.15 + the Free Software Foundation; either version 2 of the License, or 9.16 + (at your option) any later version. 9.17 + 9.18 + This program is distributed in the hope that it will be useful, 9.19 + but WITHOUT ANY WARRANTY; without even the implied warranty of 9.20 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9.21 + GNU General Public License for more details. 9.22 + 9.23 + You should have received a copy of the GNU General Public License 9.24 + along with this program; if not, write to the Free Software 9.25 + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 9.26 +*/ 9.27 + 9.28 +/* 9.29 + inspired by http://swapped.cc/halloc/ 9.30 +*/ 9.31 + 9.32 + 9.33 +#ifdef _SAMBA_BUILD_ 9.34 +#include "includes.h" 9.35 +#if ((SAMBA_VERSION_MAJOR==3)&&(SAMBA_VERSION_MINOR<9)) 9.36 +/* This is to circumvent SAMBA3's paranoid malloc checker. Here in this file 9.37 + * we trust ourselves... */ 9.38 +#ifdef malloc 9.39 +#undef malloc 9.40 +#endif 9.41 +#ifdef realloc 9.42 +#undef realloc 9.43 +#endif 9.44 +#endif 9.45 +#else 9.46 +#include <stdio.h> 9.47 +#include <stdlib.h> 9.48 +#include <string.h> 9.49 +#include <stdarg.h> 9.50 +#include <stdint.h> 9.51 +#include "talloc.h" 9.52 +/* assume a modern system */ 9.53 +#define HAVE_VA_COPY 9.54 +#endif 9.55 + 9.56 +/* use this to force every realloc to change the pointer, to stress test 9.57 + code that might not cope */ 9.58 +#ifdef TESTING 9.59 +#define ALWAYS_REALLOC 1 9.60 +void *test_malloc(size_t size); 9.61 +#define malloc test_malloc 9.62 +#endif 9.63 + 9.64 +#define MAX_TALLOC_SIZE 0x10000000 9.65 +#define TALLOC_MAGIC 0xe814ec4f 9.66 +#define TALLOC_MAGIC_FREE 0x7faebef3 9.67 +#define TALLOC_MAGIC_REFERENCE ((const char *)1) 9.68 + 9.69 +/* by default we abort when given a bad pointer (such as when talloc_free() is called 9.70 + on a pointer that came from malloc() */ 9.71 +#ifndef TALLOC_ABORT 9.72 +#define TALLOC_ABORT(reason) abort() 9.73 +#endif 9.74 + 9.75 +#ifndef discard_const_p 9.76 +#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) 9.77 +# define discard_const_p(type, ptr) ((type *)((intptr_t)(ptr))) 9.78 +#else 9.79 +# define discard_const_p(type, ptr) ((type *)(ptr)) 9.80 +#endif 9.81 +#endif 9.82 + 9.83 +/* this null_context is only used if talloc_enable_leak_report() or 9.84 + talloc_enable_leak_report_full() is called, otherwise it remains 9.85 + NULL 9.86 +*/ 9.87 +static const void *null_context; 9.88 +static void *cleanup_context; 9.89 +static int (*malloc_fail_handler)(void *); 9.90 +static void *malloc_fail_data; 9.91 + 9.92 +struct talloc_reference_handle { 9.93 + struct talloc_reference_handle *next, *prev; 9.94 + void *ptr; 9.95 +}; 9.96 + 9.97 +typedef int (*talloc_destructor_t)(void *); 9.98 + 9.99 +struct talloc_chunk { 9.100 + struct talloc_chunk *next, *prev; 9.101 + struct talloc_chunk *parent, *child; 9.102 + struct talloc_reference_handle *refs; 9.103 + size_t size; 9.104 + unsigned magic; 9.105 + talloc_destructor_t destructor; 9.106 + const char *name; 9.107 +}; 9.108 + 9.109 +/* panic if we get a bad magic value */ 9.110 +static struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr) 9.111 +{ 9.112 + struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, ptr)-1; 9.113 + if (tc->magic != TALLOC_MAGIC) { 9.114 + if (tc->magic == TALLOC_MAGIC_FREE) { 9.115 + TALLOC_ABORT("Bad talloc magic value - double free"); 9.116 + } else { 9.117 + TALLOC_ABORT("Bad talloc magic value - unknown value"); 9.118 + } 9.119 + } 9.120 + 9.121 + return tc; 9.122 +} 9.123 + 9.124 +/* hook into the front of the list */ 9.125 +#define _TLIST_ADD(list, p) \ 9.126 +do { \ 9.127 + if (!(list)) { \ 9.128 + (list) = (p); \ 9.129 + (p)->next = (p)->prev = NULL; \ 9.130 + } else { \ 9.131 + (list)->prev = (p); \ 9.132 + (p)->next = (list); \ 9.133 + (p)->prev = NULL; \ 9.134 + (list) = (p); \ 9.135 + }\ 9.136 +} while (0) 9.137 + 9.138 +/* remove an element from a list - element doesn't have to be in list. */ 9.139 +#define _TLIST_REMOVE(list, p) \ 9.140 +do { \ 9.141 + if ((p) == (list)) { \ 9.142 + (list) = (p)->next; \ 9.143 + if (list) (list)->prev = NULL; \ 9.144 + } else { \ 9.145 + if ((p)->prev) (p)->prev->next = (p)->next; \ 9.146 + if ((p)->next) (p)->next->prev = (p)->prev; \ 9.147 + } \ 9.148 + if ((p) && ((p) != (list))) (p)->next = (p)->prev = NULL; \ 9.149 +} while (0) 9.150 + 9.151 + 9.152 +/* 9.153 + return the parent chunk of a pointer 9.154 +*/ 9.155 +static struct talloc_chunk *talloc_parent_chunk(const void *ptr) 9.156 +{ 9.157 + struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); 9.158 + while (tc->prev) tc=tc->prev; 9.159 + return tc->parent; 9.160 +} 9.161 + 9.162 +void *talloc_parent(const void *ptr) 9.163 +{ 9.164 + struct talloc_chunk *tc = talloc_parent_chunk(ptr); 9.165 + return (void *)(tc+1); 9.166 +} 9.167 + 9.168 +/* 9.169 + Allocate a bit of memory as a child of an existing pointer 9.170 +*/ 9.171 +void *_talloc(const void *context, size_t size) 9.172 +{ 9.173 + struct talloc_chunk *tc; 9.174 + 9.175 + if (context == NULL) { 9.176 + context = null_context; 9.177 + } 9.178 + 9.179 + if (size >= MAX_TALLOC_SIZE) { 9.180 + return NULL; 9.181 + } 9.182 + 9.183 + tc = malloc(sizeof(*tc)+size); 9.184 + if (tc == NULL) { 9.185 + if (malloc_fail_handler) 9.186 + if (malloc_fail_handler(malloc_fail_data)) 9.187 + tc = malloc(sizeof(*tc)+size); 9.188 + if (!tc) 9.189 + return NULL; 9.190 + } 9.191 + 9.192 + tc->size = size; 9.193 + tc->magic = TALLOC_MAGIC; 9.194 + tc->destructor = NULL; 9.195 + tc->child = NULL; 9.196 + tc->name = NULL; 9.197 + tc->refs = NULL; 9.198 + 9.199 + if (context) { 9.200 + struct talloc_chunk *parent = talloc_chunk_from_ptr(context); 9.201 + 9.202 + tc->parent = parent; 9.203 + 9.204 + if (parent->child) { 9.205 + parent->child->parent = NULL; 9.206 + } 9.207 + 9.208 + _TLIST_ADD(parent->child, tc); 9.209 + } else { 9.210 + tc->next = tc->prev = tc->parent = NULL; 9.211 + } 9.212 + 9.213 + return (void *)(tc+1); 9.214 +} 9.215 + 9.216 + 9.217 +/* 9.218 + setup a destructor to be called on free of a pointer 9.219 + the destructor should return 0 on success, or -1 on failure. 9.220 + if the destructor fails then the free is failed, and the memory can 9.221 + be continued to be used 9.222 +*/ 9.223 +void talloc_set_destructor(const void *ptr, int (*destructor)(void *)) 9.224 +{ 9.225 + struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); 9.226 + tc->destructor = destructor; 9.227 +} 9.228 + 9.229 +/* 9.230 + increase the reference count on a piece of memory. 9.231 +*/ 9.232 +void talloc_increase_ref_count(const void *ptr) 9.233 +{ 9.234 + talloc_reference(null_context, ptr); 9.235 +} 9.236 + 9.237 +/* 9.238 + helper for talloc_reference() 9.239 +*/ 9.240 +static int talloc_reference_destructor(void *ptr) 9.241 +{ 9.242 + struct talloc_reference_handle *handle = ptr; 9.243 + struct talloc_chunk *tc1 = talloc_chunk_from_ptr(ptr); 9.244 + struct talloc_chunk *tc2 = talloc_chunk_from_ptr(handle->ptr); 9.245 + if (tc1->destructor != (talloc_destructor_t)-1) { 9.246 + tc1->destructor = NULL; 9.247 + } 9.248 + _TLIST_REMOVE(tc2->refs, handle); 9.249 + talloc_free(handle); 9.250 + return 0; 9.251 +} 9.252 + 9.253 +/* 9.254 + make a secondary reference to a pointer, hanging off the given context. 9.255 + the pointer remains valid until both the original caller and this given 9.256 + context are freed. 9.257 + 9.258 + the major use for this is when two different structures need to reference the 9.259 + same underlying data, and you want to be able to free the two instances separately, 9.260 + and in either order 9.261 +*/ 9.262 +void *talloc_reference(const void *context, const void *ptr) 9.263 +{ 9.264 + struct talloc_chunk *tc; 9.265 + struct talloc_reference_handle *handle; 9.266 + if (ptr == NULL) return NULL; 9.267 + 9.268 + tc = talloc_chunk_from_ptr(ptr); 9.269 + handle = talloc_named_const(context, sizeof(*handle), TALLOC_MAGIC_REFERENCE); 9.270 + 9.271 + if (handle == NULL) return NULL; 9.272 + 9.273 + /* note that we hang the destructor off the handle, not the 9.274 + main context as that allows the caller to still setup their 9.275 + own destructor on the context if they want to */ 9.276 + talloc_set_destructor(handle, talloc_reference_destructor); 9.277 + handle->ptr = discard_const_p(void, ptr); 9.278 + _TLIST_ADD(tc->refs, handle); 9.279 + return handle->ptr; 9.280 +} 9.281 + 9.282 +/* 9.283 + remove a secondary reference to a pointer. This undo's what 9.284 + talloc_reference() has done. The context and pointer arguments 9.285 + must match those given to a talloc_reference() 9.286 +*/ 9.287 +static int talloc_unreference(const void *context, const void *ptr) 9.288 +{ 9.289 + struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); 9.290 + struct talloc_reference_handle *h; 9.291 + 9.292 + if (context == NULL) { 9.293 + context = null_context; 9.294 + } 9.295 + 9.296 + for (h=tc->refs;h;h=h->next) { 9.297 + struct talloc_chunk *p = talloc_parent_chunk(h); 9.298 + if ((p==NULL && context==NULL) || p+1 == context) break; 9.299 + } 9.300 + if (h == NULL) { 9.301 + return -1; 9.302 + } 9.303 + 9.304 + talloc_set_destructor(h, NULL); 9.305 + _TLIST_REMOVE(tc->refs, h); 9.306 + talloc_free(h); 9.307 + return 0; 9.308 +} 9.309 + 9.310 +/* 9.311 + remove a specific parent context from a pointer. This is a more 9.312 + controlled varient of talloc_free() 9.313 +*/ 9.314 +int talloc_unlink(const void *context, void *ptr) 9.315 +{ 9.316 + struct talloc_chunk *tc_p, *new_p; 9.317 + void *new_parent; 9.318 + 9.319 + if (ptr == NULL) { 9.320 + return -1; 9.321 + } 9.322 + 9.323 + if (context == NULL) { 9.324 + context = null_context; 9.325 + } 9.326 + 9.327 + if (talloc_unreference(context, ptr) == 0) { 9.328 + return 0; 9.329 + } 9.330 + 9.331 + if (context == NULL) { 9.332 + if (talloc_parent_chunk(ptr) != NULL) { 9.333 + return -1; 9.334 + } 9.335 + } else { 9.336 + if (talloc_chunk_from_ptr(context) != talloc_parent_chunk(ptr)) { 9.337 + return -1; 9.338 + } 9.339 + } 9.340 + 9.341 + tc_p = talloc_chunk_from_ptr(ptr); 9.342 + 9.343 + if (tc_p->refs == NULL) { 9.344 + return talloc_free(ptr); 9.345 + } 9.346 + 9.347 + new_p = talloc_parent_chunk(tc_p->refs); 9.348 + if (new_p) { 9.349 + new_parent = new_p+1; 9.350 + } else { 9.351 + new_parent = NULL; 9.352 + } 9.353 + 9.354 + if (talloc_unreference(new_parent, ptr) != 0) { 9.355 + return -1; 9.356 + } 9.357 + 9.358 + talloc_steal(new_parent, ptr); 9.359 + 9.360 + return 0; 9.361 +} 9.362 + 9.363 +/* 9.364 + add a name to an existing pointer - va_list version 9.365 +*/ 9.366 +static void talloc_set_name_v(const void *ptr, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0); 9.367 + 9.368 +static void talloc_set_name_v(const void *ptr, const char *fmt, va_list ap) 9.369 +{ 9.370 + struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); 9.371 + tc->name = talloc_vasprintf(ptr, fmt, ap); 9.372 + if (tc->name) { 9.373 + talloc_set_name_const(tc->name, ".name"); 9.374 + } 9.375 +} 9.376 + 9.377 +/* 9.378 + add a name to an existing pointer 9.379 +*/ 9.380 +void talloc_set_name(const void *ptr, const char *fmt, ...) 9.381 +{ 9.382 + va_list ap; 9.383 + va_start(ap, fmt); 9.384 + talloc_set_name_v(ptr, fmt, ap); 9.385 + va_end(ap); 9.386 +} 9.387 + 9.388 +/* 9.389 + more efficient way to add a name to a pointer - the name must point to a 9.390 + true string constant 9.391 +*/ 9.392 +void talloc_set_name_const(const void *ptr, const char *name) 9.393 +{ 9.394 + struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); 9.395 + tc->name = name; 9.396 +} 9.397 + 9.398 +/* 9.399 + create a named talloc pointer. Any talloc pointer can be named, and 9.400 + talloc_named() operates just like talloc() except that it allows you 9.401 + to name the pointer. 9.402 +*/ 9.403 +void *talloc_named(const void *context, size_t size, const char *fmt, ...) 9.404 +{ 9.405 + va_list ap; 9.406 + void *ptr; 9.407 + 9.408 + ptr = _talloc(context, size); 9.409 + if (ptr == NULL) return NULL; 9.410 + 9.411 + va_start(ap, fmt); 9.412 + talloc_set_name_v(ptr, fmt, ap); 9.413 + va_end(ap); 9.414 + 9.415 + return ptr; 9.416 +} 9.417 + 9.418 +/* 9.419 + create a named talloc pointer. Any talloc pointer can be named, and 9.420 + talloc_named() operates just like talloc() except that it allows you 9.421 + to name the pointer. 9.422 +*/ 9.423 +void *talloc_named_const(const void *context, size_t size, const char *name) 9.424 +{ 9.425 + void *ptr; 9.426 + 9.427 + ptr = _talloc(context, size); 9.428 + if (ptr == NULL) { 9.429 + return NULL; 9.430 + } 9.431 + 9.432 + talloc_set_name_const(ptr, name); 9.433 + 9.434 + return ptr; 9.435 +} 9.436 + 9.437 +/* 9.438 + return the name of a talloc ptr, or "UNNAMED" 9.439 +*/ 9.440 +const char *talloc_get_name(const void *ptr) 9.441 +{ 9.442 + struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); 9.443 + if (tc->name == TALLOC_MAGIC_REFERENCE) { 9.444 + return ".reference"; 9.445 + } 9.446 + if (tc->name) { 9.447 + return tc->name; 9.448 + } 9.449 + return "UNNAMED"; 9.450 +} 9.451 + 9.452 + 9.453 +/* 9.454 + check if a pointer has the given name. If it does, return the pointer, 9.455 + otherwise return NULL 9.456 +*/ 9.457 +void *talloc_check_name(const void *ptr, const char *name) 9.458 +{ 9.459 + const char *pname; 9.460 + if (ptr == NULL) return NULL; 9.461 + pname = talloc_get_name(ptr); 9.462 + if (pname == name || strcmp(pname, name) == 0) { 9.463 + return discard_const_p(void, ptr); 9.464 + } 9.465 + return NULL; 9.466 +} 9.467 + 9.468 + 9.469 +/* 9.470 + this is for compatibility with older versions of talloc 9.471 +*/ 9.472 +void *talloc_init(const char *fmt, ...) 9.473 +{ 9.474 + va_list ap; 9.475 + void *ptr; 9.476 + 9.477 + ptr = _talloc(NULL, 0); 9.478 + if (ptr == NULL) return NULL; 9.479 + 9.480 + va_start(ap, fmt); 9.481 + talloc_set_name_v(ptr, fmt, ap); 9.482 + va_end(ap); 9.483 + 9.484 + return ptr; 9.485 +} 9.486 + 9.487 +/* 9.488 + this is a replacement for the Samba3 talloc_destroy_pool functionality. It 9.489 + should probably not be used in new code. It's in here to keep the talloc 9.490 + code consistent across Samba 3 and 4. 9.491 +*/ 9.492 +void talloc_free_children(void *ptr) 9.493 +{ 9.494 + struct talloc_chunk *tc; 9.495 + 9.496 + if (ptr == NULL) { 9.497 + return; 9.498 + } 9.499 + 9.500 + tc = talloc_chunk_from_ptr(ptr); 9.501 + 9.502 + while (tc->child) { 9.503 + /* we need to work out who will own an abandoned child 9.504 + if it cannot be freed. In priority order, the first 9.505 + choice is owner of any remaining reference to this 9.506 + pointer, the second choice is our parent, and the 9.507 + final choice is the null context. */ 9.508 + void *child = tc->child+1; 9.509 + const void *new_parent = null_context; 9.510 + if (tc->child->refs) { 9.511 + struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs); 9.512 + if (p) new_parent = p+1; 9.513 + } 9.514 + if (talloc_free(child) == -1) { 9.515 + if (new_parent == null_context) { 9.516 + struct talloc_chunk *p = talloc_parent_chunk(ptr); 9.517 + if (p) new_parent = p+1; 9.518 + } 9.519 + talloc_steal(new_parent, child); 9.520 + } 9.521 + } 9.522 +} 9.523 + 9.524 +/* 9.525 + free a talloc pointer. This also frees all child pointers of this 9.526 + pointer recursively 9.527 + 9.528 + return 0 if the memory is actually freed, otherwise -1. The memory 9.529 + will not be freed if the ref_count is > 1 or the destructor (if 9.530 + any) returns non-zero 9.531 +*/ 9.532 +int talloc_free(void *ptr) 9.533 +{ 9.534 + struct talloc_chunk *tc; 9.535 + 9.536 + if (ptr == NULL) { 9.537 + return -1; 9.538 + } 9.539 + 9.540 + tc = talloc_chunk_from_ptr(ptr); 9.541 + 9.542 + if (tc->refs) { 9.543 + talloc_reference_destructor(tc->refs); 9.544 + return -1; 9.545 + } 9.546 + 9.547 + if (tc->destructor) { 9.548 + talloc_destructor_t d = tc->destructor; 9.549 + if (d == (talloc_destructor_t)-1) { 9.550 + return -1; 9.551 + } 9.552 + tc->destructor = (talloc_destructor_t)-1; 9.553 + if (d(ptr) == -1) { 9.554 + tc->destructor = d; 9.555 + return -1; 9.556 + } 9.557 + tc->destructor = NULL; 9.558 + } 9.559 + 9.560 + talloc_free_children(ptr); 9.561 + 9.562 + if (tc->parent) { 9.563 + _TLIST_REMOVE(tc->parent->child, tc); 9.564 + if (tc->parent->child) { 9.565 + tc->parent->child->parent = tc->parent; 9.566 + } 9.567 + } else { 9.568 + if (tc->prev) tc->prev->next = tc->next; 9.569 + if (tc->next) tc->next->prev = tc->prev; 9.570 + } 9.571 + 9.572 + tc->magic = TALLOC_MAGIC_FREE; 9.573 + 9.574 + free(tc); 9.575 + return 0; 9.576 +} 9.577 + 9.578 + 9.579 + 9.580 +/* 9.581 + A talloc version of realloc. The context argument is only used if 9.582 + ptr is NULL 9.583 +*/ 9.584 +void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name) 9.585 +{ 9.586 + struct talloc_chunk *tc; 9.587 + void *new_ptr; 9.588 + 9.589 + /* size zero is equivalent to free() */ 9.590 + if (size == 0) { 9.591 + talloc_free(ptr); 9.592 + return NULL; 9.593 + } 9.594 + 9.595 + if (size >= MAX_TALLOC_SIZE) { 9.596 + return NULL; 9.597 + } 9.598 + 9.599 + /* realloc(NULL) is equavalent to malloc() */ 9.600 + if (ptr == NULL) { 9.601 + return talloc_named_const(context, size, name); 9.602 + } 9.603 + 9.604 + tc = talloc_chunk_from_ptr(ptr); 9.605 + 9.606 + /* don't allow realloc on referenced pointers */ 9.607 + if (tc->refs) { 9.608 + return NULL; 9.609 + } 9.610 + 9.611 + /* by resetting magic we catch users of the old memory */ 9.612 + tc->magic = TALLOC_MAGIC_FREE; 9.613 + 9.614 +#if ALWAYS_REALLOC 9.615 + new_ptr = malloc(size + sizeof(*tc)); 9.616 + if (!new_ptr) { 9.617 + tc->magic = TALLOC_MAGIC; 9.618 + if (malloc_fail_handler) 9.619 + if (malloc_fail_handler(malloc_fail_data)) 9.620 + new_ptr = malloc(size + sizeof(*tc)); 9.621 + } 9.622 + if (new_ptr) { 9.623 + memcpy(new_ptr, tc, tc->size + sizeof(*tc)); 9.624 + free(tc); 9.625 + } 9.626 +#else 9.627 + new_ptr = realloc(tc, size + sizeof(*tc)); 9.628 + if (!new_ptr) { 9.629 + tc->magic = TALLOC_MAGIC; 9.630 + if (malloc_fail_handler) 9.631 + if (malloc_fail_handler(malloc_fail_data)) 9.632 + new_ptr = realloc(tc, size + sizeof(*tc)); 9.633 + } 9.634 +#endif 9.635 + if (!new_ptr) { 9.636 + tc->magic = TALLOC_MAGIC; 9.637 + return NULL; 9.638 + } 9.639 + 9.640 + tc = new_ptr; 9.641 + tc->magic = TALLOC_MAGIC; 9.642 + if (tc->parent) { 9.643 + tc->parent->child = new_ptr; 9.644 + } 9.645 + if (tc->child) { 9.646 + tc->child->parent = new_ptr; 9.647 + } 9.648 + 9.649 + if (tc->prev) { 9.650 + tc->prev->next = tc; 9.651 + } 9.652 + if (tc->next) { 9.653 + tc->next->prev = tc; 9.654 + } 9.655 + 9.656 + tc->size = size; 9.657 + talloc_set_name_const(tc+1, name); 9.658 + 9.659 + return (void *)(tc+1); 9.660 +} 9.661 + 9.662 +/* 9.663 + move a lump of memory from one talloc context to another return the 9.664 + ptr on success, or NULL if it could not be transferred. 9.665 + passing NULL as ptr will always return NULL with no side effects. 9.666 +*/ 9.667 +void *talloc_steal(const void *new_ctx, const void *ptr) 9.668 +{ 9.669 + struct talloc_chunk *tc, *new_tc; 9.670 + 9.671 + if (!ptr) { 9.672 + return NULL; 9.673 + } 9.674 + 9.675 + if (new_ctx == NULL) { 9.676 + new_ctx = null_context; 9.677 + } 9.678 + 9.679 + tc = talloc_chunk_from_ptr(ptr); 9.680 + 9.681 + if (new_ctx == NULL) { 9.682 + if (tc->parent) { 9.683 + _TLIST_REMOVE(tc->parent->child, tc); 9.684 + if (tc->parent->child) { 9.685 + tc->parent->child->parent = tc->parent; 9.686 + } 9.687 + } else { 9.688 + if (tc->prev) tc->prev->next = tc->next; 9.689 + if (tc->next) tc->next->prev = tc->prev; 9.690 + } 9.691 + 9.692 + tc->parent = tc->next = tc->prev = NULL; 9.693 + return discard_const_p(void, ptr); 9.694 + } 9.695 + 9.696 + new_tc = talloc_chunk_from_ptr(new_ctx); 9.697 + 9.698 + if (tc == new_tc) { 9.699 + return discard_const_p(void, ptr); 9.700 + } 9.701 + 9.702 + if (tc->parent) { 9.703 + _TLIST_REMOVE(tc->parent->child, tc); 9.704 + if (tc->parent->child) { 9.705 + tc->parent->child->parent = tc->parent; 9.706 + } 9.707 + } else { 9.708 + if (tc->prev) tc->prev->next = tc->next; 9.709 + if (tc->next) tc->next->prev = tc->prev; 9.710 + } 9.711 + 9.712 + tc->parent = new_tc; 9.713 + if (new_tc->child) new_tc->child->parent = NULL; 9.714 + _TLIST_ADD(new_tc->child, tc); 9.715 + 9.716 + return discard_const_p(void, ptr); 9.717 +} 9.718 + 9.719 +/* 9.720 + return the total size of a talloc pool (subtree) 9.721 +*/ 9.722 +off_t talloc_total_size(const void *ptr) 9.723 +{ 9.724 + off_t total = 0; 9.725 + struct talloc_chunk *c, *tc; 9.726 + 9.727 + if (ptr == NULL) { 9.728 + ptr = null_context; 9.729 + } 9.730 + if (ptr == NULL) { 9.731 + return 0; 9.732 + } 9.733 + 9.734 + tc = talloc_chunk_from_ptr(ptr); 9.735 + 9.736 + total = tc->size; 9.737 + for (c=tc->child;c;c=c->next) { 9.738 + total += talloc_total_size(c+1); 9.739 + } 9.740 + return total; 9.741 +} 9.742 + 9.743 +/* 9.744 + return the total number of blocks in a talloc pool (subtree) 9.745 +*/ 9.746 +off_t talloc_total_blocks(const void *ptr) 9.747 +{ 9.748 + off_t total = 0; 9.749 + struct talloc_chunk *c, *tc; 9.750 + 9.751 + if (ptr == NULL) { 9.752 + ptr = null_context; 9.753 + } 9.754 + if (ptr == NULL) { 9.755 + return 0; 9.756 + } 9.757 + tc = talloc_chunk_from_ptr(ptr); 9.758 + 9.759 + total++; 9.760 + for (c=tc->child;c;c=c->next) { 9.761 + total += talloc_total_blocks(c+1); 9.762 + } 9.763 + return total; 9.764 +} 9.765 + 9.766 +/* 9.767 + return the number of external references to a pointer 9.768 +*/ 9.769 +static int talloc_reference_count(const void *ptr) 9.770 +{ 9.771 + struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); 9.772 + struct talloc_reference_handle *h; 9.773 + int ret = 0; 9.774 + 9.775 + for (h=tc->refs;h;h=h->next) { 9.776 + ret++; 9.777 + } 9.778 + return ret; 9.779 +} 9.780 + 9.781 +/* 9.782 + report on memory usage by all children of a pointer, giving a full tree view 9.783 +*/ 9.784 +void talloc_report_depth(const void *ptr, FILE *f, int depth) 9.785 +{ 9.786 + struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr); 9.787 + 9.788 + for (c=tc->child;c;c=c->next) { 9.789 + if (c->name == TALLOC_MAGIC_REFERENCE) { 9.790 + struct talloc_reference_handle *handle = (void *)(c+1); 9.791 + const char *name2 = talloc_get_name(handle->ptr); 9.792 + fprintf(f, "%*sreference to: %s\n", depth*4, "", name2); 9.793 + } else { 9.794 + const char *name = talloc_get_name(c+1); 9.795 + fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d)\n", 9.796 + depth*4, "", 9.797 + name, 9.798 + (unsigned long)talloc_total_size(c+1), 9.799 + (unsigned long)talloc_total_blocks(c+1), 9.800 + talloc_reference_count(c+1)); 9.801 + talloc_report_depth(c+1, f, depth+1); 9.802 + } 9.803 + } 9.804 + 9.805 +} 9.806 + 9.807 +/* 9.808 + report on memory usage by all children of a pointer, giving a full tree view 9.809 +*/ 9.810 +void talloc_report_full(const void *ptr, FILE *f) 9.811 +{ 9.812 + if (ptr == NULL) { 9.813 + ptr = null_context; 9.814 + } 9.815 + if (ptr == NULL) return; 9.816 + 9.817 + fprintf(f,"full talloc report on '%s' (total %lu bytes in %lu blocks)\n", 9.818 + talloc_get_name(ptr), 9.819 + (unsigned long)talloc_total_size(ptr), 9.820 + (unsigned long)talloc_total_blocks(ptr)); 9.821 + 9.822 + talloc_report_depth(ptr, f, 1); 9.823 + fflush(f); 9.824 +} 9.825 + 9.826 +/* 9.827 + report on memory usage by all children of a pointer 9.828 +*/ 9.829 +void talloc_report(const void *ptr, FILE *f) 9.830 +{ 9.831 + struct talloc_chunk *c, *tc; 9.832 + 9.833 + if (ptr == NULL) { 9.834 + ptr = null_context; 9.835 + } 9.836 + if (ptr == NULL) return; 9.837 + 9.838 + fprintf(f,"talloc report on '%s' (total %lu bytes in %lu blocks)\n", 9.839 + talloc_get_name(ptr), 9.840 + (unsigned long)talloc_total_size(ptr), 9.841 + (unsigned long)talloc_total_blocks(ptr)); 9.842 + 9.843 + tc = talloc_chunk_from_ptr(ptr); 9.844 + 9.845 + for (c=tc->child;c;c=c->next) { 9.846 + fprintf(f, "\t%-30s contains %6lu bytes in %3lu blocks\n", 9.847 + talloc_get_name(c+1), 9.848 + (unsigned long)talloc_total_size(c+1), 9.849 + (unsigned long)talloc_total_blocks(c+1)); 9.850 + } 9.851 + fflush(f); 9.852 +} 9.853 + 9.854 +/* 9.855 + report on any memory hanging off the null context 9.856 +*/ 9.857 +static void talloc_report_null(void) 9.858 +{ 9.859 + if (talloc_total_size(null_context) != 0) { 9.860 + talloc_report(null_context, stderr); 9.861 + } 9.862 +} 9.863 + 9.864 +/* 9.865 + report on any memory hanging off the null context 9.866 +*/ 9.867 +static void talloc_report_null_full(void) 9.868 +{ 9.869 + if (talloc_total_size(null_context) != 0) { 9.870 + talloc_report_full(null_context, stderr); 9.871 + } 9.872 +} 9.873 + 9.874 +/* 9.875 + enable tracking of the NULL context 9.876 +*/ 9.877 +void talloc_enable_null_tracking(void) 9.878 +{ 9.879 + if (null_context == NULL) { 9.880 + null_context = talloc_named_const(NULL, 0, "null_context"); 9.881 + } 9.882 +} 9.883 + 9.884 +/* 9.885 + enable leak reporting on exit 9.886 +*/ 9.887 +void talloc_enable_leak_report(void) 9.888 +{ 9.889 + talloc_enable_null_tracking(); 9.890 + atexit(talloc_report_null); 9.891 +} 9.892 + 9.893 +/* 9.894 + enable full leak reporting on exit 9.895 +*/ 9.896 +void talloc_enable_leak_report_full(void) 9.897 +{ 9.898 + talloc_enable_null_tracking(); 9.899 + atexit(talloc_report_null_full); 9.900 +} 9.901 + 9.902 +/* 9.903 + talloc and zero memory. 9.904 +*/ 9.905 +void *_talloc_zero(const void *ctx, size_t size, const char *name) 9.906 +{ 9.907 + void *p = talloc_named_const(ctx, size, name); 9.908 + 9.909 + if (p) { 9.910 + memset(p, '\0', size); 9.911 + } 9.912 + 9.913 + return p; 9.914 +} 9.915 + 9.916 + 9.917 +/* 9.918 + memdup with a talloc. 9.919 +*/ 9.920 +void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name) 9.921 +{ 9.922 + void *newp = talloc_named_const(t, size, name); 9.923 + 9.924 + if (newp) { 9.925 + memcpy(newp, p, size); 9.926 + } 9.927 + 9.928 + return newp; 9.929 +} 9.930 + 9.931 +/* 9.932 + strdup with a talloc 9.933 +*/ 9.934 +char *talloc_strdup(const void *t, const char *p) 9.935 +{ 9.936 + char *ret; 9.937 + if (!p) { 9.938 + return NULL; 9.939 + } 9.940 + ret = talloc_memdup(t, p, strlen(p) + 1); 9.941 + if (ret) { 9.942 + talloc_set_name_const(ret, ret); 9.943 + } 9.944 + return ret; 9.945 +} 9.946 + 9.947 +/* 9.948 + strndup with a talloc 9.949 +*/ 9.950 +char *talloc_strndup(const void *t, const char *p, size_t n) 9.951 +{ 9.952 + size_t len; 9.953 + char *ret; 9.954 + 9.955 + for (len=0; p[len] && len<n; len++) ; 9.956 + 9.957 + ret = _talloc(t, len + 1); 9.958 + if (!ret) { return NULL; } 9.959 + memcpy(ret, p, len); 9.960 + ret[len] = 0; 9.961 + talloc_set_name_const(ret, ret); 9.962 + return ret; 9.963 +} 9.964 + 9.965 +#ifndef VA_COPY 9.966 +#ifdef HAVE_VA_COPY 9.967 +#define VA_COPY(dest, src) va_copy(dest, src) 9.968 +#elif defined(HAVE___VA_COPY) 9.969 +#define VA_COPY(dest, src) __va_copy(dest, src) 9.970 +#else 9.971 +#define VA_COPY(dest, src) (dest) = (src) 9.972 +#endif 9.973 +#endif 9.974 + 9.975 +char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) 9.976 +{ 9.977 + int len; 9.978 + char *ret; 9.979 + va_list ap2; 9.980 + 9.981 + VA_COPY(ap2, ap); 9.982 + 9.983 + len = vsnprintf(NULL, 0, fmt, ap2); 9.984 + 9.985 + ret = _talloc(t, len+1); 9.986 + if (ret) { 9.987 + VA_COPY(ap2, ap); 9.988 + vsnprintf(ret, len+1, fmt, ap2); 9.989 + talloc_set_name_const(ret, ret); 9.990 + } 9.991 + 9.992 + return ret; 9.993 +} 9.994 + 9.995 + 9.996 +/* 9.997 + Perform string formatting, and return a pointer to newly allocated 9.998 + memory holding the result, inside a memory pool. 9.999 + */ 9.1000 +char *talloc_asprintf(const void *t, const char *fmt, ...) 9.1001 +{ 9.1002 + va_list ap; 9.1003 + char *ret; 9.1004 + 9.1005 + va_start(ap, fmt); 9.1006 + ret = talloc_vasprintf(t, fmt, ap); 9.1007 + va_end(ap); 9.1008 + return ret; 9.1009 +} 9.1010 + 9.1011 + 9.1012 +/** 9.1013 + * Realloc @p s to append the formatted result of @p fmt and @p ap, 9.1014 + * and return @p s, which may have moved. Good for gradually 9.1015 + * accumulating output into a string buffer. 9.1016 + **/ 9.1017 + 9.1018 +static char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0); 9.1019 + 9.1020 +static char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) 9.1021 +{ 9.1022 + struct talloc_chunk *tc; 9.1023 + int len, s_len; 9.1024 + va_list ap2; 9.1025 + 9.1026 + if (s == NULL) { 9.1027 + return talloc_vasprintf(NULL, fmt, ap); 9.1028 + } 9.1029 + 9.1030 + tc = talloc_chunk_from_ptr(s); 9.1031 + 9.1032 + VA_COPY(ap2, ap); 9.1033 + 9.1034 + s_len = tc->size - 1; 9.1035 + len = vsnprintf(NULL, 0, fmt, ap2); 9.1036 + 9.1037 + s = talloc_realloc(NULL, s, char, s_len + len+1); 9.1038 + if (!s) return NULL; 9.1039 + 9.1040 + VA_COPY(ap2, ap); 9.1041 + 9.1042 + vsnprintf(s+s_len, len+1, fmt, ap2); 9.1043 + talloc_set_name_const(s, s); 9.1044 + 9.1045 + return s; 9.1046 +} 9.1047 + 9.1048 +/* 9.1049 + Realloc @p s to append the formatted result of @p fmt and return @p 9.1050 + s, which may have moved. Good for gradually accumulating output 9.1051 + into a string buffer. 9.1052 + */ 9.1053 +char *talloc_asprintf_append(char *s, const char *fmt, ...) 9.1054 +{ 9.1055 + va_list ap; 9.1056 + 9.1057 + va_start(ap, fmt); 9.1058 + s = talloc_vasprintf_append(s, fmt, ap); 9.1059 + va_end(ap); 9.1060 + return s; 9.1061 +} 9.1062 + 9.1063 +/* 9.1064 + alloc an array, checking for integer overflow in the array size 9.1065 +*/ 9.1066 +void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name) 9.1067 +{ 9.1068 + if (count >= MAX_TALLOC_SIZE/el_size) { 9.1069 + return NULL; 9.1070 + } 9.1071 + return talloc_named_const(ctx, el_size * count, name); 9.1072 +} 9.1073 + 9.1074 +/* 9.1075 + alloc an zero array, checking for integer overflow in the array size 9.1076 +*/ 9.1077 +void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name) 9.1078 +{ 9.1079 + if (count >= MAX_TALLOC_SIZE/el_size) { 9.1080 + return NULL; 9.1081 + } 9.1082 + return _talloc_zero(ctx, el_size * count, name); 9.1083 +} 9.1084 + 9.1085 + 9.1086 +/* 9.1087 + realloc an array, checking for integer overflow in the array size 9.1088 +*/ 9.1089 +void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name) 9.1090 +{ 9.1091 + if (count >= MAX_TALLOC_SIZE/el_size) { 9.1092 + return NULL; 9.1093 + } 9.1094 + return _talloc_realloc(ctx, ptr, el_size * count, name); 9.1095 +} 9.1096 + 9.1097 +/* 9.1098 + a function version of talloc_realloc(), so it can be passed as a function pointer 9.1099 + to libraries that want a realloc function (a realloc function encapsulates 9.1100 + all the basic capabilities of an allocation library, which is why this is useful) 9.1101 +*/ 9.1102 +void *talloc_realloc_fn(const void *context, void *ptr, size_t size) 9.1103 +{ 9.1104 + return _talloc_realloc(context, ptr, size, NULL); 9.1105 +} 9.1106 + 9.1107 + 9.1108 +static void talloc_autofree(void) 9.1109 +{ 9.1110 + talloc_free(cleanup_context); 9.1111 + cleanup_context = NULL; 9.1112 +} 9.1113 + 9.1114 +/* 9.1115 + return a context which will be auto-freed on exit 9.1116 + this is useful for reducing the noise in leak reports 9.1117 +*/ 9.1118 +void *talloc_autofree_context(void) 9.1119 +{ 9.1120 + if (cleanup_context == NULL) { 9.1121 + cleanup_context = talloc_named_const(NULL, 0, "autofree_context"); 9.1122 + atexit(talloc_autofree); 9.1123 + } 9.1124 + return cleanup_context; 9.1125 +} 9.1126 + 9.1127 +size_t talloc_get_size(const void *context) 9.1128 +{ 9.1129 + struct talloc_chunk *tc; 9.1130 + 9.1131 + if (context == NULL) 9.1132 + return 0; 9.1133 + 9.1134 + tc = talloc_chunk_from_ptr(context); 9.1135 + 9.1136 + return tc->size; 9.1137 +} 9.1138 + 9.1139 +talloc_fail_handler *talloc_set_fail_handler(talloc_fail_handler *handler, 9.1140 + void *data) 9.1141 +{ 9.1142 + talloc_fail_handler *old = malloc_fail_handler; 9.1143 + malloc_fail_handler = handler; 9.1144 + malloc_fail_data = data; 9.1145 + return old; 9.1146 +}
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 10.2 +++ b/tools/xenstore/talloc.h Tue Jun 07 12:43:58 2005 +0000 10.3 @@ -0,0 +1,134 @@ 10.4 +#ifndef _TALLOC_H_ 10.5 +#define _TALLOC_H_ 10.6 +/* 10.7 + Unix SMB/CIFS implementation. 10.8 + Samba temporary memory allocation functions 10.9 + 10.10 + Copyright (C) Andrew Tridgell 2004-2005 10.11 + 10.12 + This program is free software; you can redistribute it and/or modify 10.13 + it under the terms of the GNU General Public License as published by 10.14 + the Free Software Foundation; either version 2 of the License, or 10.15 + (at your option) any later version. 10.16 + 10.17 + This program is distributed in the hope that it will be useful, 10.18 + but WITHOUT ANY WARRANTY; without even the implied warranty of 10.19 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10.20 + GNU General Public License for more details. 10.21 + 10.22 + You should have received a copy of the GNU General Public License 10.23 + along with this program; if not, write to the Free Software 10.24 + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 10.25 +*/ 10.26 + 10.27 +/* this is only needed for compatibility with the old talloc */ 10.28 +typedef void TALLOC_CTX; 10.29 + 10.30 +/* 10.31 + this uses a little trick to allow __LINE__ to be stringified 10.32 +*/ 10.33 +#define _STRING_LINE_(s) #s 10.34 +#define _STRING_LINE2_(s) _STRING_LINE_(s) 10.35 +#define __LINESTR__ _STRING_LINE2_(__LINE__) 10.36 +#define __location__ __FILE__ ":" __LINESTR__ 10.37 + 10.38 +#ifndef TALLOC_DEPRECATED 10.39 +#define TALLOC_DEPRECATED 0 10.40 +#endif 10.41 + 10.42 +/* useful macros for creating type checked pointers */ 10.43 +#define talloc(ctx, type) (type *)talloc_named_const(ctx, sizeof(type), #type) 10.44 +#define talloc_size(ctx, size) talloc_named_const(ctx, size, __location__) 10.45 + 10.46 +#define talloc_new(ctx) talloc_named_const(ctx, 0, "talloc_new: " __location__) 10.47 + 10.48 +#define talloc_zero(ctx, type) (type *)_talloc_zero(ctx, sizeof(type), #type) 10.49 +#define talloc_zero_size(ctx, size) _talloc_zero(ctx, size, __location__) 10.50 + 10.51 +#define talloc_zero_array(ctx, type, count) (type *)_talloc_zero_array(ctx, sizeof(type), count, #type) 10.52 +#define talloc_array(ctx, type, count) (type *)_talloc_array(ctx, sizeof(type), count, #type) 10.53 +#define talloc_array_size(ctx, size, count) _talloc_array(ctx, size, count, __location__) 10.54 + 10.55 +#define talloc_realloc(ctx, p, type, count) (type *)_talloc_realloc_array(ctx, p, sizeof(type), count, #type) 10.56 +#define talloc_realloc_size(ctx, ptr, size) _talloc_realloc(ctx, ptr, size, __location__) 10.57 + 10.58 +#define talloc_memdup(t, p, size) _talloc_memdup(t, p, size, __location__) 10.59 + 10.60 +#define malloc_p(type) (type *)malloc(sizeof(type)) 10.61 +#define malloc_array_p(type, count) (type *)realloc_array(NULL, sizeof(type), count) 10.62 +#define realloc_p(p, type, count) (type *)realloc_array(p, sizeof(type), count) 10.63 + 10.64 +#define data_blob(ptr, size) data_blob_named(ptr, size, "DATA_BLOB: "__location__) 10.65 +#define data_blob_talloc(ctx, ptr, size) data_blob_talloc_named(ctx, ptr, size, "DATA_BLOB: "__location__) 10.66 +#define data_blob_dup_talloc(ctx, blob) data_blob_talloc_named(ctx, (blob)->data, (blob)->length, "DATA_BLOB: "__location__) 10.67 + 10.68 +#define talloc_set_type(ptr, type) talloc_set_name_const(ptr, #type) 10.69 +#define talloc_get_type(ptr, type) (type *)talloc_check_name(ptr, #type) 10.70 + 10.71 + 10.72 +#if TALLOC_DEPRECATED 10.73 +#define talloc_zero_p(ctx, type) talloc_zero(ctx, type) 10.74 +#define talloc_p(ctx, type) talloc(ctx, type) 10.75 +#define talloc_array_p(ctx, type, count) talloc_array(ctx, type, count) 10.76 +#define talloc_realloc_p(ctx, p, type, count) talloc_realloc(ctx, p, type, count) 10.77 +#define talloc_destroy(ctx) talloc_free(ctx) 10.78 +#endif 10.79 + 10.80 +#ifndef PRINTF_ATTRIBUTE 10.81 +#if (__GNUC__ >= 3) 10.82 +/** Use gcc attribute to check printf fns. a1 is the 1-based index of 10.83 + * the parameter containing the format, and a2 the index of the first 10.84 + * argument. Note that some gcc 2.x versions don't handle this 10.85 + * properly **/ 10.86 +#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2))) 10.87 +#else 10.88 +#define PRINTF_ATTRIBUTE(a1, a2) 10.89 +#endif 10.90 +#endif 10.91 + 10.92 + 10.93 +/* The following definitions come from talloc.c */ 10.94 +void *_talloc(const void *context, size_t size); 10.95 +void talloc_set_destructor(const void *ptr, int (*destructor)(void *)); 10.96 +void talloc_increase_ref_count(const void *ptr); 10.97 +void *talloc_reference(const void *context, const void *ptr); 10.98 +int talloc_unlink(const void *context, void *ptr); 10.99 +void talloc_set_name(const void *ptr, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3); 10.100 +void talloc_set_name_const(const void *ptr, const char *name); 10.101 +void *talloc_named(const void *context, size_t size, 10.102 + const char *fmt, ...) PRINTF_ATTRIBUTE(3,4); 10.103 +void *talloc_named_const(const void *context, size_t size, const char *name); 10.104 +const char *talloc_get_name(const void *ptr); 10.105 +void *talloc_check_name(const void *ptr, const char *name); 10.106 +void talloc_report_depth(const void *ptr, FILE *f, int depth); 10.107 +void *talloc_parent(const void *ptr); 10.108 +void *talloc_init(const char *fmt, ...) PRINTF_ATTRIBUTE(1,2); 10.109 +int talloc_free(void *ptr); 10.110 +void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name); 10.111 +void *talloc_steal(const void *new_ctx, const void *ptr); 10.112 +off_t talloc_total_size(const void *ptr); 10.113 +off_t talloc_total_blocks(const void *ptr); 10.114 +void talloc_report_full(const void *ptr, FILE *f); 10.115 +void talloc_report(const void *ptr, FILE *f); 10.116 +void talloc_enable_null_tracking(void); 10.117 +void talloc_enable_leak_report(void); 10.118 +void talloc_enable_leak_report_full(void); 10.119 +void *_talloc_zero(const void *ctx, size_t size, const char *name); 10.120 +void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name); 10.121 +char *talloc_strdup(const void *t, const char *p); 10.122 +char *talloc_strndup(const void *t, const char *p, size_t n); 10.123 +char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0); 10.124 +char *talloc_asprintf(const void *t, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3); 10.125 +char *talloc_asprintf_append(char *s, 10.126 + const char *fmt, ...) PRINTF_ATTRIBUTE(2,3); 10.127 +void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name); 10.128 +void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name); 10.129 +void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name); 10.130 +void *talloc_realloc_fn(const void *context, void *ptr, size_t size); 10.131 +void *talloc_autofree_context(void); 10.132 +size_t talloc_get_size(const void *ctx); 10.133 + 10.134 +typedef int talloc_fail_handler(void *); 10.135 +talloc_fail_handler *talloc_set_fail_handler(talloc_fail_handler *, void *); 10.136 +#endif 10.137 +
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 11.2 +++ b/tools/xenstore/talloc_guide.txt Tue Jun 07 12:43:58 2005 +0000 11.3 @@ -0,0 +1,569 @@ 11.4 +Using talloc in Samba4 11.5 +---------------------- 11.6 + 11.7 +Andrew Tridgell 11.8 +September 2004 11.9 + 11.10 +The most current version of this document is available at 11.11 + http://samba.org/ftp/unpacked/samba4/source/lib/talloc/talloc_guide.txt 11.12 + 11.13 +If you are used to talloc from Samba3 then please read this carefully, 11.14 +as talloc has changed a lot. 11.15 + 11.16 +The new talloc is a hierarchical, reference counted memory pool system 11.17 +with destructors. Quite a mounthful really, but not too bad once you 11.18 +get used to it. 11.19 + 11.20 +Perhaps the biggest change from Samba3 is that there is no distinction 11.21 +between a "talloc context" and a "talloc pointer". Any pointer 11.22 +returned from talloc() is itself a valid talloc context. This means 11.23 +you can do this: 11.24 + 11.25 + struct foo *X = talloc(mem_ctx, struct foo); 11.26 + X->name = talloc_strdup(X, "foo"); 11.27 + 11.28 +and the pointer X->name would be a "child" of the talloc context "X" 11.29 +which is itself a child of mem_ctx. So if you do talloc_free(mem_ctx) 11.30 +then it is all destroyed, whereas if you do talloc_free(X) then just X 11.31 +and X->name are destroyed, and if you do talloc_free(X->name) then 11.32 +just the name element of X is destroyed. 11.33 + 11.34 +If you think about this, then what this effectively gives you is an 11.35 +n-ary tree, where you can free any part of the tree with 11.36 +talloc_free(). 11.37 + 11.38 +If you find this confusing, then I suggest you run the testsuite to 11.39 +watch talloc in action. You may also like to add your own tests to 11.40 +testsuite.c to clarify how some particular situation is handled. 11.41 + 11.42 + 11.43 +Performance 11.44 +----------- 11.45 + 11.46 +All the additional features of talloc() over malloc() do come at a 11.47 +price. We have a simple performance test in Samba4 that measures 11.48 +talloc() versus malloc() performance, and it seems that talloc() is 11.49 +about 10% slower than malloc() on my x86 Debian Linux box. For Samba, 11.50 +the great reduction in code complexity that we get by using talloc 11.51 +makes this worthwhile, especially as the total overhead of 11.52 +talloc/malloc in Samba is already quite small. 11.53 + 11.54 + 11.55 +talloc API 11.56 +---------- 11.57 + 11.58 +The following is a complete guide to the talloc API. Read it all at 11.59 +least twice. 11.60 + 11.61 + 11.62 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.63 +(type *)talloc(const void *context, type); 11.64 + 11.65 +The talloc() macro is the core of the talloc library. It takes a 11.66 +memory context and a type, and returns a pointer to a new area of 11.67 +memory of the given type. 11.68 + 11.69 +The returned pointer is itself a talloc context, so you can use it as 11.70 +the context argument to more calls to talloc if you wish. 11.71 + 11.72 +The returned pointer is a "child" of the supplied context. This means 11.73 +that if you talloc_free() the context then the new child disappears as 11.74 +well. Alternatively you can free just the child. 11.75 + 11.76 +The context argument to talloc() can be NULL, in which case a new top 11.77 +level context is created. 11.78 + 11.79 + 11.80 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.81 +void *talloc_size(const void *context, size_t size); 11.82 + 11.83 +The function talloc_size() should be used when you don't have a 11.84 +convenient type to pass to talloc(). Unlike talloc(), it is not type 11.85 +safe (as it returns a void *), so you are on your own for type checking. 11.86 + 11.87 + 11.88 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.89 +int talloc_free(void *ptr); 11.90 + 11.91 +The talloc_free() function frees a piece of talloc memory, and all its 11.92 +children. You can call talloc_free() on any pointer returned by 11.93 +talloc(). 11.94 + 11.95 +The return value of talloc_free() indicates success or failure, with 0 11.96 +returned for success and -1 for failure. The only possible failure 11.97 +condition is if the pointer had a destructor attached to it and the 11.98 +destructor returned -1. See talloc_set_destructor() for details on 11.99 +destructors. 11.100 + 11.101 +If this pointer has an additional parent when talloc_free() is called 11.102 +then the memory is not actually released, but instead the most 11.103 +recently established parent is destroyed. See talloc_reference() for 11.104 +details on establishing additional parents. 11.105 + 11.106 +For more control on which parent is removed, see talloc_unlink() 11.107 + 11.108 +talloc_free() operates recursively on its children. 11.109 + 11.110 + 11.111 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.112 +int talloc_free_children(void *ptr); 11.113 + 11.114 +The talloc_free_children() walks along the list of all children of a 11.115 +talloc context and talloc_free()s only the children, not the context 11.116 +itself. 11.117 + 11.118 + 11.119 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.120 +void *talloc_reference(const void *context, const void *ptr); 11.121 + 11.122 +The talloc_reference() function makes "context" an additional parent 11.123 +of "ptr". 11.124 + 11.125 +The return value of talloc_reference() is always the original pointer 11.126 +"ptr", unless talloc ran out of memory in creating the reference in 11.127 +which case it will return NULL (each additional reference consumes 11.128 +around 48 bytes of memory on intel x86 platforms). 11.129 + 11.130 +If "ptr" is NULL, then the function is a no-op, and simply returns NULL. 11.131 + 11.132 +After creating a reference you can free it in one of the following 11.133 +ways: 11.134 + 11.135 + - you can talloc_free() any parent of the original pointer. That 11.136 + will reduce the number of parents of this pointer by 1, and will 11.137 + cause this pointer to be freed if it runs out of parents. 11.138 + 11.139 + - you can talloc_free() the pointer itself. That will destroy the 11.140 + most recently established parent to the pointer and leave the 11.141 + pointer as a child of its current parent. 11.142 + 11.143 +For more control on which parent to remove, see talloc_unlink() 11.144 + 11.145 + 11.146 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.147 +int talloc_unlink(const void *context, const void *ptr); 11.148 + 11.149 +The talloc_unlink() function removes a specific parent from ptr. The 11.150 +context passed must either be a context used in talloc_reference() 11.151 +with this pointer, or must be a direct parent of ptr. 11.152 + 11.153 +Note that if the parent has already been removed using talloc_free() 11.154 +then this function will fail and will return -1. Likewise, if "ptr" 11.155 +is NULL, then the function will make no modifications and return -1. 11.156 + 11.157 +Usually you can just use talloc_free() instead of talloc_unlink(), but 11.158 +sometimes it is useful to have the additional control on which parent 11.159 +is removed. 11.160 + 11.161 + 11.162 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.163 +void talloc_set_destructor(const void *ptr, int (*destructor)(void *)); 11.164 + 11.165 +The function talloc_set_destructor() sets the "destructor" for the 11.166 +pointer "ptr". A destructor is a function that is called when the 11.167 +memory used by a pointer is about to be released. The destructor 11.168 +receives the pointer as an argument, and should return 0 for success 11.169 +and -1 for failure. 11.170 + 11.171 +The destructor can do anything it wants to, including freeing other 11.172 +pieces of memory. A common use for destructors is to clean up 11.173 +operating system resources (such as open file descriptors) contained 11.174 +in the structure the destructor is placed on. 11.175 + 11.176 +You can only place one destructor on a pointer. If you need more than 11.177 +one destructor then you can create a zero-length child of the pointer 11.178 +and place an additional destructor on that. 11.179 + 11.180 +To remove a destructor call talloc_set_destructor() with NULL for the 11.181 +destructor. 11.182 + 11.183 +If your destructor attempts to talloc_free() the pointer that it is 11.184 +the destructor for then talloc_free() will return -1 and the free will 11.185 +be ignored. This would be a pointless operation anyway, as the 11.186 +destructor is only called when the memory is just about to go away. 11.187 + 11.188 + 11.189 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.190 +void talloc_increase_ref_count(const void *ptr); 11.191 + 11.192 +The talloc_increase_ref_count(ptr) function is exactly equivalent to: 11.193 + 11.194 + talloc_reference(NULL, ptr); 11.195 + 11.196 +You can use either syntax, depending on which you think is clearer in 11.197 +your code. 11.198 + 11.199 + 11.200 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.201 +void talloc_set_name(const void *ptr, const char *fmt, ...); 11.202 + 11.203 +Each talloc pointer has a "name". The name is used principally for 11.204 +debugging purposes, although it is also possible to set and get the 11.205 +name on a pointer in as a way of "marking" pointers in your code. 11.206 + 11.207 +The main use for names on pointer is for "talloc reports". See 11.208 +talloc_report() and talloc_report_full() for details. Also see 11.209 +talloc_enable_leak_report() and talloc_enable_leak_report_full(). 11.210 + 11.211 +The talloc_set_name() function allocates memory as a child of the 11.212 +pointer. It is logically equivalent to: 11.213 + talloc_set_name_const(ptr, talloc_asprintf(ptr, fmt, ...)); 11.214 + 11.215 +Note that multiple calls to talloc_set_name() will allocate more 11.216 +memory without releasing the name. All of the memory is released when 11.217 +the ptr is freed using talloc_free(). 11.218 + 11.219 + 11.220 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.221 +void talloc_set_name_const(const void *ptr, const char *name); 11.222 + 11.223 +The function talloc_set_name_const() is just like talloc_set_name(), 11.224 +but it takes a string constant, and is much faster. It is extensively 11.225 +used by the "auto naming" macros, such as talloc_p(). 11.226 + 11.227 +This function does not allocate any memory. It just copies the 11.228 +supplied pointer into the internal representation of the talloc 11.229 +ptr. This means you must not pass a name pointer to memory that will 11.230 +disappear before the ptr is freed with talloc_free(). 11.231 + 11.232 + 11.233 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.234 +void *talloc_named(const void *context, size_t size, const char *fmt, ...); 11.235 + 11.236 +The talloc_named() function creates a named talloc pointer. It is 11.237 +equivalent to: 11.238 + 11.239 + ptr = talloc_size(context, size); 11.240 + talloc_set_name(ptr, fmt, ....); 11.241 + 11.242 + 11.243 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.244 +void *talloc_named_const(const void *context, size_t size, const char *name); 11.245 + 11.246 +This is equivalent to: 11.247 + 11.248 + ptr = talloc_size(context, size); 11.249 + talloc_set_name_const(ptr, name); 11.250 + 11.251 + 11.252 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.253 +const char *talloc_get_name(const void *ptr); 11.254 + 11.255 +This returns the current name for the given talloc pointer. See 11.256 +talloc_set_name() for details. 11.257 + 11.258 + 11.259 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.260 +void *talloc_init(const char *fmt, ...); 11.261 + 11.262 +This function creates a zero length named talloc context as a top 11.263 +level context. It is equivalent to: 11.264 + 11.265 + talloc_named(NULL, 0, fmt, ...); 11.266 + 11.267 + 11.268 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.269 +void *talloc_new(void *ctx); 11.270 + 11.271 +This is a utility macro that creates a new memory context hanging 11.272 +off an exiting context, automatically naming it "talloc_new: __location__" 11.273 +where __location__ is the source line it is called from. It is 11.274 +particularly useful for creating a new temporary working context. 11.275 + 11.276 + 11.277 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.278 +(type *)talloc_realloc(const void *context, void *ptr, type, count); 11.279 + 11.280 +The talloc_realloc() macro changes the size of a talloc 11.281 +pointer. The "count" argument is the number of elements of type "type" 11.282 +that you want the resulting pointer to hold. 11.283 + 11.284 +talloc_realloc() has the following equivalences: 11.285 + 11.286 + talloc_realloc(context, NULL, type, 1) ==> talloc(context, type); 11.287 + talloc_realloc(context, NULL, type, N) ==> talloc_array(context, type, N); 11.288 + talloc_realloc(context, ptr, type, 0) ==> talloc_free(ptr); 11.289 + 11.290 +The "context" argument is only used if "ptr" is not NULL, otherwise it 11.291 +is ignored. 11.292 + 11.293 +talloc_realloc() returns the new pointer, or NULL on failure. The call 11.294 +will fail either due to a lack of memory, or because the pointer has 11.295 +more than one parent (see talloc_reference()). 11.296 + 11.297 + 11.298 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.299 +void *talloc_realloc_size(const void *context, void *ptr, size_t size); 11.300 + 11.301 +the talloc_realloc_size() function is useful when the type is not 11.302 +known so the typesafe talloc_realloc() cannot be used. 11.303 + 11.304 + 11.305 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.306 +void *talloc_steal(const void *new_ctx, const void *ptr); 11.307 + 11.308 +The talloc_steal() function changes the parent context of a talloc 11.309 +pointer. It is typically used when the context that the pointer is 11.310 +currently a child of is going to be freed and you wish to keep the 11.311 +memory for a longer time. 11.312 + 11.313 +The talloc_steal() function returns the pointer that you pass it. It 11.314 +does not have any failure modes. 11.315 + 11.316 +NOTE: It is possible to produce loops in the parent/child relationship 11.317 +if you are not careful with talloc_steal(). No guarantees are provided 11.318 +as to your sanity or the safety of your data if you do this. 11.319 + 11.320 +talloc_steal (new_ctx, NULL) will return NULL with no sideeffects. 11.321 + 11.322 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.323 +off_t talloc_total_size(const void *ptr); 11.324 + 11.325 +The talloc_total_size() function returns the total size in bytes used 11.326 +by this pointer and all child pointers. Mostly useful for debugging. 11.327 + 11.328 +Passing NULL is allowed, but it will only give a meaningful result if 11.329 +talloc_enable_leak_report() or talloc_enable_leak_report_full() has 11.330 +been called. 11.331 + 11.332 + 11.333 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.334 +off_t talloc_total_blocks(const void *ptr); 11.335 + 11.336 +The talloc_total_blocks() function returns the total memory block 11.337 +count used by this pointer and all child pointers. Mostly useful for 11.338 +debugging. 11.339 + 11.340 +Passing NULL is allowed, but it will only give a meaningful result if 11.341 +talloc_enable_leak_report() or talloc_enable_leak_report_full() has 11.342 +been called. 11.343 + 11.344 + 11.345 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.346 +void talloc_report(const void *ptr, FILE *f); 11.347 + 11.348 +The talloc_report() function prints a summary report of all memory 11.349 +used by ptr. One line of report is printed for each immediate child of 11.350 +ptr, showing the total memory and number of blocks used by that child. 11.351 + 11.352 +You can pass NULL for the pointer, in which case a report is printed 11.353 +for the top level memory context, but only if 11.354 +talloc_enable_leak_report() or talloc_enable_leak_report_full() has 11.355 +been called. 11.356 + 11.357 + 11.358 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.359 +void talloc_report_full(const void *ptr, FILE *f); 11.360 + 11.361 +This provides a more detailed report than talloc_report(). It will 11.362 +recursively print the ensire tree of memory referenced by the 11.363 +pointer. References in the tree are shown by giving the name of the 11.364 +pointer that is referenced. 11.365 + 11.366 +You can pass NULL for the pointer, in which case a report is printed 11.367 +for the top level memory context, but only if 11.368 +talloc_enable_leak_report() or talloc_enable_leak_report_full() has 11.369 +been called. 11.370 + 11.371 + 11.372 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.373 +void talloc_enable_leak_report(void); 11.374 + 11.375 +This enables calling of talloc_report(NULL, stderr) when the program 11.376 +exits. In Samba4 this is enabled by using the --leak-report command 11.377 +line option. 11.378 + 11.379 +For it to be useful, this function must be called before any other 11.380 +talloc function as it establishes a "null context" that acts as the 11.381 +top of the tree. If you don't call this function first then passing 11.382 +NULL to talloc_report() or talloc_report_full() won't give you the 11.383 +full tree printout. 11.384 + 11.385 +Here is a typical talloc report: 11.386 + 11.387 +talloc report on 'null_context' (total 267 bytes in 15 blocks) 11.388 + libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks 11.389 + libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks 11.390 + iconv(UTF8,CP850) contains 42 bytes in 2 blocks 11.391 + libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks 11.392 + iconv(CP850,UTF8) contains 42 bytes in 2 blocks 11.393 + iconv(UTF8,UTF-16LE) contains 45 bytes in 2 blocks 11.394 + iconv(UTF-16LE,UTF8) contains 45 bytes in 2 blocks 11.395 + 11.396 + 11.397 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.398 +void talloc_enable_leak_report_full(void); 11.399 + 11.400 +This enables calling of talloc_report_full(NULL, stderr) when the 11.401 +program exits. In Samba4 this is enabled by using the 11.402 +--leak-report-full command line option. 11.403 + 11.404 +For it to be useful, this function must be called before any other 11.405 +talloc function as it establishes a "null context" that acts as the 11.406 +top of the tree. If you don't call this function first then passing 11.407 +NULL to talloc_report() or talloc_report_full() won't give you the 11.408 +full tree printout. 11.409 + 11.410 +Here is a typical full report: 11.411 + 11.412 +full talloc report on 'root' (total 18 bytes in 8 blocks) 11.413 + p1 contains 18 bytes in 7 blocks (ref 0) 11.414 + r1 contains 13 bytes in 2 blocks (ref 0) 11.415 + reference to: p2 11.416 + p2 contains 1 bytes in 1 blocks (ref 1) 11.417 + x3 contains 1 bytes in 1 blocks (ref 0) 11.418 + x2 contains 1 bytes in 1 blocks (ref 0) 11.419 + x1 contains 1 bytes in 1 blocks (ref 0) 11.420 + 11.421 + 11.422 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.423 +void talloc_enable_null_tracking(void); 11.424 + 11.425 +This enables tracking of the NULL memory context without enabling leak 11.426 +reporting on exit. Useful for when you want to do your own leak 11.427 +reporting call via talloc_report_null_full(); 11.428 + 11.429 + 11.430 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.431 +(type *)talloc_zero(const void *ctx, type); 11.432 + 11.433 +The talloc_zero() macro is equivalent to: 11.434 + 11.435 + ptr = talloc(ctx, type); 11.436 + if (ptr) memset(ptr, 0, sizeof(type)); 11.437 + 11.438 + 11.439 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.440 +void *talloc_zero_size(const void *ctx, size_t size) 11.441 + 11.442 +The talloc_zero_size() function is useful when you don't have a known type 11.443 + 11.444 + 11.445 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.446 +void *talloc_memdup(const void *ctx, const void *p, size_t size); 11.447 + 11.448 +The talloc_memdup() function is equivalent to: 11.449 + 11.450 + ptr = talloc_size(ctx, size); 11.451 + if (ptr) memcpy(ptr, p, size); 11.452 + 11.453 + 11.454 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.455 +char *talloc_strdup(const void *ctx, const char *p); 11.456 + 11.457 +The talloc_strdup() function is equivalent to: 11.458 + 11.459 + ptr = talloc_size(ctx, strlen(p)+1); 11.460 + if (ptr) memcpy(ptr, p, strlen(p)+1); 11.461 + 11.462 +This functions sets the name of the new pointer to the passed 11.463 +string. This is equivalent to: 11.464 + talloc_set_name_const(ptr, ptr) 11.465 + 11.466 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.467 +char *talloc_strndup(const void *t, const char *p, size_t n); 11.468 + 11.469 +The talloc_strndup() function is the talloc equivalent of the C 11.470 +library function strndup() 11.471 + 11.472 +This functions sets the name of the new pointer to the passed 11.473 +string. This is equivalent to: 11.474 + talloc_set_name_const(ptr, ptr) 11.475 + 11.476 + 11.477 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.478 +char *talloc_vasprintf(const void *t, const char *fmt, va_list ap); 11.479 + 11.480 +The talloc_vasprintf() function is the talloc equivalent of the C 11.481 +library function vasprintf() 11.482 + 11.483 + 11.484 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.485 +char *talloc_asprintf(const void *t, const char *fmt, ...); 11.486 + 11.487 +The talloc_asprintf() function is the talloc equivalent of the C 11.488 +library function asprintf() 11.489 + 11.490 +This functions sets the name of the new pointer to the passed 11.491 +string. This is equivalent to: 11.492 + talloc_set_name_const(ptr, ptr) 11.493 + 11.494 + 11.495 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.496 +char *talloc_asprintf_append(char *s, const char *fmt, ...); 11.497 + 11.498 +The talloc_asprintf_append() function appends the given formatted 11.499 +string to the given string. 11.500 + 11.501 + 11.502 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.503 +(type *)talloc_array(const void *ctx, type, uint_t count); 11.504 + 11.505 +The talloc_array() macro is equivalent to: 11.506 + 11.507 + (type *)talloc_size(ctx, sizeof(type) * count); 11.508 + 11.509 +except that it provides integer overflow protection for the multiply, 11.510 +returning NULL if the multiply overflows. 11.511 + 11.512 + 11.513 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.514 +void *talloc_array_size(const void *ctx, size_t size, uint_t count); 11.515 + 11.516 +The talloc_array_size() function is useful when the type is not 11.517 +known. It operates in the same way as talloc_array(), but takes a size 11.518 +instead of a type. 11.519 + 11.520 + 11.521 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.522 +void *talloc_realloc_fn(const void *ctx, void *ptr, size_t size); 11.523 + 11.524 +This is a non-macro version of talloc_realloc(), which is useful 11.525 +as libraries sometimes want a ralloc function pointer. A realloc() 11.526 +implementation encapsulates the functionality of malloc(), free() and 11.527 +realloc() in one call, which is why it is useful to be able to pass 11.528 +around a single function pointer. 11.529 + 11.530 + 11.531 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.532 +void *talloc_autofree_context(void); 11.533 + 11.534 +This is a handy utility function that returns a talloc context 11.535 +which will be automatically freed on program exit. This can be used 11.536 +to reduce the noise in memory leak reports. 11.537 + 11.538 + 11.539 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.540 +void *talloc_check_name(const void *ptr, const char *name); 11.541 + 11.542 +This function checks if a pointer has the specified name. If it does 11.543 +then the pointer is returned. It it doesn't then NULL is returned. 11.544 + 11.545 + 11.546 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.547 +(type *)talloc_get_type(const void *ptr, type); 11.548 + 11.549 +This macro allows you to do type checking on talloc pointers. It is 11.550 +particularly useful for void* private pointers. It is equivalent to 11.551 +this: 11.552 + 11.553 + (type *)talloc_check_name(ptr, #type) 11.554 + 11.555 + 11.556 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.557 +talloc_set_type(const void *ptr, type); 11.558 + 11.559 +This macro allows you to force the name of a pointer to be a 11.560 +particular type. This can be used in conjunction with 11.561 +talloc_get_type() to do type checking on void* pointers. 11.562 + 11.563 +It is equivalent to this: 11.564 + talloc_set_name_const(ptr, #type) 11.565 + 11.566 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 11.567 +talloc_get_size(const void *ctx); 11.568 + 11.569 +This function lets you know the amount of memory alloced so far by 11.570 +this context. It does NOT account for subcontext memory. 11.571 +This can be used to calculate the size of an array. 11.572 +
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 12.2 +++ b/tools/xenstore/testsuite/01simple.sh Tue Jun 07 12:43:58 2005 +0000 12.3 @@ -0,0 +1,4 @@ 12.4 +#! /bin/sh 12.5 + 12.6 +# Create an entry, read it. 12.7 +[ "`echo -e 'write /test create contents\nread /test' | ./xs_test 2>&1`" = "contents" ]
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 13.2 +++ b/tools/xenstore/testsuite/02directory.sh Tue Jun 07 12:43:58 2005 +0000 13.3 @@ -0,0 +1,31 @@ 13.4 +#! /bin/sh 13.5 + 13.6 +# Root directory has nothing in it. 13.7 +[ "`echo -e 'dir /' | ./xs_test 2>&1`" = "" ] 13.8 + 13.9 +# Create a file. 13.10 +[ "`echo -e 'write /test create contents' | ./xs_test 2>&1`" = "" ] 13.11 + 13.12 +# Directory shows it. 13.13 +[ "`echo -e 'dir /' | ./xs_test 2>&1`" = "test" ] 13.14 + 13.15 +# Make a new directory. 13.16 +[ "`echo -e 'mkdir /dir' | ./xs_test 2>&1`" = "" ] 13.17 + 13.18 +# Check it's there. 13.19 +DIR="`echo -e 'dir /' | ./xs_test 2>&1`" 13.20 +[ "$DIR" = "test 13.21 +dir" ] || [ "$DIR" = "dir 13.22 +test" ] 13.23 + 13.24 +# Check it's empty. 13.25 +[ "`echo -e 'dir /dir' | ./xs_test 2>&1`" = "" ] 13.26 + 13.27 +# Create a file, check it exists. 13.28 +[ "`echo -e 'write /dir/test2 create contents2' | ./xs_test 2>&1`" = "" ] 13.29 +[ "`echo -e 'dir /dir' | ./xs_test 2>&1`" = "test2" ] 13.30 +[ "`echo -e 'read /dir/test2' | ./xs_test 2>&1`" = "contents2" ] 13.31 + 13.32 +# Creating dir over the top should fail. 13.33 +[ "`echo -e 'mkdir /dir' | ./xs_test 2>&1`" = "FATAL: mkdir: File exists" ] 13.34 +[ "`echo -e 'mkdir /dir/test2' | ./xs_test 2>&1`" = "FATAL: mkdir: File exists" ]
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 14.2 +++ b/tools/xenstore/testsuite/03write.sh Tue Jun 07 12:43:58 2005 +0000 14.3 @@ -0,0 +1,17 @@ 14.4 +#! /bin/sh 14.5 + 14.6 +# Write without create fails. 14.7 +[ "`echo -e 'write /test none contents' | ./xs_test 2>&1`" = "FATAL: write: No such file or directory" ] 14.8 + 14.9 +# Exclusive write succeeds 14.10 +[ "`echo -e 'write /test excl contents' | ./xs_test 2>&1`" = "" ] 14.11 +[ "`echo -e 'read /test' | ./xs_test 2>&1`" = "contents" ] 14.12 + 14.13 +# Exclusive write fails to overwrite. 14.14 +[ "`echo -e 'write /test excl contents' | ./xs_test 2>&1`" = "FATAL: write: File exists" ] 14.15 + 14.16 +# Non-exclusive overwrite succeeds. 14.17 +[ "`echo -e 'write /test none contents2' | ./xs_test 2>&1`" = "" ] 14.18 +[ "`echo -e 'read /test' | ./xs_test 2>&1`" = "contents2" ] 14.19 +[ "`echo -e 'write /test create contents3' | ./xs_test 2>&1`" = "" ] 14.20 +[ "`echo -e 'read /test' | ./xs_test 2>&1`" = "contents3" ]
15.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 15.2 +++ b/tools/xenstore/testsuite/04rm.sh Tue Jun 07 12:43:58 2005 +0000 15.3 @@ -0,0 +1,18 @@ 15.4 +#! /bin/sh 15.5 + 15.6 +# Remove non-existant fails. 15.7 +[ "`echo -e 'rm /test' | ./xs_test 2>&1`" = "FATAL: rm: No such file or directory" ] 15.8 +[ "`echo -e 'rm /dir/test' | ./xs_test 2>&1`" = "FATAL: rm: No such file or directory" ] 15.9 + 15.10 +# Create file and remove it 15.11 +[ "`echo -e 'write /test excl contents' | ./xs_test 2>&1`" = "" ] 15.12 +[ "`echo -e 'rm /test' | ./xs_test 2>&1`" = "" ] 15.13 + 15.14 +# Create directory and remove it. 15.15 +[ "`echo -e 'mkdir /dir' | ./xs_test 2>&1`" = "" ] 15.16 +[ "`echo -e 'rm /dir' | ./xs_test 2>&1`" = "" ] 15.17 + 15.18 +# Create directory, create file, remove all. 15.19 +[ "`echo -e 'mkdir /dir' | ./xs_test 2>&1`" = "" ] 15.20 +[ "`echo -e 'write /dir/test excl contents' | ./xs_test 2>&1`" = "" ] 15.21 +[ "`echo -e 'rm /dir' | ./xs_test 2>&1`" = "" ]
16.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 16.2 +++ b/tools/xenstore/testsuite/05filepermissions.sh Tue Jun 07 12:43:58 2005 +0000 16.3 @@ -0,0 +1,49 @@ 16.4 +#! /bin/sh 16.5 + 16.6 +# Fail to get perms on non-existent file. 16.7 +[ "`echo -e 'getperm /test' | ./xs_test 2>&1`" = "FATAL: getperm: No such file or directory" ] 16.8 +[ "`echo -e 'getperm /dir/test' | ./xs_test 2>&1`" = "FATAL: getperm: No such file or directory" ] 16.9 + 16.10 +# Create file: we own it, noone has access. 16.11 +[ "`echo -e 'write /test excl contents' | ./xs_test 2>&1`" = "" ] 16.12 +[ "`echo -e 'getperm /test' | ./xs_test 2>&1`" = "0 NONE" ] 16.13 +[ "`echo -e 'setid 1\ngetperm /test' | ./xs_test 2>&1`" = "FATAL: getperm: Permission denied" ] 16.14 +[ "`echo -e 'setid 1\nread /test' | ./xs_test 2>&1`" = "FATAL: read: Permission denied" ] 16.15 +[ "`echo -e 'setid 1\nwrite /test none contents2' | ./xs_test 2>&1`" = "FATAL: write: Permission denied" ] 16.16 + 16.17 +# Grant everyone read access to file. 16.18 +[ "`echo -e 'setperm /test 0 READ' | ./xs_test 2>&1`" = "" ] 16.19 +[ "`echo -e 'setid 1\ngetperm /test' | ./xs_test 2>&1`" = "0 READ" ] 16.20 +[ "`echo -e 'setid 1\nread /test' | ./xs_test 2>&1`" = "contents" ] 16.21 +[ "`echo -e 'setid 1\nwrite /test none contents2' | ./xs_test 2>&1`" = "FATAL: write: Permission denied" ] 16.22 + 16.23 +# Grant everyone write access to file. 16.24 +[ "`echo -e 'setperm /test 0 WRITE' | ./xs_test 2>&1`" = "" ] 16.25 +[ "`echo -e 'setid 1\ngetperm /test' | ./xs_test 2>&1`" = "FATAL: getperm: Permission denied" ] 16.26 +[ "`echo -e 'setid 1\nread /test' | ./xs_test 2>&1`" = "FATAL: read: Permission denied" ] 16.27 +[ "`echo -e 'setid 1\nwrite /test none contents2' | ./xs_test 2>&1`" = "" ] 16.28 +[ "`echo -e 'read /test' | ./xs_test 2>&1`" = "contents2" ] 16.29 + 16.30 +# Grant everyone both read and write access. 16.31 +[ "`echo -e 'setperm /test 0 READ/WRITE' | ./xs_test 2>&1`" = "" ] 16.32 +[ "`echo -e 'setid 1\ngetperm /test' | ./xs_test 2>&1`" = "0 READ/WRITE" ] 16.33 +[ "`echo -e 'setid 1\nread /test' | ./xs_test 2>&1`" = "contents2" ] 16.34 +[ "`echo -e 'setid 1\nwrite /test none contents3' | ./xs_test 2>&1`" = "" ] 16.35 +[ "`echo -e 'setid 1\nread /test' | ./xs_test 2>&1`" = "contents3" ] 16.36 + 16.37 +# Change so that user 1 owns it, noone else can do anything. 16.38 +[ "`echo -e 'setperm /test 1 NONE' | ./xs_test 2>&1`" = "" ] 16.39 +[ "`echo -e 'setid 1\ngetperm /test' | ./xs_test 2>&1`" = "1 NONE" ] 16.40 +[ "`echo -e 'setid 1\nread /test' | ./xs_test 2>&1`" = "contents3" ] 16.41 +[ "`echo -e 'setid 1\nwrite /test none contents4' | ./xs_test 2>&1`" = "" ] 16.42 + 16.43 +# User 2 can do nothing. 16.44 +[ "`echo -e 'setid 2\nsetperm /test 2 NONE' | ./xs_test 2>&1`" = "FATAL: setperm: Permission denied" ] 16.45 +[ "`echo -e 'setid 2\ngetperm /test' | ./xs_test 2>&1`" = "FATAL: getperm: Permission denied" ] 16.46 +[ "`echo -e 'setid 2\nread /test' | ./xs_test 2>&1`" = "FATAL: read: Permission denied" ] 16.47 +[ "`echo -e 'setid 2\nwrite /test none contents4' | ./xs_test 2>&1`" = "FATAL: write: Permission denied" ] 16.48 + 16.49 +# Tools can always access things. 16.50 +[ "`echo -e 'getperm /test' | ./xs_test 2>&1`" = "1 NONE" ] 16.51 +[ "`echo -e 'read /test' | ./xs_test 2>&1`" = "contents4" ] 16.52 +[ "`echo -e 'write /test none contents5' | ./xs_test 2>&1`" = "" ]
17.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 17.2 +++ b/tools/xenstore/testsuite/06dirpermissions.sh Tue Jun 07 12:43:58 2005 +0000 17.3 @@ -0,0 +1,61 @@ 17.4 +#! /bin/sh 17.5 + 17.6 +# Root directory: owned by tool, everyone has read access. 17.7 +[ "`echo -e 'getperm /' | ./xs_test 2>&1`" = "0 READ" ] 17.8 + 17.9 +# Create directory: we own it, noone has access. 17.10 +[ "`echo -e 'mkdir /dir' | ./xs_test 2>&1`" = "" ] 17.11 +[ "`echo -e 'getperm /dir' | ./xs_test 2>&1`" = "0 NONE" ] 17.12 +[ "`echo -e 'setid 1\ndir /dir' | ./xs_test 2>&1`" = "FATAL: dir: Permission denied" ] 17.13 +[ "`echo -e 'setid 1\nread /dir/test create contents2' | ./xs_test 2>&1`" = "FATAL: read: Permission denied" ] 17.14 +[ "`echo -e 'setid 1\nwrite /dir/test create contents2' | ./xs_test 2>&1`" = "FATAL: write: Permission denied" ] 17.15 + 17.16 +# Grant everyone read access to directoy. 17.17 +[ "`echo -e 'setperm /dir 0 READ' | ./xs_test 2>&1`" = "" ] 17.18 +[ "`echo -e 'setid 1\ngetperm /dir' | ./xs_test 2>&1`" = "0 READ" ] 17.19 +[ "`echo -e 'setid 1\ndir /dir' | ./xs_test 2>&1`" = "" ] 17.20 +[ "`echo -e 'setid 1\nwrite /dir/test create contents2' | ./xs_test 2>&1`" = "FATAL: write: Permission denied" ] 17.21 + 17.22 +# Grant everyone write access to directory. 17.23 +[ "`echo -e 'setperm /dir 0 WRITE' | ./xs_test 2>&1`" = "" ] 17.24 +[ "`echo -e 'setid 1\ngetperm /dir' | ./xs_test 2>&1`" = "FATAL: getperm: Permission denied" ] 17.25 +[ "`echo -e 'setid 1\ndir /dir' | ./xs_test 2>&1`" = "FATAL: dir: Permission denied" ] 17.26 +[ "`echo -e 'setid 1\nwrite /dir/test create contents' | ./xs_test 2>&1`" = "" ] 17.27 +[ "`echo -e 'read /dir/test' | ./xs_test 2>&1`" = "contents" ] 17.28 + 17.29 +# Grant everyone both read and write access. 17.30 +[ "`echo -e 'setperm /dir 0 READ/WRITE' | ./xs_test 2>&1`" = "" ] 17.31 +[ "`echo -e 'setid 1\ngetperm /dir' | ./xs_test 2>&1`" = "0 READ/WRITE" ] 17.32 +[ "`echo -e 'setid 1\ndir /dir' | ./xs_test 2>&1`" = "test" ] 17.33 +[ "`echo -e 'setid 1\nwrite /dir/test2 create contents' | ./xs_test 2>&1`" = "" ] 17.34 +[ "`echo -e 'setid 1\nread /dir/test2' | ./xs_test 2>&1`" = "contents" ] 17.35 + 17.36 +# Change so that user 1 owns it, noone else can do anything. 17.37 +[ "`echo -e 'setperm /dir 1 NONE' | ./xs_test 2>&1`" = "" ] 17.38 +[ "`echo -e 'setid 1\ngetperm /dir' | ./xs_test 2>&1`" = "1 NONE" ] 17.39 +[ "`echo -e 'setid 1\ndir /dir' | ./xs_test 2>&1 | sort`" = "test 17.40 +test2" ] 17.41 +[ "`echo -e 'setid 1\nwrite /dir/test3 create contents' | ./xs_test 2>&1`" = "" ] 17.42 + 17.43 +# User 2 can do nothing. Can't even tell if file exists. 17.44 +[ "`echo -e 'setid 2\nsetperm /dir 2 NONE' | ./xs_test 2>&1`" = "FATAL: setperm: Permission denied" ] 17.45 +[ "`echo -e 'setid 2\ngetperm /dir' | ./xs_test 2>&1`" = "FATAL: getperm: Permission denied" ] 17.46 +[ "`echo -e 'setid 2\ndir /dir' | ./xs_test 2>&1`" = "FATAL: dir: Permission denied" ] 17.47 +[ "`echo -e 'setid 2\nread /dir/test' | ./xs_test 2>&1`" = "FATAL: read: Permission denied" ] 17.48 +[ "`echo -e 'setid 2\nread /dir/test2' | ./xs_test 2>&1`" = "FATAL: read: Permission denied" ] 17.49 +[ "`echo -e 'setid 2\nread /dir/test3' | ./xs_test 2>&1`" = "FATAL: read: Permission denied" ] 17.50 +[ "`echo -e 'setid 2\nread /dir/test4' | ./xs_test 2>&1`" = "FATAL: read: Permission denied" ] 17.51 +[ "`echo -e 'setid 2\nwrite /dir/test none contents' | ./xs_test 2>&1`" = "FATAL: write: Permission denied" ] 17.52 +[ "`echo -e 'setid 2\nwrite /dir/test create contents' | ./xs_test 2>&1`" = "FATAL: write: Permission denied" ] 17.53 +[ "`echo -e 'setid 2\nwrite /dir/test excl contents' | ./xs_test 2>&1`" = "FATAL: write: Permission denied" ] 17.54 +[ "`echo -e 'setid 2\nwrite /dir/test4 none contents' | ./xs_test 2>&1`" = "FATAL: write: Permission denied" ] 17.55 +[ "`echo -e 'setid 2\nwrite /dir/test4 create contents' | ./xs_test 2>&1`" = "FATAL: write: Permission denied" ] 17.56 +[ "`echo -e 'setid 2\nwrite /dir/test4 excl contents' | ./xs_test 2>&1`" = "FATAL: write: Permission denied" ] 17.57 + 17.58 +# Tools can always access things. 17.59 +[ "`echo -e 'getperm /dir' | ./xs_test 2>&1`" = "1 NONE" ] 17.60 +[ "`echo -e 'dir /dir' | ./xs_test 2>&1 | sort`" = "test 17.61 +test2 17.62 +test3" ] 17.63 +[ "`echo -e 'write /dir/test4 create contents' | ./xs_test 2>&1`" = "" ] 17.64 +
18.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 18.2 +++ b/tools/xenstore/testsuite/07watch.sh Tue Jun 07 12:43:58 2005 +0000 18.3 @@ -0,0 +1,32 @@ 18.4 +#! /bin/sh 18.5 + 18.6 +# Watch something, write to it, check watch has fired. 18.7 +[ "`echo -e 'write /test create contents' | ./xs_test 2>&1`" = "" ] 18.8 + 18.9 +[ "`echo -e '1 watch /test 100\n2 write /test create contents2\n1 waitwatch\n1 ackwatch' | ./xs_test 2>&1`" = "1:/test" ] 18.10 + 18.11 +# Check that reads don't set it off. 18.12 +[ "`echo -e '1 watch /test 100\n2 read /test\n1 waitwatch' | ./xs_test 2>&1`" = "2:contents2 18.13 +1:waitwatch timeout" ] 18.14 + 18.15 +# mkdir, setperm and rm should (also /tests watching dirs) 18.16 +[ "`echo -e 'mkdir /dir' | ./xs_test 2>&1`" = "" ] 18.17 +[ "`echo -e '1 watch /dir 100\n2 mkdir /dir/newdir\n1 waitwatch\n1 ackwatch\n2 setperm /dir/newdir 0 READ\n1 waitwatch\n1 ackwatch\n2 rm /dir/newdir\n1 waitwatch\n1 ackwatch' | ./xs_test 2>&1`" = "1:/dir/newdir 18.18 +1:/dir/newdir 18.19 +1:/dir/newdir" ] 18.20 + 18.21 +# ignore watches while doing commands, should work. 18.22 +[ "`echo -e 'watch /dir 100\nwrite /dir/test create contents\nread /dir/test\nwaitwatch\nackwatch' | ./xs_test 2>&1`" = "contents 18.23 +/dir/test" ] 18.24 + 18.25 +# watch priority /test. 18.26 +[ "`echo -e '1 watch /dir 1\n3 watch /dir 3\n2 watch /dir 2\nwrite /dir/test create contents\n3 waitwatch\n3 ackwatch\n2 waitwatch\n2 ackwatch\n1 waitwatch\n1 ackwatch' | ./xs_test 2>&1`" = "3:/dir/test 18.27 +2:/dir/test 18.28 +1:/dir/test" ] 18.29 + 18.30 +# If one dies (without acking), the other should still get ack. 18.31 +[ "`echo -e '1 watch /dir 0\n2 watch /dir 1\nwrite /dir/test create contents\n2 waitwatch\n2 close\n1 waitwatch\n1 ackwatch' | ./xs_test 2>&1`" = "2:/dir/test 18.32 +1:/dir/test" ] 18.33 + 18.34 +# If one dies (without reading at all), the other should still get ack. 18.35 +[ "`echo -e '1 watch /dir 0\n2 watch /dir 1\nwrite /dir/test create contents\n2 close\n1 waitwatch\n1 ackwatch' | ./xs_test 2>&1`" = "1:/dir/test" ]
19.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 19.2 +++ b/tools/xenstore/testsuite/08transaction.sh Tue Jun 07 12:43:58 2005 +0000 19.3 @@ -0,0 +1,54 @@ 19.4 +#! /bin/sh 19.5 +# Test transactions. 19.6 + 19.7 +# Simple transaction: create a file inside transaction. 19.8 +[ "`echo -e '1 start / 19.9 +1 write /entry1 create contents 19.10 +2 dir / 19.11 +1 dir / 19.12 +1 commit 19.13 +2 read /entry1' | ./xs_test`" = "1:entry1 19.14 +2:contents" ] 19.15 +echo rm /entry1 | ./xs_test 19.16 + 19.17 +# Create a file and abort transaction. 19.18 +[ "`echo -e '1 start / 19.19 +1 write /entry1 create contents 19.20 +2 dir / 19.21 +1 dir / 19.22 +1 abort 19.23 +2 dir /' | ./xs_test`" = "1:entry1" ] 19.24 + 19.25 +echo write /entry1 create contents | ./xs_test 19.26 +# Delete in transaction, commit 19.27 +[ "`echo -e '1 start / 19.28 +1 rm /entry1 19.29 +2 dir / 19.30 +1 dir / 19.31 +1 commit 19.32 +2 dir /' | ./xs_test`" = "2:entry1" ] 19.33 + 19.34 +# Delete in transaction, abort. 19.35 +echo write /entry1 create contents | ./xs_test 19.36 +[ "`echo -e '1 start / 19.37 +1 rm /entry1 19.38 +2 dir / 19.39 +1 dir / 19.40 +1 abort 19.41 +2 dir /' | ./xs_test`" = "2:entry1 19.42 +2:entry1" ] 19.43 + 19.44 +# Transactions can take as long as the want... 19.45 +[ "`echo -e 'start / 19.46 +sleep 1 19.47 +rm /entry1 19.48 +commit 19.49 +dir /' | ./xs_test`" = "" ] 19.50 + 19.51 +# ... as long as noone is waiting. 19.52 +[ "`echo -e '1 start / 19.53 +2 mkdir /dir 19.54 +1 mkdir /dir 19.55 +1 dir / 19.56 +1 commit' | ./xs_test 2>&1`" = "1:dir 19.57 +FATAL: 1: commit: Connection timed out" ]
20.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 20.2 +++ b/tools/xenstore/testsuite/09domain.sh Tue Jun 07 12:43:58 2005 +0000 20.3 @@ -0,0 +1,15 @@ 20.4 +#! /bin/sh 20.5 +# Test domain communication. 20.6 + 20.7 +# Create a domain, write an entry. 20.8 +[ "`echo -e 'introduce 1 100 7 /my/home 20.9 +1 write /entry1 create contents 20.10 +dir /' | ./xs_test 2>&1`" = "handle is 1 20.11 +entry1" ] 20.12 + 20.13 +# Release that domain. 20.14 +[ "`echo -e 'release 1' | ./xs_test`" = "" ] 20.15 + 20.16 +# Introduce and release by same connection. 20.17 +[ "`echo -e 'introduce 1 100 7 /my/home 20.18 +release 1' | ./xs_test 2>&1`" = "handle is 1" ]
21.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 21.2 +++ b/tools/xenstore/testsuite/test.sh Tue Jun 07 12:43:58 2005 +0000 21.3 @@ -0,0 +1,44 @@ 21.4 +#! /bin/sh 21.5 + 21.6 +set -e 21.7 +set -m 21.8 + 21.9 +run_test() 21.10 +{ 21.11 + rm -rf $XENSTORED_ROOTDIR 21.12 + mkdir $XENSTORED_ROOTDIR 21.13 +# Weird failures with this. 21.14 + if type valgrind >/dev/null 2>&1; then 21.15 + valgrind -q --logfile-fd=3 ./xenstored_test --output-pid --no-fork 3>testsuite/tmp/vgout > /tmp/pid & 21.16 + while [ ! -s /tmp/pid ]; do sleep 0; done 21.17 + PID=`cat /tmp/pid` 21.18 + rm /tmp/pid 21.19 + else 21.20 + PID=`./xenstored_test --output-pid` 21.21 + fi 21.22 + if sh -e $2 $1; then 21.23 + if [ -s testsuite/tmp/vgout ]; then 21.24 + kill $PID 21.25 + echo VALGRIND errors: 21.26 + cat testsuite/tmp/vgout 21.27 + return 1 21.28 + fi 21.29 + echo shutdown | ./xs_test 21.30 + return 0 21.31 + else 21.32 + # In case daemon is wedged. 21.33 + kill $PID 21.34 + sleep 1 21.35 + return 1 21.36 + fi 21.37 +} 21.38 + 21.39 +for f in testsuite/[0-9]*.sh; do 21.40 + if run_test $f; then 21.41 + echo Test $f passed... 21.42 + else 21.43 + echo Test $f failed, running verbosely... 21.44 + run_test $f -x 21.45 + exit 1 21.46 + fi 21.47 +done
22.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 22.2 +++ b/tools/xenstore/utils.c Tue Jun 07 12:43:58 2005 +0000 22.3 @@ -0,0 +1,143 @@ 22.4 +#define _GNU_SOURCE 22.5 +#include <stdio.h> 22.6 +#include <stdarg.h> 22.7 +#include <stdlib.h> 22.8 +#include <string.h> 22.9 +#include <errno.h> 22.10 +#include <unistd.h> 22.11 +#include <fcntl.h> 22.12 +#include <sys/types.h> 22.13 +#include <signal.h> 22.14 + 22.15 +#include "utils.h" 22.16 + 22.17 +void xprintf(const char *fmt, ...) 22.18 +{ 22.19 + static FILE *out = NULL; 22.20 + va_list args; 22.21 + if (!out) 22.22 + out = fopen("/dev/console", "w"); 22.23 + if (!out) 22.24 + out = stderr; 22.25 + 22.26 + va_start(args, fmt); 22.27 + vfprintf(out, fmt, args); 22.28 + va_end(args); 22.29 + fflush(out); 22.30 +} 22.31 + 22.32 +void barf(const char *fmt, ...) 22.33 +{ 22.34 + char *str; 22.35 + va_list arglist; 22.36 + 22.37 + xprintf("FATAL: "); 22.38 + 22.39 + va_start(arglist, fmt); 22.40 + vasprintf(&str, fmt, arglist); 22.41 + va_end(arglist); 22.42 + 22.43 + xprintf("%s\n", str); 22.44 + free(str); 22.45 + exit(1); 22.46 +} 22.47 + 22.48 +void barf_perror(const char *fmt, ...) 22.49 +{ 22.50 + char *str; 22.51 + int err = errno; 22.52 + va_list arglist; 22.53 + 22.54 + xprintf("FATAL: "); 22.55 + 22.56 + va_start(arglist, fmt); 22.57 + vasprintf(&str, fmt, arglist); 22.58 + va_end(arglist); 22.59 + 22.60 + xprintf("%s: %s\n", str, strerror(err)); 22.61 + free(str); 22.62 + exit(1); 22.63 +} 22.64 + 22.65 +void *_realloc_array(void *ptr, size_t size, size_t num) 22.66 +{ 22.67 + if (num >= SIZE_MAX/size) 22.68 + return NULL; 22.69 + return realloc_nofail(ptr, size * num); 22.70 +} 22.71 + 22.72 +void *realloc_nofail(void *ptr, size_t size) 22.73 +{ 22.74 + ptr = realloc(ptr, size); 22.75 + if (ptr) 22.76 + return ptr; 22.77 + barf("realloc of %zu failed", size); 22.78 +} 22.79 + 22.80 +void *malloc_nofail(size_t size) 22.81 +{ 22.82 + void *ptr = malloc(size); 22.83 + if (ptr) 22.84 + return ptr; 22.85 + barf("malloc of %zu failed", size); 22.86 +} 22.87 + 22.88 +/* Stevens. */ 22.89 +void daemonize(void) 22.90 +{ 22.91 + pid_t pid; 22.92 + 22.93 + /* Separate from our parent via fork, so init inherits us. */ 22.94 + if ((pid = fork()) < 0) 22.95 + barf_perror("Failed to fork daemon"); 22.96 + if (pid != 0) 22.97 + exit(0); 22.98 + 22.99 + close(STDIN_FILENO); 22.100 + close(STDOUT_FILENO); 22.101 + close(STDERR_FILENO); 22.102 + 22.103 + /* Session leader so ^C doesn't whack us. */ 22.104 + setsid(); 22.105 + /* Move off any mount points we might be in. */ 22.106 + chdir("/"); 22.107 + /* Discard our parent's old-fashioned umask prejudices. */ 22.108 + umask(0); 22.109 +} 22.110 + 22.111 + 22.112 +/* This version adds one byte (for nul term) */ 22.113 +void *grab_file(const char *filename, unsigned long *size) 22.114 +{ 22.115 + unsigned int max = 16384; 22.116 + int ret, fd; 22.117 + void *buffer; 22.118 + 22.119 + if (streq(filename, "-")) 22.120 + fd = dup(STDIN_FILENO); 22.121 + else 22.122 + fd = open(filename, O_RDONLY, 0); 22.123 + 22.124 + if (fd < 0) 22.125 + return NULL; 22.126 + 22.127 + buffer = malloc(max+1); 22.128 + *size = 0; 22.129 + while ((ret = read(fd, buffer + *size, max - *size)) > 0) { 22.130 + *size += ret; 22.131 + if (*size == max) 22.132 + buffer = realloc(buffer, max *= 2 + 1); 22.133 + } 22.134 + if (ret < 0) { 22.135 + free(buffer); 22.136 + buffer = NULL; 22.137 + } else 22.138 + ((char *)buffer)[*size] = '\0'; 22.139 + close(fd); 22.140 + return buffer; 22.141 +} 22.142 + 22.143 +void release_file(void *data, unsigned long size __attribute__((unused))) 22.144 +{ 22.145 + free(data); 22.146 +}
23.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 23.2 +++ b/tools/xenstore/utils.h Tue Jun 07 12:43:58 2005 +0000 23.3 @@ -0,0 +1,61 @@ 23.4 +#ifndef _UTILS_H 23.5 +#define _UTILS_H 23.6 +#include <stdbool.h> 23.7 +#include <string.h> 23.8 +#include <stdint.h> 23.9 + 23.10 +/* Is A == B ? */ 23.11 +#define streq(a,b) (strcmp((a),(b)) == 0) 23.12 + 23.13 +/* Does A start with B ? */ 23.14 +#define strstarts(a,b) (strncmp((a),(b),strlen(b)) == 0) 23.15 + 23.16 +/* Does A end in B ? */ 23.17 +static inline bool strends(const char *a, const char *b) 23.18 +{ 23.19 + if (strlen(a) < strlen(b)) 23.20 + return false; 23.21 + 23.22 + return streq(a + strlen(a) - strlen(b), b); 23.23 +} 23.24 + 23.25 +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) 23.26 + 23.27 +#define ___stringify(x) #x 23.28 +#define __stringify(x) ___stringify(x) 23.29 + 23.30 +/* Convenient wrappers for malloc and realloc. Use them. */ 23.31 +#define new(type) ((type *)malloc_nofail(sizeof(type))) 23.32 +#define new_array(type, num) realloc_array((type *)0, (num)) 23.33 +#define realloc_array(ptr, num) ((__typeof__(ptr))_realloc_array((ptr), sizeof((*ptr)), (num))) 23.34 + 23.35 +void *malloc_nofail(size_t size); 23.36 +void *realloc_nofail(void *ptr, size_t size); 23.37 +void *_realloc_array(void *ptr, size_t size, size_t num); 23.38 + 23.39 +void barf(const char *fmt, ...) __attribute__((noreturn)); 23.40 +void barf_perror(const char *fmt, ...) __attribute__((noreturn)); 23.41 + 23.42 +/* This version adds one byte (for nul term) */ 23.43 +void *grab_file(const char *filename, unsigned long *size); 23.44 +void release_file(void *data, unsigned long size); 23.45 + 23.46 +/* For writing daemons, based on Stevens. */ 23.47 +void daemonize(void); 23.48 + 23.49 +/* Signal handling: returns fd to listen on. */ 23.50 +int signal_to_fd(int signal); 23.51 +void close_signal(int fd); 23.52 + 23.53 +void xprintf(const char *fmt, ...); 23.54 + 23.55 +#define eprintf(_fmt, _args...) xprintf("[ERR] %s" _fmt, __FUNCTION__, ##_args) 23.56 +#define iprintf(_fmt, _args...) xprintf("[INF] %s" _fmt, __FUNCTION__, ##_args) 23.57 + 23.58 +#ifdef DEBUG 23.59 +#define dprintf(_fmt, _args...) xprintf("[DBG] %s" _fmt, __FUNCTION__, ##_args) 23.60 +#else 23.61 +#define dprintf(_fmt, _args...) ((void)0) 23.62 +#endif 23.63 + 23.64 +#endif /* _UTILS_H */
24.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 24.2 +++ b/tools/xenstore/xenstored.h Tue Jun 07 12:43:58 2005 +0000 24.3 @@ -0,0 +1,81 @@ 24.4 +/* 24.5 + Simple prototyle Xen Store Daemon providing simple tree-like database. 24.6 + Copyright (C) 2005 Rusty Russell IBM Corporation 24.7 + 24.8 + This program is free software; you can redistribute it and/or modify 24.9 + it under the terms of the GNU General Public License as published by 24.10 + the Free Software Foundation; either version 2 of the License, or 24.11 + (at your option) any later version. 24.12 + 24.13 + This program is distributed in the hope that it will be useful, 24.14 + but WITHOUT ANY WARRANTY; without even the implied warranty of 24.15 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24.16 + GNU General Public License for more details. 24.17 + 24.18 + You should have received a copy of the GNU General Public License 24.19 + along with this program; if not, write to the Free Software 24.20 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 24.21 +*/ 24.22 +#ifndef _XENSTORED_H 24.23 +#define _XENSTORED_H 24.24 + 24.25 +enum xsd_sockmsg_type 24.26 +{ 24.27 + XS_DEBUG, 24.28 + XS_SHUTDOWN, 24.29 + XS_DIRECTORY, 24.30 + XS_READ, 24.31 + XS_GET_PERMS, 24.32 + XS_WATCH, 24.33 + XS_WATCH_ACK, 24.34 + XS_UNWATCH, 24.35 + XS_TRANSACTION_START, 24.36 + XS_TRANSACTION_END, 24.37 + XS_OP_READ_ONLY = XS_TRANSACTION_END, 24.38 + XS_INTRODUCE, 24.39 + XS_RELEASE, 24.40 + XS_GETDOMAINPATH, 24.41 + XS_WRITE, 24.42 + XS_MKDIR, 24.43 + XS_RM, 24.44 + XS_SET_PERMS, 24.45 + XS_WATCH_EVENT, 24.46 + XS_ERROR, 24.47 +}; 24.48 + 24.49 +#define XS_WRITE_NONE "NONE" 24.50 +#define XS_WRITE_CREATE "CREATE" 24.51 +#define XS_WRITE_CREATE_EXCL "CREATE|EXCL" 24.52 + 24.53 +/* We hand errors as strings, for portability. */ 24.54 +struct xsd_errors 24.55 +{ 24.56 + int errnum; 24.57 + const char *errstring; 24.58 +}; 24.59 +#define XSD_ERROR(x) { x, #x } 24.60 +static struct xsd_errors xsd_errors[] __attribute__((unused)) = { 24.61 + XSD_ERROR(EINVAL), 24.62 + XSD_ERROR(EACCES), 24.63 + XSD_ERROR(EEXIST), 24.64 + XSD_ERROR(EISDIR), 24.65 + XSD_ERROR(ENOENT), 24.66 + XSD_ERROR(ENOMEM), 24.67 + XSD_ERROR(ENOSPC), 24.68 + XSD_ERROR(EIO), 24.69 + XSD_ERROR(ENOTEMPTY), 24.70 + XSD_ERROR(ENOSYS), 24.71 + XSD_ERROR(EROFS), 24.72 + XSD_ERROR(EBUSY), 24.73 + XSD_ERROR(ETIMEDOUT), 24.74 + XSD_ERROR(EISCONN), 24.75 +}; 24.76 +struct xsd_sockmsg 24.77 +{ 24.78 + u32 type; 24.79 + u32 len; /* Length of data following this. */ 24.80 + 24.81 + /* Generally followed by nul-terminated string(s). */ 24.82 +}; 24.83 + 24.84 +#endif /* _XENSTORED_H */
25.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 25.2 +++ b/tools/xenstore/xenstored_core.c Tue Jun 07 12:43:58 2005 +0000 25.3 @@ -0,0 +1,1354 @@ 25.4 +/* 25.5 + Simple prototype Xen Store Daemon providing simple tree-like database. 25.6 + Copyright (C) 2005 Rusty Russell IBM Corporation 25.7 + 25.8 + This program is free software; you can redistribute it and/or modify 25.9 + it under the terms of the GNU General Public License as published by 25.10 + the Free Software Foundation; either version 2 of the License, or 25.11 + (at your option) any later version. 25.12 + 25.13 + This program is distributed in the hope that it will be useful, 25.14 + but WITHOUT ANY WARRANTY; without even the implied warranty of 25.15 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25.16 + GNU General Public License for more details. 25.17 + 25.18 + You should have received a copy of the GNU General Public License 25.19 + along with this program; if not, write to the Free Software 25.20 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 25.21 +*/ 25.22 + 25.23 +#include <sys/types.h> 25.24 +#include <sys/stat.h> 25.25 +#include <sys/socket.h> 25.26 +#include <sys/select.h> 25.27 +#include <sys/un.h> 25.28 +#include <sys/time.h> 25.29 +#include <time.h> 25.30 +#include <unistd.h> 25.31 +#include <fcntl.h> 25.32 +#include <stdbool.h> 25.33 +#include <stdio.h> 25.34 +#include <stdarg.h> 25.35 +#include <stdlib.h> 25.36 +#include <syslog.h> 25.37 +#include <string.h> 25.38 +#include <errno.h> 25.39 +#include <dirent.h> 25.40 +#include <getopt.h> 25.41 +#include <signal.h> 25.42 +#include <assert.h> 25.43 +#include <setjmp.h> 25.44 + 25.45 +//#define DEBUG 25.46 +#include "utils.h" 25.47 +#include "list.h" 25.48 +#include "talloc.h" 25.49 +#include "xs_lib.h" 25.50 +#include "xenstored.h" 25.51 +#include "xenstored_core.h" 25.52 +#include "xenstored_watch.h" 25.53 +#include "xenstored_transaction.h" 25.54 +#include "xenstored_domain.h" 25.55 + 25.56 +static bool verbose; 25.57 +static LIST_HEAD(connections); 25.58 + 25.59 +#ifdef TESTING 25.60 +static bool failtest = false; 25.61 + 25.62 +/* We override talloc's malloc. */ 25.63 +void *test_malloc(size_t size) 25.64 +{ 25.65 + /* 1 in 20 means only about 50% of connections establish. */ 25.66 + if (failtest && (random() % 32) == 0) 25.67 + return NULL; 25.68 + return malloc(size); 25.69 +} 25.70 + 25.71 +static void stop_failtest(int signum __attribute__((unused))) 25.72 +{ 25.73 + failtest = false; 25.74 +} 25.75 + 25.76 +/* Need these before we #define away write_all/mkdir in testing.h */ 25.77 +bool test_write_all(int fd, void *contents, unsigned int len); 25.78 +bool test_write_all(int fd, void *contents, unsigned int len) 25.79 +{ 25.80 + if (failtest && (random() % 8) == 0) { 25.81 + if (len) 25.82 + len = random() % len; 25.83 + write(fd, contents, len); 25.84 + errno = ENOSPC; 25.85 + return false; 25.86 + } 25.87 + return write_all(fd, contents, len); 25.88 +} 25.89 + 25.90 +int test_mkdir(const char *dir, int perms); 25.91 +int test_mkdir(const char *dir, int perms) 25.92 +{ 25.93 + if (failtest && (random() % 8) == 0) { 25.94 + errno = ENOSPC; 25.95 + return -1; 25.96 + } 25.97 + return mkdir(dir, perms); 25.98 +} 25.99 +#endif /* TESTING */ 25.100 + 25.101 +#include "xenstored_test.h" 25.102 + 25.103 +/* FIXME: Ideally, this should never be called. Some can be eliminated. */ 25.104 +/* Something is horribly wrong: shutdown immediately. */ 25.105 +void __attribute__((noreturn)) corrupt(struct connection *conn, 25.106 + const char *fmt, ...) 25.107 +{ 25.108 + va_list arglist; 25.109 + char *str; 25.110 + int saved_errno = errno; 25.111 + 25.112 + va_start(arglist, fmt); 25.113 + str = talloc_vasprintf(NULL, fmt, arglist); 25.114 + va_end(arglist); 25.115 + 25.116 + eprintf("xenstored corruption: connection id %i: err %s: %s", 25.117 + conn ? (int)conn->id : -1, strerror(saved_errno), str); 25.118 +#ifdef TESTING 25.119 + /* Allow them to attach debugger. */ 25.120 + sleep(30); 25.121 +#endif 25.122 + syslog(LOG_DAEMON, 25.123 + "xenstored corruption: connection id %i: err %s: %s", 25.124 + conn ? (int)conn->id : -1, strerror(saved_errno), str); 25.125 + _exit(2); 25.126 +} 25.127 + 25.128 +static bool write_message(struct connection *conn) 25.129 +{ 25.130 + int ret; 25.131 + struct buffered_data *out = conn->out; 25.132 + 25.133 + if (out->inhdr) { 25.134 + if (verbose) 25.135 + xprintf("Writing msg %i out to %p\n", 25.136 + out->hdr.msg.type, conn); 25.137 + ret = conn->write(conn, out->hdr.raw + out->used, 25.138 + sizeof(out->hdr) - out->used); 25.139 + if (ret < 0) 25.140 + return false; 25.141 + 25.142 + out->used += ret; 25.143 + if (out->used < sizeof(out->hdr)) 25.144 + return true; 25.145 + 25.146 + out->inhdr = false; 25.147 + out->used = 0; 25.148 + 25.149 + /* Second write might block if non-zero. */ 25.150 + if (out->hdr.msg.len) 25.151 + return true; 25.152 + } 25.153 + 25.154 + if (verbose) 25.155 + xprintf("Writing data len %i out to %p\n", 25.156 + out->hdr.msg.len, conn); 25.157 + ret = conn->write(conn, out->buffer + out->used, 25.158 + out->hdr.msg.len - out->used); 25.159 + 25.160 + if (ret < 0) 25.161 + return false; 25.162 + 25.163 + out->used += ret; 25.164 + if (out->used != out->hdr.msg.len) 25.165 + return true; 25.166 + 25.167 + conn->out = NULL; 25.168 + 25.169 + /* If this was an event, we wait for ack, otherwise we're done. */ 25.170 + if (!is_watch_event(conn, out)) 25.171 + talloc_free(out); 25.172 + 25.173 + queue_next_event(conn); 25.174 + return true; 25.175 +} 25.176 + 25.177 +static int destroy_conn(void *_conn) 25.178 +{ 25.179 + struct connection *conn = _conn; 25.180 + 25.181 + /* Flush outgoing if possible, but don't block. */ 25.182 + if (!conn->domain) { 25.183 + fd_set set; 25.184 + struct timeval none; 25.185 + 25.186 + FD_ZERO(&set); 25.187 + FD_SET(conn->fd, &set); 25.188 + none.tv_sec = none.tv_usec = 0; 25.189 + 25.190 + while (conn->out 25.191 + && select(conn->fd+1, NULL, &set, NULL, &none) == 1) 25.192 + if (!write_message(conn)) 25.193 + break; 25.194 + close(conn->fd); 25.195 + } 25.196 + list_del(&conn->list); 25.197 + return 0; 25.198 +} 25.199 + 25.200 +static int initialize_set(fd_set *inset, fd_set *outset, int sock, int ro_sock, 25.201 + int event_fd) 25.202 +{ 25.203 + struct connection *i; 25.204 + int max; 25.205 + 25.206 + FD_ZERO(inset); 25.207 + FD_ZERO(outset); 25.208 + FD_SET(sock, inset); 25.209 + max = sock; 25.210 + FD_SET(ro_sock, inset); 25.211 + if (ro_sock > max) 25.212 + max = ro_sock; 25.213 + FD_SET(event_fd, inset); 25.214 + if (event_fd > max) 25.215 + max = event_fd; 25.216 + list_for_each_entry(i, &connections, list) { 25.217 + if (i->domain) 25.218 + continue; 25.219 + if (!i->blocked) 25.220 + FD_SET(i->fd, inset); 25.221 + if (i->out) 25.222 + FD_SET(i->fd, outset); 25.223 + if (i->fd > max) 25.224 + max = i->fd; 25.225 + } 25.226 + return max; 25.227 +} 25.228 + 25.229 +/* Read everything from a talloc_open'ed fd. */ 25.230 +static void *read_all(int *fd, unsigned int *size) 25.231 +{ 25.232 + unsigned int max = 4; 25.233 + int ret; 25.234 + void *buffer = talloc_size(fd, max); 25.235 + 25.236 + *size = 0; 25.237 + while ((ret = read(*fd, buffer + *size, max - *size)) > 0) { 25.238 + *size += ret; 25.239 + if (*size == max) 25.240 + buffer = talloc_realloc_size(fd, buffer, max *= 2); 25.241 + } 25.242 + if (ret < 0) 25.243 + return NULL; 25.244 + return buffer; 25.245 +} 25.246 + 25.247 +static int destroy_fd(void *_fd) 25.248 +{ 25.249 + int *fd = _fd; 25.250 + close(*fd); 25.251 + return 0; 25.252 +} 25.253 + 25.254 +/* Return a pointer to an fd, self-closing and attached to this pathname. */ 25.255 +static int *talloc_open(const char *pathname, int flags, int mode) 25.256 +{ 25.257 + int *fd; 25.258 + 25.259 + fd = talloc(pathname, int); 25.260 + *fd = open(pathname, flags, mode); 25.261 + if (*fd < 0) { 25.262 + int saved_errno = errno; 25.263 + talloc_free(fd); 25.264 + errno = saved_errno; 25.265 + return NULL; 25.266 + } 25.267 + talloc_set_destructor(fd, destroy_fd); 25.268 + return fd; 25.269 +} 25.270 + 25.271 +/* Is child a subnode of parent, or equal? */ 25.272 +bool is_child(const char *child, const char *parent) 25.273 +{ 25.274 + unsigned int len = strlen(parent); 25.275 + 25.276 + /* / should really be "" for this algorithm to work, but that's a 25.277 + * usability nightmare. */ 25.278 + if (streq(parent, "/")) 25.279 + return true; 25.280 + 25.281 + if (strncmp(child, parent, len) != 0) 25.282 + return false; 25.283 + 25.284 + return child[len] == '/' || child[len] == '\0'; 25.285 +} 25.286 + 25.287 +/* Answer never ends in /. */ 25.288 +char *node_dir_outside_transaction(const char *node) 25.289 +{ 25.290 + if (streq(node, "/")) 25.291 + return talloc_strdup(node, xs_daemon_store()); 25.292 + return talloc_asprintf(node, "%s%s", xs_daemon_store(), node); 25.293 +} 25.294 + 25.295 +static char *node_dir(struct transaction *trans, const char *node) 25.296 +{ 25.297 + if (!trans || !within_transaction(trans, node)) 25.298 + return node_dir_outside_transaction(node); 25.299 + return node_dir_inside_transaction(trans, node); 25.300 +} 25.301 + 25.302 +static char *node_datafile(struct transaction *trans, const char *node) 25.303 +{ 25.304 + return talloc_asprintf(node, "%s/.data", node_dir(trans, node)); 25.305 +} 25.306 + 25.307 +static char *node_permfile(struct transaction *trans, const char *node) 25.308 +{ 25.309 + return talloc_asprintf(node, "%s/.perms", node_dir(trans, node)); 25.310 +} 25.311 + 25.312 +struct buffered_data *new_buffer(void *ctx) 25.313 +{ 25.314 + struct buffered_data *data; 25.315 + 25.316 + data = talloc(ctx, struct buffered_data); 25.317 + data->inhdr = true; 25.318 + data->used = 0; 25.319 + data->buffer = NULL; 25.320 + 25.321 + return data; 25.322 +} 25.323 + 25.324 +/* Return length of string (including nul) at this offset. */ 25.325 +unsigned int get_string(const struct buffered_data *data, unsigned int offset) 25.326 +{ 25.327 + const char *nul; 25.328 + 25.329 + if (offset >= data->used) 25.330 + return 0; 25.331 + 25.332 + nul = memchr(data->buffer + offset, 0, data->used - offset); 25.333 + if (!nul) 25.334 + return 0; 25.335 + 25.336 + return nul - (data->buffer + offset) + 1; 25.337 +} 25.338 + 25.339 +/* Break input into vectors, return the number, fill in up to num of them. */ 25.340 +unsigned int get_strings(struct buffered_data *data, 25.341 + char *vec[], unsigned int num) 25.342 +{ 25.343 + unsigned int off, i, len; 25.344 + 25.345 + off = i = 0; 25.346 + while ((len = get_string(data, off)) != 0) { 25.347 + if (i < num) 25.348 + vec[i] = data->buffer + off; 25.349 + i++; 25.350 + off += len; 25.351 + } 25.352 + return i; 25.353 +} 25.354 + 25.355 +/* Returns "false", meaning "connection is not blocked". */ 25.356 +bool send_reply(struct connection *conn, enum xsd_sockmsg_type type, 25.357 + const void *data, unsigned int len) 25.358 +{ 25.359 + struct buffered_data *bdata; 25.360 + 25.361 + /* When data gets freed, we want list entry is destroyed (so 25.362 + * list entry is a child). */ 25.363 + bdata = new_buffer(conn); 25.364 + bdata->buffer = talloc_array(bdata, char, len); 25.365 + 25.366 + bdata->hdr.msg.type = type; 25.367 + bdata->hdr.msg.len = len; 25.368 + memcpy(bdata->buffer, data, len); 25.369 + 25.370 + /* There might be an event going out now. Queue behind it. */ 25.371 + if (conn->out) { 25.372 + assert(conn->out->hdr.msg.type == XS_WATCH_EVENT); 25.373 + assert(!conn->waiting_reply); 25.374 + conn->waiting_reply = bdata; 25.375 + } else 25.376 + conn->out = bdata; 25.377 + return false; 25.378 +} 25.379 + 25.380 +/* Some routines (write, mkdir, etc) just need a non-error return */ 25.381 +bool send_ack(struct connection *conn, enum xsd_sockmsg_type type) 25.382 +{ 25.383 + return send_reply(conn, type, "OK", sizeof("OK")); 25.384 +} 25.385 + 25.386 +bool send_error(struct connection *conn, int error) 25.387 +{ 25.388 + unsigned int i; 25.389 + 25.390 + for (i = 0; error != xsd_errors[i].errnum; i++) 25.391 + if (i == ARRAY_SIZE(xsd_errors) - 1) 25.392 + corrupt(conn, "Unknown error %i (%s)", error, 25.393 + strerror(error)); 25.394 + 25.395 + return send_reply(conn, XS_ERROR, xsd_errors[i].errstring, 25.396 + strlen(xsd_errors[i].errstring) + 1); 25.397 +} 25.398 + 25.399 +static bool valid_chars(const char *node) 25.400 +{ 25.401 + /* Nodes can have lots of crap. */ 25.402 + return (strspn(node, 25.403 + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 25.404 + "abcdefghijklmnopqrstuvwxyz" 25.405 + "0123456789-/_@") == strlen(node)); 25.406 +} 25.407 + 25.408 +static bool is_valid_nodename(const char *node) 25.409 +{ 25.410 + /* Must start in /. */ 25.411 + if (!strstarts(node, "/")) 25.412 + return false; 25.413 + 25.414 + /* Cannot end in / (unless it's just "/"). */ 25.415 + if (strends(node, "/") && !streq(node, "/")) 25.416 + return false; 25.417 + 25.418 + /* No double //. */ 25.419 + if (strstr(node, "//")) 25.420 + return false; 25.421 + 25.422 + return valid_chars(node); 25.423 +} 25.424 + 25.425 +/* We expect one arg in the input: return NULL otherwise. */ 25.426 +static const char *onearg(struct buffered_data *in) 25.427 +{ 25.428 + if (get_string(in, 0) != in->used) 25.429 + return NULL; 25.430 + return in->buffer; 25.431 +} 25.432 + 25.433 +/* If it fails, returns NULL and sets errno. */ 25.434 +static struct xs_permissions *get_perms(struct transaction *transaction, 25.435 + const char *node, unsigned int *num) 25.436 +{ 25.437 + unsigned int size; 25.438 + char *strings; 25.439 + struct xs_permissions *ret; 25.440 + int *fd; 25.441 + 25.442 + fd = talloc_open(node_permfile(transaction, node), O_RDONLY, 0); 25.443 + if (!fd) 25.444 + return NULL; 25.445 + strings = read_all(fd, &size); 25.446 + if (!strings) 25.447 + return NULL; 25.448 + 25.449 + *num = count_strings(strings, size); 25.450 + ret = talloc_array(node, struct xs_permissions, *num); 25.451 + if (!strings_to_perms(ret, *num, strings)) 25.452 + corrupt(NULL, "Permissions corrupt for %s", node); 25.453 + 25.454 + return ret; 25.455 +} 25.456 + 25.457 +static char *perms_to_strings(const char *node, 25.458 + struct xs_permissions *perms, unsigned int num, 25.459 + unsigned int *len) 25.460 +{ 25.461 + unsigned int i; 25.462 + char *strings = NULL; 25.463 + char buffer[MAX_STRLEN(domid_t) + 1]; 25.464 + 25.465 + for (*len = 0, i = 0; i < num; i++) { 25.466 + if (!perm_to_string(&perms[i], buffer)) 25.467 + return NULL; 25.468 + 25.469 + strings = talloc_realloc(node, strings, char, 25.470 + *len + strlen(buffer) + 1); 25.471 + strcpy(strings + *len, buffer); 25.472 + *len += strlen(buffer) + 1; 25.473 + } 25.474 + return strings; 25.475 +} 25.476 + 25.477 +/* Destroy this, and its children, and its children's children. */ 25.478 +int destroy_path(void *path) 25.479 +{ 25.480 + DIR *dir; 25.481 + struct dirent *dirent; 25.482 + 25.483 + dir = opendir(path); 25.484 + if (!dir) { 25.485 + if (unlink(path) == 0 || errno == ENOENT) 25.486 + return 0; 25.487 + corrupt(NULL, "Destroying path %s", path); 25.488 + } 25.489 + 25.490 + while ((dirent = readdir(dir)) != NULL) { 25.491 + char fullpath[strlen(path) + 1 + strlen(dirent->d_name) + 1]; 25.492 + sprintf(fullpath, "%s/%s", (char *)path, dirent->d_name); 25.493 + if (!streq(dirent->d_name,".") && !streq(dirent->d_name,"..")) 25.494 + destroy_path(fullpath); 25.495 + } 25.496 + closedir(dir); 25.497 + if (rmdir(path) != 0) 25.498 + corrupt(NULL, "Destroying directory %s", path); 25.499 + return 0; 25.500 +} 25.501 + 25.502 +/* Create a self-destructing temporary file */ 25.503 +static char *tempfile(const char *path, void *contents, unsigned int len) 25.504 +{ 25.505 + int *fd; 25.506 + char *tmppath = talloc_asprintf(path, "%s.tmp", path); 25.507 + 25.508 + fd = talloc_open(tmppath, O_WRONLY|O_CREAT|O_EXCL, 0640); 25.509 + if (!fd) 25.510 + return NULL; 25.511 + talloc_set_destructor(tmppath, destroy_path); 25.512 + if (!write_all(*fd, contents, len)) 25.513 + return NULL; 25.514 + 25.515 + return tmppath; 25.516 +} 25.517 + 25.518 +/* We assume rename() doesn't fail on moves in same dir. */ 25.519 +static void commit_tempfile(const char *path) 25.520 +{ 25.521 + char realname[strlen(path) + 1]; 25.522 + unsigned int len = strrchr(path, '.') - path; 25.523 + 25.524 + memcpy(realname, path, len); 25.525 + realname[len] = '\0'; 25.526 + if (rename(path, realname) != 0) 25.527 + corrupt(NULL, "Committing %s", realname); 25.528 + talloc_set_destructor(path, NULL); 25.529 +} 25.530 + 25.531 +static bool set_perms(struct transaction *transaction, 25.532 + const char *node, 25.533 + struct xs_permissions *perms, unsigned int num) 25.534 +{ 25.535 + unsigned int len; 25.536 + char *permpath, *strings; 25.537 + 25.538 + strings = perms_to_strings(node, perms, num, &len); 25.539 + if (!strings) 25.540 + return false; 25.541 + 25.542 + /* Create then move. */ 25.543 + permpath = tempfile(node_permfile(transaction, node), strings, len); 25.544 + if (!permpath) 25.545 + return false; 25.546 + 25.547 + commit_tempfile(permpath); 25.548 + return true; 25.549 +} 25.550 + 25.551 +static char *get_parent(const char *node) 25.552 +{ 25.553 + char *slash = strrchr(node + 1, '/'); 25.554 + if (!slash) 25.555 + return talloc_strdup(node, "/"); 25.556 + return talloc_asprintf(node, "%.*s", slash - node, node); 25.557 +} 25.558 + 25.559 +static enum xs_perm_type perm_for_id(domid_t id, 25.560 + struct xs_permissions *perms, 25.561 + unsigned int num) 25.562 +{ 25.563 + unsigned int i; 25.564 + 25.565 + /* Owners and tools get it all... */ 25.566 + if (!id || perms[0].id == id) 25.567 + return XS_PERM_READ|XS_PERM_WRITE|XS_PERM_CREATE|XS_PERM_OWNER; 25.568 + 25.569 + for (i = 1; i < num; i++) 25.570 + if (perms[i].id == id) 25.571 + return perms[i].perms; 25.572 + 25.573 + return perms[0].perms; 25.574 +} 25.575 + 25.576 +/* We have a weird permissions system. You can allow someone into a 25.577 + * specific node without allowing it in the parents. If it's going to 25.578 + * fail, however, we don't want the errno to indicate any information 25.579 + * about the node. */ 25.580 +static int check_with_parents(struct connection *conn, const char *node, 25.581 + int errnum) 25.582 +{ 25.583 + struct xs_permissions *perms; 25.584 + unsigned int num; 25.585 + 25.586 + /* We always tell them about memory failures. */ 25.587 + if (errnum == ENOMEM) 25.588 + return errnum; 25.589 + 25.590 + do { 25.591 + node = get_parent(node); 25.592 + perms = get_perms(conn->transaction, node, &num); 25.593 + if (perms) 25.594 + break; 25.595 + } while (!streq(node, "/")); 25.596 + 25.597 + /* No permission at root? We're in trouble. */ 25.598 + if (!perms) 25.599 + corrupt(conn, "No permissions file at root"); 25.600 + 25.601 + if (!(perm_for_id(conn->id, perms, num) & XS_PERM_READ)) 25.602 + return EACCES; 25.603 + 25.604 + return errnum; 25.605 +} 25.606 + 25.607 +bool check_node_perms(struct connection *conn, const char *node, 25.608 + enum xs_perm_type perm) 25.609 +{ 25.610 + struct xs_permissions *perms; 25.611 + unsigned int num; 25.612 + 25.613 + if (!node) { 25.614 + errno = EINVAL; 25.615 + return false; 25.616 + } 25.617 + 25.618 + if (!node || !is_valid_nodename(node)) { 25.619 + errno = EINVAL; 25.620 + return false; 25.621 + } 25.622 + 25.623 + if (!conn->write && (perm & XS_PERM_WRITE)) { 25.624 + errno = EROFS; 25.625 + return false; 25.626 + } 25.627 + 25.628 + perms = get_perms(conn->transaction, node, &num); 25.629 + /* No permissions. If we want to create it and 25.630 + * it doesn't exist, check parent directory. */ 25.631 + if (!perms && errno == ENOENT && (perm & XS_PERM_CREATE)) { 25.632 + char *parent = get_parent(node); 25.633 + if (!parent) 25.634 + return false; 25.635 + 25.636 + perms = get_perms(conn->transaction, parent, &num); 25.637 + } 25.638 + if (!perms) { 25.639 + errno = check_with_parents(conn, node, errno); 25.640 + return false; 25.641 + } 25.642 + 25.643 + if (perm_for_id(conn->id, perms, num) & perm) 25.644 + return true; 25.645 + 25.646 + errno = check_with_parents(conn, node, EACCES); 25.647 + return false; 25.648 +} 25.649 + 25.650 +static bool send_directory(struct connection *conn, const char *node) 25.651 +{ 25.652 + char *path, *reply = talloc_strdup(node, ""); 25.653 + unsigned int reply_len = 0; 25.654 + DIR *dir; 25.655 + struct dirent *dirent; 25.656 + 25.657 + if (!check_node_perms(conn, node, XS_PERM_READ)) 25.658 + return send_error(conn, errno); 25.659 + 25.660 + path = node_dir(conn->transaction, node); 25.661 + dir = opendir(path); 25.662 + if (!dir) 25.663 + return send_error(conn, errno); 25.664 + 25.665 + while ((dirent = readdir(dir)) != NULL) { 25.666 + int len = strlen(dirent->d_name) + 1; 25.667 + 25.668 + if (!valid_chars(dirent->d_name)) 25.669 + continue; 25.670 + 25.671 + reply = talloc_realloc(path, reply, char, reply_len + len); 25.672 + strcpy(reply + reply_len, dirent->d_name); 25.673 + reply_len += len; 25.674 + } 25.675 + closedir(dir); 25.676 + 25.677 + return send_reply(conn, XS_DIRECTORY, reply, reply_len); 25.678 +} 25.679 + 25.680 +static bool do_read(struct connection *conn, const char *node) 25.681 +{ 25.682 + char *value; 25.683 + unsigned int size; 25.684 + int *fd; 25.685 + 25.686 + if (!check_node_perms(conn, node, XS_PERM_READ)) 25.687 + return send_error(conn, errno); 25.688 + 25.689 + fd = talloc_open(node_datafile(conn->transaction, node), O_RDONLY, 0); 25.690 + if (!fd) { 25.691 + /* Data file doesn't exist? We call that a directory */ 25.692 + if (errno == ENOENT) 25.693 + errno = EISDIR; 25.694 + return send_error(conn, errno); 25.695 + } 25.696 + 25.697 + value = read_all(fd, &size); 25.698 + if (!value) 25.699 + return send_error(conn, errno); 25.700 + 25.701 + return send_reply(conn, XS_READ, value, size); 25.702 +} 25.703 + 25.704 +/* Create a new directory. Optionally put data in it (if data != NULL) */ 25.705 +static bool new_directory(struct connection *conn, 25.706 + const char *node, void *data, unsigned int datalen) 25.707 +{ 25.708 + struct xs_permissions perms; 25.709 + char *permstr; 25.710 + unsigned int len; 25.711 + int *fd; 25.712 + char *dir = node_dir(conn->transaction, node); 25.713 + 25.714 + if (mkdir(dir, 0750) != 0) 25.715 + return false; 25.716 + 25.717 + /* Set destructor so we clean up if neccesary. */ 25.718 + talloc_set_destructor(dir, destroy_path); 25.719 + 25.720 + /* Default permisisons: we own it, noone else has permission. */ 25.721 + perms.id = conn->id; 25.722 + perms.perms = XS_PERM_NONE; 25.723 + 25.724 + permstr = perms_to_strings(dir, &perms, 1, &len); 25.725 + fd = talloc_open(node_permfile(conn->transaction, node), 25.726 + O_WRONLY|O_CREAT|O_EXCL, 0640); 25.727 + if (!fd || !write_all(*fd, permstr, len)) 25.728 + return false; 25.729 + 25.730 + if (data) { 25.731 + char *datapath = node_datafile(conn->transaction, node); 25.732 + 25.733 + fd = talloc_open(datapath, O_WRONLY|O_CREAT|O_EXCL, 0640); 25.734 + if (!fd || !write_all(*fd, data, datalen)) 25.735 + return false; 25.736 + } 25.737 + 25.738 + /* Finished! */ 25.739 + talloc_set_destructor(dir, NULL); 25.740 + return true; 25.741 +} 25.742 + 25.743 +/* path, flags, data... */ 25.744 +static bool do_write(struct connection *conn, struct buffered_data *in) 25.745 +{ 25.746 + unsigned int offset, datalen; 25.747 + char *vec[2]; 25.748 + char *node, *tmppath; 25.749 + enum xs_perm_type mode; 25.750 + struct stat st; 25.751 + 25.752 + /* Extra "strings" can be created by binary data. */ 25.753 + if (get_strings(in, vec, ARRAY_SIZE(vec)) < ARRAY_SIZE(vec)) 25.754 + return send_error(conn, EINVAL); 25.755 + 25.756 + node = vec[0]; 25.757 + if (!within_transaction(conn->transaction, node)) 25.758 + return send_error(conn, EROFS); 25.759 + 25.760 + if (transaction_block(conn, node)) 25.761 + return true; 25.762 + 25.763 + offset = strlen(vec[0]) + strlen(vec[1]) + 2; 25.764 + datalen = in->used - offset; 25.765 + 25.766 + if (streq(vec[1], XS_WRITE_NONE)) 25.767 + mode = XS_PERM_WRITE; 25.768 + else if (streq(vec[1], XS_WRITE_CREATE)) 25.769 + mode = XS_PERM_WRITE|XS_PERM_CREATE; 25.770 + else if (streq(vec[1], XS_WRITE_CREATE_EXCL)) 25.771 + mode = XS_PERM_WRITE|XS_PERM_CREATE; 25.772 + else 25.773 + return send_error(conn, EINVAL); 25.774 + 25.775 + if (!check_node_perms(conn, node, mode)) 25.776 + return send_error(conn, errno); 25.777 + 25.778 + if (lstat(node_dir(conn->transaction, node), &st) != 0) { 25.779 + /* Does not exist... */ 25.780 + if (errno != ENOENT) 25.781 + return send_error(conn, errno); 25.782 + 25.783 + /* Not going to create it? */ 25.784 + if (!(mode & XS_PERM_CREATE)) 25.785 + return send_error(conn, ENOENT); 25.786 + 25.787 + if (!new_directory(conn, node, in->buffer + offset, datalen)) 25.788 + return send_error(conn, errno); 25.789 + } else { 25.790 + /* Exists... */ 25.791 + if (streq(vec[1], XS_WRITE_CREATE_EXCL)) 25.792 + return send_error(conn, EEXIST); 25.793 + 25.794 + tmppath = tempfile(node_datafile(conn->transaction, node), 25.795 + in->buffer + offset, datalen); 25.796 + if (!tmppath) 25.797 + return send_error(conn, errno); 25.798 + 25.799 + commit_tempfile(tmppath); 25.800 + } 25.801 + 25.802 + add_change_node(conn->transaction, node); 25.803 + send_ack(conn, XS_WRITE); 25.804 + fire_watches(conn->transaction, node); 25.805 + return false; 25.806 +} 25.807 + 25.808 +static bool do_mkdir(struct connection *conn, const char *node) 25.809 +{ 25.810 + if (!check_node_perms(conn, node, XS_PERM_WRITE|XS_PERM_CREATE)) 25.811 + return send_error(conn, errno); 25.812 + 25.813 + if (!within_transaction(conn->transaction, node)) 25.814 + return send_error(conn, EROFS); 25.815 + 25.816 + if (transaction_block(conn, node)) 25.817 + return true; 25.818 + 25.819 + if (!new_directory(conn, node, NULL, 0)) 25.820 + return send_error(conn, errno); 25.821 + 25.822 + add_change_node(conn->transaction, node); 25.823 + send_ack(conn, XS_MKDIR); 25.824 + fire_watches(conn->transaction, node); 25.825 + return false; 25.826 +} 25.827 + 25.828 +static bool do_rm(struct connection *conn, const char *node) 25.829 +{ 25.830 + char *tmppath, *path; 25.831 + 25.832 + if (!check_node_perms(conn, node, XS_PERM_WRITE)) 25.833 + return send_error(conn, errno); 25.834 + 25.835 + if (!within_transaction(conn->transaction, node)) 25.836 + return send_error(conn, EROFS); 25.837 + 25.838 + if (transaction_block(conn, node)) 25.839 + return true; 25.840 + 25.841 + if (streq(node, "/")) 25.842 + return send_error(conn, EINVAL); 25.843 + 25.844 + /* We move the directory to temporary name, destructor cleans up. */ 25.845 + path = node_dir(conn->transaction, node); 25.846 + tmppath = talloc_asprintf(node, "%s.tmp", path); 25.847 + talloc_set_destructor(tmppath, destroy_path); 25.848 + 25.849 + if (rename(path, tmppath) != 0) 25.850 + return send_error(conn, errno); 25.851 + 25.852 + add_change_node(conn->transaction, node); 25.853 + send_ack(conn, XS_RM); 25.854 + fire_watches(conn->transaction, node); 25.855 + return false; 25.856 +} 25.857 + 25.858 +static bool do_get_perms(struct connection *conn, const char *node) 25.859 +{ 25.860 + struct xs_permissions *perms; 25.861 + char *strings; 25.862 + unsigned int len, num; 25.863 + 25.864 + if (!check_node_perms(conn, node, XS_PERM_READ)) 25.865 + return send_error(conn, errno); 25.866 + 25.867 + perms = get_perms(conn->transaction, node, &num); 25.868 + if (!perms) 25.869 + return send_error(conn, errno); 25.870 + 25.871 + strings = perms_to_strings(node, perms, num, &len); 25.872 + if (!strings) 25.873 + return send_error(conn, errno); 25.874 + 25.875 + return send_reply(conn, XS_GET_PERMS, strings, len); 25.876 +} 25.877 + 25.878 +static bool do_set_perms(struct connection *conn, struct buffered_data *in) 25.879 +{ 25.880 + unsigned int num; 25.881 + char *node; 25.882 + struct xs_permissions *perms; 25.883 + 25.884 + num = count_strings(in->buffer, in->used); 25.885 + if (num < 2) 25.886 + return send_error(conn, EINVAL); 25.887 + 25.888 + /* First arg is node name. */ 25.889 + node = in->buffer; 25.890 + in->buffer += strlen(in->buffer) + 1; 25.891 + num--; 25.892 + 25.893 + if (!within_transaction(conn->transaction, node)) 25.894 + return send_error(conn, EROFS); 25.895 + 25.896 + if (transaction_block(conn, node)) 25.897 + return true; 25.898 + 25.899 + /* We must own node to do this (tools can do this too). */ 25.900 + if (!check_node_perms(conn, node, XS_PERM_WRITE|XS_PERM_OWNER)) 25.901 + return send_error(conn, errno); 25.902 + 25.903 + perms = talloc_array(node, struct xs_permissions, num); 25.904 + if (!strings_to_perms(perms, num, in->buffer)) 25.905 + return send_error(conn, errno); 25.906 + 25.907 + if (!set_perms(conn->transaction, node, perms, num)) 25.908 + return send_error(conn, errno); 25.909 + add_change_node(conn->transaction, node); 25.910 + send_ack(conn, XS_SET_PERMS); 25.911 + fire_watches(conn->transaction, node); 25.912 + return false; 25.913 +} 25.914 + 25.915 +/* Process "in" for conn: "in" will vanish after this conversation, so 25.916 + * we can talloc off it for temporary variables. May free "conn". 25.917 + * Returns true if can't complete due to block. 25.918 + */ 25.919 +static bool process_message(struct connection *conn, struct buffered_data *in) 25.920 +{ 25.921 + switch (in->hdr.msg.type) { 25.922 + case XS_DIRECTORY: 25.923 + return send_directory(conn, onearg(in)); 25.924 + 25.925 + case XS_READ: 25.926 + return do_read(conn, onearg(in)); 25.927 + 25.928 + case XS_WRITE: 25.929 + return do_write(conn, in); 25.930 + 25.931 + case XS_MKDIR: 25.932 + return do_mkdir(conn, onearg(in)); 25.933 + 25.934 + case XS_RM: 25.935 + return do_rm(conn, onearg(in)); 25.936 + 25.937 + case XS_GET_PERMS: 25.938 + return do_get_perms(conn, onearg(in)); 25.939 + 25.940 + case XS_SET_PERMS: 25.941 + return do_set_perms(conn, in); 25.942 + 25.943 + case XS_SHUTDOWN: 25.944 + send_ack(conn, XS_SHUTDOWN); 25.945 + /* Everything hangs off auto-free context, freed at exit. */ 25.946 + exit(0); 25.947 + 25.948 +#ifdef TESTING 25.949 + case XS_DEBUG: { 25.950 + /* For testing, we allow them to set id. */ 25.951 + if (streq(in->buffer, "setid")) { 25.952 + conn->id = atoi(in->buffer + get_string(in, 0)); 25.953 + send_ack(conn, XS_DEBUG); 25.954 + } else if (streq(in->buffer, "failtest")) { 25.955 + if (get_string(in, 0) < in->used) 25.956 + srandom(atoi(in->buffer + get_string(in, 0))); 25.957 + send_ack(conn, XS_DEBUG); 25.958 + failtest = true; 25.959 + } 25.960 + return false; 25.961 + } 25.962 +#endif /* TESTING */ 25.963 + 25.964 + case XS_WATCH: 25.965 + return do_watch(conn, in); 25.966 + 25.967 + case XS_WATCH_ACK: 25.968 + return do_watch_ack(conn); 25.969 + 25.970 + case XS_UNWATCH: 25.971 + return do_unwatch(conn, onearg(in)); 25.972 + 25.973 + case XS_TRANSACTION_START: 25.974 + return do_transaction_start(conn, onearg(in)); 25.975 + 25.976 + case XS_TRANSACTION_END: 25.977 + return do_transaction_end(conn, onearg(in)); 25.978 + 25.979 + case XS_INTRODUCE: 25.980 + return do_introduce(conn, in); 25.981 + 25.982 + case XS_RELEASE: 25.983 + return do_release(conn, onearg(in)); 25.984 + 25.985 + case XS_GETDOMAINPATH: 25.986 + return do_get_domain_path(conn, onearg(in)); 25.987 + 25.988 + case XS_WATCH_EVENT: 25.989 + default: 25.990 + eprintf("Client unknown operation %i", in->hdr.msg.type); 25.991 + send_error(conn, ENOSYS); 25.992 + return false; 25.993 + } 25.994 +} 25.995 + 25.996 +static int out_of_mem(void *data) 25.997 +{ 25.998 + longjmp(*(jmp_buf *)data, 1); 25.999 +} 25.1000 + 25.1001 +static void consider_message(struct connection *conn) 25.1002 +{ 25.1003 + struct buffered_data *in = NULL; 25.1004 + enum xsd_sockmsg_type type = conn->in->hdr.msg.type; 25.1005 + jmp_buf talloc_fail; 25.1006 + 25.1007 + /* For simplicity, we kill the connection on OOM. */ 25.1008 + talloc_set_fail_handler(out_of_mem, &talloc_fail); 25.1009 + if (setjmp(talloc_fail)) { 25.1010 + talloc_free(conn); 25.1011 + goto end; 25.1012 + } 25.1013 + 25.1014 + if (verbose) 25.1015 + xprintf("Got message %i len %i from %p\n", 25.1016 + type, conn->in->hdr.msg.len, conn); 25.1017 + 25.1018 + /* We might get a command while waiting for an ack: this means 25.1019 + * the other end discarded it: we will re-transmit. */ 25.1020 + if (type != XS_WATCH_ACK) 25.1021 + reset_watch_event(conn); 25.1022 + 25.1023 + /* Careful: process_message may free connection. We detach 25.1024 + * "in" beforehand and allocate the new buffer to avoid 25.1025 + * touching conn after process_message. 25.1026 + */ 25.1027 + in = talloc_steal(talloc_autofree_context(), conn->in); 25.1028 + conn->in = new_buffer(conn); 25.1029 + if (process_message(conn, in)) { 25.1030 + /* Blocked by transaction: queue for re-xmit. */ 25.1031 + talloc_free(conn->in); 25.1032 + conn->in = in; 25.1033 + in = NULL; 25.1034 + } 25.1035 + 25.1036 +end: 25.1037 + talloc_free(in); 25.1038 + talloc_set_fail_handler(NULL, NULL); 25.1039 + if (talloc_total_blocks(NULL) 25.1040 + != talloc_total_blocks(talloc_autofree_context()) + 1) 25.1041 + talloc_report_full(NULL, stderr); 25.1042 +} 25.1043 + 25.1044 +/* Errors in reading or allocating here mean we get out of sync, so we 25.1045 + * drop the whole client connection. */ 25.1046 +void handle_input(struct connection *conn) 25.1047 +{ 25.1048 + int bytes; 25.1049 + struct buffered_data *in; 25.1050 + 25.1051 + assert(!conn->blocked); 25.1052 + in = conn->in; 25.1053 + 25.1054 + /* Not finished header yet? */ 25.1055 + if (in->inhdr) { 25.1056 + bytes = conn->read(conn, in->hdr.raw + in->used, 25.1057 + sizeof(in->hdr) - in->used); 25.1058 + if (bytes <= 0) 25.1059 + goto bad_client; 25.1060 + in->used += bytes; 25.1061 + if (in->used != sizeof(in->hdr)) 25.1062 + return; 25.1063 + 25.1064 + if (in->hdr.msg.len > PATH_MAX) { 25.1065 + syslog(LOG_DAEMON, "Client tried to feed us %i", 25.1066 + in->hdr.msg.len); 25.1067 + goto bad_client; 25.1068 + } 25.1069 + 25.1070 + in->buffer = talloc_array(in, char, in->hdr.msg.len); 25.1071 + if (!in->buffer) 25.1072 + goto bad_client; 25.1073 + in->used = 0; 25.1074 + in->inhdr = false; 25.1075 + return; 25.1076 + } 25.1077 + 25.1078 + bytes = conn->read(conn, in->buffer + in->used, 25.1079 + in->hdr.msg.len - in->used); 25.1080 + if (bytes < 0) 25.1081 + goto bad_client; 25.1082 + 25.1083 + in->used += bytes; 25.1084 + if (in->used != in->hdr.msg.len) 25.1085 + return; 25.1086 + 25.1087 + consider_message(conn); 25.1088 + return; 25.1089 + 25.1090 +bad_client: 25.1091 + /* Kill it. */ 25.1092 + talloc_free(conn); 25.1093 +} 25.1094 + 25.1095 +void handle_output(struct connection *conn) 25.1096 +{ 25.1097 + if (!write_message(conn)) 25.1098 + talloc_free(conn); 25.1099 +} 25.1100 + 25.1101 +/* If a transaction has ended, see if we can unblock any connections. */ 25.1102 +static void unblock_connections(void) 25.1103 +{ 25.1104 + struct connection *i, *tmp; 25.1105 + 25.1106 + list_for_each_entry_safe(i, tmp, &connections, list) { 25.1107 + if (!i->blocked) 25.1108 + continue; 25.1109 + 25.1110 + if (!transaction_covering_node(i->blocked)) { 25.1111 + talloc_free(i->blocked); 25.1112 + i->blocked = NULL; 25.1113 + consider_message(i); 25.1114 + } 25.1115 + } 25.1116 + 25.1117 + /* To balance bias, move first entry to end. */ 25.1118 + if (!list_empty(&connections)) { 25.1119 + i = list_top(&connections, struct connection, list); 25.1120 + list_del(&i->list); 25.1121 + list_add_tail(&i->list, &connections); 25.1122 + } 25.1123 +} 25.1124 + 25.1125 +struct connection *new_connection(connwritefn_t *write, connreadfn_t *read) 25.1126 +{ 25.1127 + struct connection *new; 25.1128 + jmp_buf talloc_fail; 25.1129 + 25.1130 + new = talloc(talloc_autofree_context(), struct connection); 25.1131 + if (!new) 25.1132 + return NULL; 25.1133 + 25.1134 + new->blocked = false; 25.1135 + new->out = new->waiting_reply = NULL; 25.1136 + new->event = NULL; 25.1137 + new->fd = -1; 25.1138 + new->id = 0; 25.1139 + new->domain = NULL; 25.1140 + new->transaction = NULL; 25.1141 + new->write = write; 25.1142 + new->read = read; 25.1143 + 25.1144 + talloc_set_fail_handler(out_of_mem, &talloc_fail); 25.1145 + if (setjmp(talloc_fail)) { 25.1146 + talloc_free(new); 25.1147 + return NULL; 25.1148 + } 25.1149 + new->in = new_buffer(new); 25.1150 + talloc_set_fail_handler(NULL, NULL); 25.1151 + 25.1152 + list_add_tail(&new->list, &connections); 25.1153 + talloc_set_destructor(new, destroy_conn); 25.1154 + return new; 25.1155 +} 25.1156 + 25.1157 +static int writefd(struct connection *conn, const void *data, unsigned int len) 25.1158 +{ 25.1159 + return write(conn->fd, data, len); 25.1160 +} 25.1161 + 25.1162 +static int readfd(struct connection *conn, void *data, unsigned int len) 25.1163 +{ 25.1164 + return read(conn->fd, data, len); 25.1165 +} 25.1166 + 25.1167 +static void accept_connection(int sock, bool canwrite) 25.1168 +{ 25.1169 + int fd; 25.1170 + struct connection *conn; 25.1171 + 25.1172 + fd = accept(sock, NULL, NULL); 25.1173 + if (fd < 0) 25.1174 + return; 25.1175 + 25.1176 + conn = new_connection(canwrite ? writefd : NULL, readfd); 25.1177 + if (conn) 25.1178 + conn->fd = fd; 25.1179 + else 25.1180 + close(fd); 25.1181 +} 25.1182 + 25.1183 +/* Calc timespan from now to absolute time. */ 25.1184 +static void time_relative_to_now(struct timeval *tv) 25.1185 +{ 25.1186 + struct timeval now; 25.1187 + 25.1188 + gettimeofday(&now, NULL); 25.1189 + if (timercmp(&now, tv, >)) 25.1190 + timerclear(tv); 25.1191 + else { 25.1192 + tv->tv_sec -= now.tv_sec; 25.1193 + if (now.tv_usec > tv->tv_usec) { 25.1194 + tv->tv_sec--; 25.1195 + tv->tv_usec += 1000000; 25.1196 + } 25.1197 + tv->tv_usec -= now.tv_usec; 25.1198 + } 25.1199 +} 25.1200 + 25.1201 +static struct option options[] = { { "no-fork", 0, NULL, 'N' }, 25.1202 + { "verbose", 0, NULL, 'V' }, 25.1203 + { "output-pid", 0, NULL, 'P' }, 25.1204 + { NULL, 0, NULL, 0 } }; 25.1205 + 25.1206 +int main(int argc, char *argv[]) 25.1207 +{ 25.1208 + int opt, *sock, *ro_sock, event_fd, max, tmpout; 25.1209 + struct sockaddr_un addr; 25.1210 + fd_set inset, outset; 25.1211 + bool dofork = true; 25.1212 + bool outputpid = false; 25.1213 + 25.1214 + while ((opt = getopt_long(argc, argv, "DV", options, NULL)) != -1) { 25.1215 + switch (opt) { 25.1216 + case 'N': 25.1217 + dofork = false; 25.1218 + break; 25.1219 + case 'V': 25.1220 + verbose = true; 25.1221 + break; 25.1222 + case 'P': 25.1223 + outputpid = true; 25.1224 + break; 25.1225 + } 25.1226 + } 25.1227 + if (optind != argc) 25.1228 + barf("%s: No arguments desired", argv[0]); 25.1229 + 25.1230 + talloc_enable_leak_report_full(); 25.1231 + 25.1232 + /* Create sockets for them to listen to. */ 25.1233 + sock = talloc(talloc_autofree_context(), int); 25.1234 + *sock = socket(PF_UNIX, SOCK_STREAM, 0); 25.1235 + if (*sock < 0) 25.1236 + barf_perror("Could not create socket"); 25.1237 + ro_sock = talloc(talloc_autofree_context(), int); 25.1238 + *ro_sock = socket(PF_UNIX, SOCK_STREAM, 0); 25.1239 + if (*ro_sock < 0) 25.1240 + barf_perror("Could not create socket"); 25.1241 + talloc_set_destructor(sock, destroy_fd); 25.1242 + talloc_set_destructor(ro_sock, destroy_fd); 25.1243 + 25.1244 + /* Don't kill us with SIGPIPE. */ 25.1245 + signal(SIGPIPE, SIG_IGN); 25.1246 + 25.1247 + /* FIXME: Be more sophisticated, don't mug running daemon. */ 25.1248 + unlink(xs_daemon_socket()); 25.1249 + unlink(xs_daemon_socket_ro()); 25.1250 + 25.1251 + addr.sun_family = AF_UNIX; 25.1252 + strcpy(addr.sun_path, xs_daemon_socket()); 25.1253 + if (bind(*sock, (struct sockaddr *)&addr, sizeof(addr)) != 0) 25.1254 + barf_perror("Could not bind socket to %s", xs_daemon_socket()); 25.1255 + strcpy(addr.sun_path, xs_daemon_socket_ro()); 25.1256 + if (bind(*ro_sock, (struct sockaddr *)&addr, sizeof(addr)) != 0) 25.1257 + barf_perror("Could not bind socket to %s", 25.1258 + xs_daemon_socket_ro()); 25.1259 + if (chmod(xs_daemon_socket(), 0600) != 0 25.1260 + || chmod(xs_daemon_socket_ro(), 0660) != 0) 25.1261 + barf_perror("Could not chmod sockets"); 25.1262 + 25.1263 + if (listen(*sock, 1) != 0 25.1264 + || listen(*ro_sock, 1) != 0) 25.1265 + barf_perror("Could not listen on sockets"); 25.1266 + 25.1267 + /* If we're the first, create .perms file for root. */ 25.1268 + if (mkdir(xs_daemon_store(), 0750) == 0) { 25.1269 + struct xs_permissions perms; 25.1270 + char *root = talloc_strdup(talloc_autofree_context(), "/"); 25.1271 + 25.1272 + perms.id = 0; 25.1273 + perms.perms = XS_PERM_READ; 25.1274 + if (!set_perms(NULL, root, &perms, 1)) 25.1275 + barf_perror("Could not create permissions in root"); 25.1276 + talloc_free(root); 25.1277 + mkdir(xs_daemon_transactions(), 0750); 25.1278 + } else if (errno != EEXIST) 25.1279 + barf_perror("Could not create root %s", xs_daemon_store()); 25.1280 + 25.1281 + /* Listen to hypervisor. */ 25.1282 + event_fd = domain_init(); 25.1283 + 25.1284 + /* Debugging: daemonize() closes standard fds, so dup here. */ 25.1285 + tmpout = dup(STDOUT_FILENO); 25.1286 + if (dofork) { 25.1287 + openlog("xenstored", 0, LOG_DAEMON); 25.1288 + daemonize(); 25.1289 + } 25.1290 + 25.1291 + if (outputpid) { 25.1292 + char buffer[20]; 25.1293 + sprintf(buffer, "%i\n", getpid()); 25.1294 + write(tmpout, buffer, strlen(buffer)); 25.1295 + } 25.1296 + close(tmpout); 25.1297 + 25.1298 +#ifdef TESTING 25.1299 + signal(SIGUSR1, stop_failtest); 25.1300 +#endif 25.1301 + 25.1302 + /* Get ready to listen to the tools. */ 25.1303 + max = initialize_set(&inset, &outset, *sock, *ro_sock, event_fd); 25.1304 + 25.1305 + /* Main loop. */ 25.1306 + for (;;) { 25.1307 + struct connection *i; 25.1308 + struct timeval *tvp = NULL, tv; 25.1309 + 25.1310 + timerclear(&tv); 25.1311 + shortest_transaction_timeout(&tv); 25.1312 + if (timerisset(&tv)) { 25.1313 + time_relative_to_now(&tv); 25.1314 + tvp = &tv; 25.1315 + } 25.1316 + 25.1317 + if (select(max+1, &inset, &outset, NULL, tvp) < 0) { 25.1318 + if (errno == EINTR) 25.1319 + continue; 25.1320 + barf_perror("Select failed"); 25.1321 + } 25.1322 + 25.1323 + if (FD_ISSET(*sock, &inset)) 25.1324 + accept_connection(*sock, true); 25.1325 + 25.1326 + if (FD_ISSET(*ro_sock, &inset)) 25.1327 + accept_connection(*ro_sock, false); 25.1328 + 25.1329 + if (FD_ISSET(event_fd, &inset)) 25.1330 + handle_event(event_fd); 25.1331 + 25.1332 + list_for_each_entry(i, &connections, list) { 25.1333 + if (i->domain) 25.1334 + continue; 25.1335 + 25.1336 + /* Operations can delete themselves or others 25.1337 + * (xs_release): list is not safe after input, 25.1338 + * so break. */ 25.1339 + if (FD_ISSET(i->fd, &inset)) { 25.1340 + handle_input(i); 25.1341 + break; 25.1342 + } 25.1343 + if (FD_ISSET(i->fd, &outset)) { 25.1344 + handle_output(i); 25.1345 + break; 25.1346 + } 25.1347 + } 25.1348 + 25.1349 + if (tvp) 25.1350 + check_transaction_timeout(); 25.1351 + 25.1352 + /* If transactions ended, we might be able to do more work. */ 25.1353 + unblock_connections(); 25.1354 + 25.1355 + max = initialize_set(&inset, &outset, *sock,*ro_sock,event_fd); 25.1356 + } 25.1357 +}
26.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 26.2 +++ b/tools/xenstore/xenstored_core.h Tue Jun 07 12:43:58 2005 +0000 26.3 @@ -0,0 +1,123 @@ 26.4 +/* 26.5 + Internal interfaces for Xen Store Daemon. 26.6 + Copyright (C) 2005 Rusty Russell IBM Corporation 26.7 + 26.8 + This program is free software; you can redistribute it and/or modify 26.9 + it under the terms of the GNU General Public License as published by 26.10 + the Free Software Foundation; either version 2 of the License, or 26.11 + (at your option) any later version. 26.12 + 26.13 + This program is distributed in the hope that it will be useful, 26.14 + but WITHOUT ANY WARRANTY; without even the implied warranty of 26.15 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 26.16 + GNU General Public License for more details. 26.17 + 26.18 + You should have received a copy of the GNU General Public License 26.19 + along with this program; if not, write to the Free Software 26.20 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 26.21 +*/ 26.22 +#ifndef _XENSTORED_INTERNAL_H 26.23 +#define _XENSTORED_INTERNAL_H 26.24 +#include <stdbool.h> 26.25 +#include <stdint.h> 26.26 +#include <errno.h> 26.27 +#include "xs_lib.h" 26.28 +#include "xenstored.h" 26.29 +#include "list.h" 26.30 + 26.31 +struct buffered_data 26.32 +{ 26.33 + /* Are we still doing the header? */ 26.34 + bool inhdr; 26.35 + /* How far are we? */ 26.36 + unsigned int used; 26.37 + union { 26.38 + struct xsd_sockmsg msg; 26.39 + char raw[sizeof(struct xsd_sockmsg)]; 26.40 + } hdr; 26.41 + /* The actual data. */ 26.42 + char *buffer; 26.43 +}; 26.44 + 26.45 +struct connection; 26.46 +typedef int connwritefn_t(struct connection *, const void *, unsigned int); 26.47 +typedef int connreadfn_t(struct connection *, void *, unsigned int); 26.48 + 26.49 +struct connection 26.50 +{ 26.51 + struct list_head list; 26.52 + 26.53 + /* The file descriptor we came in on. */ 26.54 + int fd; 26.55 + 26.56 + /* Who am I? 0 for socket connections. */ 26.57 + domid_t id; 26.58 + 26.59 + /* Are we blocked waiting for a transaction to end? Contains node. */ 26.60 + char *blocked; 26.61 + 26.62 + /* Our current event. If all used, we're waiting for ack. */ 26.63 + struct watch_event *event; 26.64 + 26.65 + /* Buffered incoming data. */ 26.66 + struct buffered_data *in; 26.67 + 26.68 + /* Buffered output data */ 26.69 + struct buffered_data *out; 26.70 + 26.71 + /* If we had a watch fire outgoing when we needed to reply... */ 26.72 + struct buffered_data *waiting_reply; 26.73 + 26.74 + /* My transaction, if any. */ 26.75 + struct transaction *transaction; 26.76 + 26.77 + /* The domain I'm associated with, if any. */ 26.78 + struct domain *domain; 26.79 + 26.80 + /* Methods for communicating over this connection: write can be NULL */ 26.81 + connwritefn_t *write; 26.82 + connreadfn_t *read; 26.83 +}; 26.84 + 26.85 +/* Return length of string (including nul) at this offset. */ 26.86 +unsigned int get_string(const struct buffered_data *data, 26.87 + unsigned int offset); 26.88 + 26.89 +/* Break input into vectors, return the number, fill in up to num of them. */ 26.90 +unsigned int get_strings(struct buffered_data *data, 26.91 + char *vec[], unsigned int num); 26.92 + 26.93 +/* Is child node a child or equal to parent node? */ 26.94 +bool is_child(const char *child, const char *parent); 26.95 + 26.96 +/* Create a new buffer with lifetime of context. */ 26.97 +struct buffered_data *new_buffer(void *ctx); 26.98 + 26.99 +bool send_reply(struct connection *conn, enum xsd_sockmsg_type type, 26.100 + const void *data, unsigned int len); 26.101 + 26.102 +/* Some routines (write, mkdir, etc) just need a non-error return */ 26.103 +bool send_ack(struct connection *conn, enum xsd_sockmsg_type type); 26.104 + 26.105 +/* Send an error: error is usually "errno". */ 26.106 +bool send_error(struct connection *conn, int error); 26.107 + 26.108 +/* Check permissions on this node. */ 26.109 +bool check_node_perms(struct connection *conn, const char *node, 26.110 + enum xs_perm_type perm); 26.111 + 26.112 +/* Path to this node outside transaction. */ 26.113 +char *node_dir_outside_transaction(const char *node); 26.114 + 26.115 +/* Fail due to excessive corruption, capitalist pigdogs! */ 26.116 +void __attribute__((noreturn)) corrupt(struct connection *conn, 26.117 + const char *fmt, ...); 26.118 + 26.119 +struct connection *new_connection(connwritefn_t *write, connreadfn_t *read); 26.120 + 26.121 +void handle_input(struct connection *conn); 26.122 +void handle_output(struct connection *conn); 26.123 + 26.124 +/* Convenient talloc-style destructor for paths. */ 26.125 +int destroy_path(void *path); 26.126 +#endif /* _XENSTORED_INTERNAL_H */
27.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 27.2 +++ b/tools/xenstore/xenstored_domain.c Tue Jun 07 12:43:58 2005 +0000 27.3 @@ -0,0 +1,387 @@ 27.4 +/* 27.5 + Domain communications for Xen Store Daemon. 27.6 + Copyright (C) 2005 Rusty Russell IBM Corporation 27.7 + 27.8 + This program is free software; you can redistribute it and/or modify 27.9 + it under the terms of the GNU General Public License as published by 27.10 + the Free Software Foundation; either version 2 of the License, or 27.11 + (at your option) any later version. 27.12 + 27.13 + This program is distributed in the hope that it will be useful, 27.14 + but WITHOUT ANY WARRANTY; without even the implied warranty of 27.15 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27.16 + GNU General Public License for more details. 27.17 + 27.18 + You should have received a copy of the GNU General Public License 27.19 + along with this program; if not, write to the Free Software 27.20 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 27.21 +*/ 27.22 + 27.23 +#include <stdio.h> 27.24 +#include <linux/ioctl.h> 27.25 +#include <sys/ioctl.h> 27.26 +#include <sys/mman.h> 27.27 +#include <unistd.h> 27.28 +#include <stdlib.h> 27.29 +#include <stdarg.h> 27.30 +#include <sys/types.h> 27.31 +#include <sys/stat.h> 27.32 +#include <fcntl.h> 27.33 + 27.34 +//#define DEBUG 27.35 +#include "utils.h" 27.36 +#include "talloc.h" 27.37 +#include "xenstored_core.h" 27.38 +#include "xenstored_domain.h" 27.39 +#include "xenstored_test.h" 27.40 + 27.41 +static int *xc_handle; 27.42 +static int eventchn_fd; 27.43 +static unsigned int ringbuf_datasize; 27.44 + 27.45 +struct domain 27.46 +{ 27.47 + struct list_head list; 27.48 + 27.49 + /* The id of this domain */ 27.50 + domid_t domid; 27.51 + 27.52 + /* Event channel port */ 27.53 + u16 port; 27.54 + 27.55 + /* Domain path in store. */ 27.56 + char *path; 27.57 + 27.58 + /* Shared page. */ 27.59 + void *page; 27.60 + 27.61 + /* Input and output ringbuffer heads. */ 27.62 + struct ringbuf_head *input, *output; 27.63 + 27.64 + /* The connection associated with this. */ 27.65 + struct connection *conn; 27.66 + 27.67 +}; 27.68 + 27.69 +static LIST_HEAD(domains); 27.70 + 27.71 +void domain_set_conn(struct domain *domain, struct connection *conn) 27.72 +{ 27.73 + domain->conn = conn; 27.74 +} 27.75 + 27.76 +struct ringbuf_head 27.77 +{ 27.78 + u32 write; /* Next place to write to */ 27.79 + u32 read; /* Next place to read from */ 27.80 + u8 flags; 27.81 + char buf[0]; 27.82 +} __attribute__((packed)); 27.83 + 27.84 +#define EVENTCHN_BIND _IO('E', 2) 27.85 +#define EVENTCHN_UNBIND _IO('E', 3) 27.86 + 27.87 +/* FIXME: Mark connection as broken (close it?) when this happens. */ 27.88 +static bool check_buffer(const struct ringbuf_head *h) 27.89 +{ 27.90 + return (h->write < ringbuf_datasize && h->read < ringbuf_datasize); 27.91 +} 27.92 + 27.93 +/* We can't fill last byte: would look like empty buffer. */ 27.94 +static void *get_output_chunk(const struct ringbuf_head *h, 27.95 + void *buf, u32 *len) 27.96 +{ 27.97 + u32 read_mark; 27.98 + 27.99 + if (h->read == 0) 27.100 + read_mark = ringbuf_datasize - 1; 27.101 + else 27.102 + read_mark = h->read - 1; 27.103 + 27.104 + /* Here to the end of buffer, unless they haven't read some out. */ 27.105 + *len = ringbuf_datasize - h->write; 27.106 + if (read_mark >= h->write) 27.107 + *len = read_mark - h->write; 27.108 + return buf + h->write; 27.109 +} 27.110 + 27.111 +static const void *get_input_chunk(const struct ringbuf_head *h, 27.112 + const void *buf, u32 *len) 27.113 +{ 27.114 + /* Here to the end of buffer, unless they haven't written some. */ 27.115 + *len = ringbuf_datasize - h->read; 27.116 + if (h->write >= h->read) 27.117 + *len = h->write - h->read; 27.118 + return buf + h->read; 27.119 +} 27.120 + 27.121 +static void update_output_chunk(struct ringbuf_head *h, u32 len) 27.122 +{ 27.123 + h->write += len; 27.124 + if (h->write == ringbuf_datasize) 27.125 + h->write = 0; 27.126 +} 27.127 + 27.128 +static void update_input_chunk(struct ringbuf_head *h, u32 len) 27.129 +{ 27.130 + h->read += len; 27.131 + if (h->read == ringbuf_datasize) 27.132 + h->read = 0; 27.133 +} 27.134 + 27.135 +static bool buffer_has_input(const struct ringbuf_head *h) 27.136 +{ 27.137 + u32 len; 27.138 + 27.139 + get_input_chunk(h, NULL, &len); 27.140 + return (len != 0); 27.141 +} 27.142 + 27.143 +static bool buffer_has_output_room(const struct ringbuf_head *h) 27.144 +{ 27.145 + u32 len; 27.146 + 27.147 + get_output_chunk(h, NULL, &len); 27.148 + return (len != 0); 27.149 +} 27.150 + 27.151 +static int writechn(struct connection *conn, const void *data, unsigned int len) 27.152 +{ 27.153 + u32 avail; 27.154 + void *dest; 27.155 + struct ringbuf_head h; 27.156 + 27.157 + /* Must read head once, and before anything else, and verified. */ 27.158 + h = *conn->domain->output; 27.159 + mb(); 27.160 + if (!check_buffer(&h)) { 27.161 + errno = EIO; 27.162 + return -1; 27.163 + } 27.164 + 27.165 + dest = get_output_chunk(&h, conn->domain->output->buf, &avail); 27.166 + if (avail < len) 27.167 + len = avail; 27.168 + 27.169 + memcpy(dest, data, len); 27.170 + mb(); 27.171 + update_output_chunk(conn->domain->output, len); 27.172 + /* FIXME: Probably not neccessary. */ 27.173 + mb(); 27.174 + xc_evtchn_send(*xc_handle, conn->domain->port); 27.175 + return len; 27.176 +} 27.177 + 27.178 +static int readchn(struct connection *conn, void *data, unsigned int len) 27.179 +{ 27.180 + u32 avail; 27.181 + const void *src; 27.182 + struct ringbuf_head h; 27.183 + bool was_full; 27.184 + 27.185 + /* Must read head once, and before anything else, and verified. */ 27.186 + h = *conn->domain->input; 27.187 + mb(); 27.188 + 27.189 + if (!check_buffer(&h)) { 27.190 + errno = EIO; 27.191 + return -1; 27.192 + } 27.193 + 27.194 + src = get_input_chunk(&h, conn->domain->input->buf, &avail); 27.195 + if (avail < len) 27.196 + len = avail; 27.197 + 27.198 + was_full = !buffer_has_output_room(&h); 27.199 + memcpy(data, src, len); 27.200 + mb(); 27.201 + update_input_chunk(conn->domain->input, len); 27.202 + /* FIXME: Probably not neccessary. */ 27.203 + mb(); 27.204 + 27.205 + /* If it was full, tell them we've taken some. */ 27.206 + if (was_full) 27.207 + xc_evtchn_send(*xc_handle, conn->domain->port); 27.208 + return len; 27.209 +} 27.210 + 27.211 +static int destroy_domain(void *_domain) 27.212 +{ 27.213 + struct domain *domain = _domain; 27.214 + 27.215 + list_del(&domain->list); 27.216 + 27.217 + if (domain->port && 27.218 + (ioctl(eventchn_fd, EVENTCHN_UNBIND, domain->port) != 0)) 27.219 + eprintf("> Unbinding port %i failed!\n", domain->port); 27.220 + 27.221 + if(domain->page) 27.222 + munmap(domain->page, getpagesize()); 27.223 + 27.224 + return 0; 27.225 +} 27.226 + 27.227 +static struct domain *find_domain(u16 port) 27.228 +{ 27.229 + struct domain *i; 27.230 + 27.231 + list_for_each_entry(i, &domains, list) { 27.232 + if (i->port == port) 27.233 + return i; 27.234 + } 27.235 + return NULL; 27.236 +} 27.237 + 27.238 +void handle_event(int event_fd) 27.239 +{ 27.240 + u16 port; 27.241 + struct domain *domain; 27.242 + 27.243 + if (read(event_fd, &port, sizeof(port)) != sizeof(port)) 27.244 + barf_perror("Failed to read from event fd"); 27.245 + 27.246 + /* We have to handle *all* the data available before we ack: 27.247 + * careful that handle_input/handle_output can destroy conn. 27.248 + */ 27.249 + while ((domain = find_domain(port)) != NULL) { 27.250 + if (!domain->conn->blocked && buffer_has_input(domain->input)) 27.251 + handle_input(domain->conn); 27.252 + else if (domain->conn->out 27.253 + && buffer_has_output_room(domain->output)) 27.254 + handle_output(domain->conn); 27.255 + else 27.256 + break; 27.257 + } 27.258 + 27.259 +#ifndef TESTING 27.260 + if (write(event_fd, &port, sizeof(port)) != sizeof(port)) 27.261 + barf_perror("Failed to write to event fd"); 27.262 +#endif 27.263 +} 27.264 + 27.265 +/* domid, mfn, evtchn, path */ 27.266 +bool do_introduce(struct connection *conn, struct buffered_data *in) 27.267 +{ 27.268 + struct domain *domain; 27.269 + char *vec[4]; 27.270 + 27.271 + if (get_strings(in, vec, ARRAY_SIZE(vec)) < ARRAY_SIZE(vec)) 27.272 + return send_error(conn, EINVAL); 27.273 + 27.274 + /* Hang domain off "in" until we're finished. */ 27.275 + domain = talloc(in, struct domain); 27.276 + domain->domid = atoi(vec[0]); 27.277 + domain->port = atoi(vec[2]); 27.278 + domain->path = talloc_strdup(domain, vec[3]); 27.279 + talloc_set_destructor(domain, destroy_domain); 27.280 + if (!domain->port || !domain->domid) 27.281 + return send_error(conn, EINVAL); 27.282 + domain->page = xc_map_foreign_range(*xc_handle, domain->domid, 27.283 + getpagesize(), 27.284 + PROT_READ|PROT_WRITE, 27.285 + atol(vec[1])); 27.286 + if (!domain->page) 27.287 + return send_error(conn, errno); 27.288 + 27.289 + /* One in each half of page. */ 27.290 + domain->input = domain->page; 27.291 + domain->output = domain->page + getpagesize()/2; 27.292 + 27.293 + /* Tell kernel we're interested in this event. */ 27.294 + if (ioctl(eventchn_fd, EVENTCHN_BIND, domain->port) != 0) 27.295 + return send_error(conn, errno); 27.296 + 27.297 + domain->conn = new_connection(writechn, readchn); 27.298 + domain->conn->domain = domain; 27.299 + 27.300 + talloc_steal(domain->conn, domain); 27.301 + list_add(&domain->list, &domains); 27.302 + 27.303 + return send_ack(conn, XS_INTRODUCE); 27.304 +} 27.305 + 27.306 +static struct domain *find_domain_by_domid(domid_t domid) 27.307 +{ 27.308 + struct domain *i; 27.309 + 27.310 + list_for_each_entry(i, &domains, list) { 27.311 + if (i->domid == domid) 27.312 + return i; 27.313 + } 27.314 + return NULL; 27.315 +} 27.316 + 27.317 +/* domid */ 27.318 +bool do_release(struct connection *conn, const char *domid_str) 27.319 +{ 27.320 + struct domain *domain; 27.321 + domid_t domid; 27.322 + 27.323 + if (!domid_str) 27.324 + return send_error(conn, EINVAL); 27.325 + 27.326 + domid = atoi(domid_str); 27.327 + if (!domid) 27.328 + return send_error(conn, EINVAL); 27.329 + 27.330 + domain = find_domain_by_domid(domid); 27.331 + if (!domain) 27.332 + return send_error(conn, ENOENT); 27.333 + 27.334 + if (!domain->conn) 27.335 + return send_error(conn, EINVAL); 27.336 + 27.337 + talloc_free(domain->conn); 27.338 + return send_ack(conn, XS_RELEASE); 27.339 +} 27.340 + 27.341 +bool do_get_domain_path(struct connection *conn, const char *domid_str) 27.342 +{ 27.343 + struct domain *domain; 27.344 + domid_t domid; 27.345 + 27.346 + if (!domid_str) 27.347 + return send_error(conn, EINVAL); 27.348 + 27.349 + domid = atoi(domid_str); 27.350 + if (domid == 0) 27.351 + domain = conn->domain; 27.352 + else 27.353 + domain = find_domain_by_domid(domid); 27.354 + 27.355 + if (!domain) 27.356 + return send_error(conn, ENOENT); 27.357 + 27.358 + return send_reply(conn, XS_GETDOMAINPATH, domain->path, 27.359 + strlen(domain->path) + 1); 27.360 +} 27.361 + 27.362 +static int close_xc_handle(void *_handle) 27.363 +{ 27.364 + xc_interface_close(*(int *)_handle); 27.365 + return 0; 27.366 +} 27.367 + 27.368 +/* Returns the event channel handle. */ 27.369 +int domain_init(void) 27.370 +{ 27.371 + /* The size of the ringbuffer: half a page minus head structure. */ 27.372 + ringbuf_datasize = getpagesize() / 2 - sizeof(struct ringbuf_head); 27.373 + 27.374 + xc_handle = talloc(talloc_autofree_context(), int); 27.375 + if (!xc_handle) 27.376 + barf_perror("Failed to allocate domain handle"); 27.377 + *xc_handle = xc_interface_open(); 27.378 + if (*xc_handle < 0) 27.379 + barf_perror("Failed to open connection to hypervisor"); 27.380 + talloc_set_destructor(xc_handle, close_xc_handle); 27.381 + 27.382 +#ifdef TESTING 27.383 + eventchn_fd = fake_open_eventchn(); 27.384 +#else 27.385 + eventchn_fd = open("/dev/xen/evtchn", O_RDWR); 27.386 +#endif 27.387 + if (eventchn_fd < 0) 27.388 + barf_perror("Failed to open connection to hypervisor"); 27.389 + return eventchn_fd; 27.390 +}
28.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 28.2 +++ b/tools/xenstore/xenstored_domain.h Tue Jun 07 12:43:58 2005 +0000 28.3 @@ -0,0 +1,38 @@ 28.4 +/* 28.5 + Domain communications for Xen Store Daemon. 28.6 + Copyright (C) 2005 Rusty Russell IBM Corporation 28.7 + 28.8 + This program is free software; you can redistribute it and/or modify 28.9 + it under the terms of the GNU General Public License as published by 28.10 + the Free Software Foundation; either version 2 of the License, or 28.11 + (at your option) any later version. 28.12 + 28.13 + This program is distributed in the hope that it will be useful, 28.14 + but WITHOUT ANY WARRANTY; without even the implied warranty of 28.15 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 28.16 + GNU General Public License for more details. 28.17 + 28.18 + You should have received a copy of the GNU General Public License 28.19 + along with this program; if not, write to the Free Software 28.20 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28.21 +*/ 28.22 +#ifndef _XENSTORED_DOMAIN_H 28.23 +#define _XENSTORED_DOMAIN_H 28.24 + 28.25 +void handle_event(int event_fd); 28.26 + 28.27 +/* domid, mfn, eventchn, path */ 28.28 +bool do_introduce(struct connection *conn, struct buffered_data *in); 28.29 + 28.30 +/* domid */ 28.31 +bool do_release(struct connection *conn, const char *domid_str); 28.32 + 28.33 +/* domid */ 28.34 +bool do_get_domain_path(struct connection *conn, const char *domid_str); 28.35 + 28.36 +/* Returns the event channel handle */ 28.37 +int domain_init(void); 28.38 + 28.39 +void domain_set_conn(struct domain *domain, struct connection *conn); 28.40 + 28.41 +#endif /* _XENSTORED_DOMAIN_H */
29.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 29.2 +++ b/tools/xenstore/xenstored_test.h Tue Jun 07 12:43:58 2005 +0000 29.3 @@ -0,0 +1,37 @@ 29.4 +/* 29.5 + Testing replcements for Xen Store Daemon. 29.6 + Copyright (C) 2005 Rusty Russell IBM Corporation 29.7 + 29.8 + This program is free software; you can redistribute it and/or modify 29.9 + it under the terms of the GNU General Public License as published by 29.10 + the Free Software Foundation; either version 2 of the License, or 29.11 + (at your option) any later version. 29.12 + 29.13 + This program is distributed in the hope that it will be useful, 29.14 + but WITHOUT ANY WARRANTY; without even the implied warranty of 29.15 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29.16 + GNU General Public License for more details. 29.17 + 29.18 + You should have received a copy of the GNU General Public License 29.19 + along with this program; if not, write to the Free Software 29.20 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 29.21 +*/ 29.22 +#ifndef _XENSTORED_TEST_H 29.23 +#define _XENSTORED_TEST_H 29.24 + 29.25 +#ifdef TESTING 29.26 +bool test_write_all(int fd, void *contents, unsigned int len); 29.27 +#define write_all test_write_all 29.28 + 29.29 +int test_mkdir(const char *dir, int perms); 29.30 +#define mkdir test_mkdir 29.31 + 29.32 +int fake_open_eventchn(void); 29.33 +void fake_block_events(void); 29.34 +void fake_ack_event(void); 29.35 + 29.36 +#define ioctl(a,b,c) 0 29.37 + 29.38 +#endif 29.39 + 29.40 +#endif /* _XENSTORED_INTERNAL_H */
30.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 30.2 +++ b/tools/xenstore/xenstored_transaction.c Tue Jun 07 12:43:58 2005 +0000 30.3 @@ -0,0 +1,284 @@ 30.4 +/* 30.5 + Transaction code for Xen Store Daemon. 30.6 + Copyright (C) 2005 Rusty Russell IBM Corporation 30.7 + 30.8 + This program is free software; you can redistribute it and/or modify 30.9 + it under the terms of the GNU General Public License as published by 30.10 + the Free Software Foundation; either version 2 of the License, or 30.11 + (at your option) any later version. 30.12 + 30.13 + This program is distributed in the hope that it will be useful, 30.14 + but WITHOUT ANY WARRANTY; without even the implied warranty of 30.15 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 30.16 + GNU General Public License for more details. 30.17 + 30.18 + You should have received a copy of the GNU General Public License 30.19 + along with this program; if not, write to the Free Software 30.20 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 30.21 +*/ 30.22 + 30.23 +#include <stdio.h> 30.24 +#include <sys/types.h> 30.25 +#include <sys/stat.h> 30.26 +#include <sys/wait.h> 30.27 +#include <sys/time.h> 30.28 +#include <time.h> 30.29 +#include <stdarg.h> 30.30 +#include <stdlib.h> 30.31 +#include "talloc.h" 30.32 +#include "list.h" 30.33 +#include "xenstored_transaction.h" 30.34 +#include "xenstored_watch.h" 30.35 +#include "xs_lib.h" 30.36 +#include "utils.h" 30.37 +#include "xenstored_test.h" 30.38 + 30.39 +struct changed_node 30.40 +{ 30.41 + /* The list within this transaction. */ 30.42 + struct list_head list; 30.43 + 30.44 + /* The name of the node. */ 30.45 + char *node; 30.46 +}; 30.47 + 30.48 +struct transaction 30.49 +{ 30.50 + /* Global list of transactions. */ 30.51 + struct list_head list; 30.52 + 30.53 + /* My owner (conn->transaction == me). */ 30.54 + struct connection *conn; 30.55 + 30.56 + /* Subtree this transaction covers */ 30.57 + char *node; 30.58 + 30.59 + /* Base for this transaction. */ 30.60 + char *divert; 30.61 + 30.62 + /* List of changed nodes. */ 30.63 + struct list_head changes; 30.64 + 30.65 + /* Someone's waiting: time limit. */ 30.66 + struct timeval timeout; 30.67 + 30.68 + /* We've timed out. */ 30.69 + bool destined_to_fail; 30.70 +}; 30.71 +static LIST_HEAD(transactions); 30.72 + 30.73 +bool within_transaction(struct transaction *trans, const char *node) 30.74 +{ 30.75 + if (!trans) 30.76 + return true; 30.77 + return is_child(node, trans->node); 30.78 +} 30.79 + 30.80 +/* You are on notice: this transaction is blocking someone. */ 30.81 +static void start_transaction_timeout(struct transaction *trans) 30.82 +{ 30.83 + if (timerisset(&trans->timeout)) 30.84 + return; 30.85 + 30.86 + /* One second timeout. */ 30.87 + gettimeofday(&trans->timeout, NULL); 30.88 + trans->timeout.tv_sec += 1; 30.89 +} 30.90 + 30.91 +struct transaction *transaction_covering_node(const char *node) 30.92 +{ 30.93 + struct transaction *i; 30.94 + 30.95 + list_for_each_entry(i, &transactions, list) { 30.96 + if (i->destined_to_fail) 30.97 + continue; 30.98 + if (is_child(i->node, node) || is_child(node, i->node)) 30.99 + return i; 30.100 + } 30.101 + return NULL; 30.102 +} 30.103 + 30.104 +bool transaction_block(struct connection *conn, const char *node) 30.105 +{ 30.106 + struct transaction *trans; 30.107 + 30.108 + /* Transactions don't overlap, so we can't be blocked by 30.109 + * others if we're in one. */ 30.110 + if (conn->transaction) 30.111 + return false; 30.112 + 30.113 + trans = transaction_covering_node(node); 30.114 + if (trans) { 30.115 + start_transaction_timeout(trans); 30.116 + conn->blocked = talloc_strdup(conn, node); 30.117 + return true; 30.118 + } 30.119 + return false; 30.120 +} 30.121 + 30.122 +/* Callers get a change node (which can fail) and only commit after they've 30.123 + * finished. This way they don't have to unwind eg. a write. */ 30.124 +void add_change_node(struct transaction *trans, const char *node) 30.125 +{ 30.126 + struct changed_node *i; 30.127 + 30.128 + if (!trans) 30.129 + return; 30.130 + 30.131 + list_for_each_entry(i, &trans->changes, list) 30.132 + if (streq(i->node, node)) 30.133 + return; 30.134 + 30.135 + i = talloc(trans, struct changed_node); 30.136 + i->node = talloc_strdup(i, node); 30.137 + INIT_LIST_HEAD(&i->list); 30.138 + list_add_tail(&i->list, &trans->changes); 30.139 +} 30.140 + 30.141 +char *node_dir_inside_transaction(struct transaction *trans, const char *node) 30.142 +{ 30.143 + return talloc_asprintf(node, "%s%s", trans->divert, 30.144 + node + strlen(trans->node)); 30.145 +} 30.146 + 30.147 +void shortest_transaction_timeout(struct timeval *tv) 30.148 +{ 30.149 + struct transaction *i; 30.150 + 30.151 + list_for_each_entry(i, &transactions, list) { 30.152 + if (!timerisset(&i->timeout)) 30.153 + continue; 30.154 + 30.155 + if (!timerisset(tv) || timercmp(&i->timeout, tv, <)) 30.156 + *tv = i->timeout; 30.157 + } 30.158 +} 30.159 + 30.160 +void check_transaction_timeout(void) 30.161 +{ 30.162 + struct transaction *i; 30.163 + struct timeval now; 30.164 + 30.165 + gettimeofday(&now, NULL); 30.166 + 30.167 + list_for_each_entry(i, &transactions, list) { 30.168 + if (!timerisset(&i->timeout)) 30.169 + continue; 30.170 + 30.171 + if (timercmp(&i->timeout, &now, <)) 30.172 + i->destined_to_fail = true; 30.173 + } 30.174 +} 30.175 + 30.176 +/* FIXME: Eliminate all uses of this */ 30.177 +static bool do_command(const char *cmd) 30.178 +{ 30.179 + int ret; 30.180 + 30.181 + ret = system(cmd); 30.182 + if (ret == -1) 30.183 + return false; 30.184 + if (!WIFEXITED(ret) || WEXITSTATUS(ret) != 0) { 30.185 + errno = EIO; 30.186 + return false; 30.187 + } 30.188 + return true; 30.189 +} 30.190 + 30.191 +static int destroy_transaction(void *_transaction) 30.192 +{ 30.193 + struct transaction *trans = _transaction; 30.194 + 30.195 + list_del(&trans->list); 30.196 + return destroy_path(trans->divert); 30.197 +} 30.198 + 30.199 +bool do_transaction_start(struct connection *conn, const char *node) 30.200 +{ 30.201 + struct transaction *transaction; 30.202 + char *dir, *cmd; 30.203 + 30.204 + if (conn->transaction) 30.205 + return send_error(conn, EBUSY); 30.206 + 30.207 + if (!check_node_perms(conn, node, XS_PERM_READ)) 30.208 + return send_error(conn, errno); 30.209 + 30.210 + if (transaction_block(conn, node)) 30.211 + return true; 30.212 + 30.213 + dir = node_dir_outside_transaction(node); 30.214 + 30.215 + /* Attach transaction to node for autofree until it's complete */ 30.216 + transaction = talloc(node, struct transaction); 30.217 + transaction->node = talloc_strdup(transaction, node); 30.218 + transaction->divert = talloc_asprintf(transaction, "%s/%p/", 30.219 + xs_daemon_transactions(), 30.220 + transaction); 30.221 + cmd = talloc_asprintf(node, "cp -a %s %s", dir, transaction->divert); 30.222 + if (!do_command(cmd)) 30.223 + corrupt(conn, "Creating transaction %s", transaction->divert); 30.224 + 30.225 + talloc_steal(conn, transaction); 30.226 + INIT_LIST_HEAD(&transaction->changes); 30.227 + transaction->conn = conn; 30.228 + timerclear(&transaction->timeout); 30.229 + transaction->destined_to_fail = false; 30.230 + list_add_tail(&transaction->list, &transactions); 30.231 + conn->transaction = transaction; 30.232 + talloc_set_destructor(transaction, destroy_transaction); 30.233 + return send_ack(transaction->conn, XS_TRANSACTION_START); 30.234 +} 30.235 + 30.236 +static bool commit_transaction(struct transaction *trans) 30.237 +{ 30.238 + char *tmp, *dir; 30.239 + struct changed_node *i; 30.240 + 30.241 + /* Move: orig -> .old, repl -> orig. Cleanup deletes .old. */ 30.242 + dir = node_dir_outside_transaction(trans->node); 30.243 + tmp = talloc_asprintf(trans, "%s.old", dir); 30.244 + 30.245 + if (rename(dir, tmp) != 0) 30.246 + return false; 30.247 + if (rename(trans->divert, dir) != 0) 30.248 + corrupt(trans->conn, "Failed rename %s to %s", 30.249 + trans->divert, dir); 30.250 + 30.251 + trans->divert = tmp; 30.252 + 30.253 + /* Fire off the watches for everything that changed. */ 30.254 + list_for_each_entry(i, &trans->changes, list) 30.255 + fire_watches(NULL, i->node); 30.256 + return true; 30.257 +} 30.258 + 30.259 +bool do_transaction_end(struct connection *conn, const char *arg) 30.260 +{ 30.261 + if (!arg || (!streq(arg, "T") && !streq(arg, "F"))) 30.262 + return send_error(conn, EINVAL); 30.263 + 30.264 + if (!conn->transaction) 30.265 + return send_error(conn, ENOENT); 30.266 + 30.267 + if (streq(arg, "T")) { 30.268 + if (conn->transaction->destined_to_fail) { 30.269 + send_error(conn, ETIMEDOUT); 30.270 + goto failed; 30.271 + } 30.272 + if (!commit_transaction(conn->transaction)) { 30.273 + send_error(conn, errno); 30.274 + goto failed; 30.275 + } 30.276 + } 30.277 + 30.278 + talloc_free(conn->transaction); 30.279 + conn->transaction = NULL; 30.280 + return send_ack(conn, XS_TRANSACTION_END); 30.281 + 30.282 +failed: 30.283 + talloc_free(conn->transaction); 30.284 + conn->transaction = NULL; 30.285 + return false; 30.286 +} 30.287 +
31.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 31.2 +++ b/tools/xenstore/xenstored_transaction.h Tue Jun 07 12:43:58 2005 +0000 31.3 @@ -0,0 +1,50 @@ 31.4 +/* 31.5 + Transaction code for Xen Store Daemon. 31.6 + Copyright (C) 2005 Rusty Russell IBM Corporation 31.7 + 31.8 + This program is free software; you can redistribute it and/or modify 31.9 + it under the terms of the GNU General Public License as published by 31.10 + the Free Software Foundation; either version 2 of the License, or 31.11 + (at your option) any later version. 31.12 + 31.13 + This program is distributed in the hope that it will be useful, 31.14 + but WITHOUT ANY WARRANTY; without even the implied warranty of 31.15 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 31.16 + GNU General Public License for more details. 31.17 + 31.18 + You should have received a copy of the GNU General Public License 31.19 + along with this program; if not, write to the Free Software 31.20 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 31.21 +*/ 31.22 +#ifndef _XENSTORED_TRANSACTION_H 31.23 +#define _XENSTORED_TRANSACTION_H 31.24 +#include "xenstored_core.h" 31.25 + 31.26 +struct transaction; 31.27 + 31.28 +bool do_transaction_start(struct connection *conn, const char *node); 31.29 +bool do_transaction_end(struct connection *conn, const char *arg); 31.30 + 31.31 +/* Is node covered by this transaction? */ 31.32 +bool within_transaction(struct transaction *trans, const char *node); 31.33 + 31.34 +/* If a write op on this node blocked by another connections' transaction, 31.35 + * mark conn, setup transaction timeout and return true. 31.36 + */ 31.37 +bool transaction_block(struct connection *conn, const char *node); 31.38 + 31.39 +/* Return transaction which covers this node. */ 31.40 +struct transaction *transaction_covering_node(const char *node); 31.41 + 31.42 +/* Return directory of node within transaction t. */ 31.43 +char *node_dir_inside_transaction(struct transaction *t, const char *node); 31.44 + 31.45 +/* This node was changed: can fail and longjmp. */ 31.46 +void add_change_node(struct transaction *trans, const char *node); 31.47 + 31.48 +/* Get shortest timeout: leave tv unset if none. */ 31.49 +void shortest_transaction_timeout(struct timeval *tv); 31.50 + 31.51 +/* Have any transactions timed out yet? */ 31.52 +void check_transaction_timeout(void); 31.53 +#endif /* _XENSTORED_TRANSACTION_H */
32.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 32.2 +++ b/tools/xenstore/xenstored_watch.c Tue Jun 07 12:43:58 2005 +0000 32.3 @@ -0,0 +1,279 @@ 32.4 +/* 32.5 + Watch code for Xen Store Daemon. 32.6 + Copyright (C) 2005 Rusty Russell IBM Corporation 32.7 + 32.8 + This program is free software; you can redistribute it and/or modify 32.9 + it under the terms of the GNU General Public License as published by 32.10 + the Free Software Foundation; either version 2 of the License, or 32.11 + (at your option) any later version. 32.12 + 32.13 + This program is distributed in the hope that it will be useful, 32.14 + but WITHOUT ANY WARRANTY; without even the implied warranty of 32.15 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 32.16 + GNU General Public License for more details. 32.17 + 32.18 + You should have received a copy of the GNU General Public License 32.19 + along with this program; if not, write to the Free Software 32.20 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 32.21 +*/ 32.22 + 32.23 +#include <stdio.h> 32.24 +#include <sys/types.h> 32.25 +#include <stdarg.h> 32.26 +#include <stdlib.h> 32.27 +#include "talloc.h" 32.28 +#include "list.h" 32.29 +#include "xenstored_watch.h" 32.30 +#include "xs_lib.h" 32.31 +#include "utils.h" 32.32 +#include "xenstored_test.h" 32.33 + 32.34 +/* We create this if anyone is interested "node", then we pass it from 32.35 + * watch to watch as each connection acks it. 32.36 + */ 32.37 +struct watch_event 32.38 +{ 32.39 + /* The watch we are firing for (watch->events) */ 32.40 + struct list_head list; 32.41 + 32.42 + /* Watch we are currently attached to. */ 32.43 + struct watch *watch; 32.44 + 32.45 + struct buffered_data *data; 32.46 +}; 32.47 + 32.48 +struct watch 32.49 +{ 32.50 + struct list_head list; 32.51 + unsigned int priority; 32.52 + 32.53 + /* Current outstanding events applying to this watch. */ 32.54 + struct list_head events; 32.55 + 32.56 + char *node; 32.57 + struct connection *conn; 32.58 +}; 32.59 +static LIST_HEAD(watches); 32.60 + 32.61 +static void reset_event(struct watch_event *event) 32.62 +{ 32.63 + event->data->inhdr = true; 32.64 + event->data->used = 0; 32.65 +} 32.66 + 32.67 +/* We received a non-ACK response: re-queue any watch we just sent. */ 32.68 +void reset_watch_event(struct connection *conn) 32.69 +{ 32.70 + if (waiting_for_ack(conn)) 32.71 + reset_event(conn->event); 32.72 +} 32.73 + 32.74 +/* We're waiting if we have an event and we sent it all. */ 32.75 +bool waiting_for_ack(struct connection *conn) 32.76 +{ 32.77 + if (!conn->event) 32.78 + return false; 32.79 + 32.80 + if (conn->event->data->inhdr) 32.81 + return false; 32.82 + return conn->event->data->used == conn->event->data->hdr.msg.len; 32.83 +} 32.84 + 32.85 +bool is_watch_event(struct connection *conn, struct buffered_data *out) 32.86 +{ 32.87 + return (conn->event && out == conn->event->data); 32.88 +} 32.89 + 32.90 +/* Look through our watches: if any of them have an event, queue it. */ 32.91 +void queue_next_event(struct connection *conn) 32.92 +{ 32.93 + struct watch *watch; 32.94 + 32.95 + /* We had a reply queued already? Send it. */ 32.96 + if (conn->waiting_reply) { 32.97 + conn->out = conn->waiting_reply; 32.98 + conn->waiting_reply = NULL; 32.99 + return; 32.100 + } 32.101 + 32.102 + /* If we're waiting for ack, don't queue more. */ 32.103 + if (waiting_for_ack(conn)) 32.104 + return; 32.105 + 32.106 + /* Find a good event to send. */ 32.107 + if (!conn->event) { 32.108 + list_for_each_entry(watch, &watches, list) { 32.109 + if (watch->conn != conn) 32.110 + continue; 32.111 + 32.112 + conn->event = list_top(&watch->events, 32.113 + struct watch_event, list); 32.114 + if (conn->event) 32.115 + break; 32.116 + } 32.117 + if (!conn->event) 32.118 + return; 32.119 + } 32.120 + 32.121 + conn->out = conn->event->data; 32.122 +} 32.123 + 32.124 +/* Watch on DIR applies to DIR, DIR/FILE, but not DIRLONG. */ 32.125 +static bool watch_applies(const struct watch *watch, const char *node) 32.126 +{ 32.127 + return is_child(node, watch->node); 32.128 +} 32.129 + 32.130 +static struct watch *find_watch(const char *node) 32.131 +{ 32.132 + struct watch *watch; 32.133 + 32.134 + list_for_each_entry(watch, &watches, list) { 32.135 + if (watch_applies(watch, node)) 32.136 + return watch; 32.137 + } 32.138 + return NULL; 32.139 +} 32.140 + 32.141 +static struct watch *find_next_watch(struct watch *watch, const char *node) 32.142 +{ 32.143 + list_for_each_entry_continue(watch, &watches, list) { 32.144 + if (watch_applies(watch, node)) 32.145 + return watch; 32.146 + } 32.147 + return NULL; 32.148 +} 32.149 + 32.150 +/* FIXME: we fail to fire on out of memory. Should drop connections. */ 32.151 +void fire_watches(struct transaction *trans, const char *node) 32.152 +{ 32.153 + struct watch *watch; 32.154 + struct watch_event *event; 32.155 + 32.156 + /* During transactions, don't fire watches. */ 32.157 + if (trans) 32.158 + return; 32.159 + 32.160 + watch = find_watch(node); 32.161 + if (!watch) 32.162 + return; 32.163 + 32.164 + /* Create and fill in info about event. */ 32.165 + event = talloc(talloc_autofree_context(), struct watch_event); 32.166 + event->data = new_buffer(event); 32.167 + event->data->hdr.msg.type = XS_WATCH_EVENT; 32.168 + event->data->hdr.msg.len = strlen(node) + 1; 32.169 + event->data->buffer = talloc_strdup(event->data, node); 32.170 + 32.171 + /* Tie event to this watch. */ 32.172 + event->watch = watch; 32.173 + list_add(&event->list, &watch->events); 32.174 + 32.175 + /* If connection not doing anything, queue this. */ 32.176 + if (!watch->conn->out) 32.177 + queue_next_event(watch->conn); 32.178 +} 32.179 + 32.180 +/* We're done with this event: see if anyone else wants it. */ 32.181 +static void move_event_onwards(struct watch_event *event) 32.182 +{ 32.183 + list_del(&event->list); 32.184 + reset_event(event); 32.185 + 32.186 + /* Remove from this watch, and find next watch to put this on. */ 32.187 + event->watch = find_next_watch(event->watch, event->data->buffer); 32.188 + if (!event->watch) { 32.189 + talloc_free(event); 32.190 + return; 32.191 + } 32.192 + 32.193 + list_add(&event->list, &event->watch->events); 32.194 + 32.195 + /* If connection not doing anything, queue this. */ 32.196 + if (!event->watch->conn->out) 32.197 + queue_next_event(event->watch->conn); 32.198 +} 32.199 + 32.200 +static int destroy_watch(void *_watch) 32.201 +{ 32.202 + struct watch *watch = _watch; 32.203 + struct watch_event *event; 32.204 + 32.205 + /* Forget about sending out or waiting for acks for this watch. */ 32.206 + if (watch->conn->event && watch->conn->event->watch == watch) 32.207 + watch->conn->event = NULL; 32.208 + 32.209 + /* If we have pending events, pass them on to others. */ 32.210 + while ((event = list_top(&watch->events, struct watch_event, list))) 32.211 + move_event_onwards(event); 32.212 + 32.213 + /* Remove from global list. */ 32.214 + list_del(&watch->list); 32.215 + return 0; 32.216 +} 32.217 + 32.218 +/* We keep watches in priority order. */ 32.219 +static void insert_watch(struct watch *watch) 32.220 +{ 32.221 + struct watch *i; 32.222 + 32.223 + list_for_each_entry(i, &watches, list) { 32.224 + if (i->priority <= watch->priority) { 32.225 + list_add_tail(&watch->list, &i->list); 32.226 + return; 32.227 + } 32.228 + } 32.229 + 32.230 + list_add_tail(&watch->list, &watches); 32.231 +} 32.232 + 32.233 +bool do_watch(struct connection *conn, struct buffered_data *in) 32.234 +{ 32.235 + struct watch *watch; 32.236 + char *vec[2]; 32.237 + 32.238 + if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec)) 32.239 + return send_error(conn, EINVAL); 32.240 + 32.241 + if (!check_node_perms(conn, vec[0], XS_PERM_READ)) 32.242 + return send_error(conn, errno); 32.243 + 32.244 + watch = talloc(conn, struct watch); 32.245 + watch->node = talloc_strdup(watch, vec[0]); 32.246 + watch->conn = conn; 32.247 + watch->priority = strtoul(vec[1], NULL, 0); 32.248 + INIT_LIST_HEAD(&watch->events); 32.249 + 32.250 + insert_watch(watch); 32.251 + talloc_set_destructor(watch, destroy_watch); 32.252 + return send_ack(conn, XS_WATCH); 32.253 +} 32.254 + 32.255 +bool do_watch_ack(struct connection *conn) 32.256 +{ 32.257 + struct watch_event *event; 32.258 + 32.259 + if (!waiting_for_ack(conn)) 32.260 + return send_error(conn, ENOENT); 32.261 + 32.262 + /* Remove this watch event. */ 32.263 + event = conn->event; 32.264 + conn->event = NULL; 32.265 + 32.266 + move_event_onwards(event); 32.267 + return send_ack(conn, XS_WATCH_ACK); 32.268 +} 32.269 + 32.270 +bool do_unwatch(struct connection *conn, const char *node) 32.271 +{ 32.272 + struct watch *watch; 32.273 + 32.274 + list_for_each_entry(watch, &watches, list) { 32.275 + if (watch->conn == conn 32.276 + && streq(watch->node, node)) { 32.277 + talloc_free(watch); 32.278 + return send_ack(conn, XS_UNWATCH); 32.279 + } 32.280 + } 32.281 + return send_error(conn, ENOENT); 32.282 +}
33.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 33.2 +++ b/tools/xenstore/xenstored_watch.h Tue Jun 07 12:43:58 2005 +0000 33.3 @@ -0,0 +1,42 @@ 33.4 +/* 33.5 + Watch code for Xen Store Daemon. 33.6 + Copyright (C) 2005 Rusty Russell IBM Corporation 33.7 + 33.8 + This program is free software; you can redistribute it and/or modify 33.9 + it under the terms of the GNU General Public License as published by 33.10 + the Free Software Foundation; either version 2 of the License, or 33.11 + (at your option) any later version. 33.12 + 33.13 + This program is distributed in the hope that it will be useful, 33.14 + but WITHOUT ANY WARRANTY; without even the implied warranty of 33.15 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 33.16 + GNU General Public License for more details. 33.17 + 33.18 + You should have received a copy of the GNU General Public License 33.19 + along with this program; if not, write to the Free Software 33.20 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 33.21 +*/ 33.22 +#ifndef _XENSTORED_WATCH_H 33.23 +#define _XENSTORED_WATCH_H 33.24 +#include "xenstored_core.h" 33.25 + 33.26 +bool do_watch(struct connection *conn, struct buffered_data *in); 33.27 +bool do_watch_ack(struct connection *conn); 33.28 +bool do_unwatch(struct connection *conn, const char *node); 33.29 + 33.30 +/* Is this a watch event message for this connection? */ 33.31 +bool is_watch_event(struct connection *conn, struct buffered_data *out); 33.32 + 33.33 +/* Look through our watches: if any of them have an event, queue it. */ 33.34 +void queue_next_event(struct connection *conn); 33.35 + 33.36 +/* Is this connection waiting for a watch acknowledgement? */ 33.37 +bool waiting_for_ack(struct connection *conn); 33.38 + 33.39 +/* Reset event if we were sending one */ 33.40 +void reset_watch_event(struct connection *conn); 33.41 + 33.42 +/* Fire all watches. */ 33.43 +void fire_watches(struct transaction *trans, const char *node); 33.44 + 33.45 +#endif /* _XENSTORED_WATCH_H */
34.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 34.2 +++ b/tools/xenstore/xs.c Tue Jun 07 12:43:58 2005 +0000 34.3 @@ -0,0 +1,551 @@ 34.4 +/* 34.5 + Xen Store Daemon interface providing simple tree-like database. 34.6 + Copyright (C) 2005 Rusty Russell IBM Corporation 34.7 + 34.8 + This program is free software; you can redistribute it and/or modify 34.9 + it under the terms of the GNU General Public License as published by 34.10 + the Free Software Foundation; either version 2 of the License, or 34.11 + (at your option) any later version. 34.12 + 34.13 + This program is distributed in the hope that it will be useful, 34.14 + but WITHOUT ANY WARRANTY; without even the implied warranty of 34.15 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 34.16 + GNU General Public License for more details. 34.17 + 34.18 + You should have received a copy of the GNU General Public License 34.19 + along with this program; if not, write to the Free Software 34.20 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 34.21 +*/ 34.22 + 34.23 +#include <sys/types.h> 34.24 +#include <sys/stat.h> 34.25 +#include <fcntl.h> 34.26 +#include <sys/socket.h> 34.27 +#include <sys/un.h> 34.28 +#include <string.h> 34.29 +#include <unistd.h> 34.30 +#include <stdbool.h> 34.31 +#include <stdlib.h> 34.32 +#include <assert.h> 34.33 +#include <stdio.h> 34.34 +#include <signal.h> 34.35 +#include <stdint.h> 34.36 +#include <errno.h> 34.37 +#include "xs.h" 34.38 +#include "xenstored.h" 34.39 +#include "xs_lib.h" 34.40 +#include "utils.h" 34.41 + 34.42 +struct xs_handle 34.43 +{ 34.44 + int fd; 34.45 +}; 34.46 + 34.47 +/* Get the socket from the store daemon handle. 34.48 + */ 34.49 +int xs_fileno(struct xs_handle *h) 34.50 +{ 34.51 + return h->fd; 34.52 +} 34.53 + 34.54 +static struct xs_handle *get_socket(const char *connect_to) 34.55 +{ 34.56 + struct sockaddr_un addr; 34.57 + int sock, saved_errno; 34.58 + struct xs_handle *h = NULL; 34.59 + 34.60 + sock = socket(PF_UNIX, SOCK_STREAM, 0); 34.61 + if (sock < 0) 34.62 + return NULL; 34.63 + 34.64 + addr.sun_family = AF_UNIX; 34.65 + strcpy(addr.sun_path, connect_to); 34.66 + 34.67 + if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) { 34.68 + h = malloc(sizeof(*h)); 34.69 + if (h) { 34.70 + h->fd = sock; 34.71 + return h; 34.72 + } 34.73 + } 34.74 + 34.75 + saved_errno = errno; 34.76 + close(sock); 34.77 + free(h); 34.78 + errno = saved_errno; 34.79 + return NULL; 34.80 +} 34.81 + 34.82 +struct xs_handle *xs_daemon_open(void) 34.83 +{ 34.84 + return get_socket(xs_daemon_socket()); 34.85 +} 34.86 + 34.87 +struct xs_handle *xs_daemon_open_readonly(void) 34.88 +{ 34.89 + return get_socket(xs_daemon_socket_ro()); 34.90 +} 34.91 + 34.92 +void xs_daemon_close(struct xs_handle *h) 34.93 +{ 34.94 + if (h->fd >= 0) 34.95 + close(h->fd); 34.96 + free(h); 34.97 +} 34.98 + 34.99 +static bool read_all(int fd, void *data, unsigned int len) 34.100 +{ 34.101 + while (len) { 34.102 + int done; 34.103 + 34.104 + done = read(fd, data, len); 34.105 + if (done < 0) { 34.106 + if (errno == EINTR) 34.107 + continue; 34.108 + return false; 34.109 + } 34.110 + if (done == 0) { 34.111 + /* It closed fd on us? EBADF is appropriate. */ 34.112 + errno = EBADF; 34.113 + return false; 34.114 + } 34.115 + data += done; 34.116 + len -= done; 34.117 + } 34.118 + 34.119 + return true; 34.120 +} 34.121 + 34.122 +#ifdef XSTEST 34.123 +#define read_all read_all_choice 34.124 +#define write_all write_all_choice 34.125 +#endif 34.126 + 34.127 +static int get_error(const char *errorstring) 34.128 +{ 34.129 + unsigned int i; 34.130 + 34.131 + for (i = 0; !streq(errorstring, xsd_errors[i].errstring); i++) 34.132 + if (i == ARRAY_SIZE(xsd_errors) - 1) 34.133 + return EINVAL; 34.134 + return xsd_errors[i].errnum; 34.135 +} 34.136 + 34.137 +static void *read_reply(int fd, enum xsd_sockmsg_type *type, unsigned int *len) 34.138 +{ 34.139 + struct xsd_sockmsg msg; 34.140 + void *ret; 34.141 + int saved_errno; 34.142 + 34.143 + if (!read_all(fd, &msg, sizeof(msg))) 34.144 + return NULL; 34.145 + 34.146 + ret = malloc(msg.len); 34.147 + if (!ret) 34.148 + return NULL; 34.149 + 34.150 + if (!read_all(fd, ret, msg.len)) { 34.151 + saved_errno = errno; 34.152 + free(ret); 34.153 + errno = saved_errno; 34.154 + return NULL; 34.155 + } 34.156 + 34.157 + *type = msg.type; 34.158 + if (len) 34.159 + *len = msg.len; 34.160 + return ret; 34.161 +} 34.162 + 34.163 +/* Send message to xs, get malloc'ed reply. NULL and set errno on error. */ 34.164 +static void *xs_talkv(struct xs_handle *h, enum xsd_sockmsg_type type, 34.165 + const struct iovec *iovec, 34.166 + unsigned int num_vecs, 34.167 + unsigned int *len) 34.168 +{ 34.169 + struct xsd_sockmsg msg; 34.170 + void *ret = NULL; 34.171 + int saved_errno; 34.172 + unsigned int i; 34.173 + struct sigaction ignorepipe, oldact; 34.174 + 34.175 + msg.type = type; 34.176 + msg.len = 0; 34.177 + for (i = 0; i < num_vecs; i++) 34.178 + msg.len += iovec[i].iov_len; 34.179 + 34.180 + ignorepipe.sa_handler = SIG_IGN; 34.181 + sigemptyset(&ignorepipe.sa_mask); 34.182 + ignorepipe.sa_flags = 0; 34.183 + sigaction(SIGPIPE, &ignorepipe, &oldact); 34.184 + 34.185 + if (!write_all(h->fd, &msg, sizeof(msg))) 34.186 + goto fail; 34.187 + 34.188 + for (i = 0; i < num_vecs; i++) 34.189 + if (!write_all(h->fd, iovec[i].iov_base, iovec[i].iov_len)) 34.190 + goto fail; 34.191 + 34.192 + /* Watches can have fired before reply comes: daemon detects 34.193 + * and re-transmits, so we can ignore this. */ 34.194 + do { 34.195 + free(ret); 34.196 + ret = read_reply(h->fd, &msg.type, len); 34.197 + if (!ret) 34.198 + goto fail; 34.199 + } while (msg.type == XS_WATCH_EVENT); 34.200 + 34.201 + sigaction(SIGPIPE, &oldact, NULL); 34.202 + if (msg.type == XS_ERROR) { 34.203 + saved_errno = get_error(ret); 34.204 + free(ret); 34.205 + errno = saved_errno; 34.206 + return NULL; 34.207 + } 34.208 + 34.209 + assert(msg.type == type); 34.210 + return ret; 34.211 + 34.212 +fail: 34.213 + /* We're in a bad state, so close fd. */ 34.214 + saved_errno = errno; 34.215 + sigaction(SIGPIPE, &oldact, NULL); 34.216 + close(h->fd); 34.217 + h->fd = -1; 34.218 + errno = saved_errno; 34.219 + return NULL; 34.220 +} 34.221 + 34.222 +/* free(), but don't change errno. */ 34.223 +static void free_no_errno(void *p) 34.224 +{ 34.225 + int saved_errno = errno; 34.226 + free(p); 34.227 + errno = saved_errno; 34.228 +} 34.229 + 34.230 +/* Simplified version of xs_talkv: single message. */ 34.231 +static void *xs_single(struct xs_handle *h, enum xsd_sockmsg_type type, 34.232 + const char *string, unsigned int *len) 34.233 +{ 34.234 + struct iovec iovec; 34.235 + 34.236 + iovec.iov_base = (void *)string; 34.237 + iovec.iov_len = strlen(string) + 1; 34.238 + return xs_talkv(h, type, &iovec, 1, len); 34.239 +} 34.240 + 34.241 +static bool xs_bool(char *reply) 34.242 +{ 34.243 + if (!reply) 34.244 + return false; 34.245 + free(reply); 34.246 + return true; 34.247 +} 34.248 + 34.249 +char **xs_directory(struct xs_handle *h, const char *path, unsigned int *num) 34.250 +{ 34.251 + char *strings, *p, **ret; 34.252 + unsigned int len; 34.253 + 34.254 + strings = xs_single(h, XS_DIRECTORY, path, &len); 34.255 + if (!strings) 34.256 + return NULL; 34.257 + 34.258 + /* Count the strings. */ 34.259 + *num = count_strings(strings, len); 34.260 + 34.261 + /* Transfer to one big alloc for easy freeing. */ 34.262 + ret = malloc(*num * sizeof(char *) + len); 34.263 + if (!ret) { 34.264 + free_no_errno(strings); 34.265 + return NULL; 34.266 + } 34.267 + memcpy(&ret[*num], strings, len); 34.268 + free_no_errno(strings); 34.269 + 34.270 + strings = (char *)&ret[*num]; 34.271 + for (p = strings, *num = 0; p < strings + len; p += strlen(p) + 1) 34.272 + ret[(*num)++] = p; 34.273 + return ret; 34.274 +} 34.275 + 34.276 +/* Get the value of a single file. 34.277 + * Returns a malloced value: call free() on it after use. 34.278 + * len indicates length in bytes. 34.279 + */ 34.280 +void *xs_read(struct xs_handle *h, const char *path, unsigned int *len) 34.281 +{ 34.282 + return xs_single(h, XS_READ, path, len); 34.283 +} 34.284 + 34.285 +/* Write the value of a single file. 34.286 + * Returns false on failure. createflags can be 0, O_CREAT, or O_CREAT|O_EXCL. 34.287 + */ 34.288 +bool xs_write(struct xs_handle *h, const char *path, 34.289 + const void *data, unsigned int len, int createflags) 34.290 +{ 34.291 + const char *flags; 34.292 + struct iovec iovec[3]; 34.293 + 34.294 + /* Format: Flags (as string), path, data. */ 34.295 + if (createflags == 0) 34.296 + flags = XS_WRITE_NONE; 34.297 + else if (createflags == O_CREAT) 34.298 + flags = XS_WRITE_CREATE; 34.299 + else if (createflags == (O_CREAT|O_EXCL)) 34.300 + flags = XS_WRITE_CREATE_EXCL; 34.301 + else { 34.302 + errno = EINVAL; 34.303 + return false; 34.304 + } 34.305 + 34.306 + iovec[0].iov_base = (void *)path; 34.307 + iovec[0].iov_len = strlen(path) + 1; 34.308 + iovec[1].iov_base = (void *)flags; 34.309 + iovec[1].iov_len = strlen(flags) + 1; 34.310 + iovec[2].iov_base = (void *)data; 34.311 + iovec[2].iov_len = len; 34.312 + 34.313 + return xs_bool(xs_talkv(h, XS_WRITE, iovec, ARRAY_SIZE(iovec), NULL)); 34.314 +} 34.315 + 34.316 +/* Create a new directory. 34.317 + * Returns false on failure. 34.318 + */ 34.319 +bool xs_mkdir(struct xs_handle *h, const char *path) 34.320 +{ 34.321 + return xs_bool(xs_single(h, XS_MKDIR, path, NULL)); 34.322 +} 34.323 + 34.324 +/* Destroy a file or directory (directories must be empty). 34.325 + * Returns false on failure. 34.326 + */ 34.327 +bool xs_rm(struct xs_handle *h, const char *path) 34.328 +{ 34.329 + return xs_bool(xs_single(h, XS_RM, path, NULL)); 34.330 +} 34.331 + 34.332 +/* Get permissions of node (first element is owner). 34.333 + * Returns malloced array, or NULL: call free() after use. 34.334 + */ 34.335 +struct xs_permissions *xs_get_permissions(struct xs_handle *h, 34.336 + const char *path, 34.337 + unsigned int *num) 34.338 +{ 34.339 + char *strings; 34.340 + unsigned int len; 34.341 + struct xs_permissions *ret; 34.342 + 34.343 + strings = xs_single(h, XS_GET_PERMS, path, &len); 34.344 + if (!strings) 34.345 + return NULL; 34.346 + 34.347 + /* Count the strings: each one perms then domid. */ 34.348 + *num = count_strings(strings, len); 34.349 + 34.350 + /* Transfer to one big alloc for easy freeing. */ 34.351 + ret = malloc(*num * sizeof(struct xs_permissions)); 34.352 + if (!ret) { 34.353 + free_no_errno(strings); 34.354 + return NULL; 34.355 + } 34.356 + 34.357 + if (!strings_to_perms(ret, *num, strings)) { 34.358 + free_no_errno(ret); 34.359 + ret = NULL; 34.360 + } 34.361 + 34.362 + free(strings); 34.363 + return ret; 34.364 +} 34.365 + 34.366 +/* Set permissions of node (must be owner). 34.367 + * Returns false on failure. 34.368 + */ 34.369 +bool xs_set_permissions(struct xs_handle *h, const char *path, 34.370 + struct xs_permissions *perms, 34.371 + unsigned int num_perms) 34.372 +{ 34.373 + unsigned int i; 34.374 + struct iovec iov[1+num_perms]; 34.375 + 34.376 + iov[0].iov_base = (void *)path; 34.377 + iov[0].iov_len = strlen(path) + 1; 34.378 + 34.379 + for (i = 0; i < num_perms; i++) { 34.380 + char buffer[MAX_STRLEN(domid_t)+1]; 34.381 + 34.382 + if (!perm_to_string(&perms[i], buffer)) 34.383 + goto unwind; 34.384 + 34.385 + iov[i+1].iov_base = strdup(buffer); 34.386 + iov[i+1].iov_len = strlen(buffer) + 1; 34.387 + if (!iov[i+1].iov_base) 34.388 + goto unwind; 34.389 + } 34.390 + 34.391 + if (!xs_bool(xs_talkv(h, XS_SET_PERMS, iov, 1+num_perms, NULL))) 34.392 + goto unwind; 34.393 + for (i = 0; i < num_perms; i++) 34.394 + free(iov[i+1].iov_base); 34.395 + return true; 34.396 + 34.397 +unwind: 34.398 + num_perms = i; 34.399 + for (i = 0; i < num_perms; i++) 34.400 + free_no_errno(iov[i+1].iov_base); 34.401 + return false; 34.402 +} 34.403 + 34.404 +/* Watch a node for changes (poll on fd to detect, or call read_watch()). 34.405 + * When the node (or any child) changes, fd will become readable. 34.406 + * Priority indicates order if multiple watchers: higher is first. 34.407 + * Returns false on failure. 34.408 + */ 34.409 +bool xs_watch(struct xs_handle *h, const char *path, unsigned int priority) 34.410 +{ 34.411 + char prio[MAX_STRLEN(priority)]; 34.412 + struct iovec iov[2]; 34.413 + 34.414 + sprintf(prio, "%u", priority); 34.415 + iov[0].iov_base = (void *)path; 34.416 + iov[0].iov_len = strlen(path) + 1; 34.417 + iov[1].iov_base = prio; 34.418 + iov[1].iov_len = strlen(prio) + 1; 34.419 + 34.420 + return xs_bool(xs_talkv(h, XS_WATCH, iov, ARRAY_SIZE(iov), NULL)); 34.421 +} 34.422 + 34.423 +/* Find out what node change was on (will block if nothing pending). 34.424 + * Returns malloced path, or NULL: call free() after use. 34.425 + */ 34.426 +char *xs_read_watch(struct xs_handle *h) 34.427 +{ 34.428 + struct xsd_sockmsg msg; 34.429 + char *path; 34.430 + 34.431 + if (!read_all(h->fd, &msg, sizeof(msg))) 34.432 + return NULL; 34.433 + 34.434 + assert(msg.type == XS_WATCH_EVENT); 34.435 + path = malloc(msg.len); 34.436 + if (!path) 34.437 + return NULL; 34.438 + 34.439 + if (!read_all(h->fd, path, msg.len)) { 34.440 + free_no_errno(path); 34.441 + return NULL; 34.442 + } 34.443 + return path; 34.444 +} 34.445 + 34.446 +/* Acknowledge watch on node. Watches must be acknowledged before 34.447 + * any other watches can be read. 34.448 + * Returns false on failure. 34.449 + */ 34.450 +bool xs_acknowledge_watch(struct xs_handle *h) 34.451 +{ 34.452 + return xs_bool(xs_single(h, XS_WATCH_ACK, "OK", NULL)); 34.453 +} 34.454 + 34.455 +/* Remove a watch on a node. 34.456 + * Returns false on failure (no watch on that node). 34.457 + */ 34.458 +bool xs_unwatch(struct xs_handle *h, const char *path) 34.459 +{ 34.460 + return xs_bool(xs_single(h, XS_UNWATCH, path, NULL)); 34.461 +} 34.462 + 34.463 +/* Start a transaction: changes by others will not be seen during this 34.464 + * transaction, and changes will not be visible to others until end. 34.465 + * Transaction only applies to the given subtree. 34.466 + * You can only have one transaction at any time. 34.467 + * Returns false on failure. 34.468 + */ 34.469 +bool xs_transaction_start(struct xs_handle *h, const char *subtree) 34.470 +{ 34.471 + return xs_bool(xs_single(h, XS_TRANSACTION_START, subtree, NULL)); 34.472 +} 34.473 + 34.474 +/* End a transaction. 34.475 + * If abandon is true, transaction is discarded instead of committed. 34.476 + * Returns false on failure, which indicates an error: transactions will 34.477 + * not fail spuriously. 34.478 + */ 34.479 +bool xs_transaction_end(struct xs_handle *h, bool abort) 34.480 +{ 34.481 + char abortstr[2]; 34.482 + 34.483 + if (abort) 34.484 + strcpy(abortstr, "F"); 34.485 + else 34.486 + strcpy(abortstr, "T"); 34.487 + return xs_bool(xs_single(h, XS_TRANSACTION_END, abortstr, NULL)); 34.488 +} 34.489 + 34.490 +/* Introduce a new domain. 34.491 + * This tells the store daemon about a shared memory page and event channel 34.492 + * associated with a domain: the domain uses these to communicate. 34.493 + */ 34.494 +bool xs_introduce_domain(struct xs_handle *h, 34.495 + domid_t domid, 34.496 + unsigned long mfn, 34.497 + unsigned int eventchn, 34.498 + const char *path) 34.499 +{ 34.500 + char domid_str[MAX_STRLEN(domid)]; 34.501 + char mfn_str[MAX_STRLEN(mfn)]; 34.502 + char eventchn_str[MAX_STRLEN(eventchn)]; 34.503 + struct iovec iov[4]; 34.504 + 34.505 + sprintf(domid_str, "%u", domid); 34.506 + sprintf(mfn_str, "%lu", mfn); 34.507 + sprintf(eventchn_str, "%u", eventchn); 34.508 + 34.509 + iov[0].iov_base = domid_str; 34.510 + iov[0].iov_len = strlen(domid_str) + 1; 34.511 + iov[1].iov_base = mfn_str; 34.512 + iov[1].iov_len = strlen(mfn_str) + 1; 34.513 + iov[2].iov_base = eventchn_str; 34.514 + iov[2].iov_len = strlen(eventchn_str) + 1; 34.515 + iov[3].iov_base = (char *)path; 34.516 + iov[3].iov_len = strlen(path) + 1; 34.517 + 34.518 + return xs_bool(xs_talkv(h, XS_INTRODUCE, iov, ARRAY_SIZE(iov), NULL)); 34.519 +} 34.520 + 34.521 +bool xs_release_domain(struct xs_handle *h, 34.522 + domid_t domid) 34.523 +{ 34.524 + char domid_str[MAX_STRLEN(domid)]; 34.525 + 34.526 + sprintf(domid_str, "%u", domid); 34.527 + 34.528 + return xs_bool(xs_single(h, XS_RELEASE, domid_str, NULL)); 34.529 +} 34.530 + 34.531 +bool xs_shutdown(struct xs_handle *h) 34.532 +{ 34.533 + bool ret = xs_bool(xs_single(h, XS_SHUTDOWN, "", NULL)); 34.534 + if (ret) { 34.535 + char c; 34.536 + /* Wait for it to actually shutdown. */ 34.537 + read(h->fd, &c, 1); 34.538 + } 34.539 + return ret; 34.540 +} 34.541 + 34.542 +/* Only useful for DEBUG versions */ 34.543 +char *xs_debug_command(struct xs_handle *h, const char *cmd, 34.544 + void *data, unsigned int len) 34.545 +{ 34.546 + struct iovec iov[2]; 34.547 + 34.548 + iov[0].iov_base = (void *)cmd; 34.549 + iov[0].iov_len = strlen(cmd) + 1; 34.550 + iov[1].iov_base = data; 34.551 + iov[1].iov_len = len; 34.552 + 34.553 + return xs_talkv(h, XS_DEBUG, iov, ARRAY_SIZE(iov), NULL); 34.554 +}
35.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 35.2 +++ b/tools/xenstore/xs.h Tue Jun 07 12:43:58 2005 +0000 35.3 @@ -0,0 +1,146 @@ 35.4 +#ifndef _XS_H 35.5 +#define _XS_H 35.6 +/* 35.7 + Xen Store Daemon providing simple tree-like database. 35.8 + Copyright (C) 2005 Rusty Russell IBM Corporation 35.9 + 35.10 + This program is free software; you can redistribute it and/or modify 35.11 + it under the terms of the GNU General Public License as published by 35.12 + the Free Software Foundation; either version 2 of the License, or 35.13 + (at your option) any later version. 35.14 + 35.15 + This program is distributed in the hope that it will be useful, 35.16 + but WITHOUT ANY WARRANTY; without even the implied warranty of 35.17 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 35.18 + GNU General Public License for more details. 35.19 + 35.20 + You should have received a copy of the GNU General Public License 35.21 + along with this program; if not, write to the Free Software 35.22 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 35.23 +*/ 35.24 + 35.25 +/* On failure, these routines set errno. */ 35.26 +#include "xs_lib.h" 35.27 + 35.28 +struct xs_handle; 35.29 + 35.30 +/* Connect to the xs daemon. 35.31 + * Returns a handle or NULL. 35.32 + */ 35.33 +struct xs_handle *xs_daemon_open(void); 35.34 + 35.35 +/* Connect to the xs daemon (readonly for non-root clients). 35.36 + * Returns a handle or NULL. 35.37 + */ 35.38 +struct xs_handle *xs_daemon_open_readonly(void); 35.39 + 35.40 +/* Close the connection to the xs daemon. */ 35.41 +void xs_daemon_close(struct xs_handle *); 35.42 + 35.43 +/* Get contents of a directory. 35.44 + * Returns a malloced array: call free() on it after use. 35.45 + * Num indicates size. 35.46 + */ 35.47 +char **xs_directory(struct xs_handle *h, const char *path, unsigned int *num); 35.48 + 35.49 +/* Get the value of a single file. 35.50 + * Returns a malloced value: call free() on it after use. 35.51 + * len indicates length in bytes. 35.52 + */ 35.53 +void *xs_read(struct xs_handle *h, const char *path, unsigned int *len); 35.54 + 35.55 +/* Write the value of a single file. 35.56 + * Returns false on failure. createflags can be 0, O_CREAT, or O_CREAT|O_EXCL. 35.57 + */ 35.58 +bool xs_write(struct xs_handle *h, const char *path, const void *data, unsigned int len, 35.59 + int createflags); 35.60 + 35.61 +/* Create a new directory. 35.62 + * Returns false on failure. 35.63 + */ 35.64 +bool xs_mkdir(struct xs_handle *h, const char *path); 35.65 + 35.66 +/* Destroy a file or directory (and children). 35.67 + * Returns false on failure. 35.68 + */ 35.69 +bool xs_rm(struct xs_handle *h, const char *path); 35.70 + 35.71 +/* Get permissions of node (first element is owner, first perms is "other"). 35.72 + * Returns malloced array, or NULL: call free() after use. 35.73 + */ 35.74 +struct xs_permissions *xs_get_permissions(struct xs_handle *h, 35.75 + const char *path, 35.76 + unsigned int *num); 35.77 + 35.78 +/* Set permissions of node (must be owner). 35.79 + * Returns false on failure. 35.80 + */ 35.81 +bool xs_set_permissions(struct xs_handle *h, 35.82 + const char *path, 35.83 + struct xs_permissions *perms, 35.84 + unsigned int num_perms); 35.85 + 35.86 +/* Watch a node for changes (poll on fd to detect, or call read_watch()). 35.87 + * When the node (or any child) changes, fd will become readable. 35.88 + * Priority indicates order if multiple watchers: higher is first. 35.89 + * Returns false on failure. 35.90 + */ 35.91 +bool xs_watch(struct xs_handle *h, const char *path, unsigned int priority); 35.92 + 35.93 +/* Return the FD to poll on to see if a watch has fired. */ 35.94 +int xs_fileno(struct xs_handle *h); 35.95 + 35.96 +/* Find out what node change was on (will block if nothing pending). 35.97 + * Returns malloced path, or NULL: call free() after use. 35.98 + */ 35.99 +char *xs_read_watch(struct xs_handle *h); 35.100 + 35.101 +/* Acknowledge watch on node. Watches must be acknowledged before 35.102 + * any other watches can be read. 35.103 + * Returns false on failure. 35.104 + */ 35.105 +bool xs_acknowledge_watch(struct xs_handle *h); 35.106 + 35.107 +/* Remove a watch on a node. 35.108 + * Returns false on failure (no watch on that node). 35.109 + */ 35.110 +bool xs_unwatch(struct xs_handle *h, const char *path); 35.111 + 35.112 +/* Start a transaction: changes by others will not be seen during this 35.113 + * transaction, and changes will not be visible to others until end. 35.114 + * Transaction only applies to the given subtree. 35.115 + * You can only have one transaction at any time. 35.116 + * Returns false on failure. 35.117 + */ 35.118 +bool xs_transaction_start(struct xs_handle *h, const char *subtree); 35.119 + 35.120 +/* End a transaction. 35.121 + * If abandon is true, transaction is discarded instead of committed. 35.122 + * Returns false on failure, which indicates an error: transactions will 35.123 + * not fail spuriously. 35.124 + */ 35.125 +bool xs_transaction_end(struct xs_handle *h, bool abort); 35.126 + 35.127 +/* Introduce a new domain. 35.128 + * This tells the store daemon about a shared memory page, event channel 35.129 + * and store path associated with a domain: the domain uses these to communicate. 35.130 + */ 35.131 +bool xs_introduce_domain(struct xs_handle *h, 35.132 + domid_t domid, 35.133 + unsigned long mfn, 35.134 + unsigned int eventchn, 35.135 + const char *path); 35.136 + 35.137 +/* Release a domain. 35.138 + * Tells the store domain to release the memory page to the domain. 35.139 + */ 35.140 +bool xs_release_domain(struct xs_handle *h, domid_t domid); 35.141 + 35.142 +/* Only useful for DEBUG versions */ 35.143 +char *xs_debug_command(struct xs_handle *h, const char *cmd, 35.144 + void *data, unsigned int len); 35.145 + 35.146 +/* Shut down the daemon. */ 35.147 +bool xs_shutdown(struct xs_handle *h); 35.148 + 35.149 +#endif /* _XS_H */
36.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 36.2 +++ b/tools/xenstore/xs_lib.c Tue Jun 07 12:43:58 2005 +0000 36.3 @@ -0,0 +1,141 @@ 36.4 +#include "xs_lib.h" 36.5 +#include <unistd.h> 36.6 +#include <stdio.h> 36.7 +#include <string.h> 36.8 +#include <stdlib.h> 36.9 +#include <errno.h> 36.10 + 36.11 +/* Common routines for the Xen store daemon and client library. */ 36.12 + 36.13 +static const char *xs_daemon_rootdir(void) 36.14 +{ 36.15 + char *s = getenv("XENSTORED_ROOTDIR"); 36.16 + return (s ? s : "/var/lib/xenstored"); 36.17 +} 36.18 + 36.19 +static const char *xs_daemon_rundir(void) 36.20 +{ 36.21 + char *s = getenv("XENSTORED_RUNDIR"); 36.22 + return (s ? s : "/var/run/xenstored"); 36.23 +} 36.24 + 36.25 +const char *xs_daemon_socket(void) 36.26 +{ 36.27 + static char buf[PATH_MAX]; 36.28 + sprintf(buf, "%s/socket", xs_daemon_rundir()); 36.29 + return buf; 36.30 +} 36.31 + 36.32 +const char *xs_daemon_socket_ro(void) 36.33 +{ 36.34 + static char buf[PATH_MAX]; 36.35 + sprintf(buf, "%s/socket_ro", xs_daemon_rundir()); 36.36 + return buf; 36.37 +} 36.38 + 36.39 +const char *xs_daemon_store(void) 36.40 +{ 36.41 + static char buf[PATH_MAX]; 36.42 + sprintf(buf, "%s/store", xs_daemon_rootdir()); 36.43 + return buf; 36.44 +} 36.45 + 36.46 +const char *xs_daemon_transactions(void) 36.47 +{ 36.48 + static char buf[PATH_MAX]; 36.49 + sprintf(buf, "%s/transactions", xs_daemon_rootdir()); 36.50 + return buf; 36.51 +} 36.52 + 36.53 +/* Simple routines for writing to sockets, etc. */ 36.54 +bool write_all(int fd, const void *data, unsigned int len) 36.55 +{ 36.56 + while (len) { 36.57 + int done; 36.58 + 36.59 + done = write(fd, data, len); 36.60 + if (done < 0 && errno == EINTR) 36.61 + continue; 36.62 + if (done <= 0) 36.63 + return false; 36.64 + data += done; 36.65 + len -= done; 36.66 + } 36.67 + 36.68 + return true; 36.69 +} 36.70 + 36.71 +/* Convert strings to permissions. False if a problem. */ 36.72 +bool strings_to_perms(struct xs_permissions *perms, unsigned int num, 36.73 + const char *strings) 36.74 +{ 36.75 + const char *p; 36.76 + char *end; 36.77 + unsigned int i; 36.78 + 36.79 + for (p = strings, i = 0; i < num; i++) { 36.80 + /* "r", "w", or "b" for both. */ 36.81 + switch (*p) { 36.82 + case 'r': 36.83 + perms[i].perms = XS_PERM_READ; 36.84 + break; 36.85 + case 'w': 36.86 + perms[i].perms = XS_PERM_WRITE; 36.87 + break; 36.88 + case 'b': 36.89 + perms[i].perms = XS_PERM_READ|XS_PERM_WRITE; 36.90 + break; 36.91 + case 'n': 36.92 + perms[i].perms = XS_PERM_NONE; 36.93 + break; 36.94 + default: 36.95 + errno = EINVAL; 36.96 + return false; 36.97 + } 36.98 + p++; 36.99 + perms[i].id = strtol(p, &end, 0); 36.100 + if (*end || !*p) { 36.101 + errno = EINVAL; 36.102 + return false; 36.103 + } 36.104 + p = end + 1; 36.105 + } 36.106 + return true; 36.107 +} 36.108 + 36.109 +/* Convert permissions to a string (up to len MAX_STRLEN(domid_t)+1). */ 36.110 +bool perm_to_string(const struct xs_permissions *perm, char *buffer) 36.111 +{ 36.112 + switch (perm->perms) { 36.113 + case XS_PERM_WRITE: 36.114 + *buffer = 'w'; 36.115 + break; 36.116 + case XS_PERM_READ: 36.117 + *buffer = 'r'; 36.118 + break; 36.119 + case XS_PERM_READ|XS_PERM_WRITE: 36.120 + *buffer = 'b'; 36.121 + break; 36.122 + case XS_PERM_NONE: 36.123 + *buffer = 'n'; 36.124 + break; 36.125 + default: 36.126 + errno = EINVAL; 36.127 + return false; 36.128 + } 36.129 + sprintf(buffer+1, "%i", (int)perm->id); 36.130 + return true; 36.131 +} 36.132 + 36.133 +/* Given a string and a length, count how many strings (nul terms). */ 36.134 +unsigned int count_strings(const char *strings, unsigned int len) 36.135 +{ 36.136 + unsigned int num; 36.137 + const char *p; 36.138 + 36.139 + for (p = strings, num = 0; p < strings + len; p += strlen(p) + 1) 36.140 + num++; 36.141 + 36.142 + return num; 36.143 +} 36.144 +
37.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 37.2 +++ b/tools/xenstore/xs_lib.h Tue Jun 07 12:43:58 2005 +0000 37.3 @@ -0,0 +1,63 @@ 37.4 +#ifndef _XR_LIB_H 37.5 +#define _XR_LIB_H 37.6 +/* 37.7 + Common routines between Xen store user library and daemon. 37.8 + Copyright (C) 2005 Rusty Russell IBM Corporation 37.9 + 37.10 + This program is free software; you can redistribute it and/or modify 37.11 + it under the terms of the GNU General Public License as published by 37.12 + the Free Software Foundation; either version 2 of the License, or 37.13 + (at your option) any later version. 37.14 + 37.15 + This program is distributed in the hope that it will be useful, 37.16 + but WITHOUT ANY WARRANTY; without even the implied warranty of 37.17 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 37.18 + GNU General Public License for more details. 37.19 + 37.20 + You should have received a copy of the GNU General Public License 37.21 + along with this program; if not, write to the Free Software 37.22 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 37.23 +*/ 37.24 +#include <stdbool.h> 37.25 +#include <limits.h> 37.26 +#include <xc.h> 37.27 + 37.28 +/* Bitmask of permissions. */ 37.29 +enum xs_perm_type { 37.30 + XS_PERM_NONE = 0, 37.31 + XS_PERM_READ = 1, 37.32 + XS_PERM_WRITE = 2, 37.33 + /* Internal use. */ 37.34 + XS_PERM_CREATE = 4, 37.35 + XS_PERM_OWNER = 8, 37.36 +}; 37.37 + 37.38 +struct xs_permissions 37.39 +{ 37.40 + domid_t id; 37.41 + enum xs_perm_type perms; 37.42 +}; 37.43 + 37.44 +/* Each 10 bits takes ~ 3 digits, plus one, plus one for nul terminator. */ 37.45 +#define MAX_STRLEN(x) ((sizeof(x) * CHAR_BIT + CHAR_BIT-1) / 10 * 3 + 2) 37.46 + 37.47 +/* Path for various daemon things: env vars can override. */ 37.48 +const char *xs_daemon_socket(void); 37.49 +const char *xs_daemon_socket_ro(void); 37.50 +const char *xs_daemon_store(void); 37.51 +const char *xs_daemon_transactions(void); 37.52 + 37.53 +/* Simple write function: loops for you. */ 37.54 +bool write_all(int fd, const void *data, unsigned int len); 37.55 + 37.56 +/* Convert strings to permissions. False if a problem. */ 37.57 +bool strings_to_perms(struct xs_permissions *perms, unsigned int num, 37.58 + const char *strings); 37.59 + 37.60 +/* Convert permissions to a string (up to len MAX_STRLEN(domid_t)+1). */ 37.61 +bool perm_to_string(const struct xs_permissions *perm, char *buffer); 37.62 + 37.63 +/* Given a string and a length, count how many strings (nul terms). */ 37.64 +unsigned int count_strings(const char *strings, unsigned int len); 37.65 + 37.66 +#endif /* _XS_LIB_H */
38.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 38.2 +++ b/tools/xenstore/xs_random.c Tue Jun 07 12:43:58 2005 +0000 38.3 @@ -0,0 +1,1646 @@ 38.4 +/* Random tests. 38.5 + 38.6 + We check that the results from a real filesystem are the same. 38.7 +*/ 38.8 +#include <sys/types.h> 38.9 +#include <stdio.h> 38.10 +#include <stdarg.h> 38.11 +#include <stdlib.h> 38.12 +#include <dirent.h> 38.13 +#include <errno.h> 38.14 +#include <sys/stat.h> 38.15 +#include <unistd.h> 38.16 +#include <fcntl.h> 38.17 +#include <signal.h> 38.18 +#include <sys/wait.h> 38.19 +#include "xs.h" 38.20 +#include "talloc.h" 38.21 +#include "utils.h" 38.22 + 38.23 +struct ops 38.24 +{ 38.25 + char *name; 38.26 + 38.27 + char **(*dir)(void *h, const char *path, unsigned int *num); 38.28 + 38.29 + void *(*read)(void *h, const char *path, unsigned int *len); 38.30 + 38.31 + bool (*write)(void *h, const char *path, const void *data, 38.32 + unsigned int len, int createflags); 38.33 + 38.34 + bool (*mkdir)(void *h, const char *path); 38.35 + 38.36 + bool (*rm)(void *h, const char *path); 38.37 + 38.38 + struct xs_permissions *(*get_perms)(void *h, 38.39 + const char *path, 38.40 + unsigned int *num); 38.41 + 38.42 + bool (*set_perms)(void *h, 38.43 + const char *path, 38.44 + struct xs_permissions *perms, 38.45 + unsigned int num); 38.46 + 38.47 + bool (*transaction_start)(void *h, const char *subtree); 38.48 + bool (*transaction_end)(void *h, bool abort); 38.49 + 38.50 + /* Create and destroy a new handle. */ 38.51 + void *(*handle)(const char *path); 38.52 + void (*close)(void *); 38.53 +}; 38.54 + 38.55 +struct file_ops_info 38.56 +{ 38.57 + const char *base; 38.58 + char *transact_base; 38.59 + char *transact; 38.60 +}; 38.61 + 38.62 +static void convert_to_dir(const char *dirname) 38.63 +{ 38.64 + char *tmpname = talloc_asprintf(dirname, "%s.tmp", dirname); 38.65 + if (rename(dirname, tmpname) != 0) 38.66 + barf_perror("Failed to rename %s to %s", dirname, tmpname); 38.67 + if (mkdir(dirname, 0700) != 0) 38.68 + barf_perror("Failed to mkdir %s", dirname); 38.69 + if (rename(tmpname,talloc_asprintf(dirname, "%s/.DATA", dirname)) != 0) 38.70 + barf_perror("Failed to rename into %s", dirname); 38.71 + /* If perms exists, move it in. */ 38.72 + rename(talloc_asprintf(dirname, "%s.perms", dirname), 38.73 + talloc_asprintf(dirname, "%s/.perms", dirname)); 38.74 +} 38.75 + 38.76 +/* Files can be used as dirs, too. Convert them when they are. */ 38.77 +static void maybe_convert_to_directory(const char *filename) 38.78 +{ 38.79 + struct stat st; 38.80 + char *dirname = talloc_asprintf(filename, "%.*s", 38.81 + strrchr(filename, '/') - filename, 38.82 + filename); 38.83 + if (lstat(dirname, &st) == 0 && S_ISREG(st.st_mode)) 38.84 + convert_to_dir(dirname); 38.85 +} 38.86 + 38.87 +static char *get_name(struct file_ops_info *info, const char *path) 38.88 +{ 38.89 + if (info->transact_base) 38.90 + return talloc_asprintf(path, "%s%s", info->transact_base, 38.91 + path); 38.92 + return talloc_asprintf(path, "%s%s", info->base, path); 38.93 +} 38.94 + 38.95 +static char *path_to_name(struct file_ops_info *info, const char *path) 38.96 +{ 38.97 + char *filename = get_name(info, path); 38.98 + maybe_convert_to_directory(filename); 38.99 + return filename; 38.100 +} 38.101 + 38.102 +/* Is child a subnode of parent, or equal? */ 38.103 +static bool is_child(const char *child, const char *parent) 38.104 +{ 38.105 + unsigned int len = strlen(parent); 38.106 + 38.107 + /* / should really be "" for this algorithm to work, but that's a 38.108 + * usability nightmare. */ 38.109 + if (streq(parent, "/")) 38.110 + return true; 38.111 + 38.112 + if (strncmp(child, parent, len) != 0) 38.113 + return false; 38.114 + 38.115 + return child[len] == '/' || child[len] == '\0'; 38.116 +} 38.117 + 38.118 +static bool write_ok(struct file_ops_info *info, const char *path) 38.119 +{ 38.120 + if (info->transact && !is_child(path, info->transact)) { 38.121 + errno = EROFS; 38.122 + return false; 38.123 + } 38.124 + return true; 38.125 +} 38.126 + 38.127 +static char **file_directory(struct file_ops_info *info, 38.128 + const char *path, unsigned int *num) 38.129 +{ 38.130 + char **ret; 38.131 + DIR *dir; 38.132 + struct dirent *dirent; 38.133 + char *p, *dirname = path_to_name(info, path); 38.134 + unsigned int i, len = 0; 38.135 + struct stat st; 38.136 + 38.137 + /* If it exists, but isn't a directory, we convert it. */ 38.138 + if (lstat(dirname, &st) == 0 && !S_ISDIR(st.st_mode)) 38.139 + convert_to_dir(dirname); 38.140 + 38.141 + *num = 0; 38.142 + dir = opendir(dirname); 38.143 + if (!dir) 38.144 + return NULL;; 38.145 + 38.146 + /* Once to count them. */ 38.147 + while ((dirent = readdir(dir)) != NULL) { 38.148 + if (strchr(dirent->d_name, '.')) 38.149 + continue; 38.150 + len += strlen(dirent->d_name) + 1; 38.151 + (*num)++; 38.152 + } 38.153 + rewinddir(dir); 38.154 + 38.155 + /* Now allocate and fill in. */ 38.156 + ret = malloc(sizeof(char *) * *num + len); 38.157 + p = (char *)&ret[*num]; 38.158 + i = 0; 38.159 + while ((dirent = readdir(dir)) != NULL) { 38.160 + if (strchr(dirent->d_name, '.')) 38.161 + continue; 38.162 + ret[i] = p; 38.163 + strcpy(p, dirent->d_name); 38.164 + p += strlen(p) + 1; 38.165 + i++; 38.166 + } 38.167 + closedir(dir); 38.168 + 38.169 + return ret; 38.170 +} 38.171 + 38.172 +static char *filename_to_data(const char *filename) 38.173 +{ 38.174 + struct stat st; 38.175 + 38.176 + if (lstat(filename, &st) == 0 && S_ISDIR(st.st_mode)) 38.177 + return talloc_asprintf(filename, "%s/.DATA", filename); 38.178 + return (char *)filename; 38.179 +} 38.180 + 38.181 +static void *file_read(struct file_ops_info *info, 38.182 + const char *path, unsigned int *len) 38.183 +{ 38.184 + void *ret; 38.185 + char *filename = filename_to_data(path_to_name(info, path)); 38.186 + unsigned long size; 38.187 + 38.188 + ret = grab_file(filename, &size); 38.189 + /* Directory exists, .DATA doesn't. */ 38.190 + if (!ret && errno == ENOENT && strends(filename, ".DATA")) 38.191 + errno = EISDIR; 38.192 + *len = size; 38.193 + return ret; 38.194 +} 38.195 + 38.196 +static struct xs_permissions *file_get_perms(struct file_ops_info *info, 38.197 + const char *path, 38.198 + unsigned int *num) 38.199 +{ 38.200 + void *perms; 38.201 + struct xs_permissions *ret; 38.202 + char *filename = path_to_name(info, path); 38.203 + char *permfile; 38.204 + unsigned long size; 38.205 + struct stat st; 38.206 + 38.207 + /* No permfile: we didn't bother, return defaults. */ 38.208 + if (lstat(filename, &st) != 0) 38.209 + return NULL; 38.210 + 38.211 + if (S_ISDIR(st.st_mode)) 38.212 + permfile = talloc_asprintf(path, "%s/.perms", filename); 38.213 + else 38.214 + permfile = talloc_asprintf(path, "%s.perms", filename); 38.215 + 38.216 + perms = grab_file(permfile, &size); 38.217 + if (!perms) { 38.218 + ret = new(struct xs_permissions); 38.219 + ret[0].id = 0; 38.220 + /* Default for root is readable. */ 38.221 + if (streq(path, "/")) 38.222 + ret[0].perms = XS_PERM_READ; 38.223 + else 38.224 + ret[0].perms = XS_PERM_NONE; 38.225 + *num = 1; 38.226 + release_file(perms, size); 38.227 + return ret; 38.228 + } 38.229 + *num = count_strings(perms, size); 38.230 + 38.231 + ret = new_array(struct xs_permissions, *num); 38.232 + if (!strings_to_perms(ret, *num, perms)) 38.233 + barf("Reading permissions from %s", permfile); 38.234 + release_file(perms, size); 38.235 + return ret; 38.236 +} 38.237 + 38.238 +static bool file_set_perms(struct file_ops_info *info, 38.239 + const char *path, 38.240 + struct xs_permissions *perms, 38.241 + unsigned int num) 38.242 +{ 38.243 + unsigned int i; 38.244 + char *filename = path_to_name(info, path); 38.245 + char *permfile; 38.246 + int fd; 38.247 + struct stat st; 38.248 + 38.249 + if (num < 1) { 38.250 + errno = EINVAL; 38.251 + return false; 38.252 + } 38.253 + 38.254 + if (!write_ok(info, path)) 38.255 + return false; 38.256 + 38.257 + /* Check non-perm file exists/ */ 38.258 + if (lstat(filename, &st) != 0) 38.259 + return false; 38.260 + 38.261 + if (S_ISDIR(st.st_mode)) 38.262 + permfile = talloc_asprintf(path, "%s/.perms", filename); 38.263 + else 38.264 + permfile = talloc_asprintf(path, "%s.perms", filename); 38.265 + 38.266 + fd = open(permfile, O_WRONLY|O_CREAT|O_TRUNC, 0600); 38.267 + if (fd < 0) 38.268 + return false; 38.269 + 38.270 + for (i = 0; i < num; i++) { 38.271 + char buffer[100]; 38.272 + 38.273 + if (!perm_to_string(&perms[i], buffer)) { 38.274 + int saved_errno = errno; 38.275 + close(fd); 38.276 + errno = saved_errno; 38.277 + return false; 38.278 + } 38.279 + if (write(fd, buffer, strlen(buffer) + 1) 38.280 + != (int)strlen(buffer) + 1) 38.281 + barf_perror("Failed to write perm"); 38.282 + } 38.283 + close(fd); 38.284 + return true; 38.285 +} 38.286 + 38.287 +static bool file_write(struct file_ops_info *info, 38.288 + const char *path, const void *data, 38.289 + unsigned int len, int createflags) 38.290 +{ 38.291 + char *filename = filename_to_data(path_to_name(info, path)); 38.292 + int fd; 38.293 + 38.294 + /* Kernel isn't strict, but library is. */ 38.295 + if (createflags & ~(O_CREAT|O_EXCL)) { 38.296 + errno = EINVAL; 38.297 + return false; 38.298 + } 38.299 + 38.300 + if (!write_ok(info, path)) 38.301 + return false; 38.302 + 38.303 + /* We regard it as existing if dir exists. */ 38.304 + if (strends(filename, ".DATA")) { 38.305 + if (!createflags) 38.306 + createflags = O_CREAT; 38.307 + if (createflags & O_EXCL) { 38.308 + errno = EEXIST; 38.309 + return false; 38.310 + } 38.311 + } 38.312 + 38.313 + fd = open(filename, createflags|O_TRUNC|O_WRONLY, 0600); 38.314 + if (fd < 0) { 38.315 + /* FIXME: Another hack. */ 38.316 + if (!(createflags & O_CREAT) && errno == EISDIR) 38.317 + errno = EEXIST; 38.318 + return false; 38.319 + } 38.320 + 38.321 + if (write(fd, data, len) != (int)len) 38.322 + barf_perror("Bad write to %s", filename); 38.323 + 38.324 + close(fd); 38.325 + return true; 38.326 +} 38.327 + 38.328 +static bool file_mkdir(struct file_ops_info *info, const char *path) 38.329 +{ 38.330 + char *dirname = path_to_name(info, path); 38.331 + 38.332 + /* Same effective order as daemon, so error returns are right. */ 38.333 + if (mkdir(dirname, 0700) != 0) { 38.334 + if (errno != ENOENT && errno != ENOTDIR) 38.335 + write_ok(info, path); 38.336 + return false; 38.337 + } 38.338 + 38.339 + if (!write_ok(info, path)) { 38.340 + int saved_errno = errno; 38.341 + rmdir(dirname); 38.342 + errno = saved_errno; 38.343 + return false; 38.344 + } 38.345 + return true; 38.346 +} 38.347 + 38.348 +static void do_command(const char *cmd) 38.349 +{ 38.350 + int ret; 38.351 + 38.352 + ret = system(cmd); 38.353 + if (ret == -1 || !WIFEXITED(ret) || WEXITSTATUS(ret) != 0) 38.354 + barf_perror("Failed '%s': %i", cmd, ret); 38.355 +} 38.356 + 38.357 +static bool file_rm(struct file_ops_info *info, const char *path) 38.358 +{ 38.359 + char *filename = path_to_name(info, path); 38.360 + struct stat st; 38.361 + 38.362 + if (info->transact && streq(info->transact, path)) { 38.363 + errno = EINVAL; 38.364 + return false; 38.365 + } 38.366 + 38.367 + if (lstat(filename, &st) != 0) 38.368 + return false; 38.369 + 38.370 + if (!write_ok(info, path)) 38.371 + return false; 38.372 + 38.373 + if (streq(path, "/")) { 38.374 + errno = EINVAL; 38.375 + return false; 38.376 + } 38.377 + 38.378 + do_command(talloc_asprintf(path, "rm -f %s.perms; rm -r %s", 38.379 + filename, filename)); 38.380 + return true; 38.381 +} 38.382 + 38.383 +static bool file_transaction_start(struct file_ops_info *info, 38.384 + const char *subtree) 38.385 +{ 38.386 + char *cmd; 38.387 + char *filename = path_to_name(info, subtree); 38.388 + struct stat st; 38.389 + 38.390 + if (info->transact) { 38.391 + errno = EBUSY; 38.392 + return false; 38.393 + } 38.394 + 38.395 + if (lstat(filename, &st) != 0) 38.396 + return false; 38.397 + 38.398 + cmd = talloc_asprintf(NULL, "cp -r %s %s.transact", 38.399 + info->base, info->base); 38.400 + do_command(cmd); 38.401 + talloc_free(cmd); 38.402 + 38.403 + info->transact_base = talloc_asprintf(NULL, "%s.transact", info->base); 38.404 + info->transact = talloc_strdup(NULL, subtree); 38.405 + return true; 38.406 +} 38.407 + 38.408 +static bool file_transaction_end(struct file_ops_info *info, bool abort) 38.409 +{ 38.410 + char *old, *cmd; 38.411 + 38.412 + if (!info->transact) { 38.413 + errno = ENOENT; 38.414 + return false; 38.415 + } 38.416 + 38.417 + if (abort) { 38.418 + cmd = talloc_asprintf(NULL, "rm -r %s", info->transact_base); 38.419 + do_command(cmd); 38.420 + goto success; 38.421 + } 38.422 + 38.423 + old = talloc_asprintf(NULL, "rm -rf %s", info->base); 38.424 + do_command(old); 38.425 + talloc_free(old); 38.426 + 38.427 + cmd = talloc_asprintf(NULL, "mv %s %s", 38.428 + info->transact_base, info->base); 38.429 + do_command(cmd); 38.430 + 38.431 +success: 38.432 + talloc_free(cmd); 38.433 + talloc_free(info->transact); 38.434 + talloc_free(info->transact_base); 38.435 + info->transact = NULL; 38.436 + info->transact_base = NULL; 38.437 + return true; 38.438 +} 38.439 + 38.440 +static struct file_ops_info *file_handle(const char *dir) 38.441 +{ 38.442 + struct file_ops_info *info = talloc(NULL, struct file_ops_info); 38.443 + 38.444 + info->base = dir; 38.445 + info->transact_base = NULL; 38.446 + info->transact = NULL; 38.447 + return info; 38.448 +} 38.449 + 38.450 +static void file_close(struct file_ops_info *handle) 38.451 +{ 38.452 + talloc_free(handle); 38.453 +} 38.454 + 38.455 +static struct xs_handle *xs_handle(const char *dir __attribute__((unused))) 38.456 +{ 38.457 + struct xs_handle *h; 38.458 + 38.459 + h = xs_daemon_open(); 38.460 + if (!h) 38.461 + barf_perror("Connecting to xs daemon"); 38.462 + return h; 38.463 +} 38.464 + 38.465 +static void xs_close(struct xs_handle *handle) 38.466 +{ 38.467 + xs_daemon_close(handle); 38.468 +} 38.469 + 38.470 +struct ops file_ops = { 38.471 + .name = "FILE", 38.472 + .dir = (void *)file_directory, 38.473 + .read = (void *)file_read, 38.474 + .write = (void *)file_write, 38.475 + .mkdir = (void *)file_mkdir, 38.476 + .rm = (void *)file_rm, 38.477 + .get_perms = (void *)file_get_perms, 38.478 + .set_perms = (void *)file_set_perms, 38.479 + .transaction_start = (void *)file_transaction_start, 38.480 + .transaction_end = (void *)file_transaction_end, 38.481 + .handle = (void *)file_handle, 38.482 + .close = (void *)file_close, 38.483 +}; 38.484 + 38.485 +struct ops xs_ops = { 38.486 + .name = "XS", 38.487 + .dir = (void *)xs_directory, 38.488 + .read = (void *)xs_read, 38.489 + .write = (void *)xs_write, 38.490 + .mkdir = (void *)xs_mkdir, 38.491 + .rm = (void *)xs_rm, 38.492 + .get_perms = (void *)xs_get_permissions, 38.493 + .set_perms = (void *)xs_set_permissions, 38.494 + .transaction_start = (void *)xs_transaction_start, 38.495 + .transaction_end = (void *)xs_transaction_end, 38.496 + .handle = (void *)xs_handle, 38.497 + .close = (void *)xs_close, 38.498 +}; 38.499 + 38.500 +static int strptrcmp(const void *a, const void *b) 38.501 +{ 38.502 + return strcmp(*(char **)a, *(char **)b); 38.503 +} 38.504 + 38.505 +static void sort_dir(char **dir, unsigned int num) 38.506 +{ 38.507 + qsort(dir, num, sizeof(char *), strptrcmp); 38.508 +} 38.509 + 38.510 +static char *dump_dir(struct ops *ops, 38.511 + void *h, 38.512 + const char *node, 38.513 + char **dir, 38.514 + unsigned int numdirs, 38.515 + unsigned int depth) 38.516 +{ 38.517 + char *ret = talloc_strdup(node, ""); 38.518 + unsigned int i; 38.519 + char spacing[depth+1]; 38.520 + 38.521 + memset(spacing, ' ', depth); 38.522 + spacing[depth] = '\0'; 38.523 + 38.524 + sort_dir(dir, numdirs); 38.525 + 38.526 + for (i = 0; i < numdirs; i++) { 38.527 + struct xs_permissions *perms; 38.528 + unsigned int j, numperms; 38.529 + unsigned int len; 38.530 + char *contents; 38.531 + unsigned int subnum; 38.532 + char **subdirs; 38.533 + char *subret; 38.534 + char *subnode = talloc_asprintf(node, "%s/%s", node, dir[i]); 38.535 + 38.536 + perms = ops->get_perms(h, subnode, &numperms); 38.537 + if (!perms) 38.538 + return NULL; 38.539 + ret = talloc_asprintf_append(ret, "%s%s: ", spacing, dir[i]); 38.540 + for (j = 0; j < numperms; j++) { 38.541 + char buffer[100]; 38.542 + if (!perm_to_string(&perms[j], buffer)) 38.543 + barf("perm to string"); 38.544 + ret = talloc_asprintf_append(ret, "%s ", buffer); 38.545 + } 38.546 + free(perms); 38.547 + ret = talloc_asprintf_append(ret, "\n"); 38.548 + 38.549 + /* Even directories can have contents. */ 38.550 + contents = ops->read(h, subnode, &len); 38.551 + if (!contents) { 38.552 + if (errno != EISDIR) 38.553 + return NULL; 38.554 + } else { 38.555 + ret = talloc_asprintf_append(ret, " %s(%.*s)\n", 38.556 + spacing, len, contents); 38.557 + free(contents); 38.558 + } 38.559 + 38.560 + /* Every node is a directory. */ 38.561 + subdirs = ops->dir(h, subnode, &subnum); 38.562 + if (!subdirs) 38.563 + return NULL; 38.564 + subret = dump_dir(ops, h, subnode, subdirs, subnum, depth+1); 38.565 + if (!subret) 38.566 + return NULL; 38.567 + ret = talloc_asprintf_append(ret, "%s", subret); 38.568 + free(subdirs); 38.569 + } 38.570 + return ret; 38.571 +} 38.572 + 38.573 +static char *dump(struct ops *ops, void *h) 38.574 +{ 38.575 + char **subdirs; 38.576 + unsigned int subnum; 38.577 + char *ret = NULL, *root = talloc_strdup(NULL, "/"); 38.578 + 38.579 + subdirs = ops->dir(h, root, &subnum); 38.580 + if (subdirs) { 38.581 + ret = dump_dir(ops, h, talloc_strdup(root, ""), subdirs, 38.582 + subnum, 0); 38.583 + free(subdirs); 38.584 + if (ret) 38.585 + talloc_steal(NULL, ret); 38.586 + } 38.587 + talloc_free(root); 38.588 + return ret; 38.589 +} 38.590 + 38.591 +/* jhash.h: Jenkins hash support. 38.592 + * 38.593 + * Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net) 38.594 + * 38.595 + * http://burtleburtle.net/bob/hash/ 38.596 + * 38.597 + * These are the credits from Bob's sources: 38.598 + * 38.599 + * lookup2.c, by Bob Jenkins, December 1996, Public Domain. 38.600 + * hash(), hash2(), hash3, and mix() are externally useful functions. 38.601 + * Routines to test the hash are included if SELF_TEST is defined. 38.602 + * You can use this free for any purpose. It has no warranty. 38.603 + * 38.604 + * Copyright (C) 2003 David S. Miller (davem@redhat.com) 38.605 + * 38.606 + * I've modified Bob's hash to be useful in the Linux kernel, and 38.607 + * any bugs present are surely my fault. -DaveM 38.608 + */ 38.609 + 38.610 +/* NOTE: Arguments are modified. */ 38.611 +#define __jhash_mix(a, b, c) \ 38.612 +{ \ 38.613 + a -= b; a -= c; a ^= (c>>13); \ 38.614 + b -= c; b -= a; b ^= (a<<8); \ 38.615 + c -= a; c -= b; c ^= (b>>13); \ 38.616 + a -= b; a -= c; a ^= (c>>12); \ 38.617 + b -= c; b -= a; b ^= (a<<16); \ 38.618 + c -= a; c -= b; c ^= (b>>5); \ 38.619 + a -= b; a -= c; a ^= (c>>3); \ 38.620 + b -= c; b -= a; b ^= (a<<10); \ 38.621 + c -= a; c -= b; c ^= (b>>15); \ 38.622 +} 38.623 + 38.624 +/* The golden ration: an arbitrary value */ 38.625 +#define JHASH_GOLDEN_RATIO 0x9e3779b9 38.626 + 38.627 +/* The most generic version, hashes an arbitrary sequence 38.628 + * of bytes. No alignment or length assumptions are made about 38.629 + * the input key. 38.630 + */ 38.631 +static inline u32 jhash(const void *key, u32 length, u32 initval) 38.632 +{ 38.633 + u32 a, b, c, len; 38.634 + const u8 *k = key; 38.635 + 38.636 + len = length; 38.637 + a = b = JHASH_GOLDEN_RATIO; 38.638 + c = initval; 38.639 + 38.640 + while (len >= 12) { 38.641 + a += (k[0] +((u32)k[1]<<8) +((u32)k[2]<<16) +((u32)k[3]<<24)); 38.642 + b += (k[4] +((u32)k[5]<<8) +((u32)k[6]<<16) +((u32)k[7]<<24)); 38.643 + c += (k[8] +((u32)k[9]<<8) +((u32)k[10]<<16)+((u32)k[11]<<24)); 38.644 + 38.645 + __jhash_mix(a,b,c); 38.646 + 38.647 + k += 12; 38.648 + len -= 12; 38.649 + } 38.650 + 38.651 + c += length; 38.652 + switch (len) { 38.653 + case 11: c += ((u32)k[10]<<24); 38.654 + case 10: c += ((u32)k[9]<<16); 38.655 + case 9 : c += ((u32)k[8]<<8); 38.656 + case 8 : b += ((u32)k[7]<<24); 38.657 + case 7 : b += ((u32)k[6]<<16); 38.658 + case 6 : b += ((u32)k[5]<<8); 38.659 + case 5 : b += k[4]; 38.660 + case 4 : a += ((u32)k[3]<<24); 38.661 + case 3 : a += ((u32)k[2]<<16); 38.662 + case 2 : a += ((u32)k[1]<<8); 38.663 + case 1 : a += k[0]; 38.664 + }; 38.665 + 38.666 + __jhash_mix(a,b,c); 38.667 + 38.668 + return c; 38.669 +} 38.670 + 38.671 +/* A special optimized version that handles 1 or more of u32s. 38.672 + * The length parameter here is the number of u32s in the key. 38.673 + */ 38.674 +static inline u32 jhash2(u32 *k, u32 length, u32 initval) 38.675 +{ 38.676 + u32 a, b, c, len; 38.677 + 38.678 + a = b = JHASH_GOLDEN_RATIO; 38.679 + c = initval; 38.680 + len = length; 38.681 + 38.682 + while (len >= 3) { 38.683 + a += k[0]; 38.684 + b += k[1]; 38.685 + c += k[2]; 38.686 + __jhash_mix(a, b, c); 38.687 + k += 3; len -= 3; 38.688 + } 38.689 + 38.690 + c += length * 4; 38.691 + 38.692 + switch (len) { 38.693 + case 2 : b += k[1]; 38.694 + case 1 : a += k[0]; 38.695 + }; 38.696 + 38.697 + __jhash_mix(a,b,c); 38.698 + 38.699 + return c; 38.700 +} 38.701 + 38.702 + 38.703 +/* A special ultra-optimized versions that knows they are hashing exactly 38.704 + * 3, 2 or 1 word(s). 38.705 + * 38.706 + * NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally 38.707 + * done at the end is not done here. 38.708 + */ 38.709 +static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval) 38.710 +{ 38.711 + a += JHASH_GOLDEN_RATIO; 38.712 + b += JHASH_GOLDEN_RATIO; 38.713 + c += initval; 38.714 + 38.715 + __jhash_mix(a, b, c); 38.716 + 38.717 + return c; 38.718 +} 38.719 + 38.720 +static inline u32 jhash_2words(u32 a, u32 b, u32 initval) 38.721 +{ 38.722 + return jhash_3words(a, b, 0, initval); 38.723 +} 38.724 + 38.725 +static inline u32 jhash_1word(u32 a, u32 initval) 38.726 +{ 38.727 + return jhash_3words(a, 0, 0, initval); 38.728 +} 38.729 + 38.730 +static unsigned int get_randomness(int *state) 38.731 +{ 38.732 + return jhash_1word((*state)++, *state * 1103515243); 38.733 +} 38.734 + 38.735 +static char *random_path(int *state) 38.736 +{ 38.737 + unsigned int i; 38.738 + char *ret = NULL; 38.739 + 38.740 + if (get_randomness(state) % 20 == 0) 38.741 + return talloc_strdup(NULL, "/"); 38.742 + 38.743 + for (i = 0; i < 1 || (get_randomness(state) % 2); i++) { 38.744 + ret = talloc_asprintf_append(ret, "/%i", 38.745 + get_randomness(state) % 15); 38.746 + } 38.747 + return ret; 38.748 +} 38.749 + 38.750 +static char *bool_to_errstring(bool result) 38.751 +{ 38.752 + if (result) 38.753 + return talloc_strdup(NULL, "OK"); 38.754 + 38.755 + /* Real daemon can never return this. */ 38.756 + if (errno == ENOTDIR) 38.757 + errno = ENOENT; 38.758 + return talloc_asprintf(NULL, "FAILED:%s", strerror(errno)); 38.759 +} 38.760 + 38.761 +static char *linearize_dir(char **dir, unsigned int *num) 38.762 +{ 38.763 + char *result = NULL; 38.764 + unsigned int i; 38.765 + 38.766 + if (!dir) 38.767 + return bool_to_errstring(false); 38.768 + 38.769 + if (!*num) { 38.770 + free(dir); 38.771 + return talloc_strdup(NULL, ""); 38.772 + } 38.773 + 38.774 + sort_dir(dir, *num); 38.775 + for (i = 0; i < *num; i++) 38.776 + result = talloc_asprintf_append(result, "%s\n", dir[i]); 38.777 + free(dir); 38.778 + return result; 38.779 +} 38.780 + 38.781 +static char *linearize_read(char *read, unsigned int *size) 38.782 +{ 38.783 + char *ret; 38.784 + 38.785 + if (!read) 38.786 + return bool_to_errstring(false); 38.787 + 38.788 + ret = talloc_asprintf(NULL, "%i:%.*s", *size, *size, read); 38.789 + free(read); 38.790 + return ret; 38.791 +} 38.792 + 38.793 +static char *linearize_perms(struct xs_permissions *perms, unsigned int *size) 38.794 +{ 38.795 + char *ret = NULL; 38.796 + unsigned int i; 38.797 + 38.798 + if (!perms) 38.799 + return bool_to_errstring(false); 38.800 + 38.801 + for (i = 0; i < *size; i++) 38.802 + ret = talloc_asprintf_append(ret, "(%u %u)", 38.803 + perms[i].id, perms[i].perms); 38.804 + 38.805 + free(perms); 38.806 + return ret; 38.807 +} 38.808 + 38.809 +static int random_flags(int *state) 38.810 +{ 38.811 + switch (get_randomness(state) % 4) { 38.812 + case 0: 38.813 + return 0; 38.814 + case 1: 38.815 + return O_CREAT; 38.816 + case 2: 38.817 + return O_CREAT|O_EXCL; 38.818 + default: 38.819 + return get_randomness(state); 38.820 + } 38.821 +} 38.822 + 38.823 +/* Do the next operation, return the results. */ 38.824 +static char *do_next_op(struct ops *ops, void *h, int state, bool verbose) 38.825 +{ 38.826 + char *name; 38.827 + unsigned int num; 38.828 + char *ret; 38.829 + 38.830 + if (verbose) 38.831 + printf("State %i: ", state); 38.832 + 38.833 + name = random_path(&state); 38.834 + switch (get_randomness(&state) % 9) { 38.835 + case 0: 38.836 + if (verbose) 38.837 + printf("DIR %s\n", name); 38.838 + ret = linearize_dir(ops->dir(h, name, &num), &num); 38.839 + break; 38.840 + case 1: 38.841 + if (verbose) 38.842 + printf("READ %s\n", name); 38.843 + ret = linearize_read(ops->read(h, name, &num), &num); 38.844 + break; 38.845 + case 2: { 38.846 + int flags = random_flags(&state); 38.847 + char *contents = talloc_asprintf(NULL, "%i", 38.848 + get_randomness(&state)); 38.849 + unsigned int len = get_randomness(&state)%(strlen(contents)+1); 38.850 + if (verbose) 38.851 + printf("WRITE %s %s %.*s\n", name, 38.852 + flags == O_CREAT ? "O_CREAT" 38.853 + : flags == (O_CREAT|O_EXCL) ? "O_CREAT|O_EXCL" 38.854 + : flags == 0 ? "0" : "CRAPFLAGS", 38.855 + len, contents); 38.856 + ret = bool_to_errstring(ops->write(h, name, contents, len, 38.857 + flags)); 38.858 + talloc_steal(ret, contents); 38.859 + break; 38.860 + } 38.861 + case 3: 38.862 + if (verbose) 38.863 + printf("MKDIR %s\n", name); 38.864 + ret = bool_to_errstring(ops->mkdir(h, name)); 38.865 + break; 38.866 + case 4: 38.867 + if (verbose) 38.868 + printf("RM %s\n", name); 38.869 + ret = bool_to_errstring(ops->rm(h, name)); 38.870 + break; 38.871 + case 5: 38.872 + if (verbose) 38.873 + printf("GETPERMS %s\n", name); 38.874 + ret = linearize_perms(ops->get_perms(h, name, &num), 38.875 + &num); 38.876 + break; 38.877 + case 6: { 38.878 + unsigned int i, num = get_randomness(&state)%8; 38.879 + struct xs_permissions perms[num]; 38.880 + 38.881 + if (verbose) 38.882 + printf("SETPERMS %s: ", name); 38.883 + for (i = 0; i < num; i++) { 38.884 + perms[i].id = get_randomness(&state)%8; 38.885 + perms[i].perms = get_randomness(&state)%4; 38.886 + if (verbose) 38.887 + printf("%i%c ", perms[i].id, 38.888 + perms[i].perms == XS_PERM_WRITE ? 'W' 38.889 + : perms[i].perms == XS_PERM_READ ? 'R' 38.890 + : perms[i].perms == 38.891 + (XS_PERM_READ|XS_PERM_WRITE) ? 'B' 38.892 + : 'N'); 38.893 + } 38.894 + if (verbose) 38.895 + printf("\n"); 38.896 + ret = bool_to_errstring(ops->set_perms(h, name, perms, 38.897 + num)); 38.898 + break; 38.899 + } 38.900 + case 7: { 38.901 + if (verbose) 38.902 + printf("START %s\n", name); 38.903 + ret = bool_to_errstring(ops->transaction_start(h, name)); 38.904 + if (streq(ret, "OK")) { 38.905 + talloc_free(ret); 38.906 + ret = talloc_asprintf(NULL, "OK:START-TRANSACT:%s", 38.907 + name); 38.908 + } 38.909 + 38.910 + break; 38.911 + } 38.912 + case 8: { 38.913 + bool abort = (get_randomness(&state) % 2); 38.914 + 38.915 + if (verbose) 38.916 + printf("STOP %s\n", abort ? "ABORT" : "COMMIT"); 38.917 + ret = bool_to_errstring(ops->transaction_end(h, abort)); 38.918 + if (streq(ret, "OK")) { 38.919 + talloc_free(ret); 38.920 + ret = talloc_strdup(NULL, "OK:STOP-TRANSACT"); 38.921 + } 38.922 + break; 38.923 + } 38.924 + default: 38.925 + barf("Impossible randomness"); 38.926 + } 38.927 + 38.928 + talloc_steal(ret, name); 38.929 + return ret; 38.930 +} 38.931 + 38.932 +static int daemon_pid; 38.933 + 38.934 +static void cleanup_xs_ops(void) 38.935 +{ 38.936 + char *cmd; 38.937 + if (daemon_pid) { 38.938 + struct xs_handle *h; 38.939 + h = xs_daemon_open(); 38.940 + if (h) { 38.941 + if (xs_shutdown(h)) { 38.942 + waitpid(daemon_pid, NULL, 0); 38.943 + daemon_pid = 0; 38.944 + } 38.945 + xs_daemon_close(h); 38.946 + } 38.947 + if (daemon_pid) { 38.948 + kill(daemon_pid, SIGTERM); 38.949 + waitpid(daemon_pid, NULL, 0); 38.950 + } 38.951 + } 38.952 + 38.953 + cmd = talloc_asprintf(NULL, "rm -rf testsuite/tmp/*"); 38.954 + do_command(cmd); 38.955 + talloc_free(cmd); 38.956 +} 38.957 + 38.958 +static void cleanup_file_ops(const char *dir) 38.959 +{ 38.960 + char *cmd; 38.961 + 38.962 + cmd = talloc_asprintf(NULL, "rm -rf %s %s.transact", dir, dir); 38.963 + do_command(cmd); 38.964 + talloc_free(cmd); 38.965 +} 38.966 + 38.967 +static void cleanup(const char *dir) 38.968 +{ 38.969 + cleanup_xs_ops(); 38.970 + cleanup_file_ops(dir); 38.971 +} 38.972 + 38.973 +static void setup_file_ops(const char *dir) 38.974 +{ 38.975 + if (mkdir(dir, 0700) != 0) 38.976 + barf_perror("Creating directory %s", dir); 38.977 +} 38.978 + 38.979 +static void setup_xs_ops(void) 38.980 +{ 38.981 + int fds[2]; 38.982 + 38.983 + /* Start daemon. */ 38.984 + pipe(fds); 38.985 + if ((daemon_pid = fork())) { 38.986 + /* Child writes PID when its ready: we wait for that. */ 38.987 + char buffer[20]; 38.988 + close(fds[1]); 38.989 + if (read(fds[0], buffer, sizeof(buffer)) < 0) 38.990 + barf("Failed to summon daemon"); 38.991 + close(fds[0]); 38.992 + } else { 38.993 + dup2(fds[1], STDOUT_FILENO); 38.994 + close(fds[0]); 38.995 +#if 0 38.996 + execlp("valgrind", "valgrind", "xenstored_test", "--output-pid", 38.997 + "--no-fork", NULL); 38.998 +#else 38.999 + execlp("./xenstored_test", "xenstored_test", "--output-pid", 38.1000 + "--no-fork", NULL); 38.1001 +#endif 38.1002 + exit(1); 38.1003 + } 38.1004 +} 38.1005 + 38.1006 +static void setup(const char *dir) 38.1007 +{ 38.1008 + setup_file_ops(dir); 38.1009 + setup_xs_ops(); 38.1010 +}; 38.1011 + 38.1012 +struct simple_data 38.1013 +{ 38.1014 + unsigned int seed; 38.1015 + bool print_progress; 38.1016 + bool fast; 38.1017 + struct ops *ops; 38.1018 + const char *dir; 38.1019 +}; 38.1020 + 38.1021 +/* Just a random test. Don't care about results, just that it doesn't 38.1022 + * go boom. */ 38.1023 +static unsigned int try_simple(const bool *trymap, 38.1024 + unsigned int number, 38.1025 + bool verbose, 38.1026 + void *_data) 38.1027 +{ 38.1028 + unsigned int i, print; 38.1029 + void *h; 38.1030 + char *snapshot = NULL; 38.1031 + struct simple_data *data = _data; 38.1032 + 38.1033 + if (data->ops == &xs_ops) { 38.1034 + cleanup_xs_ops(); 38.1035 + setup_xs_ops(); 38.1036 + } else { 38.1037 + cleanup_file_ops(data->dir); 38.1038 + setup_file_ops(data->dir); 38.1039 + } 38.1040 + h = data->ops->handle(data->dir); 38.1041 + 38.1042 + print = number / 76; 38.1043 + if (!print) 38.1044 + print = 1; 38.1045 + 38.1046 + for (i = 0; i < number; i++) { 38.1047 + char *ret; 38.1048 + 38.1049 + if (data->print_progress) { 38.1050 + if (i % print == 0) { 38.1051 + printf("."); 38.1052 + fflush(stdout); 38.1053 + } 38.1054 + } 38.1055 + 38.1056 + if (trymap && !trymap[i]) 38.1057 + continue; 38.1058 + 38.1059 + ret = do_next_op(data->ops, h, i + data->seed, verbose); 38.1060 + if (verbose) 38.1061 + printf("-> %.*s\n", strchr(ret, '\n') - ret, ret); 38.1062 + if (streq(ret, "FAILED:Bad file descriptor")) 38.1063 + goto out; 38.1064 + if (kill(daemon_pid, 0) != 0) 38.1065 + goto out; 38.1066 + 38.1067 + if (!data->fast) { 38.1068 + if (strstarts(ret, "OK:START-TRANSACT:")) { 38.1069 + void *pre = data->ops->handle(data->dir); 38.1070 + 38.1071 + snapshot = dump(data->ops, pre); 38.1072 + if (!snapshot) 38.1073 + goto out; 38.1074 + data->ops->close(pre); 38.1075 + } else if (streq(ret, "OK:STOP-TRANSACT")) { 38.1076 + talloc_free(snapshot); 38.1077 + snapshot = NULL; 38.1078 + } 38.1079 + } 38.1080 + 38.1081 + talloc_free(ret); 38.1082 + 38.1083 + if (snapshot) { 38.1084 + void *pre = data->ops->handle(data->dir); 38.1085 + char *contents; 38.1086 + 38.1087 + contents = dump(data->ops, pre); 38.1088 + if (!contents) 38.1089 + goto out; 38.1090 + 38.1091 + if (!streq(contents, snapshot)) 38.1092 + goto out; 38.1093 + 38.1094 + talloc_free(contents); 38.1095 + data->ops->close(pre); 38.1096 + } 38.1097 + } 38.1098 + if (data->print_progress) 38.1099 + printf("\n"); 38.1100 + 38.1101 +out: 38.1102 + data->ops->close(h); 38.1103 + return i; 38.1104 +} 38.1105 + 38.1106 +/* Binary elimination: try eliminating all of them, then reduce. */ 38.1107 +static void reduce(bool *map, 38.1108 + unsigned int number, 38.1109 + unsigned int try_start, unsigned int try_num, 38.1110 + unsigned int (*try)(const bool *map, 38.1111 + unsigned int number, 38.1112 + bool verbose, 38.1113 + void *), 38.1114 + void *data) 38.1115 +{ 38.1116 + bool newmap[number]; 38.1117 + 38.1118 + if (try_num == 0) 38.1119 + return; 38.1120 + 38.1121 + /* Try skipping everything between start and end. */ 38.1122 + memcpy(newmap, map, sizeof(newmap)); 38.1123 + memset(newmap + try_start, 0, try_num * sizeof(bool)); 38.1124 + 38.1125 + /* We want the *same* failure: must fail at "number-1". */ 38.1126 + if (try(newmap, number, false, data) == number - 1) { 38.1127 + memset(map + try_start, 0, try_num * sizeof(bool)); 38.1128 + return; 38.1129 + } 38.1130 + 38.1131 + if (try_num == 1) 38.1132 + return; 38.1133 + 38.1134 + /* Try each half... */ 38.1135 + reduce(map, number, try_start, try_num/2, try, data); 38.1136 + reduce(map, number, try_start + try_num/2, try_num - try_num/2, 38.1137 + try, data); 38.1138 +} 38.1139 + 38.1140 +static void reduce_problem(unsigned int failed, 38.1141 + unsigned int (*try)(const bool *map, 38.1142 + unsigned int number, 38.1143 + bool verbose, 38.1144 + void *data), 38.1145 + void *data) 38.1146 +{ 38.1147 + bool map[failed]; 38.1148 + 38.1149 + memset(map, 1, sizeof(map)); 38.1150 + reduce(map, failed, 0, failed-1, try, data); 38.1151 + 38.1152 + printf("Cut down:\n"); 38.1153 + if (try(map, failed, true, data) != failed - 1) { 38.1154 + printf("Except, that didn't actually fail. Bugger!"); 38.1155 + exit(2); 38.1156 + } 38.1157 + exit(1); 38.1158 +} 38.1159 + 38.1160 +/* Just a random test. Don't care about results, just that it doesn't 38.1161 + * go boom. */ 38.1162 +static void simple_test(const char *dir, 38.1163 + unsigned int iters, unsigned int seed, 38.1164 + bool fast, bool verbose) 38.1165 +{ 38.1166 + struct simple_data data; 38.1167 + unsigned int try; 38.1168 + 38.1169 + data.seed = seed; 38.1170 + data.print_progress = !verbose; 38.1171 + data.fast = fast; 38.1172 + data.ops = &xs_ops; 38.1173 + data.dir = dir; 38.1174 + 38.1175 + try = try_simple(NULL, iters, verbose, &data); 38.1176 + if (try == iters) { 38.1177 + cleanup_xs_ops(); 38.1178 + printf("Succeeded\n"); 38.1179 + exit(0); 38.1180 + } 38.1181 + printf("Failed on iteration %u\n", try + 1); 38.1182 + data.print_progress = false; 38.1183 + reduce_problem(try + 1, try_simple, &data); 38.1184 +} 38.1185 + 38.1186 +static bool ops_equal(struct ops *a, void *ah, 38.1187 + struct ops *b, void *bh, 38.1188 + const char *node, 38.1189 + struct ops **fail) 38.1190 +{ 38.1191 + char **dira = NULL, **dirb = NULL; 38.1192 + char *dataa = NULL, *datab = NULL; 38.1193 + unsigned int i, numa, numb, lena, lenb; 38.1194 + struct xs_permissions *permsa = NULL, *permsb = NULL; 38.1195 + unsigned int numpermsa, numpermsb; 38.1196 + char *nodename; 38.1197 + bool ret = false; 38.1198 + 38.1199 + /* FILE backend expects talloc'ed pointer. */ 38.1200 + nodename = talloc_strdup(NULL, node); 38.1201 + permsa = a->get_perms(ah, nodename, &numpermsa); 38.1202 + if (!permsa) { 38.1203 + *fail = a; 38.1204 + goto out; 38.1205 + } 38.1206 + permsb = b->get_perms(bh, nodename, &numpermsb); 38.1207 + if (!permsb) { 38.1208 + *fail = b; 38.1209 + goto out; 38.1210 + } 38.1211 + if (numpermsa != numpermsb) 38.1212 + goto out; 38.1213 + for (i = 0; i < numpermsa; i++) { 38.1214 + if (permsa[i].perms != permsb[i].perms) 38.1215 + goto out; 38.1216 + if (permsa[i].id != permsb[i].id) 38.1217 + goto out; 38.1218 + } 38.1219 + 38.1220 + /* Non-pure-directory nodes contain data. */ 38.1221 + dataa = a->read(ah, nodename, &lena); 38.1222 + if (!dataa && errno != EISDIR) { 38.1223 + *fail = a; 38.1224 + goto out; 38.1225 + } 38.1226 + datab = b->read(bh, nodename, &lenb); 38.1227 + if (!datab && errno != EISDIR) { 38.1228 + *fail = b; 38.1229 + goto out; 38.1230 + } 38.1231 + 38.1232 + if (dataa) { 38.1233 + if (!datab) 38.1234 + goto out; 38.1235 + if (lena != lenb) 38.1236 + goto out; 38.1237 + 38.1238 + if (memcmp(dataa, datab, lena) != 0) 38.1239 + goto out; 38.1240 + } else 38.1241 + if (datab) 38.1242 + goto out; 38.1243 + 38.1244 + /* Everything is a directory. */ 38.1245 + dira = a->dir(ah, nodename, &numa); 38.1246 + if (!dira) { 38.1247 + *fail = a; 38.1248 + goto out; 38.1249 + } 38.1250 + dirb = b->dir(bh, nodename, &numb); 38.1251 + if (!dirb) { 38.1252 + *fail = b; 38.1253 + goto out; 38.1254 + } 38.1255 + if (numa != numb) 38.1256 + goto out; 38.1257 + sort_dir(dira, numa); 38.1258 + sort_dir(dirb, numb); 38.1259 + for (i = 0; i < numa; i++) { 38.1260 + char subnode[strlen(node) + 1 + strlen(dira[i]) + 1]; 38.1261 + 38.1262 + if (!streq(dira[i], dirb[i])) 38.1263 + goto out; 38.1264 + 38.1265 + strcpy(subnode, node); 38.1266 + if (!streq(node, "/")) 38.1267 + strcat(subnode, "/"); 38.1268 + strcat(subnode, dira[i]); 38.1269 + if (!ops_equal(a, ah, b, bh, subnode, fail)) 38.1270 + goto out; 38.1271 + } 38.1272 + 38.1273 + ret = true; 38.1274 +out: 38.1275 + free(permsa); 38.1276 + free(permsb); 38.1277 + free(dataa); 38.1278 + free(datab); 38.1279 + free(dira); 38.1280 + free(dirb); 38.1281 + talloc_free(nodename); 38.1282 + return ret; 38.1283 +} 38.1284 + 38.1285 +struct diff_data 38.1286 +{ 38.1287 + unsigned int seed; 38.1288 + bool print_progress; 38.1289 + bool fast; 38.1290 + const char *dir; 38.1291 +}; 38.1292 + 38.1293 +/* Differential: try both file and xs backend, watch for differences. */ 38.1294 +static unsigned int try_diff(const bool *trymap, 38.1295 + unsigned int number, 38.1296 + bool verbose, 38.1297 + void *_data) 38.1298 +{ 38.1299 + void *fileh, *xsh; 38.1300 + char *transact = NULL; 38.1301 + struct ops *fail; 38.1302 + struct diff_data *data = _data; 38.1303 + unsigned int i, print; 38.1304 + 38.1305 + cleanup(data->dir); 38.1306 + setup(data->dir); 38.1307 + 38.1308 + fileh = file_handle(data->dir); 38.1309 + xsh = xs_handle(data->dir); 38.1310 + 38.1311 + print = number / 76; 38.1312 + if (!print) 38.1313 + print = 1; 38.1314 + 38.1315 + for (i = 0; i < number; i++) { 38.1316 + char *file, *xs; 38.1317 + 38.1318 + if (data->print_progress) { 38.1319 + if (i % print == 0) { 38.1320 + printf("."); 38.1321 + fflush(stdout); 38.1322 + } 38.1323 + } 38.1324 + if (trymap && !trymap[i]) 38.1325 + continue; 38.1326 + 38.1327 + if (verbose) 38.1328 + printf("FILE: "); 38.1329 + 38.1330 + file = do_next_op(&file_ops, fileh, i+data->seed, verbose); 38.1331 + if (verbose) 38.1332 + printf("-> %.*s\n", strchr(file, '/') - file, file); 38.1333 + 38.1334 + if (verbose) 38.1335 + printf("XS: "); 38.1336 + xs = do_next_op(&xs_ops, xsh, i+data->seed, verbose); 38.1337 + if (verbose) 38.1338 + printf("-> %.*s\n", strchr(xs, '/') - xs, xs); 38.1339 + 38.1340 + if (!streq(file, xs)) 38.1341 + goto out; 38.1342 + 38.1343 + if (strstarts(file, "OK:START-TRANSACT:")) 38.1344 + transact = talloc_strdup(NULL, 38.1345 + file + 38.1346 + strlen("OK:START-TRANSACT:")); 38.1347 + else if (streq(file, "OK:STOP-TRANSACT")) { 38.1348 + talloc_free(transact); 38.1349 + transact = NULL; 38.1350 + } 38.1351 + 38.1352 + talloc_free(file); 38.1353 + talloc_free(xs); 38.1354 + 38.1355 + if (data->fast) 38.1356 + continue; 38.1357 + 38.1358 + fail = NULL; 38.1359 + if (!ops_equal(&xs_ops, xsh, &file_ops, fileh, "/", &fail)) { 38.1360 + if (fail) 38.1361 + barf("%s failed during test\n", fail->name); 38.1362 + if (verbose) 38.1363 + printf("Trees differ:\nXS:%s\nFILE%s\n", 38.1364 + dump(&xs_ops, xsh), 38.1365 + dump(&file_ops, fileh)); 38.1366 + goto out; 38.1367 + } 38.1368 + 38.1369 + if (transact) { 38.1370 + void *fileh_pre = file_handle(data->dir); 38.1371 + void *xsh_pre = xs_handle(data->dir); 38.1372 + 38.1373 + fail = NULL; 38.1374 + if (!ops_equal(&xs_ops, xsh_pre, &file_ops, fileh_pre, 38.1375 + transact, &fail)) { 38.1376 + if (fail) 38.1377 + barf("%s failed during transact\n", 38.1378 + fail->name); 38.1379 + 38.1380 + xs_daemon_close(xsh_pre); 38.1381 + talloc_free(fileh_pre); 38.1382 + goto out; 38.1383 + } 38.1384 + xs_daemon_close(xsh_pre); 38.1385 + talloc_free(fileh_pre); 38.1386 + } 38.1387 + } 38.1388 + if (data->print_progress) 38.1389 + printf("\n"); 38.1390 + 38.1391 + fail = NULL; 38.1392 + if (data->fast) 38.1393 + if (!ops_equal(&xs_ops, xsh, &file_ops, fileh, "/", &fail)) 38.1394 + barf("Final result not the same: try without --fast"); 38.1395 +out: 38.1396 + file_ops.close(fileh); 38.1397 + xs_ops.close(xsh); 38.1398 + return i; 38.1399 +} 38.1400 + 38.1401 +/* Differential random test: compare results against file backend. */ 38.1402 +static void diff_test(const char *dir, 38.1403 + unsigned int iters, unsigned int seed, bool fast, 38.1404 + bool verbose) 38.1405 +{ 38.1406 + struct diff_data data; 38.1407 + unsigned int try; 38.1408 + 38.1409 + data.seed = seed; 38.1410 + data.print_progress = !verbose; 38.1411 + data.fast = fast; 38.1412 + data.dir = dir; 38.1413 + 38.1414 + try = try_diff(NULL, iters, verbose, &data); 38.1415 + if (try == iters) { 38.1416 + cleanup_xs_ops(); 38.1417 + printf("Succeeded\n"); 38.1418 + exit(0); 38.1419 + } 38.1420 + printf("Failed on iteration %u\n", try + 1); 38.1421 + data.print_progress = false; 38.1422 + reduce_problem(try + 1, try_diff, &data); 38.1423 +} 38.1424 + 38.1425 +struct fail_data 38.1426 +{ 38.1427 + unsigned int seed; 38.1428 + bool print_progress; 38.1429 + const char *dir; 38.1430 +}; 38.1431 + 38.1432 +/* Try xs with inserted failures: every op should either succeed or fail. */ 38.1433 +static unsigned int try_fail(const bool *trymap, 38.1434 + unsigned int number, 38.1435 + bool verbose, 38.1436 + void *_data) 38.1437 +{ 38.1438 + unsigned int i, print, tried = 0, aborted = 0; 38.1439 + struct fail_data *data = _data; 38.1440 + struct xs_handle *tmpxsh; 38.1441 + struct file_ops_info *tmpfileh; 38.1442 + void *fileh, *xsh; 38.1443 + struct ops *fail; 38.1444 + char seed[20]; 38.1445 + 38.1446 + /* Make sure failures off to shut down. */ 38.1447 + if (daemon_pid) 38.1448 + kill(daemon_pid, SIGUSR1); 38.1449 + cleanup(data->dir); 38.1450 + setup(data->dir); 38.1451 + 38.1452 + fileh = file_handle(data->dir); 38.1453 + xsh = xs_handle(data->dir); 38.1454 + 38.1455 + sprintf(seed, "%i", data->seed); 38.1456 + free(xs_debug_command(xsh, "failtest", seed, strlen(seed)+1)); 38.1457 + 38.1458 + print = number / 76; 38.1459 + if (!print) 38.1460 + print = 1; 38.1461 + 38.1462 + for (i = 0; i < number; i++) { 38.1463 + unsigned int limit, failed; 38.1464 + char *ret; 38.1465 + 38.1466 + /* A few times we fail due to other end OOM. */ 38.1467 + limit = 0; 38.1468 + while (!xsh) { 38.1469 + xsh = xs_handle(data->dir); 38.1470 + if (!xsh && errno == ECONNREFUSED) { 38.1471 + if (verbose) 38.1472 + printf("Daemon refused connection\n"); 38.1473 + goto out; 38.1474 + } 38.1475 + if (!xsh && limit++ == 5) { 38.1476 + printf("Daemon failed conn 5 times\n"); 38.1477 + goto out; 38.1478 + } 38.1479 + } 38.1480 + 38.1481 + if (data->print_progress) { 38.1482 + if (i % print == 0) { 38.1483 + printf("."); 38.1484 + fflush(stdout); 38.1485 + } 38.1486 + } 38.1487 + if (trymap && !trymap[i]) 38.1488 + continue; 38.1489 + 38.1490 + if (verbose) 38.1491 + printf("(%i) ", i); 38.1492 + ret = do_next_op(&xs_ops, xsh, i + data->seed, verbose); 38.1493 + if (streq(ret, "FAILED:Connection reset by peer") 38.1494 + || streq(ret, "FAILED:Bad file descriptor") 38.1495 + || streq(ret, "FAILED:Broken pipe")) { 38.1496 + xs_close(xsh); 38.1497 + xsh = NULL; 38.1498 + failed = 2; 38.1499 + } else if (strstarts(ret, "OK")) 38.1500 + failed = 0; 38.1501 + else 38.1502 + failed = 1; 38.1503 + 38.1504 + tried++; 38.1505 + if (xsh) 38.1506 + aborted++; 38.1507 + 38.1508 + if (verbose) 38.1509 + printf("-> %.*s\n", strchr(ret, '\n') - ret, ret); 38.1510 + 38.1511 + talloc_free(ret); 38.1512 + 38.1513 + /* Turn off failures using signal. */ 38.1514 + if (kill(daemon_pid, SIGUSR1) != 0) { 38.1515 + if (verbose) 38.1516 + printf("Failed to signal daemon\n"); 38.1517 + goto out; 38.1518 + } 38.1519 + 38.1520 + if (failed == 0) { 38.1521 + /* Succeeded? Do same thing to file backend 38.1522 + * to compare */ 38.1523 + try_applying: 38.1524 + ret = do_next_op(&file_ops, fileh, i + data->seed, 38.1525 + false); 38.1526 + if (!strstarts(ret, "OK")) { 38.1527 + if (!verbose) 38.1528 + printf("File op failed on %i\n", 38.1529 + i + data->seed); 38.1530 + talloc_free(ret); 38.1531 + goto out; 38.1532 + } 38.1533 + talloc_free(ret); 38.1534 + } 38.1535 + 38.1536 + tmpxsh = xs_handle(data->dir); 38.1537 + if (!tmpxsh) { 38.1538 + if (verbose) 38.1539 + printf("Failed to open signalled daemon"); 38.1540 + goto out; 38.1541 + } 38.1542 + tmpfileh = file_handle(data->dir); 38.1543 + 38.1544 + fail = NULL; 38.1545 + if (!ops_equal(&xs_ops, tmpxsh, &file_ops, tmpfileh, "/", 38.1546 + &fail)) { 38.1547 + xs_close(tmpxsh); 38.1548 + file_close(tmpfileh); 38.1549 + if (fail) { 38.1550 + if (verbose) 38.1551 + printf("%s failed\n", fail->name); 38.1552 + goto out; 38.1553 + } 38.1554 + /* Maybe op succeeded: try comparing after local op? */ 38.1555 + if (failed == 2) { 38.1556 + failed = 0; 38.1557 + if (verbose) 38.1558 + printf("(Looks like it succeeded)\n"); 38.1559 + goto try_applying; 38.1560 + } 38.1561 + if (verbose) 38.1562 + printf("Two backends not equal\n"); 38.1563 + goto out; 38.1564 + } 38.1565 + 38.1566 + /* If we lost the xs handle, that ended the transaction */ 38.1567 + if (!xsh) 38.1568 + file_transaction_end(fileh, true); 38.1569 + 38.1570 + /* Turn failures back on. */ 38.1571 + free(xs_debug_command(tmpxsh, "failtest", NULL, 0)); 38.1572 + xs_close(tmpxsh); 38.1573 + file_close(tmpfileh); 38.1574 + } 38.1575 + 38.1576 + printf("Total %u of %u not aborted\n", tried - aborted, tried); 38.1577 +out: 38.1578 + if (xsh) 38.1579 + xs_close(xsh); 38.1580 + return i; 38.1581 +} 38.1582 + 38.1583 +static void fail_test(const char *dir, 38.1584 + unsigned int iters, unsigned int seed, 38.1585 + bool fast __attribute__((unused)), bool verbose) 38.1586 +{ 38.1587 + struct fail_data data; 38.1588 + unsigned int try; 38.1589 + 38.1590 + data.seed = seed; 38.1591 + data.print_progress = !verbose; 38.1592 + data.dir = dir; 38.1593 + 38.1594 + try = try_fail(NULL, iters, verbose, &data); 38.1595 + if (try == iters) { 38.1596 + cleanup_xs_ops(); 38.1597 + printf("Succeeded\n"); 38.1598 + exit(0); 38.1599 + } 38.1600 + printf("Failed on iteration %u\n", try + 1); 38.1601 + fflush(stdout); 38.1602 + data.print_progress = false; 38.1603 + reduce_problem(try + 1, try_fail, &data); 38.1604 +} 38.1605 + 38.1606 +int main(int argc, char *argv[]) 38.1607 +{ 38.1608 + bool verbose = false; 38.1609 + bool simple = false; 38.1610 + bool fast = false; 38.1611 + bool fail = false; 38.1612 + 38.1613 + if (argv[1] && streq(argv[1], "--fail")) { 38.1614 + fail = true; 38.1615 + argv++; 38.1616 + argc--; 38.1617 + } 38.1618 + 38.1619 + if (argv[1] && streq(argv[1], "--simple")) { 38.1620 + simple = true; 38.1621 + argv++; 38.1622 + argc--; 38.1623 + } 38.1624 + 38.1625 + if (argv[1] && streq(argv[1], "--fast")) { 38.1626 + fast = true; 38.1627 + argv++; 38.1628 + argc--; 38.1629 + } 38.1630 + 38.1631 + if (argv[1] && streq(argv[1], "--verbose")) { 38.1632 + verbose = true; 38.1633 + argv++; 38.1634 + argc--; 38.1635 + } 38.1636 + 38.1637 + if (argc != 4) 38.1638 + barf("Usage: xs_random [--fail|--simple] [--fast] [--verbose] <directory> <iterations> <seed>"); 38.1639 + 38.1640 + talloc_enable_null_tracking(); 38.1641 + 38.1642 + if (fail) 38.1643 + fail_test(argv[1], atoi(argv[2]), atoi(argv[3]), fast, verbose); 38.1644 + else if (simple) 38.1645 + simple_test(argv[1], atoi(argv[2]), atoi(argv[3]), fast, verbose); 38.1646 + else 38.1647 + diff_test(argv[1], atoi(argv[2]), atoi(argv[3]), fast, verbose); 38.1648 + exit(2); 38.1649 +}
39.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 39.2 +++ b/tools/xenstore/xs_stress.c Tue Jun 07 12:43:58 2005 +0000 39.3 @@ -0,0 +1,207 @@ 39.4 +/* Stress test for Xen Store: multiple people hammering transactions */ 39.5 +#include "xs.h" 39.6 +#include "utils.h" 39.7 +#include <stdlib.h> 39.8 +#include <stdio.h> 39.9 +#include <sys/types.h> 39.10 +#include <sys/wait.h> 39.11 +#include <sys/stat.h> 39.12 +#include <fcntl.h> 39.13 +#include <unistd.h> 39.14 + 39.15 +#define NUM_HANDLES 2 39.16 +#define DIR_FANOUT 3 39.17 +#define DIR_DEPTH 3 39.18 + 39.19 +/* How often to print progress */ 39.20 +static int print; 39.21 + 39.22 +/* Layout looks like /<num>/<num>/count. */ 39.23 +static void work(unsigned int cycles, unsigned int childnum) 39.24 +{ 39.25 + unsigned int i; 39.26 + struct xs_handle *handles[NUM_HANDLES]; 39.27 + char id; 39.28 + 39.29 + if (childnum < 10) 39.30 + id = '0' + childnum; 39.31 + else 39.32 + id = 'A' + childnum - 10; 39.33 + 39.34 + for (i = 0; i < NUM_HANDLES; i++) { 39.35 + handles[i] = xs_daemon_open(); 39.36 + if (!handles[i]) 39.37 + barf_perror("Opening handle %i", i); 39.38 + } 39.39 + 39.40 + srandom(childnum); 39.41 + for (i = 0; i < cycles; i++) { 39.42 + unsigned int lockdepth, j, len; 39.43 + char file[100] = "", lockdir[100]; 39.44 + char *contents, tmp[100]; 39.45 + struct xs_handle *h = handles[random() % NUM_HANDLES]; 39.46 + 39.47 + lockdepth = random() % DIR_DEPTH; 39.48 + for (j = 0; j < DIR_DEPTH; j++) { 39.49 + if (j == lockdepth) 39.50 + strcpy(lockdir, file); 39.51 + sprintf(file + strlen(file), "/%li", 39.52 + random()%DIR_FANOUT); 39.53 + } 39.54 + if (streq(lockdir, "")) 39.55 + strcpy(lockdir, "/"); 39.56 + 39.57 + if (!xs_transaction_start(h, lockdir)) 39.58 + barf_perror("%i: starting transaction %i on %s", 39.59 + childnum, i, lockdir); 39.60 + 39.61 + sprintf(file + strlen(file), "/count"); 39.62 + contents = xs_read(h, file, &len); 39.63 + if (!contents) 39.64 + barf_perror("%i: can't read %s iter %i", 39.65 + childnum, file, i); 39.66 + sprintf(tmp, "%i", atoi(contents) + 1); 39.67 + if (!xs_write(h, file, tmp, strlen(tmp)+1, 0)) 39.68 + barf_perror("%i: can't write %s iter %i", 39.69 + childnum, file, i); 39.70 + 39.71 + /* Abandon 1 in 10 */ 39.72 + if (random() % 10 == 0) { 39.73 + if (!xs_transaction_end(h, true)) 39.74 + barf_perror("%i: can't abort transact %s", 39.75 + childnum, lockdir); 39.76 + i--; 39.77 + } else { 39.78 + if (!xs_transaction_end(h, false)) 39.79 + barf_perror("%i: can't commit transact %s", 39.80 + childnum, lockdir); 39.81 + 39.82 + /* Offset when we print . so kids don't all 39.83 + * print at once. */ 39.84 + if ((i + print/(childnum+1)) % print == 0) 39.85 + write(STDOUT_FILENO, &id, 1); 39.86 + } 39.87 + } 39.88 +} 39.89 + 39.90 +static void create_dirs(struct xs_handle *h, const char *base, int togo) 39.91 +{ 39.92 + unsigned int i; 39.93 + char filename[100]; 39.94 + 39.95 + if (togo == 0) { 39.96 + sprintf(filename, "%s/count", base); 39.97 + if (!xs_write(h, filename, "0", 2, O_EXCL|O_CREAT)) 39.98 + barf_perror("Writing to %s", filename); 39.99 + return; 39.100 + } 39.101 + 39.102 + for (i = 0; i < DIR_FANOUT; i++) { 39.103 + sprintf(filename, "%s/%i", base, i); 39.104 + if (!xs_mkdir(h, filename)) 39.105 + barf_perror("xs_mkdir %s", filename); 39.106 + create_dirs(h, filename, togo-1); 39.107 + } 39.108 +} 39.109 + 39.110 +static unsigned int add_count(struct xs_handle *h, const char *base, int togo) 39.111 +{ 39.112 + unsigned int i, count; 39.113 + char filename[100]; 39.114 + 39.115 + if (togo == 0) { 39.116 + char *answer; 39.117 + unsigned int len; 39.118 + 39.119 + sprintf(filename, "%s/count", base); 39.120 + answer = xs_read(h, filename, &len); 39.121 + if (!answer) 39.122 + barf_perror("Reading %s", filename); 39.123 + count = atoi(answer); 39.124 + free(answer); 39.125 + return count; 39.126 + } 39.127 + 39.128 + count = 0; 39.129 + for (i = 0; i < DIR_FANOUT; i++) { 39.130 + sprintf(filename, "%s/%i", base, i); 39.131 + count += add_count(h, filename, togo-1); 39.132 + } 39.133 + return count; 39.134 +} 39.135 + 39.136 +static void setup(void) 39.137 +{ 39.138 + struct xs_handle *h; 39.139 + 39.140 + /* Do setup. */ 39.141 + h = xs_daemon_open(); 39.142 + if (!h) 39.143 + barf_perror("Contacting daemon"); 39.144 + create_dirs(h, "", DIR_DEPTH); 39.145 + xs_daemon_close(h); 39.146 +} 39.147 + 39.148 +static unsigned int tally_counts(void) 39.149 +{ 39.150 + struct xs_handle *h; 39.151 + unsigned int ret; 39.152 + 39.153 + h = xs_daemon_open(); 39.154 + if (!h) 39.155 + barf_perror("Contacting daemon"); 39.156 + 39.157 + ret = add_count(h, "", DIR_DEPTH); 39.158 + xs_daemon_close(h); 39.159 + return ret; 39.160 +} 39.161 + 39.162 +int main(int argc, char *argv[]) 39.163 +{ 39.164 + unsigned int i; 39.165 + bool failed = false; 39.166 + int kids[10]; 39.167 + 39.168 + if (argc != 2) 39.169 + barf("Usage: xs_stress <iterations>"); 39.170 + 39.171 + printf("Setting up directories...\n"); 39.172 + setup(); 39.173 + 39.174 + print = atoi(argv[1]) / 76; 39.175 + if (!print) 39.176 + print = 1; 39.177 + 39.178 + printf("Running %i children...\n", ARRAY_SIZE(kids)); 39.179 + for (i = 0; i < ARRAY_SIZE(kids); i++) { 39.180 + kids[i] = fork(); 39.181 + if (kids[i] == -1) 39.182 + barf_perror("fork"); 39.183 + if (kids[i] == 0) { 39.184 + work(atoi(argv[1]) / ARRAY_SIZE(kids), i); 39.185 + exit(0); 39.186 + } 39.187 + } 39.188 + 39.189 + for (i = 0; i < ARRAY_SIZE(kids); i++) { 39.190 + int status; 39.191 + if (waitpid(kids[i], &status, 0) == -1) 39.192 + barf_perror("waitpid"); 39.193 + if (!WIFEXITED(status)) 39.194 + barf("Kid %i died via signal %i\n", 39.195 + i, WTERMSIG(status)); 39.196 + if (WEXITSTATUS(status) != 0) { 39.197 + printf("Child %i exited %i\n", i, WEXITSTATUS(status)); 39.198 + failed = true; 39.199 + } 39.200 + } 39.201 + if (failed) 39.202 + exit(1); 39.203 + 39.204 + printf("\nCounting results...\n"); 39.205 + i = tally_counts(); 39.206 + if (i != (unsigned)atoi(argv[1])) 39.207 + barf("Total counts %i not %s", i, atoi(argv[1])); 39.208 + printf("Success!\n"); 39.209 + exit(0); 39.210 +}
40.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 40.2 +++ b/tools/xenstore/xs_test.c Tue Jun 07 12:43:58 2005 +0000 40.3 @@ -0,0 +1,647 @@ 40.4 +/* 40.5 + Xen Store Daemon Test tool 40.6 + Copyright (C) 2005 Rusty Russell IBM Corporation 40.7 + 40.8 + This program is free software; you can redistribute it and/or modify 40.9 + it under the terms of the GNU General Public License as published by 40.10 + the Free Software Foundation; either version 2 of the License, or 40.11 + (at your option) any later version. 40.12 + 40.13 + This program is distributed in the hope that it will be useful, 40.14 + but WITHOUT ANY WARRANTY; without even the implied warranty of 40.15 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 40.16 + GNU General Public License for more details. 40.17 + 40.18 + You should have received a copy of the GNU General Public License 40.19 + along with this program; if not, write to the Free Software 40.20 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 40.21 +*/ 40.22 + 40.23 +#include <stdio.h> 40.24 +#include <stdlib.h> 40.25 +#include <sys/types.h> 40.26 +#include <sys/stat.h> 40.27 +#include <fcntl.h> 40.28 +#include <signal.h> 40.29 +#include <stdint.h> 40.30 +#include <stdbool.h> 40.31 +#include <stdlib.h> 40.32 +#include <sys/mman.h> 40.33 +#include "utils.h" 40.34 +#include "xs_lib.h" 40.35 + 40.36 +#define XSTEST 40.37 + 40.38 +static struct xs_handle *handles[10] = { NULL }; 40.39 + 40.40 +struct ringbuf_head 40.41 +{ 40.42 + uint32_t write; /* Next place to write to */ 40.43 + uint32_t read; /* Next place to read from */ 40.44 + uint8_t flags; 40.45 + char buf[0]; 40.46 +} __attribute__((packed)); 40.47 + 40.48 +static struct ringbuf_head *out, *in; 40.49 +static unsigned int ringbuf_datasize; 40.50 +static int daemon_pid; 40.51 + 40.52 +/* FIXME: Mark connection as broken (close it?) when this happens. */ 40.53 +static bool check_buffer(const struct ringbuf_head *h) 40.54 +{ 40.55 + return (h->write < ringbuf_datasize && h->read < ringbuf_datasize); 40.56 +} 40.57 + 40.58 +/* We can't fill last byte: would look like empty buffer. */ 40.59 +static void *get_output_chunk(const struct ringbuf_head *h, 40.60 + void *buf, uint32_t *len) 40.61 +{ 40.62 + uint32_t read_mark; 40.63 + 40.64 + if (h->read == 0) 40.65 + read_mark = ringbuf_datasize - 1; 40.66 + else 40.67 + read_mark = h->read - 1; 40.68 + 40.69 + /* Here to the end of buffer, unless they haven't read some out. */ 40.70 + *len = ringbuf_datasize - h->write; 40.71 + if (read_mark >= h->write) 40.72 + *len = read_mark - h->write; 40.73 + return buf + h->write; 40.74 +} 40.75 + 40.76 +static const void *get_input_chunk(const struct ringbuf_head *h, 40.77 + const void *buf, uint32_t *len) 40.78 +{ 40.79 + /* Here to the end of buffer, unless they haven't written some. */ 40.80 + *len = ringbuf_datasize - h->read; 40.81 + if (h->write >= h->read) 40.82 + *len = h->write - h->read; 40.83 + return buf + h->read; 40.84 +} 40.85 + 40.86 +static void update_output_chunk(struct ringbuf_head *h, uint32_t len) 40.87 +{ 40.88 + h->write += len; 40.89 + if (h->write == ringbuf_datasize) 40.90 + h->write = 0; 40.91 +} 40.92 + 40.93 +static void update_input_chunk(struct ringbuf_head *h, uint32_t len) 40.94 +{ 40.95 + h->read += len; 40.96 + if (h->read == ringbuf_datasize) 40.97 + h->read = 0; 40.98 +} 40.99 + 40.100 +/* FIXME: We spin, and we're sloppy. */ 40.101 +static bool read_all_shmem(int fd __attribute__((unused)), 40.102 + void *data, unsigned int len) 40.103 +{ 40.104 + unsigned int avail; 40.105 + 40.106 + if (!check_buffer(in)) 40.107 + barf("Corrupt buffer"); 40.108 + 40.109 + while (len) { 40.110 + const void *src = get_input_chunk(in, in->buf, &avail); 40.111 + if (avail > len) 40.112 + avail = len; 40.113 + memcpy(data, src, avail); 40.114 + data += avail; 40.115 + len -= avail; 40.116 + update_input_chunk(in, avail); 40.117 + } 40.118 + 40.119 + /* Tell other end we read something. */ 40.120 + kill(daemon_pid, SIGUSR2); 40.121 + return true; 40.122 +} 40.123 + 40.124 +static bool write_all_shmem(int fd __attribute__((unused)), 40.125 + const void *data, unsigned int len) 40.126 +{ 40.127 + uint32_t avail; 40.128 + 40.129 + if (!check_buffer(out)) 40.130 + barf("Corrupt buffer"); 40.131 + 40.132 + while (len) { 40.133 + void *dst = get_output_chunk(out, out->buf, &avail); 40.134 + if (avail > len) 40.135 + avail = len; 40.136 + memcpy(dst, data, avail); 40.137 + data += avail; 40.138 + len -= avail; 40.139 + update_output_chunk(out, avail); 40.140 + } 40.141 + 40.142 + /* Tell other end we wrote something. */ 40.143 + kill(daemon_pid, SIGUSR2); 40.144 + return true; 40.145 +} 40.146 + 40.147 +static bool read_all(int fd, void *data, unsigned int len); 40.148 +static bool read_all_choice(int fd, void *data, unsigned int len) 40.149 +{ 40.150 + if (fd == -2) 40.151 + return read_all_shmem(fd, data, len); 40.152 + return read_all(fd, data, len); 40.153 +} 40.154 + 40.155 +static bool write_all_choice(int fd, const void *data, unsigned int len) 40.156 +{ 40.157 + if (fd == -2) 40.158 + return write_all_shmem(fd, data, len); 40.159 + return write_all(fd, data, len); 40.160 +} 40.161 + 40.162 +/* We want access to internal functions. */ 40.163 +#include "xs.c" 40.164 + 40.165 +static void __attribute__((noreturn)) usage(void) 40.166 +{ 40.167 + barf("Usage:\n" 40.168 + " xs_test [--readonly] [--notimeout]\n" 40.169 + "Reads commands from stdin, one per line:" 40.170 + " dir <path>\n" 40.171 + " read <path>\n" 40.172 + " write <path> <flags> <value>...\n" 40.173 + " setid <id>\n" 40.174 + " mkdir <path>\n" 40.175 + " rm <path>\n" 40.176 + " getperm <path>\n" 40.177 + " setperm <path> <id> <flags> ...\n" 40.178 + " shutdown\n" 40.179 + " watch <path> <prio>\n" 40.180 + " waitwatch\n" 40.181 + " ackwatch\n" 40.182 + " unwatch <path>\n" 40.183 + " close\n" 40.184 + " start <node>\n" 40.185 + " abort\n" 40.186 + " introduce <domid> <mfn> <eventchn>\n" 40.187 + " commit\n" 40.188 + " sleep <seconds>\n" 40.189 + " dump\n"); 40.190 +} 40.191 + 40.192 +static char *arg(char *line, unsigned int num) 40.193 +{ 40.194 + static char *args[10]; 40.195 + unsigned int i, len = 0; 40.196 + 40.197 + for (i = 0; i <= num; i++) { 40.198 + line += len; 40.199 + line += strspn(line, " \t\n"); 40.200 + len = strcspn(line, " \t\n"); 40.201 + if (!len) 40.202 + barf("Can't get arg %u", num); 40.203 + } 40.204 + 40.205 + free(args[num]); 40.206 + args[num] = malloc(len + 1); 40.207 + memcpy(args[num], line, len); 40.208 + args[num][len] = '\0'; 40.209 + return args[num]; 40.210 +} 40.211 + 40.212 +static char *command; 40.213 +static void __attribute__((noreturn)) failed(int handle) 40.214 +{ 40.215 + if (handle) 40.216 + barf_perror("%i: %s", handle, command); 40.217 + barf_perror("%s", command); 40.218 +} 40.219 + 40.220 +static void do_dir(unsigned int handle, char *path) 40.221 +{ 40.222 + char **entries; 40.223 + unsigned int i, num; 40.224 + 40.225 + entries = xs_directory(handles[handle], path, &num); 40.226 + if (!entries) 40.227 + failed(handle); 40.228 + 40.229 + for (i = 0; i < num; i++) 40.230 + if (handle) 40.231 + printf("%i:%s\n", handle, entries[i]); 40.232 + else 40.233 + printf("%s\n", entries[i]); 40.234 + free(entries); 40.235 +} 40.236 + 40.237 +static void do_read(unsigned int handle, char *path) 40.238 +{ 40.239 + char *value; 40.240 + unsigned int len; 40.241 + 40.242 + value = xs_read(handles[handle], path, &len); 40.243 + if (!value) 40.244 + failed(handle); 40.245 + 40.246 + if (handle) 40.247 + printf("%i:%.*s\n", handle, len, value); 40.248 + else 40.249 + printf("%.*s\n", len, value); 40.250 +} 40.251 + 40.252 +static void do_write(unsigned int handle, char *path, char *flags, char *data) 40.253 +{ 40.254 + int f; 40.255 + 40.256 + if (streq(flags, "none")) 40.257 + f = 0; 40.258 + else if (streq(flags, "create")) 40.259 + f = O_CREAT; 40.260 + else if (streq(flags, "excl")) 40.261 + f = O_CREAT | O_EXCL; 40.262 + else if (streq(flags, "crap")) 40.263 + f = 100; 40.264 + else 40.265 + barf("write flags 'none', 'create' or 'excl' only"); 40.266 + 40.267 + if (!xs_write(handles[handle], path, data, strlen(data)+1, f)) 40.268 + failed(handle); 40.269 +} 40.270 + 40.271 +static void do_setid(unsigned int handle, char *id) 40.272 +{ 40.273 + if (!xs_bool(xs_debug_command(handles[handle], "setid", id, 40.274 + strlen(id)+1))) 40.275 + failed(handle); 40.276 +} 40.277 + 40.278 +static void do_mkdir(unsigned int handle, char *path) 40.279 +{ 40.280 + if (!xs_mkdir(handles[handle], path)) 40.281 + failed(handle); 40.282 +} 40.283 + 40.284 +static void do_rm(unsigned int handle, char *path) 40.285 +{ 40.286 + if (!xs_rm(handles[handle], path)) 40.287 + failed(handle); 40.288 +} 40.289 + 40.290 +static void do_getperm(unsigned int handle, char *path) 40.291 +{ 40.292 + unsigned int i, num; 40.293 + struct xs_permissions *perms; 40.294 + 40.295 + perms = xs_get_permissions(handles[handle], path, &num); 40.296 + if (!perms) 40.297 + failed(handle); 40.298 + 40.299 + for (i = 0; i < num; i++) { 40.300 + char *permstring; 40.301 + 40.302 + switch (perms[i].perms) { 40.303 + case XS_PERM_NONE: 40.304 + permstring = "NONE"; 40.305 + break; 40.306 + case XS_PERM_WRITE: 40.307 + permstring = "WRITE"; 40.308 + break; 40.309 + case XS_PERM_READ: 40.310 + permstring = "READ"; 40.311 + break; 40.312 + case XS_PERM_READ|XS_PERM_WRITE: 40.313 + permstring = "READ/WRITE"; 40.314 + break; 40.315 + default: 40.316 + barf("bad perm value %i", perms[i].perms); 40.317 + } 40.318 + 40.319 + if (handle) 40.320 + printf("%i:%i %s\n", handle, perms[i].id, permstring); 40.321 + else 40.322 + printf("%i %s\n", perms[i].id, permstring); 40.323 + } 40.324 + free(perms); 40.325 +} 40.326 + 40.327 +static void do_setperm(unsigned int handle, char *path, char *line) 40.328 +{ 40.329 + unsigned int i; 40.330 + struct xs_permissions perms[100]; 40.331 + 40.332 + strtok(line, " \t\n"); 40.333 + strtok(NULL, " \t\n"); 40.334 + for (i = 0; ; i++) { 40.335 + char *arg = strtok(NULL, " \t\n"); 40.336 + if (!arg) 40.337 + break; 40.338 + perms[i].id = atoi(arg); 40.339 + arg = strtok(NULL, " \t\n"); 40.340 + if (!arg) 40.341 + break; 40.342 + if (streq(arg, "WRITE")) 40.343 + perms[i].perms = XS_PERM_WRITE; 40.344 + else if (streq(arg, "READ")) 40.345 + perms[i].perms = XS_PERM_READ; 40.346 + else if (streq(arg, "READ/WRITE")) 40.347 + perms[i].perms = XS_PERM_READ|XS_PERM_WRITE; 40.348 + else if (streq(arg, "NONE")) 40.349 + perms[i].perms = XS_PERM_NONE; 40.350 + else 40.351 + barf("bad flags %s\n", arg); 40.352 + } 40.353 + 40.354 + if (!xs_set_permissions(handles[handle], path, perms, i)) 40.355 + failed(handle); 40.356 +} 40.357 + 40.358 +static void do_shutdown(unsigned int handle) 40.359 +{ 40.360 + if (!xs_shutdown(handles[handle])) 40.361 + failed(handle); 40.362 +} 40.363 + 40.364 +static void do_watch(unsigned int handle, const char *node, const char *pri) 40.365 +{ 40.366 + if (!xs_watch(handles[handle], node, atoi(pri))) 40.367 + failed(handle); 40.368 +} 40.369 + 40.370 +static void do_waitwatch(unsigned int handle) 40.371 +{ 40.372 + char *node; 40.373 + 40.374 + node = xs_read_watch(handles[handle]); 40.375 + if (!node) 40.376 + failed(handle); 40.377 + 40.378 + if (handle) 40.379 + printf("%i:%s\n", handle, node); 40.380 + else 40.381 + printf("%s\n", node); 40.382 + free(node); 40.383 +} 40.384 + 40.385 +static void do_ackwatch(unsigned int handle) 40.386 +{ 40.387 + if (!xs_acknowledge_watch(handles[handle])) 40.388 + failed(handle); 40.389 +} 40.390 + 40.391 +static void do_unwatch(unsigned int handle, const char *node) 40.392 +{ 40.393 + if (!xs_unwatch(handles[handle], node)) 40.394 + failed(handle); 40.395 +} 40.396 + 40.397 +static void do_start(unsigned int handle, const char *node) 40.398 +{ 40.399 + if (!xs_transaction_start(handles[handle], node)) 40.400 + failed(handle); 40.401 +} 40.402 + 40.403 +static void do_end(unsigned int handle, bool abort) 40.404 +{ 40.405 + if (!xs_transaction_end(handles[handle], abort)) 40.406 + failed(handle); 40.407 +} 40.408 + 40.409 +static void do_introduce(unsigned int handle, 40.410 + const char *domid, 40.411 + const char *mfn, 40.412 + const char *eventchn, 40.413 + const char *path) 40.414 +{ 40.415 + unsigned int i; 40.416 + int fd; 40.417 + 40.418 + /* We poll, so ignore signal */ 40.419 + signal(SIGUSR2, SIG_IGN); 40.420 + for (i = 0; i < ARRAY_SIZE(handles); i++) 40.421 + if (!handles[i]) 40.422 + break; 40.423 + 40.424 + fd = open("/tmp/xcmap", O_RDWR); 40.425 + /* Set in and out pointers. */ 40.426 + out = mmap(NULL, getpagesize(), PROT_WRITE|PROT_READ, MAP_SHARED,fd,0); 40.427 + if (out == MAP_FAILED) 40.428 + barf_perror("Failed to map /tmp/xcmap page"); 40.429 + in = (void *)out + getpagesize() / 2; 40.430 + close(fd); 40.431 + 40.432 + /* Tell them the event channel and our PID. */ 40.433 + *(int *)((void *)out + 32) = getpid(); 40.434 + *(u16 *)((void *)out + 36) = atoi(eventchn); 40.435 + 40.436 + /* Create new handle. */ 40.437 + handles[i] = new(struct xs_handle); 40.438 + handles[i]->fd = -2; 40.439 + 40.440 + if (!xs_introduce_domain(handles[handle], atoi(domid), 40.441 + atol(mfn), atoi(eventchn), path)) 40.442 + failed(handle); 40.443 + printf("handle is %i\n", i); 40.444 + 40.445 + /* Read in daemon pid. */ 40.446 + daemon_pid = *(int *)((void *)out + 32); 40.447 +} 40.448 + 40.449 +static void do_release(unsigned int handle, const char *domid) 40.450 +{ 40.451 + if (!xs_release_domain(handles[handle], atoi(domid))) 40.452 + failed(handle); 40.453 +} 40.454 + 40.455 +static int strptrcmp(const void *a, const void *b) 40.456 +{ 40.457 + return strcmp(*(char **)a, *(char **)b); 40.458 +} 40.459 + 40.460 +static void sort_dir(char **dir, unsigned int num) 40.461 +{ 40.462 + qsort(dir, num, sizeof(char *), strptrcmp); 40.463 +} 40.464 + 40.465 +static void dump_dir(unsigned int handle, 40.466 + const char *node, 40.467 + char **dir, 40.468 + unsigned int numdirs, 40.469 + unsigned int depth) 40.470 +{ 40.471 + unsigned int i; 40.472 + char spacing[depth+1]; 40.473 + 40.474 + memset(spacing, ' ', depth); 40.475 + spacing[depth] = '\0'; 40.476 + 40.477 + sort_dir(dir, numdirs); 40.478 + 40.479 + for (i = 0; i < numdirs; i++) { 40.480 + struct xs_permissions *perms; 40.481 + unsigned int j, numperms; 40.482 + unsigned int len; 40.483 + char *contents; 40.484 + unsigned int subnum; 40.485 + char **subdirs; 40.486 + char subnode[strlen(node) + 1 + strlen(dir[i]) + 1]; 40.487 + 40.488 + sprintf(subnode, "%s/%s", node, dir[i]); 40.489 + 40.490 + perms = xs_get_permissions(handles[handle], subnode,&numperms); 40.491 + if (!perms) 40.492 + failed(handle); 40.493 + 40.494 + printf("%s%s: ", spacing, dir[i]); 40.495 + for (j = 0; j < numperms; j++) { 40.496 + char buffer[100]; 40.497 + if (!perm_to_string(&perms[j], buffer)) 40.498 + barf("perm to string"); 40.499 + printf("%s ", buffer); 40.500 + } 40.501 + free(perms); 40.502 + printf("\n"); 40.503 + 40.504 + /* Even directories can have contents. */ 40.505 + contents = xs_read(handles[handle], subnode, &len); 40.506 + if (!contents) { 40.507 + if (errno != EISDIR) 40.508 + failed(handle); 40.509 + } else { 40.510 + printf(" %s(%.*s)\n", spacing, len, contents); 40.511 + free(contents); 40.512 + } 40.513 + 40.514 + /* Every node is a directory. */ 40.515 + subdirs = xs_directory(handles[handle], subnode, &subnum); 40.516 + if (!subdirs) 40.517 + failed(handle); 40.518 + dump_dir(handle, subnode, subdirs, subnum, depth+1); 40.519 + free(subdirs); 40.520 + } 40.521 +} 40.522 + 40.523 +static void dump(int handle) 40.524 +{ 40.525 + char **subdirs; 40.526 + unsigned int subnum; 40.527 + 40.528 + subdirs = xs_directory(handles[handle], "/", &subnum); 40.529 + if (!subdirs) 40.530 + failed(handle); 40.531 + 40.532 + dump_dir(handle, "", subdirs, subnum, 0); 40.533 + free(subdirs); 40.534 +} 40.535 + 40.536 +int main(int argc, char *argv[]) 40.537 +{ 40.538 + char line[1024]; 40.539 + bool readonly = false, timeout = true; 40.540 + int handle; 40.541 + 40.542 + static void alarmed(int sig __attribute__((unused))) 40.543 + { 40.544 + if (handle) { 40.545 + char handlename[10]; 40.546 + sprintf(handlename, "%u:", handle); 40.547 + write(STDOUT_FILENO, handlename, strlen(handlename)); 40.548 + } 40.549 + write(STDOUT_FILENO, command, strlen(command)); 40.550 + write(STDOUT_FILENO, " timeout\n", strlen(" timeout\n")); 40.551 + exit(1); 40.552 + } 40.553 + 40.554 + if (argc > 1 && streq(argv[1], "--readonly")) { 40.555 + readonly = true; 40.556 + argc--; 40.557 + argv++; 40.558 + } 40.559 + 40.560 + if (argc > 1 && streq(argv[1], "--notimeout")) { 40.561 + timeout = false; 40.562 + argc--; 40.563 + argv++; 40.564 + } 40.565 + 40.566 + if (argc != 1) 40.567 + usage(); 40.568 + 40.569 + /* The size of the ringbuffer: half a page minus head structure. */ 40.570 + ringbuf_datasize = getpagesize() / 2 - sizeof(struct ringbuf_head); 40.571 + 40.572 + signal(SIGALRM, alarmed); 40.573 + while (fgets(line, sizeof(line), stdin)) { 40.574 + char *endp; 40.575 + 40.576 + if (strspn(line, " \n") == strlen(line)) 40.577 + continue; 40.578 + if (strstarts(line, "#")) 40.579 + continue; 40.580 + 40.581 + handle = strtoul(line, &endp, 10); 40.582 + if (endp != line) 40.583 + memmove(line, endp+1, strlen(endp)); 40.584 + else 40.585 + handle = 0; 40.586 + 40.587 + if (!handles[handle]) { 40.588 + if (readonly) 40.589 + handles[handle] = xs_daemon_open_readonly(); 40.590 + else 40.591 + handles[handle] = xs_daemon_open(); 40.592 + if (!handles[handle]) 40.593 + barf_perror("Opening connection to daemon"); 40.594 + } 40.595 + command = arg(line, 0); 40.596 + 40.597 + if (timeout) 40.598 + alarm(5); 40.599 + if (streq(command, "dir")) 40.600 + do_dir(handle, arg(line, 1)); 40.601 + else if (streq(command, "read")) 40.602 + do_read(handle, arg(line, 1)); 40.603 + else if (streq(command, "write")) 40.604 + do_write(handle, 40.605 + arg(line, 1), arg(line, 2), arg(line, 3)); 40.606 + else if (streq(command, "setid")) 40.607 + do_setid(handle, arg(line, 1)); 40.608 + else if (streq(command, "mkdir")) 40.609 + do_mkdir(handle, arg(line, 1)); 40.610 + else if (streq(command, "rm")) 40.611 + do_rm(handle, arg(line, 1)); 40.612 + else if (streq(command, "getperm")) 40.613 + do_getperm(handle, arg(line, 1)); 40.614 + else if (streq(command, "setperm")) 40.615 + do_setperm(handle, arg(line, 1), line); 40.616 + else if (streq(command, "shutdown")) 40.617 + do_shutdown(handle); 40.618 + else if (streq(command, "watch")) 40.619 + do_watch(handle, arg(line, 1), arg(line, 2)); 40.620 + else if (streq(command, "waitwatch")) 40.621 + do_waitwatch(handle); 40.622 + else if (streq(command, "ackwatch")) 40.623 + do_ackwatch(handle); 40.624 + else if (streq(command, "unwatch")) 40.625 + do_unwatch(handle, arg(line, 1)); 40.626 + else if (streq(command, "close")) { 40.627 + xs_daemon_close(handles[handle]); 40.628 + handles[handle] = NULL; 40.629 + } else if (streq(command, "start")) 40.630 + do_start(handle, arg(line, 1)); 40.631 + else if (streq(command, "commit")) 40.632 + do_end(handle, false); 40.633 + else if (streq(command, "abort")) 40.634 + do_end(handle, true); 40.635 + else if (streq(command, "introduce")) 40.636 + do_introduce(handle, arg(line, 1), arg(line, 2), 40.637 + arg(line, 3), arg(line, 4)); 40.638 + else if (streq(command, "release")) 40.639 + do_release(handle, arg(line, 1)); 40.640 + else if (streq(command, "dump")) 40.641 + dump(handle); 40.642 + else if (streq(command, "sleep")) 40.643 + sleep(atoi(arg(line, 1))); 40.644 + else 40.645 + barf("Unknown command %s", command); 40.646 + fflush(stdout); 40.647 + alarm(0); 40.648 + } 40.649 + return 0; 40.650 +}