xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
From: Vincent Hanquez <vincent.hanquez@eu.citrix.com>
To: xen-devel@lists.xensource.com
Cc: Vincent Hanquez <vincent.hanquez@eu.citrix.com>
Subject: [PATCH 2/6] add ocaml xenstored
Date: Mon,  1 Mar 2010 11:59:47 +0000	[thread overview]
Message-ID: <1267444791-4810-3-git-send-email-vincent.hanquez@eu.citrix.com> (raw)
In-Reply-To: <1267444791-4810-1-git-send-email-vincent.hanquez@eu.citrix.com>

[-- Attachment #1: Type: text/plain, Size: 2488 bytes --]


Signed-off-by: Vincent Hanquez <vincent.hanquez@eu.citrix.com>
---
 tools/ocaml/xenstored/Makefile       |   54 ++++
 tools/ocaml/xenstored/config.ml      |  112 ++++++++
 tools/ocaml/xenstored/connection.ml  |  234 +++++++++++++++++
 tools/ocaml/xenstored/connections.ml |  167 ++++++++++++
 tools/ocaml/xenstored/define.ml      |   40 +++
 tools/ocaml/xenstored/disk.ml        |  157 ++++++++++++
 tools/ocaml/xenstored/domain.ml      |   62 +++++
 tools/ocaml/xenstored/domains.ml     |   84 ++++++
 tools/ocaml/xenstored/event.ml       |   29 +++
 tools/ocaml/xenstored/logging.ml     |  238 ++++++++++++++++++
 tools/ocaml/xenstored/parse_arg.ml   |   68 +++++
 tools/ocaml/xenstored/perms.ml       |  165 ++++++++++++
 tools/ocaml/xenstored/process.ml     |  395 +++++++++++++++++++++++++++++
 tools/ocaml/xenstored/quota.ml       |   83 ++++++
 tools/ocaml/xenstored/store.ml       |  460 ++++++++++++++++++++++++++++++++++
 tools/ocaml/xenstored/symbol.ml      |   76 ++++++
 tools/ocaml/xenstored/symbol.mli     |   52 ++++
 tools/ocaml/xenstored/transaction.ml |  197 +++++++++++++++
 tools/ocaml/xenstored/utils.ml       |  107 ++++++++
 tools/ocaml/xenstored/xenstored.conf |   30 +++
 tools/ocaml/xenstored/xenstored.ml   |  404 +++++++++++++++++++++++++++++
 21 files changed, 3214 insertions(+), 0 deletions(-)
 create mode 100644 tools/ocaml/xenstored/Makefile
 create mode 100644 tools/ocaml/xenstored/config.ml
 create mode 100644 tools/ocaml/xenstored/connection.ml
 create mode 100644 tools/ocaml/xenstored/connections.ml
 create mode 100644 tools/ocaml/xenstored/define.ml
 create mode 100644 tools/ocaml/xenstored/disk.ml
 create mode 100644 tools/ocaml/xenstored/domain.ml
 create mode 100644 tools/ocaml/xenstored/domains.ml
 create mode 100644 tools/ocaml/xenstored/event.ml
 create mode 100644 tools/ocaml/xenstored/logging.ml
 create mode 100644 tools/ocaml/xenstored/parse_arg.ml
 create mode 100644 tools/ocaml/xenstored/perms.ml
 create mode 100644 tools/ocaml/xenstored/process.ml
 create mode 100644 tools/ocaml/xenstored/quota.ml
 create mode 100644 tools/ocaml/xenstored/store.ml
 create mode 100644 tools/ocaml/xenstored/symbol.ml
 create mode 100644 tools/ocaml/xenstored/symbol.mli
 create mode 100644 tools/ocaml/xenstored/transaction.ml
 create mode 100644 tools/ocaml/xenstored/utils.ml
 create mode 100644 tools/ocaml/xenstored/xenstored.conf
 create mode 100644 tools/ocaml/xenstored/xenstored.ml


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0002-add-ocaml-xenstored.patch --]
[-- Type: text/x-patch; name="0002-add-ocaml-xenstored.patch", Size: 108196 bytes --]

