From d6e0c2a67dbdb3f940d60f68bbcf58a5bdee4a97 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Sun, 27 Jul 2008 18:26:13 +0000 Subject: [PATCH] * sysdeps/unix/sysv/linux/syscalls.list: Add __pipe2 alias. * io/pipe2.c: Likewise. * sysdeps/unix/sysv/linux/kernel-features.h: Define __ASSUME_PIPE2 instead of __ASSUME_PACCEPT. * include/unistd.h: Declare __have_pipe2. * libio/iopopen.c: Implement "e" flag. * libio/Makefile (tests): Add tst-popen1. * libio/tst-popen1.c: New file. --- ChangeLog | 10 ++ include/unistd.h | 7 ++ io/pipe2.c | 3 +- libio/Makefile | 4 +- libio/iopopen.c | 115 +++++++++++++++++----- libio/tst-popen1.c | 49 +++++++++ sysdeps/unix/sysv/linux/kernel-features.h | 2 +- sysdeps/unix/sysv/linux/syscalls.list | 2 +- 8 files changed, 165 insertions(+), 27 deletions(-) create mode 100644 libio/tst-popen1.c diff --git a/ChangeLog b/ChangeLog index b37f4c5f6d..87baa5a943 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,15 @@ 2008-07-27 Ulrich Drepper + * sysdeps/unix/sysv/linux/syscalls.list: Add __pipe2 alias. + * io/pipe2.c: Likewise. + * sysdeps/unix/sysv/linux/kernel-features.h: Define __ASSUME_PIPE2 + instead of __ASSUME_PACCEPT. + * include/unistd.h: Declare __have_pipe2. + * libio/iopopen.c: Implement "e" flag. + * libio/Makefile (tests): Add tst-popen1. + * libio/tst-popen1.c: New file. + + * sysdeps/unix/sysv/linux/bits/socket.h: Define PF_ISDN and AF_ISDN. * sysdeps/unix/sysv/linux/sparc/bits/socket.h: Likewise. diff --git a/include/unistd.h b/include/unistd.h index f34d53f223..34d7477f9e 100644 --- a/include/unistd.h +++ b/include/unistd.h @@ -48,6 +48,7 @@ extern ssize_t __libc_write (int __fd, __const void *__buf, size_t __n); libc_hidden_proto (__libc_write) extern int __pipe (int __pipedes[2]); libc_hidden_proto (__pipe) +extern int __pipe2 (int __pipedes[2], int __flags); extern unsigned int __sleep (unsigned int __seconds); extern int __chown (__const char *__file, __uid_t __owner, __gid_t __group); @@ -165,4 +166,10 @@ extern int __libc_pause (void); /* Not cancelable variant. */ extern int __pause_nocancel (void) attribute_hidden; +extern int __have_sock_cloexec; +/* At lot of other functionality became available at the same time as + SOCK_CLOEXEC. Avoid defining separate variables for all of them + unless it is really necessary. */ +#define __have_pipe2 __have_sock_cloexec + #endif diff --git a/io/pipe2.c b/io/pipe2.c index a0b8a8b1f8..aa54d17ae6 100644 --- a/io/pipe2.c +++ b/io/pipe2.c @@ -25,7 +25,7 @@ PIPEDES[1] can be read from PIPEDES[0]. Apply FLAGS to the new file descriptors. Returns 0 if successful, -1 if not. */ int -pipe2 (pipedes, flags) +__pipe2 (pipedes, flags) int pipedes[2]; int flags; { @@ -38,6 +38,7 @@ pipe2 (pipedes, flags) __set_errno (ENOSYS); return -1; } +weak_alias (__pipe2, pipe2) stub_warning (pipe2) #include diff --git a/libio/Makefile b/libio/Makefile index 31fac70cfd..385040fb96 100644 --- a/libio/Makefile +++ b/libio/Makefile @@ -1,4 +1,4 @@ -# Copyright (C) 1995-2002,2003,2004,2006,2007 Free Software Foundation, Inc. +# Copyright (C) 1995-2004,2006,2007,2008 Free Software Foundation, Inc. # This file is part of the GNU C Library. # The GNU C Library is free software; you can redistribute it and/or @@ -58,7 +58,7 @@ tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc \ tst-memstream1 tst-memstream2 \ tst-wmemstream1 tst-wmemstream2 \ bug-memstream1 bug-wmemstream1 \ - tst-setvbuf1 + tst-setvbuf1 tst-popen1 test-srcs = test-freopen all: # Make this the default target; it will be defined in Rules. diff --git a/libio/iopopen.c b/libio/iopopen.c index d5c6305b09..0ea7c2317b 100644 --- a/libio/iopopen.c +++ b/libio/iopopen.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1993, 1997-2002, 2003, 2004, 2007 +/* Copyright (C) 1993, 1997-2002, 2003, 2004, 2007, 2008 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Per Bothner . @@ -56,15 +56,6 @@ extern _IO_pid_t _IO_fork (void) __THROW; #endif /* _IO_HAVE_SYS_WAIT */ -#ifndef _IO_pipe -#ifdef _LIBC -#define _IO_pipe __pipe -#else -#define _IO_pipe pipe -#endif -extern int _IO_pipe (int des[2]) __THROW; -#endif - #ifndef _IO_dup2 #ifdef _LIBC #define _IO_dup2 __dup2 @@ -131,41 +122,99 @@ _IO_new_proc_open (fp, command, mode) volatile int parent_end, child_end; int pipe_fds[2]; _IO_pid_t child_pid; + + int do_read = 0; + int do_write = 0; + int do_cloexec = 0; + while (*mode != '\0') + switch (*mode++) + { + case 'r': + do_read = 1; + break; + case 'w': + do_write = 1; + break; + case 'e': + do_cloexec = 1; + break; + default: + errout: + __set_errno (EINVAL); + return NULL; + } + + if ((do_read ^ do_write) == 0) + goto errout; + if (_IO_file_is_open (fp)) return NULL; - if (_IO_pipe (pipe_fds) < 0) - return NULL; - if (mode[0] == 'r' && mode[1] == '\0') + +#ifdef O_CLOEXEC +# ifndef __ASSUME_PIPE2 + if (__have_pipe2 >= 0) +# endif + { + int r = __pipe2 (pipe_fds, O_CLOEXEC); +# ifndef __ASSUME_PIPE2 + if (__have_pipe2 == 0) + __have_pipe2 = r != -1 || errno != ENOSYS ? 1 : -1; + + if (__have_pipe2 > 0) +# endif + if (r < 0) + return NULL; + } +#endif +#ifndef __ASSUME_PIPE2 +# ifdef O_CLOEXEC + if (__have_pipe2 < 0) +# endif + if (__pipe (pipe_fds) < 0) + return NULL; +#endif + + if (do_read) { parent_end = pipe_fds[0]; child_end = pipe_fds[1]; read_or_write = _IO_NO_WRITES; } - else if (mode[0] == 'w' && mode[1] == '\0') + else { parent_end = pipe_fds[1]; child_end = pipe_fds[0]; read_or_write = _IO_NO_READS; } - else - { - _IO_close (pipe_fds[0]); - _IO_close (pipe_fds[1]); - __set_errno (EINVAL); - return NULL; - } + ((_IO_proc_file *) fp)->pid = child_pid = _IO_fork (); if (child_pid == 0) { - int child_std_end = mode[0] == 'r' ? 1 : 0; + int child_std_end = do_read ? 1 : 0; struct _IO_proc_file *p; +#ifndef __ASSUME_PIPE2 + /* If we have pipe2 the descriptor is marked for close-on-exec. */ _IO_close (parent_end); +#endif if (child_end != child_std_end) { _IO_dup2 (child_end, child_std_end); +#ifndef __ASSUME_PIPE2 _IO_close (child_end); +#endif + } +#ifdef O_CLOEXEC + else + { + /* The descriptor is already the one we will use. But it must + not be marked close-on-exec. Undo the effects. */ +# ifndef __ASSUME_PIPE2 + if (__have_pipe2 > 0) +# endif + __fcntl (child_end, F_SETFD, 0); } +#endif /* POSIX.2: "popen() shall ensure that any streams from previous popen() calls that remain open in the parent process are closed in the new child process." */ @@ -189,6 +238,28 @@ _IO_new_proc_open (fp, command, mode) _IO_close (parent_end); return NULL; } + + if (do_cloexec) + { +#ifndef __ASSUME_PIPE2 +# ifdef O_CLOEXEC + if (__have_pipe2 < 0) +# endif + __fcntl (parent_end, F_SETFD, FD_CLOEXEC); +#endif + } + else + { +#ifdef O_CLOEXEC + /* Undo the effects of the pipe2 call which set the + close-on-exec flag. */ +# ifndef __ASSUME_PIPE2 + if (__have_pipe2 > 0) +# endif + __fcntl (parent_end, F_SETFD, 0); +#endif + } + _IO_fileno (fp) = parent_end; /* Link into proc_file_chain. */ diff --git a/libio/tst-popen1.c b/libio/tst-popen1.c new file mode 100644 index 0000000000..bae6615b9b --- /dev/null +++ b/libio/tst-popen1.c @@ -0,0 +1,49 @@ +#include +#include + +static int +do_test (void) +{ + int res = 0; + + FILE *fp = popen ("echo hello", "r"); + if (fp == NULL) + { + puts ("first popen failed"); + res = 1; + } + else + { + int fd = fileno (fp); + if (fcntl (fd, F_GETFD) == FD_CLOEXEC) + { + puts ("first popen(\"r\") set FD_CLOEXEC"); + res = 1; + } + + fclose (fp); + } + + fp = popen ("echo hello", "re"); + if (fp == NULL) + { + puts ("second popen failed"); + res = 1; + } + else + { + int fd = fileno (fp); + if (fcntl (fd, F_GETFD) != FD_CLOEXEC) + { + puts ("second popen(\"r\") did not set FD_CLOEXEC"); + res = 1; + } + + fclose (fp); + } + + return res; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/sysdeps/unix/sysv/linux/kernel-features.h b/sysdeps/unix/sysv/linux/kernel-features.h index 74558cf65a..df87ae7c48 100644 --- a/sysdeps/unix/sysv/linux/kernel-features.h +++ b/sysdeps/unix/sysv/linux/kernel-features.h @@ -505,5 +505,5 @@ || defined __ia64__ || defined __sparc__) # define __ASSUME_SOCK_CLOEXEC 1 # define __ASSUME_IN_NONBLOCK 1 -# define __ASSUME_PACCEPT 1 +# define __ASSUME_PIPE2 1 #endif diff --git a/sysdeps/unix/sysv/linux/syscalls.list b/sysdeps/unix/sysv/linux/syscalls.list index b0fe6707f1..f654d5ee00 100644 --- a/sysdeps/unix/sysv/linux/syscalls.list +++ b/sysdeps/unix/sysv/linux/syscalls.list @@ -47,7 +47,7 @@ nfsservctl EXTRA nfsservctl i:ipp nfsservctl pause - pause Ci: __libc_pause pause personality EXTRA personality i:i __personality personality pipe - pipe i:f __pipe pipe -pipe2 - pipe2 i:fi pipe2 +pipe2 - pipe2 i:fi __pipe2 pipe2 pivot_root EXTRA pivot_root i:ss pivot_root prctl EXTRA prctl i:iiiii __prctl prctl putpmsg - putpmsg i:ippii putpmsg