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>
author cl349@firebug.cl.cam.ac.uk
date Tue Jun 07 12:43:58 2005 +0000 (2005-06-07)
parents 3917e69c7587
children 4ad402c55b9f
files .rootkeys BitKeeper/etc/ignore tools/Makefile tools/xenstore/.gdbinit tools/xenstore/Makefile tools/xenstore/TODO tools/xenstore/fake_libxc.c tools/xenstore/list.h tools/xenstore/talloc.c tools/xenstore/talloc.h tools/xenstore/talloc_guide.txt tools/xenstore/testsuite/01simple.sh tools/xenstore/testsuite/02directory.sh tools/xenstore/testsuite/03write.sh tools/xenstore/testsuite/04rm.sh tools/xenstore/testsuite/05filepermissions.sh tools/xenstore/testsuite/06dirpermissions.sh tools/xenstore/testsuite/07watch.sh tools/xenstore/testsuite/08transaction.sh tools/xenstore/testsuite/09domain.sh tools/xenstore/testsuite/test.sh tools/xenstore/utils.c tools/xenstore/utils.h tools/xenstore/xenstored.h tools/xenstore/xenstored_core.c tools/xenstore/xenstored_core.h tools/xenstore/xenstored_domain.c tools/xenstore/xenstored_domain.h tools/xenstore/xenstored_test.h tools/xenstore/xenstored_transaction.c tools/xenstore/xenstored_transaction.h tools/xenstore/xenstored_watch.c tools/xenstore/xenstored_watch.h tools/xenstore/xs.c tools/xenstore/xs.h tools/xenstore/xs_lib.c tools/xenstore/xs_lib.h tools/xenstore/xs_random.c tools/xenstore/xs_stress.c tools/xenstore/xs_test.c
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 +}