mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-04-29 19:30:36 +02:00
Avoid throwing exceptions during early boot if stdin is closed
* libguile/fports.c (scm_i_fdes_is_valid): New internal helper. (scm_i_fdes_to_port): Use new helper. * libguile/fports.h: Declare new helper. * libguile/init.c (scm_standard_stream_to_port): Refactor to use scm_i_fdes_is_valid.
This commit is contained in:
parent
cf693d862d
commit
dbc93d6195
3 changed files with 37 additions and 55 deletions
|
@ -401,6 +401,29 @@ SCM_DEFINE (scm_i_open_file, "open-file", 2, 0, 1,
|
|||
|
||||
/* Building Guile ports from a file descriptor. */
|
||||
|
||||
int
|
||||
scm_i_fdes_is_valid (int fdes, long mode_bits)
|
||||
{
|
||||
#ifdef F_GETFL
|
||||
int flags = fcntl (fdes, F_GETFL, 0);
|
||||
if (flags == -1)
|
||||
return 0;
|
||||
flags &= O_ACCMODE;
|
||||
if (flags == O_RDWR)
|
||||
return 1;
|
||||
if (flags != O_WRONLY && (mode_bits & SCM_WRTNG))
|
||||
return 0;
|
||||
if (flags != O_RDONLY && (mode_bits & SCM_RDNG))
|
||||
return 0;
|
||||
return 1;
|
||||
#else
|
||||
/* If we don't have F_GETFL, as on mingw, at least we can test that
|
||||
it is a valid file descriptor. */
|
||||
struct stat st;
|
||||
return fstat (fdes, &st) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Build a Scheme port from an open file descriptor `fdes'.
|
||||
MODE indicates whether FILE is open for reading or writing; it uses
|
||||
the same notation as open-file's second argument.
|
||||
|
@ -415,27 +438,14 @@ scm_i_fdes_to_port (int fdes, long mode_bits, SCM name, unsigned options)
|
|||
|
||||
if (options & SCM_FPORT_OPTION_VERIFY)
|
||||
{
|
||||
/* Check that the foreign FD is valid and matches the mode
|
||||
bits. */
|
||||
#ifdef F_GETFL
|
||||
int flags = fcntl (fdes, F_GETFL, 0);
|
||||
if (flags == -1)
|
||||
SCM_SYSERROR;
|
||||
flags &= O_ACCMODE;
|
||||
if (flags != O_RDWR
|
||||
&& ((flags != O_WRONLY && (mode_bits & SCM_WRTNG))
|
||||
|| (flags != O_RDONLY && (mode_bits & SCM_RDNG))))
|
||||
errno = 0;
|
||||
if (!scm_i_fdes_is_valid (fdes, mode_bits))
|
||||
{
|
||||
if (errno)
|
||||
SCM_SYSERROR;
|
||||
SCM_MISC_ERROR ("requested file mode not available on fdes",
|
||||
SCM_EOL);
|
||||
}
|
||||
#else
|
||||
/* If we don't have F_GETFL, as on mingw, at least we can test that
|
||||
it is a valid file descriptor. */
|
||||
struct stat st;
|
||||
if (fstat (fdes, &st) != 0)
|
||||
SCM_SYSERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
fp = (scm_t_fport *) scm_gc_malloc_pointerless (sizeof (scm_t_fport),
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef SCM_FPORTS_H
|
||||
#define SCM_FPORTS_H
|
||||
|
||||
/* Copyright 1995-2001,2006,2008-2009,2011-2012,2017-2018
|
||||
/* Copyright 1995-2001,2006,2008-2009,2011-2012,2017-2019
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of Guile.
|
||||
|
@ -86,8 +86,10 @@ enum scm_fport_option
|
|||
that case. */
|
||||
SCM_FPORT_OPTION_NOT_SEEKABLE = 1U<<1
|
||||
};
|
||||
SCM_INTERNAL int scm_i_fdes_is_valid (int fdes, long mode_bits);
|
||||
SCM_INTERNAL SCM scm_i_fdes_to_port (int fdes, long mode_bits, SCM name,
|
||||
unsigned options);
|
||||
|
||||
#endif /* BUILDING_LIBGUILE */
|
||||
|
||||
#endif /* SCM_FPORTS_H */
|
||||
|
|
|
@ -156,49 +156,19 @@
|
|||
|
||||
/* initializing standard and current I/O ports */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int fdes;
|
||||
char *mode;
|
||||
} stream_body_data;
|
||||
|
||||
/* proc to be called in scope of exception handler stream_handler. */
|
||||
static SCM
|
||||
stream_body (void *data)
|
||||
{
|
||||
stream_body_data *body_data = (stream_body_data *) data;
|
||||
SCM port = scm_fdes_to_port (body_data->fdes, body_data->mode, SCM_BOOL_F);
|
||||
scm_set_port_revealed_x (port, SCM_INUM1);
|
||||
return port;
|
||||
}
|
||||
|
||||
/* exception handler for stream_body. */
|
||||
static SCM
|
||||
stream_handler (void *data SCM_UNUSED,
|
||||
SCM tag SCM_UNUSED,
|
||||
SCM throw_args SCM_UNUSED)
|
||||
{
|
||||
return SCM_BOOL_F;
|
||||
}
|
||||
|
||||
/* Convert a file descriptor to a port, using scm_fdes_to_port.
|
||||
- set the revealed count for FILE's file descriptor to 1, so
|
||||
that fdes won't be closed when the port object is GC'd.
|
||||
- catch exceptions: allow Guile to be able to start up even
|
||||
if it has been handed bogus stdin/stdout/stderr. replace the
|
||||
bad ports with void ports. */
|
||||
that fdes won't be closed when the port object is GC'd. */
|
||||
static SCM
|
||||
scm_standard_stream_to_port (int fdes, char *mode)
|
||||
{
|
||||
SCM port;
|
||||
stream_body_data body_data;
|
||||
long mode_bits = scm_mode_bits (mode);
|
||||
|
||||
body_data.fdes = fdes;
|
||||
body_data.mode = mode;
|
||||
port = scm_internal_catch (SCM_BOOL_T, stream_body, &body_data,
|
||||
stream_handler, NULL);
|
||||
if (scm_is_false (port))
|
||||
port = scm_void_port (mode);
|
||||
if (!scm_i_fdes_is_valid (fdes, mode_bits))
|
||||
return scm_void_port (mode);
|
||||
|
||||
SCM port = scm_i_fdes_to_port (fdes, mode_bits, SCM_BOOL_F, 0);
|
||||
scm_set_port_revealed_x (port, SCM_INUM1);
|
||||
return port;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue