commit 227d9de37c26f7e72666aae8bcec159db4cd3bfe
Author: Jon Ludlam <jon@dhcp-3-31.uk.xensource.com>
Date:   Fri Jul 1 14:00:39 2011 +0100

    Add a couple of useful functions to forkhelpers and unixext - a way of executing a command and sending stdin to it, and a statvfs call

--- a/stdext/forkhelpers.ml
+++ b/stdext/forkhelpers.ml
@@ -161,23 +161,34 @@
     close_fds
 
 
+let execute_command_get_output_inner ?env ?stdin ?(syslog_stdout=NoSyslogging) cmd args =
+	let stdinandpipes = Opt.map (fun str -> 
+		let (x,y) = Unix.pipe () in
+		(str,x,y)) stdin in
+	Pervasiveext.finally (fun () -> 
+		match with_logfile_fd "execute_command_get_out" (fun out_fd ->
+			with_logfile_fd "execute_command_get_err" (fun err_fd ->
+				let (sock,pid) = safe_close_and_exec ?env (Opt.map (fun (_,fd,_) -> fd) stdinandpipes) (Some out_fd) (Some err_fd) [] ~syslog_stdout cmd args in
+				Opt.map (fun (str,_,wr) -> Unixext.really_write_string wr str) stdinandpipes;
+				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)
+		(fun () -> Opt.iter (fun (_,x,y) -> Unix.close x; Unix.close y) stdinandpipes)
+
 let execute_command_get_output ?env ?(syslog_stdout=NoSyslogging) cmd args =
-  match with_logfile_fd "execute_command_get_out" (fun out_fd ->
-    with_logfile_fd "execute_command_get_err" (fun err_fd ->
-      let (sock,pid) = safe_close_and_exec ?env None (Some out_fd) (Some err_fd) [] ~syslog_stdout 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
+	execute_command_get_output_inner ?env ?stdin:None ~syslog_stdout cmd args
 
+let execute_command_get_output_send_stdin ?env ?(syslog_stdout=NoSyslogging) cmd args stdin =
+	execute_command_get_output_inner ?env ~stdin ~syslog_stdout cmd args
--- a/stdext/forkhelpers.mli
+++ b/stdext/forkhelpers.mli
@@ -44,6 +44,11 @@
     [Spawn_internal_error(stderr, stdout, Unix.process_status)] *)
 val execute_command_get_output : ?env:string array -> ?syslog_stdout:syslog_stdout_t -> string -> string list -> string * string
 
+(** [execute_command_get_output cmd args stdin] runs [cmd args], passes in the string [stdin] and returns (stdout, stderr)
+	on success (exit 0). On failure this raises 
+    [Spawn_internal_error(stderr, stdout, Unix.process_status)] *)
+val execute_command_get_output_send_stdin : ?env:string array -> ?syslog_stdout:syslog_stdout_t -> string -> string list -> string -> string * string
+
 (** Thrown by [execute_command_get_output] if the subprocess exits with a non-zero exit code *)
 exception Spawn_internal_error of string * string * Unix.process_status
 
--- a/stdext/unixext.ml
+++ b/stdext/unixext.ml
@@ -620,3 +620,20 @@
 
 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"
+
+
+type statvfs_t = {
+	f_bsize : int64;
+	f_frsize : int64;
+	f_blocks : int64;
+	f_bfree : int64;
+	f_bavail : int64;
+	f_files : int64;
+	f_ffree : int64;
+	f_favail : int64;
+	f_fsid : int64;
+	f_flag : int64;
+	f_namemax : int64;
+}
+
+external statvfs : string -> statvfs_t = "stub_statvfs"
--- a/stdext/unixext.mli
+++ b/stdext/unixext.mli
@@ -139,3 +139,19 @@
 
 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"
+
+type statvfs_t = {
+	f_bsize : int64;
+	f_frsize : int64;
+	f_blocks : int64;
+	f_bfree : int64;
+	f_bavail : int64;
+	f_files : int64;
+	f_ffree : int64;
+	f_favail : int64;
+	f_fsid : int64;
+	f_flag : int64;
+	f_namemax : int64;
+}
+
+val statvfs : string -> statvfs_t
--- a/stdext/unixext_stubs.c
+++ b/stdext/unixext_stubs.c
@@ -21,6 +21,7 @@
 #include <unistd.h> /* needed for _SC_OPEN_MAX */
 #include <stdio.h> /* snprintf */
 #include <sys/ioctl.h>
+#include <sys/statvfs.h>
 #include <linux/fs.h> 
 
 #include <caml/mlvalues.h>
@@ -405,3 +406,40 @@
 
   CAMLreturn(res);
 }
+
+CAMLprim value stub_statvfs(value filename) 
+{
+  CAMLparam1(filename);
+  CAMLlocal2(v,tmp);
+  int ret;
+  int i;
+  struct statvfs buf;
+
+  ret = statvfs(String_val(filename), &buf);
+
+  if(ret == -1) uerror("statvfs", Nothing);
+
+  tmp=caml_copy_int64(0);
+
+  /* Allocate the thing to return and ensure each of the
+	 fields is set to something valid before attempting 
+	 any further allocations */
+  v=alloc_small(11,0);
+  for(i=0; i<11; i++) {
+	Field(v,i)=tmp;
+  }
+
+  Field(v,0)=caml_copy_int64(buf.f_bsize);
+  Field(v,1)=caml_copy_int64(buf.f_frsize);
+  Field(v,2)=caml_copy_int64(buf.f_blocks);
+  Field(v,3)=caml_copy_int64(buf.f_bfree);
+  Field(v,4)=caml_copy_int64(buf.f_bavail);
+  Field(v,5)=caml_copy_int64(buf.f_files);
+  Field(v,6)=caml_copy_int64(buf.f_ffree);
+  Field(v,7)=caml_copy_int64(buf.f_favail);
+  Field(v,8)=caml_copy_int64(buf.f_fsid);
+  Field(v,9)=caml_copy_int64(buf.f_flag);
+  Field(v,10)=caml_copy_int64(buf.f_namemax);
+
+  CAMLreturn(v);
+}