diff --git a/tools/ocaml/xenstored/Makefile b/tools/ocaml/xenstored/Makefile
new file mode 100644
index 0000000..0e7cce4
--- /dev/null
+++ b/tools/ocaml/xenstored/Makefile
@@ -0,0 +1,54 @@
+OCAML_TOPLEVEL = ..
+include $(OCAML_TOPLEVEL)/common.make
+
+OCAMLINCLUDE += \
+	-I $(OCAML_TOPLEVEL)/libs/log \
+	-I $(OCAML_TOPLEVEL)/libs/xb \
+	-I $(OCAML_TOPLEVEL)/libs/uuid \
+	-I $(OCAML_TOPLEVEL)/libs/mmap \
+	-I $(OCAML_TOPLEVEL)/libs/xc \
+	-I $(OCAML_TOPLEVEL)/libs/eventchn \
+	-I $(OCAML_TOPLEVEL)/libs/stdext
+
+OBJS = define \
+	config \
+	logging \
+	quota \
+	perms \
+	symbol \
+	utils \
+	store \
+	disk \
+	transaction \
+	event \
+	domain \
+	domains \
+	connection \
+	connections \
+	parse_arg \
+	process \
+	xenstored
+
+INTF = symbol.cmi
+XENSTOREDLIBS = \
+	unix.cmxa \
+	$(OCAML_TOPLEVEL)/libs/uuid/uuid.cmxa \
+	-ccopt -L -ccopt $(OCAML_TOPLEVEL)/libs/mmap $(OCAML_TOPLEVEL)/libs/mmap/mmap.cmxa \
+	-ccopt -L -ccopt $(OCAML_TOPLEVEL)/libs/log $(OCAML_TOPLEVEL)/libs/log/log.cmxa \
+	-ccopt -L -ccopt $(OCAML_TOPLEVEL)/libs/eventchn $(OCAML_TOPLEVEL)/libs/eventchn/eventchn.cmxa \
+	-ccopt -L -ccopt $(OCAML_TOPLEVEL)/libs/xc $(OCAML_TOPLEVEL)/libs/xc/xc.cmxa \
+	-ccopt -L -ccopt $(OCAML_TOPLEVEL)/libs/xb $(OCAML_TOPLEVEL)/libs/xb/xb.cmxa \
+	-ccopt -L -ccopt $(OCAML_TOPLEVEL)/libs/stdext $(OCAML_TOPLEVEL)/libs/stdext/stdext.cmxa
+
+PROGRAMS = oxenstored
+
+oxenstored_LIBS = $(XENSTOREDLIBS)
+oxenstored_OBJS = $(OBJS)
+
+OCAML_PROGRAM = oxenstored
+
+all: $(INTF) $(PROGRAMS)
+
+bins: $(PROGRAMS)
+
+include $(OCAML_TOPLEVEL)/Makefile.rules
diff --git a/tools/ocaml/xenstored/config.ml b/tools/ocaml/xenstored/config.ml
new file mode 100644
index 0000000..0ee7bc3
--- /dev/null
+++ b/tools/ocaml/xenstored/config.ml
@@ -0,0 +1,112 @@
+(*
+ * Copyright (C) 2006-2007 XenSource Ltd.
+ * Copyright (C) 2008      Citrix Ltd.
+ * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *)
+
+type ty =
+	| Set_bool of bool ref
+	| Set_int of int ref
+	| Set_string of string ref
+	| Set_float of float ref
+	| Unit of (unit -> unit)
+	| Bool of (bool -> unit)
+	| Int of (int -> unit)
+	| String of (string -> unit)
+	| Float of (float -> unit)
+
+exception Error of (string * string) list
+
+let trim_start lc s =
+	let len = String.length s and i = ref 0 in
+	while !i < len && (List.mem s.[!i] lc)
+	do
+		incr i
+	done;
+	if !i < len then String.sub s !i (len - !i) else ""
+
+let trim_end lc s =
+	let i = ref (String.length s - 1) in
+	while !i > 0 && (List.mem s.[!i] lc)
+	do
+		decr i
+	done;
+	if !i >= 0 then String.sub s 0 (!i + 1) else ""
+
+let rec split ?limit:(limit=(-1)) c s =
+	let i = try String.index s c with Not_found -> -1 in
+	let nlimit = if limit = -1 || limit = 0 then limit else limit - 1 in
+	if i = -1 || nlimit = 0 then
+		[ s ]
+	else
+		let a = String.sub s 0 i
+		and b = String.sub s (i + 1) (String.length s - i - 1) in
+		a :: (split ~limit: nlimit c b)
+
+let parse_line stream =
+	let lc = [ ' '; '\t' ] in
+	let trim_spaces s = trim_end lc (trim_start lc s) in
+	let to_config s =
+		match split ~limit:2 '=' s with
+		| k :: v :: [] -> Some (trim_end lc k, trim_start lc v)
+		| _            -> None in
+	let rec read_filter_line () =
+		try
+			let line = trim_spaces (input_line stream) in
+			if String.length line > 0 && line.[0] <> '#' then
+				match to_config line with
+				| None   -> read_filter_line ()
+				| Some x -> x :: read_filter_line ()
+			else
+				read_filter_line ()
+		with
+			End_of_file -> [] in
+	read_filter_line ()
+
+let parse filename =
+	let stream = open_in filename in
+	let cf = parse_line stream in
+	close_in stream;
+	cf
+
+let validate cf expected other =
+	let err = ref [] in
+	let append x = err := x :: !err in
+	List.iter (fun (k, v) ->
+		try
+			if not (List.mem_assoc k expected) then
+				other k v
+			else let ty = List.assoc k expected in
+			match ty with
+			| Unit f       -> f ()
+			| Bool f       -> f (bool_of_string v)
+			| String f     -> f v
+			| Int f        -> f (int_of_string v)
+			| Float f      -> f (float_of_string v)
+			| Set_bool r   -> r := (bool_of_string v)
+			| Set_string r -> r := v
+			| Set_int r    -> r := int_of_string v
+			| Set_float r  -> r := (float_of_string v)
+		with
+		| Not_found                 -> append (k, "unknown key")
+		| Failure "int_of_string"   -> append (k, "expect int arg")
+		| Failure "bool_of_string"  -> append (k, "expect bool arg")
+		| Failure "float_of_string" -> append (k, "expect float arg")
+		| exn                       -> append (k, Printexc.to_string exn)
+		) cf;
+	if !err != [] then raise (Error !err)
+
+(** read a filename, parse and validate, and return the errors if any *)
+let read filename expected other =
+	let cf = parse filename in
+	validate cf expected other
diff --git a/tools/ocaml/xenstored/connection.ml b/tools/ocaml/xenstored/connection.ml
new file mode 100644
index 0000000..9da9e7c
--- /dev/null
+++ b/tools/ocaml/xenstored/connection.ml
@@ -0,0 +1,234 @@
+(*
+ * Copyright (C) 2006-2007 XenSource Ltd.
+ * Copyright (C) 2008      Citrix Ltd.
+ * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *)
+
+exception End_of_file
+
+open Stringext
+
+type watch = {
+	con: t;
+	token: string;
+	path: string;
+	base: string;
+	is_relative: bool;
+}
+
+and t = {
+	xb: Xb.t;
+	dom: Domain.t option;
+	transactions: (int, Transaction.t) Hashtbl.t;
+	mutable next_tid: int;
+	watches: (string, watch list) Hashtbl.t;
+	mutable nb_watches: int;
+	anonid: int;
+	mutable stat_nb_ops: int;
+	mutable perm: Perms.Connection.t;
+}
+
+let get_path con =
+Printf.sprintf "/local/domain/%i/" (match con.dom with None -> 0 | Some d -> Domain.get_id d)
+
+let watch_create ~con ~path ~token = { 
+	con = con; 
+	token = token; 
+	path = path; 
+	base = get_path con; 
+	is_relative = path.[0] <> '/' && path.[0] <> '@'
+}
+
+let get_con w = w.con
+ 
+let number_of_transactions con =
+	Hashtbl.length con.transactions
+
+let get_domain con = con.dom
+
+let anon_id_next = ref 1
+
+let get_domstr con =
+	match con.dom with
+	| None     -> "A" ^ (string_of_int con.anonid)
+	| Some dom -> "D" ^ (string_of_int (Domain.get_id dom))
+
+let make_perm dom =
+	let domid = 
+		match dom with
+		| None   -> 0
+		| Some d -> Domain.get_id d
+	in 
+	Perms.Connection.create ~perms:[Perms.READ; Perms.WRITE] domid
+
+let create xbcon dom =
+	let id =
+		match dom with
+		| None -> let old = !anon_id_next in incr anon_id_next; old
+		| Some _ -> 0  
+		in
+	let con = 
+	{
+	xb = xbcon;
+	dom = dom;
+	transactions = Hashtbl.create 5;
+	next_tid = 1;
+	watches = Hashtbl.create 8;
+	nb_watches = 0;
+	anonid = id;
+	stat_nb_ops = 0;
+	perm = make_perm dom;
+	}
+	in 
+	Logging.new_connection ~tid:Transaction.none ~con:(get_domstr con);
+	con
+
+let get_fd con = Xb.get_fd con.xb
+let close con =
+	Logging.end_connection ~tid:Transaction.none ~con:(get_domstr con);
+	Xb.close con.xb
+
+let get_perm con =
+	con.perm
+
+let restrict con domid =
+	con.perm <- Perms.Connection.restrict con.perm domid
+
+let set_target con target_domid =
+	con.perm <- Perms.Connection.set_target (get_perm con) ~perms:[Perms.READ; Perms.WRITE] target_domid
+
+let send_reply con tid rid ty data =
+	Xb.queue con.xb (Xb.Packet.create tid rid ty data)
+
+let send_error con tid rid err = send_reply con tid rid Xb.Op.Error (err ^ "\000")
+let send_ack con tid rid ty = send_reply con tid rid ty "OK\000"
+
+let get_watch_path con path =
+	if path.[0] = '@' || path.[0] = '/' then
+		path
+	else
+		let rpath = get_path con in
+		rpath ^ path
+
+let get_watches (con: t) path =
+	if Hashtbl.mem con.watches path
+	then Hashtbl.find con.watches path
+	else []
+
+let get_children_watches con path =
+	let path = path ^ "/" in
+	List.concat (Hashtbl.fold (fun p w l ->
+		if String.startswith path p then w :: l else l) con.watches [])
+
+let is_dom0 con =
+	Perms.Connection.is_dom0 (get_perm con)
+
+let add_watch con path token =
+	if !Quota.activate && !Define.maxwatch > 0 &&
+	   not (is_dom0 con) && con.nb_watches > !Define.maxwatch then
+		raise Quota.Limit_reached;
+	let apath = get_watch_path con path in
+	let l = get_watches con apath in
+	if List.exists (fun w -> w.token = token) l then
+		raise Define.Already_exist;
+	let watch = watch_create ~con ~token ~path in
+	Hashtbl.replace con.watches apath (watch :: l);
+	con.nb_watches <- con.nb_watches + 1;
+	apath, watch
+
+let del_watch con path token =
+	let apath = get_watch_path con path in
+	let ws = Hashtbl.find con.watches apath in
+	let w = List.find (fun w -> w.token = token) ws in
+	let filtered = Utils.list_remove w ws in
+	if List.length filtered > 0 then
+		Hashtbl.replace con.watches apath filtered
+	else
+		Hashtbl.remove con.watches apath;
+	con.nb_watches <- con.nb_watches - 1;
+	apath, w
+
+let list_watches con =
+	let ll = Hashtbl.fold 
+		(fun _ watches acc -> List.map (fun watch -> watch.path, watch.token) watches :: acc)
+		con.watches [] in
+	List.concat ll
+
+let fire_single_watch watch =
+	let data = Utils.join_by_null [watch.path; watch.token; ""] in
+	send_reply watch.con Transaction.none 0 Xb.Op.Watchevent data
+
+let fire_watch watch path =
+	let new_path =
+		if watch.is_relative && path.[0] = '/'
+		then begin
+			let n = String.length watch.base
+		 	and m = String.length path in
+			String.sub path n (m - n)
+		end else
+			path
+	in
+	let data = Utils.join_by_null [ new_path; watch.token; "" ] in
+	send_reply watch.con Transaction.none 0 Xb.Op.Watchevent data
+
+let find_next_tid con =
+	let ret = con.next_tid in con.next_tid <- con.next_tid + 1; ret
+
+let start_transaction con store =
+	if !Define.maxtransaction > 0 && not (is_dom0 con)
+	&& Hashtbl.length con.transactions > !Define.maxtransaction then
+		raise Quota.Transaction_opened;
+	let id = find_next_tid con in
+	let ntrans = Transaction.make id store in
+	Hashtbl.add con.transactions id ntrans;
+	Logging.start_transaction ~tid:id ~con:(get_domstr con);
+	id
+
+let end_transaction con tid commit =
+	let trans = Hashtbl.find con.transactions tid in
+	Hashtbl.remove con.transactions tid;
+	Logging.end_transaction ~tid ~con:(get_domstr con);
+	if commit then Transaction.commit ~con:(get_domstr con) trans else true
+
+let get_transaction con tid =
+	Hashtbl.find con.transactions tid
+
+let do_input con = Xb.input con.xb
+let has_input con = Xb.has_in_packet con.xb
+let pop_in con = Xb.get_in_packet con.xb
+let has_more_input con = Xb.has_more_input con.xb
+
+let has_output con = Xb.has_output con.xb
+let has_new_output con = Xb.has_new_output con.xb
+let peek_output con = Xb.peek_output con.xb
+let do_output con = Xb.output con.xb
+
+let incr_ops con = con.stat_nb_ops <- con.stat_nb_ops + 1
+
+let mark_symbols con =
+	Hashtbl.iter (fun _ t -> Store.mark_symbols (Transaction.get_store t)) con.transactions
+
+let stats con =
+	Hashtbl.length con.watches, con.stat_nb_ops
+
+let dump con chan =
+	match con.dom with
+	| Some dom -> 
+		let domid = Domain.get_id dom in
+		(* dump domain *)
+		Domain.dump dom chan;
+		(* dump watches *)
+		List.iter (fun (path, token) ->
+			Printf.fprintf chan "watch,%d,%s,%s\n" domid (Utils.hexify path) (Utils.hexify token)
+			) (list_watches con);
+	| None -> ()
diff --git a/tools/ocaml/xenstored/connections.ml b/tools/ocaml/xenstored/connections.ml
new file mode 100644
index 0000000..c331bab
--- /dev/null
+++ b/tools/ocaml/xenstored/connections.ml
@@ -0,0 +1,167 @@
+(*
+ * Copyright (C) 2006-2007 XenSource Ltd.
+ * Copyright (C) 2008      Citrix Ltd.
+ * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
+ * Author Thomas Gazagnaire <thomas.gazagnaire@eu.citrix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *)
+
+let debug fmt = Logs.debug "general" fmt
+
+type t = {
+	mutable anonymous: Connection.t list;
+	domains: (int, Connection.t) Hashtbl.t;
+	mutable watches: (string, Connection.watch list) Trie.t;
+}
+
+let create () = { anonymous = []; domains = Hashtbl.create 8; watches = Trie.create () }
+
+let add_anonymous cons fd can_write =
+	let xbcon = Xb.open_fd fd in
+	let con = Connection.create xbcon None in
+	cons.anonymous <- con :: cons.anonymous
+
+let add_domain cons dom =
+	let xbcon = Xb.open_mmap (Domain.get_interface dom) (fun () -> Domain.notify dom) in
+	let con = Connection.create xbcon (Some dom) in
+	Hashtbl.add cons.domains (Domain.get_id dom) con
+
+let select cons =
+	let inset = List.map (fun c -> Connection.get_fd c) cons.anonymous
+	and outset = List.fold_left (fun l c -> if Connection.has_output c
+						then Connection.get_fd c :: l
+						else l) [] cons.anonymous in
+	inset, outset
+
+let find cons fd =
+	List.find (fun c -> Connection.get_fd c = fd) cons.anonymous
+
+let find_domain cons id =
+	Hashtbl.find cons.domains id
+
+let del_watches_of_con con watches =
+	match List.filter (fun w -> Connection.get_con w != con) watches with
+	| [] -> None
+	| ws -> Some ws 
+
+let del_anonymous cons con =
+	try
+		cons.anonymous <- Utils.list_remove con cons.anonymous;
+		cons.watches <- Trie.map (del_watches_of_con con) cons.watches;
+		Connection.close con
+	with exn ->
+		debug "del anonymous %s" (Printexc.to_string exn)
+
+let del_domain cons id =
+	try
+		let con = find_domain cons id in
+		Hashtbl.remove cons.domains id;
+		cons.watches <- Trie.map (del_watches_of_con con) cons.watches;
+		Connection.close con
+	with exn ->
+		debug "del domain %u: %s" id (Printexc.to_string exn)
+
+let iter_domains cons fct =
+	Hashtbl.iter (fun k c -> fct c) cons.domains
+
+let iter_anonymous cons fct =
+	List.iter (fun c -> fct c) (List.rev cons.anonymous)
+
+let iter cons fct =
+	iter_domains cons fct; iter_anonymous cons fct
+
+let has_more_work cons =
+	Hashtbl.fold (fun id con acc ->
+		if Connection.has_more_input con then
+			con :: acc
+		else
+			acc) cons.domains []
+
+let key_of_str path =
+	if path.[0] = '@'
+	then [path]
+	else "" :: Store.Path.to_string_list (Store.Path.of_string path)
+
+let key_of_path path =
+	"" :: Store.Path.to_string_list path
+
+let add_watch cons con path token =
+	let apath, watch = Connection.add_watch con path token in
+	let key = key_of_str apath in
+	let watches =
+ 		if Trie.mem cons.watches key
+ 		then Trie.find cons.watches key
+ 		else []
+	in
+ 	cons.watches <- Trie.set cons.watches key (watch :: watches);
+	watch
+
+let del_watch cons con path token =
+ 	let apath, watch = Connection.del_watch con path token in
+ 	let key = key_of_str apath in
+ 	let watches = Utils.list_remove watch (Trie.find cons.watches key) in
+ 	if watches = [] then
+		cons.watches <- Trie.unset cons.watches key
+ 	else
+		cons.watches <- Trie.set cons.watches key watches;
+ 	watch
+
+(* path is absolute *)
+let fire_watches cons path recurse =
+	let key = key_of_path path in
+	let path = Store.Path.to_string path in
+	let fire_watch _ = function
+		| None         -> ()
+		| Some watches -> List.iter (fun w -> Connection.fire_watch w path) watches
+	in
+	let fire_rec x = function
+		| None         -> ()
+		| Some watches -> 
+			  List.iter (fun w -> Connection.fire_single_watch w) watches
+	in
+	Trie.iter_path fire_watch cons.watches key;
+	if recurse then
+		Trie.iter fire_rec (Trie.sub cons.watches key)
+
+let fire_spec_watches cons specpath =
+	iter cons (fun con ->
+		List.iter (fun w -> Connection.fire_single_watch w) (Connection.get_watches con specpath))
+
+let set_target cons domain target_domain =
+	let con = find_domain cons domain in
+	Connection.set_target con target_domain
+
+let number_of_transactions cons =
+	let res = ref 0 in
+	let aux con = 
+		res := Connection.number_of_transactions con + !res
+	in
+	iter cons aux;
+	!res
+
+let stats cons =
+	let nb_ops_anon = ref 0 
+	and nb_watchs_anon = ref 0
+	and nb_ops_dom = ref 0
+	and nb_watchs_dom = ref 0 in
+	iter_anonymous cons (fun con ->
+		let con_watchs, con_ops = Connection.stats con in
+		nb_ops_anon := !nb_ops_anon + con_ops;
+		nb_watchs_anon := !nb_watchs_anon + con_watchs;
+	);
+	iter_domains cons (fun con ->
+		let con_watchs, con_ops = Connection.stats con in
+		nb_ops_dom := !nb_ops_dom + con_ops;
+		nb_watchs_dom := !nb_watchs_dom + con_watchs;
+	);
+	(List.length cons.anonymous, !nb_ops_anon, !nb_watchs_anon,
+	 Hashtbl.length cons.domains, !nb_ops_dom, !nb_watchs_dom)
diff --git a/tools/ocaml/xenstored/define.ml b/tools/ocaml/xenstored/define.ml
new file mode 100644
index 0000000..19a699f
--- /dev/null
+++ b/tools/ocaml/xenstored/define.ml
@@ -0,0 +1,40 @@
+(*
+ * Copyright (C) 2006-2007 XenSource Ltd.
+ * Copyright (C) 2008      Citrix Ltd.
+ * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *)
+
+let xenstored_major = 1
+let xenstored_minor = 0
+
+let xenstored_proc_kva = "/proc/xen/xsd_kva"
+let xenstored_proc_port = "/proc/xen/xsd_port"
+
+let xs_daemon_socket = "/var/run/xenstored/socket"
+let xs_daemon_socket_ro = "/var/run/xenstored/socket_ro"
+
+let default_config_dir = "/etc/xensource"
+
+let maxwatch = ref (50)
+let maxtransaction = ref (20)
+
+let domid_self = 0x7FF0
+
+exception Not_a_directory of string
+exception Not_a_value of string
+exception Already_exist
+exception Doesnt_exist
+exception Lookup_Doesnt_exist of string
+exception Invalid_path
+exception Permission_denied
+exception Unknown_operation
diff --git a/tools/ocaml/xenstored/disk.ml b/tools/ocaml/xenstored/disk.ml
new file mode 100644
index 0000000..65dd42a
--- /dev/null
+++ b/tools/ocaml/xenstored/disk.ml
@@ -0,0 +1,157 @@
+(*
+ * Copyright (C) 2006-2007 XenSource Ltd.
+ * Copyright (C) 2008      Citrix Ltd.
+ * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *)
+
+let enable = ref false
+let xs_daemon_database = "/var/run/xenstored/db"
+
+let error = Logs.error "general"
+
+(* unescape utils *)
+exception Bad_escape
+
+let is_digit c = match c with '0' .. '9' -> true | _ -> false
+
+let undec c =
+	match c with
+	| '0' .. '9' -> (Char.code c) - (Char.code '0')
+	| _          -> raise (Failure "undecify")
+
+let unhex c =
+	let c = Char.lowercase c in
+	match c with
+	| '0' .. '9' -> (Char.code c) - (Char.code '0')
+	| 'a' .. 'f' -> (Char.code c) - (Char.code 'a') + 10
+	| _          -> raise (Failure "unhexify")
+
+let string_unescaped s =
+	let len = String.length s
+	and i = ref 0 in
+	let d = Buffer.create len in
+
+	let read_escape () =
+		incr i;
+		match s.[!i] with
+		| 'n'  -> '\n'
+		| 'r'  -> '\r'
+		| '\\' -> '\\'
+		| '\'' -> '\''
+		| '"'  -> '"'
+		| 't'  -> '\t'
+		| 'b'  -> '\b'
+		| 'x'  ->
+			let v = (unhex s.[!i + 1] * 16) + unhex s.[!i + 2] in
+			i := !i + 2;
+			Char.chr v
+		| c    ->
+			if is_digit c then (
+				let v = (undec s.[!i]) * 100 +
+					(undec s.[!i + 1]) * 10 +
+					(undec s.[!i + 2]) in
+				i := !i + 2;
+				Char.chr v
+			) else
+				raise Bad_escape
+	in
+
+	while !i < len
+	do
+		let c = match s.[!i] with
+		| '\\' -> read_escape ()
+		| c    -> c in
+		Buffer.add_char d c;
+		incr i
+	done;
+	Buffer.contents d
+
+(* file -> lines_of_file *)
+let file_readlines file =
+	let channel = open_in file in
+	let rec input_line_list channel =
+		let line = try input_line channel with End_of_file -> "" in
+		if String.length line > 0 then
+			line :: input_line_list channel
+		else (
+			close_in channel;
+			[]
+		) in
+	input_line_list channel
+
+let rec map_string_list_range l s =
+	match l with
+	| [] -> []
+	| (a,b) :: l -> String.sub s a (b - a) :: map_string_list_range l s
+
+let is_digit c =
+	try ignore (int_of_char c); true with _ -> false
+
+let rec parse_perm s =
+	let len = String.length s in
+	if len = 0 then
+		[]
+	else
+		let i = ref 1 in
+		while !i < len && is_digit s.[!i] do incr i done;
+		let x = String.sub s 0 !i
+		and lx = String.sub s !i len in
+		x :: parse_perm lx
+
+let read store =
+	(* don't let the permission get on our way, full perm ! *)
+	let v = Store.get_ops store Perms.Connection.full_rights in
+
+	(* a line is : path{perm} or path{perm} = value *)
+	let parse_line s =
+		let path, perm, value =
+			let len = String.length s in
+			let si = if String.contains s '=' then
+					String.index s '='
+				else
+					len - 1 in
+			let pi = String.rindex_from s si '{' in
+			let epi = String.index_from s pi '}' in
+
+			if String.contains s '=' then
+				let ss = map_string_list_range [ (0, pi);
+				                                 (pi + 1, epi);
+				                                 (si + 2, len); ] s in
+				(List.nth ss 0, List.nth ss 1, List.nth ss 2)
+			else
+				let ss = map_string_list_range [ (0, pi);
+				                                 (pi + 1, epi);
+				                               ] s in
+				(List.nth ss 0, List.nth ss 1, "")
+			in
+		let path = Store.Path.of_string path in
+		v.Store.write path (string_unescaped value);
+		v.Store.setperms path (Perms.Node.of_strings (parse_perm perm)) in
+	try
+		let lines = file_readlines xs_daemon_database in
+		List.iter (fun s -> parse_line s) lines
+	with exc ->
+		error "caught exn %s" (Printexc.to_string exc)
+
+let write store =
+	if !enable then
+	try
+		let tfile = Printf.sprintf "%s#" xs_daemon_database in
+		let channel = open_out_gen [ Open_wronly; Open_creat; Open_trunc; ]
+		                           0o600 tfile in
+		Store.dump store channel;
+		flush channel;
+		close_out channel;
+		Unix.rename tfile xs_daemon_database
+	with exc ->
+		error "caught exn %s" (Printexc.to_string exc)
diff --git a/tools/ocaml/xenstored/domain.ml b/tools/ocaml/xenstored/domain.ml
new file mode 100644
index 0000000..258d172
--- /dev/null
+++ b/tools/ocaml/xenstored/domain.ml
@@ -0,0 +1,62 @@
+(*
+ * Copyright (C) 2006-2007 XenSource Ltd.
+ * Copyright (C) 2008      Citrix Ltd.
+ * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *)
+
+open Printf
+
+let debug fmt = Logs.debug "general" fmt
+
+type t =
+{
+	id: Xc.domid;
+	mfn: nativeint;
+	remote_port: int;
+	interface: Mmap.mmap_interface;
+	eventchn: Event.t;
+	mutable port: int;
+}
+
+let get_path dom = "/local/domain/" ^ (sprintf "%u" dom.id)
+let get_id domain = domain.id
+let get_interface d = d.interface
+let get_mfn d = d.mfn
+let get_remote_port d = d.remote_port
+
+let dump d chan =
+	fprintf chan "dom,%d,%nd,%d\n" d.id d.mfn d.port
+
+let notify dom = Event.notify dom.eventchn dom.port; ()
+
+let bind_interdomain dom =
+	dom.port <- Event.bind_interdomain dom.eventchn dom.id dom.remote_port;
+	debug "domain %d bound port %d" dom.id dom.port
+
+
+let close dom =
+	debug "domain %d unbound port %d" dom.id dom.port;
+	Event.unbind dom.eventchn dom.port;
+	Mmap.unmap dom.interface;
+	()
+
+let make id mfn remote_port interface eventchn = {
+	id = id;
+	mfn = mfn;
+	remote_port = remote_port;
+	interface = interface;
+	eventchn = eventchn;
+	port = -1
+}
+
+let is_dom0 d = d.id = 0
diff --git a/tools/ocaml/xenstored/domains.ml b/tools/ocaml/xenstored/domains.ml
new file mode 100644
index 0000000..54d50d8
--- /dev/null
+++ b/tools/ocaml/xenstored/domains.ml
@@ -0,0 +1,84 @@
+(*
+ * Copyright (C) 2006-2007 XenSource Ltd.
+ * Copyright (C) 2008      Citrix Ltd.
+ * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *)
+
+type domains = {
+	eventchn: Event.t;
+	table: (Xc.domid, Domain.t) Hashtbl.t;
+}
+
+let init eventchn =
+	{ eventchn = eventchn; table = Hashtbl.create 10 }
+let del doms id = Hashtbl.remove doms.table id
+let exist doms id = Hashtbl.mem doms.table id
+let find doms id = Hashtbl.find doms.table id
+let number doms = Hashtbl.length doms.table
+let iter doms fct = Hashtbl.iter (fun _ b -> fct b) doms.table
+
+let cleanup xc doms =
+	let notify = ref false in
+	let dead_dom = ref [] in
+
+	Hashtbl.iter (fun id _ -> if id <> 0 then
+		try
+			let info = Xc.domain_getinfo xc id in
+			if info.Xc.shutdown || info.Xc.dying then (
+				Logs.debug "general" "Domain %u died (dying=%b, shutdown %b -- code %d)"
+				                    id info.Xc.dying info.Xc.shutdown info.Xc.shutdown_code;
+				if info.Xc.dying then
+					dead_dom := id :: !dead_dom
+				else
+					notify := true;
+			)
+		with Xc.Error _ ->
+			Logs.debug "general" "Domain %u died -- no domain info" id;
+			dead_dom := id :: !dead_dom;
+		) doms.table;
+	List.iter (fun id ->
+		let dom = Hashtbl.find doms.table id in
+		Domain.close dom;
+		Hashtbl.remove doms.table id;
+	) !dead_dom;
+	!notify, !dead_dom
+
+let resume doms domid =
+	()
+
+let create xc doms domid mfn port =
+	let interface = Xc.map_foreign_range xc domid (Mmap.getpagesize()) mfn in
+	let dom = Domain.make domid mfn port interface doms.eventchn in
+	Hashtbl.add doms.table domid dom;
+	Domain.bind_interdomain dom;
+	dom
+
+let create0 fake doms =
+	let port, interface =
+		if fake then (
+			0, Xc.with_intf (fun xc -> Xc.map_foreign_range xc 0 (Mmap.getpagesize()) 0n)
+		) else (
+			let port = Utils.read_file_single_integer Define.xenstored_proc_port
+			and fd = Unix.openfile Define.xenstored_proc_kva
+					       [ Unix.O_RDWR ] 0o600 in
+			let interface = Mmap.mmap fd Mmap.RDWR Mmap.SHARED
+						  (Mmap.getpagesize()) 0 in
+			Unix.close fd;
+			port, interface
+		)
+		in
+	let dom = Domain.make 0 Nativeint.zero port interface doms.eventchn in
+	Hashtbl.add doms.table 0 dom;
+	Domain.bind_interdomain dom;
+	Domain.notify dom;
+	dom
diff --git a/tools/ocaml/xenstored/event.ml b/tools/ocaml/xenstored/event.ml
new file mode 100644
index 0000000..5cbdccf
--- /dev/null
+++ b/tools/ocaml/xenstored/event.ml
@@ -0,0 +1,29 @@
+(*
+ * Copyright (C) 2006-2007 XenSource Ltd.
+ * Copyright (C) 2008      Citrix Ltd.
+ * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *)
+
+(**************** high level binding ****************)
+type t = {
+	fd: Unix.file_descr;
+	mutable virq_port: int;
+}
+
+let init () = { fd = Eventchn.init (); virq_port = -1; }
+let bind_virq eventchn = eventchn.virq_port <- Eventchn.bind_virq eventchn.fd
+let bind_interdomain eventchn domid port = Eventchn.bind_interdomain eventchn.fd domid port
+let unbind eventchn port = Eventchn.unbind eventchn.fd port
+let notify eventchn port = Eventchn.notify eventchn.fd port
+let read_port eventchn = Eventchn.read_port eventchn.fd
+let write_port eventchn port = Eventchn.write_port eventchn.fd port
diff --git a/tools/ocaml/xenstored/logging.ml b/tools/ocaml/xenstored/logging.ml
new file mode 100644
index 0000000..639ac2a
--- /dev/null
+++ b/tools/ocaml/xenstored/logging.ml
@@ -0,0 +1,238 @@
+(*
+ * Copyright (C) 2006-2007 XenSource Ltd.
+ * Copyright (C) 2008      Citrix Ltd.
+ * Author Thomas Gazagnaire <thomas.gazagnaire@citrix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *)
+
+open Printf
+
+let error fmt = Logs.error "general" fmt
+let info fmt = Logs.info "general" fmt
+let debug fmt = Logs.debug "general" fmt
+
+let access_log_file = ref "/var/log/xenstored-access.log"
+let access_log_nb_files = ref 20
+let access_log_nb_lines = ref 13215
+let activate_access_log = ref true
+
+(* maximal size of the lines in xenstore-acces.log file *)
+let line_size = 180
+
+let log_read_ops = ref false
+let log_transaction_ops = ref false
+let log_special_ops = ref false
+
+type access_type =
+	| Coalesce
+	| Conflict
+	| Commit
+	| Newconn
+	| Endconn
+	| XbOp of Xb.Op.operation
+
+type access =
+	{
+		fd: out_channel ref;
+		counter: int ref;
+		write: tid:int -> con:string -> ?data:string -> access_type -> unit;
+	}
+
+let string_of_date () =
+	let time = Unix.gettimeofday () in
+	let tm = Unix.localtime time in
+	let msec = time -. (floor time) in
+	sprintf "%d%.2d%.2d %.2d:%.2d:%.2d.%.3d" (1900 + tm.Unix.tm_year)
+		(tm.Unix.tm_mon + 1)
+		tm.Unix.tm_mday
+		tm.Unix.tm_hour
+		tm.Unix.tm_min
+		tm.Unix.tm_sec
+		(int_of_float (1000.0 *. msec))
+
+let fill_with_space n s =
+	if String.length s < n
+	then 
+		let r = String.make n ' ' in
+		String.blit s 0  r 0 (String.length s);
+		r
+	else 
+		s
+
+let string_of_tid ~con tid =
+	if tid = 0
+	then fill_with_space 12 (sprintf "%s" con)
+	else fill_with_space 12 (sprintf "%s.%i" con tid)
+
+let string_of_access_type = function
+	| Coalesce                -> "coalesce "
+	| Conflict                -> "conflict "
+	| Commit                  -> "commit   "
+	| Newconn                 -> "newconn  "
+	| Endconn                 -> "endconn  "
+
+	| XbOp op -> match op with
+	| Xb.Op.Debug             -> "debug    "
+
+	| Xb.Op.Directory         -> "directory"
+	| Xb.Op.Read              -> "read     "
+	| Xb.Op.Getperms          -> "getperms "
+
+	| Xb.Op.Watch             -> "watch    "
+	| Xb.Op.Unwatch           -> "unwatch  "
+
+	| Xb.Op.Transaction_start -> "t start  "
+	| Xb.Op.Transaction_end   -> "t end    "
+
+	| Xb.Op.Introduce         -> "introduce"
+	| Xb.Op.Release           -> "release  "
+	| Xb.Op.Getdomainpath     -> "getdomain"
+	| Xb.Op.Isintroduced      -> "is introduced"
+	| Xb.Op.Resume            -> "resume   "
+ 
+	| Xb.Op.Write             -> "write    "
+	| Xb.Op.Mkdir             -> "mkdir    "
+	| Xb.Op.Rm                -> "rm       "
+	| Xb.Op.Setperms          -> "setperms "
+	| Xb.Op.Restrict          -> "restrict "
+	| Xb.Op.Set_target        -> "settarget"
+
+	| Xb.Op.Error             -> "error    "
+	| Xb.Op.Watchevent        -> "w event  "
+
+	| x                       -> Xb.Op.to_string x
+
+let file_exists file =
+	try
+		Unix.close (Unix.openfile file [Unix.O_RDONLY] 0o644);
+		true
+	with _ ->
+		false
+
+let log_rotate fd =
+	let file n = sprintf "%s.%i" !access_log_file n in
+	let log_files =
+		let rec aux accu n =
+			if n >= !access_log_nb_files
+			then accu
+			else if n = 1 && file_exists !access_log_file
+			then aux [!access_log_file,1] 2
+			else
+				let file = file (n-1) in
+				if file_exists file
+				then aux ((file,n) :: accu) (n+1)
+				else accu
+		in
+		aux [] 1
+	in
+	let rec rename = function
+		| (f,n) :: t when n < !access_log_nb_files -> 
+			Unix.rename f (file n);
+			rename t
+		| _ -> ()
+	in
+	rename log_files;
+	close_out !fd;
+	fd := open_out !access_log_file
+
+let sanitize_data data =
+	let data = String.copy data in
+	for i = 0 to String.length data - 1
+	do
+		if data.[i] = '\000' then
+			data.[i] <- ' '
+	done;
+	String.escaped data
+
+let make save_to_disk =
+	let fd = ref (open_out_gen [Open_append; Open_creat] 0o644 !access_log_file) in
+	let counter = ref 0 in
+	{
+		fd = fd;
+		counter = counter;
+		write = 
+			if not !activate_access_log || !access_log_nb_files = 0
+			then begin fun ~tid ~con ?data _ -> () end
+			else fun ~tid ~con ?(data="") access_type ->
+				let s = Printf.sprintf "[%s] %s %s %s\n" (string_of_date()) (string_of_tid ~con tid) 
+					(string_of_access_type access_type) (sanitize_data data) in
+				let s =
+					if String.length s > line_size
+					then begin
+						let s = String.sub s 0 line_size in
+						s.[line_size-3] <- '.'; 
+						s.[line_size-2] <- '.';
+						s.[line_size-1] <- '\n';
+						s
+					end else
+						s
+				in
+				incr counter;
+				output_string !fd s;
+				flush !fd;
+				if !counter > !access_log_nb_lines 
+				then begin 
+					log_rotate fd;
+					save_to_disk ();
+					counter := 0;
+				end
+	}
+
+let access : (access option) ref = ref None
+let init aal save_to_disk =
+	activate_access_log := aal;
+	access := Some (make save_to_disk)
+
+let write_access_log ~con ~tid ?data access_type = 
+        try
+	  Pervasiveext.maybe (fun a -> a.write access_type ~con ~tid ?data) !access
+	with _ -> ()
+
+let new_connection = write_access_log Newconn
+let end_connection = write_access_log Endconn
+let read_coalesce ~tid ~con data =
+	if !log_read_ops
+	then write_access_log Coalesce ~tid ~con ~data:("read "^data)
+let write_coalesce data = write_access_log Coalesce ~data:("write "^data)
+let conflict = write_access_log Conflict
+let commit = write_access_log Commit
+
+let xb_op ~tid ~con ~ty data =
+	let print =
+	match ty with
+		| Xb.Op.Read | Xb.Op.Directory | Xb.Op.Getperms -> !log_read_ops
+		| Xb.Op.Transaction_start | Xb.Op.Transaction_end ->
+			false (* transactions are managed below *)
+		| Xb.Op.Introduce | Xb.Op.Release | Xb.Op.Getdomainpath | Xb.Op.Isintroduced | Xb.Op.Resume ->
+			!log_special_ops
+		| _ -> true
+	in
+		if print 
+		then write_access_log ~tid ~con ~data (XbOp ty)
+
+let start_transaction ~tid ~con = 
+	if !log_transaction_ops && tid <> 0
+	then write_access_log ~tid ~con (XbOp Xb.Op.Transaction_start)
+
+let end_transaction ~tid ~con = 
+	if !log_transaction_ops && tid <> 0
+	then write_access_log ~tid ~con (XbOp Xb.Op.Transaction_end)
+
+let xb_answer ~tid ~con ~ty data =
+	let print = match ty with
+		| Xb.Op.Error when data="ENOENT " -> !log_read_ops
+		| Xb.Op.Error -> !log_special_ops
+		| Xb.Op.Watchevent -> true
+		| _ -> false
+	in
+		if print
+		then write_access_log ~tid ~con ~data (XbOp ty)
diff --git a/tools/ocaml/xenstored/parse_arg.ml b/tools/ocaml/xenstored/parse_arg.ml
new file mode 100644
index 0000000..5d21601
--- /dev/null
+++ b/tools/ocaml/xenstored/parse_arg.ml
@@ -0,0 +1,68 @@
+(*
+ * Copyright (C) 2006-2007 XenSource Ltd.
+ * Copyright (C) 2008      Citrix Ltd.
+ * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *)
+
+type config =
+{
+	domain_init: bool;
+	activate_access_log: bool;
+	daemonize: bool;
+	reraise_top_level: bool;
+	config_file: string option;
+	pidfile: string option; (* old xenstored compatibility *)
+	tracefile: string option; (* old xenstored compatibility *)
+	restart: bool;
+	disable_socket: bool;
+}
+
+let do_argv =
+	let pidfile = ref "" and tracefile = ref "" (* old xenstored compatibility *)
+	and domain_init = ref true
+	and activate_access_log = ref true
+	and daemonize = ref true
+	and reraise_top_level = ref false
+	and config_file = ref ""
+	and restart = ref false
+	and disable_socket = ref false in
+
+	let speclist =
+		[ ("--no-domain-init", Arg.Unit (fun () -> domain_init := false),
+		   "to state that xenstored should not initialise dom0");
+		  ("--config-file", Arg.Set_string config_file,
+		   "set an alternative location for the configuration file");
+		  ("--no-fork", Arg.Unit (fun () -> daemonize := false),
+		   "to request that the daemon does not fork");
+		  ("--reraise-top-level", Arg.Unit (fun () -> reraise_top_level := true),
+		   "reraise exceptions caught at the top level");
+		  ("--no-access-log", Arg.Unit (fun () -> activate_access_log := false),
+		  "do not create a xenstore-access.log file");
+		  ("--pid-file", Arg.Set_string pidfile, ""); (* for compatibility *)
+		  ("-T", Arg.Set_string tracefile, ""); (* for compatibility *)
+		  ("--restart", Arg.Set restart, "Read database on starting");
+		  ("--disable-socket", Arg.Unit (fun () -> disable_socket := true), "Disable socket");
+		] in
+	let usage_msg = "usage : xenstored [--config-file <filename>] [--no-domain-init] [--help] [--no-fork] [--reraise-top-level] [--restart] [--disable-socket]" in
+	Arg.parse speclist (fun s -> ()) usage_msg;
+	{
+		domain_init = !domain_init;
+		activate_access_log = !activate_access_log;
+		daemonize = !daemonize;
+		reraise_top_level = !reraise_top_level;
+		config_file = if !config_file <> "" then Some !config_file else None;
+		pidfile = if !pidfile <> "" then Some !pidfile else None;
+		tracefile = if !tracefile <> "" then Some !tracefile else None;
+		restart = !restart;
+		disable_socket = !disable_socket;
+	}
diff --git a/tools/ocaml/xenstored/perms.ml b/tools/ocaml/xenstored/perms.ml
new file mode 100644
index 0000000..99b48f3
--- /dev/null
+++ b/tools/ocaml/xenstored/perms.ml
@@ -0,0 +1,165 @@
+(*
+ * Copyright (C) 2006-2007 XenSource Ltd.
+ * Copyright (C) 2008      Citrix Ltd.
+ * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
+ * Author Thomas Gazagnaire <thomas.gazagnaire@eu.citrix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *)
+
+let activate = ref true
+
+type permty = READ | WRITE | RDWR | NONE
+
+let char_of_permty perm =
+	match perm with
+	| READ -> 'r'
+	| WRITE -> 'w'
+	| RDWR -> 'b'
+	| NONE -> 'n'
+
+let permty_of_char c =
+	match c with
+	| 'r' -> READ
+	| 'w' -> WRITE
+	| 'b' -> RDWR
+	| 'n' -> NONE
+	| _ -> invalid_arg "unknown permission type"
+
+
+(* node permissions *)
+module Node =
+struct
+
+type t =
+{
+	owner: Xc.domid;
+	other: permty;
+	acl: (Xc.domid * permty) list;
+}
+
+let create owner other acl =
+	{ owner = owner; other = other; acl = acl }
+
+let get_other perms = perms.other
+let get_acl perms = perms.acl
+let get_owner perm = perm.owner
+
+let default0 = create 0 NONE []
+
+let perm_of_string s =
+	let ty = permty_of_char s.[0]
+	and id = int_of_string (String.sub s 1 (String.length s - 1)) in
+	(id, ty)
+
+let of_strings ls =
+	let vect = List.map (perm_of_string) ls in
+	match vect with
+	| [] -> invalid_arg "permvec empty"
+	| h :: l -> create (fst h) (snd h) l
+
+(* [s] must end with '\000' *)
+let of_string s =
+	let ls = Stringext.String.split '\000' s in
+	let ls = if ls = [] then ls else List.rev (List.tl (List.rev ls)) in
+	of_strings ls
+
+let string_of_perm perm =
+	Printf.sprintf "%c%u" (char_of_permty (snd perm)) (fst perm)
+
+let to_string permvec =
+	let l = ((permvec.owner, permvec.other) :: permvec.acl) in
+	String.concat "\000" (List.map string_of_perm l)
+
+end
+
+
+(* permission of connections *)
+module Connection =
+struct
+
+type elt = Xc.domid * (permty list)
+type t =
+	{ main: elt;
+	  target: elt option; }
+
+let full_rights : t =
+	{ main = 0, [READ; WRITE];
+	  target = None }
+
+let create ?(perms=[NONE]) domid : t =
+	{ main = (domid, perms);
+	  target = None }
+
+let set_target (connection:t) ?(perms=[NONE]) domid =
+	{ connection with target = Some (domid, perms) }
+
+let get_owners (connection:t) =
+	match connection.main, connection.target with
+	| c1, Some c2 -> [ fst c1; fst c2 ]
+	| c1, None    -> [ fst c1 ]
+
+let is_owner (connection:t) id =
+	match connection.target with
+	| Some target -> fst connection.main = id || fst target = id
+	| None        -> fst connection.main = id
+
+let is_dom0 (connection:t) =
+	is_owner connection 0
+
+let restrict (connection:t) domid =
+	match connection.target, connection.main with
+	| None, (0, perms) -> { connection with main = (domid, perms) }
+	| _                -> raise Define.Permission_denied
+
+let elt_to_string (i,p) =
+	Printf.sprintf "%i%S" i (String.concat "" (List.map Stringext.String.of_char (List.map char_of_permty p)))
+
+let to_string connection =
+	Printf.sprintf "%s%s" (elt_to_string connection.main) (Pervasiveext.default "" (Pervasiveext.may elt_to_string connection.target))
+end
+
+(* check if owner of the current connection and of the current node are the same *)
+let check_owner (connection:Connection.t) (node:Node.t) =
+	if !activate && not (Connection.is_dom0 connection)
+	then Connection.is_owner connection (Node.get_owner node)
+	else true
+
+(* check if the current connection has the requested perm on the current node *)
+let check (connection:Connection.t) request (node:Node.t) =
+	let check_acl domainid =
+		let perm =
+			if List.mem_assoc domainid (Node.get_acl node)
+			then List.assoc domainid (Node.get_acl node)
+			else Node.get_other node
+		in
+		match perm, request with
+		| NONE, _ ->
+			Logs.info "io" "Permission denied: Domain %d has no permission" domainid;
+			false
+		| RDWR, _ -> true
+		| READ, READ -> true
+		| WRITE, WRITE -> true
+		| READ, _ ->
+			Logs.info "io" "Permission denied: Domain %d has read only access" domainid;
+			false
+		| WRITE, _ ->
+			Logs.info "io" "Permission denied: Domain %d has write only access" domainid;
+			false
+	in
+	if !activate
+	&& not (Connection.is_dom0 connection)
+	&& not (check_owner connection node)
+	&& not (List.exists check_acl (Connection.get_owners connection))
+	then raise Define.Permission_denied
+
+let equiv perm1 perm2 =
+	(Node.to_string perm1) = (Node.to_string perm2)
diff --git a/tools/ocaml/xenstored/process.ml b/tools/ocaml/xenstored/process.ml
new file mode 100644
index 0000000..bc4a2dd
--- /dev/null
+++ b/tools/ocaml/xenstored/process.ml
@@ -0,0 +1,395 @@
+(*
+ * Copyright (C) 2006-2007 XenSource Ltd.
+ * Copyright (C) 2008      Citrix Ltd.
+ * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *)
+
+open Printf
+
+exception Transaction_again
+exception Transaction_nested
+exception Domain_not_match
+exception Invalid_Cmd_Args
+
+let allow_debug = ref false
+
+let c_int_of_string s =
+	let v = ref 0 in
+	let is_digit c = c >= '0' && c <= '9' in
+	let len = String.length s in
+	let i = ref 0 in
+	while !i < len && not (is_digit s.[!i]) do incr i done;
+	while !i < len && is_digit s.[!i]
+	do
+		let x = (Char.code s.[!i]) - (Char.code '0') in
+		v := !v * 10 + x;
+		incr i
+	done;
+	!v
+
+(* when we don't want a limit, apply a max limit of 8 arguments.
+   no arguments take more than 3 currently, which is pointless to split
+   more than needed. *)
+let split limit c s =
+	let limit = match limit with None -> 8 | Some x -> x in
+	Stringext.String.split ~limit c s
+
+let split_one_path data con =
+	let args = split (Some 2) '\000' data in
+	match args with
+	| path :: "" :: [] -> Store.Path.create path (Connection.get_path con)
+	| _                -> raise Invalid_Cmd_Args
+
+let process_watch ops cons =
+	let do_op_watch op cons =
+		let recurse = match (fst op) with
+		| Xb.Op.Write    -> false
+		| Xb.Op.Mkdir    -> false
+		| Xb.Op.Rm       -> true
+		| Xb.Op.Setperms -> false
+		| _              -> raise (Failure "huh ?") in
+		Connections.fire_watches cons (snd op) recurse in
+	List.iter (fun op -> do_op_watch op cons) ops
+
+let create_implicit_path t perm path =
+	let dirname = Store.Path.get_parent path in
+	if not (Transaction.path_exists t dirname) then (
+		let rec check_path p =
+			match p with
+			| []      -> []
+			| h :: l  ->
+				if Transaction.path_exists t h then
+					check_path l
+				else
+					p in
+		let ret = check_path (List.tl (Store.Path.get_hierarchy dirname)) in
+		List.iter (fun s -> Transaction.mkdir ~with_watch:false t perm s) ret
+	)
+
+(* packets *)
+let do_debug con t domains cons data =
+	if not !allow_debug
+	then None
+	else try match split None '\000' data with
+	| "print" :: msg :: _ ->
+		Logging.xb_op ~tid:0 ~ty:Xb.Op.Debug ~con:"=======>" msg;
+		None
+	| "quota" :: domid :: _ ->
+		let domid = int_of_string domid in
+		let quota = (Store.get_quota t.Transaction.store) in
+		Some (Quota.to_string quota domid ^ "\000")
+	| "mfn" :: domid :: _ ->
+		let domid = int_of_string domid in
+		let con = Connections.find_domain cons domid in
+		Pervasiveext.may (fun dom -> Printf.sprintf "%nd\000" (Domain.get_mfn dom)) (Connection.get_domain con)
+	| _ -> None
+	with _ -> None
+
+let do_directory con t domains cons data =
+	let path = split_one_path data con in
+	let entries = Transaction.ls t (Connection.get_perm con) path in
+	if List.length entries > 0 then
+		(Utils.join_by_null entries) ^ "\000"
+	else
+		""
+
+let do_read con t domains cons data =
+	let path = split_one_path data con in
+	Transaction.read t (Connection.get_perm con) path
+
+let do_getperms con t domains cons data =
+	let path = split_one_path data con in
+	let perms = Transaction.getperms t (Connection.get_perm con) path in
+	Perms.Node.to_string perms ^ "\000"
+
+let do_watch con t rid domains cons data =
+	let (node, token) = 
+		match (split None '\000' data) with
+		| [node; token; ""]   -> node, token
+		| _                   -> raise Invalid_Cmd_Args
+		in
+	let watch = Connections.add_watch cons con node token in
+	Connection.send_ack con (Transaction.get_id t) rid Xb.Op.Watch;
+	Connection.fire_single_watch watch
+
+let do_unwatch con t domains cons data =
+	let (node, token) =
+		match (split None '\000' data) with
+		| [node; token; ""]   -> node, token
+		| _                   -> raise Invalid_Cmd_Args
+		in
+	Connections.del_watch cons con node token
+
+let do_transaction_start con t domains cons data =
+	if Transaction.get_id t <> Transaction.none then
+		raise Transaction_nested;
+	let store = Transaction.get_store t in
+	string_of_int (Connection.start_transaction con store) ^ "\000"
+
+let do_transaction_end con t domains cons data =
+	let commit =
+		match (split None '\000' data) with
+		| "T" :: _ -> true
+		| "F" :: _ -> false
+		| x :: _   -> raise (Invalid_argument x)
+		| _        -> raise Invalid_Cmd_Args
+		in
+	let success =
+		Connection.end_transaction con (Transaction.get_id t) commit in
+	if not success then
+		raise Transaction_again;
+	if commit then
+		process_watch (List.rev (Transaction.get_ops t)) cons
+
+let do_introduce con t domains cons data =
+	if not (Connection.is_dom0 con)
+	then raise Define.Permission_denied;
+	let (domid, mfn, port) =
+		match (split None '\000' data) with
+		| domid :: mfn :: port :: _ ->
+			int_of_string domid, Nativeint.of_string mfn, int_of_string port
+		| _                         -> raise Invalid_Cmd_Args;
+		in
+	let dom =
+		if Domains.exist domains domid then
+			Domains.find domains domid
+		else try
+			let ndom = Xc.with_intf (fun xc ->
+				Domains.create xc domains domid mfn port) in
+			Connections.add_domain cons ndom;
+			Connections.fire_spec_watches cons "@introduceDomain";
+			ndom
+		with _ -> raise Invalid_Cmd_Args
+	in
+	if (Domain.get_remote_port dom) <> port || (Domain.get_mfn dom) <> mfn then
+		raise Domain_not_match
+
+let do_release con t domains cons data =
+	if not (Connection.is_dom0 con)
+	then raise Define.Permission_denied;
+	let domid =
+		match (split None '\000' data) with
+		| [domid;""] -> int_of_string domid
+		| _          -> raise Invalid_Cmd_Args
+		in
+	let fire_spec_watches = Domains.exist domains domid in
+	Domains.del domains domid;
+	Connections.del_domain cons domid;
+	if fire_spec_watches 
+	then Connections.fire_spec_watches cons "@releaseDomain"
+	else raise Invalid_Cmd_Args
+
+let do_resume con t domains cons data =
+	if not (Connection.is_dom0 con)
+	then raise Define.Permission_denied;
+	let domid =
+		match (split None '\000' data) with
+		| domid :: _ -> int_of_string domid
+		| _          -> raise Invalid_Cmd_Args
+		in
+	if Domains.exist domains domid
+	then Domains.resume domains domid
+	else raise Invalid_Cmd_Args
+
+let do_getdomainpath con t domains cons data =
+	let domid =
+		match (split None '\000' data) with
+		| domid :: "" :: [] -> c_int_of_string domid
+		| _                 -> raise Invalid_Cmd_Args
+		in
+	sprintf "/local/domain/%u\000" domid
+
+let do_write con t domains cons data =
+	let path, value =
+		match (split (Some 2) '\000' data) with
+		| path :: value :: [] -> Store.Path.create path (Connection.get_path con), value
+		| _                   -> raise Invalid_Cmd_Args
+		in
+	create_implicit_path t (Connection.get_perm con) path;
+	Transaction.write t (Connection.get_perm con) path value
+
+let do_mkdir con t domains cons data =
+	let path = split_one_path data con in
+	create_implicit_path t (Connection.get_perm con) path;
+	try
+		Transaction.mkdir t (Connection.get_perm con) path
+	with
+		Define.Already_exist -> ()
+
+let do_rm con t domains cons data =
+	let path = split_one_path data con in
+	try
+		Transaction.rm t (Connection.get_perm con) path
+	with
+		Define.Doesnt_exist -> ()
+
+let do_setperms con t domains cons data =
+	let path, perms =
+		match (split (Some 2) '\000' data) with
+		| path :: perms :: _ ->
+			Store.Path.create path (Connection.get_path con),
+			(Perms.Node.of_string perms)
+		| _                   -> raise Invalid_Cmd_Args
+		in
+	Transaction.setperms t (Connection.get_perm con) path perms
+
+let do_error con t domains cons data =
+	raise Define.Unknown_operation
+
+let do_isintroduced con t domains cons data =
+	let domid =
+		match (split None '\000' data) with
+		| domid :: _ -> int_of_string domid
+		| _          -> raise Invalid_Cmd_Args
+		in
+	if domid = Define.domid_self || Domains.exist domains domid then "T\000" else "F\000"
+
+(* [restrict] is in the patch queue since xen3.2 *)
+let do_restrict con t domains cons data =
+	if not (Connection.is_dom0 con)
+	then raise Define.Permission_denied;
+	let domid =
+		match (split None '\000' data) with
+		| [ domid; "" ] -> c_int_of_string domid
+		| _          -> raise Invalid_Cmd_Args
+	in
+	Connection.restrict con domid
+
+(* only in >= xen3.3                                                                                    *)
+(* we ensure backward compatibility with restrict by counting the number of argument of set_target ...  *)
+(* This is not very elegant, but it is safe as 'restrict' only restricts permission of dom0 connections *)
+let do_set_target con t domains cons data =
+	if not (Connection.is_dom0 con)
+	then raise Define.Permission_denied;
+	match split None '\000' data with
+		| [ domid; "" ]               -> do_restrict con t domains con data (* backward compatibility with xen3.2-pq *)
+		| [ domid; target_domid; "" ] -> Connections.set_target cons (c_int_of_string domid) (c_int_of_string target_domid)
+		| _                           -> raise Invalid_Cmd_Args
+
+(*------------- Generic handling of ty ------------------*)
+let reply_ack fct ty con t rid doms cons data =
+	fct con t doms cons data;
+	Connection.send_ack con (Transaction.get_id t) rid ty;
+	if Transaction.get_id t = Transaction.none then
+		process_watch (Transaction.get_ops t) cons
+
+let reply_data fct ty con t rid doms cons data =
+	let ret = fct con t doms cons data in
+	Connection.send_reply con (Transaction.get_id t) rid ty ret
+
+let reply_data_or_ack fct ty con t rid doms cons data =
+	match fct con t doms cons data with
+		| Some ret -> Connection.send_reply con (Transaction.get_id t) rid ty ret
+		| None -> Connection.send_ack con (Transaction.get_id t) rid ty
+
+let reply_none fct ty con t rid doms cons data =
+	(* let the function reply *)
+	fct con t rid doms cons data
+
+let function_of_type ty =
+	match ty with
+	| Xb.Op.Debug             -> reply_data_or_ack do_debug
+	| Xb.Op.Directory         -> reply_data do_directory
+	| Xb.Op.Read              -> reply_data do_read
+	| Xb.Op.Getperms          -> reply_data do_getperms
+	| Xb.Op.Watch             -> reply_none do_watch
+	| Xb.Op.Unwatch           -> reply_ack do_unwatch
+	| Xb.Op.Transaction_start -> reply_data do_transaction_start
+	| Xb.Op.Transaction_end   -> reply_ack do_transaction_end
+	| Xb.Op.Introduce         -> reply_ack do_introduce
+	| Xb.Op.Release           -> reply_ack do_release
+	| Xb.Op.Getdomainpath     -> reply_data do_getdomainpath
+	| Xb.Op.Write             -> reply_ack do_write
+	| Xb.Op.Mkdir             -> reply_ack do_mkdir
+	| Xb.Op.Rm                -> reply_ack do_rm
+	| Xb.Op.Setperms          -> reply_ack do_setperms
+	| Xb.Op.Isintroduced      -> reply_data do_isintroduced
+	| Xb.Op.Resume            -> reply_ack do_resume
+	| Xb.Op.Set_target        -> reply_ack do_set_target
+	| Xb.Op.Restrict          -> reply_ack do_restrict
+	| _                       -> reply_ack do_error
+
+let input_handle_error ~cons ~doms ~fct ~ty ~con ~t ~rid ~data =
+	let reply_error e =
+		Connection.send_error con (Transaction.get_id t) rid e in
+	try
+		fct ty con t rid doms cons data
+	with
+	| Define.Invalid_path          -> reply_error "EINVAL"
+	| Define.Already_exist         -> reply_error "EEXIST"
+	| Define.Doesnt_exist          -> reply_error "ENOENT"
+	| Define.Lookup_Doesnt_exist s -> reply_error "ENOENT"
+	| Define.Permission_denied     -> reply_error "EACCES"
+	| Not_found                    -> reply_error "ENOENT"
+	| Invalid_Cmd_Args             -> reply_error "EINVAL"
+	| Invalid_argument i           -> reply_error "EINVAL"
+	| Transaction_again            -> reply_error "EAGAIN"
+	| Transaction_nested           -> reply_error "EBUSY"
+	| Domain_not_match             -> reply_error "EINVAL"
+	| Quota.Limit_reached          -> reply_error "EQUOTA"
+	| Quota.Data_too_big           -> reply_error "E2BIG"
+	| Quota.Transaction_opened     -> reply_error "EQUOTA"
+	| (Failure "int_of_string")    -> reply_error "EINVAL"
+	| Define.Unknown_operation     -> reply_error "ENOSYS"
+
+(**
+ * Nothrow guarantee.
+ *)
+let process_packet ~store ~cons ~doms ~con ~tid ~rid ~ty ~data =
+	try
+		let fct = function_of_type ty in
+		let t =
+			if tid = Transaction.none then
+				Transaction.make tid store
+			else
+				Connection.get_transaction con tid
+			in
+		input_handle_error ~cons ~doms ~fct ~ty ~con ~t ~rid ~data;
+	with exn ->
+		Logs.error "general" "process packet: %s"
+		          (Printexc.to_string exn);
+		Connection.send_error con tid rid "EIO"
+
+let write_access_log ~ty ~tid ~con ~data =
+	Logging.xb_op ~ty ~tid ~con:(Connection.get_domstr con) data
+
+let write_answer_log ~ty ~tid ~con ~data =
+	Logging.xb_answer ~ty ~tid ~con:(Connection.get_domstr con) data
+
+let do_input store cons doms con =
+	if Connection.do_input con then (
+		let packet = Connection.pop_in con in
+		let tid, rid, ty, data = Xb.Packet.unpack packet in
+		(* As we don't log IO, do not call an unnecessary sanitize_data 
+		   Logs.info "io" "[%s] -> [%d] %s \"%s\""
+		         (Connection.get_domstr con) tid
+		         (Xb.Op.to_string ty) (sanitize_data data); *)
+		process_packet ~store ~cons ~doms ~con ~tid ~rid ~ty ~data;
+		write_access_log ~ty ~tid ~con ~data;
+		Connection.incr_ops con;
+	)
+
+let do_output store cons doms con =
+	if Connection.has_output con then (
+		if Connection.has_new_output con then (
+			let packet = Connection.peek_output con in
+			let tid, rid, ty, data = Xb.Packet.unpack packet in
+			(* As we don't log IO, do not call an unnecessary sanitize_data 
+			   Logs.info "io" "[%s] <- %s \"%s\""
+			         (Connection.get_domstr con)
+			         (Xb.Op.to_string ty) (sanitize_data data);*)
+			write_answer_log ~ty ~tid ~con ~data;
+		);
+		ignore (Connection.do_output con)
+	)
+
diff --git a/tools/ocaml/xenstored/quota.ml b/tools/ocaml/xenstored/quota.ml
new file mode 100644
index 0000000..4091e40
--- /dev/null
+++ b/tools/ocaml/xenstored/quota.ml
@@ -0,0 +1,83 @@
+(*
+ * Copyright (C) 2006-2007 XenSource Ltd.
+ * Copyright (C) 2008      Citrix Ltd.
+ * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *)
+
+exception Limit_reached
+exception Data_too_big
+exception Transaction_opened
+
+let warn fmt = Logs.warn "general" fmt
+let activate = ref true
+let maxent = ref (10000)
+let maxsize = ref (4096)
+
+type t = {
+	maxent: int;               (* max entities per domU *)
+	maxsize: int;              (* max size of data store in one node *)
+	cur: (Xc.domid, int) Hashtbl.t; (* current domains quota *)
+}
+
+let to_string quota domid =
+	if Hashtbl.mem quota.cur domid
+	then Printf.sprintf "dom%i quota: %i/%i" domid (Hashtbl.find quota.cur domid) quota.maxent
+	else Printf.sprintf "dom%i quota: not set" domid
+
+let create () =
+	{ maxent = !maxent; maxsize = !maxsize; cur = Hashtbl.create 100; }
+
+let copy quota = { quota with cur = (Hashtbl.copy quota.cur) }
+
+let del quota id = Hashtbl.remove quota.cur id
+
+let _check quota id size =
+	if size > quota.maxsize then (
+		warn "domain %u err create entry: data too big %d" id size;
+		raise Data_too_big
+	);
+	if id > 0 && Hashtbl.mem quota.cur id then
+		let entry = Hashtbl.find quota.cur id in
+		if entry >= quota.maxent then (
+			warn "domain %u cannot create entry: quota reached" id;
+			raise Limit_reached
+		)
+
+let check quota id size =
+	if !activate then
+		_check quota id size
+
+let get_entry quota id = Hashtbl.find quota.cur id
+
+let set_entry quota id nb =
+	if nb = 0
+	then Hashtbl.remove quota.cur id
+	else begin
+	if Hashtbl.mem quota.cur id then
+		Hashtbl.replace quota.cur id nb
+	else
+		Hashtbl.add quota.cur id nb
+	end
+
+let del_entry quota id =
+	try
+		let nb = get_entry quota id in
+		set_entry quota id (nb - 1)
+	with Not_found -> ()
+
+let add_entry quota id =
+	let nb = try get_entry quota id with Not_found -> 0 in
+	set_entry quota id (nb + 1)
+
+let add quota diff =
+	Hashtbl.iter (fun id nb -> set_entry quota id (get_entry quota id + nb)) diff.cur
diff --git a/tools/ocaml/xenstored/store.ml b/tools/ocaml/xenstored/store.ml
new file mode 100644
index 0000000..857f51e
--- /dev/null
+++ b/tools/ocaml/xenstored/store.ml
@@ -0,0 +1,460 @@
+(*
+ * Copyright (C) 2006-2007 XenSource Ltd.
+ * Copyright (C) 2008      Citrix Ltd.
+ * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
+ * Author Thomas Gazagnaire <thomas.gazagnaire@eu.citrix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *)
+
+module Node = struct
+
+type t = {
+	name: Symbol.t;
+	perms: Perms.Node.t;
+	value: string;
+	children: t list;
+}
+
+let create _name _perms _value =
+	{ name = Symbol.of_string _name; perms = _perms; value = _value; children = []; }
+
+let get_owner node = Perms.Node.get_owner node.perms
+let get_children node = node.children
+let get_value node = node.value
+let get_perms node = node.perms
+let get_name node = Symbol.to_string node.name
+
+let set_value node nvalue = 
+	if node.value = nvalue
+	then node
+	else { node with value = nvalue }
+
+let set_perms node nperms = { node with perms = nperms }
+
+let add_child node child =
+	{ node with children = child :: node.children }
+
+let exists node childname =
+	let childname = Symbol.of_string childname in
+	List.exists (fun n -> n.name = childname) node.children
+
+let find node childname =
+	let childname = Symbol.of_string childname in
+	List.find (fun n -> n.name = childname) node.children
+
+let replace_child node child nchild =
+	(* this is the on-steroid version of the filter one-replace one *)
+	let rec replace_one_in_list l =
+		match l with
+		| []                               -> []
+		| h :: tl when h.name = child.name -> nchild :: tl
+		| h :: tl                          -> h :: replace_one_in_list tl
+		in
+	{ node with children = (replace_one_in_list node.children) }
+
+let del_childname node childname =
+	let sym = Symbol.of_string childname in
+	let rec delete_one_in_list l =
+		match l with
+		| []                        -> raise Not_found
+		| h :: tl when h.name = sym -> tl
+		| h :: tl                   -> h :: delete_one_in_list tl
+		in
+	{ node with children = (delete_one_in_list node.children) }
+
+let del_all_children node =
+	{ node with children = [] }
+
+(* check if the current node can be accessed by the current connection with rperm permissions *)
+let check_perm node connection request =
+	Perms.check connection request node.perms
+
+(* check if the current node is owned by the current connection *)
+let check_owner node connection =
+	if not (Perms.check_owner connection node.perms)
+	then begin
+		Logs.info "io" "Permission denied: Domain %d not owner" (get_owner node);
+		raise Define.Permission_denied;
+	end
+
+let rec recurse fct node = fct node; List.iter (recurse fct) node.children
+
+let unpack node = (Symbol.to_string node.name, node.perms, node.value)
+
+end
+
+module Path = struct
+
+(* represent a path in a store.
+ * [] -> "/"
+ * [ "local"; "domain"; "1" ] -> "/local/domain/1"
+ *)
+type t = string list
+
+let char_is_valid c =
+	(c >= 'a' && c <= 'z') ||
+	(c >= 'A' && c <= 'Z') ||
+	(c >= '0' && c <= '9') ||
+	c = '_' || c = '-' || c = '@'
+
+let name_is_valid name =
+	name <> "" && Stringext.String.fold_left (fun accu c -> accu && char_is_valid c) true name
+
+let is_valid path =
+	List.for_all name_is_valid path
+
+let of_string s =
+	if s.[0] = '@'
+	then [s]
+	else if s = "/"
+	then []
+	else match Stringext.String.split '/' s with
+		| "" :: path when is_valid path -> path
+		| _ -> raise Define.Invalid_path
+
+let create path connection_path =
+	of_string (Utils.path_validate path connection_path)
+
+let to_string t =
+	"/" ^ (String.concat "/" t)
+
+let to_string_list x = x
+
+let get_parent t =
+	if t = [] then [] else List.rev (List.tl (List.rev t))
+
+let get_hierarchy path =
+	Utils.get_hierarchy path
+
+let get_common_prefix p1 p2 =
+	let rec compare l1 l2 =
+		match l1, l2 with
+		| h1 :: tl1, h2 :: tl2 ->
+			if h1 = h2 then h1 :: (compare tl1 tl2) else []
+		| _, [] | [], _ ->
+			(* if l1 or l2 is empty, we found the equal part already *)
+			[]
+		in
+	compare p1 p2
+
+let rec lookup_modify node path fct =
+	match path with
+	| []      -> raise (Define.Invalid_path)
+	| h :: [] -> fct node h
+	| h :: l  ->
+		let (n, c) =
+			if not (Node.exists node h) then
+				raise (Define.Lookup_Doesnt_exist h)
+			else
+				(node, Node.find node h) in
+		let nc = lookup_modify c l fct in
+		Node.replace_child n c nc
+
+let apply_modify rnode path fct =
+	lookup_modify rnode path fct
+
+let rec lookup_get node path =
+	match path with
+	| []      -> raise (Define.Invalid_path)
+	| h :: [] ->
+		(try
+			Node.find node h
+		with Not_found ->
+			raise Define.Doesnt_exist)
+	| h :: l  -> let cnode = Node.find node h in lookup_get cnode l
+
+let get_node rnode path =
+	if path = [] then
+		Some rnode
+	else (
+		try Some (lookup_get rnode path) with Define.Doesnt_exist -> None
+	)
+
+(* get the deepest existing node for this path *)
+let rec get_deepest_existing_node node = function
+	| [] -> node
+	| h :: t ->
+		try get_deepest_existing_node (Node.find node h) t 
+		with Not_found -> node
+
+let set_node rnode path nnode =
+	let quota = Quota.create () in
+	if !Quota.activate then Node.recurse (fun node -> Quota.add_entry quota (Node.get_owner node)) nnode;
+	if path = [] then
+		nnode, quota
+	else
+		let set_node node name =
+			try
+				let ent = Node.find node name in
+				if !Quota.activate then Node.recurse (fun node -> Quota.del_entry quota (Node.get_owner node)) ent;
+				Node.replace_child node ent nnode
+			with Not_found ->
+				Node.add_child node nnode
+			in
+		apply_modify rnode path set_node, quota
+
+(* read | ls | getperms use this *)
+let rec lookup node path fct =
+	match path with
+	| []      -> raise (Define.Invalid_path)
+	| h :: [] -> fct node h
+	| h :: l  -> let cnode = Node.find node h in lookup cnode l fct
+
+let apply rnode path fct =
+	lookup rnode path fct
+end
+
+type t =
+{
+	mutable stat_transaction_coalesce: int;
+	mutable stat_transaction_abort: int;
+	mutable root: Node.t;
+	mutable quota: Quota.t;
+}
+
+let get_root store = store.root
+let set_root store root = store.root <- root
+
+let get_quota store = store.quota
+let set_quota store quota = store.quota <- quota
+
+(* modifying functions *)
+let path_mkdir store perm path =
+	let do_mkdir node name =
+		try
+			let ent = Node.find node name in
+			Node.check_perm ent perm Perms.WRITE;
+			raise Define.Already_exist
+		with Not_found ->
+			Node.check_perm node perm Perms.WRITE;
+			Node.add_child node (Node.create name node.Node.perms "") in
+	if path = [] then
+		store.root
+	else
+		Path.apply_modify store.root path do_mkdir
+
+let path_write store perm path value =
+	let node_created = ref false in
+	let do_write node name =
+		try
+			let ent = Node.find node name in
+			Node.check_perm ent perm Perms.WRITE;
+			let nent = Node.set_value ent value in
+			Node.replace_child node ent nent
+		with Not_found ->
+			node_created := true;
+			Node.check_perm node perm Perms.WRITE;
+			Node.add_child node (Node.create name node.Node.perms value) in
+	if path = [] then (
+		Node.check_perm store.root perm Perms.WRITE;
+		Node.set_value store.root value, false
+	) else
+		Path.apply_modify store.root path do_write, !node_created
+
+let path_rm store perm path =
+	let do_rm node name =
+		try
+			let ent = Node.find node name in
+			Node.check_perm ent perm Perms.WRITE;
+			Node.del_childname node name
+		with Not_found ->
+			raise Define.Doesnt_exist in
+	if path = [] then
+		Node.del_all_children store.root
+	else
+		Path.apply_modify store.root path do_rm
+
+let path_setperms store perm path perms =
+	if path = [] then
+		Node.set_perms store.root perms
+	else
+		let do_setperms node name =
+			let c = Node.find node name in
+			Node.check_owner c perm;
+			Node.check_perm c perm Perms.WRITE;
+			let nc = Node.set_perms c perms in
+			Node.replace_child node c nc
+		in
+		Path.apply_modify store.root path do_setperms
+
+(* accessing functions *)
+let get_node store path =
+	Path.get_node store.root path
+
+let get_deepest_existing_node store path =
+	Path.get_deepest_existing_node store.root path
+
+let read store perm path =
+	let do_read node name =
+		let ent = Node.find node name in
+		Node.check_perm ent perm Perms.READ;
+		ent.Node.value
+	in
+	Path.apply store.root path do_read
+
+let ls store perm path =
+	let children =
+		if path = [] then
+			(Node.get_children store.root)
+		else
+			let do_ls node name =
+				let cnode = Node.find node name in
+				Node.check_perm cnode perm Perms.READ;
+				cnode.Node.children in
+			Path.apply store.root path do_ls in
+	List.rev (List.map (fun n -> Symbol.to_string n.Node.name) children)
+
+let getperms store perm path =
+	if path = [] then
+		(Node.get_perms store.root)
+	else
+		let fct n name =
+			let c = Node.find n name in
+			Node.check_perm c perm Perms.READ;
+			c.Node.perms in
+		Path.apply store.root path fct
+
+let path_exists store path =
+	if path = [] then
+		true
+	else
+		try
+			let check_exist node name =
+				ignore(Node.find node name);
+				true in
+			Path.apply store.root path check_exist
+		with Not_found -> false
+
+
+(* others utils *)
+let traversal root_node f =
+	let rec _traversal path node =
+		f path node;
+		List.iter (_traversal (path @ [ Symbol.to_string node.Node.name ])) node.Node.children
+		in
+	_traversal [] root_node
+		
+let dump_store_buf root_node =
+	let buf = Buffer.create 8192 in
+	let dump_node path node =
+		let pathstr = String.concat "/" path in
+		Printf.bprintf buf "%s/%s{%s}" pathstr (Symbol.to_string node.Node.name)
+		               (String.escaped (Perms.Node.to_string (Node.get_perms node)));
+		if String.length node.Node.value > 0 then
+			Printf.bprintf buf " = %s\n" (String.escaped node.Node.value)
+		else
+			Printf.bprintf buf "\n";
+		in
+	traversal root_node dump_node;
+	buf
+
+let dump_store chan root_node =
+	let buf = dump_store_buf root_node in
+	output_string chan (Buffer.contents buf);
+	Buffer.reset buf
+
+let dump_fct store f = traversal store.root f
+let dump store out_chan = dump_store out_chan store.root
+let dump_stdout store = dump_store stdout store.root
+let dump_buffer store = dump_store_buf store.root
+
+
+(* modifying functions with quota udpate *)
+let set_node store path node =
+	let root, quota_diff = Path.set_node store.root path node in
+	store.root <- root;
+	Quota.add store.quota quota_diff
+
+let write store perm path value =
+	let owner = Node.get_owner (get_deepest_existing_node store path) in
+	Quota.check store.quota owner (String.length value);
+	let root, node_created = path_write store perm path value in
+	store.root <- root;
+	if node_created
+	then Quota.add_entry store.quota owner
+
+let mkdir store perm path =
+	let owner = Node.get_owner (get_deepest_existing_node store path) in
+	Quota.check store.quota owner 0;
+	store.root <- path_mkdir store perm path;
+	Quota.add_entry store.quota owner
+
+let rm store perm path =
+	let rmed_node = Path.get_node store.root path in
+	match rmed_node with
+	| None -> raise Define.Doesnt_exist
+	| Some rmed_node ->
+		store.root <- path_rm store perm path;
+		Node.recurse (fun node -> Quota.del_entry store.quota (Node.get_owner node)) rmed_node
+
+let setperms store perm path nperms =
+	match Path.get_node store.root path with
+	| None -> raise Define.Doesnt_exist
+	| Some node ->
+		let old_owner = Node.get_owner node in
+		let new_owner = Perms.Node.get_owner nperms in
+		Quota.check store.quota new_owner 0;
+		store.root <- path_setperms store perm path nperms;
+		Quota.del_entry store.quota old_owner;
+		Quota.add_entry store.quota new_owner
+
+type ops = {
+	store: t;
+	write: Path.t -> string -> unit;
+	mkdir: Path.t -> unit;
+	rm: Path.t -> unit;
+	setperms: Path.t -> Perms.Node.t -> unit;
+	ls: Path.t -> string list;
+	read: Path.t -> string;
+	getperms: Path.t -> Perms.Node.t;
+	path_exists: Path.t -> bool;
+}
+
+let get_ops store perms = {
+	store = store;
+	write = write store perms;
+	mkdir = mkdir store perms;
+	rm = rm store perms;
+	setperms = setperms store perms;
+	ls = ls store perms;
+	read = read store perms;
+	getperms = getperms store perms;
+	path_exists = path_exists store;
+}
+
+let create () = {
+	stat_transaction_coalesce = 0;
+	stat_transaction_abort = 0;
+	root = Node.create "" Perms.Node.default0 "";
+	quota = Quota.create ();
+}
+let copy store = {
+	stat_transaction_coalesce = store.stat_transaction_coalesce;
+	stat_transaction_abort = store.stat_transaction_abort;
+	root = store.root;
+	quota = Quota.copy store.quota;
+}
+
+let mark_symbols store =
+	Node.recurse (fun node -> Symbol.mark_as_used node.Node.name) store.root
+
+let incr_transaction_coalesce store =
+	store.stat_transaction_coalesce <- store.stat_transaction_coalesce + 1
+let incr_transaction_abort store =
+	store.stat_transaction_abort <- store.stat_transaction_abort + 1
+
+let stats store =
+	let nb_nodes = ref 0 in
+	traversal store.root (fun path node ->
+		incr nb_nodes
+	);
+	!nb_nodes, store.stat_transaction_abort, store.stat_transaction_coalesce
diff --git a/tools/ocaml/xenstored/symbol.ml b/tools/ocaml/xenstored/symbol.ml
new file mode 100644
index 0000000..4420c6a
--- /dev/null
+++ b/tools/ocaml/xenstored/symbol.ml
@@ -0,0 +1,76 @@
+(*
+ * Copyright (C) 2006-2007 XenSource Ltd.
+ * Copyright (C) 2008      Citrix Ltd.
+ * Author Thomas Gazagnaire <thomas.gazagnaire@eu.citrix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *)
+
+type t = int
+
+type 'a record = { data: 'a; mutable garbage: bool }
+let int_string_tbl : (int,string record) Hashtbl.t = Hashtbl.create 1024
+let string_int_tbl : (string,int) Hashtbl.t = Hashtbl.create 1024
+
+let created_counter = ref 0
+let used_counter = ref 0
+
+let count = ref 0
+let rec fresh () =
+	if Hashtbl.mem int_string_tbl !count
+	then begin
+		incr count;
+		fresh ()
+	end else
+		!count
+
+let new_record v = { data=v; garbage=false }
+
+let of_string name =
+	if Hashtbl.mem string_int_tbl name
+	then begin
+		incr used_counter;
+		Hashtbl.find string_int_tbl name
+	end else begin
+		let i = fresh () in
+		incr created_counter;
+		Hashtbl.add string_int_tbl name i;
+		Hashtbl.add int_string_tbl i (new_record name);
+		i
+	end
+
+let to_string i =
+	(Hashtbl.find int_string_tbl i).data
+
+let mark_all_as_unused () =
+	Hashtbl.iter (fun _ v -> v.garbage <- true) int_string_tbl
+
+let mark_as_used symb =
+	let record1 = Hashtbl.find int_string_tbl symb in
+		record1.garbage <- false
+
+let garbage () =
+	let records = Hashtbl.fold (fun symb record accu ->
+		if record.garbage then (symb, record.data) :: accu else accu
+	) int_string_tbl [] in
+	let remove (int,string) =
+		Hashtbl.remove int_string_tbl int;
+		Hashtbl.remove string_int_tbl string
+	in
+	created_counter := 0;
+	used_counter := 0;
+	List.iter remove records
+
+let stats () =
+	Hashtbl.length string_int_tbl
+
+let created () = !created_counter
+let used () = !used_counter
diff --git a/tools/ocaml/xenstored/symbol.mli b/tools/ocaml/xenstored/symbol.mli
new file mode 100644
index 0000000..8ed709f
--- /dev/null
+++ b/tools/ocaml/xenstored/symbol.mli
@@ -0,0 +1,52 @@
+(*
+ * Copyright (C) 2006-2007 XenSource Ltd.
+ * Copyright (C) 2008      Citrix Ltd.
+ * Author Thomas Gazagnaire <thomas.gazagnaire@eu.citrix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *)
+
+(** Node names *)
+
+(** Xenstore nodes names are often the same, ie. "local", "domain", "device", ... so it is worth to 
+    manipulate them through the use of small identifiers that we call symbols. These symbols can be 
+    compared in constant time (as opposite to strings) and should help the ocaml GC. *)
+
+type t
+(** The type of symbols. *)
+
+val of_string : string -> t
+(** Convert a string into a symbol. *)
+
+val to_string : t -> string
+(** Convert a symbol into a string. *)
+
+(** {6 Garbage Collection} *)
+
+(** Symbols need to be regulary garbage collected. The following steps should be followed:
+-     mark all the knowns symbols as unused (with [mark_all_as_unused]);
+-     mark all the symbols really usefull as used (with [mark_as_used]); and
+-     finally, call [garbage] *)
+
+val mark_all_as_unused : unit -> unit
+val mark_as_used : t -> unit
+val garbage : unit -> unit
+
+(** {6 Statistics } *)
+
+val stats : unit -> int
+(** Get the number of used symbols. *)
+
+val created : unit -> int
+(** Returns the number of symbols created since the last GC. *)
+
+val used : unit -> int
+(** Returns the number of existing symbols used since the last GC *)
diff --git a/tools/ocaml/xenstored/transaction.ml b/tools/ocaml/xenstored/transaction.ml
new file mode 100644
index 0000000..bf1f6aa
--- /dev/null
+++ b/tools/ocaml/xenstored/transaction.ml
@@ -0,0 +1,197 @@
+(*
+ * Copyright (C) 2006-2007 XenSource Ltd.
+ * Copyright (C) 2008      Citrix Ltd.
+ * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
+ * Author Thomas Gazagnaire <thomas.gazagnaire@citrix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *)
+
+let none = 0
+let test_eagain = ref false
+let do_coalesce = ref true
+
+let check_parents_perms_identical root1 root2 path =
+	let hierarch = Store.Path.get_hierarchy path in
+	let permdiff = List.fold_left (fun acc path ->
+		let n1 = Store.Path.get_node root1 path
+		and n2 = Store.Path.get_node root2 path in
+		match n1, n2 with
+		| Some n1, Some n2 ->
+			not (Perms.equiv (Store.Node.get_perms n1) (Store.Node.get_perms n2)) || acc
+		| _ ->
+			true || acc
+	) false hierarch in
+	(not permdiff)
+
+let get_lowest path1 path2 =
+	match path2 with
+	| None       -> Some path1
+	| Some path2 -> Some (Store.Path.get_common_prefix path1 path2)
+
+let test_coalesce oldroot currentroot optpath =
+	match optpath with
+	| None      -> true
+	| Some path ->
+		let oldnode = Store.Path.get_node oldroot path
+		and currentnode = Store.Path.get_node currentroot path in
+		
+		match oldnode, currentnode with
+		| (Some oldnode), (Some currentnode) ->
+			if oldnode == currentnode then (
+				check_parents_perms_identical oldroot currentroot path
+			) else (
+				false
+			)
+		| None, None -> (
+			(* ok then it doesn't exists in the old version and the current version,
+			   just sneak it in as a child of the parent node if it exists, or else fail *)
+			let pnode = Store.Path.get_node currentroot (Store.Path.get_parent path) in
+			match pnode with
+			| None       -> false (* ok it doesn't exists, just bail out. *)
+			| Some pnode -> true
+			)
+		| _ ->
+			false
+
+let can_coalesce oldroot currentroot path =
+	if !do_coalesce then
+		try test_coalesce oldroot currentroot path with _ -> false
+	else
+		false
+
+type ty = No | Full of (int * Store.Node.t * Store.t)
+
+type t = {
+	ty: ty;
+	store: Store.t;
+	mutable ops: (Xb.Op.operation * Store.Path.t) list;
+	mutable read_lowpath: Store.Path.t option;
+	mutable write_lowpath: Store.Path.t option;
+}
+
+let make id store =
+	let ty = if id = none then No else Full(id, Store.get_root store, store) in
+	{
+		ty = ty;
+		store = if id = none then store else Store.copy store;
+		ops = [];
+		read_lowpath = None;
+		write_lowpath = None;
+	}
+
+let get_id t = match t.ty with No -> none | Full (id, _, _) -> id
+let get_store t = t.store
+let get_ops t = t.ops
+
+let add_wop t ty path = t.ops <- (ty, path) :: t.ops
+let set_read_lowpath t path = t.read_lowpath <- get_lowest path t.read_lowpath
+let set_write_lowpath t path = t.write_lowpath <- get_lowest path t.write_lowpath
+
+let path_exists t path = Store.path_exists t.store path
+
+let write t perm path value =
+	let path_exists = path_exists t path in
+	Store.write t.store perm path value;
+	if path_exists
+	then set_write_lowpath t path
+	else set_write_lowpath t (Store.Path.get_parent path);
+	add_wop t Xb.Op.Write path
+
+let mkdir ?(with_watch=true) t perm path =
+	Store.mkdir t.store perm path;
+	set_write_lowpath t path;
+	if with_watch then
+		add_wop t Xb.Op.Mkdir path
+
+let setperms t perm path perms =
+	Store.setperms t.store perm path perms;
+	set_write_lowpath t path;
+	add_wop t Xb.Op.Setperms path
+
+let rm t perm path =
+	Store.rm t.store perm path;
+	set_write_lowpath t (Store.Path.get_parent path);
+	add_wop t Xb.Op.Rm path
+
+let ls t perm path =	
+	let r = Store.ls t.store perm path in
+	set_read_lowpath t path;
+	r
+
+let read t perm path =
+	let r = Store.read t.store perm path in
+	set_read_lowpath t path;
+	r
+
+let getperms t perm path =
+	let r = Store.getperms t.store perm path in
+	set_read_lowpath t path;
+	r
+
+let commit ~con t =
+	let has_write_ops = List.length t.ops > 0 in
+	let has_coalesced = ref false in
+	let has_commited =
+	match t.ty with
+	| No                         -> true
+	| Full (id, oldroot, cstore) ->
+		let commit_partial oldroot cstore store =
+			(* get the lowest path of the query and verify that it hasn't
+			   been modified by others transactions. *)
+			if can_coalesce oldroot (Store.get_root cstore) t.read_lowpath
+			&& can_coalesce oldroot (Store.get_root cstore) t.write_lowpath then (
+				Pervasiveext.maybe (fun p ->
+					let n = Store.get_node store p in
+
+					(* it has to be in the store, otherwise it means bugs
+					   in the lowpath registration. we don't need to handle none. *)
+					Pervasiveext.maybe (fun n -> Store.set_node cstore p n) n;
+					Logging.write_coalesce ~tid:(get_id t) ~con (Store.Path.to_string p);
+				) t.write_lowpath;
+				Pervasiveext.maybe (fun p ->
+					Logging.read_coalesce ~tid:(get_id t) ~con (Store.Path.to_string p)
+					) t.read_lowpath;
+				has_coalesced := true;
+				Store.incr_transaction_coalesce cstore;
+				true
+			) else (
+				(* cannot do anything simple, just discard the queries,
+				   and the client need to redo it later *)
+				Store.incr_transaction_abort cstore;
+				false
+			)
+			in
+		let try_commit oldroot cstore store =
+			if oldroot == Store.get_root cstore then (
+				(* move the new root to the current store, if the oldroot
+				   has not been modified *)
+				if has_write_ops then (
+					Store.set_root cstore (Store.get_root store);
+					Store.set_quota cstore (Store.get_quota store)
+				);
+				true
+			) else
+				(* we try a partial commit if possible *)
+				commit_partial oldroot cstore store
+			in
+		if !test_eagain && Random.int 3 = 0 then
+			false
+		else
+			try_commit oldroot cstore t.store
+		in
+	if has_commited && has_write_ops then
+		Disk.write t.store;
+	if not has_commited 
+	then Logging.conflict ~tid:(get_id t) ~con
+	else if not !has_coalesced 
+	then Logging.commit ~tid:(get_id t) ~con;
+	has_commited
diff --git a/tools/ocaml/xenstored/utils.ml b/tools/ocaml/xenstored/utils.ml
new file mode 100644
index 0000000..115d617
--- /dev/null
+++ b/tools/ocaml/xenstored/utils.ml
@@ -0,0 +1,107 @@
+(*
+ * Copyright (C) 2006-2007 XenSource Ltd.
+ * Copyright (C) 2008      Citrix Ltd.
+ * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *)
+
+open Printf
+open Pervasiveext
+
+(* lists utils *)
+let filter_out filter l =
+	List.filter (fun x -> not (List.mem x filter)) l
+
+let filter_in filter l =
+	List.filter (fun x -> List.mem x filter) l
+
+let list_remove element l =
+	List.filter (fun e -> e != element) l
+
+let list_tl_multi n l =
+	let rec do_tl i x =
+		if i = 0 then x else do_tl (i - 1) (List.tl x)
+		in
+	do_tl n l
+
+(* string utils *)
+let get_hierarchy path =
+	let l = List.length path in
+	let revpath = List.rev path in
+	let rec sub i =
+		let x = List.rev (list_tl_multi (l - i) revpath) in
+		if i = l then [ x ] else x :: sub (i + 1)
+		in
+	sub 0
+
+let hexify s =
+	let hexseq_of_char c = sprintf "%02x" (Char.code c) in
+	let hs = String.create (String.length s * 2) in
+	for i = 0 to String.length s - 1
+	do
+		let seq = hexseq_of_char s.[i] in
+		hs.[i * 2] <- seq.[0];
+		hs.[i * 2 + 1] <- seq.[1];
+	done;
+	hs
+
+let unhexify hs =
+	let char_of_hexseq seq0 seq1 = Char.chr (int_of_string (sprintf "0x%c%c" seq0 seq1)) in
+	let s = String.create (String.length hs / 2) in
+	for i = 0 to String.length s - 1
+	do
+		s.[i] <- char_of_hexseq hs.[i * 2] hs.[i * 2 + 1]
+	done;
+	s
+
+let trim_path path =
+	try
+		let rindex = String.rindex path '/' in
+		String.sub path 0 rindex
+	with
+		Not_found -> ""
+
+let join_by_null ls = String.concat "\000" ls
+
+(* unix utils *)
+let create_unix_socket name =
+	Unixext.unlink_safe name;
+	Unixext.mkdir_rec (Filename.dirname name) 0o700;
+	let sockaddr = Unix.ADDR_UNIX(name) in
+	let sock = Unix.socket Unix.PF_UNIX Unix.SOCK_STREAM 0 in
+	Unix.bind sock sockaddr;
+	Unix.listen sock 1;
+	sock
+
+let read_file_single_integer filename =
+	let fd = Unix.openfile filename [ Unix.O_RDONLY ] 0o640 in
+	let buf = String.make 20 (char_of_int 0) in
+	let sz = Unix.read fd buf 0 20 in
+	Unix.close fd;
+	int_of_string (String.sub buf 0 sz)
+
+let path_complete path connection_path =
+	if String.get path 0 <> '/' then
+		connection_path ^ path
+	else
+		path
+
+let path_validate path connection_path =
+	if String.length path = 0 || String.length path > 1024 then
+		raise Define.Invalid_path
+	else
+		let cpath = path_complete path connection_path in
+		if String.get cpath 0 <> '/' then
+			raise Define.Invalid_path
+		else
+			cpath
+
diff --git a/tools/ocaml/xenstored/xenstored.conf b/tools/ocaml/xenstored/xenstored.conf
new file mode 100644
index 0000000..0e0e5fb
--- /dev/null
+++ b/tools/ocaml/xenstored/xenstored.conf
@@ -0,0 +1,30 @@
+# default xenstored config
+
+# Where the pid file is stored
+pid-file = /var/run/xensource/xenstored.pid
+
+# Randomly failed a transaction with EAGAIN. Used for testing Xs user
+test-eagain = true
+
+# Activate transaction merge support
+merge-activate = true
+
+# Activate node permission system
+perms-activate = true
+
+# Activate quota
+quota-activate = true
+quota-maxentity = 1000
+quota-maxsize = 2048
+quota-maxwatch = 100
+quota-transaction = 10
+
+# Activate filed base backend
+persistant = false
+
+# Logs
+log = error;general;file:/var/log/xenstored.log
+log = warn;general;file:/var/log/xenstored.log
+log = info;general;file:/var/log/xenstored.log
+
+# log = debug;io;file:/var/log/xenstored-io.log
diff --git a/tools/ocaml/xenstored/xenstored.ml b/tools/ocaml/xenstored/xenstored.ml
new file mode 100644
index 0000000..36e01ad
--- /dev/null
+++ b/tools/ocaml/xenstored/xenstored.ml
@@ -0,0 +1,404 @@
+(*
+ * Copyright (C) 2006-2007 XenSource Ltd.
+ * Copyright (C) 2008      Citrix Ltd.
+ * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
+ * Author Thomas Gazagnaire <thomas.gazagnaire@eu.citrix.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *)
+
+open Printf
+open Parse_arg
+open Pervasiveext
+open Logging
+
+(*------------ event klass processors --------------*)
+let process_connection_fds store cons domains rset wset =
+	let try_fct fct c =
+		try
+			fct store cons domains c
+		with
+		| Unix.Unix_error(err, "write", _) ->
+			Connections.del_anonymous cons c;
+			error "closing socket connection: write error: %s"
+			      (Unix.error_message err)
+		| Unix.Unix_error(err, "read", _) ->
+			Connections.del_anonymous cons c;
+			if err <> Unix.ECONNRESET then
+			error "closing socket connection: read error: %s"
+			      (Unix.error_message err)
+		| Xb.End_of_file ->
+			Connections.del_anonymous cons c;
+			debug "closing socket connection"
+		in
+	let process_fdset_with fds fct =
+		List.iter (fun fd ->
+		           try try_fct fct (Connections.find cons fd)
+		           with Not_found -> ()) fds
+	in
+	process_fdset_with rset Process.do_input;
+	process_fdset_with wset Process.do_output
+
+let process_domains store cons domains =
+	let do_io_domain domain =
+		let con = Connections.find_domain cons (Domain.get_id domain) in
+		Process.do_input store cons domains con;
+		Process.do_output store cons domains con in
+	Domains.iter domains do_io_domain
+
+let sigusr1_handler store =
+	try
+		let channel = open_out_gen [ Open_wronly; Open_creat; Open_trunc; ]
+		                           0o600 "/var/run/xenstored/db.debug" in
+		finally (fun () -> Store.dump store channel)
+			(fun () -> close_out channel)
+	with _ ->
+		()
+
+let sighup_handler _ =
+	try Logs.reopen (); info "Log re-opened" with _ -> ()
+
+let config_filename cf =
+	match cf.config_file with
+	| Some name -> name
+	| None      -> Define.default_config_dir ^ "/xenstored.conf"
+
+let default_pidfile = "/var/run/xenstored.pid"
+
+let parse_config filename =
+	let pidfile = ref default_pidfile in
+	let set_log s =
+		let ls = Stringext.String.split ~limit:3 ';' s in
+		let level, key, logger = match ls with
+		| [ level; key; logger ] -> level, key, logger
+		| _ -> failwith "format mismatch: expecting 3 arguments" in
+
+		let loglevel = match level with
+		| "debug" -> Log.Debug
+		| "info"  -> Log.Info
+		| "warn"  -> Log.Warn
+		| "error" -> Log.Error
+		| s       -> failwith (sprintf "Unknown log level: %s" s) in
+
+		(* if key is empty, append to the default logger *)
+		let append =
+			if key = "" then
+				Logs.append_default
+			else
+				Logs.append key in
+		append loglevel logger in
+	let options = [
+		("merge-activate", Config.Set_bool Transaction.do_coalesce);
+		("perms-activate", Config.Set_bool Perms.activate);
+		("quota-activate", Config.Set_bool Quota.activate);
+		("quota-maxwatch", Config.Set_int Define.maxwatch);
+		("quota-transaction", Config.Set_int Define.maxtransaction);
+		("quota-maxentity", Config.Set_int Quota.maxent);
+		("quota-maxsize", Config.Set_int Quota.maxsize);
+		("test-eagain", Config.Set_bool Transaction.test_eagain);
+		("log", Config.String set_log);
+		("persistant", Config.Set_bool Disk.enable);
+		("access-log-file", Config.Set_string Logging.access_log_file);
+		("access-log-nb-files", Config.Set_int Logging.access_log_nb_files);
+		("access-log-nb-lines", Config.Set_int Logging.access_log_nb_lines);
+		("access-log-read-ops", Config.Set_bool Logging.log_read_ops);
+		("access-log-transactions-ops", Config.Set_bool Logging.log_transaction_ops);
+		("access-log-special-ops", Config.Set_bool Logging.log_special_ops);
+		("allow-debug", Config.Set_bool Process.allow_debug);
+		("pid-file", Config.Set_string pidfile); ] in
+	begin try Config.read filename options (fun _ _ -> raise Not_found)
+	with
+	| Config.Error err -> List.iter (fun (k, e) ->
+		match e with
+		| "unknown key" -> eprintf "config: unknown key %s\n" k
+		| _             -> eprintf "config: %s: %s\n" k e
+		) err;
+	| Sys_error m -> eprintf "error: config: %s\n" m;
+	end;
+	!pidfile
+
+module DB = struct
+
+exception Bad_format of string
+
+let dump_format_header = "$xenstored-dump-format"
+
+let from_channel_f chan domain_f watch_f store_f =
+	let unhexify s = Utils.unhexify s in
+	let getpath s = Store.Path.of_string (Utils.unhexify s) in
+	let header = input_line chan in
+	if header <> dump_format_header then
+		raise (Bad_format "header");
+	let quit = ref false in
+	while not !quit
+	do
+		try
+			let line = input_line chan in
+			let l = Stringext.String.split ',' line in
+			try
+				match l with
+				| "dom" :: domid :: mfn :: port :: []->
+					domain_f (int_of_string domid)
+					         (Nativeint.of_string mfn)
+					         (int_of_string port)
+				| "watch" :: domid :: path :: token :: [] ->
+					watch_f (int_of_string domid)
+					        (unhexify path) (unhexify token)
+				| "store" :: path :: perms :: value :: [] ->
+					store_f (getpath path)
+					        (Perms.Node.of_string (unhexify perms ^ "\000"))
+					        (unhexify value)
+				| _ ->
+					info "restoring: ignoring unknown line: %s" line
+			with exn ->
+				info "restoring: ignoring unknown line: %s (exception: %s)"
+				     line (Printexc.to_string exn);
+				()
+		with End_of_file ->
+			quit := true
+	done;
+	()
+
+let from_channel store cons doms chan =
+	(* don't let the permission get on our way, full perm ! *)
+	let op = Store.get_ops store Perms.Connection.full_rights in
+	let xc = Xc.interface_open () in
+
+	let domain_f domid mfn port =
+		let ndom =
+			if domid > 0 then
+				Domains.create xc doms domid mfn port
+			else
+				Domains.create0 false doms
+			in
+		Connections.add_domain cons ndom;
+		in
+	let watch_f domid path token = 
+		let con = Connections.find_domain cons domid in
+		ignore (Connections.add_watch cons con path token)
+		in
+	let store_f path perms value =
+		op.Store.write path value;
+		op.Store.setperms path perms
+		in
+	finally (fun () -> from_channel_f chan domain_f watch_f store_f)
+	        (fun () -> Xc.interface_close xc)
+
+let from_file store cons doms file =
+	let channel = open_in file in
+	finally (fun () -> from_channel store doms cons channel)
+	        (fun () -> close_in channel)
+
+let to_channel store cons chan =
+	let hexify s = Utils.hexify s in
+
+	fprintf chan "%s\n" dump_format_header;
+
+	(* dump connections related to domains; domid, mfn, eventchn port, watches *)
+	Connections.iter_domains cons (fun con -> Connection.dump con chan);
+
+	(* dump the store *)
+	Store.dump_fct store (fun path node ->
+		let name, perms, value = Store.Node.unpack node in
+		let fullpath = (Store.Path.to_string path) ^ "/" ^ name in
+		let permstr = Perms.Node.to_string perms in
+		fprintf chan "store,%s,%s,%s\n" (hexify fullpath) (hexify permstr) (hexify value)
+	);
+	flush chan;
+	()
+
+
+let to_file store cons file =
+	let channel = open_out_gen [ Open_wronly; Open_creat; Open_trunc; ] 0o600 file in
+	finally (fun () -> to_channel store cons channel)
+	        (fun () -> close_out channel)
+end
+
+let _ =
+	printf "Xen Storage Daemon, version %d.%d\n%!"
+	       Define.xenstored_major Define.xenstored_minor;
+
+	let cf = do_argv in
+	let pidfile =
+		if Sys.file_exists (config_filename cf) then
+			parse_config (config_filename cf)
+		else
+			default_pidfile
+		in
+
+	(try 
+		Unixext.mkdir_rec (Filename.dirname pidfile) 0o755
+	with _ ->
+		()
+	);
+
+	let rw_sock, ro_sock =
+		if cf.disable_socket then
+			None, None
+		else
+			Some (Unix.handle_unix_error Utils.create_unix_socket Define.xs_daemon_socket),
+			Some (Unix.handle_unix_error Utils.create_unix_socket Define.xs_daemon_socket_ro)
+		in
+	
+	if cf.daemonize then
+		Unixext.daemonize ();
+
+	(try Unixext.pidfile_write pidfile with _ -> ());
+
+	info "Xen Storage Daemon, version %d.%d"
+	     Define.xenstored_major Define.xenstored_minor;
+
+	(* for compatilibity with old xenstored *)
+	begin match cf.pidfile with
+	| Some pidfile -> Unixext.pidfile_write pidfile
+	| None         -> () end;
+
+	let store = Store.create () in
+	let eventchn = Event.init () in
+	let domains = Domains.init eventchn in
+	let cons = Connections.create () in
+
+	let quit = ref false in
+
+	if cf.restart then (
+		DB.from_file store domains cons "/var/run/xenstored/db";
+		Event.bind_virq eventchn
+	) else (
+		if !Disk.enable then (
+			info "reading store from disk";
+			Disk.read store
+		);
+
+		let localpath = Store.Path.of_string "/local" in
+		if not (Store.path_exists store localpath) then
+			Store.mkdir store (Perms.Connection.create 0) localpath;
+
+		if cf.domain_init then (
+			let usingxiu = Xc.using_injection () in
+			Connections.add_domain cons (Domains.create0 usingxiu domains);
+			Event.bind_virq eventchn
+		);
+	);
+
+	Sys.set_signal Sys.sighup (Sys.Signal_handle sighup_handler);
+	Sys.set_signal Sys.sigterm (Sys.Signal_handle (fun i -> quit := true));
+	Sys.set_signal Sys.sigusr1 (Sys.Signal_handle (fun i -> sigusr1_handler store));
+	Sys.set_signal Sys.sigpipe Sys.Signal_ignore;
+
+	Logging.init cf.activate_access_log (fun () -> DB.to_file store cons "/var/run/xenstored/db");
+
+	let spec_fds =
+		(match rw_sock with None -> [] | Some x -> [ x ]) @
+		(match ro_sock with None -> [] | Some x -> [ x ]) @
+		(if cf.domain_init then [ eventchn.Event.fd ] else [])
+		in
+
+	let xc = Xc.interface_open () in
+
+	let process_special_fds rset =
+		let accept_connection can_write fd =
+			let (cfd, addr) = Unix.accept fd in
+			debug "new connection through socket";
+			Connections.add_anonymous cons cfd can_write
+		and handle_eventchn fd =
+			let port = Event.read_port eventchn in
+			finally (fun () ->
+				if port = eventchn.Event.virq_port then (
+					let (notify, deaddom) = Domains.cleanup xc domains in
+					List.iter (Connections.del_domain cons) deaddom;
+					if deaddom <> [] || notify then
+						Connections.fire_spec_watches cons "@releaseDomain"
+				)
+			) (fun () -> Event.write_port eventchn port);
+		and do_if_set fd set fct =
+			if List.mem fd set then
+				fct fd in
+
+		maybe (fun fd -> do_if_set fd rset (accept_connection true)) rw_sock;
+		maybe (fun fd -> do_if_set fd rset (accept_connection false)) ro_sock;
+		do_if_set eventchn.Event.fd rset (handle_eventchn)
+		in
+
+	let last_stat_time = ref 0. in
+	let periodic_ops_counter = ref 0 in
+	let periodic_ops () =
+		(* we garbage collect the string->int dictionary after a sizeable amount of operations,
+		 * there's no need to be really fast even if we got loose
+		 * objects since names are often reuse.
+		 *)
+		if Symbol.created () > 1000 || Symbol.used () > 20000
+		then begin
+			Symbol.mark_all_as_unused ();
+			Store.mark_symbols store;
+			Connections.iter cons Connection.mark_symbols;
+			Symbol.garbage ()
+		end;
+
+		(* make sure we don't print general stats faster than 2 min *)
+		let ntime = Unix.gettimeofday () in
+		if ntime > (!last_stat_time +. 120.) then (
+			last_stat_time := ntime;
+
+			let gc = Gc.stat () in
+			let (lanon, lanon_ops, lanon_watchs,
+			     ldom, ldom_ops, ldom_watchs) = Connections.stats cons in
+			let store_nodes, store_abort, store_coalesce = Store.stats store in
+			let symtbl_len = Symbol.stats () in
+
+			info "store stat: nodes(%d) t-abort(%d) t-coalesce(%d)"
+			     store_nodes store_abort store_coalesce;
+			info "sytbl stat: %d" symtbl_len;
+			info "  con stat: anonymous(%d, %d o, %d w) domains(%d, %d o, %d w)"
+			     lanon lanon_ops lanon_watchs ldom ldom_ops ldom_watchs;
+			info "  mem stat: minor(%.0f) promoted(%.0f) major(%.0f) heap(%d w, %d c) live(%d w, %d b) free(%d w, %d b)"
+			     gc.Gc.minor_words gc.Gc.promoted_words gc.Gc.major_words
+			     gc.Gc.heap_words gc.Gc.heap_chunks
+			     gc.Gc.live_words gc.Gc.live_blocks
+			     gc.Gc.free_words gc.Gc.free_blocks
+		)
+		in
+
+	let main_loop () =
+		incr periodic_ops_counter;
+		if !periodic_ops_counter > 20 then (
+			periodic_ops_counter := 0;
+			periodic_ops ();
+		);
+
+		let mw = Connections.has_more_work cons in
+		let inset, outset = Connections.select cons in
+		let timeout = if List.length mw > 0 then 0. else -1. in
+		let rset, wset, _ =
+		try
+			Unix.select (spec_fds @ inset) outset [] timeout
+		with Unix.Unix_error(Unix.EINTR, _, _) ->
+			[], [], [] in
+		let sfds, cfds =
+			List.partition (fun fd -> List.mem fd spec_fds) rset in
+		if List.length sfds > 0 then
+			process_special_fds sfds;
+		if List.length cfds > 0 || List.length wset > 0 then
+			process_connection_fds store cons domains cfds wset;
+		process_domains store cons domains
+		in
+
+	while not !quit
+	do
+		try
+			main_loop ()
+		with exc ->
+			error "caught exception %s" (Printexc.to_string exc);
+			if cf.reraise_top_level then
+				raise exc
+	done;
+	info "stopping xenstored";
+	DB.to_file store cons "/var/run/xenstored/db";
+	()

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

  parent reply	other threads:[~2010-03-01 11:59 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-03-01 11:59 [RFC][PATCH 0/6] merge ocaml xenstored and dependencies Vincent Hanquez
2010-03-01 11:59 ` [PATCH 1/6] add ocaml libs (xc/xb/xs/eventchn) Vincent Hanquez
2010-03-01 11:59 ` Vincent Hanquez [this message]
2010-03-01 11:59 ` [PATCH 3/6] add compilation makefile to ocaml directory Vincent Hanquez
2010-03-01 11:59 ` [PATCH 4/6] remove hook from external ocaml repository Vincent Hanquez
2010-03-01 11:59 ` [PATCH 5/6] add ocaml tools to build if defined. default to n Vincent Hanquez
2010-03-01 11:59 ` [PATCH 6/6] default ocaml tools config variable to y Vincent Hanquez

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1267444791-4810-3-git-send-email-vincent.hanquez@eu.citrix.com \
    --to=vincent.hanquez@eu.citrix.com \
    --cc=xen-devel@lists.xensource.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).