direct-io.hg

changeset 5396:6d3e8f90c2df

bitkeeper revision 1.1700 (42a854e79oBFuqa_DSY4Lr9IhenUQw)

Merge xenstore changes.
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
author cl349@firebug.cl.cam.ac.uk
date Thu Jun 09 14:40:39 2005 +0000 (2005-06-09)
parents 29cc3bc7efec ccd879d035da
children 849b58da37b7
files .rootkeys BitKeeper/etc/ignore linux-2.6.11-xen-sparse/drivers/xen/netback/control.c tools/Makefile tools/libxc/xc.h tools/libxc/xc_linux_build.c tools/python/setup.py tools/python/xen/lowlevel/xc/xc.c tools/python/xen/lowlevel/xs/xs.c tools/python/xen/lowlevel/xu/xu.c tools/python/xen/util/mac.py tools/python/xen/web/SrvDir.py tools/python/xen/xend/PrettyPrint.py tools/python/xen/xend/XendCheckpoint.py tools/python/xen/xend/XendDomain.py tools/python/xen/xend/XendDomainInfo.py tools/python/xen/xend/XendRoot.py tools/python/xen/xend/XendVnet.py tools/python/xen/xend/image.py tools/python/xen/xend/server/SrvConsole.py tools/python/xen/xend/server/SrvDaemon.py tools/python/xen/xend/server/SrvDomain.py tools/python/xen/xend/server/SrvDomainDir.py tools/python/xen/xend/server/blkif.py tools/python/xen/xend/server/channel.py tools/python/xen/xend/server/console.py tools/python/xen/xend/server/controller.py tools/python/xen/xend/server/netif.py tools/python/xen/xend/server/params.py tools/python/xen/xend/server/usbif.py tools/python/xen/xend/uuid.py tools/python/xen/xend/xenstore/__init__.py tools/python/xen/xend/xenstore/xsnode.py tools/python/xen/xend/xenstore/xsobj.py tools/python/xen/xend/xenstore/xsresource.py tools/xenstore/.gdbinit tools/xenstore/Makefile tools/xenstore/TODO tools/xenstore/fake_libxc.c tools/xenstore/list.h tools/xenstore/talloc.c tools/xenstore/talloc.h tools/xenstore/talloc_guide.txt tools/xenstore/testsuite/01simple.sh tools/xenstore/testsuite/02directory.sh tools/xenstore/testsuite/03write.sh tools/xenstore/testsuite/04rm.sh tools/xenstore/testsuite/05filepermissions.sh tools/xenstore/testsuite/06dirpermissions.sh tools/xenstore/testsuite/07watch.sh tools/xenstore/testsuite/08transaction.sh tools/xenstore/testsuite/09domain.sh tools/xenstore/testsuite/test.sh tools/xenstore/utils.c tools/xenstore/utils.h tools/xenstore/xenstored.h tools/xenstore/xenstored_core.c tools/xenstore/xenstored_core.h tools/xenstore/xenstored_domain.c tools/xenstore/xenstored_domain.h tools/xenstore/xenstored_test.h tools/xenstore/xenstored_transaction.c tools/xenstore/xenstored_transaction.h tools/xenstore/xenstored_watch.c tools/xenstore/xenstored_watch.h tools/xenstore/xs.c tools/xenstore/xs.h tools/xenstore/xs_lib.c tools/xenstore/xs_lib.h tools/xenstore/xs_random.c tools/xenstore/xs_stress.c tools/xenstore/xs_test.c xen/include/public/xen.h
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);
 57.1286 +	if (dofork) {
 57.1287 +		openlog("xenstored", 0, LOG_DAEMON);
 57.1288 +		daemonize();
 5