summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy Wingo <wingo@pobox.com>2012-02-08 20:08:15 +0100
committerAndy Wingo <wingo@pobox.com>2012-02-14 22:47:15 +0100
commit7565b9fc09242b0adfd81f1390e75ced3f894078 (patch)
tree1e869b5f16d61e00b5719fd184bc5c9de06ac24e
parenta01a9308f051ee1c7e214642d43a750dcd6dce7f (diff)
downloadguile-7565b9fc09242b0adfd81f1390e75ced3f894078.tar.gz
add file-port-close-on-exec?; popen takes advantage of it.
* libguile/fports.c (scm_i_evict_port): Use F_DUPFD_CLOEXEC if the port is CLOEXEC. (scm_file_port_close_on_exec_p): New interface. (scm_i_fdes_to_port): Use F_GETFD on the fd to see if it is cloexec, and if it is, mark it in the scm_t_fport. That way popen.scm won't have to do anything about it. * module/ice-9/popen.scm (ensure-fdes): No need for false-if-exception here. (open-process): Rework the port-for-each call to not bother with file descriptors that are CLOEXEC.
-rw-r--r--libguile/fports.c33
-rw-r--r--libguile/fports.h5
-rw-r--r--module/ice-9/popen.scm21
3 files changed, 48 insertions, 11 deletions
diff --git a/libguile/fports.c b/libguile/fports.c
index bb998e7c4..7807fcb07 100644
--- a/libguile/fports.c
+++ b/libguile/fports.c
@@ -1,5 +1,5 @@
/* Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
- * 2004, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+ * 2004, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -21,6 +21,7 @@
#define _LARGEFILE64_SOURCE /* ask for stat64 etc */
#define _GNU_SOURCE /* ask for LONG_LONG_MAX/LONG_LONG_MIN */
+#define _POSIX_C_SOURCE 200809L /* F_DUPFD_CLOEXEC */
#ifdef HAVE_CONFIG_H
# include <config.h>
@@ -259,7 +260,13 @@ scm_i_evict_port (void *closure, SCM port)
if ((fp != NULL) && (fp->fdes == fd))
{
- fp->fdes = dup (fd);
+ if (fp->cloexec_p)
+ /* The result will be 3 or more. Presumably we don't want
+ to accidentally end on 0, 1, or 2. */
+ fp->fdes = fcntl (fd, F_DUPFD_CLOEXEC, 3);
+ else
+ fp->fdes = dup (fd);
+
if (fp->fdes == -1)
scm_syserror ("scm_evict_ports");
scm_set_port_revealed_x (port, scm_from_int (0));
@@ -284,6 +291,17 @@ SCM_DEFINE (scm_file_port_p, "file-port?", 1, 0, 0,
#undef FUNC_NAME
+SCM_DEFINE (scm_file_port_close_on_exec_p, "file-port-close-on-exec?", 1, 0, 0,
+ (SCM fport),
+ "Determine whether @var{fobj} was created with the @code{FD_CLOEXEC} flag set.")
+#define FUNC_NAME s_scm_file_port_close_on_exec_p
+{
+ SCM_VALIDATE_OPFPORT (1, fport);
+ return scm_from_bool (SCM_FSTREAM (fport)->cloexec_p);
+}
+#undef FUNC_NAME
+
+
static SCM sys_file_port_name_canonicalization;
SCM_SYMBOL (sym_relative, "relative");
SCM_SYMBOL (sym_absolute, "absolute");
@@ -537,6 +555,7 @@ scm_i_fdes_to_port (int fdes, long mode_bits, SCM name)
SCM port;
scm_t_fport *fp;
int flags;
+ int fd_flags;
/* test that fdes is valid. */
#ifdef __MINGW32__
@@ -554,9 +573,19 @@ scm_i_fdes_to_port (int fdes, long mode_bits, SCM name)
SCM_MISC_ERROR ("requested file mode not available on fdes", SCM_EOL);
}
+#ifdef F_GETFD
+ fd_flags = fcntl (fdes, F_GETFD, 0);
+#else
+ fd_flags = 0;
+#endif
+ if (fd_flags == -1)
+ SCM_SYSERROR;
+
fp = (scm_t_fport *) scm_gc_malloc_pointerless (sizeof (scm_t_fport),
"file port");
fp->fdes = fdes;
+ fp->cloexec_p = fd_flags & FD_CLOEXEC ? 1 : 0;
+ fp->reserved = 0;
port = scm_c_make_port (scm_tc16_fport, mode_bits, (scm_t_bits)fp);
diff --git a/libguile/fports.h b/libguile/fports.h
index 32b6a5947..7a1713187 100644
--- a/libguile/fports.h
+++ b/libguile/fports.h
@@ -3,7 +3,7 @@
#ifndef SCM_FPORTS_H
#define SCM_FPORTS_H
-/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2006, 2008, 2009, 2011 Free Software Foundation, Inc.
+/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2006, 2008, 2009, 2011, 2012 Free Software Foundation, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
@@ -32,6 +32,8 @@
/* struct allocated for each buffered FPORT. */
typedef struct scm_t_fport {
int fdes; /* file descriptor. */
+ int cloexec_p : 1;
+ int reserved : 31;
} scm_t_fport;
SCM_API scm_t_bits scm_tc16_fport;
@@ -54,6 +56,7 @@ SCM_API void scm_evict_ports (int fd);
SCM_API SCM scm_open_file (SCM filename, SCM modes);
SCM_API SCM scm_fdes_to_port (int fdes, char *mode, SCM name);
SCM_API SCM scm_file_port_p (SCM obj);
+SCM_API SCM scm_file_port_close_on_exec_p (SCM fport);
SCM_INTERNAL void scm_init_fports (void);
/* internal functions */
diff --git a/module/ice-9/popen.scm b/module/ice-9/popen.scm
index b9debd444..805b7315c 100644
--- a/module/ice-9/popen.scm
+++ b/module/ice-9/popen.scm
@@ -1,6 +1,6 @@
;; popen emulation, for non-stdio based ports.
-;;;; Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2010, 2011 Free Software Foundation, Inc.
+;;;; Copyright (C) 1998, 1999, 2000, 2001, 2003, 2006, 2010, 2011, 2012 Free Software Foundation, Inc.
;;;;
;;;; This library is free software; you can redistribute it and/or
;;;; modify it under the terms of the GNU Lesser General Public
@@ -39,7 +39,9 @@
(define port/pid-table (make-weak-key-hash-table 31))
(define (ensure-fdes port mode)
- (or (false-if-exception (fileno port))
+ (or (and (file-port? port)
+ (not (port-closed? port))
+ (fileno port))
(open-fdes *null-device* mode)))
;; run a process connected to an input, an output or an
@@ -88,12 +90,15 @@
;; flushing port buffers or evicting ports.
(port-for-each (lambda (pt-entry)
- (false-if-exception
- (let ((pt-fileno (fileno pt-entry)))
- (if (not (or (= pt-fileno input-fdes)
- (= pt-fileno output-fdes)
- (= pt-fileno error-fdes)))
- (close-fdes pt-fileno))))))
+ (if (and (file-port? pt-entry)
+ (not (port-closed? pt-entry))
+ (not (file-port-close-on-exec? pt-entry)))
+ (let ((pt-fileno (fileno pt-entry)))
+ (if (not (or (= pt-fileno input-fdes)
+ (= pt-fileno output-fdes)
+ (= pt-fileno error-fdes)))
+ (false-if-exception
+ (close-fdes pt-fileno)))))))
;; Copy the three selected descriptors to the standard
;; descriptors 0, 1, 2, if not already there