[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-API] [PATCH 1 of 6] CA-33440: add a single-threaded fork/exec daemon to fork/exec on behalf of xapi



# HG changeset patch
# User Jon Ludlam <Jonathan.Ludlam@xxxxxxxxxxxxx>
# Date 1261169313 0
# Node ID 5861a396a46c196844dd7d4cb7d35df0e62a6a0c
# Parent  5f4dcbe779847ef4ac943286bd628dbdc40dc927
CA-33440: add a single-threaded fork/exec daemon to fork/exec on behalf of xapi.

The new 'fe' daemon requests and file descriptors over a unix domain socket and 
calls fork/exec/waitpid on behalf of clients.

Signed-off-by: Jon Ludlam <Jonathan.Ludlam@xxxxxxxxxxxxx>
Acked-by: David Scott <dave.scott@xxxxxxxxxxxxx>

diff -r 5f4dcbe77984 -r 5861a396a46c Makefile.in
--- a/Makefile.in       Mon Dec 14 17:31:52 2009 +0000
+++ b/Makefile.in       Fri Dec 18 20:48:33 2009 +0000
@@ -8,6 +8,9 @@
 .PHONY: all
 all:
        $(MAKE) -C uuid
+ifeq ($(HAVE_TYPECONV),type-conv)
+       $(MAKE) -C rpc-light
+endif
        $(MAKE) -C stdext
        $(MAKE) -C log
        $(MAKE) -C stunnel
@@ -15,9 +18,7 @@
        $(MAKE) -C http-svr
        $(MAKE) -C close-and-exec
        $(MAKE) -C sexpr
-ifeq ($(HAVE_TYPECONV),type-conv)
-       $(MAKE) -C rpc-light
-endif
+
 ifeq ($(HAVE_XMLM),xmlm)
        $(MAKE) -C xml-light2
        $(MAKE) -C rss
@@ -164,6 +165,7 @@
        make -C close-and-exec clean
        make -C sexpr clean
        make -C doc clean
+       make -C forking_executioner clean
 
 cleanxen:
        $(MAKE) -C mmap clean
diff -r 5f4dcbe77984 -r 5861a396a46c forking_executioner/META.in
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/forking_executioner/META.in       Fri Dec 18 20:48:33 2009 +0000
@@ -0,0 +1,5 @@
+version = "@VERSION@"
+description = "forking executioner script"
+requires = "unix,stdext"
+archive(byte) = "felib.cma"
+archive(native) = "felib.cmxa"
diff -r 5f4dcbe77984 -r 5861a396a46c forking_executioner/Makefile
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/forking_executioner/Makefile      Fri Dec 18 20:48:33 2009 +0000
@@ -0,0 +1,70 @@
+IPROG=install -m 755 -o root -g root
+CC = gcc
+CFLAGS = -Wall -fPIC -O2 -I/opt/xensource/lib/ocaml
+OCAMLC = ocamlc -g
+OCAMLOPT = ocamlopt
+
+LDFLAGS = -cclib -L./
+
+LIBEXEC  = "/opt/xensource/libexec"
+VERSION := $(shell hg parents --template "{rev}" 2>/dev/null || echo 0.0)
+OCAMLOPTFLAGS = -g -dtypes
+
+OCAMLABI := $(shell ocamlc -version)
+OCAMLLIBDIR := $(shell ocamlc -where)
+OCAMLDESTDIR ?= $(OCAMLLIBDIR)
+
+
+OBJS = 
+INTF = $(foreach obj, $(OBJS),$(obj).cmi)
+LIBS = 
+
+PROGRAMS = fe
+
+DOCDIR = /myrepos/xen-api-libs.hg/doc
+
+all: $(INTF) $(LIBS) $(PROGRAMS)
+
+bins: $(PROGRAMS)
+
+libs: $(LIBS)
+
+test_forker: test_forker.cmx
+       $(OCAMLOPT) $(OCAMLOPTFLAGS) -I ../rpc-light -I ../uuid -I ../stdext 
uuid.cmxa jsonrpc.cmxa -I ../log unix.cmxa stdext.cmxa  test_forker.cmx -o $@
+
+fe: fe_debug.cmx child.cmx fe_main.cmx
+       $(OCAMLOPT) $(OCAMLOPTFLAGS) -I ../rpc-light -I ../stdext -I ../uuid -I 
../log log.cmxa uuid.cmxa unix.cmxa jsonrpc.cmxa stdext.cmxa fe_debug.cmx 
child.cmx fe_main.cmx -o $@ 
+
+%.cmo: %.ml
+       $(OCAMLC) -c -I ../log -I ../uuid -I ../stdext -thread -o $@  $<
+
+%.cmi: %.mli
+       $(OCAMLC) -c -I ../log -I ../uuid -I ../stdext -o $@  $<
+
+%.cmx: %.ml
+       $(OCAMLOPT) $(OCAMLOPTFLAGS) -I ../log -I ../uuid -c -I ../stdext -o $@ 
$<
+
+META: META.in
+       sed 's/@VERSION@/$(VERSION)/g' < $< > $@
+
+.PHONY: install
+install: 
+
+.PHONY: bininstall
+bininstall: path = $(DESTDIR)$(LIBEXEC)
+bininstall: all
+       mkdir -p $(path)
+       $(IPROG) $(PROGRAMS) $(path)
+
+.PHONY: uninstall
+uninstall:
+
+.PHONY: binuninstall
+binuninstall:
+       rm -f $(DESTDIR)$(LIBEXEC)$(PROGRAMS)
+
+.PHONY: doc
+doc: 
+
+clean:
+       rm -f *.o *.so *.a *.cmo *.cmi *.cma *.cmx *.cmxa *.annot $(LIBS) 
$(PROGRAMS)
diff -r 5f4dcbe77984 -r 5861a396a46c forking_executioner/child.ml
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/forking_executioner/child.ml      Fri Dec 18 20:48:33 2009 +0000
@@ -0,0 +1,162 @@
+open Stringext
+
+let debug (fmt : ('a, unit, string, unit) format4) = (Printf.kprintf (fun s -> 
Printf.fprintf stderr "%s\n" s) fmt)
+
+exception Cancelled
+
+type state_t = {
+  cmdargs : string list;
+  env : string list;
+  id_to_fd_map : (string * int option) list;
+  ids_received : (string * Unix.file_descr) list;
+  fd_sock2 : Unix.file_descr option;
+  finished : bool;
+}
+
+open Fe_debug
+
+let handle_fd_sock fd_sock state =
+  try
+    let (newfd,buffer) = Fecomms.receive_named_fd fd_sock in
+    let dest_fd = List.assoc buffer state.id_to_fd_map in
+    let fd = begin 
+      match dest_fd with 
+       | Some d -> 
+           debug "Received fd named: %s - duping to %d (from %d)" buffer d 
(Unixext.int_of_file_descr newfd);
+           let d = Unixext.file_descr_of_int d in
+           begin
+             if d = newfd
+             then ()
+             else begin
+               Unix.dup2 newfd d;
+               Unix.close newfd;
+             end
+           end;
+           d
+       | None -> 
+           debug "Received fd named: %s (%d)" buffer 
(Unixext.int_of_file_descr newfd);
+           newfd
+    end in
+    {state with ids_received = (buffer,fd) :: state.ids_received}
+  with Fecomms.Connection_closed -> 
+    {state with fd_sock2 = None}
+
+let handle_comms_sock comms_sock state =
+  let call = Fecomms.read_raw_rpc comms_sock in
+  match call with 
+    | Fe.Cancel -> debug "Cancel"; raise Cancelled
+    | Fe.Exec -> debug "Exec"; {state with finished=true;}
+    | _ -> 
+       debug "Ignoring unknown command";
+       state
+
+let handle_comms_no_fd_sock2 comms_sock fd_sock state =
+  debug "Selecting in handle_comms_no_fd_sock2";
+  let (ready,_,_) = Unix.select [comms_sock; fd_sock] [] [] (-1.0) in
+  debug "Done";
+  if List.mem fd_sock ready then begin
+    debug "fd sock";
+    let fd_sock2,_ = Unix.accept fd_sock in
+    {state with fd_sock2=Some fd_sock2}
+  end else begin
+    debug "comms sock";
+    handle_comms_sock comms_sock state    
+  end
+  
+let handle_comms_with_fd_sock2 comms_sock fd_sock fd_sock2 state =
+  debug "Selecting in handle_comms_with_fd_sock2";
+  let (ready,_,_) = Unix.select [comms_sock; fd_sock2] [] [] (-1.0) in
+  debug "Done";
+  if List.mem fd_sock2 ready then begin
+    debug "fd sock2";
+    handle_fd_sock fd_sock2 state 
+  end else begin
+    debug "comms sock";
+    handle_comms_sock comms_sock state    
+  end
+
+let handle_comms comms_sock fd_sock state =
+  match state.fd_sock2 with 
+    | None -> handle_comms_no_fd_sock2 comms_sock fd_sock state
+    | Some x -> handle_comms_with_fd_sock2 comms_sock fd_sock x state
+
+let run state comms_sock fd_sock fd_sock_path =
+  let rec inner state =
+    let state = handle_comms comms_sock fd_sock state in
+    if state.finished then state else inner state
+  in
+
+  try
+    dbuffer := Buffer.create 500;
+
+    debug "Started: state.cmdargs = [%s]" (String.concat ";" (state.cmdargs));
+    debug "Started: state.env = [%s]" (String.concat ";" (state.env));
+
+    let fd = Unix.openfile "/dev/null" [ Unix.O_WRONLY ] 0o0 in
+    Unix.dup2 fd Unix.stdin;
+    Unix.dup2 fd Unix.stdout;
+    Unix.dup2 fd Unix.stderr;
+
+    if fd<>Unix.stdin && fd<>Unix.stdout && fd<>Unix.stderr then Unix.close fd;
+
+    let state = inner state in
+
+    debug "Finished...";
+    Unix.close fd_sock;
+    (match state.fd_sock2 with Some x -> Unix.close x | None -> ());
+
+    Unixext.unlink_safe fd_sock_path;
+    
+    (* Finally, replace placeholder uuids in the commandline arguments
+       to be the string representation of the fd (where we don't care what
+       fd it ends up being) *)
+    let args = List.map (fun arg ->
+      try 
+       let (id_received,fd) = List.find (fun (id_received,fd) -> 
String.endswith id_received arg) state.ids_received in
+       let stem = String.sub arg 0 (String.length arg - String.length 
id_received) in
+       stem ^ (string_of_int (Unixext.int_of_file_descr fd));
+      with _ -> arg) state.cmdargs in
+
+    debug "Args after replacement = [%s]" (String.concat ";" args);    
+
+    let fds = List.map snd state.ids_received in
+    
+    debug "I've received the following fds: [%s]\n" 
+      (String.concat ";" (List.map (fun fd -> string_of_int 
(Unixext.int_of_file_descr fd)) fds));
+
+    let result = Unix.fork () in
+
+    if result=0 then begin
+      (* child *)
+      (* Now let's close everything except those fds mentioned in the 
ids_received list *)
+      Unixext.close_all_fds_except ([Unix.stdin; Unix.stdout; Unix.stderr] @ 
fds);
+      
+      (* And exec *)
+      Unix.execve (List.hd args) (Array.of_list args) (Array.of_list state.env)
+    end else begin
+      Fecomms.write_raw_rpc comms_sock (Fe.Execed result);
+
+      List.iter (fun fd -> Unix.close fd) fds;
+      let (pid,status) = Unix.waitpid [] result in
+      let pr = match status with
+       | Unix.WEXITED n -> Fe.WEXITED n
+       | Unix.WSIGNALED n -> Fe.WSIGNALED n 
+       | Unix.WSTOPPED n -> Fe.WSTOPPED n
+      in
+      let result = Fe.Finished (pr) in
+      Fecomms.write_raw_rpc comms_sock result;
+      Unix.close comms_sock;
+      exit 0;
+    end
+  with 
+    | Cancelled ->
+       debug "Cancelling";
+       Unix.close comms_sock;
+       Unix.close fd_sock;
+       Unixext.unlink_safe fd_sock_path;
+       exit 0;
+    | e -> 
+       debug "Caught unexpected exception: %s" (Printexc.to_string e);
+       write_log ();
+       exit 1
+         
diff -r 5f4dcbe77984 -r 5861a396a46c forking_executioner/fe_debug.ml
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/forking_executioner/fe_debug.ml   Fri Dec 18 20:48:33 2009 +0000
@@ -0,0 +1,23 @@
+let log_path = "/var/log/fe.log"
+
+let dbuffer = ref (Buffer.create 1) 
+
+let gettimestring () =
+       let time = Unix.gettimeofday () in
+       let tm = Unix.gmtime time in
+        let msec = time -. (floor time) in
+       Printf.sprintf "%d%.2d%.2dT%.2d:%.2d:%.2d.%.3dZ|" (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 reset () = dbuffer := Buffer.create 100
+
+let debug (fmt : ('a, unit, string, unit) format4) = 
+  Printf.kprintf (fun s -> ignore(Printf.bprintf !dbuffer "%s|%d|%s\n" 
(gettimestring ()) (Unix.getpid ()) s)) fmt
+
+let write_log () =
+  let logfile = Unix.openfile log_path [Unix.O_WRONLY; Unix.O_CREAT; 
Unix.O_APPEND] 0o644 in
+  Unixext.really_write_string logfile (Buffer.contents !dbuffer);
+  Unix.close logfile
+
diff -r 5f4dcbe77984 -r 5861a396a46c forking_executioner/fe_main.ml
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/forking_executioner/fe_main.ml    Fri Dec 18 20:48:33 2009 +0000
@@ -0,0 +1,68 @@
+open Fe_debug
+
+let setup sock cmdargs id_to_fd_map env =
+  let fd_sock_path = Printf.sprintf "/var/xapi/forker/fd_%s" 
+    (Uuid.to_string (Uuid.make_uuid ())) in
+  let fd_sock = Fecomms.open_unix_domain_sock () in
+  Unixext.unlink_safe fd_sock_path;
+  debug "About to bind to %s" fd_sock_path;
+  Unix.bind fd_sock (Unix.ADDR_UNIX fd_sock_path);
+  Unix.listen fd_sock 5;
+  debug "bound, listening";
+  let result = Unix.fork () in
+  if result=0 
+  then begin
+    debug "Child here!";
+    let result2 = Unix.fork () in
+    if result2=0 then begin
+      debug "Grandchild here!";
+      (* Grandchild *)
+      let state = {
+       Child.cmdargs=cmdargs; 
+       env=env;
+       id_to_fd_map=id_to_fd_map; 
+       ids_received=[];
+       fd_sock2=None;
+       finished=false;
+      } in
+      Child.run state sock fd_sock fd_sock_path
+    end else begin
+      (* Child *)
+      exit 0;
+    end
+  end else begin
+    (* Parent *)
+    debug "Waiting for process %d to exit" result;
+    ignore(Unix.waitpid [] result);
+    Unix.close fd_sock;
+    Some {Fe.fd_sock_path=fd_sock_path}
+  end
+
+let _ =
+  (* Unixext.daemonize ();*)
+  Sys.set_signal Sys.sigpipe (Sys.Signal_ignore);
+
+  let main_sock = Fecomms.open_unix_domain_sock_server "/var/xapi/forker/main" 
in
+
+  while true do
+    try
+      let (sock,addr) = Unix.accept main_sock in
+      reset ();
+      let cmd = Fecomms.read_raw_rpc sock in
+      match cmd with
+       | Fe.Setup s ->
+           let result = setup sock s.Fe.cmdargs s.Fe.id_to_fd_map s.Fe.env in
+           (match result with
+             | Some response ->
+                 Fecomms.write_raw_rpc sock (Fe.Setup_response response);
+                 Unix.close sock;
+             | _ -> ())
+       | _ -> 
+           debug "Ignoring invalid message";
+           Unix.close sock
+    with e -> 
+      debug "Caught exception at top level: %s" (Printexc.to_string e);
+  done
+      
+    
+      
diff -r 5f4dcbe77984 -r 5861a396a46c forking_executioner/test_forker.ml
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/forking_executioner/test_forker.ml        Fri Dec 18 20:48:33 2009 +0000
@@ -0,0 +1,49 @@
+
+let _ = 
+  let die_at = int_of_string Sys.argv.(1) in
+  let sock = Fecomms.open_unix_domain_sock_client "/var/xapi/forker/main" in
+  let uuid = Uuid.to_string (Uuid.make_uuid ()) in
+  Printf.fprintf stderr "About to write raw rpc\n%!";
+  Fecomms.write_raw_rpc sock (Fe.Setup 
{Fe.cmdargs=["/bin/fecho";"hello";"test"]; id_to_fd_map = [(uuid,Some 
(Unixext.int_of_file_descr Unix.stdout))]; env=[]});
+  if die_at=1 then exit(1);
+  Printf.fprintf stderr "Done write raw rpc\n%!";
+  let response = Fecomms.read_raw_rpc sock in
+  if die_at=2 then exit(1);
+  Printf.fprintf stderr "Got response\n%!";
+  match response with
+    | Fe.Setup_response s ->
+       Printf.fprintf stderr "Got response: fd_sock_path=%s\n%!" 
s.Fe.fd_sock_path;
+       let (rd,wr) = Unix.pipe () in
+       let fd_sock = Fecomms.open_unix_domain_sock_client s.Fe.fd_sock_path in
+       if die_at=3 then exit(1);
+       (try
+         Fecomms.send_named_fd fd_sock uuid wr;
+       with e -> 
+         Printf.fprintf stderr "Failed to send named fd: %s%!" 
(Printexc.to_string e));
+       if die_at=4 then exit(1);
+       Unix.close wr;
+       Unix.close fd_sock;
+       Fecomms.write_raw_rpc sock Fe.Exec;
+       if die_at=5 then exit(1);
+       (match Fecomms.read_raw_rpc sock with
+         | Fe.Execed pid ->
+             Printf.fprintf stderr "Got pid: %d\n%!" pid);
+       if die_at=6 then exit(1);
+       let buffer = Buffer.create 1000 in
+       let str = String.make 1000 '\000' in
+       let rec consume () = 
+         let len = Unix.read rd str 0 (String.length str) in
+         if len=0 
+         then () 
+         else
+           begin 
+             Buffer.add_substring buffer str 0 len;
+             consume ()
+           end
+       in 
+       consume ();
+       Printf.fprintf stderr "Received: %s\n%!" (Buffer.contents buffer);
+       match Fecomms.read_raw_rpc sock with
+         | Fe.Finished res ->
+             Printf.fprintf stderr "Got finished\n%!";
+         
diff -r 5f4dcbe77984 -r 5861a396a46c stdext/META.in
--- a/stdext/META.in    Mon Dec 14 17:31:52 2009 +0000
+++ b/stdext/META.in    Fri Dec 18 20:48:33 2009 +0000
@@ -1,5 +1,5 @@
 version = "@VERSION@"
 description = "Stdext - Common stdlib extensions"
-requires = "unix,uuid,bigarray"
+requires = "unix,uuid,bigarray,rpc-light,jsonrpc"
 archive(byte) = "stdext.cma"
 archive(native) = "stdext.cmxa"
diff -r 5f4dcbe77984 -r 5861a396a46c stdext/Makefile
--- a/stdext/Makefile   Mon Dec 14 17:31:52 2009 +0000
+++ b/stdext/Makefile   Fri Dec 18 20:48:33 2009 +0000
@@ -15,12 +15,14 @@
 OCAMLLIBDIR := $(OCAMLLOC)
 OCAMLDESTDIR ?= $(OCAMLLIBDIR)
 
+FEPP = camlp4o -I ../rpc-light -I $(shell ocamlfind query type-conv) 
pa_type_conv.cmo pa_rpc.cma
+
 OCAML_TEST_INC = -I $(shell ocamlfind query oUnit)
 OCAML_TEST_LIB = $(shell ocamlfind query oUnit)/oUnit.cmxa
 
 STDEXT_OBJS = filenameext stringext arrayext hashtblext listext pervasiveext 
threadext ring \
-       qring fring opt bigbuffer unixext range vIO trie config date encodings 
forkhelpers \
-       gzip sha1sum zerocheck base64 backtrace tar
+       qring fring opt bigbuffer unixext range vIO trie config date encodings 
fe fecomms \
+       forkhelpers gzip sha1sum zerocheck base64 backtrace tar 
 
 INTF = $(foreach obj, $(STDEXT_OBJS),$(obj).cmi)
 LIBS = stdext.cma stdext.cmxa
@@ -59,8 +61,14 @@
 threadext.cmo: threadext.ml threadext.cmi
        $(OCAMLC) -thread -c -o $@ $<
 
+fecomms.cmo : fecomms.ml
+       $(OCAMLC) -I ../rpc-light -c -o $@ $<
+
+fe.cmo: fe.ml 
+       $(OCAMLC) -pp '$(FEPP)' -I ../jsonrpc -I ../rpc-light -c -o $@ $<
+
 forkhelpers.cmo: forkhelpers.ml forkhelpers.cmi
-       $(OCAMLC) -thread -c -o $@ $<
+       $(OCAMLC) -thread -I ../uuid -c -o $@ $<
 
 filenameext.cmo: filenameext.ml filenameext.cmi
        $(OCAMLC) -c -I ../uuid -o $@ $<
@@ -77,14 +85,23 @@
 filenameext.cmi: filenameext.mli
        $(OCAMLC) -c -I ../uuid -o $@ $<
 
+fe.cmi: fe.cmo
+       $(OCAMLC) -pp '$(FEPP)' -c -o $@ $<
+
 %.cmi: %.mli
        $(OCAMLC) -c -o $@ $<
+
+fe.cmx: fe.ml 
+       $(OCAMLOPT) -pp '$(FEPP)' -I ../rpc-light -c -o $@ $<
 
 threadext.cmx: threadext.ml threadext.cmi
        $(OCAMLOPT) $(OCAMLOPTFLAGS) -thread -c -o $@ $<
 
+fecomms.cmx : fecomms.ml
+       $(OCAMLOPT) -I ../rpc-light -c -o $@ $<
+
 forkhelpers.cmx: forkhelpers.ml forkhelpers.cmi
-       $(OCAMLOPT) $(OCAMLOPTFLAGS) -thread -c -o $@ $<
+       $(OCAMLOPT) $(OCAMLOPTFLAGS) -I ../uuid -thread -c -o $@ $<
 
 filenameext.cmx: filenameext.ml filenameext.cmi
        $(OCAMLOPT) $(OCAMLOPTFLAGS) -thread -c -I ../uuid -o $@ $<
diff -r 5f4dcbe77984 -r 5861a396a46c stdext/fe.ml
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/stdext/fe.ml      Fri Dec 18 20:48:33 2009 +0000
@@ -0,0 +1,24 @@
+
+type setup_cmd = {
+  cmdargs : string list;
+  env : string list;
+  id_to_fd_map : (string * int option) list } 
+
+and setup_response = {
+  fd_sock_path : string } 
+
+and process_result = 
+    | WEXITED of int
+    | WSIGNALED of int
+    | WSTOPPED of int
+
+and ferpc = 
+    | Setup of setup_cmd
+    | Setup_response of setup_response
+    | Cancel 
+    | Exec
+    | Execed of int
+    | Finished of process_result
+    | Log_reopen
+with rpc
+
diff -r 5f4dcbe77984 -r 5861a396a46c stdext/fecomms.ml
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/stdext/fecomms.ml Fri Dec 18 20:48:33 2009 +0000
@@ -0,0 +1,42 @@
+open Fe
+
+let open_unix_domain_sock () =
+  Unix.socket Unix.PF_UNIX Unix.SOCK_STREAM 0
+
+let open_unix_domain_sock_server path =
+  Unixext.unlink_safe path;
+  let sock = open_unix_domain_sock () in
+  Unix.bind sock (Unix.ADDR_UNIX path);
+  Unix.listen sock 5;
+  sock
+
+let open_unix_domain_sock_client path =
+  let sock = open_unix_domain_sock () in
+  Unix.connect sock (Unix.ADDR_UNIX path);
+  sock
+
+let read_raw_rpc sock =
+  let buffer = String.make 12 '\000' in
+  Unixext.really_read sock buffer 0 12;
+  let len = int_of_string buffer in
+  let body = Unixext.really_read_string sock len in
+  ferpc_of_rpc (Jsonrpc.of_string body)
+
+let write_raw_rpc sock ferpc =
+  let body = Jsonrpc.to_string (rpc_of_ferpc ferpc) in
+  let len = String.length body in
+  let buffer = Printf.sprintf "%012d%s" len body in
+  Unixext.really_write_string sock buffer
+
+exception Connection_closed
+
+let receive_named_fd sock =
+  let buffer = String.make 36 '\000' in
+  let (len,from,newfd) = Unixext.recv_fd sock buffer 0 36 [] in  
+  if len=0 then raise Connection_closed;
+  (newfd,buffer)
+
+let send_named_fd sock uuid fd =
+  ignore(Unixext.send_fd sock uuid 0 (String.length uuid) [] fd)
+  
+    
diff -r 5f4dcbe77984 -r 5861a396a46c stdext/fecomms.mli
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/stdext/fecomms.mli        Fri Dec 18 20:48:33 2009 +0000
@@ -0,0 +1,8 @@
+val open_unix_domain_sock : unit -> Unix.file_descr
+val open_unix_domain_sock_server : string -> Unix.file_descr
+val open_unix_domain_sock_client : string -> Unix.file_descr
+val read_raw_rpc : Unix.file_descr -> Fe.ferpc
+val write_raw_rpc : Unix.file_descr -> Fe.ferpc -> unit
+exception Connection_closed
+val receive_named_fd : Unix.file_descr -> Unix.file_descr * string
+val send_named_fd : Unix.file_descr -> string -> Unix.file_descr -> unit
diff -r 5f4dcbe77984 -r 5861a396a46c stdext/forkhelpers.ml
--- a/stdext/forkhelpers.ml     Mon Dec 14 17:31:52 2009 +0000
+++ b/stdext/forkhelpers.ml     Fri Dec 18 20:48:33 2009 +0000
@@ -22,6 +22,19 @@
 (* XXX: this is a work in progress *)
 
 open Pervasiveext
+
+type pidty = 
+    | Stdfork of int (* We've forked and execed, and therefore need to waitpid 
*)
+    | FEFork of (Unix.file_descr * int) (* The forking executioner has been 
used, therefore we need to tell it to waitpid *)
+    | Nopid
+
+let string_of_pidty p =
+  match p with
+    | Stdfork pid -> Printf.sprintf "(Stdfork %d)" pid
+    | FEFork (fd,pid) -> Printf.sprintf "(FEFork (%d,%d))" 
(Unixext.int_of_file_descr fd) pid
+    | Nopid -> "Nopid"
+
+let nopid = Nopid
 
 (** Standalone wrapper process which safely closes fds before exec()ing another
     program *)
@@ -56,7 +69,7 @@
        | None -> Unix.execv argv0 args
        | Some env -> Unix.execve argv0 args env
       with _ -> exit 1
-  end else pid
+  end else Stdfork pid
 
 (** File descriptor operations to be performed after a fork.
     These are all safe in the presence of threads *)
@@ -68,21 +81,57 @@
   | Dup2(a, b) -> Unix.dup2 a b
   | Close a -> Unix.close a
 
-(** Safe function which forks a command, closing all fds except a whitelist and
-    having performed some fd operations in the child *)
-let safe_close_and_exec ?env (pre_exec: fd_operation list) (fds: 
Unix.file_descr list) 
-    (cmd: string) (args: string list) = 
-  let cmdline = close_and_exec_cmdline fds cmd args in
-  fork_and_exec ~pre_exec:(fun () -> List.iter do_fd_operation pre_exec) ?env 
cmdline
 
 exception Subprocess_failed of int
 exception Subprocess_killed of int
 
-let waitpid pid = match Unix.waitpid [] pid with
-  | _, Unix.WEXITED 0 -> ()
-  | _, Unix.WEXITED n -> raise (Subprocess_failed n)
-  | _, Unix.WSIGNALED n -> raise (Subprocess_killed n)
-  | _, Unix.WSTOPPED n -> raise (Subprocess_killed n)
+let waitpid ty =
+  match ty with 
+    | Stdfork pid ->
+       Unix.waitpid [] pid
+    | FEFork (sock,pid) ->
+       let status = Fecomms.read_raw_rpc sock in
+       Unix.close sock;
+       begin match status with
+         | Fe.Finished (Fe.WEXITED n) -> (pid,Unix.WEXITED n)
+         | Fe.Finished (Fe.WSIGNALED n) -> (pid,Unix.WSIGNALED n)
+         | Fe.Finished (Fe.WSTOPPED n) -> (pid,Unix.WSTOPPED n)
+       end
+    | Nopid -> failwith "Can't waitpid without a process"
+
+let waitpid_nohang ty =
+  match ty with
+    | Stdfork pid ->
+       Unix.waitpid [Unix.WNOHANG] pid 
+    | FEFork (sock,pid) ->
+       (match Unix.select [sock] [] [] 0.0 with
+         | ([s],_,_) -> waitpid ty
+         | _ -> (0,Unix.WEXITED 0))
+    | Nopid -> 
+       failwith "Can't waitpid without a pid"
+         
+let dontwaitpid ty =
+  match ty with
+    | Stdfork pid ->
+       failwith "Can't do this!"
+    | FEFork (sock,pid) -> 
+       Unix.close sock
+    | Nopid -> ()
+
+
+let waitpid_fail_if_bad_exit ty =
+  let (_,status) = waitpid ty in
+  match status with
+    | (Unix.WEXITED 0) -> ()
+    | (Unix.WEXITED n) -> raise (Subprocess_failed n)
+    | (Unix.WSIGNALED n) -> raise (Subprocess_killed n)
+    | (Unix.WSTOPPED n) -> raise (Subprocess_killed n)
+
+let getpid ty =
+  match ty with
+    | Stdfork pid -> pid
+    | FEFork (sock,pid) -> pid
+    | Nopid -> failwith "No pid!"
 
 type 'a result = Success of string * 'a | Failure of string * exn
 
@@ -113,42 +162,90 @@
 
 exception Spawn_internal_error of string * string * Unix.process_status
 
-(* Execute a command, return the stdout logging or throw a 
Spawn_internal_error exception *)
+let id = ref 0 
+
+(** Safe function which forks a command, closing all fds except a whitelist and
+    having performed some fd operations in the child *)
+let safe_close_and_exec ?env stdin stdout stderr (fds: (string * 
Unix.file_descr) list) 
+    (cmd: string) (args: string list) = 
+
+  let sock = Fecomms.open_unix_domain_sock_client "/var/xapi/forker/main" in
+  let stdinuuid = Uuid.to_string (Uuid.make_uuid ()) in
+  let stdoutuuid = Uuid.to_string (Uuid.make_uuid ()) in
+  let stderruuid = Uuid.to_string (Uuid.make_uuid ()) in
+
+  let fds_to_close = ref [] in
+
+  let add_fd_to_close_list fd = fds_to_close := fd :: !fds_to_close in
+  let remove_fd_from_close_list fd = fds_to_close := List.filter (fun fd' -> 
fd' <> fd) !fds_to_close in
+  let close_fds () = List.iter (fun fd -> Unix.close fd) !fds_to_close in
+
+  finally (fun () -> 
+
+    let maybe_add_id_to_fd_map id_to_fd_map (uuid,fd,v) =
+      match v with 
+       | Some _ -> (uuid, fd)::id_to_fd_map
+       | None -> id_to_fd_map
+    in
+
+    let predefined_fds = [
+      (stdinuuid, Some 0, stdin);
+      (stdoutuuid, Some 1, stdout);
+      (stderruuid, Some 2, stderr)] 
+    in
+
+    (* We don't care what fd these end up as - they're named in the argument 
list for us, and the
+       forking executioner will sort it out. *)
+    let dest_named_fds = List.map (fun (uuid,_) -> (uuid,None)) fds in
+    let id_to_fd_map = List.fold_left maybe_add_id_to_fd_map dest_named_fds 
predefined_fds in
+
+    let env = match env with 
+      |        Some e -> e
+      | None -> [||] 
+    in
+    Fecomms.write_raw_rpc sock (Fe.Setup {Fe.cmdargs=(cmd::args); 
env=(Array.to_list env); id_to_fd_map = id_to_fd_map});
+
+    let response = Fecomms.read_raw_rpc sock in
+
+    let s = match response with
+      | Fe.Setup_response s -> s 
+      | _ -> failwith "Failed to communicate with forking executioner"
+    in
+
+    let fd_sock = Fecomms.open_unix_domain_sock_client s.Fe.fd_sock_path in
+    add_fd_to_close_list fd_sock;
+    
+    let send_named_fd uuid fd =
+      Fecomms.send_named_fd fd_sock uuid fd;
+    in
+
+    List.iter (fun (uuid,_,srcfdo) ->
+      match srcfdo with Some srcfd -> send_named_fd uuid srcfd | None -> ()) 
predefined_fds;
+    List.iter (fun (uuid,srcfd) ->
+      send_named_fd uuid srcfd) fds;
+    Fecomms.write_raw_rpc sock Fe.Exec;
+    match Fecomms.read_raw_rpc sock with Fe.Execed pid -> FEFork (sock, pid))
+   
+    close_fds
+
+
 let execute_command_get_output ?(cb_set=(fun _ -> ())) ?(cb_clear=(fun () -> 
())) cmd args =
-  let (stdout_exit, stdout_entrance) = Unix.pipe () in
-  let fds_to_close = ref [ stdout_exit; stdout_entrance ] in
-  let close' fd = 
-    if List.mem fd !fds_to_close 
-    then (Unix.close fd; fds_to_close := List.filter (fun x -> x <> fd) 
!fds_to_close) in
-  
-  let pid = ref 0 in
-  finally  (* make sure I close all my open fds in the end *)
-    (fun () ->
-       (* Open /dev/null for reading. This will be given to the closeandexec 
process as its STDIN. *)
-       with_dev_null_read (fun devnull_read ->
-         (* Capture stderr output for logging *)
-         match with_logfile_fd "execute_command_get_output"
-         (fun log_fd ->
-           pid := safe_close_and_exec
-             [ Dup2(devnull_read, Unix.stdin);
-               Dup2(stdout_entrance, Unix.stdout);
-               Dup2(log_fd, Unix.stderr);
-               Close(stdout_exit) ]
-             [ Unix.stdin; Unix.stdout; Unix.stderr ] (* close all but these *)
-             cmd args;
-           (* parent *)
-           (try cb_set !pid with _ -> ());
-           close' stdout_entrance;
-           let output = (try Unixext.read_whole_file 500 500 stdout_exit with 
_ -> "") in
-           output, snd(Unix.waitpid [] !pid)) with
-         | Success(log, (output, status)) ->
-            begin match status with
-            | Unix.WEXITED 0 -> output, log
-            | _ -> raise (Spawn_internal_error(log, output, status))
-            end
-         | Failure(log, exn) ->
-            raise exn
-       )
-    ) (fun () -> 
-        (try cb_clear () with _ -> ());
-        List.iter Unix.close !fds_to_close)
+  match with_logfile_fd "execute_command_get_out" (fun out_fd ->
+    with_logfile_fd "execute_command_get_err" (fun err_fd ->
+      let FEFork (sock,pid) = safe_close_and_exec None (Some out_fd) (Some 
err_fd) [] cmd args in
+      match Fecomms.read_raw_rpc sock with
+       | Fe.Finished x -> Unix.close sock; x
+       | _ -> Unix.close sock; failwith "Communications error"     
+    )) with
+    | Success(out,Success(err,(status))) -> 
+       begin
+         match status with
+           | Fe.WEXITED 0 -> (out,err)
+           | Fe.WEXITED n -> raise (Spawn_internal_error(err,out,Unix.WEXITED 
n))
+           | Fe.WSTOPPED n -> raise 
(Spawn_internal_error(err,out,Unix.WSTOPPED n))
+           | Fe.WSIGNALED n -> raise 
(Spawn_internal_error(err,out,Unix.WSIGNALED n))
+       end
+    | Success(_,Failure(_,exn))
+    | Failure(_, exn) ->
+       raise exn
+
diff -r 5f4dcbe77984 -r 5861a396a46c stdext/forkhelpers.mli
--- a/stdext/forkhelpers.mli    Mon Dec 14 17:31:52 2009 +0000
+++ b/stdext/forkhelpers.mli    Fri Dec 18 20:48:33 2009 +0000
@@ -26,6 +26,12 @@
 exception Subprocess_killed of int
 exception Spawn_internal_error of string * string * Unix.process_status
 
+type pidty
+
+val string_of_pidty : pidty -> string
+
+val nopid : pidty
+
 (** Standalone wrapper process which safely closes fds before exec()ing another
     program *)
 val close_and_exec : string
@@ -43,11 +49,11 @@
 (** Low-level (unsafe) function which forks, runs a 'pre_exec' function and
    then executes some other binary. It makes sure to catch any exception 
thrown by
    exec* so that we don't end up with two ocaml processes. *)
-val fork_and_exec : ?pre_exec:(unit -> unit) -> ?env:string array -> string 
list -> int
+val fork_and_exec : ?pre_exec:(unit -> unit) -> ?env:string array -> string 
list -> pidty
 
 (** Safe function which forks a command, closing all fds except a whitelist and
     having performed some fd operations in the child *)
-val safe_close_and_exec : ?env:string array -> fd_operation list -> 
Unix.file_descr list -> string -> string list -> int
+val safe_close_and_exec : ?env:string array -> Unix.file_descr option -> 
Unix.file_descr option -> Unix.file_descr option -> (string * Unix.file_descr) 
list -> string -> string list -> pidty
 
 type 'a result = Success of string * 'a | Failure of string * exn
 
@@ -62,6 +68,10 @@
 (** Execute a command, return the stdout logging or throw a 
Spawn_internal_error exception *)
 val execute_command_get_output : ?cb_set:(int -> unit) -> ?cb_clear:(unit -> 
unit) -> string -> string list -> string * string
 
-val waitpid : int -> unit
+val waitpid : pidty -> (int * Unix.process_status)
+val waitpid_nohang : pidty -> (int * Unix.process_status)
+val dontwaitpid : pidty -> unit
+val waitpid_fail_if_bad_exit : pidty -> unit
+val getpid : pidty -> int
 
 val with_dev_null : (Unix.file_descr -> 'a) -> 'a
diff -r 5f4dcbe77984 -r 5861a396a46c stdext/gzip.ml
--- a/stdext/gzip.ml    Mon Dec 14 17:31:52 2009 +0000
+++ b/stdext/gzip.ml    Fri Dec 18 20:48:33 2009 +0000
@@ -44,20 +44,18 @@
       (fun () ->
         let args = if mode = Compress then [] else ["--decompress"] @ [ 
"--stdout"; "--force" ] in
 
-        let dups, close_now, close_later = match input with
+        let stdin, stdout, close_now, close_later = match input with
           | Active -> 
-              [ Forkhelpers.Dup2(fd, Unix.stdout);        (* supplied fd is 
written to *)
-                Forkhelpers.Dup2(zcat_out, Unix.stdin) ], (* input comes from 
the pipe+fn *)
+              Some zcat_out,                              (* input comes from 
the pipe+fn *)
+              Some fd,                                    (* supplied fd is 
written to *)
               zcat_out,                                   (* we close this now 
*)
               zcat_in                                     (* close this before 
waitpid *)
           | Passive -> 
-              [ Forkhelpers.Dup2(fd, Unix.stdin);         (* supplied fd is 
read from *)
-                Forkhelpers.Dup2(zcat_in, Unix.stdout) ], (* output goes into 
the pipe+fn *) 
+              Some fd,                                    (* supplied fd is 
read from *)
+              Some zcat_in,                               (* output goes into 
the pipe+fn *) 
               zcat_in,                                    (* we close this now 
*)
               zcat_out in                                 (* close this before 
waitpid *)
-        let pid = Forkhelpers.safe_close_and_exec dups
-          [ Unix.stdout; Unix.stdin; ] (* close all but these *)
-          gzip args in
+        let pid = Forkhelpers.safe_close_and_exec stdin stdout None [] gzip 
args in
         close close_now;
         finally
           (fun () -> f close_later)
@@ -69,7 +67,7 @@
                failwith msg
                in
              close close_later;
-             match snd (Unix.waitpid [] pid) with
+             match snd (Forkhelpers.waitpid pid) with
              | Unix.WEXITED 0 -> ();
              | Unix.WEXITED i -> failwith_error (Printf.sprintf "exit code %d" 
i)
              | Unix.WSIGNALED i -> failwith_error (Printf.sprintf "killed by 
signal %d" i)
diff -r 5f4dcbe77984 -r 5861a396a46c stdext/sha1sum.ml
--- a/stdext/sha1sum.ml Mon Dec 14 17:31:52 2009 +0000
+++ b/stdext/sha1sum.ml Fri Dec 18 20:48:33 2009 +0000
@@ -38,11 +38,7 @@
     finally
       (fun () ->
         let args = [] in
-        let pid = Forkhelpers.safe_close_and_exec
-         [ Forkhelpers.Dup2(result_in, Unix.stdout);
-           Forkhelpers.Dup2(input_out, Unix.stdin) ]
-         [ Unix.stdout; Unix.stdin; ] (* close all but these *)
-         sha1sum args in
+        let pid = Forkhelpers.safe_close_and_exec (Some input_out) (Some 
result_in) None [] sha1sum args in
 
         close result_in;
         close input_out;
@@ -61,12 +57,7 @@
              close result_out;
              result)
           (fun () ->
-             match Unix.waitpid [] pid with
-             | _, Unix.WEXITED 0 -> ()
-             | _, _ -> 
-                 let msg = "sha1sum failed (non-zero error code or signal?)" in
-                 Printf.eprintf "%s" msg;
-                 failwith msg
+            Forkhelpers.waitpid_fail_if_bad_exit pid
           )
       ) (fun () -> List.iter close !to_close)
 
diff -r 5f4dcbe77984 -r 5861a396a46c stdext/unixext.ml
--- a/stdext/unixext.ml Mon Dec 14 17:31:52 2009 +0000
+++ b/stdext/unixext.ml Fri Dec 18 20:48:33 2009 +0000
@@ -485,27 +485,6 @@
     if not(List.mem i fds') then close' i
   done
 
-exception Process_output_error of string
-let get_process_output ?(handler) cmd : string =
-       let inchan = Unix.open_process_in cmd in
-
-       let buffer = Buffer.create 1024
-       and buf = String.make 1024 '\000' in
-       
-       let rec read_until_eof () =
-               let rd = input inchan buf 0 1024 in
-               if rd = 0 then
-                       ()
-               else (
-                       Buffer.add_substring buffer buf 0 rd;
-                       read_until_eof ()
-               ) in
-       (* Make sure an exception doesn't prevent us from waiting for the child 
process *)
-       (try read_until_eof () with _ -> ());
-       match (Unix.close_process_in inchan), handler with
-       | Unix.WEXITED 0, _ -> Buffer.contents buffer
-       | Unix.WEXITED n, Some handler -> handler cmd n
-       | _ -> raise (Process_output_error cmd)
 
 (** Remove "." and ".." from paths (NB doesn't attempt to resolve symlinks) *)
 let resolve_dot_and_dotdot (path: string) : string = 
@@ -676,3 +655,6 @@
 
 let http_get = Http.get
 let http_put = Http.put
+
+external send_fd : Unix.file_descr -> string -> int -> int -> Unix.msg_flag 
list -> Unix.file_descr -> int = "stub_unix_send_fd_bytecode" 
"stub_unix_send_fd"
+external recv_fd : Unix.file_descr -> string -> int -> int -> Unix.msg_flag 
list -> int * Unix.sockaddr * Unix.file_descr = "stub_unix_recv_fd"
diff -r 5f4dcbe77984 -r 5861a396a46c stdext/unixext.mli
--- a/stdext/unixext.mli        Mon Dec 14 17:31:52 2009 +0000
+++ b/stdext/unixext.mli        Fri Dec 18 20:48:33 2009 +0000
@@ -86,7 +86,6 @@
 val int_of_file_descr : Unix.file_descr -> int
 val file_descr_of_int : int -> Unix.file_descr
 val close_all_fds_except : Unix.file_descr list -> unit
-val get_process_output : ?handler:(string -> int -> string) -> string -> string
 val resolve_dot_and_dotdot : string -> string
 
 val seek_to : Unix.file_descr -> int -> int
@@ -111,3 +110,6 @@
 val http_get: open_tcp:(server:string -> (in_channel * out_channel)) -> 
uri:string -> filename:string -> server:string -> unit
 (** Upload a file via an HTTP PUT *)
 val http_put: open_tcp:(server:string -> (in_channel * out_channel)) -> 
uri:string -> filename:string -> server:string -> unit
+
+external send_fd : Unix.file_descr -> string -> int -> int -> Unix.msg_flag 
list -> Unix.file_descr -> int = "stub_unix_send_fd_bytecode" 
"stub_unix_send_fd"
+external recv_fd : Unix.file_descr -> string -> int -> int -> Unix.msg_flag 
list -> int * Unix.sockaddr * Unix.file_descr = "stub_unix_recv_fd"
diff -r 5f4dcbe77984 -r 5861a396a46c stdext/unixext_stubs.c
--- a/stdext/unixext_stubs.c    Mon Dec 14 17:31:52 2009 +0000
+++ b/stdext/unixext_stubs.c    Fri Dec 18 20:48:33 2009 +0000
@@ -16,6 +16,7 @@
 #include <errno.h>
 #include <netinet/tcp.h>
 #include <netinet/in.h>
+#include <sys/un.h>
 #include <string.h>
 #include <unistd.h> /* needed for _SC_OPEN_MAX */
 #include <stdio.h> /* snprintf */
@@ -267,3 +268,138 @@
        
        CAMLreturn(Bool_val(ret == 0));
 }
+
+static int msg_flag_table[] = {
+  MSG_OOB, MSG_DONTROUTE, MSG_PEEK
+};
+
+#define UNIX_BUFFER_SIZE 16384
+
+CAMLprim value stub_unix_send_fd(value sock, value buff, value ofs, value len, 
value flags, value fd)
+{
+  CAMLparam5(sock,buff,ofs,len,flags);
+  CAMLxparam1(fd);
+  int ret,  cv_flags, cfd;
+  long numbytes;
+  char iobuf[UNIX_BUFFER_SIZE];
+  value path;
+  int pathlen;
+  char buf[CMSG_SPACE(sizeof(cfd))];
+
+  cfd = Int_val(fd);
+
+  cv_flags = convert_flag_list(flags,msg_flag_table);
+
+  numbytes = Long_val(len);
+  if (numbytes > UNIX_BUFFER_SIZE) numbytes = UNIX_BUFFER_SIZE;
+  memmove(iobuf, &Byte(buff, Long_val(ofs)), numbytes);
+
+  /* Set up sockaddr */
+
+  struct msghdr msg;
+  struct iovec vec;
+  struct cmsghdr *cmsg;
+  
+  msg.msg_name = NULL;
+  msg.msg_namelen = 0; 
+  vec.iov_base=iobuf;
+  vec.iov_len=numbytes;
+  msg.msg_iov=&vec;
+  msg.msg_iovlen=1;
+
+  msg.msg_control = buf;
+  msg.msg_controllen = sizeof(buf);
+  cmsg = CMSG_FIRSTHDR(&msg);
+  cmsg->cmsg_level = SOL_SOCKET;
+  cmsg->cmsg_type = SCM_RIGHTS;
+  cmsg->cmsg_len = CMSG_LEN(sizeof(cfd));
+  *(int*)CMSG_DATA(cmsg) = cfd;
+  msg.msg_controllen = cmsg->cmsg_len;
+
+  msg.msg_flags = 0;
+
+  caml_enter_blocking_section();  
+  ret=sendmsg(Int_val(sock), &msg, cv_flags);
+  caml_leave_blocking_section();
+
+  if(ret == -1)
+    unixext_error(errno);
+
+  CAMLreturn(Val_int(ret));
+}
+
+CAMLprim value stub_unix_send_fd_bytecode(value *argv, int argn) 
+{
+  return stub_unix_send_fd(argv[0],argv[1],argv[2],argv[3],
+                        argv[4], argv[5]);
+}
+
+CAMLprim value stub_unix_recv_fd(value sock, value buff, value ofs, value len, 
value flags) 
+{
+  CAMLparam5(sock,buff,ofs,len,flags);
+  CAMLlocal2(res,addr);
+  int ret,  cv_flags, fd;
+  long numbytes;
+  char iobuf[UNIX_BUFFER_SIZE];
+  char buf[CMSG_SPACE(sizeof(fd))];
+  struct sockaddr_un unix_socket_name;
+
+  cv_flags = convert_flag_list(flags,msg_flag_table);
+
+  struct msghdr msg;
+  struct iovec vec;
+  struct cmsghdr *cmsg;
+
+  numbytes = Long_val(len);
+  if(numbytes > UNIX_BUFFER_SIZE)
+    numbytes = UNIX_BUFFER_SIZE;
+
+  msg.msg_name=&unix_socket_name;
+  msg.msg_namelen=sizeof(unix_socket_name);
+  vec.iov_base=iobuf;
+  vec.iov_len=numbytes;
+  msg.msg_iov=&vec;
+
+  msg.msg_iovlen=1;
+
+  msg.msg_control = buf;
+  msg.msg_controllen = sizeof(buf);
+
+  caml_enter_blocking_section();  
+  ret=recvmsg(Int_val(sock), &msg, cv_flags);
+  caml_leave_blocking_section();
+
+  if(ret == -1) 
+    unixext_error(errno);
+
+  if(ret> 0) {
+    cmsg = CMSG_FIRSTHDR(&msg);
+    if(cmsg->cmsg_level == SOL_SOCKET && (cmsg->cmsg_type == SCM_RIGHTS)) {
+      fd=Val_int(*(int*)CMSG_DATA(cmsg));
+    } else {
+      failwith("Failed to receive an fd!");
+    }
+  } else {
+    fd=Val_int(-1);
+  }
+  
+  if(ret<numbytes)
+    numbytes = ret;
+
+  memmove(&Byte(buff, Long_val(ofs)), iobuf, numbytes);
+
+  addr=alloc_small(1,0);
+  
+  if(ret>0) {
+    Field(addr,0) = copy_string(unix_socket_name.sun_path);
+  } else {
+    Field(addr,0) = copy_string("nothing");
+  }
+
+  res=alloc_small(3,0);
+  Field(res,0) = Val_int(ret);
+  Field(res,1) = addr;
+  Field(res,2) = fd;
+
+  CAMLreturn(res);
+}
diff -r 5f4dcbe77984 -r 5861a396a46c stunnel/META.in
--- a/stunnel/META.in   Mon Dec 14 17:31:52 2009 +0000
+++ b/stunnel/META.in   Fri Dec 18 20:48:33 2009 +0000
@@ -1,5 +1,5 @@
 version = "@VERSION@"
 description = "Secure Tunneling"
-requires = "unix,stdext,log"
+requires = "uuid,unix,stdext,log"
 archive(byte) = "stunnel.cma"
 archive(native) = "stunnel.cmxa"
diff -r 5f4dcbe77984 -r 5861a396a46c stunnel/Makefile
--- a/stunnel/Makefile  Mon Dec 14 17:31:52 2009 +0000
+++ b/stunnel/Makefile  Fri Dec 18 20:48:33 2009 +0000
@@ -31,13 +31,13 @@
        $(OCAMLC) -a -o $@ $(foreach obj,$(OBJS),$(obj).cmo)
 
 %.cmo: %.ml
-       $(OCAMLC) -c -I ../stdext -I ../log -o $@ $<
+       $(OCAMLC) -c -I ../stdext -I ../uuid -I ../log -o $@ $<
 
 %.cmi: %.mli
-       $(OCAMLC) -c -o $@ $<
+       $(OCAMLC) -c -I ../stdext -I ../uuid -o $@ $<
 
 %.cmx: %.ml
-       $(OCAMLOPT) $(OCAMLOPTFLAGS) -c -I ../stdext -I ../log -o $@ $<
+       $(OCAMLOPT) $(OCAMLOPTFLAGS) -c -I ../stdext -I ../uuid -I ../log -o $@ 
$<
 
 %.o: %.c
        $(CC) $(CFLAGS) -c -o $@ $<
@@ -58,6 +58,6 @@
 .PHONY: doc
 doc: $(INTF)
        python ../doc/doc.py $(DOCDIR) "stunnel" "package" "$(OBJS)" "." 
"stdext,log" ""
-       
+
 clean:
        rm -f *.o *.so *.a *.cmo *.cmi *.cma *.cmx *.cmxa *.annot $(LIBS) 
$(PROGRAMS)
diff -r 5f4dcbe77984 -r 5861a396a46c stunnel/stunnel.ml
--- a/stunnel/stunnel.ml        Mon Dec 14 17:31:52 2009 +0000
+++ b/stunnel/stunnel.ml        Fri Dec 18 20:48:33 2009 +0000
@@ -56,7 +56,8 @@
     | Some p -> p 
     | None -> raise Stunnel_binary_missing
 
-type t = { mutable pid: int; fd: Unix.file_descr; host: string; port: int; 
+
+type t = { mutable pid: Forkhelpers.pidty; fd: Unix.file_descr; host: string; 
port: int; 
           connected_time: float;
           unique_id: int option;
           mutable logfile: string;
@@ -81,7 +82,7 @@
 
 let disconnect x = 
   List.iter (ignore_exn Unix.close) [ x.fd ];
-  ignore_exn Forkhelpers.waitpid x.pid
+  ignore_exn Forkhelpers.waitpid_fail_if_bad_exit x.pid
 
 (* With some probability, stunnel fails during its startup code before it reads
    the config data from us. Therefore we get a SIGPIPE writing the config data.
@@ -94,7 +95,7 @@
   assert (not extended_diagnosis); (* !!! Unimplemented *)
   let data_out,data_in = Unix.socketpair Unix.PF_UNIX Unix.SOCK_STREAM 0 in
   let args = [ "-m"; "client"; "-s"; "-"; "-d"; Printf.sprintf "%s:%d" host 
port ] in
-  let t = { pid = 0; fd = data_out; host = host; port = port; 
+  let t = { pid = Forkhelpers.nopid; fd = data_out; host = host; port = port; 
            connected_time = Unix.gettimeofday (); unique_id = unique_id;
            logfile = "" } in
   let to_close = ref [ data_in ] in
@@ -107,12 +108,12 @@
     let fds_needed = [ Unix.stdin; Unix.stdout; Unix.stderr ] in
     t.pid <- (
       if use_external_fd_wrapper then
-        Forkhelpers.safe_close_and_exec fdops fds_needed (stunnel_path ()) args
+        Forkhelpers.safe_close_and_exec (Some data_in) (Some data_in) (Some 
logfd) [] (stunnel_path ()) args
       else
-        Forkhelpers.fork_and_exec ~pre_exec:(fun _ -> 
+       Forkhelpers.fork_and_exec ~pre_exec:(fun _ -> 
           List.iter Forkhelpers.do_fd_operation fdops;
           Unixext.close_all_fds_except fds_needed
-         ) ((stunnel_path ()) :: args)
+       ) ((stunnel_path ()) :: args)
     );
     List.iter Unix.close [ data_in ];
   ) in
@@ -131,12 +132,13 @@
   let data_out,data_in = Unix.socketpair Unix.PF_UNIX Unix.SOCK_STREAM 0
   and config_out, config_in = Unix.pipe ()
   in
+  let config_out_uuid = Uuid.to_string (Uuid.make_uuid ()) in
   (* FDs we must close. NB stdin_in and stdout_out end up in our 't' record *)
   let to_close = ref [ data_in; config_out; config_in  ] in
   let close fd = 
     if List.mem fd !to_close 
     then (Unix.close fd; to_close := List.filter (fun x -> x <> fd) !to_close) 
in
-  let t = { pid = 0; fd = data_out; host = host; port = port; 
+  let t = { pid = Forkhelpers.nopid; fd = data_out; host = host; port = port; 
            connected_time = Unix.gettimeofday (); unique_id = unique_id;
            logfile = "" } in
   let result = Forkhelpers.with_logfile_fd "stunnel"
@@ -148,27 +150,25 @@
           Forkhelpers.Dup2(data_in, Unix.stdout);
           Forkhelpers.Dup2(logfd, Unix.stderr) ] in
        let fds_needed = [ Unix.stdin; Unix.stdout; Unix.stderr; config_out ] in
-       let args = [ "-fd"; string_of_int (Unixext.int_of_file_descr 
config_out) ] in
+       let args = [ "-fd"; config_out_uuid ] in
        if use_external_fd_wrapper then begin
-        let cmdline = Printf.sprintf "Using commandline: %s\n" (String.concat 
" " (Forkhelpers.close_and_exec_cmdline fds_needed path args)) in
+        let cmdline = Printf.sprintf "Using commandline: %s\n" (String.concat 
" " (path::args)) in
         write_to_log cmdline;
        end;
        t.pid <-
-        (if use_external_fd_wrapper
-         (* Run thread-safe external wrapper *)
-         then Forkhelpers.safe_close_and_exec fdops fds_needed path args
-         (* or do it ourselves (safe if there are no threads) *)
-         else Forkhelpers.fork_and_exec ~pre_exec:
-             (fun _ -> 
-                List.iter Forkhelpers.do_fd_operation fdops;
-                Unixext.close_all_fds_except fds_needed) 
-             (path::args) );
+        if use_external_fd_wrapper
+        then Forkhelpers.safe_close_and_exec (Some data_in) (Some data_in) 
(Some logfd) [(config_out_uuid, config_out)] path args
+        else Forkhelpers.fork_and_exec ~pre_exec:
+                         (fun _ -> 
+                           List.iter Forkhelpers.do_fd_operation fdops;
+                           Unixext.close_all_fds_except fds_needed) 
+                         (path::args);
        List.iter close [ data_in; config_out; ]; 
        (* Make sure we close config_in eventually *)
        finally
         (fun () ->
 
-           let pidmsg = Printf.sprintf "stunnel has pid: %d\n" t.pid in
+           let pidmsg = Printf.sprintf "stunnel has pidty: %s\n" 
(Forkhelpers.string_of_pidty t.pid) in
            write_to_log pidmsg;
 
            let config = config_file verify_cert extended_diagnosis host port in
diff -r 5f4dcbe77984 -r 5861a396a46c stunnel/stunnel.mli
--- a/stunnel/stunnel.mli       Mon Dec 14 17:31:52 2009 +0000
+++ b/stunnel/stunnel.mli       Fri Dec 18 20:48:33 2009 +0000
@@ -23,7 +23,7 @@
 val init_stunnel_path : unit -> unit
 
 (** Represents an active stunnel connection *)
-type t = { mutable pid: int; 
+type t = { mutable pid: Forkhelpers.pidty; 
           fd: Unix.file_descr; 
           host: string; 
           port: int;
23 files changed, 814 insertions(+), 128 deletions(-)
Makefile.in                        |    8 -
forking_executioner/META.in        |    5 
forking_executioner/Makefile       |   70 ++++++++++++
forking_executioner/child.ml       |  162 +++++++++++++++++++++++++++++
forking_executioner/fe_debug.ml    |   23 ++++
forking_executioner/fe_main.ml     |   68 ++++++++++++
forking_executioner/test_forker.ml |   49 ++++++++
stdext/META.in                     |    2 
stdext/Makefile                    |   25 +++-
stdext/fe.ml                       |   24 ++++
stdext/fecomms.ml                  |   42 +++++++
stdext/fecomms.mli                 |    8 +
stdext/forkhelpers.ml              |  197 ++++++++++++++++++++++++++----------
stdext/forkhelpers.mli             |   16 ++
stdext/gzip.ml                     |   16 +-
stdext/sha1sum.ml                  |   13 --
stdext/unixext.ml                  |   24 ----
stdext/unixext.mli                 |    4 
stdext/unixext_stubs.c             |  136 ++++++++++++++++++++++++
stunnel/META.in                    |    2 
stunnel/Makefile                   |    8 -
stunnel/stunnel.ml                 |   38 +++---
stunnel/stunnel.mli                |    2 


Attachment: xen-api-libs.hg-6.patch
Description: Text Data

_______________________________________________
xen-api mailing list
xen-api@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/mailman/listinfo/xen-api

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.