let cwd () = Eio_unix.run_in_systhread ~label:"cwd" @@ fun () -> Unix.getcwd () let env () = Eio_unix.run_in_systhread ~label:"env" @@ fun () -> Unix.environment () |> Array.map (Astring.String.cut ~sep:"=") |> Array.to_list |> List.filter_map Fun.id let find_env k = env () |> List.assoc_opt k let put_env ~key ~value = Eio_unix.run_in_systhread ~label:"put_env" @@ fun () -> Unix.putenv key value let get_user_and_host fs = let passwd = Eio.Path.(load (fs / "/etc/passwd")) |> String.split_on_char '\n' |> List.map (String.split_on_char ':') in let uid = Unix.getuid () in let username = List.find_map (function | name :: _ :: m :: _ -> if int_of_string m = uid then Some name else None | _ -> None) passwd in let name = Option.value ~default:"?" username in let host = Unix.gethostname () in Fmt.str "%s@%s" name host external getpgrp : unit -> int = "caml_merry_getpgrp" external tcgetpgrp : Unix.file_descr -> int = "caml_merry_tcgetpgrp" external tcsetpgrp : int -> int -> int = "caml_merry_tcsetpgrp" let delegate_control ~pgid fn = let shell_pid = Unix.getpid () in Fun.protect ~finally:(fun () -> let _ : int = tcsetpgrp 0 shell_pid in ()) (fun () -> match tcsetpgrp (Obj.magic Unix.stdin : int) pgid with | 0 -> fn () | n -> Fmt.failwith "tcsetpgrp: %i" n) external setpgrp : int -> int -> int = "caml_merry_setpgid" let make_process_group () = let pgrp = getpgrp () in let fg_prgp = tcgetpgrp Unix.stdin in if Int.equal pgrp fg_prgp then match setpgrp 0 0 with | 0 -> () | _ -> assert false | exception Unix.Unix_error (Unix.EPERM, _, _) -> () let background () = let _pgrid = Unix.getpid () in () let fd_of_int (fd : int) : Unix.file_descr = Obj.magic fd let with_redirections (rdrs : Types.redirect list) fn = let saved_stdin = Unix.dup Unix.stdin in let saved_stdout = Unix.dup Unix.stdout in let saved_stderr = Unix.dup Unix.stderr in List.iter (function | Types.Redirect (i, fd, _) -> Eio_unix.Fd.use_exn "with_redirections" fd @@ fun fd -> if (Obj.magic fd : int) <> i then Unix.dup2 fd (fd_of_int i) | Types.Close fd -> Eio_unix.Fd.close fd) rdrs; Fun.protect ~finally:(fun () -> Unix.dup2 saved_stdin (fd_of_int 0); Unix.dup2 saved_stdout (fd_of_int 1); Unix.dup2 saved_stderr (fd_of_int 2); Unix.close saved_stdin; Unix.close saved_stdout; Unix.close saved_stderr) fn let with_stdin_in_raw_mode fn = let saved_tio = Unix.tcgetattr Unix.stdin in let tio = { saved_tio with (* input modes *) c_ignpar = true; c_istrip = false; c_inlcr = false; c_igncr = false; c_ixon = false; (* c_ixany = false; *) (* c_iuclc = false; *) c_ixoff = false; (* output modes *) c_opost = true; (* control modes *) c_isig = false; c_icanon = false; c_echo = false; c_echoe = false; c_echok = false; c_echonl = false; (* c_iexten = false; *) (* special characters *) c_vmin = 1; c_vtime = 0; } in Unix.tcsetattr Unix.stdin TCSADRAIN tio; Fun.protect ~finally:(fun () -> Unix.tcsetattr Unix.stdin TCSADRAIN saved_tio) fn module Signals = struct type t = | Interrupt | Quit | Abort | Kill | Alarm | Terminate | Exit | Stop | Hup [@@deriving to_yojson] let of_int = function | i when Int.equal i Sys.sigint -> Interrupt | i when Int.equal i Sys.sigquit -> Quit | i when Int.equal i Sys.sigabrt -> Abort | i when Int.equal i Sys.sigkill -> Kill | i when Int.equal i Sys.sigalrm -> Alarm | i when Int.equal i Sys.sigterm -> Terminate | i when Int.equal i Sys.sigstop -> Stop | i when Int.equal i Sys.sighup -> Hup (* From the manpages *) | 1 -> Hup | 2 -> Interrupt | 3 -> Quit | 6 -> Abort | 9 -> Kill | 14 -> Alarm | 15 -> Terminate | m -> Fmt.invalid_arg "Signal %i not supported yet." m let to_int = function | Interrupt -> Sys.sigint | Quit -> Sys.sigquit | Abort -> Sys.sigabrt | Kill -> Sys.sigkill | Alarm -> Sys.sigalrm | Terminate | Exit -> Sys.sigterm | Stop -> Sys.sigstop | Hup -> Sys.sighup let of_string s = match String.uppercase_ascii s with | "SIGINT" | "INT" -> Interrupt | "SIGQUIT" | "QUIT" -> Quit | "SIGABRT" | "ABRT" -> Abort | "SIGKILL" | "KILL" -> Kill | "SIGALRM" | "ALRM" -> Alarm | "SIGTERM" | "TERM" -> Terminate | "SIGSTOP" | "STOP" -> Stop | "SIGHUP" | "HUP" -> Hup | m -> Fmt.invalid_arg "Signal %s not supported or recognised." m let raise v = Unix.kill (Unix.getpid ()) (to_int v) end