···11+open Eio.Std
22+33+let resolve_program name =
44+ if not (String.contains name '/') then
55+ Sys.getenv_opt "PATH"
66+ |> Option.value ~default:"/bin:/usr/bin"
77+ |> String.split_on_char ':'
88+ |> List.find_map (fun dir ->
99+ let p = Filename.concat dir name in
1010+ if Sys.file_exists p then Some p else None)
1111+ else if Sys.file_exists name then Some name
1212+ else None
1313+1414+let read_of_fd ~sw ~default ~to_close = function
1515+ | None -> default
1616+ | Some f -> (
1717+ match Eio_unix.Resource.fd_opt f with
1818+ | Some fd -> fd
1919+ | None ->
2020+ let r, w = Eio_unix.pipe sw in
2121+ Fiber.fork ~sw (fun () ->
2222+ Eio.Flow.copy f w;
2323+ Eio.Flow.close w);
2424+ let r = Eio_unix.Resource.fd r in
2525+ to_close := r :: !to_close;
2626+ r)
2727+2828+let write_of_fd ~sw ~default ~to_close = function
2929+ | None -> default
3030+ | Some f -> (
3131+ match Eio_unix.Resource.fd_opt f with
3232+ | Some fd -> fd
3333+ | None ->
3434+ let r, w = Eio_unix.pipe sw in
3535+ Fiber.fork ~sw (fun () ->
3636+ Eio.Flow.copy r f;
3737+ Eio.Flow.close r);
3838+ let w = Eio_unix.Resource.fd w in
3939+ to_close := w :: !to_close;
4040+ w)
4141+4242+let with_close_list fn =
4343+ let to_close = ref [] in
4444+ let close () = List.iter Eio_unix.Fd.close !to_close in
4545+ match fn to_close with
4646+ | x ->
4747+ close ();
4848+ x
4949+ | exception ex ->
5050+ let bt = Printexc.get_raw_backtrace () in
5151+ close ();
5252+ Printexc.raise_with_backtrace ex bt
5353+5454+let get_executable ~args = function
5555+ | Some exe -> exe
5656+ | None -> (
5757+ match args with
5858+ | [] -> invalid_arg "Arguments list is empty and no executable given!"
5959+ | x :: _ -> (
6060+ match resolve_program x with
6161+ | Some x -> x
6262+ | None -> raise (Eio.Process.err (Executable_not_found x))))
6363+6464+let get_env = function Some e -> e | None -> Unix.environment ()
6565+6666+let spawn_unix () ~sw ?cwd ?pgid ?uid ?gid ~env ~fds ~executable args =
6767+ let open Eio_posix in
6868+ let actions =
6969+ Low_level.Process.Fork_action.
7070+ [ inherit_fds fds; execve executable ~argv:(Array.of_list args) ~env ]
7171+ in
7272+ let actions =
7373+ match pgid with
7474+ | None -> actions
7575+ | Some pgid -> Low_level.Process.Fork_action.setpgid pgid :: actions
7676+ in
7777+ let actions =
7878+ match uid with
7979+ | None -> actions
8080+ | Some uid -> Eio_unix.Private.Fork_action.setuid uid :: actions
8181+ in
8282+ let actions =
8383+ match gid with
8484+ | None -> actions
8585+ | Some gid -> Eio_unix.Private.Fork_action.setgid gid :: actions
8686+ in
8787+ let with_actions cwd fn =
8888+ match cwd with
8989+ | None -> fn actions
9090+ | Some ((dir, path) : Eio.Fs.dir_ty Eio.Path.t) -> (
9191+ match Eio_posix__.Fs.as_posix_dir dir with
9292+ | None -> Fmt.invalid_arg "cwd is not an OS directory!"
9393+ | Some dirfd ->
9494+ Switch.run ~name:"spawn_unix" @@ fun launch_sw ->
9595+ let cwd =
9696+ Eio_posix__.Err.run
9797+ (fun () ->
9898+ let flags = Low_level.Open_flags.(rdonly + directory) in
9999+ Low_level.openat ~sw:launch_sw ~mode:0 dirfd path flags)
100100+ ()
101101+ in
102102+ fn (Low_level.Process.Fork_action.fchdir cwd :: actions))
103103+ in
104104+ with_actions cwd @@ fun actions ->
105105+ Eio_posix__.Process.process (Low_level.Process.spawn ~sw actions)
106106+107107+let run ~sw _ ?stdin ?stdout ?stderr ?(fds = []) ?cwd ?env ?executable args =
108108+ with_close_list @@ fun to_close ->
109109+ let stdin_fd = read_of_fd ~sw stdin ~default:Eio_unix.Fd.stdin ~to_close in
110110+ let stdout_fd =
111111+ write_of_fd ~sw stdout ~default:Eio_unix.Fd.stdout ~to_close
112112+ in
113113+ let stderr_fd =
114114+ write_of_fd ~sw stderr ~default:Eio_unix.Fd.stderr ~to_close
115115+ in
116116+ let check_fd n (m, _, _) = Int.equal n m in
117117+ let fd_exists n = List.exists (check_fd n) fds in
118118+ let fds =
119119+ (if fd_exists 0 then [] else [ (0, stdin_fd, `Blocking) ])
120120+ @ (if fd_exists 1 then [] else [ (1, stdout_fd, `Blocking) ])
121121+ @ (if fd_exists 2 then [] else [ (2, stderr_fd, `Blocking) ])
122122+ @ fds
123123+ in
124124+ let executable = get_executable executable ~args in
125125+ let env = get_env env in
126126+ spawn_unix ~sw ?cwd ~fds ~env ~executable () args
+2-3
src/lib/posix/merry_posix.ml
···66 type t = { mgr : Eio_unix.Process.mgr_ty Eio_unix.Process.mgr }
77 type fork_action = unit
8899- let exec ?fork_actions:_ ?stdin ?stdout ?stderr t s =
1010- (* let fds = List.map (fun (i, fd) -> (i, fd, `Nonblocking)) fds in *)
99+ let exec ?fork_actions:_ ?(fds = []) ?stdin ?stdout ?stderr t args =
1110 Eio.Switch.run @@ fun sw ->
1212- Eio.Process.spawn ~sw ?stdin ?stdout ?stderr t.mgr s |> Eio.Process.await
1111+ Exec.run ~sw ~fds ?stdin ?stdout ?stderr t args |> Eio.Process.await
1312 |> function
1413 | `Exited n -> n
1514 | `Signaled n -> n
+3-2
src/lib/types.ml
···31313232 val exec :
3333 ?fork_actions:fork_action list ->
3434- ?stdin:[> Eio__Flow.source_ty ] Eio_unix.source ->
3434+ ?fds:(int * Eio_unix.Fd.t * Eio_unix.Private.Fork_action.blocking) list ->
3535+ ?stdin:_ Eio_unix.source ->
3536 ?stdout:_ Eio_unix.sink ->
3636- ?stderr:[> Eio__Flow.sink_ty ] Eio_unix.source ->
3737+ ?stderr:_ Eio_unix.sink ->
3738 t ->
3839 string list ->
3940 int