diff --git a/src/lib/eunix.ml b/src/lib/eunix.ml index 3206819..99cf020 100644 --- a/src/lib/eunix.ml +++ b/src/lib/eunix.ml @@ -18,6 +18,18 @@ let get_user_and_host () = Fmt.str "%s@%s" name host 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 () = match setpgrp 0 0 with 0 -> () | n -> exit n diff --git a/src/lib/eval.ml b/src/lib/eval.ml index 9dff8c4..dad3df3 100644 --- a/src/lib/eval.ml +++ b/src/lib/eval.ml @@ -437,7 +437,8 @@ module Make (S : Types.State) (E : Types.Exec) = struct | None -> Exit.zero ctx | Some job -> if not async then begin - J.await_exit ~pipefail:false job >|= fun () -> ctx + J.await_exit ~pipefail:false ~interactive:ctx.interactive job + >|= fun () -> ctx end else begin Exit.zero { ctx with background_jobs = job :: ctx.background_jobs } diff --git a/src/lib/interactive.ml b/src/lib/interactive.ml index dbbd73d..5417ec5 100644 --- a/src/lib/interactive.ml +++ b/src/lib/interactive.ml @@ -30,6 +30,9 @@ module Make (S : Types.State) (E : Types.Exec) = struct Format.flush_str_formatter () let run ?(prompt = default_prompt) initial_ctx = + Sys.set_signal Sys.sigttou Sys.Signal_ignore; + Sys.set_signal Sys.sigttin Sys.Signal_ignore; + Sys.set_signal Sys.sigtstp Sys.Signal_ignore; let rec loop (ctx : Eval.ctx Exit.t) = Option.iter (Fmt.epr "%s%!") (S.lookup (Exit.value ctx).state ~param:"PS1" diff --git a/src/lib/job.ml b/src/lib/job.ml index 1ce028b..314cade 100644 --- a/src/lib/job.ml +++ b/src/lib/job.ml @@ -21,9 +21,12 @@ module Make (E : Types.Exec) = struct let add_error b t = { t with processes = Nlist.cons (`Error b) t.processes } (* Section 2.9.2 https://pubs.opengroup.org/onlinepubs/9799919799/ *) - let await_exit ~pipefail t = + let await_exit ~pipefail ~interactive t = let await = function - | `Process p -> E.await p + | `Process p -> + if interactive then + Eunix.delegate_control ~pgid:t.id @@ fun () -> E.await p + else E.await p | `Built_in b -> b | `Error n -> Exit.nonzero () n in