1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-04-30 03:40:34 +02:00

fport_print: handle ttyname ENODEV

In some situations, ttyname may return ENODEV even though isatty is
true.  From ttyname(3):

  A process that keeps a file descriptor that refers to a pts(4) device
  open when switching to another mount namespace that uses a different
  /dev/ptmx instance may still accidentally find that a device path of
  the same name for that file descriptor exists.  However, this device
  path refers to a different device and thus can't be used to access the
  device that the file descriptor refers to.  Calling ttyname() or
  ttyname_r() on the file descriptor in the new mount namespace will
  cause these functions to return NULL and set errno to ENODEV.

Observed in a Debian riscv64 porterbox schroot.

When ttyname fails with ENODEV, just include the file descriptor integer
value instead.  Call ttyname() directly to avoid having to catch the
ENODEV.

* libguile/fports.c (fport_print): fall back to the integer fd when
ttyname() fails with ENODEV.
This commit is contained in:
Rob Browning 2025-01-17 11:45:26 -06:00
parent 63756efbc5
commit 48b1c4eff4
2 changed files with 27 additions and 5 deletions

5
NEWS
View file

@ -71,6 +71,11 @@ every line in a file.
tag for their type (e.g. ending up tagged as immediates SCM_IMP()).
** `readdir` and `ttyname` now release scm_i_misc_mutex during asyncs
This avoids potential deadlocks.
** Displaying a `port` won't fail when `ttyname` returns ENODEV
`ttyname` may return ENODEV even when the port `isatty()`, and
previously Guile would pass through the related exception. Now it
prints the file descriptor instead (as it does when `ttyname` isn't
available or the port isn't a tty).
Changes in 3.0.10 (since 3.0.9)

View file

@ -554,6 +554,7 @@ SCM_DEFINE (scm_adjust_port_revealed_x, "adjust-port-revealed!", 2, 0, 0,
#define FUNC_NAME "fport_print"
static int
fport_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
{
@ -570,12 +571,27 @@ fport_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
scm_putc (' ', port);
fdes = (SCM_FSTREAM (exp))->fdes;
#if (defined HAVE_TTYNAME) && (defined HAVE_POSIX)
if (isatty (fdes))
scm_display (scm_ttyname (exp), port);
#if (!defined HAVE_TTYNAME) || (!defined HAVE_POSIX)
scm_intprint (fdes, 10, port);
#else
if (!isatty (fdes))
scm_intprint (fdes, 10, port);
else
#endif /* HAVE_TTYNAME */
scm_intprint (fdes, 10, port);
{
char *name = 0;
SCM_I_LOCKED_SYSCALL(&scm_i_misc_mutex,
char *n = ttyname (fdes);
if (n) name = strdup (n));
if (name)
scm_display (scm_take_locale_string (name), port);
else if (errno == ENODEV)
// In some situations ttyname may return ENODEV even though
// isatty is true. See GNU/Linux ttyname(3) as an example.
scm_intprint (fdes, 10, port);
else
SCM_SYSERROR;
}
#endif // (defined HAVE_TTYNAME) && (defined HAVE_POSIX)
}
else
{
@ -586,6 +602,7 @@ fport_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
scm_putc ('>', port);
return 1;
}
#undef FUNC_NAME
/* fill a port's read-buffer with a single read. returns the first
char or EOF if end of file. */