xen-vtx-unstable
changeset 5396:6d3e8f90c2df
bitkeeper revision 1.1700 (42a854e79oBFuqa_DSY4Lr9IhenUQw)
Merge xenstore changes.
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
Merge xenstore changes.
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
line diff
1.1 --- a/.rootkeys Thu Jun 09 14:07:02 2005 +0000 1.2 +++ b/.rootkeys Thu Jun 09 14:40:39 2005 +0000 1.3 @@ -864,6 +864,7 @@ 40c9c469n2RRwCmjWdjdyyVRWKmgWg tools/pyt 1.4 40dc4076hGpwa8-sWRN0jtXZeQJuKg tools/python/xen/__init__.py 1.5 40dfd40aMOhnw_cQLve9462UR5yYxQ tools/python/xen/lowlevel/__init__.py 1.6 3fbd0a42l40lM0IICw2jXbQBVZSdZg tools/python/xen/lowlevel/xc/xc.c 1.7 +42a59f20JpCmm9DsCoVZowGafnhBuw tools/python/xen/lowlevel/xs/xs.c 1.8 40dc4076St6AmPTmQPrtQ6LGHPxGmw tools/python/xen/lowlevel/xu/__init__.py 1.9 40dc4076CwBYRTUQDdbdU1L6KcLgSw tools/python/xen/lowlevel/xu/xu.c 1.10 40d8915cyoVA0hJxiBFNymL7YvDaRg tools/python/xen/util/Brctl.py 1.11 @@ -871,6 +872,7 @@ 40dfd40aGqGkiopOOgJxSF4iCbHM0Q tools/pyt 1.12 4270e4efFg3wHCCxXpA0h6yoMTkeSQ tools/python/xen/util/blkif.py 1.13 4055ee4dwy4l0MghZosxoiu6zmhc9Q tools/python/xen/util/console_client.py 1.14 40c9c468IienauFHQ_xJIcqnPJ8giQ tools/python/xen/util/ip.py 1.15 +42a4a80aiq_AT5whiSw-fKhNhRKITw tools/python/xen/util/mac.py 1.16 41dde8b0yuJX-S79w4xJKxBQ-Mhp1A tools/python/xen/util/memmap.py 1.17 4288c6fcB1kUAqX0gzU85GGxmamS4Q tools/python/xen/util/process.py 1.18 4059c6a0pnxhG8hwSOivXybbGOwuXw tools/python/xen/util/tempfile.py 1.19 @@ -908,6 +910,7 @@ 40c9c4686jruMyZIqiaZRMiMoqMJtg tools/pyt 1.20 40c9c468xzANp6o2D_MeCYwNmOIUsQ tools/python/xen/xend/XendVnet.py 1.21 40c9c468x191zetrVlMnExfsQWHxIQ tools/python/xen/xend/__init__.py 1.22 40c9c468S2YnCEKmk4ey8XQIST7INg tools/python/xen/xend/encode.py 1.23 +42a475165HuglqWwNi2fjqNOIHbIKQ tools/python/xen/xend/image.py 1.24 4266169ezWIlXSfY50n6HSoVFbosmw tools/python/xen/xend/scheduler.py 1.25 40c9c468IxQabrKJSWs0aEjl-27mRQ tools/python/xen/xend/server/SrvConsole.py 1.26 40c9c4689Io5bxfbYIfRiUvsiLX0EQ tools/python/xen/xend/server/SrvConsoleDir.py 1.27 @@ -933,6 +936,11 @@ 4266169eI_oX3YBjwaeC0V-THBRnjg tools/pyt 1.28 4294a1bf8rMUcddot-B2-pOxORimOg tools/python/xen/xend/server/relocate.py 1.29 41ee5e8dq9NtihbL4nWKjuSLOhXPUg tools/python/xen/xend/server/usbif.py 1.30 40c9c469LNxLVizOUpOjEaTKKCm8Aw tools/python/xen/xend/sxp.py 1.31 +42a48d152jkT7ykQT_LWKnS-ojV_ZA tools/python/xen/xend/uuid.py 1.32 +42a5a2c0ik9zrQvwjTUKDVVEQmvO2Q tools/python/xen/xend/xenstore/__init__.py 1.33 +42a5a2c04xNCYAUXD0b9IDf4XekXRg tools/python/xen/xend/xenstore/xsnode.py 1.34 +42a5a2c0-aP98db2PJIDxQJfTEMZ-A tools/python/xen/xend/xenstore/xsobj.py 1.35 +42a5a2c0gxfQiAH_oVTShNPeG0LG2Q tools/python/xen/xend/xenstore/xsresource.py 1.36 40d05079aFRp6NQdo5wIh5Ly31c0cg tools/python/xen/xm/__init__.py 1.37 40cf2937gKQcATgXKGtNeWb1PDH5nA tools/python/xen/xm/create.py 1.38 40f552eariuUSB9TWqCPnDLz5zvxMw tools/python/xen/xm/destroy.py 1.39 @@ -1052,6 +1060,43 @@ 41d58ba6ijEF6fedqRO5vFu7uCirZg tools/xcs 1.40 4292540couq-V0TPwyQ6bspNEWNcvw tools/xcutils/Makefile 1.41 42925407VysDb9O06OK_RUzTZxfLoA tools/xcutils/xc_restore.c 1.42 42936745WTLYamYsmXm_JGJ72JX-_Q tools/xcutils/xc_save.c 1.43 +42a57d97mxMTlPnxBKep6R4ViI5rjg tools/xenstore/.gdbinit 1.44 +42a57d97ZEoHuhMAFTuBMlLzA9v_ng tools/xenstore/Makefile 1.45 +42a57d97ccA4uY-RxONvIH0P8U0gqg tools/xenstore/TODO 1.46 +42a57d972RzmyLgsoH9b8qqk-UjcCA tools/xenstore/fake_libxc.c 1.47 +42a57d97IjoPvbIVc4BUzwoKyM0VSw tools/xenstore/list.h 1.48 +42a57d97fKgtf0HQLiQkAkVsOvuSyA tools/xenstore/talloc.c 1.49 +42a57d98U3p0XP6xzCybTuaVQscUdw tools/xenstore/talloc.h 1.50 +42a57d98LFN6Mug-uR4xgAxCE7lwUg tools/xenstore/talloc_guide.txt 1.51 +42a57d98S69vKJYwO_WUjoFQZ6KzQg tools/xenstore/testsuite/01simple.sh 1.52 +42a57d98BHcFpZz_fXHweylUEUU97Q tools/xenstore/testsuite/02directory.sh 1.53 +42a57d98ua4Xeb6pmtbFNTAI833dyw tools/xenstore/testsuite/03write.sh 1.54 +42a57d98nbuCUsVT0RJj1zA1JyMDsw tools/xenstore/testsuite/04rm.sh 1.55 +42a57d98_ULKHP3_uX1PK2nPMTzWSQ tools/xenstore/testsuite/05filepermissions.sh 1.56 +42a57d98YGCLyTDSGmoyFqRqQUlagQ tools/xenstore/testsuite/06dirpermissions.sh 1.57 +42a57d98fdO519YyATk4_Zwr1STNfQ tools/xenstore/testsuite/07watch.sh 1.58 +42a57d98zZUtvirUMjmHxFphJjmO7Q tools/xenstore/testsuite/08transaction.sh 1.59 +42a57d98sn9RbpBgHRv1D99Kt7LwYA tools/xenstore/testsuite/09domain.sh 1.60 +42a57d98tSuoFCHnnM2GgENXJrRQmw tools/xenstore/testsuite/test.sh 1.61 +42a57d98zxDP2Ti7dTznGROi66rUGw tools/xenstore/utils.c 1.62 +42a57d98SDvOYCEjmCjwHSk6390GLA tools/xenstore/utils.h 1.63 +42a57d98hFKbOY9D0mCE4H4NDoKr1w tools/xenstore/xenstored.h 1.64 +42a57d981KFHLmJ0CjKkn1_gZhYvdw tools/xenstore/xenstored_core.c 1.65 +42a57d98bcgE13vYaFxGTusmWbrFDA tools/xenstore/xenstored_core.h 1.66 +42a57d98cD9wOFyRYfaEP0QgtqL1Xw tools/xenstore/xenstored_domain.c 1.67 +42a57d98noLWvXU8ePbcqvvmu4p2Gw tools/xenstore/xenstored_domain.h 1.68 +42a57d98kxHaQ1ApS7RpqmFoEnDmbg tools/xenstore/xenstored_test.h 1.69 +42a57d981c9P3aFkWtxWEIRUapt_FQ tools/xenstore/xenstored_transaction.c 1.70 +42a57d99pVo__10bbckp_b_rm6i59A tools/xenstore/xenstored_transaction.h 1.71 +42a57d99izTIjWfG-IjQAPqYlDWJNg tools/xenstore/xenstored_watch.c 1.72 +42a57d99-zLxBjzC7rfj_perV-orUg tools/xenstore/xenstored_watch.h 1.73 +42a57d99BnkhISKgCCRcUqhteyuxCw tools/xenstore/xs.c 1.74 +42a57d99FyiYSz9AkKKROrRydnA-gQ tools/xenstore/xs.h 1.75 +42a57d99SrtsJCDUlKyRPf3EX86A1Q tools/xenstore/xs_lib.c 1.76 +42a57d99L2pYeMFyjQ_4Rnb17xTSMg tools/xenstore/xs_lib.h 1.77 +42a57d99Kl6Ba8oCHv2fggl7QN9QZA tools/xenstore/xs_random.c 1.78 +42a57d99SHYR1lQOD0shuErPDg9NKQ tools/xenstore/xs_stress.c 1.79 +42a57d996aBawpkQNOWkNWXD6LrhPg tools/xenstore/xs_test.c 1.80 403a3edbrr8RE34gkbR40zep98SXbg tools/xentrace/Makefile 1.81 40a107afN60pFdURgBv9KwEzgRl5mQ tools/xentrace/formats 1.82 420d52d2_znVbT4JAPIU36vQOme83g tools/xentrace/xenctx.c
2.1 --- a/BitKeeper/etc/ignore Thu Jun 09 14:07:02 2005 +0000 2.2 +++ b/BitKeeper/etc/ignore Thu Jun 09 14:40:39 2005 +0000 2.3 @@ -94,8 +94,8 @@ tools/cmdline/* 2.4 tools/cmdline/xen/* 2.5 tools/firmware/*.bin 2.6 tools/firmware/*.sym 2.7 +tools/firmware/*/biossums 2.8 tools/firmware/*bios/*bios*.txt 2.9 -tools/firmware/*/biossums 2.10 tools/firmware/rombios/BIOS-bochs-latest 2.11 tools/firmware/rombios/_rombios_.c 2.12 tools/firmware/rombios/rombios.s 2.13 @@ -140,6 +140,13 @@ tools/xcs/xcs 2.14 tools/xcs/xcsdump 2.15 tools/xcutils/xc_restore 2.16 tools/xcutils/xc_save 2.17 +tools/xenstore/testsuite/tmp/* 2.18 +tools/xenstore/xen 2.19 +tools/xenstore/xenstored 2.20 +tools/xenstore/xenstored_test 2.21 +tools/xenstore/xs_random 2.22 +tools/xenstore/xs_stress 2.23 +tools/xenstore/xs_test 2.24 tools/xentrace/xentrace 2.25 tools/xfrd/xfrd 2.26 xen/BLOG
3.1 --- a/linux-2.6.11-xen-sparse/drivers/xen/netback/control.c Thu Jun 09 14:07:02 2005 +0000 3.2 +++ b/linux-2.6.11-xen-sparse/drivers/xen/netback/control.c Thu Jun 09 14:40:39 2005 +0000 3.3 @@ -10,6 +10,8 @@ 3.4 3.5 static void netif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id) 3.6 { 3.7 + DPRINTK("Received netif backend message, subtype=%d\n", msg->subtype); 3.8 + 3.9 switch ( msg->subtype ) 3.10 { 3.11 case CMSG_NETIF_BE_CREATE:
4.1 --- a/tools/Makefile Thu Jun 09 14:07:02 2005 +0000 4.2 +++ b/tools/Makefile Thu Jun 09 14:40:39 2005 +0000 4.3 @@ -3,12 +3,14 @@ include $(XEN_ROOT)/tools/Rules.mk 4.4 4.5 SUBDIRS := 4.6 SUBDIRS += libxc 4.7 +SUBDIRS += xenstore 4.8 SUBDIRS += misc 4.9 SUBDIRS += examples 4.10 SUBDIRS += xentrace 4.11 SUBDIRS += python 4.12 SUBDIRS += xcs 4.13 SUBDIRS += xcutils 4.14 +SUBDIRS += xenstore 4.15 SUBDIRS += pygrub 4.16 SUBDIRS += firmware 4.17
5.1 --- a/tools/libxc/xc.h Thu Jun 09 14:07:02 2005 +0000 5.2 +++ b/tools/libxc/xc.h Thu Jun 09 14:40:39 2005 +0000 5.3 @@ -252,7 +252,9 @@ int xc_linux_build(int xc_handle, 5.4 const char *cmdline, 5.5 unsigned int control_evtchn, 5.6 unsigned long flags, 5.7 - unsigned int vcpus); 5.8 + unsigned int vcpus, 5.9 + unsigned int store_evtchn, 5.10 + unsigned long *store_mfn); 5.11 5.12 int 5.13 xc_plan9_build (int xc_handle,
6.1 --- a/tools/libxc/xc_linux_build.c Thu Jun 09 14:07:02 2005 +0000 6.2 +++ b/tools/libxc/xc_linux_build.c Thu Jun 09 14:40:39 2005 +0000 6.3 @@ -48,17 +48,18 @@ static int probeimageformat(char *image, 6.4 } 6.5 6.6 static int setup_guest(int xc_handle, 6.7 - u32 dom, 6.8 - char *image, unsigned long image_size, 6.9 - gzFile initrd_gfd, unsigned long initrd_len, 6.10 - unsigned long nr_pages, 6.11 - unsigned long *pvsi, unsigned long *pvke, 6.12 - vcpu_guest_context_t *ctxt, 6.13 - const char *cmdline, 6.14 - unsigned long shared_info_frame, 6.15 - unsigned int control_evtchn, 6.16 - unsigned long flags, 6.17 - unsigned int vcpus) 6.18 + u32 dom, 6.19 + char *image, unsigned long image_size, 6.20 + gzFile initrd_gfd, unsigned long initrd_len, 6.21 + unsigned long nr_pages, 6.22 + unsigned long *pvsi, unsigned long *pvke, 6.23 + unsigned long *pvss, vcpu_guest_context_t *ctxt, 6.24 + const char *cmdline, 6.25 + unsigned long shared_info_frame, 6.26 + unsigned int control_evtchn, 6.27 + unsigned long flags, 6.28 + unsigned int vcpus, 6.29 + unsigned int store_evtchn, unsigned long *store_mfn) 6.30 { 6.31 l1_pgentry_t *vl1tab=NULL, *vl1e=NULL; 6.32 l2_pgentry_t *vl2tab=NULL, *vl2e=NULL; 6.33 @@ -91,6 +92,8 @@ static int setup_guest(int xc_handle, 6.34 unsigned long vphysmap_end; 6.35 unsigned long vstartinfo_start; 6.36 unsigned long vstartinfo_end; 6.37 + unsigned long vstoreinfo_start; 6.38 + unsigned long vstoreinfo_end; 6.39 unsigned long vstack_start; 6.40 unsigned long vstack_end; 6.41 unsigned long vpt_start; 6.42 @@ -130,7 +133,10 @@ static int setup_guest(int xc_handle, 6.43 vpt_end = vpt_start + (nr_pt_pages * PAGE_SIZE); 6.44 vstartinfo_start = vpt_end; 6.45 vstartinfo_end = vstartinfo_start + PAGE_SIZE; 6.46 - vstack_start = vstartinfo_end; 6.47 + /* Place store shared page after startinfo. */ 6.48 + vstoreinfo_start = vstartinfo_end; 6.49 + vstoreinfo_end = vstartinfo_end + PAGE_SIZE; 6.50 + vstack_start = vstoreinfo_end; 6.51 vstack_end = vstack_start + PAGE_SIZE; 6.52 v_end = (vstack_end + (1UL<<22)-1) & ~((1UL<<22)-1); 6.53 if ( (v_end - vstack_end) < (512UL << 10) ) 6.54 @@ -161,6 +167,7 @@ static int setup_guest(int xc_handle, 6.55 " Phys-Mach map: %p->%p\n" 6.56 " Page tables: %p->%p\n" 6.57 " Start info: %p->%p\n" 6.58 + " Store page: %p->%p\n" 6.59 " Boot stack: %p->%p\n" 6.60 " TOTAL: %p->%p\n", 6.61 _p(dsi.v_kernstart), _p(dsi.v_kernend), 6.62 @@ -168,6 +175,7 @@ static int setup_guest(int xc_handle, 6.63 _p(vphysmap_start), _p(vphysmap_end), 6.64 _p(vpt_start), _p(vpt_end), 6.65 _p(vstartinfo_start), _p(vstartinfo_end), 6.66 + _p(vstoreinfo_start), _p(vstoreinfo_end), 6.67 _p(vstack_start), _p(vstack_end), 6.68 _p(dsi.v_start), _p(v_end)); 6.69 printf(" ENTRY ADDRESS: %p\n", _p(dsi.v_kernentry)); 6.70 @@ -377,6 +385,8 @@ static int setup_guest(int xc_handle, 6.71 start_info->nr_pt_frames = nr_pt_pages; 6.72 start_info->mfn_list = vphysmap_start; 6.73 start_info->domain_controller_evtchn = control_evtchn; 6.74 + start_info->store_page = vstoreinfo_start; 6.75 + start_info->store_evtchn = store_evtchn; 6.76 if ( initrd_len != 0 ) 6.77 { 6.78 start_info->mod_start = vinitrd_start; 6.79 @@ -386,6 +396,9 @@ static int setup_guest(int xc_handle, 6.80 start_info->cmd_line[MAX_GUEST_CMDLINE-1] = '\0'; 6.81 munmap(start_info, PAGE_SIZE); 6.82 6.83 + /* Tell our caller where we told domain store page was. */ 6.84 + *store_mfn = page_array[((vstoreinfo_start-dsi.v_start)>>PAGE_SHIFT)]; 6.85 + 6.86 /* shared_info page starts its life empty. */ 6.87 shared_info = xc_map_foreign_range( 6.88 xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE, shared_info_frame); 6.89 @@ -407,6 +420,7 @@ static int setup_guest(int xc_handle, 6.90 free(page_array); 6.91 6.92 *pvsi = vstartinfo_start; 6.93 + *pvss = vstack_start; 6.94 *pvke = dsi.v_kernentry; 6.95 6.96 return 0; 6.97 @@ -426,7 +440,9 @@ int xc_linux_build(int xc_handle, 6.98 const char *cmdline, 6.99 unsigned int control_evtchn, 6.100 unsigned long flags, 6.101 - unsigned int vcpus) 6.102 + unsigned int vcpus, 6.103 + unsigned int store_evtchn, 6.104 + unsigned long *store_mfn) 6.105 { 6.106 dom0_op_t launch_op, op; 6.107 int initrd_fd = -1; 6.108 @@ -436,7 +452,7 @@ int xc_linux_build(int xc_handle, 6.109 unsigned long nr_pages; 6.110 char *image = NULL; 6.111 unsigned long image_size, initrd_size=0; 6.112 - unsigned long vstartinfo_start, vkern_entry; 6.113 + unsigned long vstartinfo_start, vkern_entry, vstack_start; 6.114 6.115 if ( (nr_pages = xc_get_tot_pages(xc_handle, domid)) < 0 ) 6.116 { 6.117 @@ -493,11 +509,12 @@ int xc_linux_build(int xc_handle, 6.118 } 6.119 6.120 if ( setup_guest(xc_handle, domid, image, image_size, 6.121 - initrd_gfd, initrd_size, nr_pages, 6.122 - &vstartinfo_start, &vkern_entry, 6.123 - ctxt, cmdline, 6.124 - op.u.getdomaininfo.shared_info_frame, 6.125 - control_evtchn, flags, vcpus) < 0 ) 6.126 + initrd_gfd, initrd_size, nr_pages, 6.127 + &vstartinfo_start, &vkern_entry, 6.128 + &vstack_start, ctxt, cmdline, 6.129 + op.u.getdomaininfo.shared_info_frame, 6.130 + control_evtchn, flags, vcpus, 6.131 + store_evtchn, store_mfn) < 0 ) 6.132 { 6.133 ERROR("Error constructing guest OS"); 6.134 goto error_out; 6.135 @@ -528,7 +545,7 @@ int xc_linux_build(int xc_handle, 6.136 ctxt->user_regs.ss = FLAT_KERNEL_SS; 6.137 ctxt->user_regs.cs = FLAT_KERNEL_CS; 6.138 ctxt->user_regs.eip = vkern_entry; 6.139 - ctxt->user_regs.esp = vstartinfo_start + 2*PAGE_SIZE; 6.140 + ctxt->user_regs.esp = vstack_start + PAGE_SIZE; 6.141 ctxt->user_regs.esi = vstartinfo_start; 6.142 ctxt->user_regs.eflags = 1 << 9; /* Interrupt Enable */ 6.143 6.144 @@ -550,7 +567,7 @@ int xc_linux_build(int xc_handle, 6.145 6.146 /* Ring 1 stack is the initial stack. */ 6.147 ctxt->kernel_ss = FLAT_KERNEL_SS; 6.148 - ctxt->kernel_sp = vstartinfo_start + 2*PAGE_SIZE; 6.149 + ctxt->kernel_sp = vstack_start + PAGE_SIZE; 6.150 6.151 /* No debugging. */ 6.152 memset(ctxt->debugreg, 0, sizeof(ctxt->debugreg));
7.1 --- a/tools/python/setup.py Thu Jun 09 14:07:02 2005 +0000 7.2 +++ b/tools/python/setup.py Thu Jun 09 14:40:39 2005 +0000 7.3 @@ -9,13 +9,15 @@ extra_compile_args = [ "-fno-strict-ali 7.4 7.5 include_dirs = [ XEN_ROOT + "/tools/python/xen/lowlevel/xu", 7.6 XEN_ROOT + "/tools/libxc", 7.7 + XEN_ROOT + "/tools/xenstore", 7.8 XEN_ROOT + "/tools/xcs", 7.9 ] 7.10 7.11 library_dirs = [ XEN_ROOT + "/tools/libxc", 7.12 + XEN_ROOT + "/tools/xenstore", 7.13 ] 7.14 7.15 -libraries = [ "xc" ] 7.16 +libraries = [ "xc", "xenstore" ] 7.17 7.18 xc = Extension("xc", 7.19 extra_compile_args = extra_compile_args, 7.20 @@ -30,7 +32,14 @@ xu = Extension("xu", 7.21 library_dirs = library_dirs, 7.22 libraries = libraries, 7.23 sources = [ "xen/lowlevel/xu/xu.c" ]) 7.24 - 7.25 + 7.26 +xs = Extension("xs", 7.27 + extra_compile_args = extra_compile_args, 7.28 + include_dirs = include_dirs + [ "xen/lowlevel/xs" ], 7.29 + library_dirs = library_dirs, 7.30 + libraries = libraries, 7.31 + sources = [ "xen/lowlevel/xs/xs.c" ]) 7.32 + 7.33 setup(name = 'xen', 7.34 version = '2.0', 7.35 description = 'Xen', 7.36 @@ -39,11 +48,12 @@ setup(name = 'xen', 7.37 'xen.util', 7.38 'xen.xend', 7.39 'xen.xend.server', 7.40 + 'xen.xend.xenstore', 7.41 'xen.xm', 7.42 'xen.web', 7.43 ], 7.44 ext_package = "xen.lowlevel", 7.45 - ext_modules = [ xc, xu ] 7.46 + ext_modules = [ xc, xu, xs ] 7.47 ) 7.48 7.49 os.chdir('logging')
8.1 --- a/tools/python/xen/lowlevel/xc/xc.c Thu Jun 09 14:07:02 2005 +0000 8.2 +++ b/tools/python/xen/lowlevel/xc/xc.c Thu Jun 09 14:40:39 2005 +0000 8.3 @@ -14,6 +14,7 @@ 8.4 #include <sys/socket.h> 8.5 #include <netdb.h> 8.6 #include <arpa/inet.h> 8.7 + 8.8 #include "xc_private.h" 8.9 #include "linux_boot_params.h" 8.10 8.11 @@ -259,25 +260,28 @@ static PyObject *pyxc_linux_build(PyObje 8.12 { 8.13 XcObject *xc = (XcObject *)self; 8.14 8.15 - u32 dom; 8.16 + u32 dom; 8.17 char *image, *ramdisk = NULL, *cmdline = ""; 8.18 - int control_evtchn, flags = 0, vcpus = 1; 8.19 + int flags = 0, vcpus = 1; 8.20 + int control_evtchn, store_evtchn; 8.21 + unsigned long store_mfn = 0; 8.22 8.23 - static char *kwd_list[] = { "dom", "control_evtchn", 8.24 - "image", "ramdisk", "cmdline", "flags", "vcpus", 8.25 - NULL }; 8.26 + static char *kwd_list[] = { "dom", "control_evtchn", "store_evtchn", 8.27 + "image", "ramdisk", "cmdline", "flags", 8.28 + "vcpus", NULL }; 8.29 8.30 - if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iis|ssii", kwd_list, 8.31 - &dom, &control_evtchn, 8.32 - &image, &ramdisk, &cmdline, &flags, &vcpus) ) 8.33 + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiis|ssii", kwd_list, 8.34 + &dom, &control_evtchn, &store_evtchn, 8.35 + &image, &ramdisk, &cmdline, &flags, 8.36 + &vcpus) ) 8.37 return NULL; 8.38 8.39 if ( xc_linux_build(xc->xc_handle, dom, image, 8.40 - ramdisk, cmdline, control_evtchn, flags, vcpus) != 0 ) 8.41 + ramdisk, cmdline, control_evtchn, flags, vcpus, 8.42 + store_evtchn, &store_mfn) != 0 ) 8.43 return PyErr_SetFromErrno(xc_error); 8.44 8.45 - Py_INCREF(zero); 8.46 - return zero; 8.47 + return Py_BuildValue("{s:i}", "store_mfn", store_mfn); 8.48 } 8.49 8.50 static PyObject *pyxc_plan9_build(PyObject *self, 8.51 @@ -834,6 +838,7 @@ static PyMethodDef pyxc_methods[] = { 8.52 0, "\n" 8.53 "Query the xc control interface file descriptor.\n\n" 8.54 "Returns: [int] file descriptor\n" }, 8.55 + 8.56 { "domain_create", 8.57 (PyCFunction)pyxc_domain_create, 8.58 METH_VARARGS | METH_KEYWORDS, "\n" 8.59 @@ -844,8 +849,8 @@ static PyMethodDef pyxc_methods[] = { 8.60 { "domain_dumpcore", 8.61 (PyCFunction)pyxc_domain_dumpcore, 8.62 METH_VARARGS | METH_KEYWORDS, "\n" 8.63 - "dump core of a domain.\n" 8.64 - " dom [int]: Identifier of domain to be paused.\n\n" 8.65 + "Dump core of a domain.\n" 8.66 + " dom [int]: Identifier of domain to dump core of.\n" 8.67 " corefile [string]: Name of corefile to be created.\n\n" 8.68 "Returns: [int] 0 on success; -1 on error.\n" }, 8.69
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 9.2 +++ b/tools/python/xen/lowlevel/xs/xs.c Thu Jun 09 14:40:39 2005 +0000 9.3 @@ -0,0 +1,617 @@ 9.4 +#include <Python.h> 9.5 + 9.6 +#include <stdio.h> 9.7 +#include <stdlib.h> 9.8 +#include <unistd.h> 9.9 +#include <sys/types.h> 9.10 +#include <sys/stat.h> 9.11 +#include <fcntl.h> 9.12 + 9.13 +#include "xs.h" 9.14 + 9.15 +/** @file 9.16 + * Python interface to the Xen Store Daemon (xs). 9.17 + */ 9.18 + 9.19 +/* Needed for Python versions earlier than 2.3. */ 9.20 +//#ifndef PyMODINIT_FUNC 9.21 +//#define PyMODINIT_FUNC DL_EXPORT(void) 9.22 +//#endif 9.23 + 9.24 +#define PYPKG "xen.lowlevel.xs" 9.25 + 9.26 +/** Python wrapper round an xs handle. 9.27 + */ 9.28 +typedef struct XsHandle { 9.29 + PyObject_HEAD; 9.30 + struct xs_handle *xh; 9.31 +} XsHandle; 9.32 + 9.33 +static inline struct xs_handle *xshandle(PyObject *self) 9.34 +{ 9.35 + struct xs_handle *xh = ((XsHandle*)self)->xh; 9.36 + if (!xh) 9.37 + PyErr_SetString(PyExc_RuntimeError, "invalid xenstore daemon handle"); 9.38 + return xh; 9.39 +} 9.40 + 9.41 +static inline PyObject *pyvalue_int(int val) { 9.42 + return (val 9.43 + ? PyInt_FromLong(val) 9.44 + : PyErr_SetFromErrno(PyExc_RuntimeError)); 9.45 +} 9.46 + 9.47 +static inline PyObject *pyvalue_str(char *val) { 9.48 + return (val 9.49 + ? PyString_FromString(val) 9.50 + : PyErr_SetFromErrno(PyExc_RuntimeError)); 9.51 +} 9.52 + 9.53 +static PyObject *xspy_write(PyObject *self, PyObject *args, PyObject *kwds) 9.54 +{ 9.55 + static char *kwd_spec[] = { "path", "data", "create", "excl", NULL }; 9.56 + static char *arg_spec = "ss#|ii"; 9.57 + char *path = NULL; 9.58 + char *data = NULL; 9.59 + int data_n = 0; 9.60 + int create = 0; 9.61 + int excl = 0; 9.62 + 9.63 + struct xs_handle *xh = xshandle(self); 9.64 + PyObject *val = NULL; 9.65 + int flags = 0; 9.66 + int xsval = 0; 9.67 + 9.68 + if (!xh) 9.69 + goto exit; 9.70 + if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, 9.71 + &path, &data, &data_n, &create, &excl)) 9.72 + goto exit; 9.73 + if (create) 9.74 + flags |= O_CREAT; 9.75 + if (excl) 9.76 + flags |= O_EXCL; 9.77 + xsval = xs_write(xh, path, data, data_n, flags); 9.78 + val = pyvalue_int(xsval); 9.79 + exit: 9.80 + return val; 9.81 +} 9.82 + 9.83 +static PyObject *xspy_read(PyObject *self, PyObject *args, PyObject *kwds) 9.84 +{ 9.85 + static char *kwd_spec[] = { "path", NULL }; 9.86 + static char *arg_spec = "s|"; 9.87 + char *path = NULL; 9.88 + 9.89 + struct xs_handle *xh = xshandle(self); 9.90 + char *xsval = NULL; 9.91 + int xsval_n = 0; 9.92 + PyObject *val = NULL; 9.93 + 9.94 + if (!xh) 9.95 + goto exit; 9.96 + if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, 9.97 + &path)) 9.98 + goto exit; 9.99 + xsval = xs_read(xh, path, &xsval_n); 9.100 + if (!xsval) { 9.101 + val = pyvalue_int(0); 9.102 + goto exit; 9.103 + } 9.104 + val = PyString_FromStringAndSize(xsval, xsval_n); 9.105 + exit: 9.106 + if (xsval) 9.107 + free(xsval); 9.108 + return val; 9.109 +} 9.110 + 9.111 +static PyObject *xspy_mkdir(PyObject *self, PyObject *args, PyObject *kwds) 9.112 +{ 9.113 + static char *kwd_spec[] = { "path", NULL }; 9.114 + static char *arg_spec = "s|"; 9.115 + char *path = NULL; 9.116 + 9.117 + struct xs_handle *xh = xshandle(self); 9.118 + PyObject *val = NULL; 9.119 + int xsval = 0; 9.120 + 9.121 + if (!xh) 9.122 + goto exit; 9.123 + if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path)) 9.124 + goto exit; 9.125 + xsval = xs_mkdir(xh, path); 9.126 + val = pyvalue_int(xsval); 9.127 + exit: 9.128 + return val; 9.129 +} 9.130 + 9.131 +static PyObject *xspy_ls(PyObject *self, PyObject *args, PyObject *kwds) 9.132 +{ 9.133 + static char *kwd_spec[] = { "path", NULL }; 9.134 + static char *arg_spec = "s|"; 9.135 + char *path = NULL; 9.136 + 9.137 + struct xs_handle *xh = xshandle(self); 9.138 + PyObject *val = NULL; 9.139 + char **xsval = NULL; 9.140 + int xsval_n = 0; 9.141 + int i; 9.142 + 9.143 + if (!xh) 9.144 + goto exit; 9.145 + if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path)) 9.146 + goto exit; 9.147 + xsval = xs_directory(xh, path, &xsval_n); 9.148 + if (!xsval) { 9.149 + val = pyvalue_int(0); 9.150 + goto exit; 9.151 + } 9.152 + val = PyList_New(xsval_n); 9.153 + for (i = 0; i < xsval_n; i++) 9.154 + PyList_SetItem(val, i, PyString_FromString(xsval[i])); 9.155 + exit: 9.156 + return val; 9.157 +} 9.158 + 9.159 +static PyObject *xspy_rm(PyObject *self, PyObject *args, PyObject *kwds) 9.160 +{ 9.161 + static char *kwd_spec[] = { "path", NULL }; 9.162 + static char *arg_spec = "s|"; 9.163 + char *path = NULL; 9.164 + 9.165 + struct xs_handle *xh = xshandle(self); 9.166 + PyObject *val = NULL; 9.167 + int xsval = 0; 9.168 + 9.169 + if (!xh) 9.170 + goto exit; 9.171 + if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path)) 9.172 + goto exit; 9.173 + xsval = xs_rm(xh, path); 9.174 + val = pyvalue_int(xsval); 9.175 + exit: 9.176 + return val; 9.177 +} 9.178 + 9.179 +static PyObject *xspy_get_permissions(PyObject *self, PyObject *args, 9.180 + PyObject *kwds) 9.181 +{ 9.182 + static char *kwd_spec[] = { "path", NULL }; 9.183 + static char *arg_spec = "s|"; 9.184 + char *path = NULL; 9.185 + 9.186 + struct xs_handle *xh = xshandle(self); 9.187 + PyObject *val = NULL; 9.188 + struct xs_permissions *perms; 9.189 + int perms_n = 0; 9.190 + int i; 9.191 + 9.192 + if (!xh) 9.193 + goto exit; 9.194 + if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path)) 9.195 + goto exit; 9.196 + perms = xs_get_permissions(xh, path, &perms_n); 9.197 + if (!perms) { 9.198 + PyErr_SetFromErrno(PyExc_RuntimeError); 9.199 + goto exit; 9.200 + } 9.201 + val = PyList_New(perms_n); 9.202 + for (i = 0; i < perms_n; i++, perms++) { 9.203 + PyObject *p = Py_BuildValue("{s:i,s:i,s:i,s:i,s:i}", 9.204 + "dom", perms->id, 9.205 + "read", (perms->perms & XS_PERM_READ), 9.206 + "write", (perms->perms & XS_PERM_WRITE), 9.207 + "create", (perms->perms & XS_PERM_CREATE), 9.208 + "owner", (perms->perms & XS_PERM_OWNER)); 9.209 + PyList_SetItem(val, i, p); 9.210 + } 9.211 + exit: 9.212 + return val; 9.213 +} 9.214 + 9.215 +static PyObject *xspy_set_permissions(PyObject *self, PyObject *args, 9.216 + PyObject *kwds) 9.217 +{ 9.218 + static char *kwd_spec[] = { "path", "perms", NULL }; 9.219 + static char *arg_spec = "sO"; 9.220 + char *path = NULL; 9.221 + PyObject *perms = NULL; 9.222 + static char *perm_names[] = { "dom", "read", "write", "create", "owner", 9.223 + NULL }; 9.224 + static char *perm_spec = "i|iiii"; 9.225 + 9.226 + struct xs_handle *xh = xshandle(self); 9.227 + int i, xsval; 9.228 + struct xs_permissions *xsperms = NULL; 9.229 + int xsperms_n = 0; 9.230 + PyObject *tuple0 = NULL; 9.231 + PyObject *val = NULL; 9.232 + 9.233 + if (!xh) 9.234 + goto exit; 9.235 + if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, 9.236 + &path, &perms)) 9.237 + goto exit; 9.238 + if (!PyList_Check(perms)) { 9.239 + PyErr_SetString(PyExc_RuntimeError, "perms must be a list"); 9.240 + goto exit; 9.241 + } 9.242 + xsperms_n = PyList_Size(perms); 9.243 + xsperms = calloc(xsperms_n, sizeof(struct xs_permissions)); 9.244 + if (!xsperms) { 9.245 + PyErr_SetString(PyExc_RuntimeError, "out of memory"); 9.246 + goto exit; 9.247 + } 9.248 + tuple0 = PyTuple_New(0); 9.249 + if (!tuple0) 9.250 + goto exit; 9.251 + for (i = 0; i < xsperms_n; i++) { 9.252 + /* Domain the permissions apply to. */ 9.253 + int dom = 0; 9.254 + /* Read/write perms. Set these. */ 9.255 + int p_read = 0, p_write = 0; 9.256 + /* Create/owner perms. Ignore them. 9.257 + * This is so the output from get_permissions() can be used 9.258 + * as input to set_permissions(). 9.259 + */ 9.260 + int p_create = 0, p_owner = 0; 9.261 + PyObject *p = PyList_GetItem(perms, i); 9.262 + if (!PyArg_ParseTupleAndKeywords(tuple0, p, perm_spec, perm_names, 9.263 + &dom, &p_read, &p_write, &p_create, 9.264 + &p_owner)) 9.265 + goto exit; 9.266 + xsperms[i].id = dom; 9.267 + if (p_read) 9.268 + xsperms[i].perms |= XS_PERM_READ; 9.269 + if (p_write) 9.270 + xsperms[i].perms |= XS_PERM_WRITE; 9.271 + } 9.272 + xsval = xs_set_permissions(xh, path, xsperms, xsperms_n); 9.273 + val = pyvalue_int(xsval); 9.274 + exit: 9.275 + Py_XDECREF(tuple0); 9.276 + if (xsperms) 9.277 + free(xsperms); 9.278 + return val; 9.279 +} 9.280 + 9.281 +static PyObject *xspy_watch(PyObject *self, PyObject *args, PyObject *kwds) 9.282 +{ 9.283 + static char *kwd_spec[] = { "path", "priority", NULL }; 9.284 + static char *arg_spec = "s|i"; 9.285 + char *path = NULL; 9.286 + int priority = 0; 9.287 + 9.288 + struct xs_handle *xh = xshandle(self); 9.289 + PyObject *val = NULL; 9.290 + int xsval = 0; 9.291 + 9.292 + if (!xh) 9.293 + goto exit; 9.294 + if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, 9.295 + &path, &priority)) 9.296 + goto exit; 9.297 + xsval = xs_watch(xh, path, priority); 9.298 + val = pyvalue_int(xsval); 9.299 + exit: 9.300 + return val; 9.301 +} 9.302 + 9.303 +static PyObject *xspy_read_watch(PyObject *self, PyObject *args, 9.304 + PyObject *kwds) 9.305 +{ 9.306 + static char *kwd_spec[] = { NULL }; 9.307 + static char *arg_spec = ""; 9.308 + 9.309 + struct xs_handle *xh = xshandle(self); 9.310 + PyObject *val = NULL; 9.311 + char *xsval = NULL; 9.312 + 9.313 + if (!xh) 9.314 + goto exit; 9.315 + if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec)) 9.316 + goto exit; 9.317 + xsval = xs_read_watch(xh); 9.318 + val = pyvalue_str(xsval); 9.319 + exit: 9.320 + if (xsval) 9.321 + free(xsval); 9.322 + return val; 9.323 +} 9.324 + 9.325 +static PyObject *xspy_acknowledge_watch(PyObject *self, PyObject *args, 9.326 + PyObject *kwds) 9.327 +{ 9.328 + static char *kwd_spec[] = { NULL }; 9.329 + static char *arg_spec = ""; 9.330 + 9.331 + struct xs_handle *xh = xshandle(self); 9.332 + PyObject *val = NULL; 9.333 + int xsval = 0; 9.334 + 9.335 + if (!xh) 9.336 + goto exit; 9.337 + if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec)) 9.338 + goto exit; 9.339 + xsval = xs_acknowledge_watch(xh); 9.340 + val = pyvalue_int(xsval); 9.341 + exit: 9.342 + return val; 9.343 +} 9.344 + 9.345 +static PyObject *xspy_unwatch(PyObject *self, PyObject *args, PyObject *kwds) 9.346 +{ 9.347 + static char *kwd_spec[] = { "path", NULL }; 9.348 + static char *arg_spec = "s|"; 9.349 + char *path = NULL; 9.350 + 9.351 + struct xs_handle *xh = xshandle(self); 9.352 + PyObject *val = NULL; 9.353 + int xsval = 0; 9.354 + 9.355 + if (!xh) 9.356 + goto exit; 9.357 + if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path)) 9.358 + goto exit; 9.359 + xsval = xs_unwatch(xh, path); 9.360 + val = pyvalue_int(xsval); 9.361 + exit: 9.362 + return val; 9.363 +} 9.364 + 9.365 +static PyObject *xspy_transaction_start(PyObject *self, PyObject *args, 9.366 + PyObject *kwds) 9.367 +{ 9.368 + static char *kwd_spec[] = { "path", NULL }; 9.369 + static char *arg_spec = "s|"; 9.370 + char *path = NULL; 9.371 + 9.372 + struct xs_handle *xh = xshandle(self); 9.373 + PyObject *val = NULL; 9.374 + int xsval = 0; 9.375 + 9.376 + if (!xh) 9.377 + goto exit; 9.378 + if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path)) 9.379 + goto exit; 9.380 + xsval = xs_transaction_start(xh, path); 9.381 + val = pyvalue_int(xsval); 9.382 + exit: 9.383 + return val; 9.384 +} 9.385 + 9.386 +static PyObject *xspy_transaction_end(PyObject *self, PyObject *args, 9.387 + PyObject *kwds) 9.388 +{ 9.389 + static char *kwd_spec[] = { "abort", NULL }; 9.390 + static char *arg_spec = "|i"; 9.391 + int abort = 0; 9.392 + 9.393 + struct xs_handle *xh = xshandle(self); 9.394 + PyObject *val = NULL; 9.395 + int xsval = 0; 9.396 + 9.397 + if (!xh) 9.398 + goto exit; 9.399 + if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &abort)) 9.400 + goto exit; 9.401 + xsval = xs_transaction_end(xh, abort); 9.402 + val = pyvalue_int(xsval); 9.403 + exit: 9.404 + return val; 9.405 +} 9.406 + 9.407 +static PyObject *xspy_introduce_domain(PyObject *self, PyObject *args, 9.408 + PyObject *kwds) 9.409 +{ 9.410 + static char *kwd_spec[] = { "dom", "page", "port", "path", NULL }; 9.411 + static char *arg_spec = "iiis|"; 9.412 + domid_t dom = 0; 9.413 + unsigned long page = 0; 9.414 + unsigned int port = 0; 9.415 + char *path = NULL; 9.416 + 9.417 + struct xs_handle *xh = xshandle(self); 9.418 + PyObject *val = NULL; 9.419 + int xsval = 0; 9.420 + 9.421 + if (!xh) 9.422 + goto exit; 9.423 + if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, 9.424 + &dom, &page, &port, &path)) 9.425 + goto exit; 9.426 + printf("%s> dom=%u page=0x%08lx port=%u path=%s\n", __FUNCTION__, dom, 9.427 + page, port, path); 9.428 + xsval = xs_introduce_domain(xh, dom, page, port, path); 9.429 + printf("%s> xsval=%d\n", __FUNCTION__, xsval); 9.430 + val = pyvalue_int(xsval); 9.431 + exit: 9.432 + return val; 9.433 +} 9.434 + 9.435 +static PyObject *xspy_release_domain(PyObject *self, PyObject *args, 9.436 + PyObject *kwds) 9.437 +{ 9.438 + static char *kwd_spec[] = { "dom", NULL }; 9.439 + static char *arg_spec = "i|"; 9.440 + domid_t dom; 9.441 + 9.442 + struct xs_handle *xh = xshandle(self); 9.443 + PyObject *val = NULL; 9.444 + int xsval = 0; 9.445 + 9.446 + if (!xh) 9.447 + goto exit; 9.448 + if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, 9.449 + &dom)) 9.450 + goto exit; 9.451 + printf("%s> dom=%u\n", __FUNCTION__, dom); 9.452 + xsval = xs_release_domain(xh, dom); 9.453 + printf("%s> xsval=%d\n", __FUNCTION__, xsval); 9.454 + val = pyvalue_int(xsval); 9.455 + exit: 9.456 + return val; 9.457 +} 9.458 + 9.459 +static PyObject *xspy_close(PyObject *self, PyObject *args, PyObject *kwds) 9.460 +{ 9.461 + static char *kwd_spec[] = { NULL }; 9.462 + static char *arg_spec = ""; 9.463 + 9.464 + struct xs_handle *xh = xshandle(self); 9.465 + PyObject *val = NULL; 9.466 + int xsval = 1; 9.467 + 9.468 + if (!xh) 9.469 + goto exit; 9.470 + if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec)) 9.471 + goto exit; 9.472 + xs_daemon_close(xh); 9.473 + ((XsHandle*)self)->xh = NULL; 9.474 + val = pyvalue_int(xsval); 9.475 + exit: 9.476 + return val; 9.477 +} 9.478 + 9.479 +static PyObject *xspy_shutdown(PyObject *self, PyObject *args, PyObject *kwds) 9.480 +{ 9.481 + static char *kwd_spec[] = { NULL }; 9.482 + static char *arg_spec = ""; 9.483 + 9.484 + struct xs_handle *xh = xshandle(self); 9.485 + PyObject *val = NULL; 9.486 + int xsval = 0; 9.487 + 9.488 + if (!xh) 9.489 + goto exit; 9.490 + if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec)) 9.491 + goto exit; 9.492 + xsval = xs_shutdown(xh); 9.493 + val = pyvalue_int(xsval); 9.494 + exit: 9.495 + return val; 9.496 +} 9.497 + 9.498 +#define XSPY_METH(_name) \ 9.499 + #_name, \ 9.500 + (PyCFunction) xspy_ ## _name, \ 9.501 + (METH_VARARGS | METH_KEYWORDS) 9.502 +// mtime 9.503 +// ctime 9.504 + 9.505 +static PyMethodDef xshandle_methods[] = { 9.506 + { XSPY_METH(read), 9.507 + "read(path) : read data\n" }, 9.508 + { XSPY_METH(write), 9.509 + "write(path, data, [creat], [excl]): write data\n" }, 9.510 + { XSPY_METH(ls), 9.511 + "ls(path): list directory.\n" }, 9.512 + { XSPY_METH(mkdir), 9.513 + "mkdir(path): make a directory.\n" }, 9.514 + { XSPY_METH(rm), 9.515 + "rm(path): remove a path (dir must be empty).\n" }, 9.516 + { XSPY_METH(get_permissions), 9.517 + "get_permissions(path)\n" }, 9.518 + { XSPY_METH(set_permissions), 9.519 + "set_permissions(path)\n" }, 9.520 + { XSPY_METH(watch), 9.521 + "watch(path)\n" }, 9.522 + { XSPY_METH(read_watch), 9.523 + "read_watch()\n" }, 9.524 + { XSPY_METH(acknowledge_watch), 9.525 + "acknowledge_watch()\n" }, 9.526 + { XSPY_METH(unwatch), 9.527 + "unwatch()\n" }, 9.528 + { XSPY_METH(transaction_start), 9.529 + "transaction_start()\n" }, 9.530 + { XSPY_METH(transaction_end), 9.531 + "transaction_end([abort])\n" }, 9.532 + { XSPY_METH(introduce_domain), 9.533 + "introduce_domain(dom, page, port)\n" }, 9.534 + { XSPY_METH(release_domain), 9.535 + "release_domain(dom)\n" }, 9.536 + { XSPY_METH(close), 9.537 + "close()\n" }, 9.538 + { XSPY_METH(shutdown), 9.539 + "shutdown()\n" }, 9.540 + { NULL, NULL, 0, NULL } 9.541 +}; 9.542 + 9.543 +static PyObject *xshandle_getattr(PyObject *self, char *name) 9.544 +{ 9.545 + PyObject *val = NULL; 9.546 + if (strcmp(name, "fileno") == 0) { 9.547 + struct xs_handle *xh = xshandle(self); 9.548 + val = PyInt_FromLong((xh ? xs_fileno(xh) : -1)); 9.549 + } else 9.550 + val = Py_FindMethod(xshandle_methods, self, name); 9.551 + return val; 9.552 +} 9.553 + 9.554 +static void xshandle_dealloc(PyObject *self) 9.555 +{ 9.556 + XsHandle *xh = (XsHandle*)self; 9.557 + if (xh->xh) { 9.558 + xs_daemon_close(xh->xh); 9.559 + xh->xh = NULL; 9.560 + } 9.561 + PyObject_Del(self); 9.562 +} 9.563 + 9.564 +static PyTypeObject xshandle_type = { 9.565 + PyObject_HEAD_INIT(&PyType_Type) 9.566 + 0, 9.567 + "xshandle", 9.568 + sizeof(XsHandle), 9.569 + 0, 9.570 + xshandle_dealloc, /* tp_dealloc */ 9.571 + NULL, /* tp_print */ 9.572 + xshandle_getattr, /* tp_getattr */ 9.573 + NULL, /* tp_setattr */ 9.574 + NULL, /* tp_compare */ 9.575 + NULL, /* tp_repr */ 9.576 + NULL, /* tp_as_number */ 9.577 + NULL, /* tp_as_sequence */ 9.578 + NULL, /* tp_as_mapping */ 9.579 + NULL /* tp_hash */ 9.580 +}; 9.581 + 9.582 +static PyObject *xshandle_open(PyObject *self, PyObject *args, PyObject *kwds) 9.583 +{ 9.584 + static char *kwd_spec[] = { "readonly", NULL }; 9.585 + static char *arg_spec = "|i"; 9.586 + int readonly = 0; 9.587 + 9.588 + XsHandle *xsh = NULL; 9.589 + PyObject *val = NULL; 9.590 + 9.591 + if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, 9.592 + &readonly)) 9.593 + goto exit; 9.594 + 9.595 + xsh = PyObject_New(XsHandle, &xshandle_type); 9.596 + if (!xsh) 9.597 + goto exit; 9.598 + xsh->xh = (readonly ? xs_daemon_open_readonly() : xs_daemon_open()); 9.599 + if (!xsh->xh) { 9.600 + PyObject_Del(xsh); 9.601 + val = pyvalue_int(0); 9.602 + goto exit; 9.603 + } 9.604 + val = (PyObject *)xsh; 9.605 + exit: 9.606 + return val; 9.607 +} 9.608 + 9.609 +static PyMethodDef xs_methods[] = { 9.610 + { "open", (PyCFunction)xshandle_open, (METH_VARARGS | METH_KEYWORDS), 9.611 + "Open a connection to the xenstore daemon.\n" }, 9.612 + { NULL, NULL, 0, NULL } 9.613 +}; 9.614 + 9.615 +PyMODINIT_FUNC initxs (void) 9.616 +{ 9.617 + PyObject *module; 9.618 + 9.619 + module = Py_InitModule(PYPKG, xs_methods); 9.620 +}
10.1 --- a/tools/python/xen/lowlevel/xu/xu.c Thu Jun 09 14:07:02 2005 +0000 10.2 +++ b/tools/python/xen/lowlevel/xu/xu.c Thu Jun 09 14:40:39 2005 +0000 10.3 @@ -1370,7 +1370,8 @@ static PyObject *xu_port_new(PyObject *s 10.4 10.5 fail1: 10.6 PyObject_Del((PyObject *)xup); 10.7 - return NULL; 10.8 + PyErr_SetString(PyExc_ValueError, "cannot create port"); 10.9 + return NULL; 10.10 } 10.11 10.12 static PyObject *xu_port_getattr(PyObject *obj, char *name)
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 11.2 +++ b/tools/python/xen/util/mac.py Thu Jun 09 14:40:39 2005 +0000 11.3 @@ -0,0 +1,11 @@ 11.4 + 11.5 +from string import join, split 11.6 + 11.7 +def macToString(mac): 11.8 + return ':'.join(map(lambda x: "%02x" % x, mac)) 11.9 + 11.10 +def macFromString(str): 11.11 + mac = [ int(x, 16) for x in str.split(':') ] 11.12 + if len(mac) != 6: 11.13 + raise ValueError("invalid mac: %s" % str) 11.14 + return mac
12.1 --- a/tools/python/xen/web/SrvDir.py Thu Jun 09 14:07:02 2005 +0000 12.2 +++ b/tools/python/xen/web/SrvDir.py Thu Jun 09 14:40:39 2005 +0000 12.3 @@ -77,19 +77,16 @@ class SrvDir(SrvBase): 12.4 return v 12.5 12.6 def render_GET(self, req): 12.7 - try: 12.8 - if self.use_sxp(req): 12.9 - req.setHeader("Content-type", sxp.mime_type) 12.10 - self.ls(req, 1) 12.11 - else: 12.12 - req.write('<html><head></head><body>') 12.13 - self.print_path(req) 12.14 - self.ls(req) 12.15 - self.form(req) 12.16 - req.write('</body></html>') 12.17 - return '' 12.18 - except Exception, ex: 12.19 - self._perform_err(ex, "GET", req) 12.20 + if self.use_sxp(req): 12.21 + req.setHeader("Content-type", sxp.mime_type) 12.22 + self.ls(req, 1) 12.23 + else: 12.24 + req.write('<html><head></head><body>') 12.25 + self.print_path(req) 12.26 + self.ls(req) 12.27 + self.form(req) 12.28 + req.write('</body></html>') 12.29 + return '' 12.30 12.31 def ls(self, req, use_sxp=0): 12.32 url = req.prePathURL()
13.1 --- a/tools/python/xen/xend/PrettyPrint.py Thu Jun 09 14:07:02 2005 +0000 13.2 +++ b/tools/python/xen/xend/PrettyPrint.py Thu Jun 09 14:40:39 2005 +0000 13.3 @@ -285,15 +285,18 @@ def prettyprint(sxpr, out=sys.stdout, wi 13.4 sxp.show(sxpr, out=out) 13.5 print >> out 13.6 13.7 -def prettyprintstring(sxp): 13.8 - class tmpstr: 13.9 - def __init__(self): 13.10 - self.str = "" 13.11 - def write(self, str): 13.12 - self.str = self.str + str 13.13 - tmp = tmpstr() 13.14 - prettyprint(sxp, out=tmp) 13.15 - return tmp.str 13.16 +def prettyprintstring(sxpr, width=80): 13.17 + """Prettyprint an SXP form to a string. 13.18 + 13.19 + sxpr s-expression 13.20 + width maximum output width 13.21 + """ 13.22 + io = StringIO.StringIO() 13.23 + prettyprint(sxpr, out=io, width=width) 13.24 + io.seek(0) 13.25 + val = io.getvalue() 13.26 + io.close() 13.27 + return val 13.28 13.29 def main(): 13.30 pin = sxp.Parser()
14.1 --- a/tools/python/xen/xend/XendCheckpoint.py Thu Jun 09 14:07:02 2005 +0000 14.2 +++ b/tools/python/xen/xend/XendCheckpoint.py Thu Jun 09 14:40:39 2005 +0000 14.3 @@ -43,7 +43,7 @@ def save(xd, fd, dominfo): 14.4 write_exact(fd, config, "could not write guest state file: config") 14.5 14.6 cmd = [PATH_XC_SAVE, str(xc.handle()), str(fd), 14.7 - dominfo.id] 14.8 + str(dominfo.id)] 14.9 log.info("[xc_save] " + join(cmd)) 14.10 child = xPopen3(cmd, True, -1, [fd, xc.handle()]) 14.11 14.12 @@ -63,10 +63,10 @@ def save(xd, fd, dominfo): 14.13 if fd == child.fromchild.fileno(): 14.14 l = child.fromchild.readline() 14.15 if l.rstrip() == "suspend": 14.16 - log.info("suspending %s" % dominfo.id) 14.17 + log.info("suspending %d" % dominfo.id) 14.18 xd.domain_shutdown(dominfo.id, reason='suspend') 14.19 dominfo.state_wait("suspended") 14.20 - log.info("suspend %s done" % dominfo.id) 14.21 + log.info("suspend %d done" % dominfo.id) 14.22 child.tochild.write("done\n") 14.23 child.tochild.flush() 14.24 if filter(lambda (fd, event): event & select.POLLHUP, r): 14.25 @@ -109,7 +109,7 @@ def restore(xd, fd): 14.26 "not a valid guest state file: pfn count out of range") 14.27 14.28 cmd = [PATH_XC_RESTORE, str(xc.handle()), str(fd), 14.29 - dominfo.id, str(nr_pfns)] 14.30 + str(dominfo.id), str(nr_pfns)] 14.31 log.info("[xc_restore] " + join(cmd)) 14.32 child = xPopen3(cmd, True, -1, [fd, xc.handle()]) 14.33 child.tochild.close()
15.1 --- a/tools/python/xen/xend/XendDomain.py Thu Jun 09 14:07:02 2005 +0000 15.2 +++ b/tools/python/xen/xend/XendDomain.py Thu Jun 09 14:40:39 2005 +0000 15.3 @@ -7,46 +7,42 @@ 15.4 """ 15.5 import errno 15.6 import os 15.7 -import scheduler 15.8 -import string 15.9 import sys 15.10 +import time 15.11 import traceback 15.12 -import time 15.13 15.14 import xen.lowlevel.xc; xc = xen.lowlevel.xc.new() 15.15 15.16 +from xen.xend import sxp 15.17 +from xen.xend import XendRoot; xroot = XendRoot.instance() 15.18 +from xen.xend import XendCheckpoint 15.19 +from xen.xend.XendDomainInfo import XendDomainInfo, shutdown_reason 15.20 +from xen.xend import EventServer; eserver = EventServer.instance() 15.21 +from xen.xend.XendError import XendError 15.22 +from xen.xend.XendLogging import log 15.23 +from xen.xend import scheduler 15.24 +from xen.xend.server import channel 15.25 from xen.xend.server import relocate 15.26 -import sxp 15.27 -import XendRoot; xroot = XendRoot.instance() 15.28 -import XendCheckpoint 15.29 -import XendDB 15.30 -import XendDomainInfo 15.31 -import EventServer; eserver = EventServer.instance() 15.32 -from XendError import XendError 15.33 -from XendLogging import log 15.34 - 15.35 -from xen.xend.server import channel 15.36 +from xen.xend.uuid import getUuid 15.37 +from xen.xend.xenstore import XenNode, DBMap 15.38 15.39 __all__ = [ "XendDomain" ] 15.40 15.41 SHUTDOWN_TIMEOUT = 30 15.42 15.43 +class XendDomainDict(dict): 15.44 + def get_by_name(self, name): 15.45 + try: 15.46 + return filter(lambda d: d.name == name, self.values())[0] 15.47 + except IndexError, err: 15.48 + return None 15.49 + 15.50 class XendDomain: 15.51 """Index of all domains. Singleton. 15.52 """ 15.53 15.54 - """Path to domain database.""" 15.55 - dbpath = "domain" 15.56 - 15.57 - class XendDomainDict(dict): 15.58 - def get_by_name(self, name): 15.59 - try: 15.60 - return filter(lambda d: d.name == name, self.values())[0] 15.61 - except IndexError, err: 15.62 - return None 15.63 - 15.64 """Dict of domain info indexed by domain id.""" 15.65 - domains = XendDomainDict() 15.66 + domains = None 15.67 15.68 def __init__(self): 15.69 # Hack alert. Python does not support mutual imports, but XendDomainInfo 15.70 @@ -54,8 +50,8 @@ class XendDomain: 15.71 # to import XendDomain from XendDomainInfo causes unbounded recursion. 15.72 # So we stuff the XendDomain instance (self) into xroot's components. 15.73 xroot.add_component("xen.xend.XendDomain", self) 15.74 - # Table of domain info indexed by domain id. 15.75 - self.db = XendDB.XendDB(self.dbpath) 15.76 + self.domains = XendDomainDict() 15.77 + self.dbmap = DBMap(db=XenNode("/domain")) 15.78 eserver.subscribe('xend.virq', self.onVirq) 15.79 self.initial_refresh() 15.80 15.81 @@ -77,18 +73,16 @@ class XendDomain: 15.82 domlist = xc.domain_getinfo() 15.83 doms = {} 15.84 for d in domlist: 15.85 - domid = str(d['dom']) 15.86 + domid = d['dom'] 15.87 doms[domid] = d 15.88 return doms 15.89 15.90 def xen_domain(self, dom): 15.91 """Get info about a single domain from xc. 15.92 Returns None if not found. 15.93 + 15.94 + @param dom domain id (int) 15.95 """ 15.96 - try: 15.97 - dom = int(dom) 15.98 - except ValueError: 15.99 - return None 15.100 dominfo = xc.domain_getinfo(dom, 1) 15.101 if dominfo == [] or dominfo[0]['dom'] != dom: 15.102 dominfo = None 15.103 @@ -100,37 +94,36 @@ class XendDomain: 15.104 """Refresh initial domain info from db. 15.105 """ 15.106 doms = self.xen_domains() 15.107 - for config in self.db.fetchall("").values(): 15.108 - domid = str(sxp.child_value(config, 'id')) 15.109 - if domid in doms: 15.110 + self.dbmap.readDB() 15.111 + for domdb in self.dbmap.values(): 15.112 + try: 15.113 + domid = int(domdb.id) 15.114 + except: 15.115 + domid = None 15.116 + # XXX if domid in self.domains, then something went wrong 15.117 + if (domid is None) or (domid in self.domains): 15.118 + domdb.delete() 15.119 + elif domid in doms: 15.120 try: 15.121 - self._new_domain(config, doms[domid]) 15.122 - self.update_domain(domid) 15.123 + self._new_domain(domdb, doms[domid]) 15.124 except Exception, ex: 15.125 - log.exception("Error recreating domain info: id=%s", domid) 15.126 + log.exception("Error recreating domain info: id=%d", domid) 15.127 self._delete_domain(domid) 15.128 else: 15.129 self._delete_domain(domid) 15.130 self.refresh(cleanup=True) 15.131 15.132 - def sync_domain(self, info): 15.133 - """Sync info for a domain to disk. 15.134 - 15.135 - info domain info 15.136 - """ 15.137 - self.db.save(info.id, info.sxpr()) 15.138 - 15.139 def close(self): 15.140 pass 15.141 15.142 - def _new_domain(self, savedinfo, info): 15.143 + def _new_domain(self, db, info): 15.144 """Create a domain entry from saved info. 15.145 15.146 - @param savedinfo: saved info from the db 15.147 - @param info: domain info from xen 15.148 + @param db: saved info from the db 15.149 + @param info: domain info from xen 15.150 @return: domain 15.151 """ 15.152 - dominfo = XendDomainInfo.vm_recreate(savedinfo, info) 15.153 + dominfo = XendDomainInfo.recreate(db, info) 15.154 self.domains[dominfo.id] = dominfo 15.155 return dominfo 15.156 15.157 @@ -144,11 +137,11 @@ class XendDomain: 15.158 for i, d in self.domains.items(): 15.159 if i != d.id: 15.160 del self.domains[i] 15.161 - self.db.delete(i) 15.162 + self.dbmap.delete(d.uuid) 15.163 if info.id in self.domains: 15.164 notify = False 15.165 self.domains[info.id] = info 15.166 - self.sync_domain(info) 15.167 + info.exportToDB(save=True) 15.168 if notify: 15.169 eserver.inject('xend.domain.create', [info.name, info.id]) 15.170 15.171 @@ -158,12 +151,26 @@ class XendDomain: 15.172 @param id: domain id 15.173 @param notify: send a domain died event if true 15.174 """ 15.175 + try: 15.176 + if self.xen_domain(id): 15.177 + return 15.178 + except: 15.179 + pass 15.180 info = self.domains.get(id) 15.181 if info: 15.182 del self.domains[id] 15.183 + info.cleanup() 15.184 + info.delete() 15.185 if notify: 15.186 eserver.inject('xend.domain.died', [info.name, info.id]) 15.187 - self.db.delete(id) 15.188 + # XXX this should not be needed 15.189 + for domdb in self.dbmap.values(): 15.190 + try: 15.191 + domid = int(domdb.id) 15.192 + except: 15.193 + domid = None 15.194 + if (domid is None) or (domid == id): 15.195 + domdb.delete() 15.196 15.197 def reap(self): 15.198 """Look for domains that have crashed or stopped. 15.199 @@ -178,22 +185,19 @@ class XendDomain: 15.200 not(d['running'] or d['paused'] or d['blocked'])) 15.201 if dead: 15.202 casualties.append(d) 15.203 - destroyed = 0 15.204 for d in casualties: 15.205 - id = str(d['dom']) 15.206 - #print 'reap>', id 15.207 + id = d['dom'] 15.208 dominfo = self.domains.get(id) 15.209 name = (dominfo and dominfo.name) or '??' 15.210 if dominfo and dominfo.is_terminated(): 15.211 - #print 'reap> already terminated:', id 15.212 continue 15.213 - log.debug('XendDomain>reap> domain died name=%s id=%s', name, id) 15.214 + log.debug('XendDomain>reap> domain died name=%s id=%d', name, id) 15.215 if d['shutdown']: 15.216 - reason = XendDomainInfo.shutdown_reason(d['shutdown_reason']) 15.217 - log.debug('XendDomain>reap> shutdown name=%s id=%s reason=%s', name, id, reason) 15.218 + reason = shutdown_reason(d['shutdown_reason']) 15.219 + log.debug('XendDomain>reap> shutdown name=%s id=%d reason=%s', name, id, reason) 15.220 if reason in ['suspend']: 15.221 if dominfo and dominfo.is_terminated(): 15.222 - log.debug('XendDomain>reap> Suspended domain died id=%s', id) 15.223 + log.debug('XendDomain>reap> Suspended domain died id=%d', id) 15.224 else: 15.225 eserver.inject('xend.domain.suspended', [name, id]) 15.226 if dominfo: 15.227 @@ -203,10 +207,9 @@ class XendDomain: 15.228 eserver.inject('xend.domain.exit', [name, id, reason]) 15.229 self.domain_restart_schedule(id, reason) 15.230 else: 15.231 - if xroot.get_enable_dump() == 'true': 15.232 - xc.domain_dumpcore(dom = int(id), corefile = "/var/xen/dump/%s.%s.core"%(name,id)) 15.233 + if xroot.get_enable_dump(): 15.234 + self.domain_dumpcore(id) 15.235 eserver.inject('xend.domain.exit', [name, id, 'crash']) 15.236 - destroyed += 1 15.237 self.final_domain_destroy(id) 15.238 15.239 def refresh(self, cleanup=False): 15.240 @@ -216,7 +219,7 @@ class XendDomain: 15.241 self.reap() 15.242 doms = self.xen_domains() 15.243 # Add entries for any domains we don't know about. 15.244 - for (id, d) in doms.items(): 15.245 + for id in doms.keys(): 15.246 if id not in self.domains: 15.247 self.domain_lookup(id) 15.248 # Remove entries for domains that no longer exist. 15.249 @@ -234,16 +237,7 @@ class XendDomain: 15.250 scheduler.now(self.domain_restarts) 15.251 15.252 def update_domain(self, id): 15.253 - """Update the saved info for a domain. 15.254 - 15.255 - @param id: domain id 15.256 - """ 15.257 - dominfo = self.domains.get(id) 15.258 - if dominfo: 15.259 - self.sync_domain(dominfo) 15.260 - 15.261 - def refresh_domain(self, id): 15.262 - """Refresh information for a single domain. 15.263 + """Update information for a single domain. 15.264 15.265 @param id: domain id 15.266 """ 15.267 @@ -279,8 +273,7 @@ class XendDomain: 15.268 @param config: configuration 15.269 @return: domain 15.270 """ 15.271 - dominfo = XendDomainInfo.vm_create(config) 15.272 - self._add_domain(dominfo) 15.273 + dominfo = XendDomainInfo.create(self.dbmap, config) 15.274 return dominfo 15.275 15.276 def domain_restart(self, dominfo): 15.277 @@ -293,7 +286,6 @@ class XendDomain: 15.278 [dominfo.name, dominfo.id, "begin"]) 15.279 try: 15.280 dominfo.restart() 15.281 - self._add_domain(dominfo) 15.282 log.info('Restarted domain name=%s id=%s', dominfo.name, dominfo.id) 15.283 eserver.inject("xend.domain.restart", 15.284 [dominfo.name, dominfo.id, "success"]) 15.285 @@ -309,14 +301,13 @@ class XendDomain: 15.286 """Configure an existing domain. This is intended for internal 15.287 use by domain restore and migrate. 15.288 15.289 - @param id: domain id 15.290 @param vmconfig: vm configuration 15.291 """ 15.292 config = sxp.child_value(vmconfig, 'config') 15.293 - dominfo = XendDomainInfo.vm_restore(config) 15.294 - self._add_domain(dominfo) 15.295 + uuid = sxp.child_value(vmconfig, 'uuid') 15.296 + dominfo = XendDomainInfo.restore(self.dbmap, config, uuid=uuid) 15.297 return dominfo 15.298 - 15.299 + 15.300 def domain_restore(self, src, progress=False): 15.301 """Restore a domain from file. 15.302 15.303 @@ -326,9 +317,7 @@ class XendDomain: 15.304 15.305 try: 15.306 fd = os.open(src, os.O_RDONLY) 15.307 - 15.308 return XendCheckpoint.restore(self, fd) 15.309 - 15.310 except OSError, ex: 15.311 raise XendError("can't read guest state file %s: %s" % 15.312 (src, ex[1])) 15.313 @@ -339,24 +328,35 @@ class XendDomain: 15.314 @param id: domain id 15.315 @return: domain object (or None) 15.316 """ 15.317 - id = str(id) 15.318 - self.refresh_domain(id) 15.319 + self.update_domain(id) 15.320 return self.domains.get(id) 15.321 15.322 - def domain_lookup(self, name): 15.323 - name = str(name) 15.324 - dominfo = self.domains.get_by_name(name) or self.domains.get(name) 15.325 - if dominfo: 15.326 - return dominfo 15.327 - try: 15.328 - d = self.xen_domain(name) 15.329 - if d: 15.330 - log.info("Creating entry for unknown domain: id=%s", name) 15.331 - dominfo = XendDomainInfo.vm_recreate(None, d) 15.332 - self._add_domain(dominfo) 15.333 - return dominfo 15.334 - except Exception, ex: 15.335 - log.exception("Error creating domain info: id=%s", name) 15.336 + def domain_lookup(self, id): 15.337 + dominfo = self.domains.get(id) 15.338 + if not dominfo: 15.339 + try: 15.340 + info = self.xen_domain(id) 15.341 + if info: 15.342 + uuid = getUuid() 15.343 + log.info( 15.344 + "Creating entry for unknown domain: id=%d uuid=%s", 15.345 + id, uuid) 15.346 + db = self.dbmap.addChild(uuid) 15.347 + dominfo = XendDomainInfo.recreate(db, info) 15.348 + self._add_domain(dominfo) 15.349 + except Exception, ex: 15.350 + log.exception("Error creating domain info: id=%d", id) 15.351 + return dominfo 15.352 + 15.353 + def domain_lookup_by_name(self, name): 15.354 + dominfo = self.domains.get_by_name(name) 15.355 + if not dominfo: 15.356 + try: 15.357 + id = int(name) 15.358 + dominfo = self.domain_lookup(id) 15.359 + except ValueError: 15.360 + pass 15.361 + return dominfo 15.362 15.363 def domain_unpause(self, id): 15.364 """Unpause domain execution. 15.365 @@ -366,7 +366,7 @@ class XendDomain: 15.366 dominfo = self.domain_lookup(id) 15.367 eserver.inject('xend.domain.unpause', [dominfo.name, dominfo.id]) 15.368 try: 15.369 - return xc.domain_unpause(dom=dominfo.dom) 15.370 + return xc.domain_unpause(dom=dominfo.id) 15.371 except Exception, ex: 15.372 raise XendError(str(ex)) 15.373 15.374 @@ -378,7 +378,7 @@ class XendDomain: 15.375 dominfo = self.domain_lookup(id) 15.376 eserver.inject('xend.domain.pause', [dominfo.name, dominfo.id]) 15.377 try: 15.378 - return xc.domain_pause(dom=dominfo.dom) 15.379 + return xc.domain_pause(dom=dominfo.id) 15.380 except Exception, ex: 15.381 raise XendError(str(ex)) 15.382 15.383 @@ -436,7 +436,7 @@ class XendDomain: 15.384 @param id: domain id 15.385 @param reason: shutdown reason 15.386 """ 15.387 - log.debug('domain_restart_schedule> %s %s %d', id, reason, force) 15.388 + log.debug('domain_restart_schedule> %d %s %d', id, reason, force) 15.389 dominfo = self.domain_lookup(id) 15.390 if not dominfo: 15.391 return 15.392 @@ -484,7 +484,7 @@ class XendDomain: 15.393 except: 15.394 #todo 15.395 try: 15.396 - val = xc.domain_destroy(dom=int(id)) 15.397 + val = xc.domain_destroy(dom=id) 15.398 except Exception, ex: 15.399 raise XendError(str(ex)) 15.400 return val 15.401 @@ -553,7 +553,7 @@ class XendDomain: 15.402 """ 15.403 dominfo = self.domain_lookup(id) 15.404 try: 15.405 - return xc.domain_pincpu(int(dominfo.id), vcpu, cpumap) 15.406 + return xc.domain_pincpu(dominfo.id, vcpu, cpumap) 15.407 except Exception, ex: 15.408 raise XendError(str(ex)) 15.409 15.410 @@ -562,7 +562,7 @@ class XendDomain: 15.411 """ 15.412 dominfo = self.domain_lookup(id) 15.413 try: 15.414 - return xc.bvtsched_domain_set(dom=dominfo.dom, mcuadv=mcuadv, 15.415 + return xc.bvtsched_domain_set(dom=dominfo.id, mcuadv=mcuadv, 15.416 warpback=warpback, warpvalue=warpvalue, 15.417 warpl=warpl, warpu=warpu) 15.418 except Exception, ex: 15.419 @@ -573,7 +573,7 @@ class XendDomain: 15.420 """ 15.421 dominfo = self.domain_lookup(id) 15.422 try: 15.423 - return xc.bvtsched_domain_get(dominfo.dom) 15.424 + return xc.bvtsched_domain_get(dominfo.id) 15.425 except Exception, ex: 15.426 raise XendError(str(ex)) 15.427 15.428 @@ -581,20 +581,21 @@ class XendDomain: 15.429 def domain_cpu_sedf_set(self, id, period, slice, latency, extratime, weight): 15.430 """Set Simple EDF scheduler parameters for a domain. 15.431 """ 15.432 - dominfo = self.domain_lookup(id) 15.433 + dominfo = self.domain_lookup(id) 15.434 try: 15.435 - return xc.sedf_domain_set(dominfo.dom, period, slice, latency, extratime, weight) 15.436 + return xc.sedf_domain_set(dominfo.id, period, slice, latency, extratime, weight) 15.437 except Exception, ex: 15.438 raise XendError(str(ex)) 15.439 15.440 def domain_cpu_sedf_get(self, id): 15.441 - """Get Atropos scheduler parameters for a domain. 15.442 + """Get Simple EDF scheduler parameters for a domain. 15.443 """ 15.444 dominfo = self.domain_lookup(id) 15.445 try: 15.446 - return xc.sedf_domain_get(dominfo.dom) 15.447 + return xc.sedf_domain_get(dominfo.id) 15.448 except Exception, ex: 15.449 raise XendError(str(ex)) 15.450 + 15.451 def domain_device_create(self, id, devconfig): 15.452 """Create a new device for a domain. 15.453 15.454 @@ -603,44 +604,44 @@ class XendDomain: 15.455 """ 15.456 dominfo = self.domain_lookup(id) 15.457 val = dominfo.device_create(devconfig) 15.458 - self.update_domain(dominfo.id) 15.459 + dominfo.exportToDB() 15.460 return val 15.461 15.462 - def domain_device_configure(self, id, devconfig, idx): 15.463 + def domain_device_configure(self, id, devconfig, devid): 15.464 """Configure an existing device for a domain. 15.465 15.466 @param id: domain id 15.467 @param devconfig: device configuration 15.468 - @param idx: device index 15.469 + @param devid: device id 15.470 @return: updated device configuration 15.471 """ 15.472 dominfo = self.domain_lookup(id) 15.473 - val = dominfo.device_configure(devconfig, idx) 15.474 - self.update_domain(dominfo.id) 15.475 + val = dominfo.device_configure(devconfig, devid) 15.476 + dominfo.exportToDB() 15.477 return val 15.478 15.479 - def domain_device_refresh(self, id, type, idx): 15.480 + def domain_device_refresh(self, id, type, devid): 15.481 """Refresh a device. 15.482 15.483 @param id: domain id 15.484 - @param idx: device index 15.485 + @param devid: device id 15.486 @param type: device type 15.487 """ 15.488 dominfo = self.domain_lookup(id) 15.489 - val = dominfo.device_refresh(type, idx) 15.490 - self.update_domain(dominfo.id) 15.491 + val = dominfo.device_refresh(type, devid) 15.492 + dominfo.exportToDB() 15.493 return val 15.494 15.495 - def domain_device_destroy(self, id, type, idx): 15.496 + def domain_device_destroy(self, id, type, devid): 15.497 """Destroy a device. 15.498 15.499 @param id: domain id 15.500 - @param idx: device index 15.501 + @param devid: device id 15.502 @param type: device type 15.503 """ 15.504 dominfo = self.domain_lookup(id) 15.505 - val = dominfo.device_destroy(type, idx) 15.506 - self.update_domain(dominfo.id) 15.507 + val = dominfo.device_destroy(type, devid) 15.508 + dominfo.exportToDB() 15.509 return val 15.510 15.511 def domain_devtype_ls(self, id, type): 15.512 @@ -653,22 +654,22 @@ class XendDomain: 15.513 dominfo = self.domain_lookup(id) 15.514 return dominfo.getDeviceSxprs(type) 15.515 15.516 - def domain_devtype_get(self, id, type, idx): 15.517 + def domain_devtype_get(self, id, type, devid): 15.518 """Get a device from a domain. 15.519 - 15.520 + 15.521 @param id: domain 15.522 @param type: device type 15.523 - @param idx: device index 15.524 + @param devid: device id 15.525 @return: device object (or None) 15.526 """ 15.527 dominfo = self.domain_lookup(id) 15.528 - return dominfo.getDeviceByIndex(type, idx) 15.529 + return dominfo.getDevice(type, devid) 15.530 15.531 def domain_vif_limit_set(self, id, vif, credit, period): 15.532 """Limit the vif's transmission rate 15.533 """ 15.534 dominfo = self.domain_lookup(id) 15.535 - dev = dominfo.getDeviceById('vif', vif) 15.536 + dev = dominfo.getDevice('vif', vif) 15.537 if not dev: 15.538 raise XendError("invalid vif") 15.539 return dev.setCreditLimit(credit, period) 15.540 @@ -681,30 +682,47 @@ class XendDomain: 15.541 """ 15.542 dominfo = self.domain_lookup(id) 15.543 try: 15.544 - return xc.shadow_control(dominfo.dom, op) 15.545 + return xc.shadow_control(dominfo.id, op) 15.546 except Exception, ex: 15.547 raise XendError(str(ex)) 15.548 15.549 def domain_maxmem_set(self, id, mem): 15.550 """Set the memory limit for a domain. 15.551 15.552 - @param dom: domain 15.553 + @param id: domain 15.554 @param mem: memory limit (in MB) 15.555 @return: 0 on success, -1 on error 15.556 """ 15.557 dominfo = self.domain_lookup(id) 15.558 maxmem = int(mem) * 1024 15.559 try: 15.560 - return xc.domain_setmaxmem(dominfo.dom, maxmem_kb = maxmem) 15.561 + return xc.domain_setmaxmem(dominfo.id, maxmem_kb = maxmem) 15.562 except Exception, ex: 15.563 raise XendError(str(ex)) 15.564 15.565 - def domain_mem_target_set(self, id, target): 15.566 + def domain_mem_target_set(self, id, mem): 15.567 + """Set the memory target for a domain. 15.568 + 15.569 + @param id: domain 15.570 + @param mem: memory target (in MB) 15.571 + @return: 0 on success, -1 on error 15.572 + """ 15.573 dominfo = self.domain_lookup(id) 15.574 - return dominfo.mem_target_set(target) 15.575 + return dominfo.mem_target_set(mem) 15.576 + 15.577 + def domain_dumpcore(self, id): 15.578 + """Save a core dump for a crashed domain. 15.579 + 15.580 + @param id: domain 15.581 + """ 15.582 + dominfo = self.domain_lookup(id) 15.583 + corefile = "/var/xen/dump/%s.%s.core"% (dominfo.name, dominfo.id) 15.584 + try: 15.585 + xc.domain_dumpcore(dom=dominfo.id, corefile=corefile) 15.586 + except Exception, ex: 15.587 + log.warning("Dumpcore failed, id=%s name=%s: %s", 15.588 + dominfo.id, dominfo.name, ex) 15.589 15.590 - 15.591 - 15.592 def instance(): 15.593 """Singleton constructor. Use this instead of the class constructor. 15.594 """
16.1 --- a/tools/python/xen/xend/XendDomainInfo.py Thu Jun 09 14:07:02 2005 +0000 16.2 +++ b/tools/python/xen/xend/XendDomainInfo.py Thu Jun 09 14:40:39 2005 +0000 16.3 @@ -14,21 +14,23 @@ import time 16.4 import threading 16.5 16.6 import xen.lowlevel.xc; xc = xen.lowlevel.xc.new() 16.7 -import xen.util.ip 16.8 -from xen.xend.server import channel, controller 16.9 +from xen.util.ip import check_subnet, get_current_ipgw 16.10 from xen.util.blkif import blkdev_uname_to_file 16.11 16.12 -from server.channel import channelFactory 16.13 -import server.SrvDaemon; xend = server.SrvDaemon.instance() 16.14 -from server import messages 16.15 +from xen.xend.server import controller 16.16 +from xen.xend.server import SrvDaemon; xend = SrvDaemon.instance() 16.17 +from xen.xend.server import messages 16.18 +from xen.xend.server.channel import EventChannel, channelFactory 16.19 16.20 +from xen.xend import sxp 16.21 +from xen.xend.PrettyPrint import prettyprintstring 16.22 from xen.xend.XendBootloader import bootloader 16.23 -import sxp 16.24 -from XendLogging import log 16.25 +from xen.xend.XendLogging import log 16.26 from XendError import XendError, VmError 16.27 -from XendRoot import get_component 16.28 +from xen.xend.XendRoot import get_component 16.29 16.30 -from PrettyPrint import prettyprintstring 16.31 +from xen.xend.uuid import getUuid 16.32 +from xen.xend.xenstore import DBVar 16.33 16.34 """Flag for a block device backend domain.""" 16.35 SIF_BLK_BE_DOMAIN = (1<<4) 16.36 @@ -45,11 +47,16 @@ DOMAIN_REBOOT = 1 16.37 """Shutdown code for suspend.""" 16.38 DOMAIN_SUSPEND = 2 16.39 16.40 +"""Shutdown code for crash.""" 16.41 +DOMAIN_CRASH = 3 16.42 + 16.43 """Map shutdown codes to strings.""" 16.44 shutdown_reasons = { 16.45 DOMAIN_POWEROFF: "poweroff", 16.46 DOMAIN_REBOOT : "reboot", 16.47 - DOMAIN_SUSPEND : "suspend" } 16.48 + DOMAIN_SUSPEND : "suspend", 16.49 + DOMAIN_CRASH : "crash", 16.50 + } 16.51 16.52 """Map shutdown reasons to the message type to use. 16.53 """ 16.54 @@ -81,7 +88,7 @@ STATE_VM_SUSPENDED = "suspended" 16.55 def domain_exists(name): 16.56 # See comment in XendDomain constructor. 16.57 xd = get_component('xen.xend.XendDomain') 16.58 - return xd.domain_lookup(name) 16.59 + return xd.domain_lookup_by_name(name) 16.60 16.61 def shutdown_reason(code): 16.62 """Get a shutdown reason from a code. 16.63 @@ -110,25 +117,6 @@ def get_config_handler(name): 16.64 """ 16.65 return config_handlers.get(name) 16.66 16.67 -"""Table of handlers for virtual machine images. 16.68 -Indexed by image type. 16.69 -""" 16.70 -image_handlers = {} 16.71 - 16.72 -def add_image_handler(name, h): 16.73 - """Add a handler for an image type 16.74 - @param name: image type 16.75 - @param h: handler: fn(config, name, memory, image) 16.76 - """ 16.77 - image_handlers[name] = h 16.78 - 16.79 -def get_image_handler(name): 16.80 - """Get the handler for an image type. 16.81 - @param name: image type 16.82 - @return: handler or None 16.83 - """ 16.84 - return image_handlers.get(name) 16.85 - 16.86 """Table of handlers for devices. 16.87 Indexed by device type. 16.88 """ 16.89 @@ -139,61 +127,6 @@ def add_device_handler(name, type): 16.90 16.91 def get_device_handler(name): 16.92 return device_handlers[name] 16.93 - 16.94 - 16.95 -def vm_create(config): 16.96 - """Create a VM from a configuration. 16.97 - If a vm has been partially created and there is an error it 16.98 - is destroyed. 16.99 - 16.100 - @param config configuration 16.101 - @raise: VmError for invalid configuration 16.102 - """ 16.103 - vm = XendDomainInfo() 16.104 - vm.construct(config) 16.105 - return vm 16.106 - 16.107 -def vm_restore(config): 16.108 - """Create a domain and a VM object to do a restore. 16.109 - 16.110 - @param config: domain configuration 16.111 - """ 16.112 - vm = XendDomainInfo() 16.113 - dom = xc.domain_create() 16.114 - vm.dom_construct(dom, config) 16.115 - return vm 16.116 - 16.117 -def vm_recreate(savedinfo, info): 16.118 - """Create the VM object for an existing domain. 16.119 - 16.120 - @param savedinfo: saved info from the domain DB 16.121 - @type savedinfo: sxpr 16.122 - @param info: domain info from xc 16.123 - @type info: xc domain dict 16.124 - """ 16.125 - log.debug('savedinfo=' + prettyprintstring(savedinfo)) 16.126 - log.debug('info=' + str(info)) 16.127 - vm = XendDomainInfo() 16.128 - vm.recreate = True 16.129 - vm.savedinfo = savedinfo 16.130 - vm.setdom(info['dom']) 16.131 - vm.memory = info['mem_kb']/1024 16.132 - start_time = sxp.child_value(savedinfo, 'start_time') 16.133 - if start_time is not None: 16.134 - vm.start_time = float(start_time) 16.135 - vm.restart_state = sxp.child_value(savedinfo, 'restart_state') 16.136 - vm.restart_count = int(sxp.child_value(savedinfo, 'restart_count', 0)) 16.137 - restart_time = sxp.child_value(savedinfo, 'restart_time') 16.138 - if restart_time is not None: 16.139 - vm.restart_time = float(restart_time) 16.140 - config = sxp.child_value(savedinfo, 'config') 16.141 - if config: 16.142 - vm.construct(config) 16.143 - else: 16.144 - vm.name = sxp.child_value(savedinfo, 'name', "Domain-%d" % info['dom']) 16.145 - vm.recreate = False 16.146 - vm.savedinfo = None 16.147 - return vm 16.148 16.149 def dom_get(dom): 16.150 """Get info from xen for an existing domain. 16.151 @@ -213,25 +146,104 @@ class XendDomainInfo: 16.152 """ 16.153 MINIMUM_RESTART_TIME = 20 16.154 16.155 - def __init__(self): 16.156 + def create(cls, parentdb, config): 16.157 + """Create a VM from a configuration. 16.158 + 16.159 + @param parentdb: parent db 16.160 + @param config configuration 16.161 + @raise: VmError for invalid configuration 16.162 + """ 16.163 + uuid = getUuid() 16.164 + db = parentdb.addChild(uuid) 16.165 + vm = cls(db) 16.166 + vm.construct(config) 16.167 + vm.saveDB(sync=True) 16.168 + return vm 16.169 + 16.170 + create = classmethod(create) 16.171 + 16.172 + def recreate(cls, db, info): 16.173 + """Create the VM object for an existing domain. 16.174 + 16.175 + @param db: domain db 16.176 + @param info: domain info from xc 16.177 + """ 16.178 + dom = info['dom'] 16.179 + vm = cls(db) 16.180 + db.readDB() 16.181 + vm.importFromDB() 16.182 + config = vm.config 16.183 + log.debug('info=' + str(info)) 16.184 + log.debug('config=' + prettyprintstring(config)) 16.185 + 16.186 + vm.setdom(dom) 16.187 + vm.memory = info['mem_kb']/1024 16.188 + 16.189 + if config: 16.190 + try: 16.191 + vm.recreate = True 16.192 + vm.construct(config) 16.193 + finally: 16.194 + vm.recreate = False 16.195 + else: 16.196 + vm.setName("Domain-%d" % dom) 16.197 + 16.198 + vm.exportToDB(save=True) 16.199 + return vm 16.200 + 16.201 + recreate = classmethod(recreate) 16.202 + 16.203 + def restore(cls, parentdb, config, uuid=None): 16.204 + """Create a domain and a VM object to do a restore. 16.205 + 16.206 + @param parentdb: parent db 16.207 + @param config: domain configuration 16.208 + @param uuid: uuid to use 16.209 + """ 16.210 + db = parentdb.addChild(uuid) 16.211 + vm = cls(db) 16.212 + dom = xc.domain_create() 16.213 + vm.setdom(dom) 16.214 + vm.dom_construct(vm.id, config) 16.215 + vm.saveDB(sync=True) 16.216 + return vm 16.217 + 16.218 + restore = classmethod(restore) 16.219 + 16.220 + __exports__ = [ 16.221 + DBVar('id', ty='str'), 16.222 + DBVar('name', ty='str'), 16.223 + DBVar('uuid', ty='str'), 16.224 + DBVar('config', ty='sxpr'), 16.225 + DBVar('start_time', ty='float'), 16.226 + DBVar('state', ty='str'), 16.227 + DBVar('store_mfn', ty='long'), 16.228 + DBVar('restart_mode', ty='str'), 16.229 + DBVar('restart_state', ty='str'), 16.230 + DBVar('restart_time', ty='float'), 16.231 + DBVar('restart_count', ty='int'), 16.232 + ] 16.233 + 16.234 + def __init__(self, db): 16.235 + self.db = db 16.236 + self.uuid = db.getName() 16.237 + 16.238 self.recreate = 0 16.239 self.restore = 0 16.240 + 16.241 self.config = None 16.242 self.id = None 16.243 - self.dom = None 16.244 self.cpu_weight = 1 16.245 self.start_time = None 16.246 self.name = None 16.247 self.memory = None 16.248 self.image = None 16.249 - self.ramdisk = None 16.250 - self.cmdline = None 16.251 16.252 self.channel = None 16.253 + self.store_channel = None 16.254 + self.store_mfn = None 16.255 self.controllers = {} 16.256 16.257 - self.configs = [] 16.258 - 16.259 self.info = None 16.260 self.blkif_backend = False 16.261 self.netif_backend = False 16.262 @@ -249,22 +261,39 @@ class XendDomainInfo: 16.263 self.restart_count = 0 16.264 16.265 self.console_port = None 16.266 - self.savedinfo = None 16.267 - self.image_handler = None 16.268 - self.is_vmx = False 16.269 self.vcpus = 1 16.270 self.bootloader = None 16.271 16.272 + def setDB(self, db): 16.273 + self.db = db 16.274 + 16.275 + def saveDB(self, save=False, sync=False): 16.276 + self.db.saveDB(save=save, sync=sync) 16.277 + 16.278 + def exportToDB(self, save=False, sync=False): 16.279 + if self.channel: 16.280 + self.channel.saveToDB(self.db.addChild("channel")) 16.281 + if self.store_channel: 16.282 + self.store_channel.saveToDB(self.db.addChild("store_channel")) 16.283 + self.db.exportToDB(self, fields=self.__exports__, save=save, sync=sync) 16.284 + 16.285 + def importFromDB(self): 16.286 + self.db.importFromDB(self, fields=self.__exports__) 16.287 + 16.288 def setdom(self, dom): 16.289 """Set the domain id. 16.290 16.291 @param dom: domain id 16.292 """ 16.293 - self.dom = int(dom) 16.294 - self.id = str(dom) 16.295 + self.id = int(dom) 16.296 + #self.db.id = self.id 16.297 16.298 def getDomain(self): 16.299 - return self.dom 16.300 + return self.id 16.301 + 16.302 + def setName(self, name): 16.303 + self.name = name 16.304 + self.db.name = self.name 16.305 16.306 def getName(self): 16.307 return self.name 16.308 @@ -272,6 +301,9 @@ class XendDomainInfo: 16.309 def getChannel(self): 16.310 return self.channel 16.311 16.312 + def getStoreChannel(self): 16.313 + return self.store_channel 16.314 + 16.315 def update(self, info): 16.316 """Update with info from xc.domain_getinfo(). 16.317 """ 16.318 @@ -284,6 +316,7 @@ class XendDomainInfo: 16.319 self.state = state 16.320 self.state_updated.notifyAll() 16.321 self.state_updated.release() 16.322 + self.saveDB() 16.323 16.324 def state_wait(self, state): 16.325 self.state_updated.acquire() 16.326 @@ -293,14 +326,12 @@ class XendDomainInfo: 16.327 16.328 def __str__(self): 16.329 s = "domain" 16.330 - s += " id=" + self.id 16.331 + s += " id=" + str(self.id) 16.332 s += " name=" + self.name 16.333 s += " memory=" + str(self.memory) 16.334 console = self.getConsole() 16.335 if console: 16.336 s += " console=" + str(console.console_port) 16.337 - if self.image: 16.338 - s += " image=" + self.image 16.339 s += "" 16.340 return s 16.341 16.342 @@ -327,9 +358,10 @@ class XendDomainInfo: 16.343 self.controllers[type] = ctrl 16.344 return ctrl 16.345 16.346 - def createDevice(self, type, devconfig, recreate=False): 16.347 + def createDevice(self, type, devconfig, change=False): 16.348 ctrl = self.findDeviceController(type) 16.349 - return ctrl.createDevice(devconfig, recreate=self.recreate) 16.350 + return ctrl.createDevice(devconfig, recreate=self.recreate, 16.351 + change=change) 16.352 16.353 def configureDevice(self, type, id, devconfig): 16.354 ctrl = self.getDeviceController(type) 16.355 @@ -343,30 +375,14 @@ class XendDomainInfo: 16.356 ctrl = self.getDeviceController(type) 16.357 return ctrl.deleteDevice(id) 16.358 16.359 - def getDevice(self, type, id): 16.360 - ctrl = self.getDeviceController(type) 16.361 - return ctrl.getDevice(id) 16.362 - 16.363 - def getDeviceByIndex(self, type, idx): 16.364 + def getDevice(self, type, id, error=True): 16.365 ctrl = self.getDeviceController(type) 16.366 - return ctrl.getDeviceByIndex(idx) 16.367 - 16.368 - def getDeviceConfig(self, type, id): 16.369 - ctrl = self.getDeviceController(type) 16.370 - return ctrl.getDeviceConfig(id) 16.371 - 16.372 + return ctrl.getDevice(id, error=error) 16.373 + 16.374 def getDeviceIds(self, type): 16.375 ctrl = self.getDeviceController(type) 16.376 return ctrl.getDeviceIds() 16.377 16.378 - def getDeviceIndexes(self, type): 16.379 - ctrl = self.getDeviceController(type) 16.380 - return ctrl.getDeviceIndexes() 16.381 - 16.382 - def getDeviceConfigs(self, type): 16.383 - ctrl = self.getDeviceController(type) 16.384 - return ctrl.getDeviceConfigs() 16.385 - 16.386 def getDeviceSxprs(self, type): 16.387 ctrl = self.getDeviceController(type) 16.388 return ctrl.getDeviceSxprs() 16.389 @@ -376,7 +392,8 @@ class XendDomainInfo: 16.390 ['id', self.id], 16.391 ['name', self.name], 16.392 ['memory', self.memory] ] 16.393 - 16.394 + if self.uuid: 16.395 + sxpr.append(['uuid', self.uuid]) 16.396 if self.info: 16.397 sxpr.append(['maxmem', self.info['maxmem_kb']/1024 ]) 16.398 run = (self.info['running'] and 'r') or '-' 16.399 @@ -403,6 +420,8 @@ class XendDomainInfo: 16.400 16.401 if self.channel: 16.402 sxpr.append(self.channel.sxpr()) 16.403 + if self.store_channel: 16.404 + sxpr.append(self.store_channel.sxpr()) 16.405 console = self.getConsole() 16.406 if console: 16.407 sxpr.append(console.sxpr()) 16.408 @@ -454,7 +473,7 @@ class XendDomainInfo: 16.409 return 16.410 if dominfo.is_terminated(): 16.411 return 16.412 - if not self.dom or (dominfo.dom != self.dom): 16.413 + if not self.id or (dominfo.id != self.id): 16.414 raise VmError('vm name clash: ' + name) 16.415 16.416 def construct(self, config): 16.417 @@ -467,10 +486,10 @@ class XendDomainInfo: 16.418 self.config = config 16.419 try: 16.420 # Initial domain create. 16.421 - self.name = sxp.child_value(config, 'name') 16.422 + self.setName(sxp.child_value(config, 'name')) 16.423 self.check_name(self.name) 16.424 + self.init_image() 16.425 self.configure_cpus(config) 16.426 - self.find_image_handler() 16.427 self.init_domain() 16.428 self.register_domain() 16.429 self.configure_bootloader() 16.430 @@ -481,6 +500,7 @@ class XendDomainInfo: 16.431 self.configure_restart() 16.432 self.construct_image() 16.433 self.configure() 16.434 + self.exportToDB() 16.435 except Exception, ex: 16.436 # Catch errors, cleanup and re-raise. 16.437 print 'Domain construction error:', ex 16.438 @@ -492,6 +512,7 @@ class XendDomainInfo: 16.439 def register_domain(self): 16.440 xd = get_component('xen.xend.XendDomain') 16.441 xd._add_domain(self) 16.442 + self.exportToDB() 16.443 16.444 def configure_cpus(self, config): 16.445 try: 16.446 @@ -502,8 +523,8 @@ class XendDomainInfo: 16.447 if self.memory is None: 16.448 raise VmError('missing memory size') 16.449 cpu = sxp.child_value(config, 'cpu') 16.450 - if self.recreate and self.dom and cpu is not None and int(cpu) >= 0: 16.451 - xc.domain_pincpu(self.dom, 0, 1<<int(cpu)) 16.452 + if self.recreate and self.id and cpu is not None and int(cpu) >= 0: 16.453 + xc.domain_pincpu(self.id, 0, 1<<int(cpu)) 16.454 try: 16.455 image = sxp.child_value(self.config, 'image') 16.456 vcpus = sxp.child_value(image, 'vcpus') 16.457 @@ -512,89 +533,50 @@ class XendDomainInfo: 16.458 except: 16.459 raise VmError('invalid vcpus value') 16.460 16.461 - def find_image_handler(self): 16.462 - """Construct the boot image for the domain. 16.463 - 16.464 - @return vm 16.465 + def init_image(self): 16.466 + """Create boot image handler for the domain. 16.467 """ 16.468 image = sxp.child_value(self.config, 'image') 16.469 if image is None: 16.470 raise VmError('missing image') 16.471 - image_name = sxp.name(image) 16.472 - if image_name is None: 16.473 - raise VmError('missing image name') 16.474 - if image_name == "vmx": 16.475 - self.is_vmx = True 16.476 - image_handler = get_image_handler(image_name) 16.477 - if image_handler is None: 16.478 - raise VmError('unknown image type: ' + image_name) 16.479 - self.image_handler = image_handler 16.480 - return self 16.481 + self.image = ImageHandler.create(self, image) 16.482 16.483 def construct_image(self): 16.484 - image = sxp.child_value(self.config, 'image') 16.485 - self.image_handler(self, image) 16.486 - return self 16.487 - 16.488 - def config_devices(self, name): 16.489 - """Get a list of the 'device' nodes of a given type from the config. 16.490 - 16.491 - @param name: device type 16.492 - @type name: string 16.493 - @return: device configs 16.494 - @rtype: list 16.495 + """Construct the boot image for the domain. 16.496 """ 16.497 - devices = [] 16.498 - for d in sxp.children(self.config, 'device'): 16.499 - dev = sxp.child0(d) 16.500 - if dev is None: continue 16.501 - if name == sxp.name(dev): 16.502 - devices.append(dev) 16.503 - return devices 16.504 + self.create_channel() 16.505 + self.image.createImage() 16.506 + self.image.exportToDB() 16.507 + #if self.store_channel: 16.508 + # self.db.introduceDomain(self.id, 16.509 + # self.store_mfn, 16.510 + # self.store_channel) 16.511 16.512 - def get_device_savedinfo(self, type, index): 16.513 - val = None 16.514 - if self.savedinfo is None: 16.515 - return val 16.516 - devices = sxp.child(self.savedinfo, 'devices') 16.517 - if devices is None: 16.518 - return val 16.519 - index = str(index) 16.520 - for d in sxp.children(devices, type): 16.521 - dindex = sxp.child_value(d, 'index') 16.522 - if dindex is None: continue 16.523 - if str(dindex) == index: 16.524 - val = d 16.525 - break 16.526 - return val 16.527 - 16.528 - def get_device_recreate(self, type, index): 16.529 - return self.get_device_savedinfo(type, index) or self.recreate 16.530 - 16.531 - def add_config(self, val): 16.532 - """Add configuration data to a virtual machine. 16.533 - 16.534 - @param val: data to add 16.535 + def delete(self): 16.536 + """Delete the vm's db. 16.537 """ 16.538 - self.configs.append(val) 16.539 - 16.540 - def destroy(self): 16.541 - """Completely destroy the vm. 16.542 - """ 16.543 - self.cleanup() 16.544 - return self.destroy_domain() 16.545 + if self.dom_get(self.id): 16.546 + return 16.547 + self.id = None 16.548 + self.saveDB(sync=True) 16.549 + try: 16.550 + # Todo: eventually will have to wait for devices to signal 16.551 + # destruction before can delete the db. 16.552 + if self.db: 16.553 + self.db.delete() 16.554 + except Exception, ex: 16.555 + log.warning("error in domain db delete: %s", ex) 16.556 + pass 16.557 16.558 def destroy_domain(self): 16.559 """Destroy the vm's domain. 16.560 The domain will not finally go away unless all vm 16.561 devices have been released. 16.562 """ 16.563 - if self.channel: 16.564 - self.channel.close() 16.565 - self.channel = None 16.566 - if self.dom is None: return 0 16.567 + if self.id is None: 16.568 + return 16.569 try: 16.570 - return xc.domain_destroy(dom=self.dom) 16.571 + xc.domain_destroy(dom=self.id) 16.572 except Exception, err: 16.573 log.exception("Domain destroy failed: %s", self.name) 16.574 16.575 @@ -603,6 +585,37 @@ class XendDomainInfo: 16.576 """ 16.577 self.state = STATE_VM_TERMINATED 16.578 self.release_devices() 16.579 + if self.channel: 16.580 + try: 16.581 + self.channel.close() 16.582 + self.channel = None 16.583 + except: 16.584 + pass 16.585 + if self.store_channel: 16.586 + try: 16.587 + self.store_channel.close() 16.588 + self.store_channel = None 16.589 + except: 16.590 + pass 16.591 + #try: 16.592 + # self.db.releaseDomain(self.id) 16.593 + #except Exception, ex: 16.594 + # log.warning("error in domain release on xenstore: %s", ex) 16.595 + # pass 16.596 + if self.image: 16.597 + try: 16.598 + self.image.destroy() 16.599 + self.image = None 16.600 + except: 16.601 + pass 16.602 + 16.603 + def destroy(self): 16.604 + """Clenup vm and destroy domain. 16.605 + """ 16.606 + self.cleanup() 16.607 + self.destroy_domain() 16.608 + self.saveDB() 16.609 + return 0 16.610 16.611 def is_terminated(self): 16.612 """Check if a domain has been terminated. 16.613 @@ -616,20 +629,13 @@ class XendDomainInfo: 16.614 for ctrl in self.getDeviceControllers(): 16.615 if ctrl.isDestroyed(): continue 16.616 ctrl.destroyController(reboot=reboot) 16.617 - if not reboot: 16.618 - self.configs = [] 16.619 16.620 def show(self): 16.621 """Print virtual machine info. 16.622 """ 16.623 - print "[VM dom=%d name=%s memory=%d" % (self.dom, self.name, self.memory) 16.624 + print "[VM dom=%d name=%s memory=%d" % (self.id, self.name, self.memory) 16.625 print "image:" 16.626 sxp.show(self.image) 16.627 - print 16.628 - for val in self.configs: 16.629 - print "config:" 16.630 - sxp.show(val) 16.631 - print 16.632 print "]" 16.633 16.634 def init_domain(self): 16.635 @@ -639,107 +645,42 @@ class XendDomainInfo: 16.636 return 16.637 if self.start_time is None: 16.638 self.start_time = time.time() 16.639 - if self.restore: 16.640 - return 16.641 - dom = self.dom or 0 16.642 - memory = self.memory 16.643 try: 16.644 cpu = int(sxp.child_value(self.config, 'cpu', '-1')) 16.645 except: 16.646 raise VmError('invalid cpu') 16.647 - cpu_weight = self.cpu_weight 16.648 - memory = memory * 1024 + self.pgtable_size(memory) 16.649 - dom = xc.domain_create(dom= dom) 16.650 - if self.bootloader: 16.651 - try: 16.652 - if kernel: os.unlink(kernel) 16.653 - if ramdisk: os.unlink(ramdisk) 16.654 - except OSError, e: 16.655 - log.warning('unable to unlink kernel/ramdisk: %s' %(e,)) 16.656 + dom = self.image.initDomain(self.id, self.memory, cpu, self.cpu_weight) 16.657 + log.debug('init_domain> Created domain=%d name=%s memory=%d', 16.658 + dom, self.name, self.memory) 16.659 + if not self.restore: 16.660 + self.setdom(dom) 16.661 16.662 - if dom <= 0: 16.663 - raise VmError('Creating domain failed: name=%s memory=%d' 16.664 - % (self.name, memory)) 16.665 - xc.domain_setcpuweight(dom, cpu_weight) 16.666 - xc.domain_setmaxmem(dom, memory) 16.667 - xc.domain_memory_increase_reservation(dom, memory) 16.668 - if cpu != -1: 16.669 - xc.domain_pincpu(dom, 0, 1<<int(cpu)) 16.670 - log.debug('init_domain> Created domain=%d name=%s memory=%d', dom, self.name, memory) 16.671 - self.setdom(dom) 16.672 - 16.673 - def build_domain(self, ostype, kernel, ramdisk, cmdline, memmap): 16.674 - """Build the domain boot image. 16.675 + def openChannel(self, key, local, remote): 16.676 + """Create a channel to the domain. 16.677 + If saved info is available recreate the channel. 16.678 + 16.679 + @param key db key for the saved data (if any) 16.680 + @param local default local port 16.681 + @param remote default remote port 16.682 """ 16.683 - if self.recreate or self.restore: return 16.684 - if not os.path.isfile(kernel): 16.685 - raise VmError('Kernel image does not exist: %s' % kernel) 16.686 - if ramdisk and not os.path.isfile(ramdisk): 16.687 - raise VmError('Kernel ramdisk does not exist: %s' % ramdisk) 16.688 - if len(cmdline) >= 256: 16.689 - log.warning('kernel cmdline too long, domain %d', self.dom) 16.690 - dom = self.dom 16.691 - buildfn = getattr(xc, '%s_build' % ostype) 16.692 - flags = 0 16.693 - if self.netif_backend: flags |= SIF_NET_BE_DOMAIN 16.694 - if self.blkif_backend: flags |= SIF_BLK_BE_DOMAIN 16.695 - #todo generalise this 16.696 - if ostype == "vmx": 16.697 - log.debug('building vmx domain') 16.698 - err = buildfn(dom = dom, 16.699 - image = kernel, 16.700 - control_evtchn = 0, 16.701 - memsize = self.memory, 16.702 - memmap = memmap, 16.703 - cmdline = cmdline, 16.704 - ramdisk = ramdisk, 16.705 - flags = flags) 16.706 - else: 16.707 - log.debug('building dom with %d vcpus', self.vcpus) 16.708 - err = buildfn(dom = dom, 16.709 - image = kernel, 16.710 - control_evtchn = self.channel.getRemotePort(), 16.711 - cmdline = cmdline, 16.712 - ramdisk = ramdisk, 16.713 - flags = flags, 16.714 - vcpus = self.vcpus) 16.715 - if err != 0: 16.716 - raise VmError('Building domain failed: type=%s dom=%d err=%d' 16.717 - % (ostype, dom, err)) 16.718 - 16.719 - def create_domain(self, ostype, kernel, ramdisk, cmdline, memmap=''): 16.720 - """Create a domain. Builds the image but does not configure it. 16.721 + db = self.db.addChild(key) 16.722 + chan = channelFactory().restoreFromDB(db, self.id, local, remote) 16.723 + #todo: save here? 16.724 + #chan.saveToDB(db) 16.725 + return chan 16.726 16.727 - @param ostype: OS type 16.728 - @param kernel: kernel image 16.729 - @param ramdisk: kernel ramdisk 16.730 - @param cmdline: kernel commandline 16.731 - """ 16.732 - 16.733 - self.create_channel() 16.734 - self.build_domain(ostype, kernel, ramdisk, cmdline, memmap) 16.735 - self.image = kernel 16.736 - self.ramdisk = ramdisk 16.737 - self.cmdline = cmdline 16.738 - 16.739 + def eventChannel(self, key): 16.740 + db = self.db.addChild(key) 16.741 + return EventChannel.restoreFromDB(db, 0, self.id) 16.742 + 16.743 def create_channel(self): 16.744 - """Create the control channel to the domain. 16.745 - If saved info is available recreate the channel using the saved ports. 16.746 + """Create the channels to the domain. 16.747 """ 16.748 - local = 0 16.749 - remote = 1 16.750 - if self.savedinfo: 16.751 - info = sxp.child(self.savedinfo, "channel") 16.752 - if info: 16.753 - local = int(sxp.child_value(info, "local_port", 0)) 16.754 - remote = int(sxp.child_value(info, "remote_port", 1)) 16.755 - self.channel = channelFactory().openChannel(self.dom, 16.756 - local_port=local, 16.757 - remote_port=remote) 16.758 + self.channel = self.openChannel("channel", 0, 1) 16.759 + self.store_channel = self.eventChannel("store_channel") 16.760 16.761 def create_configured_devices(self): 16.762 devices = sxp.children(self.config, 'device') 16.763 - indexes = {} 16.764 for d in devices: 16.765 dev_config = sxp.child0(d) 16.766 if dev_config is None: 16.767 @@ -748,13 +689,7 @@ class XendDomainInfo: 16.768 ctrl_type = get_device_handler(dev_type) 16.769 if ctrl_type is None: 16.770 raise VmError('unknown device type: ' + dev_type) 16.771 - # Keep track of device indexes by type, so we can fish 16.772 - # out saved info for recreation. 16.773 - idx = indexes.get(dev_type, -1) 16.774 - idx += 1 16.775 - indexes[ctrl_type] = idx 16.776 - recreate = self.get_device_recreate(dev_type, idx) 16.777 - self.createDevice(ctrl_type, dev_config, recreate=recreate) 16.778 + self.createDevice(ctrl_type, dev_config) 16.779 16.780 def create_devices(self): 16.781 """Create the devices for a vm. 16.782 @@ -766,43 +701,6 @@ class XendDomainInfo: 16.783 ctrl.initController(reboot=True) 16.784 else: 16.785 self.create_configured_devices() 16.786 - if self.is_vmx: 16.787 - self.create_vmx_model() 16.788 - 16.789 - def create_vmx_model(self): 16.790 - #todo: remove special case for vmx 16.791 - device_model = sxp.child_value(self.config, 'device_model') 16.792 - if not device_model: 16.793 - raise VmError("vmx: missing device model") 16.794 - device_config = sxp.child_value(self.config, 'device_config') 16.795 - if not device_config: 16.796 - raise VmError("vmx: missing device config") 16.797 - #todo: self.memory? 16.798 - memory = sxp.child_value(self.config, "memory") 16.799 - # Create an event channel 16.800 - device_channel = channel.eventChannel(0, self.dom) 16.801 - # see if a vncviewer was specified 16.802 - # XXX RN: bit of a hack. should unify this, maybe stick in config space 16.803 - vncconnect="" 16.804 - image = sxp.child_value(self.config, "image") 16.805 - args = sxp.child_value(image, "args") 16.806 - if args: 16.807 - arg_list = string.split(args) 16.808 - for arg in arg_list: 16.809 - al = string.split(arg, '=') 16.810 - if al[0] == "VNC_VIEWER": 16.811 - vncconnect=" -v %s" % al[1] 16.812 - break 16.813 - 16.814 - # Execute device model. 16.815 - #todo: Error handling 16.816 - # XXX RN: note that the order of args matter! 16.817 - os.system(device_model 16.818 - + " -f %s" % device_config 16.819 - + vncconnect 16.820 - + " -d %d" % self.dom 16.821 - + " -p %d" % device_channel['port1'] 16.822 - + " -m %s" % memory) 16.823 16.824 def device_create(self, dev_config): 16.825 """Create a new device. 16.826 @@ -814,16 +712,14 @@ class XendDomainInfo: 16.827 self.config.append(['device', dev.getConfig()]) 16.828 return dev.sxpr() 16.829 16.830 - def device_configure(self, dev_config, idx): 16.831 + def device_configure(self, dev_config, id): 16.832 """Configure an existing device. 16.833 16.834 @param dev_config: device configuration 16.835 - @param idx: device index 16.836 + @param id: device id 16.837 """ 16.838 type = sxp.name(dev_config) 16.839 - dev = self.getDeviceByIndex(type, idx) 16.840 - if not dev: 16.841 - raise VmError('invalid device: %s %s' % (type, idx)) 16.842 + dev = self.getDevice(type, id) 16.843 old_config = dev.getConfig() 16.844 new_config = dev.configure(dev_config, change=True) 16.845 # Patch new config into vm config. 16.846 @@ -833,26 +729,22 @@ class XendDomainInfo: 16.847 self.config[old_index] = new_full_config 16.848 return new_config 16.849 16.850 - def device_refresh(self, type, idx): 16.851 + def device_refresh(self, type, id): 16.852 """Refresh a device. 16.853 16.854 @param type: device type 16.855 - @param idx: device index 16.856 + @param id: device id 16.857 """ 16.858 - dev = self.getDeviceByIndex(type, idx) 16.859 - if not dev: 16.860 - raise VmError('invalid device: %s %s' % (type, idx)) 16.861 + dev = self.getDevice(type, id) 16.862 dev.refresh() 16.863 16.864 - def device_delete(self, type, idx): 16.865 + def device_delete(self, type, id): 16.866 """Destroy and remove a device. 16.867 16.868 @param type: device type 16.869 - @param idx: device index 16.870 + @param id: device id 16.871 """ 16.872 - dev = self.getDeviceByIndex(type, idx) 16.873 - if not dev: 16.874 - raise VmError('invalid device: %s %s' % (type, idx)) 16.875 + dev = self.getDevice(type, id) 16.876 dev_config = dev.getConfig() 16.877 if dev_config: 16.878 self.config.remove(['device', dev_config]) 16.879 @@ -861,9 +753,7 @@ class XendDomainInfo: 16.880 def configure_bootloader(self): 16.881 """Configure boot loader. 16.882 """ 16.883 - bl = sxp.child_value(self.config, "bootloader") 16.884 - if bl is not None: 16.885 - self.bootloader = bl 16.886 + self.bootloader = sxp.child_value(self.config, "bootloader") 16.887 16.888 def configure_console(self): 16.889 """Configure the vm console port. 16.890 @@ -946,6 +836,7 @@ class XendDomainInfo: 16.891 if self.bootloader: 16.892 self.config = self.bootloader_config() 16.893 self.construct(self.config) 16.894 + self.saveDB() 16.895 finally: 16.896 self.restart_state = None 16.897 16.898 @@ -1051,19 +942,6 @@ class XendDomainInfo: 16.899 log.warning("Unknown config field %s", field_name) 16.900 index[field_name] = field_index + 1 16.901 16.902 - def pgtable_size(self, memory): 16.903 - """Return the size of memory needed for 1:1 page tables for physical 16.904 - mode. 16.905 - 16.906 - @param memory: size in MB 16.907 - @return size in KB 16.908 - """ 16.909 - if self.is_vmx: 16.910 - # Logic x86-32 specific. 16.911 - # 1 page for the PGD + 1 pte page for 4MB of memory (rounded) 16.912 - return (1 + ((memory + 3) >> 2)) * 4 16.913 - return 0 16.914 - 16.915 def mem_target_set(self, target): 16.916 """Set domain memory target in pages. 16.917 """ 16.918 @@ -1090,83 +968,6 @@ class XendDomainInfo: 16.919 return 0 16.920 return timeout - (time.time() - self.shutdown_pending['start']) 16.921 16.922 -def vm_image_linux(vm, image): 16.923 - """Create a VM for a linux image. 16.924 - 16.925 - @param name: vm name 16.926 - @param memory: vm memory 16.927 - @param image: image config 16.928 - @return: vm 16.929 - """ 16.930 - kernel = sxp.child_value(image, "kernel") 16.931 - cmdline = "" 16.932 - ip = sxp.child_value(image, "ip", None) 16.933 - if ip: 16.934 - cmdline += " ip=" + ip 16.935 - root = sxp.child_value(image, "root") 16.936 - if root: 16.937 - cmdline += " root=" + root 16.938 - args = sxp.child_value(image, "args") 16.939 - if args: 16.940 - cmdline += " " + args 16.941 - ramdisk = sxp.child_value(image, "ramdisk", '') 16.942 - log.debug("creating linux domain with cmdline: %s" %(cmdline,)) 16.943 - vm.create_domain("linux", kernel, ramdisk, cmdline) 16.944 - return vm 16.945 - 16.946 -def vm_image_plan9(vm, image): 16.947 - """Create a VM for a Plan 9 image. 16.948 - 16.949 - name vm name 16.950 - memory vm memory 16.951 - image image config 16.952 - 16.953 - returns vm 16.954 - """ 16.955 - kernel = sxp.child_value(image, "kernel") 16.956 - cmdline = "" 16.957 - ip = sxp.child_value(image, "ip", "dhcp") 16.958 - if ip: 16.959 - cmdline += "ip=" + ip 16.960 - root = sxp.child_value(image, "root") 16.961 - if root: 16.962 - cmdline += "root=" + root 16.963 - args = sxp.child_value(image, "args") 16.964 - if args: 16.965 - cmdline += " " + args 16.966 - ramdisk = sxp.child_value(image, "ramdisk", '') 16.967 - log.debug("creating plan9 domain with cmdline: %s" %(cmdline,)) 16.968 - vm.create_domain("plan9", kernel, ramdisk, cmdline) 16.969 - return vm 16.970 - 16.971 -def vm_image_vmx(vm, image): 16.972 - """Create a VM for the VMX environment. 16.973 - 16.974 - @param name: vm name 16.975 - @param memory: vm memory 16.976 - @param image: image config 16.977 - @return: vm 16.978 - """ 16.979 - kernel = sxp.child_value(image, "kernel") 16.980 - cmdline = "" 16.981 - ip = sxp.child_value(image, "ip", "dhcp") 16.982 - if ip: 16.983 - cmdline += " ip=" + ip 16.984 - root = sxp.child_value(image, "root") 16.985 - if root: 16.986 - cmdline += " root=" + root 16.987 - args = sxp.child_value(image, "args") 16.988 - if args: 16.989 - cmdline += " " + args 16.990 - ramdisk = sxp.child_value(image, "ramdisk", '') 16.991 - memmap = sxp.child_value(vm.config, "memmap", '') 16.992 - memmap = sxp.parse(open(memmap))[0] 16.993 - from xen.util.memmap import memmap_parse 16.994 - memmap = memmap_parse(memmap) 16.995 - log.debug("creating vmx domain with cmdline: %s" %(cmdline,)) 16.996 - vm.create_domain("vmx", kernel, ramdisk, cmdline, memmap) 16.997 - return vm 16.998 - 16.999 def vm_field_ignore(vm, config, val, index): 16.1000 """Dummy config field handler used for fields with built-in handling. 16.1001 16.1002 @@ -1192,13 +993,20 @@ def vm_field_maxmem(vm, config, val, ind 16.1003 maxmem = int(maxmem) 16.1004 except: 16.1005 raise VmError("invalid maxmem: " + str(maxmem)) 16.1006 - xc.domain_setmaxmem(vm.dom, maxmem_kb = maxmem * 1024) 16.1007 + xc.domain_setmaxmem(vm.id, maxmem_kb = maxmem * 1024) 16.1008 16.1009 #============================================================================ 16.1010 # Register image handlers. 16.1011 -add_image_handler('linux', vm_image_linux) 16.1012 -add_image_handler('plan9', vm_image_plan9) 16.1013 -add_image_handler('vmx', vm_image_vmx) 16.1014 +from image import \ 16.1015 + addImageHandlerClass, \ 16.1016 + ImageHandler, \ 16.1017 + LinuxImageHandler, \ 16.1018 + Plan9ImageHandler, \ 16.1019 + VmxImageHandler 16.1020 + 16.1021 +addImageHandlerClass(LinuxImageHandler) 16.1022 +addImageHandlerClass(Plan9ImageHandler) 16.1023 +addImageHandlerClass(VmxImageHandler) 16.1024 16.1025 # Ignore the fields we already handle. 16.1026 add_config_handler('name', vm_field_ignore)
17.1 --- a/tools/python/xen/xend/XendRoot.py Thu Jun 09 14:07:02 2005 +0000 17.2 +++ b/tools/python/xen/xend/XendRoot.py Thu Jun 09 14:40:39 2005 +0000 17.3 @@ -25,9 +25,6 @@ import sxp 17.4 class XendRoot: 17.5 """Root of the management classes.""" 17.6 17.7 - """Default path to the root of the database.""" 17.8 - dbroot_default = "/var/lib/xen/xend-db" 17.9 - 17.10 """Default path to the config file.""" 17.11 config_default = "/etc/xen/xend-config.sxp" 17.12 17.13 @@ -82,7 +79,6 @@ class XendRoot: 17.14 components = {} 17.15 17.16 def __init__(self): 17.17 - self.dbroot = None 17.18 self.config_path = None 17.19 self.config = None 17.20 self.logging = None 17.21 @@ -171,13 +167,15 @@ class XendRoot: 17.22 def configure(self): 17.23 self.set_config() 17.24 self.configure_logger() 17.25 - self.dbroot = self.get_config_value("dbroot", self.dbroot_default) 17.26 17.27 def configure_logger(self): 17.28 logfile = self.get_config_value("logfile", self.logfile_default) 17.29 loglevel = self.get_config_value("loglevel", self.loglevel_default) 17.30 self.logging = XendLogging(logfile, level=loglevel) 17.31 - #self.logging.addLogStderr() 17.32 + 17.33 + from xen.xend.server import params 17.34 + if params.XEND_DEBUG: 17.35 + self.logging.addLogStderr() 17.36 17.37 def get_logging(self): 17.38 """Get the XendLogging instance. 17.39 @@ -189,11 +187,6 @@ class XendRoot: 17.40 """ 17.41 return self.logging and self.logging.getLogger() 17.42 17.43 - def get_dbroot(self): 17.44 - """Get the path to the database root. 17.45 - """ 17.46 - return self.dbroot 17.47 - 17.48 def set_config(self): 17.49 """If the config file exists, read it. If not, ignore it. 17.50 17.51 @@ -241,9 +234,9 @@ class XendRoot: 17.52 17.53 def get_config_bool(self, name, val=None): 17.54 v = self.get_config_value(name, val) 17.55 - if v in ['yes', '1', 'on', 1, True]: 17.56 + if v in ['yes', '1', 'on', 'true', 1, True]: 17.57 return True 17.58 - if v in ['no', '0', 'off', 0, False]: 17.59 + if v in ['no', '0', 'off', 'false', 0, False]: 17.60 return False 17.61 raise XendError("invalid xend config %s: expected bool: %s" % (name, v)) 17.62 17.63 @@ -325,7 +318,7 @@ class XendRoot: 17.64 return self.get_config_value('network-script', 'network') 17.65 17.66 def get_enable_dump(self): 17.67 - return self.get_config_value('enable-dump', 'false') 17.68 + return self.get_config_bool('enable-dump', 'no') 17.69 17.70 def get_vif_bridge(self): 17.71 return self.get_config_value('vif-bridge', 'xen-br0')
18.1 --- a/tools/python/xen/xend/XendVnet.py Thu Jun 09 14:07:02 2005 +0000 18.2 +++ b/tools/python/xen/xend/XendVnet.py Thu Jun 09 14:40:39 2005 +0000 18.3 @@ -4,11 +4,10 @@ 18.4 """ 18.5 18.6 from xen.util import Brctl 18.7 - 18.8 -import sxp 18.9 -import XendDB 18.10 -from XendError import XendError 18.11 -from XendLogging import log 18.12 +from xen.xend import sxp 18.13 +from xen.xend.XendError import XendError 18.14 +from xen.xend.XendLogging import log 18.15 +from xen.xend.xenstore import XenNode, DBMap 18.16 18.17 def vnet_cmd(cmd): 18.18 out = None 18.19 @@ -63,14 +62,15 @@ class XendVnet: 18.20 """Index of all vnets. Singleton. 18.21 """ 18.22 18.23 - dbpath = "vnet" 18.24 + dbpath = "/vnet" 18.25 18.26 def __init__(self): 18.27 # Table of vnet info indexed by vnet id. 18.28 self.vnet = {} 18.29 - self.db = XendDB.XendDB(self.dbpath) 18.30 - vnets = self.db.fetchall("") 18.31 - for config in vnets.values(): 18.32 + self.dbmap = DBMap(db=XenNode(self.dbpath)) 18.33 + self.dbmap.readDB() 18.34 + for vnetdb in self.dbmap.values(): 18.35 + config = vnetdb.config 18.36 info = XendVnetInfo(config) 18.37 self.vnet[info.id] = info 18.38 try: 18.39 @@ -115,7 +115,7 @@ class XendVnet: 18.40 """ 18.41 info = XendVnetInfo(config) 18.42 self.vnet[info.id] = info 18.43 - self.db.save(info.id, info.sxpr()) 18.44 + self.dbmap["%s/config" % info.id] = info.sxpr() 18.45 info.configure() 18.46 18.47 def vnet_delete(self, id): 18.48 @@ -126,7 +126,7 @@ class XendVnet: 18.49 info = self.vnet_get(id) 18.50 if info: 18.51 del self.vnet[id] 18.52 - self.db.delete(id) 18.53 + self.dbmap.delete(id) 18.54 info.delete() 18.55 18.56 def instance():
19.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 19.2 +++ b/tools/python/xen/xend/image.py Thu Jun 09 14:40:39 2005 +0000 19.3 @@ -0,0 +1,339 @@ 19.4 +import os 19.5 + 19.6 +import xen.lowlevel.xc; xc = xen.lowlevel.xc.new() 19.7 +from xen.xend import sxp 19.8 +from xen.xend.XendError import VmError 19.9 +from xen.xend.XendLogging import log 19.10 +from xen.xend.xenstore import DBVar 19.11 + 19.12 +class ImageHandler: 19.13 + """Abstract base class for image handlers. 19.14 + 19.15 + initDomain() is called to initialise the domain memory. 19.16 + 19.17 + createImage() is called to configure and build the domain from its 19.18 + kernel image and ramdisk etc. 19.19 + 19.20 + The method buildDomain() is used to build the domain, and must be 19.21 + defined in a subclass. Usually this is the only method that needs 19.22 + defining in a subclass. 19.23 + 19.24 + The method createDeviceModel() is called to create the domain device 19.25 + model if it needs one. The default is to do nothing. 19.26 + 19.27 + The method destroy() is called when the domain is destroyed. 19.28 + The default is to do nothing. 19.29 + 19.30 + """ 19.31 + 19.32 + #====================================================================== 19.33 + # Class vars and methods. 19.34 + 19.35 + """Table of image handler classes for virtual machine images. 19.36 + Indexed by image type. 19.37 + """ 19.38 + imageHandlerClasses = {} 19.39 + 19.40 + def addImageHandlerClass(cls, h): 19.41 + """Add a handler class for an image type 19.42 + @param h: handler: ImageHandler subclass 19.43 + """ 19.44 + cls.imageHandlerClasses[h.ostype] = h 19.45 + 19.46 + addImageHandlerClass = classmethod(addImageHandlerClass) 19.47 + 19.48 + def findImageHandlerClass(cls, image): 19.49 + """Find the image handler class for an image config. 19.50 + 19.51 + @param image config 19.52 + @return ImageHandler subclass or None 19.53 + """ 19.54 + ty = sxp.name(image) 19.55 + if ty is None: 19.56 + raise VmError('missing image type') 19.57 + imageClass = cls.imageHandlerClasses.get(ty) 19.58 + if imageClass is None: 19.59 + raise VmError('unknown image type: ' + ty) 19.60 + return imageClass 19.61 + 19.62 + findImageHandlerClass = classmethod(findImageHandlerClass) 19.63 + 19.64 + def create(cls, vm, image): 19.65 + """Create an image handler for a vm. 19.66 + 19.67 + @param vm vm 19.68 + @param image image config 19.69 + @return ImageHandler instance 19.70 + """ 19.71 + imageClass = cls.findImageHandlerClass(image) 19.72 + return imageClass(vm, image) 19.73 + 19.74 + create = classmethod(create) 19.75 + 19.76 + #====================================================================== 19.77 + # Instance vars and methods. 19.78 + 19.79 + db = None 19.80 + ostype = None 19.81 + 19.82 + config = None 19.83 + kernel = None 19.84 + ramdisk = None 19.85 + cmdline = None 19.86 + flags = 0 19.87 + 19.88 + __exports__ = [ 19.89 + DBVar('ostype', ty='str'), 19.90 + DBVar('config', ty='sxpr'), 19.91 + DBVar('kernel', ty='str'), 19.92 + DBVar('ramdisk', ty='str'), 19.93 + DBVar('cmdline', ty='str'), 19.94 + DBVar('flags', ty='int'), 19.95 + ] 19.96 + 19.97 + def __init__(self, vm, config): 19.98 + self.vm = vm 19.99 + self.db = vm.db.addChild('/image') 19.100 + self.config = config 19.101 + 19.102 + def exportToDB(self, save=False): 19.103 + self.db.exportToDB(self, fields=self.__exports__, save=save) 19.104 + 19.105 + def importFromDB(self): 19.106 + self.db.importFromDB(self, fields=self.__exports__) 19.107 + 19.108 + def unlink(self, f): 19.109 + if not f: return 19.110 + try: 19.111 + os.unlink(f) 19.112 + except OSError, ex: 19.113 + log.warning("error removing bootloader file '%s': %s", f, ex) 19.114 + 19.115 + def initDomain(self, dom, memory, cpu, cpu_weight): 19.116 + """Initial domain create. 19.117 + 19.118 + @return domain id 19.119 + """ 19.120 + 19.121 + mem_kb = self.getDomainMemory(memory) 19.122 + if not self.vm.restore: 19.123 + dom = xc.domain_create(dom = dom or 0) 19.124 + # if bootloader, unlink here. But should go after buildDomain() ? 19.125 + if self.vm.bootloader: 19.126 + self.unlink(self.kernel) 19.127 + self.unlink(self.ramdisk) 19.128 + if dom <= 0: 19.129 + raise VmError('Creating domain failed: name=%s' % self.vm.name) 19.130 + log.debug("initDomain: cpu=%d mem_kb=%d dom=%d", cpu, mem_kb, dom) 19.131 + # xc.domain_setuuid(dom, uuid) 19.132 + xc.domain_setcpuweight(dom, cpu_weight) 19.133 + xc.domain_setmaxmem(dom, mem_kb) 19.134 + xc.domain_memory_increase_reservation(dom, mem_kb) 19.135 + if cpu != -1: 19.136 + xc.domain_pincpu(dom, 0, 1<<int(cpu)) 19.137 + return dom 19.138 + 19.139 + def createImage(self): 19.140 + """Entry point to create domain memory image. 19.141 + Override in subclass if needed. 19.142 + """ 19.143 + self.configure() 19.144 + self.createDomain() 19.145 + 19.146 + def configure(self): 19.147 + """Config actions common to all unix-like domains.""" 19.148 + self.kernel = sxp.child_value(self.config, "kernel") 19.149 + self.cmdline = "" 19.150 + ip = sxp.child_value(self.config, "ip", None) 19.151 + if ip: 19.152 + self.cmdline += " ip=" + ip 19.153 + root = sxp.child_value(self.config, "root") 19.154 + if root: 19.155 + self.cmdline += " root=" + root 19.156 + args = sxp.child_value(self.config, "args") 19.157 + if args: 19.158 + self.cmdline += " " + args 19.159 + self.ramdisk = sxp.child_value(self.config, "ramdisk", '') 19.160 + 19.161 + def createDomain(self): 19.162 + """Build the domain boot image. 19.163 + """ 19.164 + # Set params and call buildDomain(). 19.165 + self.flags = 0 19.166 + if self.vm.netif_backend: self.flags |= SIF_NET_BE_DOMAIN 19.167 + if self.vm.blkif_backend: self.flags |= SIF_BLK_BE_DOMAIN 19.168 + 19.169 + if self.vm.recreate or self.vm.restore: 19.170 + return 19.171 + if not os.path.isfile(self.kernel): 19.172 + raise VmError('Kernel image does not exist: %s' % self.kernel) 19.173 + if self.ramdisk and not os.path.isfile(self.ramdisk): 19.174 + raise VmError('Kernel ramdisk does not exist: %s' % self.ramdisk) 19.175 + if len(self.cmdline) >= 256: 19.176 + log.warning('kernel cmdline too long, domain %d', self.vm.getDomain()) 19.177 + 19.178 + log.info("buildDomain os=%s dom=%d vcpus=%d", self.ostype, 19.179 + self.vm.getDomain(), self.vm.vcpus) 19.180 + err = self.buildDomain() 19.181 + if err != 0: 19.182 + raise VmError('Building domain failed: ostype=%s dom=%d err=%d' 19.183 + % (self.ostype, self.vm.getDomain(), err)) 19.184 + 19.185 + def getDomainMemory(self, mem_mb): 19.186 + """Memory (in KB) the domain will need for mem_mb (in MB).""" 19.187 + return mem_mb * 1024 19.188 + 19.189 + def buildDomain(self): 19.190 + """Build the domain. Define in subclass.""" 19.191 + raise NotImplementedError() 19.192 + 19.193 + def createDeviceModel(self): 19.194 + """Create device model for the domain (define in subclass if needed).""" 19.195 + pass 19.196 + 19.197 + def destroy(self): 19.198 + """Extra cleanup on domain destroy (define in subclass if needed).""" 19.199 + pass 19.200 + 19.201 +addImageHandlerClass = ImageHandler.addImageHandlerClass 19.202 + 19.203 +class LinuxImageHandler(ImageHandler): 19.204 + 19.205 + ostype = "linux" 19.206 + 19.207 + def buildDomain(self): 19.208 + if self.vm.store_channel: 19.209 + store_evtchn = self.vm.store_channel.port2 19.210 + else: 19.211 + store_evtchn = 0 19.212 + ret = xc.linux_build(dom = self.vm.getDomain(), 19.213 + image = self.kernel, 19.214 + control_evtchn = self.vm.channel.getRemotePort(), 19.215 + store_evtchn = store_evtchn, 19.216 + cmdline = self.cmdline, 19.217 + ramdisk = self.ramdisk, 19.218 + flags = self.flags, 19.219 + vcpus = self.vm.vcpus) 19.220 + if isinstance(ret, dict): 19.221 + self.vm.store_mfn = ret.get('store_mfn') 19.222 + return 0 19.223 + return ret 19.224 + 19.225 +class Plan9ImageHandler(ImageHandler): 19.226 + 19.227 + ostype = "plan9" 19.228 + 19.229 + def buildDomain(self): 19.230 + return xc.plan9_build(dom = self.vm.getDomain(), 19.231 + image = self.kernel, 19.232 + control_evtchn = self.vm.channel.getRemotePort(), 19.233 + cmdline = self.cmdline, 19.234 + ramdisk = self.ramdisk, 19.235 + flags = self.flags, 19.236 + vcpus = self.vm.vcpus) 19.237 + 19.238 +class VmxImageHandler(ImageHandler): 19.239 + 19.240 + __exports__ = ImageHandler.__exports__ + [ 19.241 + DBVar('memmap', ty='str'), 19.242 + DBVar('memmap_value', ty='sxpr'), 19.243 + # device channel? 19.244 + ] 19.245 + 19.246 + ostype = "vmx" 19.247 + memmap = None 19.248 + memmap_value = None 19.249 + device_channel = None 19.250 + 19.251 + def createImage(self): 19.252 + """Create a VM for the VMX environment. 19.253 + """ 19.254 + self.configure() 19.255 + self.parseMemmap() 19.256 + self.createDomain() 19.257 + 19.258 + def buildDomain(self): 19.259 + return xc.vmx_build(dom = self.vm.getDomain(), 19.260 + image = self.kernel, 19.261 + control_evtchn = 0, 19.262 + memsize = self.vm.memory, 19.263 + memmap = self.memmap_value, 19.264 + cmdline = self.cmdline, 19.265 + ramdisk = self.ramdisk, 19.266 + flags = self.flags) 19.267 + 19.268 + def parseMemmap(self): 19.269 + self.memmap = sxp.child_value(self.vm.config, "memmap") 19.270 + if self.memmap is None: 19.271 + raise VmError("missing memmap") 19.272 + memmap = sxp.parse(open(self.memmap))[0] 19.273 + from xen.util.memmap import memmap_parse 19.274 + self.memmap_value = memmap_parse(memmap) 19.275 + 19.276 + def createDeviceModel_old(self): 19.277 + device_model = sxp.child_value(self.vm.config, 'device_model') 19.278 + if not device_model: 19.279 + raise VmError("vmx: missing device model") 19.280 + device_config = sxp.child_value(self.vm.config, 'device_config') 19.281 + if not device_config: 19.282 + raise VmError("vmx: missing device config") 19.283 + # Create an event channel. 19.284 + self.device_channel = channel.eventChannel(0, self.vm.getDomain()) 19.285 + # Execute device model. 19.286 + #todo: Error handling 19.287 + os.system(device_model 19.288 + + " -f %s" % device_config 19.289 + + " -d %d" % self.vm.getDomain() 19.290 + + " -p %d" % self.device_channel['port1'] 19.291 + + " -m %s" % self.vm.memory) 19.292 + 19.293 + def createDeviceModel(self): 19.294 + device_model = sxp.child_value(self.vm.config, 'device_model') 19.295 + if not device_model: 19.296 + raise VmError("vmx: missing device model") 19.297 + device_config = sxp.child_value(self.vm.config, 'device_config') 19.298 + if not device_config: 19.299 + raise VmError("vmx: missing device config") 19.300 + # Create an event channel 19.301 + self.device_channel = channel.eventChannel(0, self.vm.getDomain()) 19.302 + # Execute device model. 19.303 + #todo: Error handling 19.304 + # XXX RN: note that the order of args matter! 19.305 + os.system(device_model 19.306 + + " -f %s" % device_config 19.307 + + self.vncParams() 19.308 + + " -d %d" % self.vm.getDomain() 19.309 + + " -p %d" % self.device_channel['port1'] 19.310 + + " -m %s" % self.vm.memory) 19.311 + 19.312 + def vncParams(self): 19.313 + # see if a vncviewer was specified 19.314 + # XXX RN: bit of a hack. should unify this, maybe stick in config space 19.315 + vncconnect="" 19.316 + image = self.config 19.317 + args = sxp.child_value(image, "args") 19.318 + if args: 19.319 + arg_list = string.split(args) 19.320 + for arg in arg_list: 19.321 + al = string.split(arg, '=') 19.322 + if al[0] == "VNC_VIEWER": 19.323 + vncconnect=" -v %s" % al[1] 19.324 + break 19.325 + return vncconnect 19.326 + 19.327 + def destroy(self): 19.328 + channel.eventChannelClose(self.device_channel) 19.329 + 19.330 + def getDomainMemory(self, mem_mb): 19.331 + return (mem_mb * 1024) + self.getPageTableSize(mem_mb) 19.332 + 19.333 + def getPageTableSize(self, mem_mb): 19.334 + """Return the size of memory needed for 1:1 page tables for physical 19.335 + mode. 19.336 + 19.337 + @param mem_mb: size in MB 19.338 + @return size in KB 19.339 + """ 19.340 + # Logic x86-32 specific. 19.341 + # 1 page for the PGD + 1 pte page for 4MB of memory (rounded) 19.342 + return (1 + ((mem_mb + 3) >> 2)) * 4
20.1 --- a/tools/python/xen/xend/server/SrvConsole.py Thu Jun 09 14:07:02 2005 +0000 20.2 +++ b/tools/python/xen/xend/server/SrvConsole.py Thu Jun 09 14:40:39 2005 +0000 20.3 @@ -30,7 +30,7 @@ class SrvConsole(SrvDir): 20.4 #self.ls() 20.5 req.write('<p>%s</p>' % self.info) 20.6 req.write('<p><a href="%s">Connect to domain %d</a></p>' 20.7 - % (self.info.uri(), self.info.dom)) 20.8 + % (self.info.uri(), self.info.id)) 20.9 self.form(req) 20.10 req.write('</body></html>') 20.11
21.1 --- a/tools/python/xen/xend/server/SrvDaemon.py Thu Jun 09 14:07:02 2005 +0000 21.2 +++ b/tools/python/xen/xend/server/SrvDaemon.py Thu Jun 09 14:40:39 2005 +0000 21.3 @@ -32,9 +32,6 @@ import event 21.4 import relocate 21.5 from params import * 21.6 21.7 -DAEMONIZE = 0 21.8 -DEBUG = 1 21.9 - 21.10 class Daemon: 21.11 """The xend daemon. 21.12 """ 21.13 @@ -128,9 +125,13 @@ class Daemon: 21.14 def cleanup_xend(self, kill=False): 21.15 return self.cleanup_process(XEND_PID_FILE, "xend", kill) 21.16 21.17 + def cleanup_xenstored(self, kill=False): 21.18 + return self.cleanup_process(XENSTORED_PID_FILE, "xenstored", kill) 21.19 + 21.20 def cleanup(self, kill=False): 21.21 self.cleanup_xend(kill=kill) 21.22 - 21.23 + #self.cleanup_xenstored(kill=kill) 21.24 + 21.25 def status(self): 21.26 """Returns the status of the xend daemon. 21.27 The return value is defined by the LSB: 21.28 @@ -166,8 +167,29 @@ class Daemon: 21.29 pidfile.close() 21.30 return pid 21.31 21.32 + def start_xenstored(self): 21.33 + """Fork and exec xenstored, writing its pid to XENSTORED_PID_FILE. 21.34 + """ 21.35 + def mkdirs(p): 21.36 + try: 21.37 + os.makedirs(p) 21.38 + except: 21.39 + pass 21.40 + mkdirs(XENSTORED_RUN_DIR) 21.41 + mkdirs(XENSTORED_LIB_DIR) 21.42 + 21.43 + pid = self.fork_pid(XENSTORED_PID_FILE) 21.44 + if pid: 21.45 + # Parent 21.46 + log.info("Started xenstored, pid=%d", pid) 21.47 + else: 21.48 + # Child 21.49 + if XEND_DAEMONIZE and (not XENSTORED_DEBUG): 21.50 + self.daemonize() 21.51 + os.execl("/usr/sbin/xenstored", "xenstored", "--no-fork") 21.52 + 21.53 def daemonize(self): 21.54 - if not DAEMONIZE: return 21.55 + if not XEND_DAEMONIZE: return 21.56 # Detach from TTY. 21.57 os.setsid() 21.58 21.59 @@ -177,16 +199,16 @@ class Daemon: 21.60 os.close(0) 21.61 os.close(1) 21.62 os.close(2) 21.63 - if DEBUG: 21.64 + if XEND_DEBUG: 21.65 os.open('/dev/null', os.O_RDONLY) 21.66 # XXX KAF: Why doesn't this capture output from C extensions that 21.67 # fprintf(stdout) or fprintf(stderr) ?? 21.68 - os.open('/var/log/xend-debug.log', os.O_WRONLY|os.O_CREAT) 21.69 + os.open(XEND_DEBUG_LOG, os.O_WRONLY|os.O_CREAT) 21.70 os.dup(1) 21.71 else: 21.72 os.open('/dev/null', os.O_RDWR) 21.73 os.dup(0) 21.74 - os.open('/var/log/xend-debug.log', os.O_WRONLY|os.O_CREAT) 21.75 + os.open(XEND_DEBUG_LOG, os.O_WRONLY|os.O_CREAT) 21.76 21.77 21.78 def start(self, trace=0): 21.79 @@ -196,11 +218,15 @@ class Daemon: 21.80 4 Insufficient privileges 21.81 """ 21.82 xend_pid = self.cleanup_xend() 21.83 + xenstored_pid = self.cleanup_xenstored() 21.84 21.85 if self.set_user(): 21.86 return 4 21.87 os.chdir("/") 21.88 21.89 + if xenstored_pid == 0: 21.90 + self.start_xenstored() 21.91 + 21.92 if xend_pid > 0: 21.93 # Trying to run an already-running service is a success. 21.94 return 0 21.95 @@ -308,7 +334,7 @@ class Daemon: 21.96 servers.start() 21.97 except Exception, ex: 21.98 print >>sys.stderr, 'Exception starting xend:', ex 21.99 - if DEBUG: 21.100 + if XEND_DEBUG: 21.101 traceback.print_exc() 21.102 log.exception("Exception starting xend") 21.103 self.exit(1)
22.1 --- a/tools/python/xen/xend/server/SrvDomain.py Thu Jun 09 14:07:02 2005 +0000 22.2 +++ b/tools/python/xen/xend/server/SrvDomain.py Thu Jun 09 14:40:39 2005 +0000 22.3 @@ -28,19 +28,19 @@ class SrvDomain(SrvDir): 22.4 fn = FormFn(self.xd.domain_configure, 22.5 [['dom', 'int'], 22.6 ['config', 'sxpr']]) 22.7 - return fn(req.args, {'dom': self.dom.dom}) 22.8 + return fn(req.args, {'dom': self.dom.id}) 22.9 22.10 def op_unpause(self, op, req): 22.11 - val = self.xd.domain_unpause(self.dom.name) 22.12 + val = self.xd.domain_unpause(self.dom.id) 22.13 return val 22.14 22.15 def op_pause(self, op, req): 22.16 - val = self.xd.domain_pause(self.dom.name) 22.17 + val = self.xd.domain_pause(self.dom.id) 22.18 return val 22.19 22.20 def op_shutdown(self, op, req): 22.21 fn = FormFn(self.xd.domain_shutdown, 22.22 - [['dom', 'str'], 22.23 + [['dom', 'int'], 22.24 ['reason', 'str'], 22.25 ['key', 'int']]) 22.26 val = fn(req.args, {'dom': self.dom.id}) 22.27 @@ -50,7 +50,7 @@ class SrvDomain(SrvDir): 22.28 22.29 def op_destroy(self, op, req): 22.30 fn = FormFn(self.xd.domain_destroy, 22.31 - [['dom', 'str'], 22.32 + [['dom', 'int'], 22.33 ['reason', 'str']]) 22.34 val = fn(req.args, {'dom': self.dom.id}) 22.35 req.setHeader("Location", "%s/.." % req.prePathURL()) 22.36 @@ -61,7 +61,7 @@ class SrvDomain(SrvDir): 22.37 22.38 def do_save(self, op, req): 22.39 fn = FormFn(self.xd.domain_save, 22.40 - [['dom', 'str'], 22.41 + [['dom', 'int'], 22.42 ['file', 'str']]) 22.43 val = fn(req.args, {'dom': self.dom.id}) 22.44 return 0 22.45 @@ -71,7 +71,7 @@ class SrvDomain(SrvDir): 22.46 22.47 def do_migrate(self, op, req): 22.48 fn = FormFn(self.xd.domain_migrate, 22.49 - [['dom', 'str'], 22.50 + [['dom', 'int'], 22.51 ['destination', 'str'], 22.52 ['live', 'int'], 22.53 ['resource', 'int']]) 22.54 @@ -79,7 +79,7 @@ class SrvDomain(SrvDir): 22.55 22.56 def op_pincpu(self, op, req): 22.57 fn = FormFn(self.xd.domain_pincpu, 22.58 - [['dom', 'str'], 22.59 + [['dom', 'int'], 22.60 ['vcpu', 'int'], 22.61 ['cpumap', 'int']]) 22.62 val = fn(req.args, {'dom': self.dom.id}) 22.63 @@ -87,7 +87,7 @@ class SrvDomain(SrvDir): 22.64 22.65 def op_cpu_bvt_set(self, op, req): 22.66 fn = FormFn(self.xd.domain_cpu_bvt_set, 22.67 - [['dom', 'str'], 22.68 + [['dom', 'int'], 22.69 ['mcuadv', 'int'], 22.70 ['warpback', 'int'], 22.71 ['warpvalue', 'int'], 22.72 @@ -99,7 +99,7 @@ class SrvDomain(SrvDir): 22.73 22.74 def op_cpu_sedf_set(self, op, req): 22.75 fn = FormFn(self.xd.domain_cpu_sedf_set, 22.76 - [['dom', 'str'], 22.77 + [['dom', 'int'], 22.78 ['period', 'int'], 22.79 ['slice', 'int'], 22.80 ['latency', 'int'], 22.81 @@ -110,28 +110,28 @@ class SrvDomain(SrvDir): 22.82 22.83 def op_maxmem_set(self, op, req): 22.84 fn = FormFn(self.xd.domain_maxmem_set, 22.85 - [['dom', 'str'], 22.86 + [['dom', 'int'], 22.87 ['memory', 'int']]) 22.88 val = fn(req.args, {'dom': self.dom.id}) 22.89 return val 22.90 22.91 def op_mem_target_set(self, op, req): 22.92 fn = FormFn(self.xd.domain_mem_target_set, 22.93 - [['dom', 'str'], 22.94 + [['dom', 'int'], 22.95 ['target', 'int']]) 22.96 val = fn(req.args, {'dom': self.dom.id}) 22.97 return val 22.98 22.99 def op_devices(self, op, req): 22.100 fn = FormFn(self.xd.domain_devtype_ls, 22.101 - [['dom', 'str'], 22.102 + [['dom', 'int'], 22.103 ['type', 'str']]) 22.104 val = fn(req.args, {'dom': self.dom.id}) 22.105 return val 22.106 22.107 def op_device(self, op, req): 22.108 fn = FormFn(self.xd.domain_devtype_get, 22.109 - [['dom', 'str'], 22.110 + [['dom', 'int'], 22.111 ['type', 'str'], 22.112 ['idx', 'int']]) 22.113 val = fn(req.args, {'dom': self.dom.id}) 22.114 @@ -142,14 +142,14 @@ class SrvDomain(SrvDir): 22.115 22.116 def op_device_create(self, op, req): 22.117 fn = FormFn(self.xd.domain_device_create, 22.118 - [['dom', 'str'], 22.119 + [['dom', 'int'], 22.120 ['config', 'sxpr']]) 22.121 val = fn(req.args, {'dom': self.dom.id}) 22.122 return val 22.123 22.124 def op_device_refresh(self, op, req): 22.125 fn = FormFn(self.xd.domain_device_refresh, 22.126 - [['dom', 'str'], 22.127 + [['dom', 'int'], 22.128 ['type', 'str'], 22.129 ['idx', 'str']]) 22.130 val = fn(req.args, {'dom': self.dom.id}) 22.131 @@ -157,7 +157,7 @@ class SrvDomain(SrvDir): 22.132 22.133 def op_device_destroy(self, op, req): 22.134 fn = FormFn(self.xd.domain_device_destroy, 22.135 - [['dom', 'str'], 22.136 + [['dom', 'int'], 22.137 ['type', 'str'], 22.138 ['idx', 'str']]) 22.139 val = fn(req.args, {'dom': self.dom.id}) 22.140 @@ -165,7 +165,7 @@ class SrvDomain(SrvDir): 22.141 22.142 def op_device_configure(self, op, req): 22.143 fn = FormFn(self.xd.domain_device_configure, 22.144 - [['dom', 'str'], 22.145 + [['dom', 'int'], 22.146 ['config', 'sxpr'], 22.147 ['idx', 'str']]) 22.148 val = fn(req.args, {'dom': self.dom.id}) 22.149 @@ -173,7 +173,7 @@ class SrvDomain(SrvDir): 22.150 22.151 def op_vif_limit_set(self, op, req): 22.152 fn = FormFn(self.xd.domain_vif_limit_set, 22.153 - [['dom', 'str'], 22.154 + [['dom', 'int'], 22.155 ['vif', 'int'], 22.156 ['credit', 'int'], 22.157 ['period', 'int']])
23.1 --- a/tools/python/xen/xend/server/SrvDomainDir.py Thu Jun 09 14:07:02 2005 +0000 23.2 +++ b/tools/python/xen/xend/server/SrvDomainDir.py Thu Jun 09 14:40:39 2005 +0000 23.3 @@ -24,7 +24,7 @@ class SrvDomainDir(SrvDir): 23.4 23.5 def domain(self, x): 23.6 val = None 23.7 - dom = self.xd.domain_lookup(x) 23.8 + dom = self.xd.domain_lookup_by_name(x) 23.9 if not dom: 23.10 raise XendError('No such domain ' + str(x)) 23.11 val = SrvDomain(dom)
24.1 --- a/tools/python/xen/xend/server/blkif.py Thu Jun 09 14:07:02 2005 +0000 24.2 +++ b/tools/python/xen/xend/server/blkif.py Thu Jun 09 14:40:39 2005 +0000 24.3 @@ -5,14 +5,15 @@ import string 24.4 24.5 from xen.util import blkif 24.6 from xen.xend.XendError import XendError, VmError 24.7 -from xen.xend import XendRoot 24.8 +from xen.xend.XendRoot import get_component 24.9 from xen.xend.XendLogging import log 24.10 from xen.xend import sxp 24.11 from xen.xend import Blkctl 24.12 +from xen.xend.xenstore import DBVar 24.13 24.14 -import channel 24.15 -from controller import CtrlMsgRcvr, Dev, DevController 24.16 -from messages import * 24.17 +from xen.xend.server import channel 24.18 +from xen.xend.server.controller import CtrlMsgRcvr, Dev, DevController 24.19 +from xen.xend.server.messages import * 24.20 24.21 class BlkifBackend: 24.22 """ Handler for the 'back-end' channel to a block device driver domain 24.23 @@ -56,7 +57,7 @@ class BlkifBackend: 24.24 24.25 def openEvtchn(self): 24.26 self.evtchn = channel.eventChannel(self.backendDomain, self.frontendDomain) 24.27 - 24.28 + 24.29 def getEventChannelBackend(self): 24.30 val = 0 24.31 if self.evtchn: 24.32 @@ -158,6 +159,18 @@ class BlkDev(Dev): 24.33 """Info record for a block device. 24.34 """ 24.35 24.36 + __exports__ = Dev.__exports__ + [ 24.37 + DBVar('dev', ty='str'), 24.38 + DBVar('vdev', ty='int'), 24.39 + DBVar('mode', ty='str'), 24.40 + DBVar('viftype', ty='str'), 24.41 + DBVar('params', ty='str'), 24.42 + DBVar('node', ty='str'), 24.43 + DBVar('device', ty='long'), 24.44 + DBVar('start_sector', ty='long'), 24.45 + DBVar('nr_sectors', ty='long'), 24.46 + ] 24.47 + 24.48 def __init__(self, controller, id, config, recreate=False): 24.49 Dev.__init__(self, controller, id, config, recreate=recreate) 24.50 self.dev = None 24.51 @@ -206,7 +219,8 @@ class BlkDev(Dev): 24.52 raise VmError('vbd: Device not found: %s' % self.dev) 24.53 24.54 try: 24.55 - self.backendDomain = int(sxp.child_value(config, 'backend', '0')) 24.56 + xd = get_component('xen.xend.XendDomain') 24.57 + self.backendDomain = xd.domain_lookup_by_name(sxp.child_value(config, 'backend', '0')).id 24.58 except: 24.59 raise XendError('invalid backend domain') 24.60 24.61 @@ -214,8 +228,7 @@ class BlkDev(Dev): 24.62 24.63 def attach(self, recreate=False, change=False): 24.64 if recreate: 24.65 - node = sxp.child_value(recreate, 'node') 24.66 - self.setNode(node) 24.67 + pass 24.68 else: 24.69 node = Blkctl.block('bind', self.type, self.params) 24.70 self.setNode(node) 24.71 @@ -263,7 +276,7 @@ class BlkDev(Dev): 24.72 24.73 def check_mounted(self, name): 24.74 mode = blkif.mount_mode(name) 24.75 - xd = XendRoot.get_component('xen.xend.XendDomain') 24.76 + xd = get_component('xen.xend.XendDomain') 24.77 for vm in xd.list(): 24.78 ctrl = vm.getDeviceController(self.getType(), error=False) 24.79 if (not ctrl): continue 24.80 @@ -292,14 +305,14 @@ class BlkDev(Dev): 24.81 val.append(['uname', self.uname]) 24.82 if self.node: 24.83 val.append(['node', self.node]) 24.84 - val.append(['index', self.getIndex()]) 24.85 return val 24.86 24.87 def getBackend(self): 24.88 return self.controller.getBackend(self.backendDomain) 24.89 24.90 def refresh(self): 24.91 - log.debug("Refreshing vbd domain=%d id=%s", self.frontendDomain, self.id) 24.92 + log.debug("Refreshing vbd domain=%d id=%s", self.frontendDomain, 24.93 + self.id) 24.94 self.interfaceChanged() 24.95 24.96 def destroy(self, change=False, reboot=False): 24.97 @@ -308,7 +321,8 @@ class BlkDev(Dev): 24.98 @param change: change flag 24.99 """ 24.100 self.destroyed = True 24.101 - log.debug("Destroying vbd domain=%d id=%s", self.frontendDomain, self.id) 24.102 + log.debug("Destroying vbd domain=%d id=%s", self.frontendDomain, 24.103 + self.id) 24.104 self.send_be_vbd_destroy() 24.105 if change: 24.106 self.interfaceChanged() 24.107 @@ -445,5 +459,4 @@ class BlkifController(DevController): 24.108 log.error("Exception connecting backend: %s", ex) 24.109 else: 24.110 log.error('interface connect on unknown interface: id=%d', id) 24.111 - 24.112
25.1 --- a/tools/python/xen/xend/server/channel.py Thu Jun 09 14:07:02 2005 +0000 25.2 +++ b/tools/python/xen/xend/server/channel.py Thu Jun 09 14:40:39 2005 +0000 25.3 @@ -14,52 +14,129 @@ DEBUG = 0 25.4 25.5 RESPONSE_TIMEOUT = 20.0 25.6 25.7 -def eventChannel(dom1, dom2): 25.8 - """Create an event channel between domains. 25.9 - The returned dict contains dom1, dom2, port1 and port2 on success. 25.10 - 25.11 - @return dict (empty on error) 25.12 +class EventChannel(dict): 25.13 + """An event channel between domains. 25.14 """ 25.15 - evtchn = xc.evtchn_bind_interdomain(dom1=dom1, dom2=dom2) 25.16 - if evtchn: 25.17 - evtchn['dom1'] = dom1 25.18 - evtchn['dom2'] = dom2 25.19 - return evtchn 25.20 + 25.21 + def interdomain(cls, dom1, dom2, port1=0, port2=0): 25.22 + """Create an event channel between domains. 25.23 + 25.24 + @return EventChannel (None on error) 25.25 + """ 25.26 + v = xc.evtchn_bind_interdomain(dom1=dom1, dom2=dom2, 25.27 + port1=port1, port2=port2) 25.28 + if v: 25.29 + v = cls(dom1, dom2, v) 25.30 + return v 25.31 + 25.32 + interdomain = classmethod(interdomain) 25.33 + 25.34 + def restoreFromDB(cls, db, dom1, dom2, port1=0, port2=0): 25.35 + """Create an event channel using db info if available. 25.36 + Inverse to saveToDB(). 25.37 + 25.38 + @param db db 25.39 + @param dom1 25.40 + @param dom2 25.41 + @param port1 25.42 + @param port2 25.43 + """ 25.44 + try: 25.45 + dom1 = int(db['dom1']) 25.46 + except: pass 25.47 + try: 25.48 + dom2 = int(db['dom2']) 25.49 + except: pass 25.50 + try: 25.51 + port1 = int(db['port1']) 25.52 + except: pass 25.53 + try: 25.54 + port2 = int(db['port2']) 25.55 + except: pass 25.56 + evtchn = cls.interdomain(dom1, dom2, port1=port1, port2=port2) 25.57 + return evtchn 25.58 + 25.59 + restoreFromDB = classmethod(restoreFromDB) 25.60 + 25.61 + def __init__(self, dom1, dom2, d): 25.62 + d['dom1'] = dom1 25.63 + d['dom2'] = dom2 25.64 + self.update(d) 25.65 + self.dom1 = dom1 25.66 + self.dom2 = dom2 25.67 + self.port1 = d.get('port1') 25.68 + self.port2 = d.get('port2') 25.69 + 25.70 + def close(self): 25.71 + """Close the event channel. 25.72 + """ 25.73 + def evtchn_close(dom, port): 25.74 + try: 25.75 + xc.evtchn_close(dom=dom, port=port) 25.76 + except Exception, ex: 25.77 + pass 25.78 + 25.79 + if DEBUG: 25.80 + print 'EventChannel>close>', self 25.81 + evtchn_close(self.dom1, self.port1) 25.82 + evtchn_close(self.dom2, self.port2) 25.83 + 25.84 + def saveToDB(self, db): 25.85 + """Save the event channel to the db so it can be restored later, 25.86 + using restoreFromDB() on the class. 25.87 + 25.88 + @param db db 25.89 + """ 25.90 + db['dom1'] = str(self.dom1) 25.91 + db['dom2'] = str(self.dom2) 25.92 + db['port1'] = str(self.port1) 25.93 + db['port2'] = str(self.port2) 25.94 + db.saveDB() 25.95 + 25.96 + def sxpr(self): 25.97 + return ['event-channel', 25.98 + ['dom1', self.dom1 ], 25.99 + ['port1', self.port1 ], 25.100 + ['dom2', self.dom2 ], 25.101 + ['port2', self.port2 ] 25.102 + ] 25.103 + 25.104 + def __repr__(self): 25.105 + return ("<EventChannel dom1:%d:%d dom2:%d:%d>" 25.106 + % (self.dom1, self.port1, self.dom2, self.port2)) 25.107 + 25.108 +def eventChannel(dom1, dom2, port1=0, port2=0): 25.109 + """Create an event channel between domains. 25.110 + 25.111 + @return EventChannel (None on error) 25.112 + """ 25.113 + return EventChannel.interdomain(dom1, dom2, port1=port1, port2=port2) 25.114 25.115 def eventChannelClose(evtchn): 25.116 - """Close an event channel that was opened by eventChannel(). 25.117 + """Close an event channel. 25.118 """ 25.119 - def evtchn_close(dom, port): 25.120 - if (dom is None) or (port is None): return 25.121 - try: 25.122 - xc.evtchn_close(dom=dom, port=port) 25.123 - except Exception, ex: 25.124 - pass 25.125 - 25.126 if not evtchn: return 25.127 - if DEBUG: 25.128 - print 'eventChannelClose>', evtchn 25.129 - evtchn_close(evtchn.get('dom1'), evtchn.get('port1')) 25.130 - evtchn_close(evtchn.get('dom2'), evtchn.get('port2')) 25.131 - 25.132 + evtchn.close() 25.133 25.134 class ChannelFactory: 25.135 - """Factory for creating channels. 25.136 + """Factory for creating control channels. 25.137 Maintains a table of channels. 25.138 """ 25.139 25.140 """ Channels indexed by index. """ 25.141 - channels = {} 25.142 + channels = None 25.143 25.144 thread = None 25.145 25.146 notifier = None 25.147 25.148 """Map of ports to the virq they signal.""" 25.149 - virqPorts = {} 25.150 + virqPorts = None 25.151 25.152 def __init__(self): 25.153 """Constructor - do not use. Use the channelFactory function.""" 25.154 + self.channels = {} 25.155 + self.virqPorts = {} 25.156 self.notifier = xu.notifier() 25.157 # Register interest in virqs. 25.158 self.bind_virq(xen.lowlevel.xc.VIRQ_DOM_EXC) 25.159 @@ -70,10 +147,6 @@ class ChannelFactory: 25.160 self.virqPorts[port] = virq 25.161 log.info("Virq %s on port %s", virq, port) 25.162 25.163 - def virq(self): 25.164 - log.error("virq") 25.165 - self.notifier.virq_send(self.virqPort) 25.166 - 25.167 def start(self): 25.168 """Fork a thread to read messages. 25.169 """ 25.170 @@ -182,9 +255,13 @@ class ChannelFactory: 25.171 return None 25.172 25.173 def openChannel(self, dom, local_port=0, remote_port=0): 25.174 - return (self.findChannel(dom, local_port=local_port, remote_port=remote_port) 25.175 - or 25.176 - self.newChannel(dom, local_port, remote_port)) 25.177 + chan = self.findChannel(dom, local_port=local_port, 25.178 + remote_port=remote_port) 25.179 + if chan: 25.180 + return chan 25.181 + chan = self.newChannel(dom, local_port, remote_port) 25.182 + return chan 25.183 + 25.184 25.185 def createPort(self, dom, local_port=0, remote_port=0): 25.186 """Create a port for a channel to the given domain. 25.187 @@ -203,8 +280,31 @@ class ChannelFactory: 25.188 @type remote: int 25.189 @return: port object 25.190 """ 25.191 - return xu.port(dom, local_port=int(local_port), 25.192 - remote_port=int(remote_port)) 25.193 + return xu.port(dom, local_port=local_port, remote_port=remote_port) 25.194 + 25.195 + def restoreFromDB(self, db, dom, local, remote): 25.196 + """Create a channel using ports restored from the db (if available). 25.197 + Otherwise use the given ports. This is the inverse operation to 25.198 + saveToDB() on a channel. 25.199 + 25.200 + @param db db 25.201 + @param dom domain the channel connects to 25.202 + @param local default local port 25.203 + @param remote default remote port 25.204 + """ 25.205 + try: 25.206 + local_port = int(db['local_port']) 25.207 + except: 25.208 + local_port = local 25.209 + try: 25.210 + remote_port = int(db['remote_port']) 25.211 + except: 25.212 + remote_port = remote 25.213 + try: 25.214 + chan = self.openChannel(dom, local_port, remote_port) 25.215 + except: 25.216 + return None 25.217 + return chan 25.218 25.219 def channelFactory(): 25.220 """Singleton constructor for the channel factory. 25.221 @@ -218,7 +318,7 @@ def channelFactory(): 25.222 return inst 25.223 25.224 class Channel: 25.225 - """Chanel to a domain. 25.226 + """Control channel to a domain. 25.227 Maintains a list of device handlers to dispatch requests to, based 25.228 on the request type. 25.229 """ 25.230 @@ -239,6 +339,17 @@ class Channel: 25.231 # Make sure the port will deliver all the messages. 25.232 self.port.register(TYPE_WILDCARD) 25.233 25.234 + def saveToDB(self, db): 25.235 + """Save the channel ports to the db so the channel can be restored later, 25.236 + using restoreFromDB() on the factory. 25.237 + 25.238 + @param db db 25.239 + """ 25.240 + if self.closed: return 25.241 + db['local_port'] = str(self.getLocalPort()) 25.242 + db['remote_port'] = str(self.getRemotePort()) 25.243 + db.saveDB() 25.244 + 25.245 def getKey(self): 25.246 """Get the channel key. 25.247 """
26.1 --- a/tools/python/xen/xend/server/console.py Thu Jun 09 14:07:02 2005 +0000 26.2 +++ b/tools/python/xen/xend/server/console.py Thu Jun 09 14:40:39 2005 +0000 26.3 @@ -13,10 +13,11 @@ from xen.xend import EventServer; eserve 26.4 from xen.xend.XendLogging import log 26.5 from xen.xend import XendRoot; xroot = XendRoot.instance() 26.6 from xen.xend import sxp 26.7 +from xen.xend.xenstore import DBVar 26.8 26.9 -from controller import CtrlMsgRcvr, Dev, DevController 26.10 -from messages import * 26.11 -from params import * 26.12 +from xen.xend.server.controller import CtrlMsgRcvr, Dev, DevController 26.13 +from xen.xend.server.messages import * 26.14 +from xen.xend.server.params import * 26.15 26.16 class ConsoleProtocol(protocol.Protocol): 26.17 """Asynchronous handler for a console socket. 26.18 @@ -76,6 +77,12 @@ class ConsoleDev(Dev, protocol.ServerFac 26.19 STATUS_CONNECTED = 'connected' 26.20 STATUS_LISTENING = 'listening' 26.21 26.22 + __exports__ = Dev.__exports__ + [ 26.23 + DBVar('status', ty='str'), 26.24 + #DBVar('listening', ty='str'), 26.25 + DBVar('console_port', ty='int'), 26.26 + ] 26.27 + 26.28 def __init__(self, controller, id, config, recreate=False): 26.29 Dev.__init__(self, controller, id, config) 26.30 self.lock = threading.RLock() 26.31 @@ -129,7 +136,6 @@ class ConsoleDev(Dev, protocol.ServerFac 26.32 val.append(['local_port', self.getLocalPort() ]) 26.33 val.append(['remote_port', self.getRemotePort() ]) 26.34 val.append(['console_port', self.console_port ]) 26.35 - val.append(['index', self.getIndex()]) 26.36 if self.addr: 26.37 val.append(['connected', self.addr[0], self.addr[1]]) 26.38 finally:
27.1 --- a/tools/python/xen/xend/server/controller.py Thu Jun 09 14:07:02 2005 +0000 27.2 +++ b/tools/python/xen/xend/server/controller.py Thu Jun 09 14:40:39 2005 +0000 27.3 @@ -4,7 +4,8 @@ for a domain. 27.4 """ 27.5 27.6 from xen.xend.XendError import XendError 27.7 -from messages import msgTypeName, printMsg, getMessageType 27.8 +from xen.xend.xenstore import DBVar 27.9 +from xen.xend.server.messages import msgTypeName, printMsg, getMessageType 27.10 27.11 DEBUG = 0 27.12 27.13 @@ -115,18 +116,18 @@ class DevControllerTable: 27.14 def getDevControllerClass(self, type): 27.15 return self.controllerClasses.get(type) 27.16 27.17 - def addDevControllerClass(self, klass): 27.18 - self.controllerClasses[klass.getType()] = klass 27.19 + def addDevControllerClass(self, cls): 27.20 + self.controllerClasses[cls.getType()] = cls 27.21 27.22 def delDevControllerClass(self, type): 27.23 if type in self.controllerClasses: 27.24 del self.controllerClasses[type] 27.25 27.26 def createDevController(self, type, vm, recreate=False): 27.27 - klass = self.getDevControllerClass(type) 27.28 - if not klass: 27.29 + cls = self.getDevControllerClass(type) 27.30 + if not cls: 27.31 raise XendError("unknown device type: " + type) 27.32 - return klass.createDevController(vm, recreate=recreate) 27.33 + return cls.createDevController(vm, recreate=recreate) 27.34 27.35 def getDevControllerTable(): 27.36 """Singleton constructor for the controller table. 27.37 @@ -138,11 +139,11 @@ def getDevControllerTable(): 27.38 devControllerTable = DevControllerTable() 27.39 return devControllerTable 27.40 27.41 -def addDevControllerClass(name, klass): 27.42 +def addDevControllerClass(name, cls): 27.43 """Add a device controller class to the controller table. 27.44 """ 27.45 - klass.name = name 27.46 - getDevControllerTable().addDevControllerClass(klass) 27.47 + cls.type = name 27.48 + getDevControllerTable().addDevControllerClass(cls) 27.49 27.50 def createDevController(name, vm, recreate=False): 27.51 return getDevControllerTable().createDevController(name, vm, recreate=recreate) 27.52 @@ -155,29 +156,57 @@ class DevController: 27.53 27.54 """ 27.55 27.56 - name = None 27.57 + # State: 27.58 + # controller/<type> : for controller 27.59 + # device/<type>/<id> : for each device 27.60 27.61 - def createDevController(klass, vm, recreate=False): 27.62 + def createDevController(cls, vm, recreate=False): 27.63 """Class method to create a dev controller. 27.64 """ 27.65 - ctrl = klass(vm, recreate=recreate) 27.66 + ctrl = cls(vm, recreate=recreate) 27.67 ctrl.initController(recreate=recreate) 27.68 + ctrl.exportToDB() 27.69 return ctrl 27.70 27.71 createDevController = classmethod(createDevController) 27.72 27.73 - def getType(klass): 27.74 - return klass.name 27.75 + def getType(cls): 27.76 + return cls.type 27.77 27.78 getType = classmethod(getType) 27.79 27.80 + __exports__ = [ 27.81 + DBVar('type', 'str'), 27.82 + DBVar('destroyed', 'bool'), 27.83 + ] 27.84 + 27.85 + # Set when registered. 27.86 + type = None 27.87 + 27.88 def __init__(self, vm, recreate=False): 27.89 self.destroyed = False 27.90 self.vm = vm 27.91 + self.db = self.getDB() 27.92 self.deviceId = 0 27.93 self.devices = {} 27.94 self.device_order = [] 27.95 27.96 + def getDB(self): 27.97 + """Get the db node to use for a controller. 27.98 + """ 27.99 + return self.vm.db.addChild("/controller/%s" % self.getType()) 27.100 + 27.101 + def getDevDB(self, id): 27.102 + """Get the db node to use for a device. 27.103 + """ 27.104 + return self.vm.db.addChild("/device/%s/%s" % (self.getType(), id)) 27.105 + 27.106 + def exportToDB(self, save=False): 27.107 + self.db.exportToDB(self, fields=self.__exports__, save=save) 27.108 + 27.109 + def importFromDB(self): 27.110 + self.db.importFromDB(self, fields=self.__exports__) 27.111 + 27.112 def getDevControllerType(self): 27.113 return self.dctype 27.114 27.115 @@ -229,18 +258,19 @@ class DevController: 27.116 i.e. it is being added at runtime rather than when the domain is created. 27.117 """ 27.118 dev = self.newDevice(self.nextDeviceId(), config, recreate=recreate) 27.119 + if self.vm.recreate: 27.120 + dev.importFromDB() 27.121 dev.init(recreate=recreate) 27.122 self.addDevice(dev) 27.123 - idx = self.getDeviceIndex(dev) 27.124 - recreate = self.vm.get_device_recreate(self.getType(), idx) 27.125 + if not recreate: 27.126 + dev.exportToDB() 27.127 dev.attach(recreate=recreate, change=change) 27.128 + dev.exportToDB() 27.129 27.130 def configureDevice(self, id, config, change=False): 27.131 """Reconfigure an existing device. 27.132 May be defined in subclass.""" 27.133 - dev = self.getDevice(id) 27.134 - if not dev: 27.135 - raise XendError("invalid device id: " + id) 27.136 + dev = self.getDevice(id, error=True) 27.137 dev.configure(config, change=change) 27.138 27.139 def destroyDevice(self, id, change=False, reboot=False): 27.140 @@ -251,9 +281,7 @@ class DevController: 27.141 27.142 The device is not deleted, since it may be recreated later. 27.143 """ 27.144 - dev = self.getDevice(id) 27.145 - if not dev: 27.146 - raise XendError("invalid device id: " + id) 27.147 + dev = self.getDevice(id, error=True) 27.148 dev.destroy(change=change, reboot=reboot) 27.149 return dev 27.150 27.151 @@ -278,24 +306,15 @@ class DevController: 27.152 def isDestroyed(self): 27.153 return self.destroyed 27.154 27.155 - def getDevice(self, id): 27.156 - return self.devices.get(id) 27.157 - 27.158 - def getDeviceByIndex(self, idx): 27.159 - if 0 <= idx < len(self.device_order): 27.160 - return self.device_order[idx] 27.161 - else: 27.162 - return None 27.163 - 27.164 - def getDeviceIndex(self, dev): 27.165 - return self.device_order.index(dev) 27.166 + def getDevice(self, id, error=False): 27.167 + dev = self.devices.get(id) 27.168 + if error and not dev: 27.169 + raise XendError("invalid device id: " + id) 27.170 + return dev 27.171 27.172 def getDeviceIds(self): 27.173 return [ dev.getId() for dev in self.device_order ] 27.174 27.175 - def getDeviceIndexes(self): 27.176 - return range(0, len(self.device_order)) 27.177 - 27.178 def getDevices(self): 27.179 return self.device_order 27.180 27.181 @@ -353,11 +372,42 @@ class Dev: 27.182 @type controller: DevController 27.183 """ 27.184 27.185 + # ./status : need 2: actual and requested? 27.186 + # down-down: initial. 27.187 + # up-up: fully up. 27.188 + # down-up: down requested, still up. Watch front and back, when both 27.189 + # down go to down-down. But what if one (or both) is not connected? 27.190 + # Still have front/back trees with status? Watch front/status, back/status? 27.191 + # up-down: up requested, still down. 27.192 + # Back-end watches ./status, front/status 27.193 + # Front-end watches ./status, back/status 27.194 + # i.e. each watches the other 2. 27.195 + # Each is status/request status/actual? 27.196 + # 27.197 + # backend? 27.198 + # frontend? 27.199 + 27.200 + __exports__ = [ 27.201 + DBVar('id', ty='int'), 27.202 + DBVar('type', ty='str'), 27.203 + DBVar('config', ty='sxpr'), 27.204 + DBVar('destroyed', ty='bool'), 27.205 + ] 27.206 + 27.207 def __init__(self, controller, id, config, recreate=False): 27.208 self.controller = controller 27.209 self.id = id 27.210 self.config = config 27.211 self.destroyed = False 27.212 + self.type = self.getType() 27.213 + 27.214 + self.db = controller.getDevDB(id) 27.215 + 27.216 + def exportToDB(self, save=False): 27.217 + self.db.exportToDB(self, fields=self.__exports__, save=save) 27.218 + 27.219 + def importFromDB(self): 27.220 + self.db.importFromDB(self, fields=self.__exports__) 27.221 27.222 def getDomain(self): 27.223 return self.controller.getDomain() 27.224 @@ -380,9 +430,6 @@ class Dev: 27.225 def getId(self): 27.226 return self.id 27.227 27.228 - def getIndex(self): 27.229 - return self.controller.getDeviceIndex(self) 27.230 - 27.231 def getConfig(self): 27.232 return self.config 27.233
28.1 --- a/tools/python/xen/xend/server/netif.py Thu Jun 09 14:07:02 2005 +0000 28.2 +++ b/tools/python/xen/xend/server/netif.py Thu Jun 09 14:40:39 2005 +0000 28.3 @@ -4,21 +4,75 @@ 28.4 28.5 import random 28.6 28.7 +from xen.util.mac import macFromString, macToString 28.8 + 28.9 from xen.xend import sxp 28.10 from xen.xend import Vifctl 28.11 from xen.xend.XendError import XendError, VmError 28.12 from xen.xend.XendLogging import log 28.13 from xen.xend import XendVnet 28.14 from xen.xend.XendRoot import get_component 28.15 +from xen.xend.xenstore import DBVar 28.16 28.17 -import channel 28.18 -from controller import CtrlMsgRcvr, Dev, DevController 28.19 -from messages import * 28.20 +from xen.xend.server import channel 28.21 +from xen.xend.server.controller import CtrlMsgRcvr, Dev, DevController 28.22 +from xen.xend.server.messages import * 28.23 28.24 class NetDev(Dev): 28.25 """A network device. 28.26 """ 28.27 28.28 + # State: 28.29 + # inherited + 28.30 + # ./config 28.31 + # ./mac 28.32 + # ./be_mac 28.33 + # ./bridge 28.34 + # ./script 28.35 + # ./ipaddr ? 28.36 + # 28.37 + # ./credit 28.38 + # ./period 28.39 + # 28.40 + # ./vifctl: up/down? 28.41 + # ./vifname 28.42 + # 28.43 + # 28.44 + # Poss should have no backend state here - except for ref to backend's own tree 28.45 + # for the device? And a status - the one we want. 28.46 + # ./back/dom 28.47 + # ./back/devid - id for back-end (netif_handle) - same as front/devid 28.48 + # ./back/id - backend id (if more than one b/e per domain) 28.49 + # ./back/status 28.50 + # ./back/tx_shmem_frame - actually these belong in back-end state 28.51 + # ./back/rx_shmem_frame 28.52 + # 28.53 + # ./front/dom 28.54 + # ./front/devid 28.55 + # ./front/status - need 2: one for requested, one for actual? Or drive from dev status 28.56 + # and this is front status only. 28.57 + # ./front/tx_shmem_frame 28.58 + # ./front/rx_shmem_frame 28.59 + # 28.60 + # ./evtchn/front - here or in front/back? 28.61 + # ./evtchn/back 28.62 + # ./evtchn/status ? 28.63 + # At present created by dev: but should be created unbound by front/back 28.64 + # separately and then bound (by back)? 28.65 + 28.66 + __exports__ = Dev.__exports__ + [ 28.67 + DBVar('config', ty='sxpr'), 28.68 + DBVar('mac', ty='mac'), 28.69 + DBVar('be_mac', ty='mac'), 28.70 + DBVar('bridge', ty='str'), 28.71 + DBVar('script', ty='str'), 28.72 + #DBVar('ipaddr'), 28.73 + DBVar('credit', ty='int'), 28.74 + DBVar('period', ty='int'), 28.75 + DBVar('vifname', ty='str'), 28.76 + DBVar('evtchn'), #todo: export fields (renamed) 28.77 + ] 28.78 + 28.79 def __init__(self, controller, id, config, recreate=False): 28.80 Dev.__init__(self, controller, id, config, recreate=recreate) 28.81 self.vif = int(self.id) 28.82 @@ -49,15 +103,19 @@ class NetDev(Dev): 28.83 def _get_config_mac(self, config): 28.84 vmac = sxp.child_value(config, 'mac') 28.85 if not vmac: return None 28.86 - mac = [ int(x, 16) for x in vmac.split(':') ] 28.87 - if len(mac) != 6: raise XendError("invalid mac: %s" % vmac) 28.88 + try: 28.89 + mac = macFromString(vmac) 28.90 + except: 28.91 + raise XendError("invalid mac: %s" % vmac) 28.92 return mac 28.93 28.94 def _get_config_be_mac(self, config): 28.95 vmac = sxp.child_value(config, 'be_mac') 28.96 if not vmac: return None 28.97 - mac = [ int(x, 16) for x in vmac.split(':') ] 28.98 - if len(mac) != 6: raise XendError("invalid backend mac: %s" % vmac) 28.99 + try: 28.100 + mac = macFromString(vmac) 28.101 + except: 28.102 + raise XendError("invalid backend mac: %s" % vmac) 28.103 return mac 28.104 28.105 def _get_config_ipaddr(self, config): 28.106 @@ -102,7 +160,7 @@ class NetDev(Dev): 28.107 else: 28.108 #todo: Code below will fail on xend restart when backend is not domain 0. 28.109 xd = get_component('xen.xend.XendDomain') 28.110 - self.backendDomain = int(xd.domain_lookup(sxp.child_value(config, 'backend', '0')).id) 28.111 + self.backendDomain = xd.domain_lookup_by_name(sxp.child_value(config, 'backend', '0')).id 28.112 except: 28.113 raise XendError('invalid backend domain') 28.114 return self.config 28.115 @@ -127,13 +185,13 @@ class NetDev(Dev): 28.116 ipaddr = self._get_config_ipaddr(config) 28.117 28.118 xd = get_component('xen.xend.XendDomain') 28.119 - backendDomain = str(xd.domain_lookup(sxp.child_value(config, 'backend', '0')).id) 28.120 + backendDomain = xd.domain_lookup_by_name(sxp.child_value(config, 'backend', '0')).id 28.121 28.122 if (mac is not None) and (mac != self.mac): 28.123 raise XendError("cannot change mac") 28.124 if (be_mac is not None) and (be_mac != self.be_mac): 28.125 raise XendError("cannot change backend mac") 28.126 - if (backendDomain is not None) and (backendDomain != str(self.backendDomain)): 28.127 + if (backendDomain is not None) and (backendDomain != self.backendDomain): 28.128 raise XendError("cannot change backend") 28.129 if (bridge is not None) and (bridge != self.bridge): 28.130 changes['bridge'] = bridge 28.131 @@ -199,7 +257,6 @@ class NetDev(Dev): 28.132 val.append(['evtchn', 28.133 self.evtchn['port1'], 28.134 self.evtchn['port2']]) 28.135 - val.append(['index', self.getIndex()]) 28.136 return val 28.137 28.138 def get_vifname(self): 28.139 @@ -213,12 +270,12 @@ class NetDev(Dev): 28.140 def get_mac(self): 28.141 """Get the MAC address as a string. 28.142 """ 28.143 - return ':'.join(map(lambda x: "%02x" % x, self.mac)) 28.144 + return macToString(self.mac) 28.145 28.146 def get_be_mac(self): 28.147 """Get the backend MAC address as a string. 28.148 """ 28.149 - return ':'.join(map(lambda x: "%02x" % x, self.be_mac)) 28.150 + return macToString(self.be_mac) 28.151 28.152 def vifctl_params(self, vmname=None): 28.153 """Get the parameters to pass to vifctl. 28.154 @@ -230,7 +287,7 @@ class NetDev(Dev): 28.155 vm = xd.domain_lookup(dom) 28.156 vmname = vm.name 28.157 except: 28.158 - vmname = 'DOM%d' % dom 28.159 + vmname = 'Domain-%d' % dom 28.160 return { 'domain': vmname, 28.161 'vif' : self.get_vifname(), 28.162 'mac' : self.get_mac(),
29.1 --- a/tools/python/xen/xend/server/params.py Thu Jun 09 14:07:02 2005 +0000 29.2 +++ b/tools/python/xen/xend/server/params.py Thu Jun 09 14:40:39 2005 +0000 29.3 @@ -1,6 +1,34 @@ 29.4 +import os 29.5 + 29.6 +def getenv(var, val, conv=None): 29.7 + """Get a value from the environment, with optional conversion. 29.8 + 29.9 + @param var name of environment variable 29.10 + @param val default value 29.11 + @param conv conversion function to apply to env value 29.12 + @return converted value or default 29.13 + """ 29.14 + try: 29.15 + v = os.getenv(var) 29.16 + if v is None: 29.17 + v = val 29.18 + else: 29.19 + print var, '=', v 29.20 + if conv: 29.21 + v = conv(v) 29.22 + except: 29.23 + v = val 29.24 + return v 29.25 + 29.26 # The following parameters could be placed in a configuration file. 29.27 -XEND_PID_FILE = '/var/run/xend.pid' 29.28 -XEND_TRACE_FILE = '/var/log/xend.trace' 29.29 +XEND_PID_FILE = '/var/run/xend.pid' 29.30 +XEND_TRACE_FILE = '/var/log/xend.trace' 29.31 +XEND_DEBUG_LOG = '/var/log/xend-debug.log' 29.32 +XEND_USER = 'root' 29.33 +XEND_DEBUG = getenv("XEND_DEBUG", 0, conv=int) 29.34 +XEND_DAEMONIZE = getenv("XEND_DAEMONIZE", not XEND_DEBUG, conv=int) 29.35 29.36 -XEND_USER = 'root' 29.37 - 29.38 +XENSTORED_PID_FILE = '/var/run/xenstored.pid' 29.39 +XENSTORED_RUN_DIR = '/var/run/xenstored' 29.40 +XENSTORED_LIB_DIR = '/var/lib/xenstored' 29.41 +XENSTORED_DEBUG = getenv("XENSTORED_DEBUG", 0, conv=int)
30.1 --- a/tools/python/xen/xend/server/usbif.py Thu Jun 09 14:07:02 2005 +0000 30.2 +++ b/tools/python/xen/xend/server/usbif.py Thu Jun 09 14:40:39 2005 +0000 30.3 @@ -7,10 +7,11 @@ 30.4 from xen.xend import sxp 30.5 from xen.xend.XendLogging import log 30.6 from xen.xend.XendError import XendError 30.7 +from xen.xend.xenstore import DBVar 30.8 30.9 -import channel 30.10 -from controller import Dev, DevController 30.11 -from messages import * 30.12 +from xen.xend.server import channel 30.13 +from xen.xend.server.controller import Dev, DevController 30.14 +from xen.xend.server.messages import * 30.15 30.16 class UsbBackend: 30.17 """Handler for the 'back-end' channel to a USB device driver domain 30.18 @@ -141,6 +142,11 @@ class UsbBackend: 30.19 30.20 30.21 class UsbDev(Dev): 30.22 + 30.23 + __exports__ = Dev.__exports__ + [ 30.24 + DBVar('port', ty='int'), 30.25 + DBVar('path', ty='str'), 30.26 + ] 30.27 30.28 def __init__(self, controller, id, config, recreate=False): 30.29 Dev.__init__(self, controller, id, config, recreate=recreate) 30.30 @@ -186,7 +192,6 @@ class UsbDev(Dev): 30.31 ['port', self.port], 30.32 ['path', self.path], 30.33 ] 30.34 - val.append(['index', self.getIndex()]) 30.35 return val 30.36 30.37 def getBackend(self):
31.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 31.2 +++ b/tools/python/xen/xend/uuid.py Thu Jun 09 14:40:39 2005 +0000 31.3 @@ -0,0 +1,65 @@ 31.4 +"""Universal(ly) Unique Identifiers (UUIDs). 31.5 +""" 31.6 +import commands 31.7 +import random 31.8 + 31.9 +def uuidgen(random=True): 31.10 + """Generate a UUID using the command uuidgen. 31.11 + 31.12 + If random is true (default) generates a random uuid. 31.13 + If random is false generates a time-based uuid. 31.14 + """ 31.15 + cmd = "uuidgen" 31.16 + if random: 31.17 + cmd += " -r" 31.18 + else: 31.19 + cmd += " -t" 31.20 + return commands.getoutput(cmd) 31.21 + 31.22 +class UuidFactoryUuidgen: 31.23 + 31.24 + """A uuid factory using uuidgen.""" 31.25 + 31.26 + def __init__(self): 31.27 + pass 31.28 + 31.29 + def getUuid(self): 31.30 + return uuidgen() 31.31 + 31.32 +class UuidFactoryRandom: 31.33 + 31.34 + """A random uuid factory.""" 31.35 + 31.36 + def __init__(self): 31.37 + f = file("/dev/urandom", "r") 31.38 + seed = f.read(16) 31.39 + f.close() 31.40 + self.rand = random.Random(seed) 31.41 + 31.42 + def randBytes(self, n): 31.43 + return [ self.rand.randint(0, 255) for i in range(0, n) ] 31.44 + 31.45 + def getUuid(self): 31.46 + bytes = self.randBytes(16) 31.47 + # Encode the variant. 31.48 + bytes[6] = (bytes[6] & 0x0f) | 0x40 31.49 + bytes[8] = (bytes[8] & 0x3f) | 0x80 31.50 + f = "%02x" 31.51 + return ( "-".join([f*4, f*2, f*2, f*2, f*6]) % tuple(bytes) ) 31.52 + 31.53 +def getFactory(): 31.54 + """Get the factory to use for creating uuids. 31.55 + This is so it's easy to change the uuid factory. 31.56 + For example, for testing we might want repeatable uuids 31.57 + rather than the random ones we normally use. 31.58 + """ 31.59 + global uuidFactory 31.60 + try: 31.61 + uuidFactory 31.62 + except: 31.63 + #uuidFactory = UuidFactoryUuidgen() 31.64 + uuidFactory = UuidFactoryRandom() 31.65 + return uuidFactory 31.66 + 31.67 +def getUuid(): 31.68 + return getFactory().getUuid()
32.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 32.2 +++ b/tools/python/xen/xend/xenstore/__init__.py Thu Jun 09 14:40:39 2005 +0000 32.3 @@ -0,0 +1,2 @@ 32.4 +from xsnode import * 32.5 +from xsobj import *
33.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 33.2 +++ b/tools/python/xen/xend/xenstore/xsnode.py Thu Jun 09 14:40:39 2005 +0000 33.3 @@ -0,0 +1,382 @@ 33.4 +import errno 33.5 +import os 33.6 +import os.path 33.7 +import select 33.8 +import sys 33.9 +import time 33.10 + 33.11 +from xen.lowlevel import xs 33.12 +from xen.xend import sxp 33.13 +from xen.xend.PrettyPrint import prettyprint 33.14 + 33.15 +SELECT_TIMEOUT = 2.0 33.16 + 33.17 +def getEventPath(event): 33.18 + return os.path.join("/_event", event) 33.19 + 33.20 +def getEventIdPath(event): 33.21 + return os.path.join(eventPath(event), "@eid") 33.22 + 33.23 +class Subscription: 33.24 + 33.25 + def __init__(self, event, fn, id): 33.26 + self.event = event 33.27 + self.watcher = None 33.28 + self.fn = fn 33.29 + self.id = id 33.30 + 33.31 + def watch(self, watcher): 33.32 + self.watcher = watcher 33.33 + watcher.addSubs(self) 33.34 + 33.35 + def unwatch(self): 33.36 + watcher = self.watcher 33.37 + if watcher: 33.38 + self.watcher = None 33.39 + watcher.delSubs(self) 33.40 + 33.41 + def notify(self, event): 33.42 + try: 33.43 + self.fn(event, id) 33.44 + except SystemExitException: 33.45 + raise 33.46 + except: 33.47 + pass 33.48 + 33.49 +class Watcher: 33.50 + 33.51 + def __init__(self, store, event): 33.52 + self.path = getEventPath(event) 33.53 + self.eidPath = getEventIdPath(event) 33.54 + store.mkdirs(self.path) 33.55 + if not store.exists(self.eidPath): 33.56 + store.writeInt(self.eidPath, 0) 33.57 + self.xs = None 33.58 + self.subs = [] 33.59 + 33.60 + def __getattr__(self, k, v): 33.61 + if k == "fileno": 33.62 + if self.xs: 33.63 + return self.xs.fileno 33.64 + else: 33.65 + return -1 33.66 + else: 33.67 + return self.__dict__.get(k, v) 33.68 + 33.69 + def addSubs(self, subs): 33.70 + self.subs.append(subs) 33.71 + self.watch() 33.72 + 33.73 + def delSubs(self, subs): 33.74 + self.subs.remove(subs) 33.75 + if len(self.subs) == 0: 33.76 + self.unwatch() 33.77 + 33.78 + def getEvent(self): 33.79 + return self.event 33.80 + 33.81 + def watch(self): 33.82 + if self.xs: return 33.83 + self.xs = xs.open() 33.84 + self.xs.watch(path) 33.85 + 33.86 + def unwatch(self): 33.87 + if self.xs: 33.88 + self.xs.unwatch(self.path) 33.89 + self.xs.close() 33.90 + self.xs = None 33.91 + 33.92 + def watching(self): 33.93 + return self.xs is not None 33.94 + 33.95 + def getNotification(self): 33.96 + p = self.xs.read_watch() 33.97 + self.xs.acknowledge_watch() 33.98 + eid = self.xs.readInt(self.eidPath) 33.99 + return p 33.100 + 33.101 + def notify(self, subs): 33.102 + p = self.getNotification() 33.103 + for s in subs: 33.104 + s.notify(p) 33.105 + 33.106 +class XenStore: 33.107 + 33.108 + def __init__(self): 33.109 + self.xs = None 33.110 + #self.xs = xs.open() 33.111 + self.subscription = {} 33.112 + self.subscription_id = 0 33.113 + self.events = {} 33.114 + self.write("/", "") 33.115 + 33.116 + def getxs(self): 33.117 + if self.xs is None: 33.118 + ex = None 33.119 + for i in range(0,20): 33.120 + try: 33.121 + self.xs = xs.open() 33.122 + ex = None 33.123 + break 33.124 + except Exception, ex: 33.125 + print >>stderr, "Exception connecting to xsdaemon:", ex 33.126 + print >>stderr, "Trying again..." 33.127 + time.sleep(1) 33.128 + else: 33.129 + raise ex 33.130 + 33.131 + #todo would like to reconnect if xs conn closes (e.g. daemon restart). 33.132 + return self.xs 33.133 + 33.134 + def dump(self, path="/", out=sys.stdout): 33.135 + print 'dump>', path 33.136 + val = ['node'] 33.137 + val.append(['path', path]) 33.138 +## perms = ['perms'] 33.139 +## for p in self.getPerms(path): 33.140 +## l = ['perm'] 33.141 +## l.append('dom', p.get['dom']) 33.142 +## for k in ['read', 'write', 'create', 'owner']: 33.143 +## v = p.get(k) 33.144 +## l.append([k, v]) 33.145 +## perms.append(l) 33.146 +## val.append(perms) 33.147 + data = self.read(path) 33.148 + if data: 33.149 + val.append(['data', data]) 33.150 + children = ['children'] 33.151 + for x in self.lsPaths(path): 33.152 + print 'dump>', 'child=', x 33.153 + children.append(self.dump(x)) 33.154 + if len(children) > 1: 33.155 + val.append(children) 33.156 + prettyprint(val, out=out) 33.157 + return val 33.158 + 33.159 + def getPerms(self, path): 33.160 + return self.getxs().get_permissions(path) 33.161 + 33.162 + def ls(self, path="/"): 33.163 + return self.getxs().ls(path) 33.164 + 33.165 + def lsPaths(self, path="/"): 33.166 + return [ os.path.join(path, x) for x in self.ls(path) ] 33.167 + 33.168 + def lsr(self, path="/", list=None): 33.169 + if list is None: 33.170 + list = [] 33.171 + list.append(path) 33.172 + for x in self.lsPaths(path): 33.173 + list.append(x) 33.174 + self.lsr(x, list=list) 33.175 + return list 33.176 + 33.177 + def rm(self, path): 33.178 + try: 33.179 + #for x in self.lsPaths(): 33.180 + # self.getxs().rm(x) 33.181 + self.getxs().rm(path) 33.182 + except: 33.183 + pass 33.184 + 33.185 + def exists(self, path): 33.186 + try: 33.187 + self.getxs().ls(path) 33.188 + return True 33.189 + except RuntimeError, ex: 33.190 + if ex.args[0] == errno.ENOENT: 33.191 + return False 33.192 + else: 33.193 + raise 33.194 + 33.195 + def mkdirs(self, path): 33.196 + if self.exists(path): 33.197 + return 33.198 + elts = path.split("/") 33.199 + p = "/" 33.200 + for x in elts: 33.201 + if x == "": continue 33.202 + p = os.path.join(p, x) 33.203 + if not self.exists(p): 33.204 + self.getxs().write(p, "", create=True) 33.205 + 33.206 + def read(self, path): 33.207 + try: 33.208 + return self.getxs().read(path) 33.209 + except RuntimeError, ex: 33.210 + if ex.args[0] == errno.EISDIR: 33.211 + return None 33.212 + else: 33.213 + raise 33.214 + 33.215 + def create(self, path, excl=False): 33.216 + self.write(path, "", create=True, excl=excl) 33.217 + 33.218 + def write(self, path, data, create=True, excl=False): 33.219 + self.mkdirs(path) 33.220 + self.getxs().write(path, data, create=create, excl=excl) 33.221 + 33.222 + def begin(self, path): 33.223 + self.getxs().begin_transaction(path) 33.224 + 33.225 + def commit(self, abandon=False): 33.226 + self.getxs().end_transaction(abort=abandon) 33.227 + 33.228 + def subscribe(self, event, fn): 33.229 + watcher = self.watchEvent(event) 33.230 + self.subscription_id += 1 33.231 + subs = Subscription(event, fn, self.subscription_id) 33.232 + self.subscription[subs.id] = subs 33.233 + subs.watch(watcher) 33.234 + return subs.id 33.235 + 33.236 + def unsubscribe(self, sid): 33.237 + s = self.subscription.get(sid) 33.238 + if not s: return 33.239 + del self.subscription[s.id] 33.240 + s.unwatch() 33.241 + unwatchEvent(s.event) 33.242 + 33.243 + def sendEvent(self, event, data): 33.244 + eventPath = getEventPath(event) 33.245 + eidPath = getEventIdPath(event) 33.246 + try: 33.247 + self.begin(eventPath) 33.248 + self.mkdirs(eventPath) 33.249 + if self.exists(eidPath): 33.250 + eid = self.readInt(eidPath) 33.251 + eid += 1 33.252 + else: 33.253 + eid = 1 33.254 + self.writeInt(eidPath, eid) 33.255 + self.write(os.path.join(eventPath, str(eid)), data) 33.256 + finally: 33.257 + self.commit() 33.258 + 33.259 + def watchEvent(self, event): 33.260 + if event in self.events: 33.261 + return 33.262 + watcher = Watcher(event) 33.263 + self.watchers[watcher.getEvent()] = watcher 33.264 + self.watchStart() 33.265 + return watcher 33.266 + 33.267 + def unwatchEvent(self, event): 33.268 + watcher = self.watchers.get(event) 33.269 + if not watcher: 33.270 + return 33.271 + if not watcher.watching(): 33.272 + del self.watchers[event] 33.273 + 33.274 + def watchStart(self): 33.275 + if self.watchThread: return 33.276 + 33.277 + def watchMain(self): 33.278 + try: 33.279 + while True: 33.280 + if self.watchThread is None: return 33.281 + if not self.events: 33.282 + return 33.283 + rd = self.watchers.values() 33.284 + try: 33.285 + (rd, wr, er) = select.select(rd, [], [], SELECT_TIMEOUT) 33.286 + for watcher in rd: 33.287 + watcher.notify() 33.288 + except socket.error, ex: 33.289 + if ex.args[0] in (EAGAIN, EINTR): 33.290 + pass 33.291 + else: 33.292 + raise 33.293 + finally: 33.294 + self.watchThread = None 33.295 + 33.296 + def introduceDomain(self, dom, page, evtchn, path): 33.297 + self.getxs().introduce_domain(dom, page, evtchn.port1, path) 33.298 + 33.299 + def releaseDomain(self, dom): 33.300 + self.getxs().release_domain(dom) 33.301 + 33.302 +def getXenStore(): 33.303 + global xenstore 33.304 + try: 33.305 + return xenstore 33.306 + except: 33.307 + xenstore = XenStore() 33.308 + return xenstore 33.309 + 33.310 +class XenNode: 33.311 + 33.312 + def __init__(self, path="/", create=True): 33.313 + self.store = getXenStore() 33.314 + self.path = path 33.315 + if not self.store.exists(path): 33.316 + if create: 33.317 + self.store.create(path) 33.318 + else: 33.319 + raise ValueError("path does not exist: '%s'" % path) 33.320 + 33.321 + def relPath(self, path=""): 33.322 + if not path: 33.323 + return self.path 33.324 + if path and path.startswith("/"): 33.325 + path = path[1:] 33.326 + return os.path.join(self.path, path) 33.327 + 33.328 + def delete(self, path=""): 33.329 + self.store.rm(self.relPath(path)) 33.330 + 33.331 + def exists(self, path=""): 33.332 + return self.store.exists(self.relPath(path)) 33.333 + 33.334 + def getNode(self, path="", create=True): 33.335 + if path == "": 33.336 + return self 33.337 + else: 33.338 + return XenNode(self.relPath(path=path), create=create) 33.339 + 33.340 + getChild = getNode 33.341 + 33.342 + def getData(self, path=""): 33.343 + path = self.relPath(path) 33.344 + try: 33.345 + return self.store.read(path) 33.346 + except: 33.347 + return None 33.348 + 33.349 + def setData(self, data, path=""): 33.350 + path = self.relPath(path) 33.351 + #print 'XenNode>setData>', 'path=', path, 'data=', data 33.352 + return self.store.write(path, data) 33.353 + 33.354 + def getLock(self): 33.355 + return None 33.356 + 33.357 + def lock(self, lockid): 33.358 + return None 33.359 + 33.360 + def unlock(self, lockid): 33.361 + return None 33.362 + 33.363 + def deleteChild(self, name): 33.364 + self.delete(name) 33.365 + 33.366 + def deleteChildren(self): 33.367 + for name in self.ls(): 33.368 + self.deleteChild(name) 33.369 + 33.370 + def getChildren(self): 33.371 + return [ self.getNode(name) for name in self.ls() ] 33.372 + 33.373 + def ls(self): 33.374 + return self.store.ls(self.path) 33.375 + 33.376 + def introduceDomain(self, dom, page, evtchn, path): 33.377 + self.store.introduceDomain(dom, page, evtchn, path) 33.378 + 33.379 + def releaseDomain(self, dom): 33.380 + self.store.releaseDomain(dom) 33.381 + 33.382 + def __repr__(self): 33.383 + return "<XenNode %s>" % self.path 33.384 + 33.385 +
34.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 34.2 +++ b/tools/python/xen/xend/xenstore/xsobj.py Thu Jun 09 14:40:39 2005 +0000 34.3 @@ -0,0 +1,522 @@ 34.4 +import string 34.5 +import types 34.6 + 34.7 +from xen.xend import sxp 34.8 +from xsnode import XenNode 34.9 +from xen.util.mac import macToString, macFromString 34.10 + 34.11 +VALID_KEY_CHARS = string.ascii_letters + string.digits + "_-@" 34.12 + 34.13 +def hasAttr(obj, attr): 34.14 + if isinstance(obj, dict): 34.15 + return obj.contains(attr) 34.16 + else: 34.17 + return hasattr(obj, attr) 34.18 + 34.19 +def getAttr(obj, attr): 34.20 + if isinstance(obj, dict): 34.21 + return dict.get(attr) 34.22 + else: 34.23 + return getattr(obj, attr, None) 34.24 + 34.25 +def setAttr(obj, attr, val): 34.26 + if isinstance(obj, dict): 34.27 + dict[attr] = val 34.28 + else: 34.29 + setattr(obj, attr, val) 34.30 + 34.31 +class DBConverter: 34.32 + """Conversion of values to and from strings in xenstore. 34.33 + """ 34.34 + 34.35 + converters = {} 34.36 + 34.37 + def checkType(cls, ty): 34.38 + if ty is None or ty in cls.converters: 34.39 + return 34.40 + raise ValueError("invalid converter type: '%s'" % ty) 34.41 + 34.42 + checkType = classmethod(checkType) 34.43 + 34.44 + def getConverter(cls, ty=None): 34.45 + if ty is None: 34.46 + ty = "str" 34.47 + conv = cls.converters.get(ty) 34.48 + if not conv: 34.49 + raise ValueError("no converter for type: '%s'" % ty) 34.50 + return conv 34.51 + 34.52 + getConverter = classmethod(getConverter) 34.53 + 34.54 + def convertToDB(cls, val, ty=None): 34.55 + return cls.getConverter(ty).toDB(val) 34.56 + 34.57 + convertToDB = classmethod(convertToDB) 34.58 + 34.59 + def convertFromDB(cls, val, ty=None): 34.60 + return cls.getConverter(ty).fromDB(val) 34.61 + 34.62 + convertFromDB = classmethod(convertFromDB) 34.63 + 34.64 + # Must define in subclass. 34.65 + name = None 34.66 + 34.67 + def __init__(self): 34.68 + self.register() 34.69 + 34.70 + def register(self): 34.71 + if not self.name: 34.72 + raise ValueError("invalid converter name: '%s'" % self.name) 34.73 + self.converters[self.name] = self 34.74 + 34.75 + def toDB(self, val): 34.76 + raise NotImplementedError() 34.77 + 34.78 + def fromDB(self, val): 34.79 + raise NotImplementedError() 34.80 + 34.81 +class StrConverter(DBConverter): 34.82 + 34.83 + name = "str" 34.84 + 34.85 + def toDB(self, val): 34.86 + # Convert True/False to 1/0, otherwise they convert to 34.87 + # 'True' and 'False' rather than '1' and '0', even though 34.88 + # isinstance(True/False, int) is true. 34.89 + if isinstance(val, bool): 34.90 + val = int(val) 34.91 + return str(val) 34.92 + 34.93 + def fromDB(self, data): 34.94 + return data 34.95 + 34.96 +StrConverter() 34.97 + 34.98 +class BoolConverter(DBConverter): 34.99 + 34.100 + name = "bool" 34.101 + 34.102 + def toDB(self, val): 34.103 + return str(int(bool(val))) 34.104 + 34.105 + def fromDB(self, data): 34.106 + return bool(int(data)) 34.107 + 34.108 +BoolConverter() 34.109 + 34.110 +class SxprConverter(DBConverter): 34.111 + 34.112 + name = "sxpr" 34.113 + 34.114 + def toDB(self, val): 34.115 + return sxp.to_string(val) 34.116 + 34.117 + def fromDB(self, data): 34.118 + return sxp.from_string(data) 34.119 + 34.120 +SxprConverter() 34.121 + 34.122 +class IntConverter(DBConverter): 34.123 + 34.124 + name = "int" 34.125 + 34.126 + def toDB(self, val): 34.127 + return str(int(val)) 34.128 + 34.129 + def fromDB(self, data): 34.130 + return int(data) 34.131 + 34.132 +IntConverter() 34.133 + 34.134 +class FloatConverter(DBConverter): 34.135 + 34.136 + name = "float" 34.137 + 34.138 + def toDB(self, val): 34.139 + return str(float(val)) 34.140 + 34.141 + def fromDB(self, data): 34.142 + return float(data) 34.143 + 34.144 +FloatConverter() 34.145 + 34.146 +class LongConverter(DBConverter): 34.147 + 34.148 + name = "long" 34.149 + 34.150 + def toDB(self, val): 34.151 + return str(long(val)) 34.152 + 34.153 + def fromDB(self, data): 34.154 + return long(data) 34.155 + 34.156 +LongConverter() 34.157 + 34.158 +class MacConverter(DBConverter): 34.159 + 34.160 + name = "mac" 34.161 + 34.162 + def toDB(self, val): 34.163 + return macToString(val) 34.164 + 34.165 + def fromDB(self, data): 34.166 + return macFromString(data) 34.167 + 34.168 +MacConverter() 34.169 + 34.170 +class DBVar: 34.171 + 34.172 + def __init__(self, var, ty=None, path=None): 34.173 + DBConverter.checkType(ty) 34.174 + if path is None: 34.175 + path = var 34.176 + self.var = var 34.177 + self.ty = ty 34.178 + self.path = path 34.179 + varpath = filter(bool, self.var.split()) 34.180 + self.attrpath = varpath[:-1] 34.181 + self.attr = varpath[-1] 34.182 + 34.183 + def exportToDB(self, db, obj): 34.184 + self.setDB(db, self.getObj(obj)) 34.185 + 34.186 + def importFromDB(self, db, obj): 34.187 + self.setObj(obj, self.getDB(db)) 34.188 + 34.189 + def getObj(self, obj): 34.190 + o = obj 34.191 + for x in self.attrpath: 34.192 + o = getAttr(o, x) 34.193 + if o is None: 34.194 + return None 34.195 + return getAttr(o, self.attr) 34.196 + 34.197 + def setObj(self, obj, val): 34.198 + o = obj 34.199 + for x in self.attrpath: 34.200 + o = getAttr(o, x) 34.201 + # Don't set obj attr if val is None. 34.202 + if val is None and hasAttr(o, self.attr): 34.203 + return 34.204 + setAttr(o, self.attr, val) 34.205 + 34.206 + def getDB(self, db): 34.207 + try: 34.208 + data = getattr(db, self.path) 34.209 + except AttributeError: 34.210 + return None 34.211 + return DBConverter.convertFromDB(data, ty=self.ty) 34.212 + 34.213 + def setDB(self, db, val): 34.214 + # Don't set in db if val is None. 34.215 + #print 'DBVar>setDB>', self.path, 'val=', val 34.216 + if val is None: 34.217 + return 34.218 + data = DBConverter.convertToDB(val, ty=self.ty) 34.219 + #print 'DBVar>setDB>', self.path, 'data=', data 34.220 + setattr(db, self.path, data) 34.221 + 34.222 + 34.223 +class DBMap(dict): 34.224 + """A persistent map. Extends dict with persistence. 34.225 + Set and get values using the usual map syntax: 34.226 + 34.227 + m[k], m.get(k) 34.228 + m[k] = v 34.229 + 34.230 + Also supports being treated as an object with attributes. 34.231 + When 'k' is a legal identifier you may also use 34.232 + 34.233 + m.k, getattr(m, k) 34.234 + m.k = v, setattr(m, k) 34.235 + k in m, hasattr(m, k) 34.236 + 34.237 + When setting you can pass in a normal value, for example 34.238 + 34.239 + m.x = 3 34.240 + 34.241 + Getting works too: 34.242 + 34.243 + m.x ==> 3 34.244 + 34.245 + while m['x'] will return the map for x. 34.246 + 34.247 + m['x'].getData() ==> 3 34.248 + 34.249 + To get values from subdirs use get() to get the subdir first: 34.250 + 34.251 + get(m, 'foo').x 34.252 + m['foo'].x 34.253 + 34.254 + instead of m.foo.x, because m.foo will return the data for field foo, 34.255 + not the directory. 34.256 + 34.257 + You can assign values into a subdir by passing a map: 34.258 + 34.259 + m.foo = {'x': 1, 'y':2 } 34.260 + 34.261 + You can also use paths as keys: 34.262 + 34.263 + m['foo/x'] = 1 34.264 + 34.265 + sets field x in subdir foo. 34.266 + 34.267 + """ 34.268 + 34.269 + __db__ = None 34.270 + __data__ = None 34.271 + __perms__ = None 34.272 + __parent__ = None 34.273 + __name__ = "" 34.274 + 34.275 + __transaction__ = False 34.276 + 34.277 + # True if value set since saved (or never saved). 34.278 + __dirty__ = True 34.279 + 34.280 + def __init__(self, parent=None, name="", db=None): 34.281 + if parent is None: 34.282 + self.__name__ = name 34.283 + else: 34.284 + if not isinstance(parent, DBMap): 34.285 + raise ValueError("invalid parent") 34.286 + self.__parent__ = parent 34.287 + self.__name__ = name 34.288 + db = self.__parent__.getChildDB(name) 34.289 + self.setDB(db) 34.290 + 34.291 + def getName(self): 34.292 + return self.__name__ 34.293 + 34.294 + def getPath(self): 34.295 + return self.__db__ and self.__db__.relPath() 34.296 + 34.297 + def introduceDomain(self, dom, page, evtchn, path=None): 34.298 + db = self.__db__ 34.299 + if path is None: 34.300 + path = db.relPath() 34.301 + print 'DBMap>introduceDomain>', dom, page, evtchn, path 34.302 + try: 34.303 + db.introduceDomain(dom, page, evtchn, path) 34.304 + except Exception, ex: 34.305 + import traceback 34.306 + traceback.print_exc() 34.307 + print 'DBMap>introduceDomain>', ex 34.308 + pass # todo: don't ignore 34.309 + 34.310 + def releaseDomain(self, dom): 34.311 + db = self.__db__ 34.312 + print 'DBMap>releaseDomain>', dom 34.313 + try: 34.314 + db.releaseDomain(dom) 34.315 + except Exception, ex: 34.316 + import traceback 34.317 + traceback.print_exc() 34.318 + print 'DBMap>releaseDomain>', ex 34.319 + pass # todo: don't ignore 34.320 + 34.321 + def transactionBegin(self): 34.322 + # Begin a transaction. 34.323 + pass 34.324 + 34.325 + def transactionCommit(self): 34.326 + # Commit writes to db. 34.327 + pass 34.328 + 34.329 + def transactionFail(self): 34.330 + # Fail a transaction. 34.331 + # We have changed values, what do we do? 34.332 + pass 34.333 + 34.334 + def watch(self, fn): 34.335 + pass 34.336 + 34.337 + def unwatch(self, watch): 34.338 + pass 34.339 + 34.340 + def checkName(self, k): 34.341 + if k == "": 34.342 + raise ValueError("invalid key, empty string") 34.343 + for c in k: 34.344 + if c in VALID_KEY_CHARS: continue 34.345 + raise ValueError("invalid key char '%s'" % c) 34.346 + 34.347 + def _setData(self, v): 34.348 + #print 'DBMap>_setData>', self.getPath(), 'data=', v 34.349 + if v != self.__data__: 34.350 + self.__dirty__ = True 34.351 + self.__data__ = v 34.352 + 34.353 + def setData(self, v): 34.354 + if isinstance(v, dict): 34.355 + for (key, val) in v.items(): 34.356 + self[key] = val 34.357 + else: 34.358 + self._setData(v) 34.359 + 34.360 + def getData(self): 34.361 + return self.__data__ 34.362 + 34.363 + def _set(self, k, v): 34.364 + dict.__setitem__(self, k, v) 34.365 + 34.366 + def _get(self, k): 34.367 + try: 34.368 + return dict.__getitem__(self, k) 34.369 + except: 34.370 + return None 34.371 + 34.372 + def _del(self, k, v): 34.373 + try: 34.374 + dict.__delitem__(self, k) 34.375 + except: 34.376 + pass 34.377 + 34.378 + def _contains(self, k): 34.379 + return dict.__contains__(self, k) 34.380 + 34.381 + def __setitem__(self, k, v, save=False): 34.382 + node = self.addChild(k) 34.383 + node.setData(v) 34.384 + if save: 34.385 + node.saveDB() 34.386 + 34.387 + def __getitem__(self, k): 34.388 + if self._contains(k): 34.389 + v = self._get(k) 34.390 + else: 34.391 + v = self.readChildDB(k) 34.392 + self._set(k, v) 34.393 + return v 34.394 + 34.395 + def __delitem__(self, k): 34.396 + self._del(k) 34.397 + self.deleteChildDB(k) 34.398 + 34.399 + def __repr__(self): 34.400 + if len(self): 34.401 + return dict.__repr__(self) 34.402 + else: 34.403 + return repr(self.__data__) 34.404 + 34.405 + def __setattr__(self, k, v): 34.406 + if k.startswith("__"): 34.407 + object.__setattr__(self, k, v) 34.408 + else: 34.409 + self.__setitem__(k, v, save=True) 34.410 + return v 34.411 + 34.412 + def __getattr__(self, k): 34.413 + if k.startswith("__"): 34.414 + v = object.__getattr__(self, k) 34.415 + else: 34.416 + try: 34.417 + v = self.__getitem__(k).getData() 34.418 + except LookupError, ex: 34.419 + raise AttributeError(ex.args) 34.420 + return v 34.421 + 34.422 + def __delattr__(self, k): 34.423 + return self.__delitem__(k) 34.424 + 34.425 + def delete(self): 34.426 + dict.clear(self) 34.427 + self.__data__ = None 34.428 + if self.__db__: 34.429 + self.__db__.delete() 34.430 + 34.431 + def clear(self): 34.432 + dict.clear(self) 34.433 + if self.__db__: 34.434 + self.__db__.deleteChildren() 34.435 + 34.436 + def getChild(self, k): 34.437 + return self._get(k) 34.438 + 34.439 + def getChildDB(self, k): 34.440 + self.checkName(k) 34.441 + return self.__db__ and self.__db__.getChild(k) 34.442 + 34.443 + def deleteChildDB(self, k): 34.444 + if self.__db__: 34.445 + self.__db__.deleteChild(k) 34.446 + 34.447 + def _addChild(self, k): 34.448 + kid = self._get(k) 34.449 + if kid is None: 34.450 + kid = DBMap(parent=self, name=k, db=self.getChildDB(k)) 34.451 + self._set(k, kid) 34.452 + return kid 34.453 + 34.454 + def addChild(self, path): 34.455 + l = path.split("/") 34.456 + n = self 34.457 + for x in l: 34.458 + if x == "": continue 34.459 + n = n._addChild(x) 34.460 + return n 34.461 + 34.462 + def setDB(self, db): 34.463 + if (db is not None) and not isinstance(db, XenNode): 34.464 + raise ValueError("invalid db") 34.465 + self.__db__ = db 34.466 + for (k, v) in self.items(): 34.467 + if v is None: continue 34.468 + if isinstance(v, DBMap): 34.469 + v._setDB(self.addChild(k), restore) 34.470 + 34.471 + def readDB(self): 34.472 + if self.__db__ is None: 34.473 + return 34.474 + self.__data__ = self.__db__.getData() 34.475 + for k in self.__db__.ls(): 34.476 + n = self.addChild(k) 34.477 + n.readDB() 34.478 + self.__dirty__ = False 34.479 + 34.480 + def readChildDB(self, k): 34.481 + if self.__db__ and (k in self.__db__.ls()): 34.482 + n = self.addChild(k) 34.483 + n.readDB() 34.484 + raise LookupError("invalid key '%s'" % k) 34.485 + 34.486 + def saveDB(self, sync=False, save=False): 34.487 + """Save unsaved data to db. 34.488 + If save or sync is true, saves whether dirty or not. 34.489 + If sync is true, removes db entries not in the map. 34.490 + """ 34.491 + 34.492 + if self.__db__ is None: 34.493 + #print 'DBMap>saveDB>',self.getPath(), 'no db' 34.494 + return 34.495 + # Write data. 34.496 + #print 'DBMap>saveDB>', self.getPath(), 'dirty=', self.__dirty__, 'data=', self.__data__ 34.497 + if ((self.__data__ is not None) 34.498 + and (sync or save or self.__dirty__)): 34.499 + self.__db__.setData(self.__data__) 34.500 + self.__dirty__ = False 34.501 + else: 34.502 + #print 'DBMap>saveDB>', self.getPath(), 'not written' 34.503 + pass 34.504 + # Write children. 34.505 + for (name, node) in self.items(): 34.506 + if not isinstance(node, DBMap): continue 34.507 + node.saveDB(sync=sync, save=save) 34.508 + # Remove db nodes not in children. 34.509 + if sync: 34.510 + for name in self.__db__.ls(): 34.511 + if name not in self: 34.512 + self.__db__.delete(name) 34.513 + 34.514 + def importFromDB(self, obj, fields): 34.515 + """Set fields in obj from db fields. 34.516 + """ 34.517 + for f in fields: 34.518 + f.importFromDB(self, obj) 34.519 + 34.520 + def exportToDB(self, obj, fields, save=False, sync=False): 34.521 + """Set fields in db from obj fields. 34.522 + """ 34.523 + for f in fields: 34.524 + f.exportToDB(self, obj) 34.525 + self.saveDB(save=save, sync=sync)
35.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 35.2 +++ b/tools/python/xen/xend/xenstore/xsresource.py Thu Jun 09 14:40:39 2005 +0000 35.3 @@ -0,0 +1,136 @@ 35.4 +#============================================================================ 35.5 +# Copyright (C) 2005 Mike Wray <mike.wray@hp.com> 35.6 +#============================================================================ 35.7 +# HTTP interface onto xenstore (read-only). 35.8 +# Mainly intended for testing. 35.9 + 35.10 +import os 35.11 +import os.path 35.12 + 35.13 +from xen.web.httpserver import HttpServer, UnixHttpServer 35.14 +from xen.web.SrvBase import SrvBase 35.15 +from xen.web.SrvDir import SrvDir 35.16 +from xen.xend.Args import FormFn 35.17 +from xen.xend.xenstore import XenNode 35.18 + 35.19 +def pathurl(req): 35.20 + url = req.prePathURL() 35.21 + if not url.endswith('/'): 35.22 + url += '/' 35.23 + return url 35.24 + 35.25 +def writelist(req, l): 35.26 + req.write('(') 35.27 + for k in l: 35.28 + req.write(' ' + k) 35.29 + req.write(')') 35.30 + 35.31 +def lsData(dbnode, req, url): 35.32 + v = dbnode.getData() 35.33 + if v is None: 35.34 + req.write('<p>No data') 35.35 + else: 35.36 + req.write('<p>Data: <pre>') 35.37 + req.write(str(v)) 35.38 + req.write('</pre>') 35.39 + v = dbnode.getLock() 35.40 + if v is None: 35.41 + req.write("<p>Unlocked") 35.42 + else: 35.43 + req.write("<p>Lock = %s" % v) 35.44 + 35.45 +def lsChildren(dbnode, req, url): 35.46 + l = dbnode.ls() 35.47 + if l: 35.48 + req.write('<p>Children: <ul>') 35.49 + for key in l: 35.50 + child = dbnode.getChild(key) 35.51 + data = child.getData() 35.52 + if data is None: data = "" 35.53 + req.write('<li><a href="%(url)s%(key)s">%(key)s</a> %(data)s</li>' 35.54 + % { "url": url, "key": key, "data": data }) 35.55 + req.write('</ul>') 35.56 + else: 35.57 + req.write('<p>No children') 35.58 + 35.59 + 35.60 +class DBDataResource(SrvBase): 35.61 + """Resource for the node data. 35.62 + """ 35.63 + 35.64 + def __init__(self, dbnode): 35.65 + SrvBase.__init__(self) 35.66 + self.dbnode = dbnode 35.67 + 35.68 + def render_GET(self, req): 35.69 + req.write('<html><head></head><body>') 35.70 + self.print_path(req) 35.71 + req.write("<pre>") 35.72 + req.write(self.getData() or self.getNoData()) 35.73 + req.write("</pre>") 35.74 + req.write('</body></html>') 35.75 + 35.76 + def getContentType(self): 35.77 + # Use content-type from metadata. 35.78 + return "text/plain" 35.79 + 35.80 + def getData(self): 35.81 + v = self.dbnode.getData() 35.82 + if v is None: return v 35.83 + return str(v) 35.84 + 35.85 + def getNoData(self): 35.86 + return "" 35.87 + 35.88 +class DBNodeResource(SrvDir): 35.89 + """Resource for a DB node. 35.90 + """ 35.91 + 35.92 + def __init__(self, dbnode): 35.93 + SrvDir.__init__(self) 35.94 + self.dbnode = dbnode 35.95 + 35.96 + def get(self, x): 35.97 + val = None 35.98 + if x == "__data__": 35.99 + val = DBDataResource(self.dbnode) 35.100 + else: 35.101 + if self.dbnode.exists(x): 35.102 + child = self.dbnode.getChild(x, create=False) 35.103 + else: 35.104 + child = None 35.105 + if child is not None: 35.106 + val = DBNodeResource(child) 35.107 + return val 35.108 + 35.109 + def render_POST(self, req): 35.110 + return self.perform(req) 35.111 + 35.112 + def ls(self, req, use_sxp=0): 35.113 + if use_sxp: 35.114 + writelist(req, self.dbnode.getChildren()) 35.115 + else: 35.116 + url = pathurl(req) 35.117 + req.write("<fieldset>") 35.118 + lsData(self.dbnode, req, url) 35.119 + lsChildren(self.dbnode, req, url) 35.120 + req.write("</fieldset>") 35.121 + 35.122 + def form(self, req): 35.123 + url = req.prePathURL() 35.124 + pass 35.125 + 35.126 +class DBRootResource(DBNodeResource): 35.127 + """Resource for the root of a DB. 35.128 + """ 35.129 + 35.130 + def __init__(self): 35.131 + DBNodeResource.__init__(self, XenNode()) 35.132 + 35.133 +def main(argv): 35.134 + root = SrvDir() 35.135 + root.putChild('xenstore', DBRootResource()) 35.136 + interface = '' 35.137 + port = 8003 35.138 + server = HttpServer(root=root, interface=interface, port=port) 35.139 + server.run()
36.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 36.2 +++ b/tools/xenstore/.gdbinit Thu Jun 09 14:40:39 2005 +0000 36.3 @@ -0,0 +1,4 @@ 36.4 +set environment XENSTORED_RUNDIR=testsuite/tmp 36.5 +set environment XENSTORED_ROOTDIR=testsuite/tmp 36.6 +handle SIGUSR1 noprint nostop 36.7 +handle SIGPIPE noprint nostop
37.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 37.2 +++ b/tools/xenstore/Makefile Thu Jun 09 14:40:39 2005 +0000 37.3 @@ -0,0 +1,97 @@ 37.4 +XEN_ROOT=../.. 37.5 +# This does something wrong to TARGET_ARCH. 37.6 +#include $(XEN_ROOT)/tools/Rules.mk 37.7 +LIBDIR = lib 37.8 +XEN_LIBXC = $(XEN_ROOT)/tools/libxc 37.9 + 37.10 +INSTALL = install 37.11 +INSTALL_DATA = $(INSTALL) -m0644 37.12 +INSTALL_PROG = $(INSTALL) -m0755 37.13 +INSTALL_DIR = $(INSTALL) -d -m0755 37.14 + 37.15 +PROFILE=#-pg 37.16 +BASECFLAGS=-Wall -W -g 37.17 +# Make gcc generate dependencies. 37.18 +BASECFLAGS += -Wp,-MD,.$(@F).d 37.19 +PROG_DEP = .*.d 37.20 +#BASECFLAGS+= -O3 $(PROFILE) 37.21 +#BASECFLAGS+= -I$(XEN_ROOT)/tools 37.22 +BASECFLAGS+= -I$(XEN_ROOT)/tools/libxc 37.23 +BASECFLAGS+= -I$(XEN_ROOT)/xen/include/public 37.24 +BASECFLAGS+= -I. 37.25 + 37.26 +CFLAGS+=$(BASECFLAGS) 37.27 +LDFLAGS=$(PROFILE) -L$(XEN_LIBXC) 37.28 +TESTDIR=`pwd`/testsuite/tmp 37.29 +TESTFLAGS=-DTESTING 37.30 +TESTENV=XENSTORED_ROOTDIR=$(TESTDIR) XENSTORED_RUNDIR=$(TESTDIR) 37.31 + 37.32 +all: xen xenstored libxenstore.a 37.33 + 37.34 +testcode: xen xs_test xenstored_test xs_random 37.35 + 37.36 +xen: 37.37 + ln -sf $(XEN_ROOT)/xen/include/public $@ 37.38 + 37.39 +xenstored: xenstored_core.o xenstored_watch.o xenstored_domain.o xenstored_transaction.o xs_lib.o talloc.o utils.o 37.40 + $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -lxc -o $@ 37.41 + 37.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 37.43 + $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ 37.44 + 37.45 +xs_test: xs_test.o xs_lib.o utils.o 37.46 +xs_random: xs_random.o xs_test_lib.o xs_lib.o talloc.o utils.o 37.47 +xs_stress: xs_stress.o xs_test_lib.o xs_lib.o talloc.o utils.o 37.48 + 37.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) 37.50 + 37.51 +xenstored_%_test.o: xenstored_%.c 37.52 + $(COMPILE.c) -o $@ $< 37.53 + 37.54 +xs_test_lib.o: xs.c 37.55 + $(COMPILE.c) -o $@ $< 37.56 + 37.57 +talloc_test.o: talloc.c 37.58 + $(COMPILE.c) -o $@ $< 37.59 + 37.60 +libxenstore.a: libxenstore.a(xs.o) libxenstore.a(xs_lib.o) 37.61 + 37.62 +clean: testsuite-clean 37.63 + rm -f *.o *.a xs_test xenstored xenstored_test xs_random xs_stress xen 37.64 + -$(RM) $(PROG_DEP) 37.65 + 37.66 +check: testsuite-run randomcheck stresstest 37.67 + 37.68 +testsuite-run: xen xenstored_test xs_test 37.69 + $(TESTENV) testsuite/test.sh 37.70 + 37.71 +testsuite-clean: 37.72 + rm -rf $(TESTDIR) 37.73 + 37.74 +# Make this visible so they can see repeat tests without --fast if they 37.75 +# fail. 37.76 +RANDSEED=$(shell date +%s) 37.77 +randomcheck: xs_random xenstored_test 37.78 + $(TESTENV) ./xs_random --simple --fast /tmp/xs_random 200000 $(RANDSEED) 37.79 + $(TESTENV) ./xs_random --fast /tmp/xs_random 100000 $(RANDSEED) 37.80 + $(TESTENV) ./xs_random --fail /tmp/xs_random 10000 $(RANDSEED) 37.81 + 37.82 +stresstest: xs_stress xenstored_test 37.83 + rm -rf $(TESTDIR)/store 37.84 + export $(TESTENV); PID=`./xenstored_test --output-pid`; ./xs_stress 10000; ret=$$?; kill $$PID; exit $$ret 37.85 + 37.86 +TAGS: 37.87 + etags `find . -name '*.[ch]'` 37.88 + 37.89 +tarball: clean 37.90 + cd .. && tar -c -j -v -h -f xenstore.tar.bz2 xenstore/ 37.91 + 37.92 +install: xenstored libxenstore.a 37.93 + $(INSTALL_DIR) -p $(DESTDIR)/var/run/xenstored 37.94 + $(INSTALL_DIR) -p $(DESTDIR)/var/lib/xenstored 37.95 + $(INSTALL_DIR) -p $(DESTDIR)/usr/sbin 37.96 + $(INSTALL_PROG) xenstored $(DESTDIR)/usr/sbin 37.97 + $(INSTALL_DIR) -p $(DESTDIR)/usr/$(LIBDIR) 37.98 + $(INSTALL_DATA) libxenstore.a $(DESTDIR)/usr/$(LIBDIR) 37.99 + 37.100 +-include $(PROG_DEP)
38.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 38.2 +++ b/tools/xenstore/TODO Thu Jun 09 14:40:39 2005 +0000 38.3 @@ -0,0 +1,7 @@ 38.4 +TODO in no particular order. Some of these will never be done. There 38.5 +are omissions of important but necessary things. It is up to the 38.6 +reader to fill in the blanks. 38.7 + 38.8 +- Remove calls to system() from daemon 38.9 +- Timeout failed watch responses 38.10 +- Timeout blocking transactions
39.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 39.2 +++ b/tools/xenstore/fake_libxc.c Thu Jun 09 14:40:39 2005 +0000 39.3 @@ -0,0 +1,119 @@ 39.4 +/* 39.5 + Fake libxc which doesn't require hypervisor but talks to xs_test. 39.6 + Copyright (C) 2005 Rusty Russell IBM Corporation 39.7 + 39.8 + This program is free software; you can redistribute it and/or modify 39.9 + it under the terms of the GNU General Public License as published by 39.10 + the Free Software Foundation; either version 2 of the License, or 39.11 + (at your option) any later version. 39.12 + 39.13 + This program is distributed in the hope that it will be useful, 39.14 + but WITHOUT ANY WARRANTY; without even the implied warranty of 39.15 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 39.16 + GNU General Public License for more details. 39.17 + 39.18 + You should have received a copy of the GNU General Public License 39.19 + along with this program; if not, write to the Free Software 39.20 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 39.21 +*/ 39.22 + 39.23 +#include <stdio.h> 39.24 +#include <stdlib.h> 39.25 +#include <sys/types.h> 39.26 +#include <sys/stat.h> 39.27 +#include <fcntl.h> 39.28 +#include <sys/mman.h> 39.29 +#include <unistd.h> 39.30 +#include <assert.h> 39.31 +#include <signal.h> 39.32 +#include "utils.h" 39.33 +#include "xenstored_core.h" 39.34 +#include "xenstored_domain.h" 39.35 +#include "xenstored_test.h" 39.36 + 39.37 +static int sigfd; 39.38 +static int xs_test_pid; 39.39 +static u16 port; 39.40 + 39.41 +/* The event channel maps to a signal, shared page to an mmapped file. */ 39.42 +int xc_evtchn_send(int xc_handle __attribute__((unused)), int local_port) 39.43 +{ 39.44 + assert(local_port == port); 39.45 + if (kill(xs_test_pid, SIGUSR2) != 0) 39.46 + barf_perror("fake event channel failed"); 39.47 + return 0; 39.48 +} 39.49 + 39.50 +void *xc_map_foreign_range(int xc_handle, u32 dom __attribute__((unused)), 39.51 + int size, int prot, 39.52 + unsigned long mfn __attribute__((unused))) 39.53 +{ 39.54 + void *ret; 39.55 + 39.56 + ret = mmap(NULL, size, prot, MAP_SHARED, xc_handle, 0); 39.57 + if (ret == MAP_FAILED) 39.58 + return NULL; 39.59 + 39.60 + /* xs_test tells us pid and port by putting it in buffer, we reply. */ 39.61 + xs_test_pid = *(int *)(ret + 32); 39.62 + port = *(int *)(ret + 36); 39.63 + *(int *)(ret + 32) = getpid(); 39.64 + return ret; 39.65 +} 39.66 + 39.67 +int xc_interface_open(void) 39.68 +{ 39.69 + int fd; 39.70 + char page[getpagesize()]; 39.71 + 39.72 + fd = open("/tmp/xcmap", O_RDWR|O_CREAT|O_TRUNC, 0600); 39.73 + if (fd < 0) 39.74 + return fd; 39.75 + 39.76 + memset(page, 0, sizeof(page)); 39.77 + if (!write_all(fd, page, sizeof(page))) 39.78 + barf_perror("Failed to write /tmp/xcmap page"); 39.79 + 39.80 + return fd; 39.81 +} 39.82 + 39.83 +int xc_interface_close(int xc_handle) 39.84 +{ 39.85 + close(xc_handle); 39.86 + return 0; 39.87 +} 39.88 + 39.89 +static void send_to_fd(int signo __attribute__((unused))) 39.90 +{ 39.91 + int saved_errno = errno; 39.92 + write(sigfd, &port, sizeof(port)); 39.93 + errno = saved_errno; 39.94 +} 39.95 + 39.96 +void fake_block_events(void) 39.97 +{ 39.98 + signal(SIGUSR2, SIG_IGN); 39.99 +} 39.100 + 39.101 +void fake_ack_event(void) 39.102 +{ 39.103 + signal(SIGUSR2, send_to_fd); 39.104 +} 39.105 + 39.106 +int fake_open_eventchn(void) 39.107 +{ 39.108 + int fds[2]; 39.109 + 39.110 + if (pipe(fds) != 0) 39.111 + return -1; 39.112 + 39.113 + if (signal(SIGUSR2, send_to_fd) == SIG_ERR) { 39.114 + int saved_errno = errno; 39.115 + close(fds[0]); 39.116 + close(fds[1]); 39.117 + errno = saved_errno; 39.118 + return -1; 39.119 + } 39.120 + sigfd = fds[1]; 39.121 + return fds[0]; 39.122 +}
40.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 40.2 +++ b/tools/xenstore/list.h Thu Jun 09 14:40:39 2005 +0000 40.3 @@ -0,0 +1,508 @@ 40.4 +#ifndef _LINUX_LIST_H 40.5 +#define _LINUX_LIST_H 40.6 +/* Taken from Linux kernel code, but de-kernelized for userspace. */ 40.7 +#include <stddef.h> 40.8 + 40.9 +/* 40.10 + * These are non-NULL pointers that will result in page faults 40.11 + * under normal circumstances, used to verify that nobody uses 40.12 + * non-initialized list entries. 40.13 + */ 40.14 +#define LIST_POISON1 ((void *) 0x00100100) 40.15 +#define LIST_POISON2 ((void *) 0x00200200) 40.16 + 40.17 +#define container_of(ptr, type, member) ({ \ 40.18 + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ 40.19 + (type *)( (char *)__mptr - offsetof(type,member) );}) 40.20 + 40.21 +/* 40.22 + * Simple doubly linked list implementation. 40.23 + * 40.24 + * Some of the internal functions ("__xxx") are useful when 40.25 + * manipulating whole lists rather than single entries, as 40.26 + * sometimes we already know the next/prev entries and we can 40.27 + * generate better code by using them directly rather than 40.28 + * using the generic single-entry routines. 40.29 + */ 40.30 + 40.31 +struct list_head { 40.32 + struct list_head *next, *prev; 40.33 +}; 40.34 + 40.35 +#define LIST_HEAD_INIT(name) { &(name), &(name) } 40.36 + 40.37 +#define LIST_HEAD(name) \ 40.38 + struct list_head name = LIST_HEAD_INIT(name) 40.39 + 40.40 +#define INIT_LIST_HEAD(ptr) do { \ 40.41 + (ptr)->next = (ptr); (ptr)->prev = (ptr); \ 40.42 +} while (0) 40.43 + 40.44 +#define list_top(head, type, member) \ 40.45 +({ \ 40.46 + struct list_head *_head = (head); \ 40.47 + list_empty(_head) ? NULL : list_entry(_head->next, type, member); \ 40.48 +}) 40.49 + 40.50 +/* 40.51 + * Insert a new entry between two known consecutive entries. 40.52 + * 40.53 + * This is only for internal list manipulation where we know 40.54 + * the prev/next entries already! 40.55 + */ 40.56 +static inline void __list_add(struct list_head *new, 40.57 + struct list_head *prev, 40.58 + struct list_head *next) 40.59 +{ 40.60 + next->prev = new; 40.61 + new->next = next; 40.62 + new->prev = prev; 40.63 + prev->next = new; 40.64 +} 40.65 + 40.66 +/** 40.67 + * list_add - add a new entry 40.68 + * @new: new entry to be added 40.69 + * @head: list head to add it after 40.70 + * 40.71 + * Insert a new entry after the specified head. 40.72 + * This is good for implementing stacks. 40.73 + */ 40.74 +static inline void list_add(struct list_head *new, struct list_head *head) 40.75 +{ 40.76 + __list_add(new, head, head->next); 40.77 +} 40.78 + 40.79 +/** 40.80 + * list_add_tail - add a new entry 40.81 + * @new: new entry to be added 40.82 + * @head: list head to add it before 40.83 + * 40.84 + * Insert a new entry before the specified head. 40.85 + * This is useful for implementing queues. 40.86 + */ 40.87 +static inline void list_add_tail(struct list_head *new, struct list_head *head) 40.88 +{ 40.89 + __list_add(new, head->prev, head); 40.90 +} 40.91 + 40.92 +/* 40.93 + * Insert a new entry between two known consecutive entries. 40.94 + * 40.95 + * This is only for internal list manipulation where we know 40.96 + * the prev/next entries already! 40.97 + */ 40.98 +static __inline__ void __list_add_rcu(struct list_head * new, 40.99 + struct list_head * prev, 40.100 + struct list_head * next) 40.101 +{ 40.102 + new->next = next; 40.103 + new->prev = prev; 40.104 + next->prev = new; 40.105 + prev->next = new; 40.106 +} 40.107 + 40.108 +/** 40.109 + * list_add_rcu - add a new entry to rcu-protected list 40.110 + * @new: new entry to be added 40.111 + * @head: list head to add it after 40.112 + * 40.113 + * Insert a new entry after the specified head. 40.114 + * This is good for implementing stacks. 40.115 + */ 40.116 +static __inline__ void list_add_rcu(struct list_head *new, struct list_head *head) 40.117 +{ 40.118 + __list_add_rcu(new, head, head->next); 40.119 +} 40.120 + 40.121 +/** 40.122 + * list_add_tail_rcu - add a new entry to rcu-protected list 40.123 + * @new: new entry to be added 40.124 + * @head: list head to add it before 40.125 + * 40.126 + * Insert a new entry before the specified head. 40.127 + * This is useful for implementing queues. 40.128 + */ 40.129 +static __inline__ void list_add_tail_rcu(struct list_head *new, struct list_head *head) 40.130 +{ 40.131 + __list_add_rcu(new, head->prev, head); 40.132 +} 40.133 + 40.134 +/* 40.135 + * Delete a list entry by making the prev/next entries 40.136 + * point to each other. 40.137 + * 40.138 + * This is only for internal list manipulation where we know 40.139 + * the prev/next entries already! 40.140 + */ 40.141 +static inline void __list_del(struct list_head * prev, struct list_head * next) 40.142 +{ 40.143 + next->prev = prev; 40.144 + prev->next = next; 40.145 +} 40.146 + 40.147 +/** 40.148 + * list_del - deletes entry from list. 40.149 + * @entry: the element to delete from the list. 40.150 + * Note: list_empty on entry does not return true after this, the entry is 40.151 + * in an undefined state. 40.152 + */ 40.153 +static inline void list_del(struct list_head *entry) 40.154 +{ 40.155 + __list_del(entry->prev, entry->next); 40.156 + entry->next = LIST_POISON1; 40.157 + entry->prev = LIST_POISON2; 40.158 +} 40.159 + 40.160 +/** 40.161 + * list_del_rcu - deletes entry from list without re-initialization 40.162 + * @entry: the element to delete from the list. 40.163 + * 40.164 + * Note: list_empty on entry does not return true after this, 40.165 + * the entry is in an undefined state. It is useful for RCU based 40.166 + * lockfree traversal. 40.167 + * 40.168 + * In particular, it means that we can not poison the forward 40.169 + * pointers that may still be used for walking the list. 40.170 + */ 40.171 +static inline void list_del_rcu(struct list_head *entry) 40.172 +{ 40.173 + __list_del(entry->prev, entry->next); 40.174 + entry->prev = LIST_POISON2; 40.175 +} 40.176 + 40.177 +/** 40.178 + * list_del_init - deletes entry from list and reinitialize it. 40.179 + * @entry: the element to delete from the list. 40.180 + */ 40.181 +static inline void list_del_init(struct list_head *entry) 40.182 +{ 40.183 + __list_del(entry->prev, entry->next); 40.184 + INIT_LIST_HEAD(entry); 40.185 +} 40.186 + 40.187 +/** 40.188 + * list_move - delete from one list and add as another's head 40.189 + * @list: the entry to move 40.190 + * @head: the head that will precede our entry 40.191 + */ 40.192 +static inline void list_move(struct list_head *list, struct list_head *head) 40.193 +{ 40.194 + __list_del(list->prev, list->next); 40.195 + list_add(list, head); 40.196 +} 40.197 + 40.198 +/** 40.199 + * list_move_tail - delete from one list and add as another's tail 40.200 + * @list: the entry to move 40.201 + * @head: the head that will follow our entry 40.202 + */ 40.203 +static inline void list_move_tail(struct list_head *list, 40.204 + struct list_head *head) 40.205 +{ 40.206 + __list_del(list->prev, list->next); 40.207 + list_add_tail(list, head); 40.208 +} 40.209 + 40.210 +/** 40.211 + * list_empty - tests whether a list is empty 40.212 + * @head: the list to test. 40.213 + */ 40.214 +static inline int list_empty(struct list_head *head) 40.215 +{ 40.216 + return head->next == head; 40.217 +} 40.218 + 40.219 +static inline void __list_splice(struct list_head *list, 40.220 + struct list_head *head) 40.221 +{ 40.222 + struct list_head *first = list->next; 40.223 + struct list_head *last = list->prev; 40.224 + struct list_head *at = head->next; 40.225 + 40.226 + first->prev = head; 40.227 + head->next = first; 40.228 + 40.229 + last->next = at; 40.230 + at->prev = last; 40.231 +} 40.232 + 40.233 +/** 40.234 + * list_splice - join two lists 40.235 + * @list: the new list to add. 40.236 + * @head: the place to add it in the first list. 40.237 + */ 40.238 +static inline void list_splice(struct list_head *list, struct list_head *head) 40.239 +{ 40.240 + if (!list_empty(list)) 40.241 + __list_splice(list, head); 40.242 +} 40.243 + 40.244 +/** 40.245 + * list_splice_init - join two lists and reinitialise the emptied list. 40.246 + * @list: the new list to add. 40.247 + * @head: the place to add it in the first list. 40.248 + * 40.249 + * The list at @list is reinitialised 40.250 + */ 40.251 +static inline void list_splice_init(struct list_head *list, 40.252 + struct list_head *head) 40.253 +{ 40.254 + if (!list_empty(list)) { 40.255 + __list_splice(list, head); 40.256 + INIT_LIST_HEAD(list); 40.257 + } 40.258 +} 40.259 + 40.260 +/** 40.261 + * list_entry - get the struct for this entry 40.262 + * @ptr: the &struct list_head pointer. 40.263 + * @type: the type of the struct this is embedded in. 40.264 + * @member: the name of the list_struct within the struct. 40.265 + */ 40.266 +#define list_entry(ptr, type, member) \ 40.267 + container_of(ptr, type, member) 40.268 + 40.269 +/** 40.270 + * list_for_each - iterate over a list 40.271 + * @pos: the &struct list_head to use as a loop counter. 40.272 + * @head: the head for your list. 40.273 + */ 40.274 +#define list_for_each(pos, head) \ 40.275 + for (pos = (head)->next; pos != (head); pos = pos->next) 40.276 + 40.277 +/** 40.278 + * list_for_each_prev - iterate over a list backwards 40.279 + * @pos: the &struct list_head to use as a loop counter. 40.280 + * @head: the head for your list. 40.281 + */ 40.282 +#define list_for_each_prev(pos, head) \ 40.283 + for (pos = (head)->prev; pos != (head); pos = pos->prev) 40.284 + 40.285 +/** 40.286 + * list_for_each_safe - iterate over a list safe against removal of list entry 40.287 + * @pos: the &struct list_head to use as a loop counter. 40.288 + * @n: another &struct list_head to use as temporary storage 40.289 + * @head: the head for your list. 40.290 + */ 40.291 +#define list_for_each_safe(pos, n, head) \ 40.292 + for (pos = (head)->next, n = pos->next; pos != (head); \ 40.293 + pos = n, n = pos->next) 40.294 + 40.295 +/** 40.296 + * list_for_each_entry - iterate over list of given type 40.297 + * @pos: the type * to use as a loop counter. 40.298 + * @head: the head for your list. 40.299 + * @member: the name of the list_struct within the struct. 40.300 + */ 40.301 +#define list_for_each_entry(pos, head, member) \ 40.302 + for (pos = list_entry((head)->next, typeof(*pos), member); \ 40.303 + &pos->member != (head); \ 40.304 + pos = list_entry(pos->member.next, typeof(*pos), member)) 40.305 + 40.306 +/** 40.307 + * list_for_each_entry_reverse - iterate backwards over list of given type. 40.308 + * @pos: the type * to use as a loop counter. 40.309 + * @head: the head for your list. 40.310 + * @member: the name of the list_struct within the struct. 40.311 + */ 40.312 +#define list_for_each_entry_reverse(pos, head, member) \ 40.313 + for (pos = list_entry((head)->prev, typeof(*pos), member); \ 40.314 + &pos->member != (head); \ 40.315 + pos = list_entry(pos->member.prev, typeof(*pos), member)) 40.316 + 40.317 + 40.318 +/** 40.319 + * list_for_each_entry_continue - iterate over list of given type 40.320 + * continuing after existing point 40.321 + * @pos: the type * to use as a loop counter. 40.322 + * @head: the head for your list. 40.323 + * @member: the name of the list_struct within the struct. 40.324 + */ 40.325 +#define list_for_each_entry_continue(pos, head, member) \ 40.326 + for (pos = list_entry(pos->member.next, typeof(*pos), member); \ 40.327 + &pos->member != (head); \ 40.328 + pos = list_entry(pos->member.next, typeof(*pos), member)) 40.329 + 40.330 +/** 40.331 + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry 40.332 + * @pos: the type * to use as a loop counter. 40.333 + * @n: another type * to use as temporary storage 40.334 + * @head: the head for your list. 40.335 + * @member: the name of the list_struct within the struct. 40.336 + */ 40.337 +#define list_for_each_entry_safe(pos, n, head, member) \ 40.338 + for (pos = list_entry((head)->next, typeof(*pos), member), \ 40.339 + n = list_entry(pos->member.next, typeof(*pos), member); \ 40.340 + &pos->member != (head); \ 40.341 + pos = n, n = list_entry(n->member.next, typeof(*n), member)) 40.342 + 40.343 + 40.344 +/* 40.345 + * Double linked lists with a single pointer list head. 40.346 + * Mostly useful for hash tables where the two pointer list head is 40.347 + * too wasteful. 40.348 + * You lose the ability to access the tail in O(1). 40.349 + */ 40.350 + 40.351 +struct hlist_head { 40.352 + struct hlist_node *first; 40.353 +}; 40.354 + 40.355 +struct hlist_node { 40.356 + struct hlist_node *next, **pprev; 40.357 +}; 40.358 + 40.359 +#define HLIST_HEAD_INIT { .first = NULL } 40.360 +#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } 40.361 +#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) 40.362 +#define INIT_HLIST_NODE(ptr) ((ptr)->next = NULL, (ptr)->pprev = NULL) 40.363 + 40.364 +static __inline__ int hlist_unhashed(struct hlist_node *h) 40.365 +{ 40.366 + return !h->pprev; 40.367 +} 40.368 + 40.369 +static __inline__ int hlist_empty(struct hlist_head *h) 40.370 +{ 40.371 + return !h->first; 40.372 +} 40.373 + 40.374 +static __inline__ void __hlist_del(struct hlist_node *n) 40.375 +{ 40.376 + struct hlist_node *next = n->next; 40.377 + struct hlist_node **pprev = n->pprev; 40.378 + *pprev = next; 40.379 + if (next) 40.380 + next->pprev = pprev; 40.381 +} 40.382 + 40.383 +static __inline__ void hlist_del(struct hlist_node *n) 40.384 +{ 40.385 + __hlist_del(n); 40.386 + n->next = LIST_POISON1; 40.387 + n->pprev = LIST_POISON2; 40.388 +} 40.389 + 40.390 +/** 40.391 + * hlist_del_rcu - deletes entry from hash list without re-initialization 40.392 + * @entry: the element to delete from the hash list. 40.393 + * 40.394 + * Note: list_unhashed() on entry does not return true after this, 40.395 + * the entry is in an undefined state. It is useful for RCU based 40.396 + * lockfree traversal. 40.397 + * 40.398 + * In particular, it means that we can not poison the forward 40.399 + * pointers that may still be used for walking the hash list. 40.400 + */ 40.401 +static inline void hlist_del_rcu(struct hlist_node *n) 40.402 +{ 40.403 + __hlist_del(n); 40.404 + n->pprev = LIST_POISON2; 40.405 +} 40.406 + 40.407 +static __inline__ void hlist_del_init(struct hlist_node *n) 40.408 +{ 40.409 + if (n->pprev) { 40.410 + __hlist_del(n); 40.411 + INIT_HLIST_NODE(n); 40.412 + } 40.413 +} 40.414 + 40.415 +#define hlist_del_rcu_init hlist_del_init 40.416 + 40.417 +static __inline__ void hlist_add_head(struct hlist_node *n, struct hlist_head *h) 40.418 +{ 40.419 + struct hlist_node *first = h->first; 40.420 + n->next = first; 40.421 + if (first) 40.422 + first->pprev = &n->next; 40.423 + h->first = n; 40.424 + n->pprev = &h->first; 40.425 +} 40.426 + 40.427 +static __inline__ void hlist_add_head_rcu(struct hlist_node *n, struct hlist_head *h) 40.428 +{ 40.429 + struct hlist_node *first = h->first; 40.430 + n->next = first; 40.431 + n->pprev = &h->first; 40.432 + if (first) 40.433 + first->pprev = &n->next; 40.434 + h->first = n; 40.435 +} 40.436 + 40.437 +/* next must be != NULL */ 40.438 +static __inline__ void hlist_add_before(struct hlist_node *n, struct hlist_node *next) 40.439 +{ 40.440 + n->pprev = next->pprev; 40.441 + n->next = next; 40.442 + next->pprev = &n->next; 40.443 + *(n->pprev) = n; 40.444 +} 40.445 + 40.446 +static __inline__ void hlist_add_after(struct hlist_node *n, 40.447 + struct hlist_node *next) 40.448 +{ 40.449 + next->next = n->next; 40.450 + *(next->pprev) = n; 40.451 + n->next = next; 40.452 +} 40.453 + 40.454 +#define hlist_entry(ptr, type, member) container_of(ptr,type,member) 40.455 + 40.456 +/* Cannot easily do prefetch unfortunately */ 40.457 +#define hlist_for_each(pos, head) \ 40.458 + for (pos = (head)->first; pos; pos = pos->next) 40.459 + 40.460 +#define hlist_for_each_safe(pos, n, head) \ 40.461 + for (pos = (head)->first; n = pos ? pos->next : 0, pos; \ 40.462 + pos = n) 40.463 + 40.464 +/** 40.465 + * hlist_for_each_entry - iterate over list of given type 40.466 + * @tpos: the type * to use as a loop counter. 40.467 + * @pos: the &struct hlist_node to use as a loop counter. 40.468 + * @head: the head for your list. 40.469 + * @member: the name of the hlist_node within the struct. 40.470 + */ 40.471 +#define hlist_for_each_entry(tpos, pos, head, member) \ 40.472 + for (pos = (head)->first; \ 40.473 + pos && ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ 40.474 + pos = pos->next) 40.475 + 40.476 +/** 40.477 + * hlist_for_each_entry_continue - iterate over a hlist continuing after existing point 40.478 + * @tpos: the type * to use as a loop counter. 40.479 + * @pos: the &struct hlist_node to use as a loop counter. 40.480 + * @member: the name of the hlist_node within the struct. 40.481 + */ 40.482 +#define hlist_for_each_entry_continue(tpos, pos, member) \ 40.483 + for (pos = (pos)->next; \ 40.484 + pos && ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ 40.485 + pos = pos->next) 40.486 + 40.487 +/** 40.488 + * hlist_for_each_entry_from - iterate over a hlist continuing from existing point 40.489 + * @tpos: the type * to use as a loop counter. 40.490 + * @pos: the &struct hlist_node to use as a loop counter. 40.491 + * @member: the name of the hlist_node within the struct. 40.492 + */ 40.493 +#define hlist_for_each_entry_from(tpos, pos, member) \ 40.494 + for (; pos && ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ 40.495 + pos = pos->next) 40.496 + 40.497 +/** 40.498 + * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry 40.499 + * @tpos: the type * to use as a loop counter. 40.500 + * @pos: the &struct hlist_node to use as a loop counter. 40.501 + * @n: another &struct hlist_node to use as temporary storage 40.502 + * @head: the head for your list. 40.503 + * @member: the name of the hlist_node within the struct. 40.504 + */ 40.505 +#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ 40.506 + for (pos = (head)->first; \ 40.507 + pos && ({ n = pos->next; 1; }) && \ 40.508 + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ 40.509 + pos = n) 40.510 + 40.511 +#endif
41.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 41.2 +++ b/tools/xenstore/talloc.c Thu Jun 09 14:40:39 2005 +0000 41.3 @@ -0,0 +1,1143 @@ 41.4 +/* 41.5 + Samba Unix SMB/CIFS implementation. 41.6 + 41.7 + Samba trivial allocation library - new interface 41.8 + 41.9 + NOTE: Please read talloc_guide.txt for full documentation 41.10 + 41.11 + Copyright (C) Andrew Tridgell 2004 41.12 + 41.13 + This program is free software; you can redistribute it and/or modify 41.14 + it under the terms of the GNU General Public License as published by 41.15 + the Free Software Foundation; either version 2 of the License, or 41.16 + (at your option) any later version. 41.17 + 41.18 + This program is distributed in the hope that it will be useful, 41.19 + but WITHOUT ANY WARRANTY; without even the implied warranty of 41.20 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 41.21 + GNU General Public License for more details. 41.22 + 41.23 + You should have received a copy of the GNU General Public License 41.24 + along with this program; if not, write to the Free Software 41.25 + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 41.26 +*/ 41.27 + 41.28 +/* 41.29 + inspired by http://swapped.cc/halloc/ 41.30 +*/ 41.31 + 41.32 + 41.33 +#ifdef _SAMBA_BUILD_ 41.34 +#include "includes.h" 41.35 +#if ((SAMBA_VERSION_MAJOR==3)&&(SAMBA_VERSION_MINOR<9)) 41.36 +/* This is to circumvent SAMBA3's paranoid malloc checker. Here in this file 41.37 + * we trust ourselves... */ 41.38 +#ifdef malloc 41.39 +#undef malloc 41.40 +#endif 41.41 +#ifdef realloc 41.42 +#undef realloc 41.43 +#endif 41.44 +#endif 41.45 +#else 41.46 +#include <stdio.h> 41.47 +#include <stdlib.h> 41.48 +#include <string.h> 41.49 +#include <stdarg.h> 41.50 +#include <stdint.h> 41.51 +#include "talloc.h" 41.52 +/* assume a modern system */ 41.53 +#define HAVE_VA_COPY 41.54 +#endif 41.55 + 41.56 +/* use this to force every realloc to change the pointer, to stress test 41.57 + code that might not cope */ 41.58 +#ifdef TESTING 41.59 +#define ALWAYS_REALLOC 1 41.60 +void *test_malloc(size_t size); 41.61 +#define malloc test_malloc 41.62 +#endif 41.63 + 41.64 +#define MAX_TALLOC_SIZE 0x10000000 41.65 +#define TALLOC_MAGIC 0xe814ec4f 41.66 +#define TALLOC_MAGIC_FREE 0x7faebef3 41.67 +#define TALLOC_MAGIC_REFERENCE ((const char *)1) 41.68 + 41.69 +/* by default we abort when given a bad pointer (such as when talloc_free() is called 41.70 + on a pointer that came from malloc() */ 41.71 +#ifndef TALLOC_ABORT 41.72 +#define TALLOC_ABORT(reason) abort() 41.73 +#endif 41.74 + 41.75 +#ifndef discard_const_p 41.76 +#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) 41.77 +# define discard_const_p(type, ptr) ((type *)((intptr_t)(ptr))) 41.78 +#else 41.79 +# define discard_const_p(type, ptr) ((type *)(ptr)) 41.80 +#endif 41.81 +#endif 41.82 + 41.83 +/* this null_context is only used if talloc_enable_leak_report() or 41.84 + talloc_enable_leak_report_full() is called, otherwise it remains 41.85 + NULL 41.86 +*/ 41.87 +static const void *null_context; 41.88 +static void *cleanup_context; 41.89 +static int (*malloc_fail_handler)(void *); 41.90 +static void *malloc_fail_data; 41.91 + 41.92 +struct talloc_reference_handle { 41.93 + struct talloc_reference_handle *next, *prev; 41.94 + void *ptr; 41.95 +}; 41.96 + 41.97 +typedef int (*talloc_destructor_t)(void *); 41.98 + 41.99 +struct talloc_chunk { 41.100 + struct talloc_chunk *next, *prev; 41.101 + struct talloc_chunk *parent, *child; 41.102 + struct talloc_reference_handle *refs; 41.103 + size_t size; 41.104 + unsigned magic; 41.105 + talloc_destructor_t destructor; 41.106 + const char *name; 41.107 +}; 41.108 + 41.109 +/* panic if we get a bad magic value */ 41.110 +static struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr) 41.111 +{ 41.112 + struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, ptr)-1; 41.113 + if (tc->magic != TALLOC_MAGIC) { 41.114 + if (tc->magic == TALLOC_MAGIC_FREE) { 41.115 + TALLOC_ABORT("Bad talloc magic value - double free"); 41.116 + } else { 41.117 + TALLOC_ABORT("Bad talloc magic value - unknown value"); 41.118 + } 41.119 + } 41.120 + 41.121 + return tc; 41.122 +} 41.123 + 41.124 +/* hook into the front of the list */ 41.125 +#define _TLIST_ADD(list, p) \ 41.126 +do { \ 41.127 + if (!(list)) { \ 41.128 + (list) = (p); \ 41.129 + (p)->next = (p)->prev = NULL; \ 41.130 + } else { \ 41.131 + (list)->prev = (p); \ 41.132 + (p)->next = (list); \ 41.133 + (p)->prev = NULL; \ 41.134 + (list) = (p); \ 41.135 + }\ 41.136 +} while (0) 41.137 + 41.138 +/* remove an element from a list - element doesn't have to be in list. */ 41.139 +#define _TLIST_REMOVE(list, p) \ 41.140 +do { \ 41.141 + if ((p) == (list)) { \ 41.142 + (list) = (p)->next; \ 41.143 + if (list) (list)->prev = NULL; \ 41.144 + } else { \ 41.145 + if ((p)->prev) (p)->prev->next = (p)->next; \ 41.146 + if ((p)->next) (p)->next->prev = (p)->prev; \ 41.147 + } \ 41.148 + if ((p) && ((p) != (list))) (p)->next = (p)->prev = NULL; \ 41.149 +} while (0) 41.150 + 41.151 + 41.152 +/* 41.153 + return the parent chunk of a pointer 41.154 +*/ 41.155 +static struct talloc_chunk *talloc_parent_chunk(const void *ptr) 41.156 +{ 41.157 + struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); 41.158 + while (tc->prev) tc=tc->prev; 41.159 + return tc->parent; 41.160 +} 41.161 + 41.162 +void *talloc_parent(const void *ptr) 41.163 +{ 41.164 + struct talloc_chunk *tc = talloc_parent_chunk(ptr); 41.165 + return (void *)(tc+1); 41.166 +} 41.167 + 41.168 +/* 41.169 + Allocate a bit of memory as a child of an existing pointer 41.170 +*/ 41.171 +void *_talloc(const void *context, size_t size) 41.172 +{ 41.173 + struct talloc_chunk *tc; 41.174 + 41.175 + if (context == NULL) { 41.176 + context = null_context; 41.177 + } 41.178 + 41.179 + if (size >= MAX_TALLOC_SIZE) { 41.180 + return NULL; 41.181 + } 41.182 + 41.183 + tc = malloc(sizeof(*tc)+size); 41.184 + if (tc == NULL) { 41.185 + if (malloc_fail_handler) 41.186 + if (malloc_fail_handler(malloc_fail_data)) 41.187 + tc = malloc(sizeof(*tc)+size); 41.188 + if (!tc) 41.189 + return NULL; 41.190 + } 41.191 + 41.192 + tc->size = size; 41.193 + tc->magic = TALLOC_MAGIC; 41.194 + tc->destructor = NULL; 41.195 + tc->child = NULL; 41.196 + tc->name = NULL; 41.197 + tc->refs = NULL; 41.198 + 41.199 + if (context) { 41.200 + struct talloc_chunk *parent = talloc_chunk_from_ptr(context); 41.201 + 41.202 + tc->parent = parent; 41.203 + 41.204 + if (parent->child) { 41.205 + parent->child->parent = NULL; 41.206 + } 41.207 + 41.208 + _TLIST_ADD(parent->child, tc); 41.209 + } else { 41.210 + tc->next = tc->prev = tc->parent = NULL; 41.211 + } 41.212 + 41.213 + return (void *)(tc+1); 41.214 +} 41.215 + 41.216 + 41.217 +/* 41.218 + setup a destructor to be called on free of a pointer 41.219 + the destructor should return 0 on success, or -1 on failure. 41.220 + if the destructor fails then the free is failed, and the memory can 41.221 + be continued to be used 41.222 +*/ 41.223 +void talloc_set_destructor(const void *ptr, int (*destructor)(void *)) 41.224 +{ 41.225 + struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); 41.226 + tc->destructor = destructor; 41.227 +} 41.228 + 41.229 +/* 41.230 + increase the reference count on a piece of memory. 41.231 +*/ 41.232 +void talloc_increase_ref_count(const void *ptr) 41.233 +{ 41.234 + talloc_reference(null_context, ptr); 41.235 +} 41.236 + 41.237 +/* 41.238 + helper for talloc_reference() 41.239 +*/ 41.240 +static int talloc_reference_destructor(void *ptr) 41.241 +{ 41.242 + struct talloc_reference_handle *handle = ptr; 41.243 + struct talloc_chunk *tc1 = talloc_chunk_from_ptr(ptr); 41.244 + struct talloc_chunk *tc2 = talloc_chunk_from_ptr(handle->ptr); 41.245 + if (tc1->destructor != (talloc_destructor_t)-1) { 41.246 + tc1->destructor = NULL; 41.247 + } 41.248 + _TLIST_REMOVE(tc2->refs, handle); 41.249 + talloc_free(handle); 41.250 + return 0; 41.251 +} 41.252 + 41.253 +/* 41.254 + make a secondary reference to a pointer, hanging off the given context. 41.255 + the pointer remains valid until both the original caller and this given 41.256 + context are freed. 41.257 + 41.258 + the major use for this is when two different structures need to reference the 41.259 + same underlying data, and you want to be able to free the two instances separately, 41.260 + and in either order 41.261 +*/ 41.262 +void *talloc_reference(const void *context, const void *ptr) 41.263 +{ 41.264 + struct talloc_chunk *tc; 41.265 + struct talloc_reference_handle *handle; 41.266 + if (ptr == NULL) return NULL; 41.267 + 41.268 + tc = talloc_chunk_from_ptr(ptr); 41.269 + handle = talloc_named_const(context, sizeof(*handle), TALLOC_MAGIC_REFERENCE); 41.270 + 41.271 + if (handle == NULL) return NULL; 41.272 + 41.273 + /* note that we hang the destructor off the handle, not the 41.274 + main context as that allows the caller to still setup their 41.275 + own destructor on the context if they want to */ 41.276 + talloc_set_destructor(handle, talloc_reference_destructor); 41.277 + handle->ptr = discard_const_p(void, ptr); 41.278 + _TLIST_ADD(tc->refs, handle); 41.279 + return handle->ptr; 41.280 +} 41.281 + 41.282 +/* 41.283 + remove a secondary reference to a pointer. This undo's what 41.284 + talloc_reference() has done. The context and pointer arguments 41.285 + must match those given to a talloc_reference() 41.286 +*/ 41.287 +static int talloc_unreference(const void *context, const void *ptr) 41.288 +{ 41.289 + struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); 41.290 + struct talloc_reference_handle *h; 41.291 + 41.292 + if (context == NULL) { 41.293 + context = null_context; 41.294 + } 41.295 + 41.296 + for (h=tc->refs;h;h=h->next) { 41.297 + struct talloc_chunk *p = talloc_parent_chunk(h); 41.298 + if ((p==NULL && context==NULL) || p+1 == context) break; 41.299 + } 41.300 + if (h == NULL) { 41.301 + return -1; 41.302 + } 41.303 + 41.304 + talloc_set_destructor(h, NULL); 41.305 + _TLIST_REMOVE(tc->refs, h); 41.306 + talloc_free(h); 41.307 + return 0; 41.308 +} 41.309 + 41.310 +/* 41.311 + remove a specific parent context from a pointer. This is a more 41.312 + controlled varient of talloc_free() 41.313 +*/ 41.314 +int talloc_unlink(const void *context, void *ptr) 41.315 +{ 41.316 + struct talloc_chunk *tc_p, *new_p; 41.317 + void *new_parent; 41.318 + 41.319 + if (ptr == NULL) { 41.320 + return -1; 41.321 + } 41.322 + 41.323 + if (context == NULL) { 41.324 + context = null_context; 41.325 + } 41.326 + 41.327 + if (talloc_unreference(context, ptr) == 0) { 41.328 + return 0; 41.329 + } 41.330 + 41.331 + if (context == NULL) { 41.332 + if (talloc_parent_chunk(ptr) != NULL) { 41.333 + return -1; 41.334 + } 41.335 + } else { 41.336 + if (talloc_chunk_from_ptr(context) != talloc_parent_chunk(ptr)) { 41.337 + return -1; 41.338 + } 41.339 + } 41.340 + 41.341 + tc_p = talloc_chunk_from_ptr(ptr); 41.342 + 41.343 + if (tc_p->refs == NULL) { 41.344 + return talloc_free(ptr); 41.345 + } 41.346 + 41.347 + new_p = talloc_parent_chunk(tc_p->refs); 41.348 + if (new_p) { 41.349 + new_parent = new_p+1; 41.350 + } else { 41.351 + new_parent = NULL; 41.352 + } 41.353 + 41.354 + if (talloc_unreference(new_parent, ptr) != 0) { 41.355 + return -1; 41.356 + } 41.357 + 41.358 + talloc_steal(new_parent, ptr); 41.359 + 41.360 + return 0; 41.361 +} 41.362 + 41.363 +/* 41.364 + add a name to an existing pointer - va_list version 41.365 +*/ 41.366 +static void talloc_set_name_v(const void *ptr, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0); 41.367 + 41.368 +static void talloc_set_name_v(const void *ptr, const char *fmt, va_list ap) 41.369 +{ 41.370 + struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); 41.371 + tc->name = talloc_vasprintf(ptr, fmt, ap); 41.372 + if (tc->name) { 41.373 + talloc_set_name_const(tc->name, ".name"); 41.374 + } 41.375 +} 41.376 + 41.377 +/* 41.378 + add a name to an existing pointer 41.379 +*/ 41.380 +void talloc_set_name(const void *ptr, const char *fmt, ...) 41.381 +{ 41.382 + va_list ap; 41.383 + va_start(ap, fmt); 41.384 + talloc_set_name_v(ptr, fmt, ap); 41.385 + va_end(ap); 41.386 +} 41.387 + 41.388 +/* 41.389 + more efficient way to add a name to a pointer - the name must point to a 41.390 + true string constant 41.391 +*/ 41.392 +void talloc_set_name_const(const void *ptr, const char *name) 41.393 +{ 41.394 + struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); 41.395 + tc->name = name; 41.396 +} 41.397 + 41.398 +/* 41.399 + create a named talloc pointer. Any talloc pointer can be named, and 41.400 + talloc_named() operates just like talloc() except that it allows you 41.401 + to name the pointer. 41.402 +*/ 41.403 +void *talloc_named(const void *context, size_t size, const char *fmt, ...) 41.404 +{ 41.405 + va_list ap; 41.406 + void *ptr; 41.407 + 41.408 + ptr = _talloc(context, size); 41.409 + if (ptr == NULL) return NULL; 41.410 + 41.411 + va_start(ap, fmt); 41.412 + talloc_set_name_v(ptr, fmt, ap); 41.413 + va_end(ap); 41.414 + 41.415 + return ptr; 41.416 +} 41.417 + 41.418 +/* 41.419 + create a named talloc pointer. Any talloc pointer can be named, and 41.420 + talloc_named() operates just like talloc() except that it allows you 41.421 + to name the pointer. 41.422 +*/ 41.423 +void *talloc_named_const(const void *context, size_t size, const char *name) 41.424 +{ 41.425 + void *ptr; 41.426 + 41.427 + ptr = _talloc(context, size); 41.428 + if (ptr == NULL) { 41.429 + return NULL; 41.430 + } 41.431 + 41.432 + talloc_set_name_const(ptr, name); 41.433 + 41.434 + return ptr; 41.435 +} 41.436 + 41.437 +/* 41.438 + return the name of a talloc ptr, or "UNNAMED" 41.439 +*/ 41.440 +const char *talloc_get_name(const void *ptr) 41.441 +{ 41.442 + struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); 41.443 + if (tc->name == TALLOC_MAGIC_REFERENCE) { 41.444 + return ".reference"; 41.445 + } 41.446 + if (tc->name) { 41.447 + return tc->name; 41.448 + } 41.449 + return "UNNAMED"; 41.450 +} 41.451 + 41.452 + 41.453 +/* 41.454 + check if a pointer has the given name. If it does, return the pointer, 41.455 + otherwise return NULL 41.456 +*/ 41.457 +void *talloc_check_name(const void *ptr, const char *name) 41.458 +{ 41.459 + const char *pname; 41.460 + if (ptr == NULL) return NULL; 41.461 + pname = talloc_get_name(ptr); 41.462 + if (pname == name || strcmp(pname, name) == 0) { 41.463 + return discard_const_p(void, ptr); 41.464 + } 41.465 + return NULL; 41.466 +} 41.467 + 41.468 + 41.469 +/* 41.470 + this is for compatibility with older versions of talloc 41.471 +*/ 41.472 +void *talloc_init(const char *fmt, ...) 41.473 +{ 41.474 + va_list ap; 41.475 + void *ptr; 41.476 + 41.477 + ptr = _talloc(NULL, 0); 41.478 + if (ptr == NULL) return NULL; 41.479 + 41.480 + va_start(ap, fmt); 41.481 + talloc_set_name_v(ptr, fmt, ap); 41.482 + va_end(ap); 41.483 + 41.484 + return ptr; 41.485 +} 41.486 + 41.487 +/* 41.488 + this is a replacement for the Samba3 talloc_destroy_pool functionality. It 41.489 + should probably not be used in new code. It's in here to keep the talloc 41.490 + code consistent across Samba 3 and 4. 41.491 +*/ 41.492 +void talloc_free_children(void *ptr) 41.493 +{ 41.494 + struct talloc_chunk *tc; 41.495 + 41.496 + if (ptr == NULL) { 41.497 + return; 41.498 + } 41.499 + 41.500 + tc = talloc_chunk_from_ptr(ptr); 41.501 + 41.502 + while (tc->child) { 41.503 + /* we need to work out who will own an abandoned child 41.504 + if it cannot be freed. In priority order, the first 41.505 + choice is owner of any remaining reference to this 41.506 + pointer, the second choice is our parent, and the 41.507 + final choice is the null context. */ 41.508 + void *child = tc->child+1; 41.509 + const void *new_parent = null_context; 41.510 + if (tc->child->refs) { 41.511 + struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs); 41.512 + if (p) new_parent = p+1; 41.513 + } 41.514 + if (talloc_free(child) == -1) { 41.515 + if (new_parent == null_context) { 41.516 + struct talloc_chunk *p = talloc_parent_chunk(ptr); 41.517 + if (p) new_parent = p+1; 41.518 + } 41.519 + talloc_steal(new_parent, child); 41.520 + } 41.521 + } 41.522 +} 41.523 + 41.524 +/* 41.525 + free a talloc pointer. This also frees all child pointers of this 41.526 + pointer recursively 41.527 + 41.528 + return 0 if the memory is actually freed, otherwise -1. The memory 41.529 + will not be freed if the ref_count is > 1 or the destructor (if 41.530 + any) returns non-zero 41.531 +*/ 41.532 +int talloc_free(void *ptr) 41.533 +{ 41.534 + struct talloc_chunk *tc; 41.535 + 41.536 + if (ptr == NULL) { 41.537 + return -1; 41.538 + } 41.539 + 41.540 + tc = talloc_chunk_from_ptr(ptr); 41.541 + 41.542 + if (tc->refs) { 41.543 + talloc_reference_destructor(tc->refs); 41.544 + return -1; 41.545 + } 41.546 + 41.547 + if (tc->destructor) { 41.548 + talloc_destructor_t d = tc->destructor; 41.549 + if (d == (talloc_destructor_t)-1) { 41.550 + return -1; 41.551 + } 41.552 + tc->destructor = (talloc_destructor_t)-1; 41.553 + if (d(ptr) == -1) { 41.554 + tc->destructor = d; 41.555 + return -1; 41.556 + } 41.557 + tc->destructor = NULL; 41.558 + } 41.559 + 41.560 + talloc_free_children(ptr); 41.561 + 41.562 + if (tc->parent) { 41.563 + _TLIST_REMOVE(tc->parent->child, tc); 41.564 + if (tc->parent->child) { 41.565 + tc->parent->child->parent = tc->parent; 41.566 + } 41.567 + } else { 41.568 + if (tc->prev) tc->prev->next = tc->next; 41.569 + if (tc->next) tc->next->prev = tc->prev; 41.570 + } 41.571 + 41.572 + tc->magic = TALLOC_MAGIC_FREE; 41.573 + 41.574 + free(tc); 41.575 + return 0; 41.576 +} 41.577 + 41.578 + 41.579 + 41.580 +/* 41.581 + A talloc version of realloc. The context argument is only used if 41.582 + ptr is NULL 41.583 +*/ 41.584 +void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name) 41.585 +{ 41.586 + struct talloc_chunk *tc; 41.587 + void *new_ptr; 41.588 + 41.589 + /* size zero is equivalent to free() */ 41.590 + if (size == 0) { 41.591 + talloc_free(ptr); 41.592 + return NULL; 41.593 + } 41.594 + 41.595 + if (size >= MAX_TALLOC_SIZE) { 41.596 + return NULL; 41.597 + } 41.598 + 41.599 + /* realloc(NULL) is equavalent to malloc() */ 41.600 + if (ptr == NULL) { 41.601 + return talloc_named_const(context, size, name); 41.602 + } 41.603 + 41.604 + tc = talloc_chunk_from_ptr(ptr); 41.605 + 41.606 + /* don't allow realloc on referenced pointers */ 41.607 + if (tc->refs) { 41.608 + return NULL; 41.609 + } 41.610 + 41.611 + /* by resetting magic we catch users of the old memory */ 41.612 + tc->magic = TALLOC_MAGIC_FREE; 41.613 + 41.614 +#if ALWAYS_REALLOC 41.615 + new_ptr = malloc(size + sizeof(*tc)); 41.616 + if (!new_ptr) { 41.617 + tc->magic = TALLOC_MAGIC; 41.618 + if (malloc_fail_handler) 41.619 + if (malloc_fail_handler(malloc_fail_data)) 41.620 + new_ptr = malloc(size + sizeof(*tc)); 41.621 + } 41.622 + if (new_ptr) { 41.623 + memcpy(new_ptr, tc, tc->size + sizeof(*tc)); 41.624 + free(tc); 41.625 + } 41.626 +#else 41.627 + new_ptr = realloc(tc, size + sizeof(*tc)); 41.628 + if (!new_ptr) { 41.629 + tc->magic = TALLOC_MAGIC; 41.630 + if (malloc_fail_handler) 41.631 + if (malloc_fail_handler(malloc_fail_data)) 41.632 + new_ptr = realloc(tc, size + sizeof(*tc)); 41.633 + } 41.634 +#endif 41.635 + if (!new_ptr) { 41.636 + tc->magic = TALLOC_MAGIC; 41.637 + return NULL; 41.638 + } 41.639 + 41.640 + tc = new_ptr; 41.641 + tc->magic = TALLOC_MAGIC; 41.642 + if (tc->parent) { 41.643 + tc->parent->child = new_ptr; 41.644 + } 41.645 + if (tc->child) { 41.646 + tc->child->parent = new_ptr; 41.647 + } 41.648 + 41.649 + if (tc->prev) { 41.650 + tc->prev->next = tc; 41.651 + } 41.652 + if (tc->next) { 41.653 + tc->next->prev = tc; 41.654 + } 41.655 + 41.656 + tc->size = size; 41.657 + talloc_set_name_const(tc+1, name); 41.658 + 41.659 + return (void *)(tc+1); 41.660 +} 41.661 + 41.662 +/* 41.663 + move a lump of memory from one talloc context to another return the 41.664 + ptr on success, or NULL if it could not be transferred. 41.665 + passing NULL as ptr will always return NULL with no side effects. 41.666 +*/ 41.667 +void *talloc_steal(const void *new_ctx, const void *ptr) 41.668 +{ 41.669 + struct talloc_chunk *tc, *new_tc; 41.670 + 41.671 + if (!ptr) { 41.672 + return NULL; 41.673 + } 41.674 + 41.675 + if (new_ctx == NULL) { 41.676 + new_ctx = null_context; 41.677 + } 41.678 + 41.679 + tc = talloc_chunk_from_ptr(ptr); 41.680 + 41.681 + if (new_ctx == NULL) { 41.682 + if (tc->parent) { 41.683 + _TLIST_REMOVE(tc->parent->child, tc); 41.684 + if (tc->parent->child) { 41.685 + tc->parent->child->parent = tc->parent; 41.686 + } 41.687 + } else { 41.688 + if (tc->prev) tc->prev->next = tc->next; 41.689 + if (tc->next) tc->next->prev = tc->prev; 41.690 + } 41.691 + 41.692 + tc->parent = tc->next = tc->prev = NULL; 41.693 + return discard_const_p(void, ptr); 41.694 + } 41.695 + 41.696 + new_tc = talloc_chunk_from_ptr(new_ctx); 41.697 + 41.698 + if (tc == new_tc) { 41.699 + return discard_const_p(void, ptr); 41.700 + } 41.701 + 41.702 + if (tc->parent) { 41.703 + _TLIST_REMOVE(tc->parent->child, tc); 41.704 + if (tc->parent->child) { 41.705 + tc->parent->child->parent = tc->parent; 41.706 + } 41.707 + } else { 41.708 + if (tc->prev) tc->prev->next = tc->next; 41.709 + if (tc->next) tc->next->prev = tc->prev; 41.710 + } 41.711 + 41.712 + tc->parent = new_tc; 41.713 + if (new_tc->child) new_tc->child->parent = NULL; 41.714 + _TLIST_ADD(new_tc->child, tc); 41.715 + 41.716 + return discard_const_p(void, ptr); 41.717 +} 41.718 + 41.719 +/* 41.720 + return the total size of a talloc pool (subtree) 41.721 +*/ 41.722 +off_t talloc_total_size(const void *ptr) 41.723 +{ 41.724 + off_t total = 0; 41.725 + struct talloc_chunk *c, *tc; 41.726 + 41.727 + if (ptr == NULL) { 41.728 + ptr = null_context; 41.729 + } 41.730 + if (ptr == NULL) { 41.731 + return 0; 41.732 + } 41.733 + 41.734 + tc = talloc_chunk_from_ptr(ptr); 41.735 + 41.736 + total = tc->size; 41.737 + for (c=tc->child;c;c=c->next) { 41.738 + total += talloc_total_size(c+1); 41.739 + } 41.740 + return total; 41.741 +} 41.742 + 41.743 +/* 41.744 + return the total number of blocks in a talloc pool (subtree) 41.745 +*/ 41.746 +off_t talloc_total_blocks(const void *ptr) 41.747 +{ 41.748 + off_t total = 0; 41.749 + struct talloc_chunk *c, *tc; 41.750 + 41.751 + if (ptr == NULL) { 41.752 + ptr = null_context; 41.753 + } 41.754 + if (ptr == NULL) { 41.755 + return 0; 41.756 + } 41.757 + tc = talloc_chunk_from_ptr(ptr); 41.758 + 41.759 + total++; 41.760 + for (c=tc->child;c;c=c->next) { 41.761 + total += talloc_total_blocks(c+1); 41.762 + } 41.763 + return total; 41.764 +} 41.765 + 41.766 +/* 41.767 + return the number of external references to a pointer 41.768 +*/ 41.769 +static int talloc_reference_count(const void *ptr) 41.770 +{ 41.771 + struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); 41.772 + struct talloc_reference_handle *h; 41.773 + int ret = 0; 41.774 + 41.775 + for (h=tc->refs;h;h=h->next) { 41.776 + ret++; 41.777 + } 41.778 + return ret; 41.779 +} 41.780 + 41.781 +/* 41.782 + report on memory usage by all children of a pointer, giving a full tree view 41.783 +*/ 41.784 +void talloc_report_depth(const void *ptr, FILE *f, int depth) 41.785 +{ 41.786 + struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr); 41.787 + 41.788 + for (c=tc->child;c;c=c->next) { 41.789 + if (c->name == TALLOC_MAGIC_REFERENCE) { 41.790 + struct talloc_reference_handle *handle = (void *)(c+1); 41.791 + const char *name2 = talloc_get_name(handle->ptr); 41.792 + fprintf(f, "%*sreference to: %s\n", depth*4, "", name2); 41.793 + } else { 41.794 + const char *name = talloc_get_name(c+1); 41.795 + fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d)\n", 41.796 + depth*4, "", 41.797 + name, 41.798 + (unsigned long)talloc_total_size(c+1), 41.799 + (unsigned long)talloc_total_blocks(c+1), 41.800 + talloc_reference_count(c+1)); 41.801 + talloc_report_depth(c+1, f, depth+1); 41.802 + } 41.803 + } 41.804 + 41.805 +} 41.806 + 41.807 +/* 41.808 + report on memory usage by all children of a pointer, giving a full tree view 41.809 +*/ 41.810 +void talloc_report_full(const void *ptr, FILE *f) 41.811 +{ 41.812 + if (ptr == NULL) { 41.813 + ptr = null_context; 41.814 + } 41.815 + if (ptr == NULL) return; 41.816 + 41.817 + fprintf(f,"full talloc report on '%s' (total %lu bytes in %lu blocks)\n", 41.818 + talloc_get_name(ptr), 41.819 + (unsigned long)talloc_total_size(ptr), 41.820 + (unsigned long)talloc_total_blocks(ptr)); 41.821 + 41.822 + talloc_report_depth(ptr, f, 1); 41.823 + fflush(f); 41.824 +} 41.825 + 41.826 +/* 41.827 + report on memory usage by all children of a pointer 41.828 +*/ 41.829 +void talloc_report(const void *ptr, FILE *f) 41.830 +{ 41.831 + struct talloc_chunk *c, *tc; 41.832 + 41.833 + if (ptr == NULL) { 41.834 + ptr = null_context; 41.835 + } 41.836 + if (ptr == NULL) return; 41.837 + 41.838 + fprintf(f,"talloc report on '%s' (total %lu bytes in %lu blocks)\n", 41.839 + talloc_get_name(ptr), 41.840 + (unsigned long)talloc_total_size(ptr), 41.841 + (unsigned long)talloc_total_blocks(ptr)); 41.842 + 41.843 + tc = talloc_chunk_from_ptr(ptr); 41.844 + 41.845 + for (c=tc->child;c;c=c->next) { 41.846 + fprintf(f, "\t%-30s contains %6lu bytes in %3lu blocks\n", 41.847 + talloc_get_name(c+1), 41.848 + (unsigned long)talloc_total_size(c+1), 41.849 + (unsigned long)talloc_total_blocks(c+1)); 41.850 + } 41.851 + fflush(f); 41.852 +} 41.853 + 41.854 +/* 41.855 + report on any memory hanging off the null context 41.856 +*/ 41.857 +static void talloc_report_null(void) 41.858 +{ 41.859 + if (talloc_total_size(null_context) != 0) { 41.860 + talloc_report(null_context, stderr); 41.861 + } 41.862 +} 41.863 + 41.864 +/* 41.865 + report on any memory hanging off the null context 41.866 +*/ 41.867 +static void talloc_report_null_full(void) 41.868 +{ 41.869 + if (talloc_total_size(null_context) != 0) { 41.870 + talloc_report_full(null_context, stderr); 41.871 + } 41.872 +} 41.873 + 41.874 +/* 41.875 + enable tracking of the NULL context 41.876 +*/ 41.877 +void talloc_enable_null_tracking(void) 41.878 +{ 41.879 + if (null_context == NULL) { 41.880 + null_context = talloc_named_const(NULL, 0, "null_context"); 41.881 + } 41.882 +} 41.883 + 41.884 +/* 41.885 + enable leak reporting on exit 41.886 +*/ 41.887 +void talloc_enable_leak_report(void) 41.888 +{ 41.889 + talloc_enable_null_tracking(); 41.890 + atexit(talloc_report_null); 41.891 +} 41.892 + 41.893 +/* 41.894 + enable full leak reporting on exit 41.895 +*/ 41.896 +void talloc_enable_leak_report_full(void) 41.897 +{ 41.898 + talloc_enable_null_tracking(); 41.899 + atexit(talloc_report_null_full); 41.900 +} 41.901 + 41.902 +/* 41.903 + talloc and zero memory. 41.904 +*/ 41.905 +void *_talloc_zero(const void *ctx, size_t size, const char *name) 41.906 +{ 41.907 + void *p = talloc_named_const(ctx, size, name); 41.908 + 41.909 + if (p) { 41.910 + memset(p, '\0', size); 41.911 + } 41.912 + 41.913 + return p; 41.914 +} 41.915 + 41.916 + 41.917 +/* 41.918 + memdup with a talloc. 41.919 +*/ 41.920 +void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name) 41.921 +{ 41.922 + void *newp = talloc_named_const(t, size, name); 41.923 + 41.924 + if (newp) { 41.925 + memcpy(newp, p, size); 41.926 + } 41.927 + 41.928 + return newp; 41.929 +} 41.930 + 41.931 +/* 41.932 + strdup with a talloc 41.933 +*/ 41.934 +char *talloc_strdup(const void *t, const char *p) 41.935 +{ 41.936 + char *ret; 41.937 + if (!p) { 41.938 + return NULL; 41.939 + } 41.940 + ret = talloc_memdup(t, p, strlen(p) + 1); 41.941 + if (ret) { 41.942 + talloc_set_name_const(ret, ret); 41.943 + } 41.944 + return ret; 41.945 +} 41.946 + 41.947 +/* 41.948 + strndup with a talloc 41.949 +*/ 41.950 +char *talloc_strndup(const void *t, const char *p, size_t n) 41.951 +{ 41.952 + size_t len; 41.953 + char *ret; 41.954 + 41.955 + for (len=0; p[len] && len<n; len++) ; 41.956 + 41.957 + ret = _talloc(t, len + 1); 41.958 + if (!ret) { return NULL; } 41.959 + memcpy(ret, p, len); 41.960 + ret[len] = 0; 41.961 + talloc_set_name_const(ret, ret); 41.962 + return ret; 41.963 +} 41.964 + 41.965 +#ifndef VA_COPY 41.966 +#ifdef HAVE_VA_COPY 41.967 +#define VA_COPY(dest, src) va_copy(dest, src) 41.968 +#elif defined(HAVE___VA_COPY) 41.969 +#define VA_COPY(dest, src) __va_copy(dest, src) 41.970 +#else 41.971 +#define VA_COPY(dest, src) (dest) = (src) 41.972 +#endif 41.973 +#endif 41.974 + 41.975 +char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) 41.976 +{ 41.977 + int len; 41.978 + char *ret; 41.979 + va_list ap2; 41.980 + 41.981 + VA_COPY(ap2, ap); 41.982 + 41.983 + len = vsnprintf(NULL, 0, fmt, ap2); 41.984 + 41.985 + ret = _talloc(t, len+1); 41.986 + if (ret) { 41.987 + VA_COPY(ap2, ap); 41.988 + vsnprintf(ret, len+1, fmt, ap2); 41.989 + talloc_set_name_const(ret, ret); 41.990 + } 41.991 + 41.992 + return ret; 41.993 +} 41.994 + 41.995 + 41.996 +/* 41.997 + Perform string formatting, and return a pointer to newly allocated 41.998 + memory holding the result, inside a memory pool. 41.999 + */ 41.1000 +char *talloc_asprintf(const void *t, const char *fmt, ...) 41.1001 +{ 41.1002 + va_list ap; 41.1003 + char *ret; 41.1004 + 41.1005 + va_start(ap, fmt); 41.1006 + ret = talloc_vasprintf(t, fmt, ap); 41.1007 + va_end(ap); 41.1008 + return ret; 41.1009 +} 41.1010 + 41.1011 + 41.1012 +/** 41.1013 + * Realloc @p s to append the formatted result of @p fmt and @p ap, 41.1014 + * and return @p s, which may have moved. Good for gradually 41.1015 + * accumulating output into a string buffer. 41.1016 + **/ 41.1017 + 41.1018 +static char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0); 41.1019 + 41.1020 +static char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) 41.1021 +{ 41.1022 + struct talloc_chunk *tc; 41.1023 + int len, s_len; 41.1024 + va_list ap2; 41.1025 + 41.1026 + if (s == NULL) { 41.1027 + return talloc_vasprintf(NULL, fmt, ap); 41.1028 + } 41.1029 + 41.1030 + tc = talloc_chunk_from_ptr(s); 41.1031 + 41.1032 + VA_COPY(ap2, ap); 41.1033 + 41.1034 + s_len = tc->size - 1; 41.1035 + len = vsnprintf(NULL, 0, fmt, ap2); 41.1036 + 41.1037 + s = talloc_realloc(NULL, s, char, s_len + len+1); 41.1038 + if (!s) return NULL; 41.1039 + 41.1040 + VA_COPY(ap2, ap); 41.1041 + 41.1042 + vsnprintf(s+s_len, len+1, fmt, ap2); 41.1043 + talloc_set_name_const(s, s); 41.1044 + 41.1045 + return s; 41.1046 +} 41.1047 + 41.1048 +/* 41.1049 + Realloc @p s to append the formatted result of @p fmt and return @p 41.1050 + s, which may have moved. Good for gradually accumulating output 41.1051 + into a string buffer. 41.1052 + */ 41.1053 +char *talloc_asprintf_append(char *s, const char *fmt, ...) 41.1054 +{ 41.1055 + va_list ap; 41.1056 + 41.1057 + va_start(ap, fmt); 41.1058 + s = talloc_vasprintf_append(s, fmt, ap); 41.1059 + va_end(ap); 41.1060 + return s; 41.1061 +} 41.1062 + 41.1063 +/* 41.1064 + alloc an array, checking for integer overflow in the array size 41.1065 +*/ 41.1066 +void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name) 41.1067 +{ 41.1068 + if (count >= MAX_TALLOC_SIZE/el_size) { 41.1069 + return NULL; 41.1070 + } 41.1071 + return talloc_named_const(ctx, el_size * count, name); 41.1072 +} 41.1073 + 41.1074 +/* 41.1075 + alloc an zero array, checking for integer overflow in the array size 41.1076 +*/ 41.1077 +void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name) 41.1078 +{ 41.1079 + if (count >= MAX_TALLOC_SIZE/el_size) { 41.1080 + return NULL; 41.1081 + } 41.1082 + return _talloc_zero(ctx, el_size * count, name); 41.1083 +} 41.1084 + 41.1085 + 41.1086 +/* 41.1087 + realloc an array, checking for integer overflow in the array size 41.1088 +*/ 41.1089 +void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name) 41.1090 +{ 41.1091 + if (count >= MAX_TALLOC_SIZE/el_size) { 41.1092 + return NULL; 41.1093 + } 41.1094 + return _talloc_realloc(ctx, ptr, el_size * count, name); 41.1095 +} 41.1096 + 41.1097 +/* 41.1098 + a function version of talloc_realloc(), so it can be passed as a function pointer 41.1099 + to libraries that want a realloc function (a realloc function encapsulates 41.1100 + all the basic capabilities of an allocation library, which is why this is useful) 41.1101 +*/ 41.1102 +void *talloc_realloc_fn(const void *context, void *ptr, size_t size) 41.1103 +{ 41.1104 + return _talloc_realloc(context, ptr, size, NULL); 41.1105 +} 41.1106 + 41.1107 + 41.1108 +static void talloc_autofree(void) 41.1109 +{ 41.1110 + talloc_free(cleanup_context); 41.1111 + cleanup_context = NULL; 41.1112 +} 41.1113 + 41.1114 +/* 41.1115 + return a context which will be auto-freed on exit 41.1116 + this is useful for reducing the noise in leak reports 41.1117 +*/ 41.1118 +void *talloc_autofree_context(void) 41.1119 +{ 41.1120 + if (cleanup_context == NULL) { 41.1121 + cleanup_context = talloc_named_const(NULL, 0, "autofree_context"); 41.1122 + atexit(talloc_autofree); 41.1123 + } 41.1124 + return cleanup_context; 41.1125 +} 41.1126 + 41.1127 +size_t talloc_get_size(const void *context) 41.1128 +{ 41.1129 + struct talloc_chunk *tc; 41.1130 + 41.1131 + if (context == NULL) 41.1132 + return 0; 41.1133 + 41.1134 + tc = talloc_chunk_from_ptr(context); 41.1135 + 41.1136 + return tc->size; 41.1137 +} 41.1138 + 41.1139 +talloc_fail_handler *talloc_set_fail_handler(talloc_fail_handler *handler, 41.1140 + void *data) 41.1141 +{ 41.1142 + talloc_fail_handler *old = malloc_fail_handler; 41.1143 + malloc_fail_handler = handler; 41.1144 + malloc_fail_data = data; 41.1145 + return old; 41.1146 +}
42.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 42.2 +++ b/tools/xenstore/talloc.h Thu Jun 09 14:40:39 2005 +0000 42.3 @@ -0,0 +1,134 @@ 42.4 +#ifndef _TALLOC_H_ 42.5 +#define _TALLOC_H_ 42.6 +/* 42.7 + Unix SMB/CIFS implementation. 42.8 + Samba temporary memory allocation functions 42.9 + 42.10 + Copyright (C) Andrew Tridgell 2004-2005 42.11 + 42.12 + This program is free software; you can redistribute it and/or modify 42.13 + it under the terms of the GNU General Public License as published by 42.14 + the Free Software Foundation; either version 2 of the License, or 42.15 + (at your option) any later version. 42.16 + 42.17 + This program is distributed in the hope that it will be useful, 42.18 + but WITHOUT ANY WARRANTY; without even the implied warranty of 42.19 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 42.20 + GNU General Public License for more details. 42.21 + 42.22 + You should have received a copy of the GNU General Public License 42.23 + along with this program; if not, write to the Free Software 42.24 + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 42.25 +*/ 42.26 + 42.27 +/* this is only needed for compatibility with the old talloc */ 42.28 +typedef void TALLOC_CTX; 42.29 + 42.30 +/* 42.31 + this uses a little trick to allow __LINE__ to be stringified 42.32 +*/ 42.33 +#define _STRING_LINE_(s) #s 42.34 +#define _STRING_LINE2_(s) _STRING_LINE_(s) 42.35 +#define __LINESTR__ _STRING_LINE2_(__LINE__) 42.36 +#define __location__ __FILE__ ":" __LINESTR__ 42.37 + 42.38 +#ifndef TALLOC_DEPRECATED 42.39 +#define TALLOC_DEPRECATED 0 42.40 +#endif 42.41 + 42.42 +/* useful macros for creating type checked pointers */ 42.43 +#define talloc(ctx, type) (type *)talloc_named_const(ctx, sizeof(type), #type) 42.44 +#define talloc_size(ctx, size) talloc_named_const(ctx, size, __location__) 42.45 + 42.46 +#define talloc_new(ctx) talloc_named_const(ctx, 0, "talloc_new: " __location__) 42.47 + 42.48 +#define talloc_zero(ctx, type) (type *)_talloc_zero(ctx, sizeof(type), #type) 42.49 +#define talloc_zero_size(ctx, size) _talloc_zero(ctx, size, __location__) 42.50 + 42.51 +#define talloc_zero_array(ctx, type, count) (type *)_talloc_zero_array(ctx, sizeof(type), count, #type) 42.52 +#define talloc_array(ctx, type, count) (type *)_talloc_array(ctx, sizeof(type), count, #type) 42.53 +#define talloc_array_size(ctx, size, count) _talloc_array(ctx, size, count, __location__) 42.54 + 42.55 +#define talloc_realloc(ctx, p, type, count) (type *)_talloc_realloc_array(ctx, p, sizeof(type), count, #type) 42.56 +#define talloc_realloc_size(ctx, ptr, size) _talloc_realloc(ctx, ptr, size, __location__) 42.57 + 42.58 +#define talloc_memdup(t, p, size) _talloc_memdup(t, p, size, __location__) 42.59 + 42.60 +#define malloc_p(type) (type *)malloc(sizeof(type)) 42.61 +#define malloc_array_p(type, count) (type *)realloc_array(NULL, sizeof(type), count) 42.62 +#define realloc_p(p, type, count) (type *)realloc_array(p, sizeof(type), count) 42.63 + 42.64 +#define data_blob(ptr, size) data_blob_named(ptr, size, "DATA_BLOB: "__location__) 42.65 +#define data_blob_talloc(ctx, ptr, size) data_blob_talloc_named(ctx, ptr, size, "DATA_BLOB: "__location__) 42.66 +#define data_blob_dup_talloc(ctx, blob) data_blob_talloc_named(ctx, (blob)->data, (blob)->length, "DATA_BLOB: "__location__) 42.67 + 42.68 +#define talloc_set_type(ptr, type) talloc_set_name_const(ptr, #type) 42.69 +#define talloc_get_type(ptr, type) (type *)talloc_check_name(ptr, #type) 42.70 + 42.71 + 42.72 +#if TALLOC_DEPRECATED 42.73 +#define talloc_zero_p(ctx, type) talloc_zero(ctx, type) 42.74 +#define talloc_p(ctx, type) talloc(ctx, type) 42.75 +#define talloc_array_p(ctx, type, count) talloc_array(ctx, type, count) 42.76 +#define talloc_realloc_p(ctx, p, type, count) talloc_realloc(ctx, p, type, count) 42.77 +#define talloc_destroy(ctx) talloc_free(ctx) 42.78 +#endif 42.79 + 42.80 +#ifndef PRINTF_ATTRIBUTE 42.81 +#if (__GNUC__ >= 3) 42.82 +/** Use gcc attribute to check printf fns. a1 is the 1-based index of 42.83 + * the parameter containing the format, and a2 the index of the first 42.84 + * argument. Note that some gcc 2.x versions don't handle this 42.85 + * properly **/ 42.86 +#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2))) 42.87 +#else 42.88 +#define PRINTF_ATTRIBUTE(a1, a2) 42.89 +#endif 42.90 +#endif 42.91 + 42.92 + 42.93 +/* The following definitions come from talloc.c */ 42.94 +void *_talloc(const void *context, size_t size); 42.95 +void talloc_set_destructor(const void *ptr, int (*destructor)(void *)); 42.96 +void talloc_increase_ref_count(const void *ptr); 42.97 +void *talloc_reference(const void *context, const void *ptr); 42.98 +int talloc_unlink(const void *context, void *ptr); 42.99 +void talloc_set_name(const void *ptr, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3); 42.100 +void talloc_set_name_const(const void *ptr, const char *name); 42.101 +void *talloc_named(const void *context, size_t size, 42.102 + const char *fmt, ...) PRINTF_ATTRIBUTE(3,4); 42.103 +void *talloc_named_const(const void *context, size_t size, const char *name); 42.104 +const char *talloc_get_name(const void *ptr); 42.105 +void *talloc_check_name(const void *ptr, const char *name); 42.106 +void talloc_report_depth(const void *ptr, FILE *f, int depth); 42.107 +void *talloc_parent(const void *ptr); 42.108 +void *talloc_init(const char *fmt, ...) PRINTF_ATTRIBUTE(1,2); 42.109 +int talloc_free(void *ptr); 42.110 +void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name); 42.111 +void *talloc_steal(const void *new_ctx, const void *ptr); 42.112 +off_t talloc_total_size(const void *ptr); 42.113 +off_t talloc_total_blocks(const void *ptr); 42.114 +void talloc_report_full(const void *ptr, FILE *f); 42.115 +void talloc_report(const void *ptr, FILE *f); 42.116 +void talloc_enable_null_tracking(void); 42.117 +void talloc_enable_leak_report(void); 42.118 +void talloc_enable_leak_report_full(void); 42.119 +void *_talloc_zero(const void *ctx, size_t size, const char *name); 42.120 +void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name); 42.121 +char *talloc_strdup(const void *t, const char *p); 42.122 +char *talloc_strndup(const void *t, const char *p, size_t n); 42.123 +char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0); 42.124 +char *talloc_asprintf(const void *t, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3); 42.125 +char *talloc_asprintf_append(char *s, 42.126 + const char *fmt, ...) PRINTF_ATTRIBUTE(2,3); 42.127 +void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name); 42.128 +void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name); 42.129 +void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name); 42.130 +void *talloc_realloc_fn(const void *context, void *ptr, size_t size); 42.131 +void *talloc_autofree_context(void); 42.132 +size_t talloc_get_size(const void *ctx); 42.133 + 42.134 +typedef int talloc_fail_handler(void *); 42.135 +talloc_fail_handler *talloc_set_fail_handler(talloc_fail_handler *, void *); 42.136 +#endif 42.137 +
43.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 43.2 +++ b/tools/xenstore/talloc_guide.txt Thu Jun 09 14:40:39 2005 +0000 43.3 @@ -0,0 +1,569 @@ 43.4 +Using talloc in Samba4 43.5 +---------------------- 43.6 + 43.7 +Andrew Tridgell 43.8 +September 2004 43.9 + 43.10 +The most current version of this document is available at 43.11 + http://samba.org/ftp/unpacked/samba4/source/lib/talloc/talloc_guide.txt 43.12 + 43.13 +If you are used to talloc from Samba3 then please read this carefully, 43.14 +as talloc has changed a lot. 43.15 + 43.16 +The new talloc is a hierarchical, reference counted memory pool system 43.17 +with destructors. Quite a mounthful really, but not too bad once you 43.18 +get used to it. 43.19 + 43.20 +Perhaps the biggest change from Samba3 is that there is no distinction 43.21 +between a "talloc context" and a "talloc pointer". Any pointer 43.22 +returned from talloc() is itself a valid talloc context. This means 43.23 +you can do this: 43.24 + 43.25 + struct foo *X = talloc(mem_ctx, struct foo); 43.26 + X->name = talloc_strdup(X, "foo"); 43.27 + 43.28 +and the pointer X->name would be a "child" of the talloc context "X" 43.29 +which is itself a child of mem_ctx. So if you do talloc_free(mem_ctx) 43.30 +then it is all destroyed, whereas if you do talloc_free(X) then just X 43.31 +and X->name are destroyed, and if you do talloc_free(X->name) then 43.32 +just the name element of X is destroyed. 43.33 + 43.34 +If you think about this, then what this effectively gives you is an 43.35 +n-ary tree, where you can free any part of the tree with 43.36 +talloc_free(). 43.37 + 43.38 +If you find this confusing, then I suggest you run the testsuite to 43.39 +watch talloc in action. You may also like to add your own tests to 43.40 +testsuite.c to clarify how some particular situation is handled. 43.41 + 43.42 + 43.43 +Performance 43.44 +----------- 43.45 + 43.46 +All the additional features of talloc() over malloc() do come at a 43.47 +price. We have a simple performance test in Samba4 that measures 43.48 +talloc() versus malloc() performance, and it seems that talloc() is 43.49 +about 10% slower than malloc() on my x86 Debian Linux box. For Samba, 43.50 +the great reduction in code complexity that we get by using talloc 43.51 +makes this worthwhile, especially as the total overhead of 43.52 +talloc/malloc in Samba is already quite small. 43.53 + 43.54 + 43.55 +talloc API 43.56 +---------- 43.57 + 43.58 +The following is a complete guide to the talloc API. Read it all at 43.59 +least twice. 43.60 + 43.61 + 43.62 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.63 +(type *)talloc(const void *context, type); 43.64 + 43.65 +The talloc() macro is the core of the talloc library. It takes a 43.66 +memory context and a type, and returns a pointer to a new area of 43.67 +memory of the given type. 43.68 + 43.69 +The returned pointer is itself a talloc context, so you can use it as 43.70 +the context argument to more calls to talloc if you wish. 43.71 + 43.72 +The returned pointer is a "child" of the supplied context. This means 43.73 +that if you talloc_free() the context then the new child disappears as 43.74 +well. Alternatively you can free just the child. 43.75 + 43.76 +The context argument to talloc() can be NULL, in which case a new top 43.77 +level context is created. 43.78 + 43.79 + 43.80 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.81 +void *talloc_size(const void *context, size_t size); 43.82 + 43.83 +The function talloc_size() should be used when you don't have a 43.84 +convenient type to pass to talloc(). Unlike talloc(), it is not type 43.85 +safe (as it returns a void *), so you are on your own for type checking. 43.86 + 43.87 + 43.88 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.89 +int talloc_free(void *ptr); 43.90 + 43.91 +The talloc_free() function frees a piece of talloc memory, and all its 43.92 +children. You can call talloc_free() on any pointer returned by 43.93 +talloc(). 43.94 + 43.95 +The return value of talloc_free() indicates success or failure, with 0 43.96 +returned for success and -1 for failure. The only possible failure 43.97 +condition is if the pointer had a destructor attached to it and the 43.98 +destructor returned -1. See talloc_set_destructor() for details on 43.99 +destructors. 43.100 + 43.101 +If this pointer has an additional parent when talloc_free() is called 43.102 +then the memory is not actually released, but instead the most 43.103 +recently established parent is destroyed. See talloc_reference() for 43.104 +details on establishing additional parents. 43.105 + 43.106 +For more control on which parent is removed, see talloc_unlink() 43.107 + 43.108 +talloc_free() operates recursively on its children. 43.109 + 43.110 + 43.111 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.112 +int talloc_free_children(void *ptr); 43.113 + 43.114 +The talloc_free_children() walks along the list of all children of a 43.115 +talloc context and talloc_free()s only the children, not the context 43.116 +itself. 43.117 + 43.118 + 43.119 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.120 +void *talloc_reference(const void *context, const void *ptr); 43.121 + 43.122 +The talloc_reference() function makes "context" an additional parent 43.123 +of "ptr". 43.124 + 43.125 +The return value of talloc_reference() is always the original pointer 43.126 +"ptr", unless talloc ran out of memory in creating the reference in 43.127 +which case it will return NULL (each additional reference consumes 43.128 +around 48 bytes of memory on intel x86 platforms). 43.129 + 43.130 +If "ptr" is NULL, then the function is a no-op, and simply returns NULL. 43.131 + 43.132 +After creating a reference you can free it in one of the following 43.133 +ways: 43.134 + 43.135 + - you can talloc_free() any parent of the original pointer. That 43.136 + will reduce the number of parents of this pointer by 1, and will 43.137 + cause this pointer to be freed if it runs out of parents. 43.138 + 43.139 + - you can talloc_free() the pointer itself. That will destroy the 43.140 + most recently established parent to the pointer and leave the 43.141 + pointer as a child of its current parent. 43.142 + 43.143 +For more control on which parent to remove, see talloc_unlink() 43.144 + 43.145 + 43.146 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.147 +int talloc_unlink(const void *context, const void *ptr); 43.148 + 43.149 +The talloc_unlink() function removes a specific parent from ptr. The 43.150 +context passed must either be a context used in talloc_reference() 43.151 +with this pointer, or must be a direct parent of ptr. 43.152 + 43.153 +Note that if the parent has already been removed using talloc_free() 43.154 +then this function will fail and will return -1. Likewise, if "ptr" 43.155 +is NULL, then the function will make no modifications and return -1. 43.156 + 43.157 +Usually you can just use talloc_free() instead of talloc_unlink(), but 43.158 +sometimes it is useful to have the additional control on which parent 43.159 +is removed. 43.160 + 43.161 + 43.162 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.163 +void talloc_set_destructor(const void *ptr, int (*destructor)(void *)); 43.164 + 43.165 +The function talloc_set_destructor() sets the "destructor" for the 43.166 +pointer "ptr". A destructor is a function that is called when the 43.167 +memory used by a pointer is about to be released. The destructor 43.168 +receives the pointer as an argument, and should return 0 for success 43.169 +and -1 for failure. 43.170 + 43.171 +The destructor can do anything it wants to, including freeing other 43.172 +pieces of memory. A common use for destructors is to clean up 43.173 +operating system resources (such as open file descriptors) contained 43.174 +in the structure the destructor is placed on. 43.175 + 43.176 +You can only place one destructor on a pointer. If you need more than 43.177 +one destructor then you can create a zero-length child of the pointer 43.178 +and place an additional destructor on that. 43.179 + 43.180 +To remove a destructor call talloc_set_destructor() with NULL for the 43.181 +destructor. 43.182 + 43.183 +If your destructor attempts to talloc_free() the pointer that it is 43.184 +the destructor for then talloc_free() will return -1 and the free will 43.185 +be ignored. This would be a pointless operation anyway, as the 43.186 +destructor is only called when the memory is just about to go away. 43.187 + 43.188 + 43.189 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.190 +void talloc_increase_ref_count(const void *ptr); 43.191 + 43.192 +The talloc_increase_ref_count(ptr) function is exactly equivalent to: 43.193 + 43.194 + talloc_reference(NULL, ptr); 43.195 + 43.196 +You can use either syntax, depending on which you think is clearer in 43.197 +your code. 43.198 + 43.199 + 43.200 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.201 +void talloc_set_name(const void *ptr, const char *fmt, ...); 43.202 + 43.203 +Each talloc pointer has a "name". The name is used principally for 43.204 +debugging purposes, although it is also possible to set and get the 43.205 +name on a pointer in as a way of "marking" pointers in your code. 43.206 + 43.207 +The main use for names on pointer is for "talloc reports". See 43.208 +talloc_report() and talloc_report_full() for details. Also see 43.209 +talloc_enable_leak_report() and talloc_enable_leak_report_full(). 43.210 + 43.211 +The talloc_set_name() function allocates memory as a child of the 43.212 +pointer. It is logically equivalent to: 43.213 + talloc_set_name_const(ptr, talloc_asprintf(ptr, fmt, ...)); 43.214 + 43.215 +Note that multiple calls to talloc_set_name() will allocate more 43.216 +memory without releasing the name. All of the memory is released when 43.217 +the ptr is freed using talloc_free(). 43.218 + 43.219 + 43.220 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.221 +void talloc_set_name_const(const void *ptr, const char *name); 43.222 + 43.223 +The function talloc_set_name_const() is just like talloc_set_name(), 43.224 +but it takes a string constant, and is much faster. It is extensively 43.225 +used by the "auto naming" macros, such as talloc_p(). 43.226 + 43.227 +This function does not allocate any memory. It just copies the 43.228 +supplied pointer into the internal representation of the talloc 43.229 +ptr. This means you must not pass a name pointer to memory that will 43.230 +disappear before the ptr is freed with talloc_free(). 43.231 + 43.232 + 43.233 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.234 +void *talloc_named(const void *context, size_t size, const char *fmt, ...); 43.235 + 43.236 +The talloc_named() function creates a named talloc pointer. It is 43.237 +equivalent to: 43.238 + 43.239 + ptr = talloc_size(context, size); 43.240 + talloc_set_name(ptr, fmt, ....); 43.241 + 43.242 + 43.243 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.244 +void *talloc_named_const(const void *context, size_t size, const char *name); 43.245 + 43.246 +This is equivalent to: 43.247 + 43.248 + ptr = talloc_size(context, size); 43.249 + talloc_set_name_const(ptr, name); 43.250 + 43.251 + 43.252 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.253 +const char *talloc_get_name(const void *ptr); 43.254 + 43.255 +This returns the current name for the given talloc pointer. See 43.256 +talloc_set_name() for details. 43.257 + 43.258 + 43.259 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.260 +void *talloc_init(const char *fmt, ...); 43.261 + 43.262 +This function creates a zero length named talloc context as a top 43.263 +level context. It is equivalent to: 43.264 + 43.265 + talloc_named(NULL, 0, fmt, ...); 43.266 + 43.267 + 43.268 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.269 +void *talloc_new(void *ctx); 43.270 + 43.271 +This is a utility macro that creates a new memory context hanging 43.272 +off an exiting context, automatically naming it "talloc_new: __location__" 43.273 +where __location__ is the source line it is called from. It is 43.274 +particularly useful for creating a new temporary working context. 43.275 + 43.276 + 43.277 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.278 +(type *)talloc_realloc(const void *context, void *ptr, type, count); 43.279 + 43.280 +The talloc_realloc() macro changes the size of a talloc 43.281 +pointer. The "count" argument is the number of elements of type "type" 43.282 +that you want the resulting pointer to hold. 43.283 + 43.284 +talloc_realloc() has the following equivalences: 43.285 + 43.286 + talloc_realloc(context, NULL, type, 1) ==> talloc(context, type); 43.287 + talloc_realloc(context, NULL, type, N) ==> talloc_array(context, type, N); 43.288 + talloc_realloc(context, ptr, type, 0) ==> talloc_free(ptr); 43.289 + 43.290 +The "context" argument is only used if "ptr" is not NULL, otherwise it 43.291 +is ignored. 43.292 + 43.293 +talloc_realloc() returns the new pointer, or NULL on failure. The call 43.294 +will fail either due to a lack of memory, or because the pointer has 43.295 +more than one parent (see talloc_reference()). 43.296 + 43.297 + 43.298 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.299 +void *talloc_realloc_size(const void *context, void *ptr, size_t size); 43.300 + 43.301 +the talloc_realloc_size() function is useful when the type is not 43.302 +known so the typesafe talloc_realloc() cannot be used. 43.303 + 43.304 + 43.305 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.306 +void *talloc_steal(const void *new_ctx, const void *ptr); 43.307 + 43.308 +The talloc_steal() function changes the parent context of a talloc 43.309 +pointer. It is typically used when the context that the pointer is 43.310 +currently a child of is going to be freed and you wish to keep the 43.311 +memory for a longer time. 43.312 + 43.313 +The talloc_steal() function returns the pointer that you pass it. It 43.314 +does not have any failure modes. 43.315 + 43.316 +NOTE: It is possible to produce loops in the parent/child relationship 43.317 +if you are not careful with talloc_steal(). No guarantees are provided 43.318 +as to your sanity or the safety of your data if you do this. 43.319 + 43.320 +talloc_steal (new_ctx, NULL) will return NULL with no sideeffects. 43.321 + 43.322 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.323 +off_t talloc_total_size(const void *ptr); 43.324 + 43.325 +The talloc_total_size() function returns the total size in bytes used 43.326 +by this pointer and all child pointers. Mostly useful for debugging. 43.327 + 43.328 +Passing NULL is allowed, but it will only give a meaningful result if 43.329 +talloc_enable_leak_report() or talloc_enable_leak_report_full() has 43.330 +been called. 43.331 + 43.332 + 43.333 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.334 +off_t talloc_total_blocks(const void *ptr); 43.335 + 43.336 +The talloc_total_blocks() function returns the total memory block 43.337 +count used by this pointer and all child pointers. Mostly useful for 43.338 +debugging. 43.339 + 43.340 +Passing NULL is allowed, but it will only give a meaningful result if 43.341 +talloc_enable_leak_report() or talloc_enable_leak_report_full() has 43.342 +been called. 43.343 + 43.344 + 43.345 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.346 +void talloc_report(const void *ptr, FILE *f); 43.347 + 43.348 +The talloc_report() function prints a summary report of all memory 43.349 +used by ptr. One line of report is printed for each immediate child of 43.350 +ptr, showing the total memory and number of blocks used by that child. 43.351 + 43.352 +You can pass NULL for the pointer, in which case a report is printed 43.353 +for the top level memory context, but only if 43.354 +talloc_enable_leak_report() or talloc_enable_leak_report_full() has 43.355 +been called. 43.356 + 43.357 + 43.358 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.359 +void talloc_report_full(const void *ptr, FILE *f); 43.360 + 43.361 +This provides a more detailed report than talloc_report(). It will 43.362 +recursively print the ensire tree of memory referenced by the 43.363 +pointer. References in the tree are shown by giving the name of the 43.364 +pointer that is referenced. 43.365 + 43.366 +You can pass NULL for the pointer, in which case a report is printed 43.367 +for the top level memory context, but only if 43.368 +talloc_enable_leak_report() or talloc_enable_leak_report_full() has 43.369 +been called. 43.370 + 43.371 + 43.372 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.373 +void talloc_enable_leak_report(void); 43.374 + 43.375 +This enables calling of talloc_report(NULL, stderr) when the program 43.376 +exits. In Samba4 this is enabled by using the --leak-report command 43.377 +line option. 43.378 + 43.379 +For it to be useful, this function must be called before any other 43.380 +talloc function as it establishes a "null context" that acts as the 43.381 +top of the tree. If you don't call this function first then passing 43.382 +NULL to talloc_report() or talloc_report_full() won't give you the 43.383 +full tree printout. 43.384 + 43.385 +Here is a typical talloc report: 43.386 + 43.387 +talloc report on 'null_context' (total 267 bytes in 15 blocks) 43.388 + libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks 43.389 + libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks 43.390 + iconv(UTF8,CP850) contains 42 bytes in 2 blocks 43.391 + libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks 43.392 + iconv(CP850,UTF8) contains 42 bytes in 2 blocks 43.393 + iconv(UTF8,UTF-16LE) contains 45 bytes in 2 blocks 43.394 + iconv(UTF-16LE,UTF8) contains 45 bytes in 2 blocks 43.395 + 43.396 + 43.397 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.398 +void talloc_enable_leak_report_full(void); 43.399 + 43.400 +This enables calling of talloc_report_full(NULL, stderr) when the 43.401 +program exits. In Samba4 this is enabled by using the 43.402 +--leak-report-full command line option. 43.403 + 43.404 +For it to be useful, this function must be called before any other 43.405 +talloc function as it establishes a "null context" that acts as the 43.406 +top of the tree. If you don't call this function first then passing 43.407 +NULL to talloc_report() or talloc_report_full() won't give you the 43.408 +full tree printout. 43.409 + 43.410 +Here is a typical full report: 43.411 + 43.412 +full talloc report on 'root' (total 18 bytes in 8 blocks) 43.413 + p1 contains 18 bytes in 7 blocks (ref 0) 43.414 + r1 contains 13 bytes in 2 blocks (ref 0) 43.415 + reference to: p2 43.416 + p2 contains 1 bytes in 1 blocks (ref 1) 43.417 + x3 contains 1 bytes in 1 blocks (ref 0) 43.418 + x2 contains 1 bytes in 1 blocks (ref 0) 43.419 + x1 contains 1 bytes in 1 blocks (ref 0) 43.420 + 43.421 + 43.422 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.423 +void talloc_enable_null_tracking(void); 43.424 + 43.425 +This enables tracking of the NULL memory context without enabling leak 43.426 +reporting on exit. Useful for when you want to do your own leak 43.427 +reporting call via talloc_report_null_full(); 43.428 + 43.429 + 43.430 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.431 +(type *)talloc_zero(const void *ctx, type); 43.432 + 43.433 +The talloc_zero() macro is equivalent to: 43.434 + 43.435 + ptr = talloc(ctx, type); 43.436 + if (ptr) memset(ptr, 0, sizeof(type)); 43.437 + 43.438 + 43.439 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.440 +void *talloc_zero_size(const void *ctx, size_t size) 43.441 + 43.442 +The talloc_zero_size() function is useful when you don't have a known type 43.443 + 43.444 + 43.445 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.446 +void *talloc_memdup(const void *ctx, const void *p, size_t size); 43.447 + 43.448 +The talloc_memdup() function is equivalent to: 43.449 + 43.450 + ptr = talloc_size(ctx, size); 43.451 + if (ptr) memcpy(ptr, p, size); 43.452 + 43.453 + 43.454 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.455 +char *talloc_strdup(const void *ctx, const char *p); 43.456 + 43.457 +The talloc_strdup() function is equivalent to: 43.458 + 43.459 + ptr = talloc_size(ctx, strlen(p)+1); 43.460 + if (ptr) memcpy(ptr, p, strlen(p)+1); 43.461 + 43.462 +This functions sets the name of the new pointer to the passed 43.463 +string. This is equivalent to: 43.464 + talloc_set_name_const(ptr, ptr) 43.465 + 43.466 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.467 +char *talloc_strndup(const void *t, const char *p, size_t n); 43.468 + 43.469 +The talloc_strndup() function is the talloc equivalent of the C 43.470 +library function strndup() 43.471 + 43.472 +This functions sets the name of the new pointer to the passed 43.473 +string. This is equivalent to: 43.474 + talloc_set_name_const(ptr, ptr) 43.475 + 43.476 + 43.477 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.478 +char *talloc_vasprintf(const void *t, const char *fmt, va_list ap); 43.479 + 43.480 +The talloc_vasprintf() function is the talloc equivalent of the C 43.481 +library function vasprintf() 43.482 + 43.483 + 43.484 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.485 +char *talloc_asprintf(const void *t, const char *fmt, ...); 43.486 + 43.487 +The talloc_asprintf() function is the talloc equivalent of the C 43.488 +library function asprintf() 43.489 + 43.490 +This functions sets the name of the new pointer to the passed 43.491 +string. This is equivalent to: 43.492 + talloc_set_name_const(ptr, ptr) 43.493 + 43.494 + 43.495 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.496 +char *talloc_asprintf_append(char *s, const char *fmt, ...); 43.497 + 43.498 +The talloc_asprintf_append() function appends the given formatted 43.499 +string to the given string. 43.500 + 43.501 + 43.502 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.503 +(type *)talloc_array(const void *ctx, type, uint_t count); 43.504 + 43.505 +The talloc_array() macro is equivalent to: 43.506 + 43.507 + (type *)talloc_size(ctx, sizeof(type) * count); 43.508 + 43.509 +except that it provides integer overflow protection for the multiply, 43.510 +returning NULL if the multiply overflows. 43.511 + 43.512 + 43.513 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.514 +void *talloc_array_size(const void *ctx, size_t size, uint_t count); 43.515 + 43.516 +The talloc_array_size() function is useful when the type is not 43.517 +known. It operates in the same way as talloc_array(), but takes a size 43.518 +instead of a type. 43.519 + 43.520 + 43.521 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.522 +void *talloc_realloc_fn(const void *ctx, void *ptr, size_t size); 43.523 + 43.524 +This is a non-macro version of talloc_realloc(), which is useful 43.525 +as libraries sometimes want a ralloc function pointer. A realloc() 43.526 +implementation encapsulates the functionality of malloc(), free() and 43.527 +realloc() in one call, which is why it is useful to be able to pass 43.528 +around a single function pointer. 43.529 + 43.530 + 43.531 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.532 +void *talloc_autofree_context(void); 43.533 + 43.534 +This is a handy utility function that returns a talloc context 43.535 +which will be automatically freed on program exit. This can be used 43.536 +to reduce the noise in memory leak reports. 43.537 + 43.538 + 43.539 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.540 +void *talloc_check_name(const void *ptr, const char *name); 43.541 + 43.542 +This function checks if a pointer has the specified name. If it does 43.543 +then the pointer is returned. It it doesn't then NULL is returned. 43.544 + 43.545 + 43.546 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.547 +(type *)talloc_get_type(const void *ptr, type); 43.548 + 43.549 +This macro allows you to do type checking on talloc pointers. It is 43.550 +particularly useful for void* private pointers. It is equivalent to 43.551 +this: 43.552 + 43.553 + (type *)talloc_check_name(ptr, #type) 43.554 + 43.555 + 43.556 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.557 +talloc_set_type(const void *ptr, type); 43.558 + 43.559 +This macro allows you to force the name of a pointer to be a 43.560 +particular type. This can be used in conjunction with 43.561 +talloc_get_type() to do type checking on void* pointers. 43.562 + 43.563 +It is equivalent to this: 43.564 + talloc_set_name_const(ptr, #type) 43.565 + 43.566 +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 43.567 +talloc_get_size(const void *ctx); 43.568 + 43.569 +This function lets you know the amount of memory alloced so far by 43.570 +this context. It does NOT account for subcontext memory. 43.571 +This can be used to calculate the size of an array. 43.572 +
44.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 44.2 +++ b/tools/xenstore/testsuite/01simple.sh Thu Jun 09 14:40:39 2005 +0000 44.3 @@ -0,0 +1,4 @@ 44.4 +#! /bin/sh 44.5 + 44.6 +# Create an entry, read it. 44.7 +[ "`echo -e 'write /test create contents\nread /test' | ./xs_test 2>&1`" = "contents" ]
45.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 45.2 +++ b/tools/xenstore/testsuite/02directory.sh Thu Jun 09 14:40:39 2005 +0000 45.3 @@ -0,0 +1,31 @@ 45.4 +#! /bin/sh 45.5 + 45.6 +# Root directory has nothing in it. 45.7 +[ "`echo -e 'dir /' | ./xs_test 2>&1`" = "" ] 45.8 + 45.9 +# Create a file. 45.10 +[ "`echo -e 'write /test create contents' | ./xs_test 2>&1`" = "" ] 45.11 + 45.12 +# Directory shows it. 45.13 +[ "`echo -e 'dir /' | ./xs_test 2>&1`" = "test" ] 45.14 + 45.15 +# Make a new directory. 45.16 +[ "`echo -e 'mkdir /dir' | ./xs_test 2>&1`" = "" ] 45.17 + 45.18 +# Check it's there. 45.19 +DIR="`echo -e 'dir /' | ./xs_test 2>&1`" 45.20 +[ "$DIR" = "test 45.21 +dir" ] || [ "$DIR" = "dir 45.22 +test" ] 45.23 + 45.24 +# Check it's empty. 45.25 +[ "`echo -e 'dir /dir' | ./xs_test 2>&1`" = "" ] 45.26 + 45.27 +# Create a file, check it exists. 45.28 +[ "`echo -e 'write /dir/test2 create contents2' | ./xs_test 2>&1`" = "" ] 45.29 +[ "`echo -e 'dir /dir' | ./xs_test 2>&1`" = "test2" ] 45.30 +[ "`echo -e 'read /dir/test2' | ./xs_test 2>&1`" = "contents2" ] 45.31 + 45.32 +# Creating dir over the top should fail. 45.33 +[ "`echo -e 'mkdir /dir' | ./xs_test 2>&1`" = "FATAL: mkdir: File exists" ] 45.34 +[ "`echo -e 'mkdir /dir/test2' | ./xs_test 2>&1`" = "FATAL: mkdir: File exists" ]
46.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 46.2 +++ b/tools/xenstore/testsuite/03write.sh Thu Jun 09 14:40:39 2005 +0000 46.3 @@ -0,0 +1,17 @@ 46.4 +#! /bin/sh 46.5 + 46.6 +# Write without create fails. 46.7 +[ "`echo -e 'write /test none contents' | ./xs_test 2>&1`" = "FATAL: write: No such file or directory" ] 46.8 + 46.9 +# Exclusive write succeeds 46.10 +[ "`echo -e 'write /test excl contents' | ./xs_test 2>&1`" = "" ] 46.11 +[ "`echo -e 'read /test' | ./xs_test 2>&1`" = "contents" ] 46.12 + 46.13 +# Exclusive write fails to overwrite. 46.14 +[ "`echo -e 'write /test excl contents' | ./xs_test 2>&1`" = "FATAL: write: File exists" ] 46.15 + 46.16 +# Non-exclusive overwrite succeeds. 46.17 +[ "`echo -e 'write /test none contents2' | ./xs_test 2>&1`" = "" ] 46.18 +[ "`echo -e 'read /test' | ./xs_test 2>&1`" = "contents2" ] 46.19 +[ "`echo -e 'write /test create contents3' | ./xs_test 2>&1`" = "" ] 46.20 +[ "`echo -e 'read /test' | ./xs_test 2>&1`" = "contents3" ]
47.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 47.2 +++ b/tools/xenstore/testsuite/04rm.sh Thu Jun 09 14:40:39 2005 +0000 47.3 @@ -0,0 +1,18 @@ 47.4 +#! /bin/sh 47.5 + 47.6 +# Remove non-existant fails. 47.7 +[ "`echo -e 'rm /test' | ./xs_test 2>&1`" = "FATAL: rm: No such file or directory" ] 47.8 +[ "`echo -e 'rm /dir/test' | ./xs_test 2>&1`" = "FATAL: rm: No such file or directory" ] 47.9 + 47.10 +# Create file and remove it 47.11 +[ "`echo -e 'write /test excl contents' | ./xs_test 2>&1`" = "" ] 47.12 +[ "`echo -e 'rm /test' | ./xs_test 2>&1`" = "" ] 47.13 + 47.14 +# Create directory and remove it. 47.15 +[ "`echo -e 'mkdir /dir' | ./xs_test 2>&1`" = "" ] 47.16 +[ "`echo -e 'rm /dir' | ./xs_test 2>&1`" = "" ] 47.17 + 47.18 +# Create directory, create file, remove all. 47.19 +[ "`echo -e 'mkdir /dir' | ./xs_test 2>&1`" = "" ] 47.20 +[ "`echo -e 'write /dir/test excl contents' | ./xs_test 2>&1`" = "" ] 47.21 +[ "`echo -e 'rm /dir' | ./xs_test 2>&1`" = "" ]
48.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 48.2 +++ b/tools/xenstore/testsuite/05filepermissions.sh Thu Jun 09 14:40:39 2005 +0000 48.3 @@ -0,0 +1,49 @@ 48.4 +#! /bin/sh 48.5 + 48.6 +# Fail to get perms on non-existent file. 48.7 +[ "`echo -e 'getperm /test' | ./xs_test 2>&1`" = "FATAL: getperm: No such file or directory" ] 48.8 +[ "`echo -e 'getperm /dir/test' | ./xs_test 2>&1`" = "FATAL: getperm: No such file or directory" ] 48.9 + 48.10 +# Create file: we own it, noone has access. 48.11 +[ "`echo -e 'write /test excl contents' | ./xs_test 2>&1`" = "" ] 48.12 +[ "`echo -e 'getperm /test' | ./xs_test 2>&1`" = "0 NONE" ] 48.13 +[ "`echo -e 'setid 1\ngetperm /test' | ./xs_test 2>&1`" = "FATAL: getperm: Permission denied" ] 48.14 +[ "`echo -e 'setid 1\nread /test' | ./xs_test 2>&1`" = "FATAL: read: Permission denied" ] 48.15 +[ "`echo -e 'setid 1\nwrite /test none contents2' | ./xs_test 2>&1`" = "FATAL: write: Permission denied" ] 48.16 + 48.17 +# Grant everyone read access to file. 48.18 +[ "`echo -e 'setperm /test 0 READ' | ./xs_test 2>&1`" = "" ] 48.19 +[ "`echo -e 'setid 1\ngetperm /test' | ./xs_test 2>&1`" = "0 READ" ] 48.20 +[ "`echo -e 'setid 1\nread /test' | ./xs_test 2>&1`" = "contents" ] 48.21 +[ "`echo -e 'setid 1\nwrite /test none contents2' | ./xs_test 2>&1`" = "FATAL: write: Permission denied" ] 48.22 + 48.23 +# Grant everyone write access to file. 48.24 +[ "`echo -e 'setperm /test 0 WRITE' | ./xs_test 2>&1`" = "" ] 48.25 +[ "`echo -e 'setid 1\ngetperm /test' | ./xs_test 2>&1`" = "FATAL: getperm: Permission denied" ] 48.26 +[ "`echo -e 'setid 1\nread /test' | ./xs_test 2>&1`" = "FATAL: read: Permission denied" ] 48.27 +[ "`echo -e 'setid 1\nwrite /test none contents2' | ./xs_test 2>&1`" = "" ] 48.28 +[ "`echo -e 'read /test' | ./xs_test 2>&1`" = "contents2" ] 48.29 + 48.30 +# Grant everyone both read and write access. 48.31 +[ "`echo -e 'setperm /test 0 READ/WRITE' | ./xs_test 2>&1`" = "" ] 48.32 +[ "`echo -e 'setid 1\ngetperm /test' | ./xs_test 2>&1`" = "0 READ/WRITE" ] 48.33 +[ "`echo -e 'setid 1\nread /test' | ./xs_test 2>&1`" = "contents2" ] 48.34 +[ "`echo -e 'setid 1\nwrite /test none contents3' | ./xs_test 2>&1`" = "" ] 48.35 +[ "`echo -e 'setid 1\nread /test' | ./xs_test 2>&1`" = "contents3" ] 48.36 + 48.37 +# Change so that user 1 owns it, noone else can do anything. 48.38 +[ "`echo -e 'setperm /test 1 NONE' | ./xs_test 2>&1`" = "" ] 48.39 +[ "`echo -e 'setid 1\ngetperm /test' | ./xs_test 2>&1`" = "1 NONE" ] 48.40 +[ "`echo -e 'setid 1\nread /test' | ./xs_test 2>&1`" = "contents3" ] 48.41 +[ "`echo -e 'setid 1\nwrite /test none contents4' | ./xs_test 2>&1`" = "" ] 48.42 + 48.43 +# User 2 can do nothing. 48.44 +[ "`echo -e 'setid 2\nsetperm /test 2 NONE' | ./xs_test 2>&1`" = "FATAL: setperm: Permission denied" ] 48.45 +[ "`echo -e 'setid 2\ngetperm /test' | ./xs_test 2>&1`" = "FATAL: getperm: Permission denied" ] 48.46 +[ "`echo -e 'setid 2\nread /test' | ./xs_test 2>&1`" = "FATAL: read: Permission denied" ] 48.47 +[ "`echo -e 'setid 2\nwrite /test none contents4' | ./xs_test 2>&1`" = "FATAL: write: Permission denied" ] 48.48 + 48.49 +# Tools can always access things. 48.50 +[ "`echo -e 'getperm /test' | ./xs_test 2>&1`" = "1 NONE" ] 48.51 +[ "`echo -e 'read /test' | ./xs_test 2>&1`" = "contents4" ] 48.52 +[ "`echo -e 'write /test none contents5' | ./xs_test 2>&1`" = "" ]
49.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 49.2 +++ b/tools/xenstore/testsuite/06dirpermissions.sh Thu Jun 09 14:40:39 2005 +0000 49.3 @@ -0,0 +1,61 @@ 49.4 +#! /bin/sh 49.5 + 49.6 +# Root directory: owned by tool, everyone has read access. 49.7 +[ "`echo -e 'getperm /' | ./xs_test 2>&1`" = "0 READ" ] 49.8 + 49.9 +# Create directory: we own it, noone has access. 49.10 +[ "`echo -e 'mkdir /dir' | ./xs_test 2>&1`" = "" ] 49.11 +[ "`echo -e 'getperm /dir' | ./xs_test 2>&1`" = "0 NONE" ] 49.12 +[ "`echo -e 'setid 1\ndir /dir' | ./xs_test 2>&1`" = "FATAL: dir: Permission denied" ] 49.13 +[ "`echo -e 'setid 1\nread /dir/test create contents2' | ./xs_test 2>&1`" = "FATAL: read: Permission denied" ] 49.14 +[ "`echo -e 'setid 1\nwrite /dir/test create contents2' | ./xs_test 2>&1`" = "FATAL: write: Permission denied" ] 49.15 + 49.16 +# Grant everyone read access to directoy. 49.17 +[ "`echo -e 'setperm /dir 0 READ' | ./xs_test 2>&1`" = "" ] 49.18 +[ "`echo -e 'setid 1\ngetperm /dir' | ./xs_test 2>&1`" = "0 READ" ] 49.19 +[ "`echo -e 'setid 1\ndir /dir' | ./xs_test 2>&1`" = "" ] 49.20 +[ "`echo -e 'setid 1\nwrite /dir/test create contents2' | ./xs_test 2>&1`" = "FATAL: write: Permission denied" ] 49.21 + 49.22 +# Grant everyone write access to directory. 49.23 +[ "`echo -e 'setperm /dir 0 WRITE' | ./xs_test 2>&1`" = "" ] 49.24 +[ "`echo -e 'setid 1\ngetperm /dir' | ./xs_test 2>&1`" = "FATAL: getperm: Permission denied" ] 49.25 +[ "`echo -e 'setid 1\ndir /dir' | ./xs_test 2>&1`" = "FATAL: dir: Permission denied" ] 49.26 +[ "`echo -e 'setid 1\nwrite /dir/test create contents' | ./xs_test 2>&1`" = "" ] 49.27 +[ "`echo -e 'read /dir/test' | ./xs_test 2>&1`" = "contents" ] 49.28 + 49.29 +# Grant everyone both read and write access. 49.30 +[ "`echo -e 'setperm /dir 0 READ/WRITE' | ./xs_test 2>&1`" = "" ] 49.31 +[ "`echo -e 'setid 1\ngetperm /dir' | ./xs_test 2>&1`" = "0 READ/WRITE" ] 49.32 +[ "`echo -e 'setid 1\ndir /dir' | ./xs_test 2>&1`" = "test" ] 49.33 +[ "`echo -e 'setid 1\nwrite /dir/test2 create contents' | ./xs_test 2>&1`" = "" ] 49.34 +[ "`echo -e 'setid 1\nread /dir/test2' | ./xs_test 2>&1`" = "contents" ] 49.35 + 49.36 +# Change so that user 1 owns it, noone else can do anything. 49.37 +[ "`echo -e 'setperm /dir 1 NONE' | ./xs_test 2>&1`" = "" ] 49.38 +[ "`echo -e 'setid 1\ngetperm /dir' | ./xs_test 2>&1`" = "1 NONE" ] 49.39 +[ "`echo -e 'setid 1\ndir /dir' | ./xs_test 2>&1 | sort`" = "test 49.40 +test2" ] 49.41 +[ "`echo -e 'setid 1\nwrite /dir/test3 create contents' | ./xs_test 2>&1`" = "" ] 49.42 + 49.43 +# User 2 can do nothing. Can't even tell if file exists. 49.44 +[ "`echo -e 'setid 2\nsetperm /dir 2 NONE' | ./xs_test 2>&1`" = "FATAL: setperm: Permission denied" ] 49.45 +[ "`echo -e 'setid 2\ngetperm /dir' | ./xs_test 2>&1`" = "FATAL: getperm: Permission denied" ] 49.46 +[ "`echo -e 'setid 2\ndir /dir' | ./xs_test 2>&1`" = "FATAL: dir: Permission denied" ] 49.47 +[ "`echo -e 'setid 2\nread /dir/test' | ./xs_test 2>&1`" = "FATAL: read: Permission denied" ] 49.48 +[ "`echo -e 'setid 2\nread /dir/test2' | ./xs_test 2>&1`" = "FATAL: read: Permission denied" ] 49.49 +[ "`echo -e 'setid 2\nread /dir/test3' | ./xs_test 2>&1`" = "FATAL: read: Permission denied" ] 49.50 +[ "`echo -e 'setid 2\nread /dir/test4' | ./xs_test 2>&1`" = "FATAL: read: Permission denied" ] 49.51 +[ "`echo -e 'setid 2\nwrite /dir/test none contents' | ./xs_test 2>&1`" = "FATAL: write: Permission denied" ] 49.52 +[ "`echo -e 'setid 2\nwrite /dir/test create contents' | ./xs_test 2>&1`" = "FATAL: write: Permission denied" ] 49.53 +[ "`echo -e 'setid 2\nwrite /dir/test excl contents' | ./xs_test 2>&1`" = "FATAL: write: Permission denied" ] 49.54 +[ "`echo -e 'setid 2\nwrite /dir/test4 none contents' | ./xs_test 2>&1`" = "FATAL: write: Permission denied" ] 49.55 +[ "`echo -e 'setid 2\nwrite /dir/test4 create contents' | ./xs_test 2>&1`" = "FATAL: write: Permission denied" ] 49.56 +[ "`echo -e 'setid 2\nwrite /dir/test4 excl contents' | ./xs_test 2>&1`" = "FATAL: write: Permission denied" ] 49.57 + 49.58 +# Tools can always access things. 49.59 +[ "`echo -e 'getperm /dir' | ./xs_test 2>&1`" = "1 NONE" ] 49.60 +[ "`echo -e 'dir /dir' | ./xs_test 2>&1 | sort`" = "test 49.61 +test2 49.62 +test3" ] 49.63 +[ "`echo -e 'write /dir/test4 create contents' | ./xs_test 2>&1`" = "" ] 49.64 +
50.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 50.2 +++ b/tools/xenstore/testsuite/07watch.sh Thu Jun 09 14:40:39 2005 +0000 50.3 @@ -0,0 +1,32 @@ 50.4 +#! /bin/sh 50.5 + 50.6 +# Watch something, write to it, check watch has fired. 50.7 +[ "`echo -e 'write /test create contents' | ./xs_test 2>&1`" = "" ] 50.8 + 50.9 +[ "`echo -e '1 watch /test 100\n2 write /test create contents2\n1 waitwatch\n1 ackwatch' | ./xs_test 2>&1`" = "1:/test" ] 50.10 + 50.11 +# Check that reads don't set it off. 50.12 +[ "`echo -e '1 watch /test 100\n2 read /test\n1 waitwatch' | ./xs_test 2>&1`" = "2:contents2 50.13 +1:waitwatch timeout" ] 50.14 + 50.15 +# mkdir, setperm and rm should (also /tests watching dirs) 50.16 +[ "`echo -e 'mkdir /dir' | ./xs_test 2>&1`" = "" ] 50.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 50.18 +1:/dir/newdir 50.19 +1:/dir/newdir" ] 50.20 + 50.21 +# ignore watches while doing commands, should work. 50.22 +[ "`echo -e 'watch /dir 100\nwrite /dir/test create contents\nread /dir/test\nwaitwatch\nackwatch' | ./xs_test 2>&1`" = "contents 50.23 +/dir/test" ] 50.24 + 50.25 +# watch priority /test. 50.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 50.27 +2:/dir/test 50.28 +1:/dir/test" ] 50.29 + 50.30 +# If one dies (without acking), the other should still get ack. 50.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 50.32 +1:/dir/test" ] 50.33 + 50.34 +# If one dies (without reading at all), the other should still get ack. 50.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" ]
51.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 51.2 +++ b/tools/xenstore/testsuite/08transaction.sh Thu Jun 09 14:40:39 2005 +0000 51.3 @@ -0,0 +1,54 @@ 51.4 +#! /bin/sh 51.5 +# Test transactions. 51.6 + 51.7 +# Simple transaction: create a file inside transaction. 51.8 +[ "`echo -e '1 start / 51.9 +1 write /entry1 create contents 51.10 +2 dir / 51.11 +1 dir / 51.12 +1 commit 51.13 +2 read /entry1' | ./xs_test`" = "1:entry1 51.14 +2:contents" ] 51.15 +echo rm /entry1 | ./xs_test 51.16 + 51.17 +# Create a file and abort transaction. 51.18 +[ "`echo -e '1 start / 51.19 +1 write /entry1 create contents 51.20 +2 dir / 51.21 +1 dir / 51.22 +1 abort 51.23 +2 dir /' | ./xs_test`" = "1:entry1" ] 51.24 + 51.25 +echo write /entry1 create contents | ./xs_test 51.26 +# Delete in transaction, commit 51.27 +[ "`echo -e '1 start / 51.28 +1 rm /entry1 51.29 +2 dir / 51.30 +1 dir / 51.31 +1 commit 51.32 +2 dir /' | ./xs_test`" = "2:entry1" ] 51.33 + 51.34 +# Delete in transaction, abort. 51.35 +echo write /entry1 create contents | ./xs_test 51.36 +[ "`echo -e '1 start / 51.37 +1 rm /entry1 51.38 +2 dir / 51.39 +1 dir / 51.40 +1 abort 51.41 +2 dir /' | ./xs_test`" = "2:entry1 51.42 +2:entry1" ] 51.43 + 51.44 +# Transactions can take as long as the want... 51.45 +[ "`echo -e 'start / 51.46 +sleep 1 51.47 +rm /entry1 51.48 +commit 51.49 +dir /' | ./xs_test`" = "" ] 51.50 + 51.51 +# ... as long as noone is waiting. 51.52 +[ "`echo -e '1 start / 51.53 +2 mkdir /dir 51.54 +1 mkdir /dir 51.55 +1 dir / 51.56 +1 commit' | ./xs_test 2>&1`" = "1:dir 51.57 +FATAL: 1: commit: Connection timed out" ]
52.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 52.2 +++ b/tools/xenstore/testsuite/09domain.sh Thu Jun 09 14:40:39 2005 +0000 52.3 @@ -0,0 +1,15 @@ 52.4 +#! /bin/sh 52.5 +# Test domain communication. 52.6 + 52.7 +# Create a domain, write an entry. 52.8 +[ "`echo -e 'introduce 1 100 7 /my/home 52.9 +1 write /entry1 create contents 52.10 +dir /' | ./xs_test 2>&1`" = "handle is 1 52.11 +entry1" ] 52.12 + 52.13 +# Release that domain. 52.14 +[ "`echo -e 'release 1' | ./xs_test`" = "" ] 52.15 + 52.16 +# Introduce and release by same connection. 52.17 +[ "`echo -e 'introduce 1 100 7 /my/home 52.18 +release 1' | ./xs_test 2>&1`" = "handle is 1" ]
53.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 53.2 +++ b/tools/xenstore/testsuite/test.sh Thu Jun 09 14:40:39 2005 +0000 53.3 @@ -0,0 +1,44 @@ 53.4 +#! /bin/sh 53.5 + 53.6 +set -e 53.7 +set -m 53.8 + 53.9 +run_test() 53.10 +{ 53.11 + rm -rf $XENSTORED_ROOTDIR 53.12 + mkdir $XENSTORED_ROOTDIR 53.13 +# Weird failures with this. 53.14 + if type valgrind >/dev/null 2>&1; then 53.15 + valgrind -q --logfile-fd=3 ./xenstored_test --output-pid --no-fork 3>testsuite/tmp/vgout > /tmp/pid & 53.16 + while [ ! -s /tmp/pid ]; do sleep 0; done 53.17 + PID=`cat /tmp/pid` 53.18 + rm /tmp/pid 53.19 + else 53.20 + PID=`./xenstored_test --output-pid` 53.21 + fi 53.22 + if sh -e $2 $1; then 53.23 + if [ -s testsuite/tmp/vgout ]; then 53.24 + kill $PID 53.25 + echo VALGRIND errors: 53.26 + cat testsuite/tmp/vgout 53.27 + return 1 53.28 + fi 53.29 + echo shutdown | ./xs_test 53.30 + return 0 53.31 + else 53.32 + # In case daemon is wedged. 53.33 + kill $PID 53.34 + sleep 1 53.35 + return 1 53.36 + fi 53.37 +} 53.38 + 53.39 +for f in testsuite/[0-9]*.sh; do 53.40 + if run_test $f; then 53.41 + echo Test $f passed... 53.42 + else 53.43 + echo Test $f failed, running verbosely... 53.44 + run_test $f -x 53.45 + exit 1 53.46 + fi 53.47 +done
54.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 54.2 +++ b/tools/xenstore/utils.c Thu Jun 09 14:40:39 2005 +0000 54.3 @@ -0,0 +1,143 @@ 54.4 +#define _GNU_SOURCE 54.5 +#include <stdio.h> 54.6 +#include <stdarg.h> 54.7 +#include <stdlib.h> 54.8 +#include <string.h> 54.9 +#include <errno.h> 54.10 +#include <unistd.h> 54.11 +#include <fcntl.h> 54.12 +#include <sys/types.h> 54.13 +#include <signal.h> 54.14 + 54.15 +#include "utils.h" 54.16 + 54.17 +void xprintf(const char *fmt, ...) 54.18 +{ 54.19 + static FILE *out = NULL; 54.20 + va_list args; 54.21 + if (!out) 54.22 + out = fopen("/dev/console", "w"); 54.23 + if (!out) 54.24 + out = stderr; 54.25 + 54.26 + va_start(args, fmt); 54.27 + vfprintf(out, fmt, args); 54.28 + va_end(args); 54.29 + fflush(out); 54.30 +} 54.31 + 54.32 +void barf(const char *fmt, ...) 54.33 +{ 54.34 + char *str; 54.35 + va_list arglist; 54.36 + 54.37 + xprintf("FATAL: "); 54.38 + 54.39 + va_start(arglist, fmt); 54.40 + vasprintf(&str, fmt, arglist); 54.41 + va_end(arglist); 54.42 + 54.43 + xprintf("%s\n", str); 54.44 + free(str); 54.45 + exit(1); 54.46 +} 54.47 + 54.48 +void barf_perror(const char *fmt, ...) 54.49 +{ 54.50 + char *str; 54.51 + int err = errno; 54.52 + va_list arglist; 54.53 + 54.54 + xprintf("FATAL: "); 54.55 + 54.56 + va_start(arglist, fmt); 54.57 + vasprintf(&str, fmt, arglist); 54.58 + va_end(arglist); 54.59 + 54.60 + xprintf("%s: %s\n", str, strerror(err)); 54.61 + free(str); 54.62 + exit(1); 54.63 +} 54.64 + 54.65 +void *_realloc_array(void *ptr, size_t size, size_t num) 54.66 +{ 54.67 + if (num >= SIZE_MAX/size) 54.68 + return NULL; 54.69 + return realloc_nofail(ptr, size * num); 54.70 +} 54.71 + 54.72 +void *realloc_nofail(void *ptr, size_t size) 54.73 +{ 54.74 + ptr = realloc(ptr, size); 54.75 + if (ptr) 54.76 + return ptr; 54.77 + barf("realloc of %zu failed", size); 54.78 +} 54.79 + 54.80 +void *malloc_nofail(size_t size) 54.81 +{ 54.82 + void *ptr = malloc(size); 54.83 + if (ptr) 54.84 + return ptr; 54.85 + barf("malloc of %zu failed", size); 54.86 +} 54.87 + 54.88 +/* Stevens. */ 54.89 +void daemonize(void) 54.90 +{ 54.91 + pid_t pid; 54.92 + 54.93 + /* Separate from our parent via fork, so init inherits us. */ 54.94 + if ((pid = fork()) < 0) 54.95 + barf_perror("Failed to fork daemon"); 54.96 + if (pid != 0) 54.97 + exit(0); 54.98 + 54.99 + close(STDIN_FILENO); 54.100 + close(STDOUT_FILENO); 54.101 + close(STDERR_FILENO); 54.102 + 54.103 + /* Session leader so ^C doesn't whack us. */ 54.104 + setsid(); 54.105 + /* Move off any mount points we might be in. */ 54.106 + chdir("/"); 54.107 + /* Discard our parent's old-fashioned umask prejudices. */ 54.108 + umask(0); 54.109 +} 54.110 + 54.111 + 54.112 +/* This version adds one byte (for nul term) */ 54.113 +void *grab_file(const char *filename, unsigned long *size) 54.114 +{ 54.115 + unsigned int max = 16384; 54.116 + int ret, fd; 54.117 + void *buffer; 54.118 + 54.119 + if (streq(filename, "-")) 54.120 + fd = dup(STDIN_FILENO); 54.121 + else 54.122 + fd = open(filename, O_RDONLY, 0); 54.123 + 54.124 + if (fd < 0) 54.125 + return NULL; 54.126 + 54.127 + buffer = malloc(max+1); 54.128 + *size = 0; 54.129 + while ((ret = read(fd, buffer + *size, max - *size)) > 0) { 54.130 + *size += ret; 54.131 + if (*size == max) 54.132 + buffer = realloc(buffer, max *= 2 + 1); 54.133 + } 54.134 + if (ret < 0) { 54.135 + free(buffer); 54.136 + buffer = NULL; 54.137 + } else 54.138 + ((char *)buffer)[*size] = '\0'; 54.139 + close(fd); 54.140 + return buffer; 54.141 +} 54.142 + 54.143 +void release_file(void *data, unsigned long size __attribute__((unused))) 54.144 +{ 54.145 + free(data); 54.146 +}
55.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 55.2 +++ b/tools/xenstore/utils.h Thu Jun 09 14:40:39 2005 +0000 55.3 @@ -0,0 +1,61 @@ 55.4 +#ifndef _UTILS_H 55.5 +#define _UTILS_H 55.6 +#include <stdbool.h> 55.7 +#include <string.h> 55.8 +#include <stdint.h> 55.9 + 55.10 +/* Is A == B ? */ 55.11 +#define streq(a,b) (strcmp((a),(b)) == 0) 55.12 + 55.13 +/* Does A start with B ? */ 55.14 +#define strstarts(a,b) (strncmp((a),(b),strlen(b)) == 0) 55.15 + 55.16 +/* Does A end in B ? */ 55.17 +static inline bool strends(const char *a, const char *b) 55.18 +{ 55.19 + if (strlen(a) < strlen(b)) 55.20 + return false; 55.21 + 55.22 + return streq(a + strlen(a) - strlen(b), b); 55.23 +} 55.24 + 55.25 +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) 55.26 + 55.27 +#define ___stringify(x) #x 55.28 +#define __stringify(x) ___stringify(x) 55.29 + 55.30 +/* Convenient wrappers for malloc and realloc. Use them. */ 55.31 +#define new(type) ((type *)malloc_nofail(sizeof(type))) 55.32 +#define new_array(type, num) realloc_array((type *)0, (num)) 55.33 +#define realloc_array(ptr, num) ((__typeof__(ptr))_realloc_array((ptr), sizeof((*ptr)), (num))) 55.34 + 55.35 +void *malloc_nofail(size_t size); 55.36 +void *realloc_nofail(void *ptr, size_t size); 55.37 +void *_realloc_array(void *ptr, size_t size, size_t num); 55.38 + 55.39 +void barf(const char *fmt, ...) __attribute__((noreturn)); 55.40 +void barf_perror(const char *fmt, ...) __attribute__((noreturn)); 55.41 + 55.42 +/* This version adds one byte (for nul term) */ 55.43 +void *grab_file(const char *filename, unsigned long *size); 55.44 +void release_file(void *data, unsigned long size); 55.45 + 55.46 +/* For writing daemons, based on Stevens. */ 55.47 +void daemonize(void); 55.48 + 55.49 +/* Signal handling: returns fd to listen on. */ 55.50 +int signal_to_fd(int signal); 55.51 +void close_signal(int fd); 55.52 + 55.53 +void xprintf(const char *fmt, ...); 55.54 + 55.55 +#define eprintf(_fmt, _args...) xprintf("[ERR] %s" _fmt, __FUNCTION__, ##_args) 55.56 +#define iprintf(_fmt, _args...) xprintf("[INF] %s" _fmt, __FUNCTION__, ##_args) 55.57 + 55.58 +#ifdef DEBUG 55.59 +#define dprintf(_fmt, _args...) xprintf("[DBG] %s" _fmt, __FUNCTION__, ##_args) 55.60 +#else 55.61 +#define dprintf(_fmt, _args...) ((void)0) 55.62 +#endif 55.63 + 55.64 +#endif /* _UTILS_H */
56.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 56.2 +++ b/tools/xenstore/xenstored.h Thu Jun 09 14:40:39 2005 +0000 56.3 @@ -0,0 +1,81 @@ 56.4 +/* 56.5 + Simple prototyle Xen Store Daemon providing simple tree-like database. 56.6 + Copyright (C) 2005 Rusty Russell IBM Corporation 56.7 + 56.8 + This program is free software; you can redistribute it and/or modify 56.9 + it under the terms of the GNU General Public License as published by 56.10 + the Free Software Foundation; either version 2 of the License, or 56.11 + (at your option) any later version. 56.12 + 56.13 + This program is distributed in the hope that it will be useful, 56.14 + but WITHOUT ANY WARRANTY; without even the implied warranty of 56.15 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 56.16 + GNU General Public License for more details. 56.17 + 56.18 + You should have received a copy of the GNU General Public License 56.19 + along with this program; if not, write to the Free Software 56.20 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 56.21 +*/ 56.22 +#ifndef _XENSTORED_H 56.23 +#define _XENSTORED_H 56.24 + 56.25 +enum xsd_sockmsg_type 56.26 +{ 56.27 + XS_DEBUG, 56.28 + XS_SHUTDOWN, 56.29 + XS_DIRECTORY, 56.30 + XS_READ, 56.31 + XS_GET_PERMS, 56.32 + XS_WATCH, 56.33 + XS_WATCH_ACK, 56.34 + XS_UNWATCH, 56.35 + XS_TRANSACTION_START, 56.36 + XS_TRANSACTION_END, 56.37 + XS_OP_READ_ONLY = XS_TRANSACTION_END, 56.38 + XS_INTRODUCE, 56.39 + XS_RELEASE, 56.40 + XS_GETDOMAINPATH, 56.41 + XS_WRITE, 56.42 + XS_MKDIR, 56.43 + XS_RM, 56.44 + XS_SET_PERMS, 56.45 + XS_WATCH_EVENT, 56.46 + XS_ERROR, 56.47 +}; 56.48 + 56.49 +#define XS_WRITE_NONE "NONE" 56.50 +#define XS_WRITE_CREATE "CREATE" 56.51 +#define XS_WRITE_CREATE_EXCL "CREATE|EXCL" 56.52 + 56.53 +/* We hand errors as strings, for portability. */ 56.54 +struct xsd_errors 56.55 +{ 56.56 + int errnum; 56.57 + const char *errstring; 56.58 +}; 56.59 +#define XSD_ERROR(x) { x, #x } 56.60 +static struct xsd_errors xsd_errors[] __attribute__((unused)) = { 56.61 + XSD_ERROR(EINVAL), 56.62 + XSD_ERROR(EACCES), 56.63 + XSD_ERROR(EEXIST), 56.64 + XSD_ERROR(EISDIR), 56.65 + XSD_ERROR(ENOENT), 56.66 + XSD_ERROR(ENOMEM), 56.67 + XSD_ERROR(ENOSPC), 56.68 + XSD_ERROR(EIO), 56.69 + XSD_ERROR(ENOTEMPTY), 56.70 + XSD_ERROR(ENOSYS), 56.71 + XSD_ERROR(EROFS), 56.72 + XSD_ERROR(EBUSY), 56.73 + XSD_ERROR(ETIMEDOUT), 56.74 + XSD_ERROR(EISCONN), 56.75 +}; 56.76 +struct xsd_sockmsg 56.77 +{ 56.78 + u32 type; 56.79 + u32 len; /* Length of data following this. */ 56.80 + 56.81 + /* Generally followed by nul-terminated string(s). */ 56.82 +}; 56.83 + 56.84 +#endif /* _XENSTORED_H */
57.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 57.2 +++ b/tools/xenstore/xenstored_core.c Thu Jun 09 14:40:39 2005 +0000 57.3 @@ -0,0 +1,1354 @@ 57.4 +/* 57.5 + Simple prototype Xen Store Daemon providing simple tree-like database. 57.6 + Copyright (C) 2005 Rusty Russell IBM Corporation 57.7 + 57.8 + This program is free software; you can redistribute it and/or modify 57.9 + it under the terms of the GNU General Public License as published by 57.10 + the Free Software Foundation; either version 2 of the License, or 57.11 + (at your option) any later version. 57.12 + 57.13 + This program is distributed in the hope that it will be useful, 57.14 + but WITHOUT ANY WARRANTY; without even the implied warranty of 57.15 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 57.16 + GNU General Public License for more details. 57.17 + 57.18 + You should have received a copy of the GNU General Public License 57.19 + along with this program; if not, write to the Free Software 57.20 + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 57.21 +*/ 57.22 + 57.23 +#include <sys/types.h> 57.24 +#include <sys/stat.h> 57.25 +#include <sys/socket.h> 57.26 +#include <sys/select.h> 57.27 +#include <sys/un.h> 57.28 +#include <sys/time.h> 57.29 +#include <time.h> 57.30 +#include <unistd.h> 57.31 +#include <fcntl.h> 57.32 +#include <stdbool.h> 57.33 +#include <stdio.h> 57.34 +#include <stdarg.h> 57.35 +#include <stdlib.h> 57.36 +#include <syslog.h> 57.37 +#include <string.h> 57.38 +#include <errno.h> 57.39 +#include <dirent.h> 57.40 +#include <getopt.h> 57.41 +#include <signal.h> 57.42 +#include <assert.h> 57.43 +#include <setjmp.h> 57.44 + 57.45 +//#define DEBUG 57.46 +#include "utils.h" 57.47 +#include "list.h" 57.48 +#include "talloc.h" 57.49 +#include "xs_lib.h" 57.50 +#include "xenstored.h" 57.51 +#include "xenstored_core.h" 57.52 +#include "xenstored_watch.h" 57.53 +#include "xenstored_transaction.h" 57.54 +#include "xenstored_domain.h" 57.55 + 57.56 +static bool verbose; 57.57 +static LIST_HEAD(connections); 57.58 + 57.59 +#ifdef TESTING 57.60 +static bool failtest = false; 57.61 + 57.62 +/* We override talloc's malloc. */ 57.63 +void *test_malloc(size_t size) 57.64 +{ 57.65 + /* 1 in 20 means only about 50% of connections establish. */ 57.66 + if (failtest && (random() % 32) == 0) 57.67 + return NULL; 57.68 + return malloc(size); 57.69 +} 57.70 + 57.71 +static void stop_failtest(int signum __attribute__((unused))) 57.72 +{ 57.73 + failtest = false; 57.74 +} 57.75 + 57.76 +/* Need these before we #define away write_all/mkdir in testing.h */ 57.77 +bool test_write_all(int fd, void *contents, unsigned int len); 57.78 +bool test_write_all(int fd, void *contents, unsigned int len) 57.79 +{ 57.80 + if (failtest && (random() % 8) == 0) { 57.81 + if (len) 57.82 + len = random() % len; 57.83 + write(fd, contents, len); 57.84 + errno = ENOSPC; 57.85 + return false; 57.86 + } 57.87 + return write_all(fd, contents, len); 57.88 +} 57.89 + 57.90 +int test_mkdir(const char *dir, int perms); 57.91 +int test_mkdir(const char *dir, int perms) 57.92 +{ 57.93 + if (failtest && (random() % 8) == 0) { 57.94 + errno = ENOSPC; 57.95 + return -1; 57.96 + } 57.97 + return mkdir(dir, perms); 57.98 +} 57.99 +#endif /* TESTING */ 57.100 + 57.101 +#include "xenstored_test.h" 57.102 + 57.103 +/* FIXME: Ideally, this should never be called. Some can be eliminated. */ 57.104 +/* Something is horribly wrong: shutdown immediately. */ 57.105 +void __attribute__((noreturn)) corrupt(struct connection *conn, 57.106 + const char *fmt, ...) 57.107 +{ 57.108 + va_list arglist; 57.109 + char *str; 57.110 + int saved_errno = errno; 57.111 + 57.112 + va_start(arglist, fmt); 57.113 + str = talloc_vasprintf(NULL, fmt, arglist); 57.114 + va_end(arglist); 57.115 + 57.116 + eprintf("xenstored corruption: connection id %i: err %s: %s", 57.117 + conn ? (int)conn->id : -1, strerror(saved_errno), str); 57.118 +#ifdef TESTING 57.119 + /* Allow them to attach debugger. */ 57.120 + sleep(30); 57.121 +#endif 57.122 + syslog(LOG_DAEMON, 57.123 + "xenstored corruption: connection id %i: err %s: %s", 57.124 + conn ? (int)conn->id : -1, strerror(saved_errno), str); 57.125 + _exit(2); 57.126 +} 57.127 + 57.128 +static bool write_message(struct connection *conn) 57.129 +{ 57.130 + int ret; 57.131 + struct buffered_data *out = conn->out; 57.132 + 57.133 + if (out->inhdr) { 57.134 + if (verbose) 57.135 + xprintf("Writing msg %i out to %p\n", 57.136 + out->hdr.msg.type, conn); 57.137 + ret = conn->write(conn, out->hdr.raw + out->used, 57.138 + sizeof(out->hdr) - out->used); 57.139 + if (ret < 0) 57.140 + return false; 57.141 + 57.142 + out->used += ret; 57.143 + if (out->used < sizeof(out->hdr)) 57.144 + return true; 57.145 + 57.146 + out->inhdr = false; 57.147 + out->used = 0; 57.148 + 57.149 + /* Second write might block if non-zero. */ 57.150 + if (out->hdr.msg.len) 57.151 + return true; 57.152 + } 57.153 + 57.154 + if (verbose) 57.155 + xprintf("Writing data len %i out to %p\n", 57.156 + out->hdr.msg.len, conn); 57.157 + ret = conn->write(conn, out->buffer + out->used, 57.158 + out->hdr.msg.len - out->used); 57.159 + 57.160 + if (ret < 0) 57.161 + return false; 57.162 + 57.163 + out->used += ret; 57.164 + if (out->used != out->hdr.msg.len) 57.165 + return true; 57.166 + 57.167 + conn->out = NULL; 57.168 + 57.169 + /* If this was an event, we wait for ack, otherwise we're done. */ 57.170 + if (!is_watch_event(conn, out)) 57.171 + talloc_free(out); 57.172 + 57.173 + queue_next_event(conn); 57.174 + return true; 57.175 +} 57.176 + 57.177 +static int destroy_conn(void *_conn) 57.178 +{ 57.179 + struct connection *conn = _conn; 57.180 + 57.181 + /* Flush outgoing if possible, but don't block. */ 57.182 + if (!conn->domain) { 57.183 + fd_set set; 57.184 + struct timeval none; 57.185 + 57.186 + FD_ZERO(&set); 57.187 + FD_SET(conn->fd, &set); 57.188 + none.tv_sec = none.tv_usec = 0; 57.189 + 57.190 + while (conn->out 57.191 + && select(conn->fd+1, NULL, &set, NULL, &none) == 1) 57.192 + if (!write_message(conn)) 57.193 + break; 57.194 + close(conn->fd); 57.195 + } 57.196 + list_del(&conn->list); 57.197 + return 0; 57.198 +} 57.199 + 57.200 +static int initialize_set(fd_set *inset, fd_set *outset, int sock, int ro_sock, 57.201 + int event_fd) 57.202 +{ 57.203 + struct connection *i; 57.204 + int max; 57.205 + 57.206 + FD_ZERO(inset); 57.207 + FD_ZERO(outset); 57.208 + FD_SET(sock, inset); 57.209 + max = sock; 57.210 + FD_SET(ro_sock, inset); 57.211 + if (ro_sock > max) 57.212 + max = ro_sock; 57.213 + FD_SET(event_fd, inset); 57.214 + if (event_fd > max) 57.215 + max = event_fd; 57.216 + list_for_each_entry(i, &connections, list) { 57.217 + if (i->domain) 57.218 + continue; 57.219 + if (!i->blocked) 57.220 + FD_SET(i->fd, inset); 57.221 + if (i->out) 57.222 + FD_SET(i->fd, outset); 57.223 + if (i->fd > max) 57.224 + max = i->fd; 57.225 + } 57.226 + return max; 57.227 +} 57.228 + 57.229 +/* Read everything from a talloc_open'ed fd. */ 57.230 +static void *read_all(int *fd, unsigned int *size) 57.231 +{ 57.232 + unsigned int max = 4; 57.233 + int ret; 57.234 + void *buffer = talloc_size(fd, max); 57.235 + 57.236 + *size = 0; 57.237 + while ((ret = read(*fd, buffer + *size, max - *size)) > 0) { 57.238 + *size += ret; 57.239 + if (*size == max) 57.240 + buffer = talloc_realloc_size(fd, buffer, max *= 2); 57.241 + } 57.242 + if (ret < 0) 57.243 + return NULL; 57.244 + return buffer; 57.245 +} 57.246 + 57.247 +static int destroy_fd(void *_fd) 57.248 +{ 57.249 + int *fd = _fd; 57.250 + close(*fd); 57.251 + return 0; 57.252 +} 57.253 + 57.254 +/* Return a pointer to an fd, self-closing and attached to this pathname. */ 57.255 +static int *talloc_open(const char *pathname, int flags, int mode) 57.256 +{ 57.257 + int *fd; 57.258 + 57.259 + fd = talloc(pathname, int); 57.260 + *fd = open(pathname, flags, mode); 57.261 + if (*fd < 0) { 57.262 + int saved_errno = errno; 57.263 + talloc_free(fd); 57.264 + errno = saved_errno; 57.265 + return NULL; 57.266 + } 57.267 + talloc_set_destructor(fd, destroy_fd); 57.268 + return fd; 57.269 +} 57.270 + 57.271 +/* Is child a subnode of parent, or equal? */ 57.272 +bool is_child(const char *child, const char *parent) 57.273 +{ 57.274 + unsigned int len = strlen(parent); 57.275 + 57.276 + /* / should really be "" for this algorithm to work, but that's a 57.277 + * usability nightmare. */ 57.278 + if (streq(parent, "/")) 57.279 + return true; 57.280 + 57.281 + if (strncmp(child, parent, len) != 0) 57.282 + return false; 57.283 + 57.284 + return child[len] == '/' || child[len] == '\0'; 57.285 +} 57.286 + 57.287 +/* Answer never ends in /. */ 57.288 +char *node_dir_outside_transaction(const char *node) 57.289 +{ 57.290 + if (streq(node, "/")) 57.291 + return talloc_strdup(node, xs_daemon_store()); 57.292 + return talloc_asprintf(node, "%s%s", xs_daemon_store(), node); 57.293 +} 57.294 + 57.295 +static char *node_dir(struct transaction *trans, const char *node) 57.296 +{ 57.297 + if (!trans || !within_transaction(trans, node)) 57.298 + return node_dir_outside_transaction(node); 57.299 + return node_dir_inside_transaction(trans, node); 57.300 +} 57.301 + 57.302 +static char *node_datafile(struct transaction *trans, const char *node) 57.303 +{ 57.304 + return talloc_asprintf(node, "%s/.data", node_dir(trans, node)); 57.305 +} 57.306 + 57.307 +static char *node_permfile(struct transaction *trans, const char *node) 57.308 +{ 57.309 + return talloc_asprintf(node, "%s/.perms", node_dir(trans, node)); 57.310 +} 57.311 + 57.312 +struct buffered_data *new_buffer(void *ctx) 57.313 +{ 57.314 + struct buffered_data *data; 57.315 + 57.316 + data = talloc(ctx, struct buffered_data); 57.317 + data->inhdr = true; 57.318 + data->used = 0; 57.319 + data->buffer = NULL; 57.320 + 57.321 + return data; 57.322 +} 57.323 + 57.324 +/* Return length of string (including nul) at this offset. */ 57.325 +unsigned int get_string(const struct buffered_data *data, unsigned int offset) 57.326 +{ 57.327 + const char *nul; 57.328 + 57.329 + if (offset >= data->used) 57.330 + return 0; 57.331 + 57.332 + nul = memchr(data->buffer + offset, 0, data->used - offset); 57.333 + if (!nul) 57.334 + return 0; 57.335 + 57.336 + return nul - (data->buffer + offset) + 1; 57.337 +} 57.338 + 57.339 +/* Break input into vectors, return the number, fill in up to num of them. */ 57.340 +unsigned int get_strings(struct buffered_data *data, 57.341 + char *vec[], unsigned int num) 57.342 +{ 57.343 + unsigned int off, i, len; 57.344 + 57.345 + off = i = 0; 57.346 + while ((len = get_string(data, off)) != 0) { 57.347 + if (i < num) 57.348 + vec[i] = data->buffer + off; 57.349 + i++; 57.350 + off += len; 57.351 + } 57.352 + return i; 57.353 +} 57.354 + 57.355 +/* Returns "false", meaning "connection is not blocked". */ 57.356 +bool send_reply(struct connection *conn, enum xsd_sockmsg_type type, 57.357 + const void *data, unsigned int len) 57.358 +{ 57.359 + struct buffered_data *bdata; 57.360 + 57.361 + /* When data gets freed, we want list entry is destroyed (so 57.362 + * list entry is a child). */ 57.363 + bdata = new_buffer(conn); 57.364 + bdata->buffer = talloc_array(bdata, char, len); 57.365 + 57.366 + bdata->hdr.msg.type = type; 57.367 + bdata->hdr.msg.len = len; 57.368 + memcpy(bdata->buffer, data, len); 57.369 + 57.370 + /* There might be an event going out now. Queue behind it. */ 57.371 + if (conn->out) { 57.372 + assert(conn->out->hdr.msg.type == XS_WATCH_EVENT); 57.373 + assert(!conn->waiting_reply); 57.374 + conn->waiting_reply = bdata; 57.375 + } else 57.376 + conn->out = bdata; 57.377 + return false; 57.378 +} 57.379 + 57.380 +/* Some routines (write, mkdir, etc) just need a non-error return */ 57.381 +bool send_ack(struct connection *conn, enum xsd_sockmsg_type type) 57.382 +{ 57.383 + return send_reply(conn, type, "OK", sizeof("OK")); 57.384 +} 57.385 + 57.386 +bool send_error(struct connection *conn, int error) 57.387 +{ 57.388 + unsigned int i; 57.389 + 57.390 + for (i = 0; error != xsd_errors[i].errnum; i++) 57.391 + if (i == ARRAY_SIZE(xsd_errors) - 1) 57.392 + corrupt(conn, "Unknown error %i (%s)", error, 57.393 + strerror(error)); 57.394 + 57.395 + return send_reply(conn, XS_ERROR, xsd_errors[i].errstring, 57.396 + strlen(xsd_errors[i].errstring) + 1); 57.397 +} 57.398 + 57.399 +static bool valid_chars(const char *node) 57.400 +{ 57.401 + /* Nodes can have lots of crap. */ 57.402 + return (strspn(node, 57.403 + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 57.404 + "abcdefghijklmnopqrstuvwxyz" 57.405 + "0123456789-/_@") == strlen(node)); 57.406 +} 57.407 + 57.408 +static bool is_valid_nodename(const char *node) 57.409 +{ 57.410 + /* Must start in /. */ 57.411 + if (!strstarts(node, "/")) 57.412 + return false; 57.413 + 57.414 + /* Cannot end in / (unless it's just "/"). */ 57.415 + if (strends(node, "/") && !streq(node, "/")) 57.416 + return false; 57.417 + 57.418 + /* No double //. */ 57.419 + if (strstr(node, "//")) 57.420 + return false; 57.421 + 57.422 + return valid_chars(node); 57.423 +} 57.424 + 57.425 +/* We expect one arg in the input: return NULL otherwise. */ 57.426 +static const char *onearg(struct buffered_data *in) 57.427 +{ 57.428 + if (get_string(in, 0) != in->used) 57.429 + return NULL; 57.430 + return in->buffer; 57.431 +} 57.432 + 57.433 +/* If it fails, returns NULL and sets errno. */ 57.434 +static struct xs_permissions *get_perms(struct transaction *transaction, 57.435 + const char *node, unsigned int *num) 57.436 +{ 57.437 + unsigned int size; 57.438 + char *strings; 57.439 + struct xs_permissions *ret; 57.440 + int *fd; 57.441 + 57.442 + fd = talloc_open(node_permfile(transaction, node), O_RDONLY, 0); 57.443 + if (!fd) 57.444 + return NULL; 57.445 + strings = read_all(fd, &size); 57.446 + if (!strings) 57.447 + return NULL; 57.448 + 57.449 + *num = count_strings(strings, size); 57.450 + ret = talloc_array(node, struct xs_permissions, *num); 57.451 + if (!strings_to_perms(ret, *num, strings)) 57.452 + corrupt(NULL, "Permissions corrupt for %s", node); 57.453 + 57.454 + return ret; 57.455 +} 57.456 + 57.457 +static char *perms_to_strings(const char *node, 57.458 + struct xs_permissions *perms, unsigned int num, 57.459 + unsigned int *len) 57.460 +{ 57.461 + unsigned int i; 57.462 + char *strings = NULL; 57.463 + char buffer[MAX_STRLEN(domid_t) + 1]; 57.464 + 57.465 + for (*len = 0, i = 0; i < num; i++) { 57.466 + if (!perm_to_string(&perms[i], buffer)) 57.467 + return NULL; 57.468 + 57.469 + strings = talloc_realloc(node, strings, char, 57.470 + *len + strlen(buffer) + 1); 57.471 + strcpy(strings + *len, buffer); 57.472 + *len += strlen(buffer) + 1; 57.473 + } 57.474 + return strings; 57.475 +} 57.476 + 57.477 +/* Destroy this, and its children, and its children's children. */ 57.478 +int destroy_path(void *path) 57.479 +{ 57.480 + DIR *dir; 57.481 + struct dirent *dirent; 57.482 + 57.483 + dir = opendir(path); 57.484 + if (!dir) { 57.485 + if (unlink(path) == 0 || errno == ENOENT) 57.486 + return 0; 57.487 + corrupt(NULL, "Destroying path %s", path); 57.488 + } 57.489 + 57.490 + while ((dirent = readdir(dir)) != NULL) { 57.491 + char fullpath[strlen(path) + 1 + strlen(dirent->d_name) + 1]; 57.492 + sprintf(fullpath, "%s/%s", (char *)path, dirent->d_name); 57.493 + if (!streq(dirent->d_name,".") && !streq(dirent->d_name,"..")) 57.494 + destroy_path(fullpath); 57.495 + } 57.496 + closedir(dir); 57.497 + if (rmdir(path) != 0) 57.498 + corrupt(NULL, "Destroying directory %s", path); 57.499 + return 0; 57.500 +} 57.501 + 57.502 +/* Create a self-destructing temporary file */ 57.503 +static char *tempfile(const char *path, void *contents, unsigned int len) 57.504 +{ 57.505 + int *fd; 57.506 + char *tmppath = talloc_asprintf(path, "%s.tmp", path); 57.507 + 57.508 + fd = talloc_open(tmppath, O_WRONLY|O_CREAT|O_EXCL, 0640); 57.509 + if (!fd) 57.510 + return NULL; 57.511 + talloc_set_destructor(tmppath, destroy_path); 57.512 + if (!write_all(*fd, contents, len)) 57.513 + return NULL; 57.514 + 57.515 + return tmppath; 57.516 +} 57.517 + 57.518 +/* We assume rename() doesn't fail on moves in same dir. */ 57.519 +static void commit_tempfile(const char *path) 57.520 +{ 57.521 + char realname[strlen(path) + 1]; 57.522 + unsigned int len = strrchr(path, '.') - path; 57.523 + 57.524 + memcpy(realname, path, len); 57.525 + realname[len] = '\0'; 57.526 + if (rename(path, realname) != 0) 57.527 + corrupt(NULL, "Committing %s", realname); 57.528 + talloc_set_destructor(path, NULL); 57.529 +} 57.530 + 57.531 +static bool set_perms(struct transaction *transaction, 57.532 + const char *node, 57.533 + struct xs_permissions *perms, unsigned int num) 57.534 +{ 57.535 + unsigned int len; 57.536 + char *permpath, *strings; 57.537 + 57.538 + strings = perms_to_strings(node, perms, num, &len); 57.539 + if (!strings) 57.540 + return false; 57.541 + 57.542 + /* Create then move. */ 57.543 + permpath = tempfile(node_permfile(transaction, node), strings, len); 57.544 + if (!permpath) 57.545 + return false; 57.546 + 57.547 + commit_tempfile(permpath); 57.548 + return true; 57.549 +} 57.550 + 57.551 +static char *get_parent(const char *node) 57.552 +{ 57.553 + char *slash = strrchr(node + 1, '/'); 57.554 + if (!slash) 57.555 + return talloc_strdup(node, "/"); 57.556 + return talloc_asprintf(node, "%.*s", slash - node, node); 57.557 +} 57.558 + 57.559 +static enum xs_perm_type perm_for_id(domid_t id, 57.560 + struct xs_permissions *perms, 57.561 + unsigned int num) 57.562 +{ 57.563 + unsigned int i; 57.564 + 57.565 + /* Owners and tools get it all... */ 57.566 + if (!id || perms[0].id == id) 57.567 + return XS_PERM_READ|XS_PERM_WRITE|XS_PERM_CREATE|XS_PERM_OWNER; 57.568 + 57.569 + for (i = 1; i < num; i++) 57.570 + if (perms[i].id == id) 57.571 + return perms[i].perms; 57.572 + 57.573 + return perms[0].perms; 57.574 +} 57.575 + 57.576 +/* We have a weird permissions system. You can allow someone into a 57.577 + * specific node without allowing it in the parents. If it's going to 57.578 + * fail, however, we don't want the errno to indicate any information 57.579 + * about the node. */ 57.580 +static int check_with_parents(struct connection *conn, const char *node, 57.581 + int errnum) 57.582 +{ 57.583 + struct xs_permissions *perms; 57.584 + unsigned int num; 57.585 + 57.586 + /* We always tell them about memory failures. */ 57.587 + if (errnum == ENOMEM) 57.588 + return errnum; 57.589 + 57.590 + do { 57.591 + node = get_parent(node); 57.592 + perms = get_perms(conn->transaction, node, &num); 57.593 + if (perms) 57.594 + break; 57.595 + } while (!streq(node, "/")); 57.596 + 57.597 + /* No permission at root? We're in trouble. */ 57.598 + if (!perms) 57.599 + corrupt(conn, "No permissions file at root"); 57.600 + 57.601 + if (!(perm_for_id(conn->id, perms, num) & XS_PERM_READ)) 57.602 + return EACCES; 57.603 + 57.604 + return errnum; 57.605 +} 57.606 + 57.607 +bool check_node_perms(struct connection *conn, const char *node, 57.608 + enum xs_perm_type perm) 57.609 +{ 57.610 + struct xs_permissions *perms; 57.611 + unsigned int num; 57.612 + 57.613 + if (!node) { 57.614 + errno = EINVAL; 57.615 + return false; 57.616 + } 57.617 + 57.618 + if (!node || !is_valid_nodename(node)) { 57.619 + errno = EINVAL; 57.620 + return false; 57.621 + } 57.622 + 57.623 + if (!conn->write && (perm & XS_PERM_WRITE)) { 57.624 + errno = EROFS; 57.625 + return false; 57.626 + } 57.627 + 57.628 + perms = get_perms(conn->transaction, node, &num); 57.629 + /* No permissions. If we want to create it and 57.630 + * it doesn't exist, check parent directory. */ 57.631 + if (!perms && errno == ENOENT && (perm & XS_PERM_CREATE)) { 57.632 + char *parent = get_parent(node); 57.633 + if (!parent) 57.634 + return false; 57.635 + 57.636 + perms = get_perms(conn->transaction, parent, &num); 57.637 + } 57.638 + if (!perms) { 57.639 + errno = check_with_parents(conn, node, errno); 57.640 + return false; 57.641 + } 57.642 + 57.643 + if (perm_for_id(conn->id, perms, num) & perm) 57.644 + return true; 57.645 + 57.646 + errno = check_with_parents(conn, node, EACCES); 57.647 + return false; 57.648 +} 57.649 + 57.650 +static bool send_directory(struct connection *conn, const char *node) 57.651 +{ 57.652 + char *path, *reply = talloc_strdup(node, ""); 57.653 + unsigned int reply_len = 0; 57.654 + DIR *dir; 57.655 + struct dirent *dirent; 57.656 + 57.657 + if (!check_node_perms(conn, node, XS_PERM_READ)) 57.658 + return send_error(conn, errno); 57.659 + 57.660 + path = node_dir(conn->transaction, node); 57.661 + dir = opendir(path); 57.662 + if (!dir) 57.663 + return send_error(conn, errno); 57.664 + 57.665 + while ((dirent = readdir(dir)) != NULL) { 57.666 + int len = strlen(dirent->d_name) + 1; 57.667 + 57.668 + if (!valid_chars(dirent->d_name)) 57.669 + continue; 57.670 + 57.671 + reply = talloc_realloc(path, reply, char, reply_len + len); 57.672 + strcpy(reply + reply_len, dirent->d_name); 57.673 + reply_len += len; 57.674 + } 57.675 + closedir(dir); 57.676 + 57.677 + return send_reply(conn, XS_DIRECTORY, reply, reply_len); 57.678 +} 57.679 + 57.680 +static bool do_read(struct connection *conn, const char *node) 57.681 +{ 57.682 + char *value; 57.683 + unsigned int size; 57.684 + int *fd; 57.685 + 57.686 + if (!check_node_perms(conn, node, XS_PERM_READ)) 57.687 + return send_error(conn, errno); 57.688 + 57.689 + fd = talloc_open(node_datafile(conn->transaction, node), O_RDONLY, 0); 57.690 + if (!fd) { 57.691 + /* Data file doesn't exist? We call that a directory */ 57.692 + if (errno == ENOENT) 57.693 + errno = EISDIR; 57.694 + return send_error(conn, errno); 57.695 + } 57.696 + 57.697 + value = read_all(fd, &size); 57.698 + if (!value) 57.699 + return send_error(conn, errno); 57.700 + 57.701 + return send_reply(conn, XS_READ, value, size); 57.702 +} 57.703 + 57.704 +/* Create a new directory. Optionally put data in it (if data != NULL) */ 57.705 +static bool new_directory(struct connection *conn, 57.706 + const char *node, void *data, unsigned int datalen) 57.707 +{ 57.708 + struct xs_permissions perms; 57.709 + char *permstr; 57.710 + unsigned int len; 57.711 + int *fd; 57.712 + char *dir = node_dir(conn->transaction, node); 57.713 + 57.714 + if (mkdir(dir, 0750) != 0) 57.715 + return false; 57.716 + 57.717 + /* Set destructor so we clean up if neccesary. */ 57.718 + talloc_set_destructor(dir, destroy_path); 57.719 + 57.720 + /* Default permisisons: we own it, noone else has permission. */ 57.721 + perms.id = conn->id; 57.722 + perms.perms = XS_PERM_NONE; 57.723 + 57.724 + permstr = perms_to_strings(dir, &perms, 1, &len); 57.725 + fd = talloc_open(node_permfile(conn->transaction, node), 57.726 + O_WRONLY|O_CREAT|O_EXCL, 0640); 57.727 + if (!fd || !write_all(*fd, permstr, len)) 57.728 + return false; 57.729 + 57.730 + if (data) { 57.731 + char *datapath = node_datafile(conn->transaction, node); 57.732 + 57.733 + fd = talloc_open(datapath, O_WRONLY|O_CREAT|O_EXCL, 0640); 57.734 + if (!fd || !write_all(*fd, data, datalen)) 57.735 + return false; 57.736 + } 57.737 + 57.738 + /* Finished! */ 57.739 + talloc_set_destructor(dir, NULL); 57.740 + return true; 57.741 +} 57.742 + 57.743 +/* path, flags, data... */ 57.744 +static bool do_write(struct connection *conn, struct buffered_data *in) 57.745 +{ 57.746 + unsigned int offset, datalen; 57.747 + char *vec[2]; 57.748 + char *node, *tmppath; 57.749 + enum xs_perm_type mode; 57.750 + struct stat st; 57.751 + 57.752 + /* Extra "strings" can be created by binary data. */ 57.753 + if (get_strings(in, vec, ARRAY_SIZE(vec)) < ARRAY_SIZE(vec)) 57.754 + return send_error(conn, EINVAL); 57.755 + 57.756 + node = vec[0]; 57.757 + if (!within_transaction(conn->transaction, node)) 57.758 + return send_error(conn, EROFS); 57.759 + 57.760 + if (transaction_block(conn, node)) 57.761 + return true; 57.762 + 57.763 + offset = strlen(vec[0]) + strlen(vec[1]) + 2; 57.764 + datalen = in->used - offset; 57.765 + 57.766 + if (streq(vec[1], XS_WRITE_NONE)) 57.767 + mode = XS_PERM_WRITE; 57.768 + else if (streq(vec[1], XS_WRITE_CREATE)) 57.769 + mode = XS_PERM_WRITE|XS_PERM_CREATE; 57.770 + else if (streq(vec[1], XS_WRITE_CREATE_EXCL)) 57.771 + mode = XS_PERM_WRITE|XS_PERM_CREATE; 57.772 + else 57.773 + return send_error(conn, EINVAL); 57.774 + 57.775 + if (!check_node_perms(conn, node, mode)) 57.776 + return send_error(conn, errno); 57.777 + 57.778 + if (lstat(node_dir(conn->transaction, node), &st) != 0) { 57.779 + /* Does not exist... */ 57.780 + if (errno != ENOENT) 57.781 + return send_error(conn, errno); 57.782 + 57.783 + /* Not going to create it? */ 57.784 + if (!(mode & XS_PERM_CREATE)) 57.785 + return send_error(conn, ENOENT); 57.786 + 57.787 + if (!new_directory(conn, node, in->buffer + offset, datalen)) 57.788 + return send_error(conn, errno); 57.789 + } else { 57.790 + /* Exists... */ 57.791 + if (streq(vec[1], XS_WRITE_CREATE_EXCL)) 57.792 + return send_error(conn, EEXIST); 57.793 + 57.794 + tmppath = tempfile(node_datafile(conn->transaction, node), 57.795 + in->buffer + offset, datalen); 57.796 + if (!tmppath) 57.797 + return send_error(conn, errno); 57.798 + 57.799 + commit_tempfile(tmppath); 57.800 + } 57.801 + 57.802 + add_change_node(conn->transaction, node); 57.803 + send_ack(conn, XS_WRITE); 57.804 + fire_watches(conn->transaction, node); 57.805 + return false; 57.806 +} 57.807 + 57.808 +static bool do_mkdir(struct connection *conn, const char *node) 57.809 +{ 57.810 + if (!check_node_perms(conn, node, XS_PERM_WRITE|XS_PERM_CREATE)) 57.811 + return send_error(conn, errno); 57.812 + 57.813 + if (!within_transaction(conn->transaction, node)) 57.814 + return send_error(conn, EROFS); 57.815 + 57.816 + if (transaction_block(conn, node)) 57.817 + return true; 57.818 + 57.819 + if (!new_directory(conn, node, NULL, 0)) 57.820 + return send_error(conn, errno); 57.821 + 57.822 + add_change_node(conn->transaction, node); 57.823 + send_ack(conn, XS_MKDIR); 57.824 + fire_watches(conn->transaction, node); 57.825 + return false; 57.826 +} 57.827 + 57.828 +static bool do_rm(struct connection *conn, const char *node) 57.829 +{ 57.830 + char *tmppath, *path; 57.831 + 57.832 + if (!check_node_perms(conn, node, XS_PERM_WRITE)) 57.833 + return send_error(conn, errno); 57.834 + 57.835 + if (!within_transaction(conn->transaction, node)) 57.836 + return send_error(conn, EROFS); 57.837 + 57.838 + if (transaction_block(conn, node)) 57.839 + return true; 57.840 + 57.841 + if (streq(node, "/")) 57.842 + return send_error(conn, EINVAL); 57.843 + 57.844 + /* We move the directory to temporary name, destructor cleans up. */ 57.845 + path = node_dir(conn->transaction, node); 57.846 + tmppath = talloc_asprintf(node, "%s.tmp", path); 57.847 + talloc_set_destructor(tmppath, destroy_path); 57.848 + 57.849 + if (rename(path, tmppath) != 0) 57.850 + return send_error(conn, errno); 57.851 + 57.852 + add_change_node(conn->transaction, node); 57.853 + send_ack(conn, XS_RM); 57.854 + fire_watches(conn->transaction, node); 57.855 + return false; 57.856 +} 57.857 + 57.858 +static bool do_get_perms(struct connection *conn, const char *node) 57.859 +{ 57.860 + struct xs_permissions *perms; 57.861 + char *strings; 57.862 + unsigned int len, num; 57.863 + 57.864 + if (!check_node_perms(conn, node, XS_PERM_READ)) 57.865 + return send_error(conn, errno); 57.866 + 57.867 + perms = get_perms(conn->transaction, node, &num); 57.868 + if (!perms) 57.869 + return send_error(conn, errno); 57.870 + 57.871 + strings = perms_to_strings(node, perms, num, &len); 57.872 + if (!strings) 57.873 + return send_error(conn, errno); 57.874 + 57.875 + return send_reply(conn, XS_GET_PERMS, strings, len); 57.876 +} 57.877 + 57.878 +static bool do_set_perms(struct connection *conn, struct buffered_data *in) 57.879 +{ 57.880 + unsigned int num; 57.881 + char *node; 57.882 + struct xs_permissions *perms; 57.883 + 57.884 + num = count_strings(in->buffer, in->used); 57.885 + if (num < 2) 57.886 + return send_error(conn, EINVAL); 57.887 + 57.888 + /* First arg is node name. */ 57.889 + node = in->buffer; 57.890 + in->buffer += strlen(in->buffer) + 1; 57.891 + num--; 57.892 + 57.893 + if (!within_transaction(conn->transaction, node)) 57.894 + return send_error(conn, EROFS); 57.895 + 57.896 + if (transaction_block(conn, node)) 57.897 + return true; 57.898 + 57.899 + /* We must own node to do this (tools can do this too). */ 57.900 + if (!check_node_perms(conn, node, XS_PERM_WRITE|XS_PERM_OWNER)) 57.901 + return send_error(conn, errno); 57.902 + 57.903 + perms = talloc_array(node, struct xs_permissions, num); 57.904 + if (!strings_to_perms(perms, num, in->buffer)) 57.905 + return send_error(conn, errno); 57.906 + 57.907 + if (!set_perms(conn->transaction, node, perms, num)) 57.908 + return send_error(conn, errno); 57.909 + add_change_node(conn->transaction, node); 57.910 + send_ack(conn, XS_SET_PERMS); 57.911 + fire_watches(conn->transaction, node); 57.912 + return false; 57.913 +} 57.914 + 57.915 +/* Process "in" for conn: "in" will vanish after this conversation, so 57.916 + * we can talloc off it for temporary variables. May free "conn". 57.917 + * Returns true if can't complete due to block. 57.918 + */ 57.919 +static bool process_message(struct connection *conn, struct buffered_data *in) 57.920 +{ 57.921 + switch (in->hdr.msg.type) { 57.922 + case XS_DIRECTORY: 57.923 + return send_directory(conn, onearg(in)); 57.924 + 57.925 + case XS_READ: 57.926 + return do_read(conn, onearg(in)); 57.927 + 57.928 + case XS_WRITE: 57.929 + return do_write(conn, in); 57.930 + 57.931 + case XS_MKDIR: 57.932 + return do_mkdir(conn, onearg(in)); 57.933 + 57.934 + case XS_RM: 57.935 + return do_rm(conn, onearg(in)); 57.936 + 57.937 + case XS_GET_PERMS: 57.938 + return do_get_perms(conn, onearg(in)); 57.939 + 57.940 + case XS_SET_PERMS: 57.941 + return do_set_perms(conn, in); 57.942 + 57.943 + case XS_SHUTDOWN: 57.944 + send_ack(conn, XS_SHUTDOWN); 57.945 + /* Everything hangs off auto-free context, freed at exit. */ 57.946 + exit(0); 57.947 + 57.948 +#ifdef TESTING 57.949 + case XS_DEBUG: { 57.950 + /* For testing, we allow them to set id. */ 57.951 + if (streq(in->buffer, "setid")) { 57.952 + conn->id = atoi(in->buffer + get_string(in, 0)); 57.953 + send_ack(conn, XS_DEBUG); 57.954 + } else if (streq(in->buffer, "failtest")) { 57.955 + if (get_string(in, 0) < in->used) 57.956 + srandom(atoi(in->buffer + get_string(in, 0))); 57.957 + send_ack(conn, XS_DEBUG); 57.958 + failtest = true; 57.959 + } 57.960 + return false; 57.961 + } 57.962 +#endif /* TESTING */ 57.963 + 57.964 + case XS_WATCH: 57.965 + return do_watch(conn, in); 57.966 + 57.967 + case XS_WATCH_ACK: 57.968 + return do_watch_ack(conn); 57.969 + 57.970 + case XS_UNWATCH: 57.971 + return do_unwatch(conn, onearg(in)); 57.972 + 57.973 + case XS_TRANSACTION_START: 57.974 + return do_transaction_start(conn, onearg(in)); 57.975 + 57.976 + case XS_TRANSACTION_END: 57.977 + return do_transaction_end(conn, onearg(in)); 57.978 + 57.979 + case XS_INTRODUCE: 57.980 + return do_introduce(conn, in); 57.981 + 57.982 + case XS_RELEASE: 57.983 + return do_release(conn, onearg(in)); 57.984 + 57.985 + case XS_GETDOMAINPATH: 57.986 + return do_get_domain_path(conn, onearg(in)); 57.987 + 57.988 + case XS_WATCH_EVENT: 57.989 + default: 57.990 + eprintf("Client unknown operation %i", in->hdr.msg.type); 57.991 + send_error(conn, ENOSYS); 57.992 + return false; 57.993 + } 57.994 +} 57.995 + 57.996 +static int out_of_mem(void *data) 57.997 +{ 57.998 + longjmp(*(jmp_buf *)data, 1); 57.999 +} 57.1000 + 57.1001 +static void consider_message(struct connection *conn) 57.1002 +{ 57.1003 + struct buffered_data *in = NULL; 57.1004 + enum xsd_sockmsg_type type = conn->in->hdr.msg.type; 57.1005 + jmp_buf talloc_fail; 57.1006 + 57.1007 + /* For simplicity, we kill the connection on OOM. */ 57.1008 + talloc_set_fail_handler(out_of_mem, &talloc_fail); 57.1009 + if (setjmp(talloc_fail)) { 57.1010 + talloc_free(conn); 57.1011 + goto end; 57.1012 + } 57.1013 + 57.1014 + if (verbose) 57.1015 + xprintf("Got message %i len %i from %p\n", 57.1016 + type, conn->in->hdr.msg.len, conn); 57.1017 + 57.1018 + /* We might get a command while waiting for an ack: this means 57.1019 + * the other end discarded it: we will re-transmit. */ 57.1020 + if (type != XS_WATCH_ACK) 57.1021 + reset_watch_event(conn); 57.1022 + 57.1023 + /* Careful: process_message may free connection. We detach 57.1024 + * "in" beforehand and allocate the new buffer to avoid 57.1025 + * touching conn after process_message. 57.1026 + */ 57.1027 + in = talloc_steal(talloc_autofree_context(), conn->in); 57.1028 + conn->in = new_buffer(conn); 57.1029 + if (process_message(conn, in)) { 57.1030 + /* Blocked by transaction: queue for re-xmit. */ 57.1031 + talloc_free(conn->in); 57.1032 + conn->in = in; 57.1033 + in = NULL; 57.1034 + } 57.1035 + 57.1036 +end: 57.1037 + talloc_free(in); 57.1038 + talloc_set_fail_handler(NULL, NULL); 57.1039 + if (talloc_total_blocks(NULL) 57.1040 + != talloc_total_blocks(talloc_autofree_context()) + 1) 57.1041 + talloc_report_full(NULL, stderr); 57.1042 +} 57.1043 + 57.1044 +/* Errors in reading or allocating here mean we get out of sync, so we 57.1045 + * drop the whole client connection. */ 57.1046 +void handle_input(struct connection *conn) 57.1047 +{ 57.1048 + int bytes; 57.1049 + struct buffered_data *in; 57.1050 + 57.1051 + assert(!conn->blocked); 57.1052 + in = conn->in; 57.1053 + 57.1054 + /* Not finished header yet? */ 57.1055 + if (in->inhdr) { 57.1056 + bytes = conn->read(conn, in->hdr.raw + in->used, 57.1057 + sizeof(in->hdr) - in->used); 57.1058 + if (bytes <= 0) 57.1059 + goto bad_client; 57.1060 + in->used += bytes; 57.1061 + if (in->used != sizeof(in->hdr)) 57.1062 + return; 57.1063 + 57.1064 + if (in->hdr.msg.len > PATH_MAX) { 57.1065 + syslog(LOG_DAEMON, "Client tried to feed us %i", 57.1066 + in->hdr.msg.len); 57.1067 + goto bad_client; 57.1068 + } 57.1069 + 57.1070 + in->buffer = talloc_array(in, char, in->hdr.msg.len); 57.1071 + if (!in->buffer) 57.1072 + goto bad_client; 57.1073 + in->used = 0; 57.1074 + in->inhdr = false; 57.1075 + return; 57.1076 + } 57.1077 + 57.1078 + bytes = conn->read(conn, in->buffer + in->used, 57.1079 + in->hdr.msg.len - in->used); 57.1080 + if (bytes < 0) 57.1081 + goto bad_client; 57.1082 + 57.1083 + in->used += bytes; 57.1084 + if (in->used != in->hdr.msg.len) 57.1085 + return; 57.1086 + 57.1087 + consider_message(conn); 57.1088 + return; 57.1089 + 57.1090 +bad_client: 57.1091 + /* Kill it. */ 57.1092 + talloc_free(conn); 57.1093 +} 57.1094 + 57.1095 +void handle_output(struct connection *conn) 57.1096 +{ 57.1097 + if (!write_message(conn)) 57.1098 + talloc_free(conn); 57.1099 +} 57.1100 + 57.1101 +/* If a transaction has ended, see if we can unblock any connections. */ 57.1102 +static void unblock_connections(void) 57.1103 +{ 57.1104 + struct connection *i, *tmp; 57.1105 + 57.1106 + list_for_each_entry_safe(i, tmp, &connections, list) { 57.1107 + if (!i->blocked) 57.1108 + continue; 57.1109 + 57.1110 + if (!transaction_covering_node(i->blocked)) { 57.1111 + talloc_free(i->blocked); 57.1112 + i->blocked = NULL; 57.1113 + consider_message(i); 57.1114 + } 57.1115 + } 57.1116 + 57.1117 + /* To balance bias, move first entry to end. */ 57.1118 + if (!list_empty(&connections)) { 57.1119 + i = list_top(&connections, struct connection, list); 57.1120 + list_del(&i->list); 57.1121 + list_add_tail(&i->list, &connections); 57.1122 + } 57.1123 +} 57.1124 + 57.1125 +struct connection *new_connection(connwritefn_t *write, connreadfn_t *read) 57.1126 +{ 57.1127 + struct connection *new; 57.1128 + jmp_buf talloc_fail; 57.1129 + 57.1130 + new = talloc(talloc_autofree_context(), struct connection); 57.1131 + if (!new) 57.1132 + return NULL; 57.1133 + 57.1134 + new->blocked = false; 57.1135 + new->out = new->waiting_reply = NULL; 57.1136 + new->event = NULL; 57.1137 + new->fd = -1; 57.1138 + new->id = 0; 57.1139 + new->domain = NULL; 57.1140 + new->transaction = NULL; 57.1141 + new->write = write; 57.1142 + new->read = read; 57.1143 + 57.1144 + talloc_set_fail_handler(out_of_mem, &talloc_fail); 57.1145 + if (setjmp(talloc_fail)) { 57.1146 + talloc_free(new); 57.1147 + return NULL; 57.1148 + } 57.1149 + new->in = new_buffer(new); 57.1150 + talloc_set_fail_handler(NULL, NULL); 57.1151 + 57.1152 + list_add_tail(&new->list, &connections); 57.1153 + talloc_set_destructor(new, destroy_conn); 57.1154 + return new; 57.1155 +} 57.1156 + 57.1157 +static int writefd(struct connection *conn, const void *data, unsigned int len) 57.1158 +{ 57.1159 + return write(conn->fd, data, len); 57.1160 +} 57.1161 + 57.1162 +static int readfd(struct connection *conn, void *data, unsigned int len) 57.1163 +{ 57.1164 + return read(conn->fd, data, len); 57.1165 +} 57.1166 + 57.1167 +static void accept_connection(int sock, bool canwrite) 57.1168 +{ 57.1169 + int fd; 57.1170 + struct connection *conn; 57.1171 + 57.1172 + fd = accept(sock, NULL, NULL); 57.1173 + if (fd < 0) 57.1174 + return; 57.1175 + 57.1176 + conn = new_connection(canwrite ? writefd : NULL, readfd); 57.1177 + if (conn) 57.1178 + conn->fd = fd; 57.1179 + else 57.1180 + close(fd); 57.1181 +} 57.1182 + 57.1183 +/* Calc timespan from now to absolute time. */ 57.1184 +static void time_relative_to_now(struct timeval *tv) 57.1185 +{ 57.1186 + struct timeval now; 57.1187 + 57.1188 + gettimeofday(&now, NULL); 57.1189 + if (timercmp(&now, tv, >)) 57.1190 + timerclear(tv); 57.1191 + else { 57.1192 + tv->tv_sec -= now.tv_sec; 57.1193 + if (now.tv_usec > tv->tv_usec) { 57.1194 + tv->tv_sec--; 57.1195 + tv->tv_usec += 1000000; 57.1196 + } 57.1197 + tv->tv_usec -= now.tv_usec; 57.1198 + } 57.1199 +} 57.1200 + 57.1201 +static struct option options[] = { { "no-fork", 0, NULL, 'N' }, 57.1202 + { "verbose", 0, NULL, 'V' }, 57.1203 + { "output-pid", 0, NULL, 'P' }, 57.1204 + { NULL, 0, NULL, 0 } }; 57.1205 + 57.1206 +int main(int argc, char *argv[]) 57.1207 +{ 57.1208 + int opt, *sock, *ro_sock, event_fd, max, tmpout; 57.1209 + struct sockaddr_un addr; 57.1210 + fd_set inset, outset; 57.1211 + bool dofork = true; 57.1212 + bool outputpid = false; 57.1213 + 57.1214 + while ((opt = getopt_long(argc, argv, "DV", options, NULL)) != -1) { 57.1215 + switch (opt) { 57.1216 + case 'N': 57.1217 + dofork = false; 57.1218 + break; 57.1219 + case 'V': 57.1220 + verbose = true; 57.1221 + break; 57.1222 + case 'P': 57.1223 + outputpid = true; 57.1224 + break; 57.1225 + } 57.1226 + } 57.1227 + if (optind != argc) 57.1228 + barf("%s: No arguments desired", argv[0]); 57.1229 + 57.1230 + talloc_enable_leak_report_full(); 57.1231 + 57.1232 + /* Create sockets for them to listen to. */ 57.1233 + sock = talloc(talloc_autofree_context(), int); 57.1234 + *sock = socket(PF_UNIX, SOCK_STREAM, 0); 57.1235 + if (*sock < 0) 57.1236 + barf_perror("Could not create socket"); 57.1237 + ro_sock = talloc(talloc_autofree_context(), int); 57.1238 + *ro_sock = socket(PF_UNIX, SOCK_STREAM, 0); 57.1239 + if (*ro_sock < 0) 57.1240 + barf_perror("Could not create socket"); 57.1241 + talloc_set_destructor(sock, destroy_fd); 57.1242 + talloc_set_destructor(ro_sock, destroy_fd); 57.1243 + 57.1244 + /* Don't kill us with SIGPIPE. */ 57.1245 + signal(SIGPIPE, SIG_IGN); 57.1246 + 57.1247 + /* FIXME: Be more sophisticated, don't mug running daemon. */ 57.1248 + unlink(xs_daemon_socket()); 57.1249 + unlink(xs_daemon_socket_ro()); 57.1250 + 57.1251 + addr.sun_family = AF_UNIX; 57.1252 + strcpy(addr.sun_path, xs_daemon_socket()); 57.1253 + if (bind(*sock, (struct sockaddr *)&addr, sizeof(addr)) != 0) 57.1254 + barf_perror("Could not bind socket to %s", xs_daemon_socket()); 57.1255 + strcpy(addr.sun_path, xs_daemon_socket_ro()); 57.1256 + if (bind(*ro_sock, (struct sockaddr *)&addr, sizeof(addr)) != 0) 57.1257 + barf_perror("Could not bind socket to %s", 57.1258 + xs_daemon_socket_ro()); 57.1259 + if (chmod(xs_daemon_socket(), 0600) != 0 57.1260 + || chmod(xs_daemon_socket_ro(), 0660) != 0) 57.1261 + barf_perror("Could not chmod sockets"); 57.1262 + 57.1263 + if (listen(*sock, 1) != 0 57.1264 + || listen(*ro_sock, 1) != 0) 57.1265 + barf_perror("Could not listen on sockets"); 57.1266 + 57.1267 + /* If we're the first, create .perms file for root. */ 57.1268 + if (mkdir(xs_daemon_store(), 0750) == 0) { 57.1269 + struct xs_permissions perms; 57.1270 + char *root = talloc_strdup(talloc_autofree_context(), "/"); 57.1271 + 57.1272 + perms.id = 0; 57.1273 + perms.perms = XS_PERM_READ; 57.1274 + if (!set_perms(NULL, root, &perms, 1)) 57.1275 + barf_perror("Could not create permissions in root"); 57.1276 + talloc_free(root); 57.1277 + mkdir(xs_daemon_transactions(), 0750); 57.1278 + } else if (errno != EEXIST) 57.1279 + barf_perror("Could not create root %s", xs_daemon_store()); 57.1280 + 57.1281 + /* Listen to hypervisor. */ 57.1282 + event_fd = domain_init(); 57.1283 + 57.1284 + /* Debugging: daemonize() closes standard fds, so dup here. */ 57.1285 + tmpout = dup(STDOUT_FILENO);