1
(* $Id: netsys_posix.ml 1629 2011-06-16 12:07:10Z gerd $ *)
11
let dlog = Netlog.Debug.mk_dlog "Netsys_posix" Debug.enable
12
let dlogr = Netlog.Debug.mk_dlogr "Netsys_posix" Debug.enable
15
Netlog.Debug.register_module "Netsys_posix" Debug.enable
17
external int64_of_file_descr : Unix.file_descr -> int64
18
= "netsys_int64_of_file_descr"
20
let int_of_file_descr =
21
match Sys.os_type with
22
| "Unix" | "Cygwin" ->
23
(fun fd -> (Obj.magic (fd:file_descr) : int))
25
(fun fd -> invalid_arg "Netsys.int_of_file_descr")
27
let file_descr_of_int =
28
match Sys.os_type with
29
| "Unix" | "Cygwin" ->
30
(fun n -> (Obj.magic (n:int) : file_descr))
32
(fun n -> invalid_arg "Netsys.file_descr_of_int")
34
(* Limits & resources *)
36
external sysconf_open_max : unit -> int = "netsys_sysconf_open_max";;
40
external fchdir : Unix.file_descr -> unit = "netsys_fchdir" ;;
41
external fdopendir : Unix.file_descr -> Unix.dir_handle = "netsys_fdopendir" ;;
43
(* Process groups, sessions, terminals *)
45
external getpgid : int -> int = "netsys_getpgid";;
46
let getpgrp() = getpgid 0;;
47
external setpgid : int -> int -> unit = "netsys_setpgid";;
48
let setpgrp() = setpgid 0 0;;
50
external tcgetpgrp : file_descr -> int = "netsys_tcgetpgrp";;
51
external tcsetpgrp : file_descr -> int -> unit = "netsys_tcsetpgrp";;
53
external ctermid : unit -> string = "netsys_ctermid";;
54
external ttyname : file_descr -> string = "netsys_ttyname";;
56
external getsid : int -> int = "netsys_getsid";;
60
try Unix.openfile (ctermid()) [Unix.O_RDWR] 0
61
with _ -> failwith "Netsys_posix.with_tty: cannot open terminal" in
66
with error -> Unix.close fd; raise error
69
let descr_input_line fd = (* unbuffered! *)
70
let b = Buffer.create 80 in
71
let s = String.create 1 in
75
let n = Unix.read fd s 0 1 in
76
if n > 0 && s.[0] <> '\n' then (
77
Buffer.add_string b s;
78
raise(Unix.Unix_error(Unix.EINTR,"",""))
81
| Unix.Unix_error(Unix.EINTR,_,_) ->
90
let tty_read_password ?(tty=Unix.stdin) prompt =
91
if Unix.isatty tty then (
92
let cleanup = ref [] in
93
let f = Unix.out_channel_of_descr tty in
94
output_string f prompt;
97
Unix.tcflush tty Unix.TCIFLUSH;
98
let p = Unix.tcgetattr tty in
103
Unix.c_echoe = false;
104
Unix.c_echok = false;
105
Unix.c_echonl = false
107
Unix.tcsetattr tty Unix.TCSAFLUSH p';
108
cleanup := (fun () -> Unix.tcsetattr tty Unix.TCSAFLUSH p) :: !cleanup;
110
Sys.signal Sys.sigint (Sys.Signal_handle(fun _ -> raise Sys.Break)) in
111
cleanup := (fun () -> Sys.set_signal Sys.sigint old_sigint) :: !cleanup;
112
let pw = descr_input_line tty in
113
output_string f "\n";
115
List.iter (fun f -> f()) !cleanup;
119
List.iter (fun f -> f()) !cleanup;
120
if error = Sys.Break then (
121
output_string f "\n";
130
(* Users and groups *)
132
external setreuid : int -> int -> unit = "netsys_setreuid";;
133
external setregid : int -> int -> unit = "netsys_setregid";;
137
external pollfd_size : unit -> int = "netsys_pollfd_size"
139
let the_pollfd_size = pollfd_size()
141
let _have_poll = the_pollfd_size > 0
142
let have_poll() = _have_poll
144
type poll_req_events = int
145
type poll_act_events = int
147
{ mutable poll_fd : Unix.file_descr;
148
mutable poll_req_events : poll_req_events;
149
mutable poll_act_events : poll_act_events;
153
| Poll_mem of poll_mem * int (*length*)
154
| Poll_emu of poll_cell array
157
{ poll_fd = Unix.stdin;
162
external mk_poll_mem : int -> poll_mem
163
= "netsys_mk_poll_mem"
165
external set_poll_mem : poll_mem -> int -> Unix.file_descr -> int -> int -> unit
166
= "netsys_set_poll_mem"
168
external get_poll_mem : poll_mem -> int -> (Unix.file_descr * int * int)
169
= "netsys_get_poll_mem"
171
external blit_poll_mem : poll_mem -> int -> poll_mem -> int -> int -> unit
172
= "netsys_blit_poll_mem"
174
external poll_constants : unit -> int array = "netsys_poll_constants"
176
let the_poll_constants = poll_constants()
178
let const_rd_event = the_poll_constants.(0)
179
let const_pri_event = the_poll_constants.(1)
180
let const_wr_event = the_poll_constants.(2)
181
let const_err_event = the_poll_constants.(3)
182
let const_hup_event = the_poll_constants.(4)
183
let const_nval_event = the_poll_constants.(5)
185
let poll_req_events rd wr pri =
186
(if rd then const_rd_event else 0) lor
187
(if wr then const_wr_event else 0) lor
188
(if pri then const_pri_event else 0)
190
let poll_req_triple p =
191
(p land const_rd_event <> 0,
192
p land const_wr_event <> 0,
193
p land const_pri_event <> 0
196
let poll_null_events() = 0
198
let poll_result p = p <> 0
199
let poll_rd_result p = p land const_rd_event <> 0
200
let poll_wr_result p = p land const_wr_event <> 0
201
let poll_pri_result p = p land const_pri_event <> 0
202
let poll_err_result p = p land const_err_event <> 0
203
let poll_hup_result p = p land const_hup_event <> 0
204
let poll_nval_result p = p land const_nval_event <> 0
206
let poll_array_length =
209
| Poll_emu e -> Array.length e
211
let set_poll_cell a k c =
212
if k < 0 || k >= poll_array_length a then
213
invalid_arg "Netsys.set_poll_cell";
216
set_poll_mem s k c.poll_fd c.poll_req_events (* c.poll_revents *) 0
218
e.(k) <- { c with poll_fd = c.poll_fd } (* copy *)
220
let get_poll_cell a k =
221
if k < 0 || k >= poll_array_length a then
222
invalid_arg "Netsys.get_poll_cell";
225
let (fd, ev, rev) = get_poll_mem s k in
226
{ poll_fd = fd; poll_req_events = ev; poll_act_events = rev }
229
{ c with poll_fd = c.poll_fd } (* copy *)
231
let blit_poll_array a1 k1 a2 k2 len =
232
let l1 = poll_array_length a1 in
233
let l2 = poll_array_length a2 in
234
if len < 0 || k1 < 0 || k1+len > l1 || k2 < 0 || k2+len > l2 then
235
invalid_arg "Netsys.get_poll_cell";
237
| (Poll_mem(s1,_), Poll_mem(s2,_)) ->
238
blit_poll_mem s1 k1 s2 k2 len
239
| (Poll_emu e1, Poll_emu e2) ->
240
Array.blit e1 k1 e2 k2 len
244
let create_poll_array n =
246
let s = mk_poll_mem n in
250
let e = Array.create n null_poll_cell in
254
external netsys_poll : poll_mem -> int -> int -> int = "netsys_poll"
257
let concat_fd_list l =
261
Int64.to_string(int64_of_file_descr fd))
267
external netsys_real_select :
268
Unix.file_descr list ->
269
Unix.file_descr list ->
270
Unix.file_descr list ->
272
(Unix.file_descr list * Unix.file_descr list * Unix.file_descr list)
273
= "netsys_real_select"
276
if Sys.os_type = "Win32" then
282
let do_poll a k tmo =
287
(* Emulate poll using Unix.select. This is slow! *)
289
if tmo < 0 then (-1.0) else float tmo *. 0.001 in
290
let l_inp = ref [] in
291
let l_out = ref [] in
292
let l_pri = ref [] in
295
let (f_inp, f_out, f_pri) = poll_req_triple c.poll_req_events in
296
if f_inp then l_inp := c.poll_fd :: !l_inp;
297
if f_out then l_out := c.poll_fd :: !l_out;
298
if f_pri then l_pri := c.poll_fd :: !l_pri;
301
sprintf "poll_emulation request in=%s out=%s pri=%s tmo=%f"
302
(concat_fd_list !l_inp)
303
(concat_fd_list !l_out)
304
(concat_fd_list !l_pri)
306
let (o_inp, o_out, o_pri) =
307
real_select !l_inp !l_out !l_pri tmo' in
309
sprintf "poll_emulation result in=%s out=%s pri=%s"
310
(concat_fd_list o_inp)
311
(concat_fd_list o_out)
312
(concat_fd_list o_pri));
313
let a_inp = Array.of_list o_inp in
314
let a_out = Array.of_list o_out in
315
let a_pri = Array.of_list o_pri in
316
Array.sort Pervasives.compare a_inp;
317
Array.sort Pervasives.compare a_out;
318
Array.sort Pervasives.compare a_pri;
322
let g_inp = Netsys_impl_util.mem_sorted_array c.poll_fd a_inp in
323
let g_out = Netsys_impl_util.mem_sorted_array c.poll_fd a_out in
324
let g_pri = Netsys_impl_util.mem_sorted_array c.poll_fd a_pri in
326
(if g_inp then const_rd_event else 0) lor
327
(if g_out then const_wr_event else 0) lor
328
(if g_pri then const_pri_event else 0) in
329
c.poll_act_events <- rev;
330
if rev <> 0 then incr n
336
if k < 0 || k > poll_array_length a then
337
invalid_arg "Netsys.poll";
339
Netsys_impl_util.slice_time_ms
341
(* tmo0 is now an int in milliseconds *)
342
let n = do_poll a k tmo0 in
343
if n = 0 then None else Some n
351
let restarting_poll a k tmo =
352
Netsys_impl_util.restart_tmo (poll a k) tmo
354
let poll_single fd r w pri tmo =
355
let a = create_poll_array 1 in
356
set_poll_cell a 0 { poll_fd = fd;
357
poll_req_events = poll_req_events r w pri;
358
poll_act_events = poll_null_events()
363
let act_events_of_int n = n
364
let int_of_act_events n = n
366
let req_events_of_int n = n
367
let int_of_req_events n = n
370
(* post fork handlers *)
372
class type post_fork_handler =
375
method run : unit -> unit
379
type t = post_fork_handler
380
let compare = Pervasives.compare
383
module PFH_Set = Set.Make(PFH)
385
let post_fork_registry = ref PFH_Set.empty
386
let post_fork_mutex = !Netsys_oothr.provider # create_mutex()
388
let register_post_fork_handler pfh =
389
post_fork_mutex # lock();
390
post_fork_registry := PFH_Set.add pfh !post_fork_registry;
391
post_fork_mutex # unlock()
393
let remove_post_fork_handler pfh =
394
post_fork_mutex # lock();
395
post_fork_registry := PFH_Set.remove pfh !post_fork_registry;
396
post_fork_mutex # unlock()
398
let run_post_fork_handlers() =
404
prerr_endline("Netsys_posix: Exception in post fork handler "
405
^ pfh#name ^ ": " ^ Netexn.to_string error)
412
type at_flag = AT_EACCESS | AT_SYMLINK_NOFOLLOW | AT_REMOVEDIR
414
(* The stubs assume these type definitions: *)
415
type open_flag1 = Unix.open_flag =
416
O_RDONLY | O_WRONLY | O_RDWR | O_NONBLOCK | O_APPEND | O_CREAT | O_TRUNC
417
| O_EXCL | O_NOCTTY | O_DSYNC | O_SYNC | O_RSYNC
419
type access_permission1 = Unix.access_permission =
420
R_OK | W_OK | X_OK | F_OK
423
external netsys_at_fdcwd : unit -> Unix.file_descr =
426
let at_fdcwd = netsys_at_fdcwd()
428
external have_at : unit -> bool
430
external openat : Unix.file_descr -> string -> Unix.open_flag list ->
431
Unix.file_perm -> Unix.file_descr
433
external faccessat : Unix.file_descr -> string -> Unix.access_permission list ->
436
external mkdirat : Unix.file_descr -> string -> int -> unit
438
external renameat : Unix.file_descr -> string -> Unix.file_descr -> string ->
441
external linkat : Unix.file_descr -> string -> Unix.file_descr -> string ->
444
external unlinkat : Unix.file_descr -> string -> at_flag list -> unit
446
external symlinkat : string -> Unix.file_descr -> string -> unit
448
external mkfifoat : Unix.file_descr -> string -> int -> unit
450
external readlinkat : Unix.file_descr -> string -> string
451
= "netsys_readlinkat"
459
| Wd_fchdir of Unix.file_descr
465
| Pg_join_group of int
468
| Fda_close of Unix.file_descr
469
| Fda_close_ignore of Unix.file_descr
470
| Fda_close_except of bool array
471
| Fda_dup2 of Unix.file_descr * Unix.file_descr
477
external netsys_spawn : wd_spec -> pg_spec -> fd_action list ->
478
sig_action list -> string array ->
479
string -> string array -> int
480
= "netsys_spawn_byte" "netsys_spawn_nat"
482
let spawn ?(chdir = Wd_keep) ?(pg = Pg_keep) ?(fd_actions = [])
483
?(sig_actions = []) ?(env = Unix.environment()) cmd args =
484
(* Fixup: if pg = Pg_new_fg_group, we remove any Sig_default for
485
SIGTTOU from sig_actions. Because of special handling, the effect
486
of Sig_default is enforced by the implementation, but this must be
487
done at [execve] time.
490
if pg = Pg_new_fg_group then
492
(fun spec -> spec <> Sig_default Sys.sigttou)
496
netsys_spawn chdir pg fd_actions sig_actions env cmd args
499
type watched_subprocess =
501
mutable alive : bool;
502
mutable allocated : bool;
505
external netsys_watch_subprocess : int -> int -> bool -> Unix.file_descr * int
506
= "netsys_watch_subprocess"
508
external netsys_ignore_subprocess : int -> unit
509
= "netsys_ignore_subprocess"
511
external netsys_forget_subprocess : int -> unit
512
= "netsys_forget_subprocess"
514
external netsys_get_subprocess_status : int -> Unix.process_status option
515
= "netsys_get_subprocess_status"
517
external install_subprocess_handler : unit -> unit
518
= "netsys_install_sigchld_handler"
520
external subprocess_cleanup_after_fork : unit -> unit
521
= "netsys_subprocess_cleanup_after_fork"
523
external netsys_kill_subprocess : int -> int -> unit
524
= "netsys_kill_subprocess"
526
external netsys_killpg_subprocess : int -> int -> unit
527
= "netsys_killpg_subprocess"
529
external kill_all_subprocesses : int -> bool -> bool -> unit
530
= "netsys_kill_all_subprocesses"
532
external killpg_all_subprocesses : int -> bool -> unit
533
= "netsys_killpg_all_subprocesses"
535
let forget_subprocess ws =
536
if ws.allocated then (
537
netsys_forget_subprocess ws.atom_idx;
538
ws.allocated <- false;
542
let watch_subprocess pid pgid kill_flag =
543
if pid <= 0 || pgid < 0 then
544
invalid_arg "Netsys_posix.watch_subprocess";
545
let fd, atom_idx = netsys_watch_subprocess pid pgid kill_flag in
546
let ws = { atom_idx = atom_idx; alive = true; allocated = true } in
547
Gc.finalise forget_subprocess ws;
550
let ignore_subprocess ws =
552
failwith "Netsys_posix.ignore_subprocess: stale reference";
553
netsys_ignore_subprocess ws.atom_idx;
556
let get_subprocess_status ws =
558
failwith "Netsys_posix.get_subprocess_status: stale reference";
559
netsys_get_subprocess_status ws.atom_idx
561
let kill_subprocess signal ws =
563
netsys_kill_subprocess signal ws.atom_idx
565
let killpg_subprocess signal ws =
567
netsys_killpg_subprocess signal ws.atom_idx
571
register_post_fork_handler
573
method name = "subprocess_cleanup_after_fork"
574
method run = subprocess_cleanup_after_fork
578
let register_subprocess_handler() =
579
Netsys_signal.register_exclusive_handler
580
~name:"Sigchld handler in Netsys_posix"
582
~install:install_subprocess_handler
589
{ nl_CODESET : string;
593
nl_T_FMT_AMPM : string;
631
nl_ABMON_10 : string;
632
nl_ABMON_11 : string;
633
nl_ABMON_12 : string;
635
nl_ERA_D_FMT : string;
636
nl_ERA_D_T_FMT : string;
637
nl_ERA_T_FMT : string;
638
nl_ALT_DIGITS : string;
639
nl_RADIXCHAR : string;
643
nl_CRNCYSTR : string;
646
external netsys_query_langinfo : string -> langinfo = "netsys_query_langinfo"
648
let cached_langinfo = ref None
650
let query_langinfo locale =
651
if locale = "" then (
652
match !cached_langinfo with
654
let li = netsys_query_langinfo "" in
655
cached_langinfo := Some li;
660
netsys_query_langinfo locale
666
type level = Netlog.level
669
| LOG_EMERG | LOG_ALERT | LOG_CRIT | LOG_ERR | LOG_WARNING
670
| LOG_NOTICE | LOG_INFO | LOG_DEBUG
677
`Warning, LOG_WARNING;
683
type syslog_facility =
706
type m_syslog_facility =
729
[ `Authpriv, LOG_AUTHPRIV;
748
`Default, LOG_DEFAULT;
759
type m_syslog_option =
766
let trans_syslog_option =
774
external netsys_openlog :
775
string option -> m_syslog_option list -> m_syslog_facility -> unit
778
external netsys_syslog :
779
m_syslog_facility -> m_level -> string -> unit
782
external netsys_closelog : unit -> unit = "netsys_closelog"
784
let openlog id_opt opts fac =
789
(fun p -> List.assoc p trans_syslog_option)
792
( List.assoc fac trans_facility )
794
| Not_found -> assert false
796
let syslog fac lev msg =
799
( List.assoc fac trans_facility )
800
( List.assoc lev trans_level )
803
| Not_found -> assert false
805
let closelog = netsys_closelog
810
external fsync : Unix.file_descr -> unit = "netsys_fsync"
811
external fdatasync : Unix.file_descr -> unit = "netsys_fdatasync"
814
(* Optional POSIX functions *)
816
external have_fadvise : unit -> bool = "netsys_have_posix_fadvise"
819
| POSIX_FADV_SEQUENTIAL
822
| POSIX_FADV_WILLNEED
823
| POSIX_FADV_DONTNEED
830
external fadvise : Unix.file_descr -> int64 -> int64 -> advice -> unit
833
external have_fallocate : unit -> bool = "netsys_have_posix_fallocate"
834
external fallocate : Unix.file_descr -> int64 -> int64 -> unit
837
(* POSIX shared memory *)
839
external have_posix_shm : unit -> bool = "netsys_have_posix_shm"
846
external shm_open : string -> shm_open_flag list -> int -> file_descr
848
external shm_unlink : string -> unit = "netsys_shm_unlink"
850
let shm_create prefix size =
851
let pid = Unix.getpid() in
852
let t = Unix.gettimeofday() in
854
let id = sprintf "%d/%f/%d" pid t n in
855
let dg = Digest.to_hex (Digest.string id) in
856
let dg8 = String.sub dg 0 8 in
857
let name = sprintf "%s_%s" prefix dg8 in
861
name [SHM_O_RDWR; SHM_O_CREAT; SHM_O_EXCL ] 0o600 in
862
Unix.fchmod fd 0o600;
863
Unix.ftruncate fd size;
866
| Unix.Unix_error(Unix.EEXIST,_,_) ->
871
type sem_kind = [ `Named | `Anonymous ]
875
type 'sem_kind semaphore =
876
Netsys_types.memory * sem_rep
877
(* We keep a reference to the bigarray to prevent that it is
878
collected while a semaphore is stored in it
881
type named_semaphore = [ `Named ] semaphore
882
type anon_sempahore = [ `Anonymous ] semaphore
888
type sem_wait_behavior =
893
Bigarray.Array1.create Bigarray.char Bigarray.c_layout 0
895
external have_posix_semaphores : unit -> bool
898
external netsys_sem_size : unit -> int
901
external netsys_sem_value_max : unit -> int
902
= "netsys_sem_value_max"
904
let sem_size = netsys_sem_size()
906
let sem_value_max = netsys_sem_value_max()
909
external netsys_sem_open :
910
string -> sem_open_flag list -> int -> int -> sem_rep
913
let sem_open name flags mode init_value =
914
if init_value < 0 || init_value > sem_value_max then
915
invalid_arg "Netsys_posix.sem_open";
916
let sr = netsys_sem_open name flags mode init_value in
919
external netsys_sem_close : sem_rep -> unit
922
let sem_close (_,sr) = netsys_sem_close sr
924
external sem_unlink : string -> unit
925
= "netsys_sem_unlink"
927
let sem_create prefix initval =
928
let pid = Unix.getpid() in
929
let t = Unix.gettimeofday() in
931
let id = sprintf "%d/%f/%d" pid t n in
932
let dg = Digest.to_hex (Digest.string id) in
933
let dg8 = String.sub dg 0 8 in
934
let name = sprintf "%s_%s" prefix dg8 in
938
name [SEM_O_CREAT; SEM_O_EXCL] 0o600 initval in
941
| Unix.Unix_error(Unix.EEXIST,_,_) ->
946
external netsys_sem_init :
947
Netsys_types.memory -> int -> bool -> int -> sem_rep
950
let sem_init mem pos pshared init_value =
951
if pos < 0 || pos > Bigarray.Array1.dim mem - sem_size then
952
invalid_arg "Netsys_posix.sem_init";
953
if init_value < 0 || init_value > sem_value_max then
954
invalid_arg "Netsys_posix.sem_init";
955
let sr = netsys_sem_init mem pos pshared init_value in
958
external netsys_as_sem : Netsys_types.memory -> int -> sem_rep
962
if pos < 0 || pos > Bigarray.Array1.dim mem - sem_size then
963
invalid_arg "Netsys_posix.as_sem";
964
let sr = netsys_as_sem mem pos in
967
external netsys_sem_destroy : sem_rep -> unit
968
= "netsys_sem_destroy"
970
let sem_destroy (_,sr) = netsys_sem_destroy sr
972
external netsys_sem_getvalue : sem_rep -> int
973
= "netsys_sem_getvalue"
975
let sem_getvalue (_,sr) = netsys_sem_getvalue sr
977
external netsys_sem_post : sem_rep -> unit
980
let sem_post (_,sr) = netsys_sem_post sr
982
external netsys_sem_wait : sem_rep -> sem_wait_behavior -> unit
985
let sem_wait (_,sr) b = netsys_sem_wait sr b
989
| Ioprio_process of int
999
external ioprio_get : ioprio_target -> ioprio = "netsys_ioprio_get"
1000
external ioprio_set : ioprio_target -> ioprio -> unit = "netsys_ioprio_set"
1003
try let _ = ioprio_get(Ioprio_process(Unix.getpid())) in true