1 (***********************************************************************)
5 (* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
7 (* Copyright 1996 Institut National de Recherche en Informatique et *)
8 (* en Automatique. All rights reserved. This file is distributed *)
9 (* under the terms of the GNU Library General Public License, with *)
10 (* the special exception on linking described in file ../../LICENSE. *)
12 (***********************************************************************)
14 (* $Id: unix.ml 8972 2008-08-01 16:29:44Z mauny $ *)
16 (* An alternate implementation of the Unix module from ../unix
17 which is safe in conjunction with bytecode threads. *)
19 (* Type definitions that matter for thread operations *)
28 (* We can't call functions from Thread because of type circularities,
29 so we redefine here the functions that we need *)
31 type resumption_status =
36 | Resumed_select of file_descr list * file_descr list * file_descr list
37 | Resumed_wait of int * process_status
39 external thread_initialize : unit -> unit = "thread_initialize"
40 external thread_wait_read : file_descr -> unit = "thread_wait_read"
41 external thread_wait_write : file_descr -> unit = "thread_wait_write"
42 external thread_select :
43 file_descr list * file_descr list * file_descr list * float
46 external thread_wait_pid : int -> resumption_status = "thread_wait_pid"
47 external thread_delay : float -> unit = "thread_delay"
49 let wait_read fd = thread_wait_read fd
50 let wait_write fd = thread_wait_write fd
51 let select_aux arg = thread_select arg
52 let wait_pid_aux pid = thread_wait_pid pid
53 let delay duration = thread_delay duration
55 (* Make sure that threads are initialized (PR#1516). *)
57 let _ = thread_initialize()
59 (* Back to the Unix module *)
132 exception Unix_error of error * string * string
134 let _ = Callback.register_exception "Unix.Unix_error"
135 (Unix_error(E2BIG, "", ""))
137 external error_message : error -> string = "unix_error_message"
139 let handle_unix_error f arg =
142 with Unix_error(err, fun_name, arg) ->
143 prerr_string Sys.argv.(0);
145 prerr_string fun_name;
146 prerr_string "\" failed";
147 if String.length arg > 0 then begin
148 prerr_string " on \"";
153 prerr_endline (error_message err);
156 external environment : unit -> string array = "unix_environment"
157 external getenv: string -> string = "caml_sys_getenv"
158 external putenv: string -> string -> unit = "unix_putenv"
160 type interval_timer =
165 type interval_timer_status =
166 { it_interval: float; (* Period *)
167 it_value: float } (* Current value of the timer *)
169 external getitimer: interval_timer -> interval_timer_status = "unix_getitimer"
171 interval_timer -> interval_timer_status -> interval_timer_status
199 external openfile : string -> open_flag list -> file_perm -> file_descr
202 external close : file_descr -> unit = "unix_close"
203 external unsafe_read : file_descr -> string -> int -> int -> int = "unix_read"
204 external unsafe_write : file_descr -> string -> int -> int -> int
206 external unsafe_single_write : file_descr -> string -> int -> int -> int
207 = "unix_single_write"
209 let rec read fd buf ofs len =
211 if ofs < 0 || len < 0 || ofs > String.length buf - len
212 then invalid_arg "Unix.read"
213 else unsafe_read fd buf ofs len
214 with Unix_error((EAGAIN | EWOULDBLOCK), _, _) ->
215 wait_read fd; read fd buf ofs len
217 let rec write fd buf ofs len =
219 if ofs < 0 || len < 0 || ofs > String.length buf - len
220 then invalid_arg "Unix.write"
221 else unsafe_write fd buf ofs len
222 with Unix_error((EAGAIN | EWOULDBLOCK), _, _) ->
223 wait_write fd; write fd buf ofs len
225 let rec single_write fd buf ofs len =
227 if ofs < 0 || len < 0 || ofs > String.length buf - len
228 then invalid_arg "Unix.partial_write"
229 else unsafe_single_write fd buf ofs len
230 with Unix_error((EAGAIN | EWOULDBLOCK), _, _) ->
231 wait_write fd; single_write fd buf ofs len
233 external in_channel_of_descr : file_descr -> in_channel
234 = "caml_ml_open_descriptor_in"
235 external out_channel_of_descr : file_descr -> out_channel
236 = "caml_ml_open_descriptor_out"
237 external descr_of_in_channel : in_channel -> file_descr
238 = "caml_channel_descriptor"
239 external descr_of_out_channel : out_channel -> file_descr
240 = "caml_channel_descriptor"
247 external lseek : file_descr -> int -> seek_command -> int = "unix_lseek"
248 external truncate : string -> int -> unit = "unix_truncate"
249 external ftruncate : file_descr -> int -> unit = "unix_ftruncate"
274 external stat : string -> stats = "unix_stat"
275 external lstat : string -> stats = "unix_lstat"
276 external fstat : file_descr -> stats = "unix_fstat"
277 external isatty : file_descr -> bool = "unix_isatty"
278 external unlink : string -> unit = "unix_unlink"
279 external rename : string -> string -> unit = "unix_rename"
280 external link : string -> string -> unit = "unix_link"
284 external lseek : file_descr -> int64 -> seek_command -> int64
286 external truncate : string -> int64 -> unit = "unix_truncate_64"
287 external ftruncate : file_descr -> int64 -> unit = "unix_ftruncate_64"
302 external stat : string -> stats = "unix_stat_64"
303 external lstat : string -> stats = "unix_lstat_64"
304 external fstat : file_descr -> stats = "unix_fstat_64"
307 type access_permission =
313 external chmod : string -> file_perm -> unit = "unix_chmod"
314 external fchmod : file_descr -> file_perm -> unit = "unix_fchmod"
315 external chown : string -> int -> int -> unit = "unix_chown"
316 external fchown : file_descr -> int -> int -> unit = "unix_fchown"
317 external umask : int -> int = "unix_umask"
318 external access : string -> access_permission list -> unit = "unix_access"
320 external dup : file_descr -> file_descr = "unix_dup"
321 external dup2 : file_descr -> file_descr -> unit = "unix_dup2"
322 external set_nonblock : file_descr -> unit = "unix_set_nonblock"
323 external clear_nonblock : file_descr -> unit = "unix_clear_nonblock"
324 external set_close_on_exec : file_descr -> unit = "unix_set_close_on_exec"
325 external clear_close_on_exec : file_descr -> unit = "unix_clear_close_on_exec"
327 external mkdir : string -> file_perm -> unit = "unix_mkdir"
328 external rmdir : string -> unit = "unix_rmdir"
329 external chdir : string -> unit = "unix_chdir"
330 external getcwd : unit -> string = "unix_getcwd"
331 external chroot : string -> unit = "unix_chroot"
335 external opendir : string -> dir_handle = "unix_opendir"
336 external readdir : dir_handle -> string = "unix_readdir"
337 external rewinddir : dir_handle -> unit = "unix_rewinddir"
338 external closedir : dir_handle -> unit = "unix_closedir"
340 external _pipe : unit -> file_descr * file_descr = "unix_pipe"
343 let (out_fd, in_fd as fd_pair) = _pipe() in
348 external symlink : string -> string -> unit = "unix_symlink"
349 external readlink : string -> string = "unix_readlink"
350 external mkfifo : string -> file_perm -> unit = "unix_mkfifo"
352 let select readfds writefds exceptfds delay =
353 match select_aux (readfds, writefds, exceptfds, delay) with
354 Resumed_select(r, w, e) -> (r, w, e)
365 external lockf : file_descr -> lock_command -> int -> unit = "unix_lockf"
367 external _execv : string -> string array -> 'a = "unix_execv"
368 external _execve : string -> string array -> string array -> 'a = "unix_execve"
369 external _execvp : string -> string array -> 'a = "unix_execvp"
370 external _execvpe : string -> string array -> string array -> 'a
373 (* Disable the timer interrupt before doing exec, because some OS
374 keep sending timer interrupts to the exec'ed code.
375 Also restore blocking mode on stdin, stdout and stderr,
376 since this is what most programs expect! *)
378 let safe_clear_nonblock fd =
379 try clear_nonblock fd with Unix_error(_,_,_) -> ()
380 let safe_set_nonblock fd =
381 try set_nonblock fd with Unix_error(_,_,_) -> ()
385 setitimer ITIMER_VIRTUAL {it_interval = 0.0; it_value = 0.0} in
386 safe_clear_nonblock stdin;
387 safe_clear_nonblock stdout;
388 safe_clear_nonblock stderr;
391 with Unix_error(_,_,_) as exn ->
392 ignore(setitimer ITIMER_VIRTUAL oldtimer);
393 safe_set_nonblock stdin;
394 safe_set_nonblock stdout;
395 safe_set_nonblock stderr;
398 let execv proc args =
399 do_exec (fun () -> _execv proc args)
401 let execve proc args env =
402 do_exec (fun () -> _execve proc args env)
404 let execvp proc args =
405 do_exec (fun () -> _execvp proc args)
407 let execvpe proc args =
408 do_exec (fun () -> _execvpe proc args)
410 external fork : unit -> int = "unix_fork"
411 external _waitpid : wait_flag list -> int -> int * process_status
415 match wait_pid_aux pid with
416 Resumed_wait(pid, status) -> (pid, status)
417 | _ -> invalid_arg "Thread.wait_pid"
419 let wait () = wait_pid (-1)
421 let waitpid flags pid =
422 if List.mem WNOHANG flags
423 then _waitpid flags pid
426 external getpid : unit -> int = "unix_getpid"
427 external getppid : unit -> int = "unix_getppid"
428 external nice : int -> int = "unix_nice"
430 external kill : int -> int -> unit = "unix_kill"
431 type sigprocmask_command = SIG_SETMASK | SIG_BLOCK | SIG_UNBLOCK
432 external sigprocmask: sigprocmask_command -> int list -> int list
434 external sigpending: unit -> int list = "unix_sigpending"
435 external sigsuspend: int list -> unit = "unix_sigsuspend"
438 let sigs = sigprocmask SIG_BLOCK [] in sigsuspend sigs
457 external time : unit -> float = "unix_time"
458 external gettimeofday : unit -> float = "unix_gettimeofday"
459 external gmtime : float -> tm = "unix_gmtime"
460 external localtime : float -> tm = "unix_localtime"
461 external mktime : tm -> float * tm = "unix_mktime"
462 external alarm : int -> int = "unix_alarm"
464 let sleep secs = delay (float secs)
466 external times : unit -> process_times = "unix_times"
467 external utimes : string -> float -> float -> unit = "unix_utimes"
469 external getuid : unit -> int = "unix_getuid"
470 external geteuid : unit -> int = "unix_geteuid"
471 external setuid : int -> unit = "unix_setuid"
472 external getgid : unit -> int = "unix_getgid"
473 external getegid : unit -> int = "unix_getegid"
474 external setgid : int -> unit = "unix_setgid"
475 external getgroups : unit -> int array = "unix_getgroups"
490 gr_mem : string array }
493 external getlogin : unit -> string = "unix_getlogin"
494 external getpwnam : string -> passwd_entry = "unix_getpwnam"
495 external getgrnam : string -> group_entry = "unix_getgrnam"
496 external getpwuid : int -> passwd_entry = "unix_getpwuid"
497 external getgrgid : int -> group_entry = "unix_getgrgid"
499 type inet_addr = string
501 external inet_addr_of_string : string -> inet_addr
502 = "unix_inet_addr_of_string"
503 external string_of_inet_addr : inet_addr -> string
504 = "unix_string_of_inet_addr"
506 let inet_addr_any = inet_addr_of_string "0.0.0.0"
507 let inet_addr_loopback = inet_addr_of_string "127.0.0.1"
509 try inet_addr_of_string "::" with Failure _ -> inet_addr_any
510 let inet6_addr_loopback =
511 try inet_addr_of_string "::1" with Failure _ -> inet_addr_loopback
513 let is_inet6_addr s = String.length s = 16
528 | ADDR_INET of inet_addr * int
530 let domain_of_sockaddr = function
531 ADDR_UNIX _ -> PF_UNIX
532 | ADDR_INET(a, _) -> if is_inet6_addr a then PF_INET6 else PF_INET
534 type shutdown_command =
544 external _socket : socket_domain -> socket_type -> int -> file_descr
546 external _socketpair :
547 socket_domain -> socket_type -> int -> file_descr * file_descr
550 let socket dom typ proto =
551 let s = _socket dom typ proto in
555 let socketpair dom typ proto =
556 let (s1, s2 as spair) = _socketpair dom typ proto in
557 set_nonblock s1; set_nonblock s2;
560 external _accept : file_descr -> file_descr * sockaddr = "unix_accept"
565 let (s, caller as result) = _accept req in
568 with Unix_error((EAGAIN | EWOULDBLOCK), _, _) -> accept req
570 external bind : file_descr -> sockaddr -> unit = "unix_bind"
571 external listen : file_descr -> int -> unit = "unix_listen"
572 external shutdown : file_descr -> shutdown_command -> unit = "unix_shutdown"
573 external getsockname : file_descr -> sockaddr = "unix_getsockname"
574 external getpeername : file_descr -> sockaddr = "unix_getpeername"
576 external _connect : file_descr -> sockaddr -> unit = "unix_connect"
581 with Unix_error((EINPROGRESS | EWOULDBLOCK | EAGAIN), _, _) ->
583 (* Check if it really worked *)
584 ignore(getpeername s)
586 external unsafe_recv :
587 file_descr -> string -> int -> int -> msg_flag list -> int
589 external unsafe_recvfrom :
590 file_descr -> string -> int -> int -> msg_flag list -> int * sockaddr
592 external unsafe_send :
593 file_descr -> string -> int -> int -> msg_flag list -> int
595 external unsafe_sendto :
596 file_descr -> string -> int -> int -> msg_flag list -> sockaddr -> int
597 = "unix_sendto" "unix_sendto_native"
599 let rec recv fd buf ofs len flags =
601 if ofs < 0 || len < 0 || ofs > String.length buf - len
602 then invalid_arg "Unix.recv"
603 else unsafe_recv fd buf ofs len flags
604 with Unix_error((EAGAIN | EWOULDBLOCK), _, _) ->
605 wait_read fd; recv fd buf ofs len flags
607 let rec recvfrom fd buf ofs len flags =
609 if ofs < 0 || len < 0 || ofs > String.length buf - len
610 then invalid_arg "Unix.recvfrom"
611 else unsafe_recvfrom fd buf ofs len flags
612 with Unix_error((EAGAIN | EWOULDBLOCK), _, _) ->
614 recvfrom fd buf ofs len flags
616 let rec send fd buf ofs len flags =
618 if ofs < 0 || len < 0 || ofs > String.length buf - len
619 then invalid_arg "Unix.send"
620 else unsafe_send fd buf ofs len flags
621 with Unix_error((EAGAIN | EWOULDBLOCK), _, _) ->
623 send fd buf ofs len flags
625 let rec sendto fd buf ofs len flags addr =
627 if ofs < 0 || len < 0 || ofs > String.length buf - len
628 then invalid_arg "Unix.sendto"
629 else unsafe_sendto fd buf ofs len flags addr
630 with Unix_error((EAGAIN | EWOULDBLOCK), _, _) ->
632 sendto fd buf ofs len flags addr
634 type socket_bool_option =
646 type socket_int_option =
654 type socket_optint_option = SO_LINGER
656 type socket_float_option =
660 type socket_error_option = SO_ERROR
664 val bool: (socket_bool_option, bool) t
665 val int: (socket_int_option, int) t
666 val optint: (socket_optint_option, int option) t
667 val float: (socket_float_option, float) t
668 val error: (socket_error_option, error option) t
669 val get: ('opt, 'v) t -> file_descr -> 'opt -> 'v
670 val set: ('opt, 'v) t -> file_descr -> 'opt -> 'v -> unit
672 type ('opt, 'v) t = int
678 external get: ('opt, 'v) t -> file_descr -> 'opt -> 'v
680 external set: ('opt, 'v) t -> file_descr -> 'opt -> 'v -> unit
684 let getsockopt fd opt = SO.get SO.bool fd opt
685 let setsockopt fd opt v = SO.set SO.bool fd opt v
687 let getsockopt_int fd opt = SO.get SO.int fd opt
688 let setsockopt_int fd opt v = SO.set SO.int fd opt v
690 let getsockopt_optint fd opt = SO.get SO.optint fd opt
691 let setsockopt_optint fd opt v = SO.set SO.optint fd opt v
693 let getsockopt_float fd opt = SO.get SO.float fd opt
694 let setsockopt_float fd opt v = SO.set SO.float fd opt v
696 let getsockopt_error fd = SO.get SO.error fd SO_ERROR
700 h_aliases : string array;
701 h_addrtype : socket_domain;
702 h_addr_list : inet_addr array }
704 type protocol_entry =
706 p_aliases : string array;
711 s_aliases : string array;
715 external gethostname : unit -> string = "unix_gethostname"
716 external gethostbyname : string -> host_entry = "unix_gethostbyname"
717 external gethostbyaddr : inet_addr -> host_entry = "unix_gethostbyaddr"
718 external getprotobyname : string -> protocol_entry
719 = "unix_getprotobyname"
720 external getprotobynumber : int -> protocol_entry
721 = "unix_getprotobynumber"
722 external getservbyname : string -> string -> service_entry
723 = "unix_getservbyname"
724 external getservbyport : int -> string -> service_entry
725 = "unix_getservbyport"
727 { ai_family : socket_domain;
728 ai_socktype : socket_type;
731 ai_canonname : string }
733 type getaddrinfo_option =
734 AI_FAMILY of socket_domain
735 | AI_SOCKTYPE of socket_type
741 external getaddrinfo_system
742 : string -> string -> getaddrinfo_option list -> addr_info list
745 let getaddrinfo_emulation node service opts =
747 let opt_socktype = ref None
748 and opt_protocol = ref 0
749 and opt_passive = ref false in
751 (function AI_SOCKTYPE s -> opt_socktype := Some s
752 | AI_PROTOCOL p -> opt_protocol := p
753 | AI_PASSIVE -> opt_passive := true
756 (* Determine socket types and port numbers *)
757 let get_port ty kind =
758 if service = "" then [ty, 0] else
760 [ty, int_of_string service]
763 [ty, (getservbyname service kind).s_port]
767 match !opt_socktype with
769 get_port SOCK_STREAM "tcp" @ get_port SOCK_DGRAM "udp"
770 | Some SOCK_STREAM ->
771 get_port SOCK_STREAM "tcp"
773 get_port SOCK_DGRAM "udp"
775 if service = "" then [ty, 0] else [] in
776 (* Determine IP addresses *)
779 if List.mem AI_PASSIVE opts
780 then [inet_addr_any, "0.0.0.0"]
781 else [inet_addr_loopback, "127.0.0.1"]
784 [inet_addr_of_string node, node]
787 let he = gethostbyname node in
789 (fun a -> (a, he.h_name))
790 (Array.to_list he.h_addr_list)
793 (* Cross-product of addresses and ports *)
799 { ai_family = PF_INET;
801 ai_protocol = !opt_protocol;
802 ai_addr = ADDR_INET(addr, port);
803 ai_canonname = name })
807 let getaddrinfo node service opts =
809 List.rev(getaddrinfo_system node service opts)
810 with Invalid_argument _ ->
811 getaddrinfo_emulation node service opts
814 { ni_hostname : string;
815 ni_service : string }
817 type getnameinfo_option =
824 external getnameinfo_system
825 : sockaddr -> getnameinfo_option list -> name_info
828 let getnameinfo_emulation addr opts =
831 { ni_hostname = ""; ni_service = f } (* why not? *)
835 if List.mem NI_NUMERICHOST opts then raise Not_found;
836 (gethostbyaddr a).h_name
838 if List.mem NI_NAMEREQD opts then raise Not_found;
839 string_of_inet_addr a in
842 if List.mem NI_NUMERICSERV opts then raise Not_found;
843 let kind = if List.mem NI_DGRAM opts then "udp" else "tcp" in
844 (getservbyport p kind).s_name
847 { ni_hostname = hostname; ni_service = service }
849 let getnameinfo addr opts =
851 getnameinfo_system addr opts
852 with Invalid_argument _ ->
853 getnameinfo_emulation addr opts
856 mutable c_ignbrk: bool;
857 mutable c_brkint: bool;
858 mutable c_ignpar: bool;
859 mutable c_parmrk: bool;
860 mutable c_inpck: bool;
861 mutable c_istrip: bool;
862 mutable c_inlcr: bool;
863 mutable c_igncr: bool;
864 mutable c_icrnl: bool;
865 mutable c_ixon: bool;
866 mutable c_ixoff: bool;
867 mutable c_opost: bool;
868 mutable c_obaud: int;
869 mutable c_ibaud: int;
870 mutable c_csize: int;
871 mutable c_cstopb: int;
872 mutable c_cread: bool;
873 mutable c_parenb: bool;
874 mutable c_parodd: bool;
875 mutable c_hupcl: bool;
876 mutable c_clocal: bool;
877 mutable c_isig: bool;
878 mutable c_icanon: bool;
879 mutable c_noflsh: bool;
880 mutable c_echo: bool;
881 mutable c_echoe: bool;
882 mutable c_echok: bool;
883 mutable c_echonl: bool;
884 mutable c_vintr: char;
885 mutable c_vquit: char;
886 mutable c_verase: char;
887 mutable c_vkill: char;
888 mutable c_veof: char;
889 mutable c_veol: char;
891 mutable c_vtime: int;
892 mutable c_vstart: char;
893 mutable c_vstop: char
896 external tcgetattr: file_descr -> terminal_io = "unix_tcgetattr"
898 type setattr_when = TCSANOW | TCSADRAIN | TCSAFLUSH
900 external tcsetattr: file_descr -> setattr_when -> terminal_io -> unit
902 external tcsendbreak: file_descr -> int -> unit = "unix_tcsendbreak"
903 external tcdrain: file_descr -> unit = "unix_tcdrain"
905 type flush_queue = TCIFLUSH | TCOFLUSH | TCIOFLUSH
907 external tcflush: file_descr -> flush_queue -> unit = "unix_tcflush"
909 type flow_action = TCOOFF | TCOON | TCIOFF | TCION
911 external tcflow: file_descr -> flow_action -> unit = "unix_tcflow"
913 external setsid : unit -> int = "unix_setsid"
915 (* High-level process management (system, popen) *)
920 execv "/bin/sh" [| "/bin/sh"; "-c"; cmd |]
924 | id -> snd(waitpid [] id)
926 let rec safe_dup fd =
927 let new_fd = dup fd in
931 let res = safe_dup fd in
937 try close fd with Unix_error(_,_,_) -> ()
939 let perform_redirections new_stdin new_stdout new_stderr =
940 let newnewstdin = safe_dup new_stdin in
941 let newnewstdout = safe_dup new_stdout in
942 let newnewstderr = safe_dup new_stderr in
943 safe_close new_stdin;
944 safe_close new_stdout;
945 safe_close new_stderr;
946 dup2 newnewstdin stdin; close newnewstdin;
947 dup2 newnewstdout stdout; close newnewstdout;
948 dup2 newnewstderr stderr; close newnewstderr
950 let create_process cmd args new_stdin new_stdout new_stderr =
954 perform_redirections new_stdin new_stdout new_stderr;
961 let create_process_env cmd args env new_stdin new_stdout new_stderr =
965 perform_redirections new_stdin new_stdout new_stderr;
973 Process of in_channel * out_channel
974 | Process_in of in_channel
975 | Process_out of out_channel
976 | Process_full of in_channel * out_channel * in_channel
978 let popen_processes = (Hashtbl.create 7 : (popen_process, int) Hashtbl.t)
980 let open_proc cmd proc input output toclose =
982 0 -> if input <> stdin then begin dup2 input stdin; close input end;
983 if output <> stdout then begin dup2 output stdout; close output end;
984 List.iter close toclose;
985 begin try execv "/bin/sh" [| "/bin/sh"; "-c"; cmd |]
988 | id -> Hashtbl.add popen_processes proc id
990 let open_process_in cmd =
991 let (in_read, in_write) = pipe() in
992 let inchan = in_channel_of_descr in_read in
993 open_proc cmd (Process_in inchan) stdin in_write [in_read];
997 let open_process_out cmd =
998 let (out_read, out_write) = pipe() in
999 let outchan = out_channel_of_descr out_write in
1000 open_proc cmd (Process_out outchan) out_read stdout [out_write];
1004 let open_process cmd =
1005 let (in_read, in_write) = pipe() in
1006 let (out_read, out_write) = pipe() in
1007 let inchan = in_channel_of_descr in_read in
1008 let outchan = out_channel_of_descr out_write in
1009 open_proc cmd (Process(inchan, outchan)) out_read in_write
1010 [in_read; out_write];
1015 let open_proc_full cmd env proc input output error toclose =
1017 0 -> dup2 input stdin; close input;
1018 dup2 output stdout; close output;
1019 dup2 error stderr; close error;
1020 List.iter close toclose;
1021 begin try execve "/bin/sh" [| "/bin/sh"; "-c"; cmd |] env
1024 | id -> Hashtbl.add popen_processes proc id
1026 let open_process_full cmd env =
1027 let (in_read, in_write) = pipe() in
1028 let (out_read, out_write) = pipe() in
1029 let (err_read, err_write) = pipe() in
1030 let inchan = in_channel_of_descr in_read in
1031 let outchan = out_channel_of_descr out_write in
1032 let errchan = in_channel_of_descr err_read in
1033 open_proc_full cmd env (Process_full(inchan, outchan, errchan))
1034 out_read in_write err_write [in_read; out_write; err_read];
1038 (inchan, outchan, errchan)
1040 let find_proc_id fun_name proc =
1042 let pid = Hashtbl.find popen_processes proc in
1043 Hashtbl.remove popen_processes proc;
1046 raise(Unix_error(EBADF, fun_name, ""))
1048 let rec waitpid_non_intr pid =
1050 with Unix_error (EINTR, _, _) -> waitpid_non_intr pid
1052 let close_process_in inchan =
1053 let pid = find_proc_id "close_process_in" (Process_in inchan) in
1055 snd(waitpid_non_intr pid)
1057 let close_process_out outchan =
1058 let pid = find_proc_id "close_process_out" (Process_out outchan) in
1060 snd(waitpid_non_intr pid)
1062 let close_process (inchan, outchan) =
1063 let pid = find_proc_id "close_process" (Process(inchan, outchan)) in
1065 begin try close_out outchan with Sys_error _ -> () end;
1066 snd(waitpid_non_intr pid)
1068 let close_process_full (inchan, outchan, errchan) =
1070 find_proc_id "close_process_full"
1071 (Process_full(inchan, outchan, errchan)) in
1073 begin try close_out outchan with Sys_error _ -> () end;
1075 snd(waitpid_non_intr pid)
1077 (* High-level network functions *)
1079 let open_connection sockaddr =
1081 socket (domain_of_sockaddr sockaddr) SOCK_STREAM 0 in
1083 connect sock sockaddr;
1084 (in_channel_of_descr sock, out_channel_of_descr sock)
1086 close sock; raise exn
1088 let shutdown_connection inchan =
1089 shutdown (descr_of_in_channel inchan) SHUTDOWN_SEND
1091 let establish_server server_fun sockaddr =
1093 socket (domain_of_sockaddr sockaddr) SOCK_STREAM 0 in
1094 setsockopt sock SO_REUSEADDR true;
1098 let (s, caller) = accept sock in
1099 (* The "double fork" trick, the process which calls server_fun will not
1100 leave a zombie process *)
1102 0 -> if fork() <> 0 then exit 0; (* The son exits, the grandson works *)
1103 let inchan = in_channel_of_descr s in
1104 let outchan = out_channel_of_descr s in
1105 server_fun inchan outchan;
1107 (* The file descriptor was already closed by close_out.
1111 | id -> close s; ignore(waitpid [] id) (* Reclaim the son *)