diff --git a/ChangeLog b/ChangeLog index dd89d6377b..8707a1b262 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,20 @@ 2005-11-09 Ulrich Drepper + * io/fcntl.h: Declare openat and openat64. + * io/Makefile (routines): Add openat and openat64. + (tests): Add tst-openat. + * io/Versions: Add openat and openat64 for GLIBC_2.4. + * sysdeps/generic/openat.c: New file. + * sysdeps/generic/openat64.c: New file. + * sysdeps/unix/sysv/linux/openat.c: New file. + * sysdeps/unix/sysv/linux/openat64.c: New file. + * io/tst-openat.c: New file. + * sysdeps/generic/check_fds.c (check_one_fd): For writable descriptors, use /dev/full. (__libc_check_standard_fds): Reverse modes so that common operations on the descriptors fail. + * sysdeps/unix/sysv/linux/device-nrs.h: Add info for /dev/full. 2005-11-07 Kazuhiro Inaoka diff --git a/NEWS b/NEWS index 34528ab2e2..e5beafd072 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -GNU C Library NEWS -- history of user-visible changes. 2005-10-22 +GNU C Library NEWS -- history of user-visible changes. 2005-11-09 Copyright (C) 1992-2002,2003,2004,2005 Free Software Foundation, Inc. See the end for copying conditions. @@ -12,6 +12,13 @@ Version 2.4 * New iconv converters for IBM1025, IBM1122, IBM1137, IBM1153, IBM1154, IBM1155, IBM1156, IBM1157, and IBM1158 contributed by Jiro Sekiba. + More converters for IBM803, IBM901, IBM902, IBM921, IBM1008, IBM1097, + IBM1112, IBM1123, IBM1130, IBM1140, IBM1141, IBM1142, IBM1143, IBM1144, + IBM1145, IBM1146, IBM1147, IBM1148, IBM1149, IBM1166, IBM1167, IBM4517, + IBM4899, IBM4909, IBM4971, IBM5347, IBM9030, IBM9066, IBM9448, IBM12712, + IBM16804, IBM1364, IBM1371, IBM1388, IBM1390, and IBM1399 contributed + by Masahide Washizawa. + * It is now possible to install audit libraries for the dynamic linker using LD_AUDIT. Implemented by Ulrich Drepper. @@ -19,6 +26,8 @@ Version 2.4 longer supported. The new NPTL implementation requires Linux 2.6 kernels. For a libc and libpthread that works well on Linux 2.4 kernels, we recommend using the stable 2.3 branch. + +* New interfaces: fdopendir, openat. Version 2.3.6 diff --git a/io/Makefile b/io/Makefile index 906d1e3301..b1ca46814b 100644 --- a/io/Makefile +++ b/io/Makefile @@ -1,4 +1,4 @@ -# Copyright (C) 1992-2002, 2003 Free Software Foundation, Inc. +# Copyright (C) 1992-2002, 2003, 2005 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 @@ -34,7 +34,8 @@ routines := \ statfs fstatfs statfs64 fstatfs64 \ statvfs fstatvfs statvfs64 fstatvfs64 \ umask chmod fchmod lchmod mkdir \ - open open64 close read write lseek lseek64 access euidaccess \ + open open64 openat openat64 close \ + read write lseek lseek64 access euidaccess \ fcntl flock lockf lockf64 \ dup dup2 pipe \ creat creat64 \ @@ -57,7 +58,8 @@ static-only-routines = stat fstat lstat mknod stat64 fstat64 lstat64 others := pwd test-srcs := ftwtest tests := test-utime test-stat test-stat2 test-lfs tst-getcwd \ - tst-fcntl bug-ftw1 bug-ftw2 bug-ftw3 bug-ftw4 tst-statvfs + tst-fcntl bug-ftw1 bug-ftw2 bug-ftw3 bug-ftw4 tst-statvfs \ + tst-openat distribute := ftwtest-sh diff --git a/io/Versions b/io/Versions index 5b311ee03b..f5cd8d5148 100644 --- a/io/Versions +++ b/io/Versions @@ -97,4 +97,7 @@ libc { # n* nftw; nftw64; } + GLIBC_2.4 { + openat; openat64; + } } diff --git a/io/fcntl.h b/io/fcntl.h index ef9d5f9b81..044a988872 100644 --- a/io/fcntl.h +++ b/io/fcntl.h @@ -1,4 +1,5 @@ -/* Copyright (C) 1991,1992,1994-2001,2003,2004 Free Software Foundation, Inc. +/* Copyright (C) 1991,1992,1994-2001,2003,2004,2005 + 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 @@ -82,6 +83,32 @@ extern int __REDIRECT (open, (__const char *__file, int __oflag, ...), open64) extern int open64 (__const char *__file, int __oflag, ...) __nonnull ((1)); #endif +#ifdef __USE_GNU +/* Similar to OPEN but a relative path name is interpreted relative to + the directory for which FD is a descriptor. + + NOTE: some other OPENAT implementation support additional functionality + through this interface, especially using the O_XATTR flag. This is not + yet supported here. + + This function is a cancellation point and therefore not marked with + __THROW. */ +# ifndef __USE_FILE_OFFSET64 +extern int openat (int __fd, __const char *__file, int __oflag, ...) + __nonnull ((2)); +# else +# ifdef __REDIRECT +extern int __REDIRECT (openat, (int __fd, __const char *__file, int __oflag, + ...), openat64) __nonnull ((2)); +# else +# define openat openat64 +# endif +# endif + +extern int openat64 (int __fd, __const char *__file, int __oflag, ...) + __nonnull ((2)); +#endif + /* Create and open FILE, with mode MODE. This takes an `int' MODE argument because that is what `mode_t' will be widened to. diff --git a/io/tst-openat.c b/io/tst-openat.c new file mode 100644 index 0000000000..c20c95a10d --- /dev/null +++ b/io/tst-openat.c @@ -0,0 +1,163 @@ +#include +#include +#include +#include +#include +#include + + +static void prepare (void); +#define PREPARE(argc, argv) prepare () + +static int do_test (void); +#define TEST_FUNCTION do_test () + +#include "../test-skeleton.c" + +static int dir_fd; + +static void +prepare (void) +{ + size_t test_dir_len = strlen (test_dir); + static const char dir_name[] = "/tst-openat.XXXXXX"; + + size_t dirbuflen = test_dir_len + sizeof (dir_name); + char *dirbuf = malloc (dirbuflen); + if (dirbuf == NULL) + { + puts ("out of memory"); + exit (1); + } + + snprintf (dirbuf, dirbuflen, "%s%s", test_dir, dir_name); + if (mkdtemp (dirbuf) == NULL) + { + puts ("cannot create temporary directory"); + exit (1); + } + + add_temp_file (dirbuf); + + dir_fd = open (dirbuf, O_RDONLY | O_DIRECTORY); + if (dir_fd == -1) + { + puts ("cannot open directory"); + exit (1); + } +} + + +static int +do_test (void) +{ + /* fdopendir takes over the descriptor, make a copy. */ + int dupfd = dup (dir_fd); + if (dupfd == -1) + { + puts ("dup failed"); + return 1; + } + if (lseek (dupfd, 0, SEEK_SET) != 0) + { + puts ("1st lseek failed"); + return 1; + } + + /* The directory should be empty safe the . and .. files. */ + DIR *dir = fdopendir (dupfd); + if (dir == NULL) + { + puts ("fdopendir failed"); + return 1; + } + struct dirent64 *d; + while ((d = readdir64 (dir)) != NULL) + if (strcmp (d->d_name, ".") != 0 && strcmp (d->d_name, "..") != 0) + { + printf ("temp directory contains file \"%s\"\n", d->d_name); + return 1; + } + closedir (dir); + + /* Try to create a file. */ + int fd = openat (dir_fd, "some-file", O_CREAT|O_RDWR|O_EXCL, 0666); + if (fd == -1) + { + puts ("file creation failed"); + return 1; + } + write (fd, "hello", 5); + close (fd); + puts ("file created"); + + /* fdopendir takes over the descriptor, make a copy. */ + dupfd = dup (dir_fd); + if (dupfd == -1) + { + puts ("dup failed"); + return 1; + } + if (lseek (dupfd, 0, SEEK_SET) != 0) + { + puts ("2nd lseek failed"); + return 1; + } + + /* The directory should be empty safe the . and .. files. */ + dir = fdopendir (dupfd); + if (dir == NULL) + { + puts ("fdopendir failed"); + return 1; + } + bool seen_file = false; + while ((d = readdir64 (dir)) != NULL) + if (strcmp (d->d_name, ".") != 0 && strcmp (d->d_name, "..") != 0) + { + if (strcmp (d->d_name, "some-file") != 0) + { + printf ("temp directory contains file \"%s\"\n", d->d_name); + return 1; + } + + seen_file = true; + } + closedir (dir); + + if (!seen_file) + { + puts ("file not created in correct directory"); + return 1; + } + + int cwdfd = open (".", O_RDONLY | O_DIRECTORY); + if (cwdfd == -1) + { + puts ("cannot get descriptor for cwd"); + return 1; + } + + if (fchdir (dir_fd) != 0) + { + puts ("1st fchdir failed"); + return 1; + } + + if (unlink ("some-file") != 0) + { + puts ("unlink failed"); + return 1; + } + + if (fchdir (cwdfd) != 0) + { + puts ("2nd fchdir failed"); + return 1; + } + + close (dir_fd); + close (cwdfd); + + return 0; +} diff --git a/sysdeps/generic/openat.c b/sysdeps/generic/openat.c new file mode 100644 index 0000000000..b058bcbe9f --- /dev/null +++ b/sysdeps/generic/openat.c @@ -0,0 +1,69 @@ +/* Copyright (C) 2005 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 + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include + +/* Open FILE with access OFLAG. Interpret relative paths relative to + the directory associated with FD. If OFLAG includes O_CREAT, a + third argument is the file protection. */ +int +openat (fd, file, oflag) + int fd; + const char *file; + int oflag; +{ + int mode; + + if (file == NULL) + { + __set_errno (EINVAL); + return -1; + } + + if (file[0] != '/') + { + /* Check FD is associated with a directory. */ + struct stat64 st; + if (__fxstat64 (_STAT_VER, fd, &st) != 0) + return -1; + + if (!S_ISDIR (st.st_mode)) + { + __set_errno (ENOTDIR); + return -1; + } + } + + if (oflag & O_CREAT) + { + va_list arg; + va_start (arg, oflag); + mode = va_arg (arg, int); + va_end (arg); + } + + __set_errno (ENOSYS); + return -1; +} +stub_warning (openat) + +#include diff --git a/sysdeps/generic/openat64.c b/sysdeps/generic/openat64.c new file mode 100644 index 0000000000..82575df399 --- /dev/null +++ b/sysdeps/generic/openat64.c @@ -0,0 +1,69 @@ +/* Copyright (C) 2005 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 + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include + +/* Open FILE with access OFLAG. Interpret relative paths relative to + the directory associated with FD. If OFLAG includes O_CREAT, a + third argument is the file protection. */ +int +openat64 (fd, file, oflag) + int fd; + const char *file; + int oflag; +{ + int mode; + + if (file == NULL) + { + __set_errno (EINVAL); + return -1; + } + + if (file[0] != '/') + { + /* Check FD is associated with a directory. */ + struct stat64 st; + if (__fxstat64 (_STAT_VER, fd, &st) != 0) + return -1; + + if (!S_ISDIR (st.st_mode)) + { + __set_errno (ENOTDIR); + return -1; + } + } + + if (oflag & O_CREAT) + { + va_list arg; + va_start (arg, oflag); + mode = va_arg (arg, int); + va_end (arg); + } + + __set_errno (ENOSYS); + return -1; +} +stub_warning (openat64) + +#include diff --git a/sysdeps/unix/sysv/linux/device-nrs.h b/sysdeps/unix/sysv/linux/device-nrs.h index 6b6578ec5f..b30c1dbede 100644 --- a/sysdeps/unix/sysv/linux/device-nrs.h +++ b/sysdeps/unix/sysv/linux/device-nrs.h @@ -1,5 +1,5 @@ /* Device numbers of devices used in the implementation. Linux version. - Copyright (C) 2000, 2001 Free Software Foundation, Inc. + Copyright (C) 2000, 2001, 2005 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 @@ -26,6 +26,10 @@ #define DEV_NULL_MAJOR 1 #define DEV_NULL_MINOR 3 +/* /dev/full is (1,7). */ +#define DEV_FULL_MAJOR 1 +#define DEV_FULL_MINOR 7 + /* Pseudo tty slaves. For Linux we use the Unix98 ttys. We could also include the old BSD-style tty buts they should not be used and the extra test would only slow down correctly set up systems. If a diff --git a/sysdeps/unix/sysv/linux/openat.c b/sysdeps/unix/sysv/linux/openat.c new file mode 100644 index 0000000000..a89f172b62 --- /dev/null +++ b/sysdeps/unix/sysv/linux/openat.c @@ -0,0 +1,110 @@ +/* Copyright (C) 2005 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 + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifndef OPENAT +# define OPENAT openat +# define MORE_OFLAGS 0 +#endif + +/* Open FILE with access OFLAG. Interpret relative paths relative to + the directory associated with FD. If OFLAG includes O_CREAT, a + third argument is the file protection. */ +int +OPENAT (fd, file, oflag) + int fd; + const char *file; + int oflag; +{ + char *buf = NULL; + + if (file[0] != '/') + { + size_t filelen = strlen (file); + static const char procfd[] = "/proc/self/fd/%d/%s"; + /* Buffer for the path name we are going to use. It consists of + - the string /proc/self/fd/ + - the file descriptor number + - the file name provided. + The final NUL is included in the sizeof. A bit of overhead + due to the format elements compensates for possible negative + numbers. */ + size_t buflen = sizeof (procfd) + sizeof (int) * 3 + filelen; + buf = alloca (buflen); + + __snprintf (buf, buflen, procfd, fd, file); + file = buf; + } + + mode_t mode = 0; + if (oflag & O_CREAT) + { + va_list arg; + va_start (arg, oflag); + mode = va_arg (arg, mode_t); + va_end (arg); + } + + INTERNAL_SYSCALL_DECL (err); + int res; + + if (SINGLE_THREAD_P) + res = INTERNAL_SYSCALL (open, err, 3, file, oflag | MORE_OFLAGS, mode); + else + { + int oldtype = LIBC_CANCEL_ASYNC (); + + res = INTERNAL_SYSCALL (open, err, 3, file, oflag | MORE_OFLAGS, mode); + + LIBC_CANCEL_RESET (oldtype); + } + + if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (res, err), 0)) + { + int errval = INTERNAL_SYSCALL_ERRNO (res, err); + if (buf != NULL && errval == ENOTDIR) + { + /* This can mean either the file desriptor is invalid or + /proc is not mounted. */ + struct stat64 st; + if (__fxstat64 (_STAT_VER, fd, &st) != 0) + /* errno is already set correctly. */ + goto out; + + /* If /proc is not mounted there is nothing we can do. */ + if (S_ISDIR (st.st_mode) + && (__xstat64 (_STAT_VER, "/proc/self/fd", &st) != 0 + || !S_ISDIR (st.st_mode))) + errval = ENOSYS; + } + + __set_errno (errval); + } + + out: + return res; +} diff --git a/sysdeps/unix/sysv/linux/openat64.c b/sysdeps/unix/sysv/linux/openat64.c new file mode 100644 index 0000000000..9e7a2b3737 --- /dev/null +++ b/sysdeps/unix/sysv/linux/openat64.c @@ -0,0 +1,4 @@ +#define OPENAT openat64 +#define MORE_OFLAGS O_LARGEFILE + +#include "openat.c"