Module Os.Pty

Executing commands in pseudoterminals.

This module provides a convenience abstraction to interact with commands spawned in pseudoterminals. It can be used to script terminal interactions. See an example.

The TTY demystified is a good read to clear up the mind about terminals.

TODO

Pseudoterminals

type t

The type for pseudoterminals.

These values encapsulate a pseudoterminal device pair returned by Fd.openpty and a process identifiers of a command spawn.

val open_with_spawn : ?env:Env.assignments -> ?cwd:Fpath.t -> ?stdin:Cmd.stdi -> ?stdout:Cmd.stdo -> ?stderr:Cmd.stdo -> Cmd.t -> (t, string) Stdlib.result

open_with_spawn cmd is like Cmd.spawn, except it allocates a pseudoterminal device pair and uses its terminal device for the spawn's stdin, stdout and stderr (unless differently specified). The returned pseudoterminal value can be used to interact with the process and must eventually be closed.

val close_noerr : t -> unit

close_noerr pty closes pty and in particular, all file descriptors held by it.

FIXME The function does not wait on the underlying the spawn. FIXME Should it kill and reap the process ?

val with_spawn : ?env:Env.assignments -> ?cwd:Fpath.t -> ?stdin:Cmd.stdi -> ?stdout:Cmd.stdo -> ?stderr:Cmd.stdo -> Cmd.t -> (t -> 'a) -> ('a, string) Stdlib.result

with_spawn cmd f does open_with_spawn cmd to get a pty and calls f pty. The function guarantees that when it returns pty was closed by close_noerr.

Operations

val write : t -> string -> (unit, string) Stdlib.result

write pty s writes s on the pseudoterminal device of pty.

val read : ?timeout:Mtime.Span.t -> ?max:int -> t -> (string option, string) Stdlib.result

read pty reads a string None is returned if eof or timeout, if timeout is unspecified then blocks forever.

val seek : ?log:bool -> ?timeout:Mtime.Span.t -> t -> string -> (unit, string) Stdlib.result

seek pty mark reads and drops pty input until the mark is seen. The next read returns the bytes after the mark.

val interact : t -> (unit, string) Stdlib.result

interact pty, connects the current process stdin and stdout to the pseudo terminal device of pty.

Note. This sets Unix.stdin to raw mode for the duration of the call.

WARNING/TODO. For now you you need to Fd.close_noerr tty for that to return when the child exits.

Properties

Warning. Performing operations on the the returned values here may have effects on the pty operations (for good or bad).

val pty : t -> Unix.file_descr

pty pty is the (controlling) pseudoterminal device of pty.

val tty : t -> Unix.file_descr

tty pty is the (controlled) terminal device of pty.

val pid : t -> Cmd.pid

pid pty is the process identifier of the process to which the terminal device of pty is connected.

val echo : t -> (bool, string) Stdlib.result

echo pty is true iff pty's termios is set to echo.

val set_echo : t -> bool -> (unit, string) Stdlib.result

set_echo pty flag sets echoing to flag.

Example

  let session ~user ~password =
    Result.join @@ Os.Pty.with_spawn (Cmd.tool "login") @@ fun pty ->
    Os.Fd.close_noerr (Os.Pty.tty pty);
    let* () = Os.Pty.seek pty "login:" in
    let* () = Os.Pty.write pty (user ^ "\n") in
    let* () = Os.Pty.seek pty "Password:" in
    let* () = Os.Pty.write pty (password ^ "\n") in
    print_endline "Login successful, have fun, use Ctrl-D to exit";
    Os.Pty.interact pty