-
Notifications
You must be signed in to change notification settings - Fork 75
support for creating ptys and a login_tty fork_action #531
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
[@@@alert "-unstable"] | ||
|
||
module Fd = Fd | ||
module Pty = Pty | ||
module Resource = Resource | ||
module Private = Private | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
/* | ||
* Copyright (c) 2004 Anil Madhavapeddy <[email protected]> | ||
* Copyright (c) 2020–2021 Craig Ferguson <[email protected]> | ||
* | ||
* Permission to use, copy, modify, and distribute this software for any | ||
* purpose with or without fee is hereby granted, provided that the above | ||
* copyright notice and this permission notice appear in all copies. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
*/ | ||
|
||
|
||
#include <stdio.h> | ||
#include <errno.h> | ||
#include <paths.h> | ||
#include <fcntl.h> | ||
#include <string.h> | ||
#include <termios.h> | ||
#include <unistd.h> | ||
#include <sys/ioctl.h> | ||
#include <signal.h> | ||
#include <limits.h> | ||
|
||
#include <pty.h> | ||
#include <utmp.h> | ||
|
||
#include <caml/mlvalues.h> | ||
#include <caml/alloc.h> | ||
#include <caml/memory.h> | ||
#include <caml/fail.h> | ||
#include <caml/callback.h> | ||
#include <caml/signals.h> | ||
#include <caml/unixsupport.h> | ||
|
||
value eio_unix_open_pty(value v_unit) | ||
{ | ||
CAMLparam1 (v_unit); | ||
char namebuf[4096]; /* Not PATH_MAX due to portability issues */ | ||
int i, masterfd, slavefd; | ||
CAMLlocal1(v_ret); | ||
|
||
i = openpty(&masterfd, &slavefd, namebuf, NULL, NULL); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The man-page notes that:
However, In a multi-domain program, all FDs must be created close-on-exec atomically, or they can leak. https://www.austingroupbugs.net/view.php?id=411 says:
However, it's not clear how widely-supported that is. The man-page for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems to come down to using either BSD-style pty handling (openpty) or Unix98-style handling (posix_openpt). The latter seems very much preferred, and a quick smoke test on macOS, Linux and OpenBSD shows posix_openpt is present there. I'll have a go at switching this PR to using /dev/ptmx instead -- there's code in portable OpenSSH to use as a guide. |
||
if (i < 0) | ||
caml_uerror("openpty", Nothing); | ||
|
||
v_ret = caml_alloc_small(3, 0); | ||
Store_field(v_ret, 0, Val_int(masterfd)); | ||
Store_field(v_ret, 1, Val_int(slavefd)); | ||
Store_field(v_ret, 2, caml_copy_string(namebuf)); | ||
CAMLreturn (v_ret); | ||
} | ||
|
||
value eio_unix_window_size(value pty, value pty_window) | ||
{ | ||
CAMLparam2 (pty, pty_window); | ||
int ptyfd; | ||
struct winsize w; | ||
w.ws_row = Int32_val(Field(pty_window, 0)); | ||
w.ws_col = Int32_val(Field(pty_window, 1)); | ||
w.ws_xpixel = Int32_val(Field(pty_window, 2)); | ||
w.ws_ypixel = Int32_val(Field(pty_window, 3)); | ||
ptyfd = Int_val(Field(pty, 0)); | ||
ioctl(ptyfd, TIOCSWINSZ, &w); | ||
CAMLreturn (Val_unit); | ||
} | ||
|
||
value eio_unix_tty_window_size(value unit) | ||
{ | ||
CAMLparam1 (unit); | ||
CAMLlocal1(pty_window); | ||
|
||
struct winsize w; | ||
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) == -1) | ||
memset(&w, 0, sizeof(w)); | ||
pty_window = caml_alloc_small(4, 0); | ||
Store_field(pty_window, 0, caml_copy_int32(w.ws_row)); | ||
Store_field(pty_window, 1, caml_copy_int32(w.ws_col)); | ||
Store_field(pty_window, 2, caml_copy_int32(w.ws_xpixel)); | ||
Store_field(pty_window, 3, caml_copy_int32(w.ws_ypixel)); | ||
CAMLreturn (pty_window); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
type pty = { | ||
masterfd : Unix.file_descr; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know this is the terminology used by pseudoterminal at some point, but it's problematic and not even that technical. Could we change it ? I've seen others use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I looked into this while experimenting with https://github.com/RyanGibb/ocaml-exec-shell. It seems UNIX/POSIX/Linux use the existing terminology and I couldn't find any discussions around changing it. A relevant thread is in the glibc mail archive where a number of alternatives are discussed. I couldn't see a consensus on new terminology, but changing master and slave to pty and tty respectively, with 'pseudoterminal device' and 'terminal device' in prose, seemed popular. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using the pty and terminal device terminology is fine by me, of course. I'll do that in the next revision of this diff. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A reinforcement that this is established terminology is it's usage in the openssh source: https://github.com/openssh/openssh-portable/blob/2709809fd616a0991dc18e3a58dea10fb383c3f0/sshpty.c#L71 |
||
slavefd : Unix.file_descr; | ||
Comment on lines
+2
to
+3
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The public interface should use |
||
name : string; | ||
} | ||
|
||
type pty_window = { | ||
row : int32; | ||
col : int32; | ||
xpixel : int32; | ||
ypixel : int32 | ||
} | ||
|
||
external open_pty : unit -> pty = "eio_unix_open_pty" | ||
external set_window_size : pty -> pty_window -> unit = "eio_unix_window_size" | ||
external tty_window_size : unit -> pty_window = "eio_unix_tty_window_size" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It needs to exit if there's an error, since the parent will assume the child failed to start. I'm also using
eio_unix_fork_error
here for consistency with the others, but maybe the others should be changed instead.