From 7c65e9001b93d5d20046bc4d50fd10fff5f4adc2 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Fri, 20 Jan 2006 07:08:05 +0000 Subject: * include/fcntl.h: Declare __have_atfcts. * sysdeps/unix/sysv/linux/faccessat.c: Use syscall if available. * sysdeps/unix/sysv/linux/fchmodat.c: Likewise. * sysdeps/unix/sysv/linux/fchownat.c: Likewise. * sysdeps/unix/sysv/linux/futimesat.c: Likewise. * sysdeps/unix/sysv/linux/linkat.c: Likewise. * sysdeps/unix/sysv/linux/mkdirat.c: Likewise. * sysdeps/unix/sysv/linux/openat.c: Likewise. * sysdeps/unix/sysv/linux/readlinkat.c: Likewise. * sysdeps/unix/sysv/linux/renameat.c: Likewise. * sysdeps/unix/sysv/linux/symlinkat.c: Likewise. * sysdeps/unix/sysv/linux/unlinkat.c: Likewise. * sysdeps/unix/sysv/linux/xmknodat.c: Likewise. * sysdeps/unix/sysv/linux/wordsize-64/fxstatat.c: Likewise. * sysdeps/unix/sysv/linux/kernel-features.h: Define __ASSUME_PSELECT, __ASSUME_PPOLL, and __ASSUME_ATFCTS if possible. * io/ppoll.c: New file. * io/Makefile (routines): Add ppoll. (CFLAGS-ppoll.c): Define. * io/Versions: Export ppoll for GLIBC_2.4. * io/sys/poll.h: Declare ppoll. * sysdeps/unix/sysv/linux/ppoll.c: New file. * misc/pselect.c: Make it possible to include this file to define the generic code as a static function. * sysdeps/unix/sysv/linux/pselect.c: New file. --- ChangeLog | 30 +++++++++ include/fcntl.h | 4 ++ io/Makefile | 3 +- io/Versions | 2 + io/ppoll.c | 76 +++++++++++++++++++++ io/sys/poll.h | 21 +++++- misc/pselect.c | 2 + nptl/ChangeLog | 4 ++ nptl/tst-cancel4.c | 50 +++++++++++++- sysdeps/unix/sysv/linux/faccessat.c | 62 +++++++++++------ sysdeps/unix/sysv/linux/fchmodat.c | 25 ++++++- sysdeps/unix/sysv/linux/fchownat.c | 24 ++++++- sysdeps/unix/sysv/linux/futimesat.c | 30 +++++++-- sysdeps/unix/sysv/linux/kernel-features.h | 24 +++++++ sysdeps/unix/sysv/linux/linkat.c | 24 ++++++- sysdeps/unix/sysv/linux/mkdirat.c | 24 ++++++- sysdeps/unix/sysv/linux/openat.c | 68 ++++++++++++++----- sysdeps/unix/sysv/linux/ppoll.c | 76 +++++++++++++++++++++ sysdeps/unix/sysv/linux/pselect.c | 92 ++++++++++++++++++++++++++ sysdeps/unix/sysv/linux/readlinkat.c | 24 ++++++- sysdeps/unix/sysv/linux/renameat.c | 26 +++++++- sysdeps/unix/sysv/linux/symlinkat.c | 24 ++++++- sysdeps/unix/sysv/linux/unlinkat.c | 23 ++++++- sysdeps/unix/sysv/linux/wordsize-64/fxstatat.c | 31 ++++++++- sysdeps/unix/sysv/linux/xmknodat.c | 37 ++++++++--- 25 files changed, 731 insertions(+), 75 deletions(-) create mode 100644 io/ppoll.c create mode 100644 sysdeps/unix/sysv/linux/ppoll.c create mode 100644 sysdeps/unix/sysv/linux/pselect.c diff --git a/ChangeLog b/ChangeLog index 55b67b4703..78148a6b80 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,33 @@ +2006-01-19 Ulrich Drepper + + * include/fcntl.h: Declare __have_atfcts. + * sysdeps/unix/sysv/linux/faccessat.c: Use syscall if available. + * sysdeps/unix/sysv/linux/fchmodat.c: Likewise. + * sysdeps/unix/sysv/linux/fchownat.c: Likewise. + * sysdeps/unix/sysv/linux/futimesat.c: Likewise. + * sysdeps/unix/sysv/linux/linkat.c: Likewise. + * sysdeps/unix/sysv/linux/mkdirat.c: Likewise. + * sysdeps/unix/sysv/linux/openat.c: Likewise. + * sysdeps/unix/sysv/linux/readlinkat.c: Likewise. + * sysdeps/unix/sysv/linux/renameat.c: Likewise. + * sysdeps/unix/sysv/linux/symlinkat.c: Likewise. + * sysdeps/unix/sysv/linux/unlinkat.c: Likewise. + * sysdeps/unix/sysv/linux/xmknodat.c: Likewise. + * sysdeps/unix/sysv/linux/wordsize-64/fxstatat.c: Likewise. + * sysdeps/unix/sysv/linux/kernel-features.h: Define __ASSUME_PSELECT, + __ASSUME_PPOLL, and __ASSUME_ATFCTS if possible. + + * io/ppoll.c: New file. + * io/Makefile (routines): Add ppoll. + (CFLAGS-ppoll.c): Define. + * io/Versions: Export ppoll for GLIBC_2.4. + * io/sys/poll.h: Declare ppoll. + * sysdeps/unix/sysv/linux/ppoll.c: New file. + + * misc/pselect.c: Make it possible to include this file to define + the generic code as a static function. + * sysdeps/unix/sysv/linux/pselect.c: New file. + 2006-01-19 Jakub Jelinek * misc/pselect.c (__pselect): Remove static. diff --git a/include/fcntl.h b/include/fcntl.h index 610e322cfd..f00881449d 100644 --- a/include/fcntl.h +++ b/include/fcntl.h @@ -25,4 +25,8 @@ extern void __atfct_seterrno_2 (int errval, int fd1, const char *buf1, int fd2, const char *buf2) attribute_hidden; + +/* Flag determining whether the *at system calls are available. */ +extern int __have_atfcts attribute_hidden; + #endif diff --git a/io/Makefile b/io/Makefile index 5e6d72eace..e005cb3cd5 100644 --- a/io/Makefile +++ b/io/Makefile @@ -48,7 +48,7 @@ routines := \ ttyname ttyname_r isatty \ link linkat symlink symlinkat readlink readlinkat \ unlink unlinkat rmdir \ - ftw ftw64 fts poll \ + ftw ftw64 fts poll ppoll \ posix_fadvise posix_fadvise64 \ posix_fallocate posix_fallocate64 \ sendfile sendfile64 @@ -72,6 +72,7 @@ include ../Rules CFLAGS-fcntl.c = -fexceptions -fasynchronous-unwind-tables CFLAGS-poll.c = -fexceptions -fasynchronous-unwind-tables +CFLAGS-ppoll.c = -fexceptions -fasynchronous-unwind-tables CFLAGS-lockf.c = -fexceptions CFLAGS-statfs.c = -fexceptions CFLAGS-fstatfs.c = -fexceptions diff --git a/io/Versions b/io/Versions index 16006a8e08..bc9c9d2685 100644 --- a/io/Versions +++ b/io/Versions @@ -110,5 +110,7 @@ libc { readlinkat; symlinkat; unlinkat; + + ppoll; } } diff --git a/io/ppoll.c b/io/ppoll.c new file mode 100644 index 0000000000..a035cfeb1f --- /dev/null +++ b/io/ppoll.c @@ -0,0 +1,76 @@ +/* Copyright (C) 2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 2006. + + 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 /* For NULL. */ +#include +#include + + +int +ppoll (struct pollfd *fds, nfds_t nfds, const struct timespec *timeout, + const sigset_t *sigmask) +{ + int tval = -1; + + /* poll uses a simple millisecond value. Convert it. */ + if (timeout != NULL) + { + if (timeout->tv_sec < 0 + || timeout->tv_nsec < 0 || timeout->tv_nsec >= 1000000000) + { + __set_errno (EINVAL); + return -1; + } + + if (timeout->tv_sec > INT_MAX / 1000 + || (timeout->tv_sec == INT_MAX / 1000 + && ((timeout->tv_nsec + 999999) / 1000000 > INT_MAX % 1000))) + /* We cannot represent the timeout in an int value. Wait + forever. */ + tval = -1; + else + tval = (timeout->tv_sec * 1000 + + (timeout->tv_nsec + 999999) / 1000000); + } + + /* The setting and restoring of the signal mask and the select call + should be an atomic operation. This can't be done without kernel + help. */ + sigset_t savemask; + if (sigmask != NULL) + __sigprocmask (SIG_SETMASK, sigmask, &savemask); + + /* Note the ppoll() is a cancellation point. But since we call + poll() which itself is a cancellation point we do not have + to do anything here. */ + int retval = __poll (fds, nfds, tval); + + if (sigmask != NULL) + __sigprocmask (SIG_SETMASK, &savemask, NULL); + + return retval; +} + +#ifndef ppoll +/* __poll handles cancellation. */ +LIBC_CANCEL_HANDLED (); +#endif diff --git a/io/sys/poll.h b/io/sys/poll.h index 9cf1b9f1c0..4085b785ee 100644 --- a/io/sys/poll.h +++ b/io/sys/poll.h @@ -1,5 +1,5 @@ /* Compatibility definitions for System V `poll' interface. - Copyright (C) 1994,1996-2001,2004,2005 Free Software Foundation, Inc. + Copyright (C) 1994,1996-2001,2004,2005,2006 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 @@ -24,6 +24,13 @@ /* Get the platform dependent bits of `poll'. */ #include +#ifdef __USE_GNU +/* Get the __sigset_t definition. */ +# include +/* Get the timespec definition. */ +# define __need_timespec +# include +#endif /* Type used for the number of file descriptors. */ @@ -50,6 +57,18 @@ __BEGIN_DECLS __THROW. */ extern int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout); +#ifdef __USE_GNU +/* Like poll, but before waiting the threads signal mask is replaced + with that specified in the fourth parameter. For better usability, + the timeout value is specified using a TIMESPEC object. + + This function is a cancellation point and therefore not marked with + __THROW. */ +extern int ppoll (struct pollfd *__fds, nfds_t __nfds, + __const struct timespec *__timeout, + __const __sigset_t *__ss); +#endif + __END_DECLS #endif /* sys/poll.h */ diff --git a/misc/pselect.c b/misc/pselect.c index 1d841a8cf4..80cf8be4b3 100644 --- a/misc/pselect.c +++ b/misc/pselect.c @@ -62,7 +62,9 @@ __pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, return retval; } +#ifndef __pselect weak_alias (__pselect, pselect) strong_alias (__pselect, __libc_pselect) /* __select handles cancellation. */ LIBC_CANCEL_HANDLED (); +#endif diff --git a/nptl/ChangeLog b/nptl/ChangeLog index a902ceb62f..dd87226d6e 100644 --- a/nptl/ChangeLog +++ b/nptl/ChangeLog @@ -1,3 +1,7 @@ +2006-01-19 Ulrich Drepper + + * tst-cancel4.c: Test ppoll. + 2006-01-18 Andreas Jaeger [BZ #2167] diff --git a/nptl/tst-cancel4.c b/nptl/tst-cancel4.c index cb7619688e..73cfa44614 100644 --- a/nptl/tst-cancel4.c +++ b/nptl/tst-cancel4.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. +/* Copyright (C) 2002, 2003, 2004, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper , 2002. @@ -523,6 +523,53 @@ tf_poll (void *arg) } +static void * +tf_ppoll (void *arg) +{ + int fd; + int r; + + if (arg == NULL) + fd = fds[0]; + else + { + char fname[] = "/tmp/tst-cancel4-fd-XXXXXX"; + tempfd = fd = mkstemp (fname); + if (fd == -1) + printf ("%s: mkstemp failed\n", __FUNCTION__); + unlink (fname); + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + struct pollfd rfs[1] = { [0] = { .fd = fd, .events = POLLIN } }; + + int s; + pthread_cleanup_push (cl, NULL); + + s = ppoll (rfs, 1, NULL, NULL); + + pthread_cleanup_pop (0); + + printf ("%s: ppoll returns with %d (%s)\n", __FUNCTION__, s, + strerror (errno)); + + exit (1); +} + + static void * tf_wait (void *arg) { @@ -2006,6 +2053,7 @@ static struct ADD_TEST (select, 2, 0), ADD_TEST (pselect, 2, 0), ADD_TEST (poll, 2, 0), + ADD_TEST (ppoll, 2, 0), ADD_TEST (write, 2, 0), ADD_TEST (writev, 2, 0), ADD_TEST (sleep, 2, 0), diff --git a/sysdeps/unix/sysv/linux/faccessat.c b/sysdeps/unix/sysv/linux/faccessat.c index 80b3b240f7..7c28280ae6 100644 --- a/sysdeps/unix/sysv/linux/faccessat.c +++ b/sysdeps/unix/sysv/linux/faccessat.c @@ -25,8 +25,10 @@ #include #include #include +#include #include + int faccessat (fd, file, mode, flag) int fd; @@ -40,42 +42,61 @@ faccessat (fd, file, mode, flag) return -1; } - char *buf = NULL; + int result; - if (fd != AT_FDCWD && file[0] != '/') +#ifdef __NR_faccessat + if (flag == 0 +# ifndef __ASSUME_ATFCTS + && __have_atfcts >= 0 +# endif + ) { - 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; + result = INLINE_SYSCALL (faccessat, 3, fd, file, mode); +# ifndef __ASSUME_ATFCTS + if (result == -1 && errno == ENOSYS) + __have_atfcts = -1; + else +# endif + return result; } +#endif +#ifndef __ASSUME_ATFCTS if ((!(flag & AT_EACCESS) || ! __libc_enable_secure) -#ifndef __NR_laccess /* Linux so far has no laccess syscall. */ +# ifndef __NR_laccess /* Linux so far has no laccess syscall. */ && !(flag & AT_SYMLINK_NOFOLLOW) -#endif +# endif ) { /* If we are not set-uid or set-gid, access does the same. */ + char *buf = NULL; + + if (fd != AT_FDCWD && 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; + } int result; INTERNAL_SYSCALL_DECL (err); -#ifdef __NR_laccess +# ifdef __NR_laccess if (flag & AT_SYMLINK_NOFOLLOW) result = INTERNAL_SYSCALL (laccess, err, 2, file, mode); else -#endif +# endif result = INTERNAL_SYSCALL (access, err, 2, file, mode); if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (result, err), 0)) @@ -86,6 +107,7 @@ faccessat (fd, file, mode, flag) return result; } +#endif struct stat64 stats; if (fstatat64 (fd, file, &stats, flag & AT_SYMLINK_NOFOLLOW)) diff --git a/sysdeps/unix/sysv/linux/fchmodat.c b/sysdeps/unix/sysv/linux/fchmodat.c index de35e4376f..8b420153f1 100644 --- a/sysdeps/unix/sysv/linux/fchmodat.c +++ b/sysdeps/unix/sysv/linux/fchmodat.c @@ -25,6 +25,7 @@ #include #include #include +#include #include int @@ -47,6 +48,24 @@ fchmodat (fd, file, mode, flag) } #endif + int result; + +#ifdef __NR_fchmodat +# ifndef __ASSUME_ATFCTS + if (__have_atfcts >= 0) +# endif + { + result = INLINE_SYSCALL (fchmodat, 3, fd, file, mode); +# ifndef __ASSUME_ATFCTS + if (result == -1 && errno == ENOSYS) + __have_atfcts = -1; + else +# endif + return result; + } +#endif + +#ifndef __ASSUME_ATFCTS char *buf = NULL; if (fd != AT_FDCWD && file[0] != '/') @@ -67,14 +86,13 @@ fchmodat (fd, file, mode, flag) file = buf; } - int result; INTERNAL_SYSCALL_DECL (err); -#ifdef __NR_lchmod +# ifdef __NR_lchmod if (flag & AT_SYMLINK_NOFOLLOW) result = INTERNAL_SYSCALL (lchmod, err, 2, file, mode); else -#endif +# endif result = INTERNAL_SYSCALL (chmod, err, 2, file, mode); if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (result, err), 0)) @@ -84,4 +102,5 @@ fchmodat (fd, file, mode, flag) } return result; +#endif } diff --git a/sysdeps/unix/sysv/linux/fchownat.c b/sysdeps/unix/sysv/linux/fchownat.c index 10d87e87fc..0f731775b3 100644 --- a/sysdeps/unix/sysv/linux/fchownat.c +++ b/sysdeps/unix/sysv/linux/fchownat.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2005 Free Software Foundation, Inc. +/* Copyright (C) 2005, 2006 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 @@ -25,6 +25,8 @@ #include #include #include +#include + /* Change the owner and group of FILE. */ int @@ -35,6 +37,24 @@ fchownat (fd, file, owner, group, flag) gid_t group; int flag; { + int result; + +#ifdef __NR_fchownat +# ifndef __ASSUME_ATFCTS + if (__have_atfcts >= 0) +# endif + { + result = INLINE_SYSCALL (fchownat, 5, fd, file, owner, group, flag); +# ifndef __ASSUME_ATFCTS + if (result == -1 && errno == ENOSYS) + __have_atfcts = -1; + else +# endif + return result; + } +#endif + +#ifndef __ASSUME_ATFCTS if (flag & ~AT_SYMLINK_NOFOLLOW) { __set_errno (EINVAL); @@ -61,7 +81,6 @@ fchownat (fd, file, owner, group, flag) file = buf; } - int result; INTERNAL_SYSCALL_DECL (err); if (flag & AT_SYMLINK_NOFOLLOW) @@ -76,4 +95,5 @@ fchownat (fd, file, owner, group, flag) } return result; +#endif } diff --git a/sysdeps/unix/sysv/linux/futimesat.c b/sysdeps/unix/sysv/linux/futimesat.c index be148b8d7a..514f456927 100644 --- a/sysdeps/unix/sysv/linux/futimesat.c +++ b/sysdeps/unix/sysv/linux/futimesat.c @@ -35,6 +35,24 @@ futimesat (fd, file, tvp) const char *file; const struct timeval tvp[2]; { + int result; + +#ifdef __NR_futimesat +# ifndef __ASSUME_ATFCTS + if (__have_atfcts >= 0) +# endif + { + result = INLINE_SYSCALL (futimesat, 3, fd, file, tvp); +# ifndef __ASSUME_ATFCTS + if (result == -1 && errno == ENOSYS) + __have_atfcts = -1; + else +# endif + return result; + } +#endif + +#ifndef __ASSUME_ATFCTS char *buf = NULL; if (file == NULL) @@ -70,24 +88,23 @@ futimesat (fd, file, tvp) file = buf; } - int result; INTERNAL_SYSCALL_DECL (err); -#ifdef __NR_utimes +# ifdef __NR_utimes result = INTERNAL_SYSCALL (utimes, err, 2, file, tvp); if (__builtin_expect (!INTERNAL_SYSCALL_ERROR_P (result, err), 1)) return result; -# ifndef __ASSUME_UTIMES +# ifndef __ASSUME_UTIMES if (INTERNAL_SYSCALL_ERRNO (result, err) != ENOSYS) goto fail; +# endif # endif -#endif /* The utimes() syscall does not exist or is not available in the used kernel. Use utime(). For this we have to convert to the data format utime() expects. */ -#ifndef __ASSUME_UTIMES +# ifndef __ASSUME_UTIMES struct utimbuf tmp; struct utimbuf *times; @@ -105,9 +122,10 @@ futimesat (fd, file, tvp) return result; fail: -#endif +# endif __atfct_seterrno (INTERNAL_SYSCALL_ERRNO (result, err), fd, buf); return -1; +#endif } diff --git a/sysdeps/unix/sysv/linux/kernel-features.h b/sysdeps/unix/sysv/linux/kernel-features.h index 594af419c8..837a1c14fb 100644 --- a/sysdeps/unix/sysv/linux/kernel-features.h +++ b/sysdeps/unix/sysv/linux/kernel-features.h @@ -463,3 +463,27 @@ #if __LINUX_KERNEL_VERSION >= 0x02041a # define __ASSUME_TMPFS_NAME 1 #endif + +/* pselect was introduced just after 2.6.16-rc1. Due to the way the + kernel versions are advertised we can only rely on 2.6.17 to have + the code. */ +#if __LINUX_KERNEL_VERSION >= 0x020611 \ + && (defined __i386__ || defined __powerpc__) +# define __ASSUME_PSELECT 1 +#endif + +/* ppoll was introduced just after 2.6.16-rc1. Due to the way the + kernel versions are advertised we can only rely on 2.6.17 to have + the code. */ +#if __LINUX_KERNEL_VERSION >= 0x020611 \ + && (defined __i386__ || defined __powerpc__) +# define __ASSUME_PPOLL 1 +#endif + +/* The *at syscalls were introduced just after 2.6.16-rc1. Due to the way the + kernel versions are advertised we can only rely on 2.6.17 to have + the code. */ +#if __LINUX_KERNEL_VERSION >= 0x020611 \ + && (defined __i386__ || defined __x86_64__) +# define __ASSUME_ATFCTS 1 +#endif diff --git a/sysdeps/unix/sysv/linux/linkat.c b/sysdeps/unix/sysv/linux/linkat.c index 8ebff74215..5485b3f61c 100644 --- a/sysdeps/unix/sysv/linux/linkat.c +++ b/sysdeps/unix/sysv/linux/linkat.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2005 Free Software Foundation, Inc. +/* Copyright (C) 2005, 2006 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 @@ -22,6 +22,7 @@ #include #include #include +#include /* Make a link to FROM named TO but relative paths in TO and FROM are @@ -33,6 +34,24 @@ linkat (fromfd, from, tofd, to) int tofd; const char *to; { + int result; + +#ifdef __NR_linkat +# ifndef __ASSUME_ATFCTS + if (__have_atfcts >= 0) +# endif + { + result = INLINE_SYSCALL (linkat, 4, fromfd, from, tofd, to); +# ifndef __ASSUME_ATFCTS + if (result == -1 && errno == ENOSYS) + __have_atfcts = -1; + else +# endif + return result; + } +#endif + +#ifndef __ASSUME_ATFCTS static const char procfd[] = "/proc/self/fd/%d/%s"; char *buffrom = NULL; @@ -74,7 +93,7 @@ linkat (fromfd, from, tofd, to) INTERNAL_SYSCALL_DECL (err); - int result = INTERNAL_SYSCALL (link, err, 2, from, to); + result = INTERNAL_SYSCALL (link, err, 2, from, to); if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (result, err), 0)) { @@ -84,4 +103,5 @@ linkat (fromfd, from, tofd, to) } return result; +#endif } diff --git a/sysdeps/unix/sysv/linux/mkdirat.c b/sysdeps/unix/sysv/linux/mkdirat.c index 367441b05b..3c190085ce 100644 --- a/sysdeps/unix/sysv/linux/mkdirat.c +++ b/sysdeps/unix/sysv/linux/mkdirat.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2005 Free Software Foundation, Inc. +/* Copyright (C) 2005, 2006 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 @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -33,6 +34,24 @@ mkdirat (fd, file, mode) const char *file; mode_t mode; { + int res; + +#ifdef __NR_mkdirat +# ifndef __ASSUME_ATFCTS + if (__have_atfcts >= 0) +# endif + { + res = INLINE_SYSCALL (mkdirat, 3, fd, file, mode); +# ifndef __ASSUME_ATFCTS + if (res == -1 && res == ENOSYS) + __have_atfcts = -1; + else +# endif + return res; + } +#endif + +#ifndef __ASSUME_ATFCTS char *buf = NULL; if (fd != AT_FDCWD && file[0] != '/') @@ -54,7 +73,7 @@ mkdirat (fd, file, mode) } INTERNAL_SYSCALL_DECL (err); - int res = INTERNAL_SYSCALL (mkdir, err, 2, file, mode); + res = INTERNAL_SYSCALL (mkdir, err, 2, file, mode); if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (res, err), 0)) { @@ -63,4 +82,5 @@ mkdirat (fd, file, mode) } return res; +#endif } diff --git a/sysdeps/unix/sysv/linux/openat.c b/sysdeps/unix/sysv/linux/openat.c index d5d976cbc4..7423800a13 100644 --- a/sysdeps/unix/sysv/linux/openat.c +++ b/sysdeps/unix/sysv/linux/openat.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2005 Free Software Foundation, Inc. +/* Copyright (C) 2005, 2006 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 @@ -23,12 +23,12 @@ #include #include #include +#include #include -#ifndef OPENAT +#if !defined OPENAT && !defined __ASSUME_ATFCTS # define OPENAT openat -# define MORE_OFLAGS 0 void @@ -53,6 +53,8 @@ __atfct_seterrno (int errval, int fd, const char *buf) __set_errno (errval); } + +int __have_atfcts; #endif /* Open FILE with access OFLAG. Interpret relative paths relative to @@ -64,6 +66,49 @@ OPENAT (fd, file, oflag) const char *file; int oflag; { + mode_t mode = 0; + if (oflag & O_CREAT) + { + va_list arg; + va_start (arg, oflag); + mode = va_arg (arg, mode_t); + va_end (arg); + } + + /* We have to add the O_LARGEFILE flag for openat64. */ +#ifdef MORE_OFLAGS + oflag |= MORE_OFLAGS; +#endif + + INTERNAL_SYSCALL_DECL (err); + int res; + +#ifdef __NR_openat +# ifndef __ASSUME_ATFCTS + if (__have_atfcts >= 0) +# endif + { + if (SINGLE_THREAD_P) + res = INLINE_SYSCALL (openat, 4, fd, file, oflag, mode); + else + { + int oldtype = LIBC_CANCEL_ASYNC (); + + res = INLINE_SYSCALL (openat, 4, fd, file, oflag, mode); + + LIBC_CANCEL_RESET (oldtype); + } + +# ifndef __ASSUME_ATFCTS + if (res == -1 && errno == ENOSYS) + __have_atfcts = -1; + else +# endif + return res; + } +#endif + +#ifndef __ASSUME_ATFCTS char *buf = NULL; if (fd != AT_FDCWD && file[0] != '/') @@ -84,25 +129,13 @@ OPENAT (fd, file, oflag) 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); + res = INTERNAL_SYSCALL (open, err, 3, file, oflag, mode); else { int oldtype = LIBC_CANCEL_ASYNC (); - res = INTERNAL_SYSCALL (open, err, 3, file, oflag | MORE_OFLAGS, mode); + res = INTERNAL_SYSCALL (open, err, 3, file, oflag, mode); LIBC_CANCEL_RESET (oldtype); } @@ -114,4 +147,5 @@ OPENAT (fd, file, oflag) } return res; +#endif } diff --git a/sysdeps/unix/sysv/linux/ppoll.c b/sysdeps/unix/sysv/linux/ppoll.c new file mode 100644 index 0000000000..cfc86ba806 --- /dev/null +++ b/sysdeps/unix/sysv/linux/ppoll.c @@ -0,0 +1,76 @@ +/* Copyright (C) 2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 2006. + + 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 + + +#ifdef __NR_ppoll +static int __generic_ppoll (struct pollfd *fds, nfds_t nfds, + const struct timespec *timeout, + const sigset_t *sigmask); + + +int +ppoll (struct pollfd *fds, nfds_t nfds, const struct timespec *timeout, + const sigset_t *sigmask) +{ + /* The Linux kernel can in some situations update the timeout value. + We do not want that so use a local variable. */ + struct timespec tval; + if (timeout != NULL) + { + tval = *timeout; + timeout = &tval; + } + + int result; + + if (SINGLE_THREAD_P) + result = INLINE_SYSCALL (ppoll, 5, fds, nfds, timeout, sigmask, _NSIG / 8); + else + { + int oldtype = LIBC_CANCEL_ASYNC (); + + result = INLINE_SYSCALL (ppoll, 5, fds, nfds, timeout, sigmask, + _NSIG / 8); + + LIBC_CANCEL_RESET (oldtype); + } + +# ifndef __ASSUME_PPOLL + if (result == -1 && errno == ENOSYS) + result = __generic_ppoll (fds, nfds, timeout, sigmask); +# endif + + return result; +} + +# ifndef __ASSUME_PPOLL +# define ppoll static __generic_ppoll +# endif +#endif + +#ifndef __ASSUME_PPOLL +# include +#endif diff --git a/sysdeps/unix/sysv/linux/pselect.c b/sysdeps/unix/sysv/linux/pselect.c new file mode 100644 index 0000000000..6fd4d3e071 --- /dev/null +++ b/sysdeps/unix/sysv/linux/pselect.c @@ -0,0 +1,92 @@ +/* Copyright (C) 2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 2006. + + 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 + + +#ifdef __NR_pselect6 +static int __generic_pselect (int nfds, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds, + const struct timespec *timeout, + const sigset_t *sigmask) + + +int +__pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, + const struct timespec *timeout, const sigset_t *sigmask) +{ + /* The Linux kernel can in some situations update the timeout value. + We do not want that so use a local variable. */ + struct timespec tval; + if (timeout != NULL) + { + tval = *timeout; + timeout = &tval; + } + + /* Note: the system call expects 7 values but on most architectures + we can only pass in 6 directly. If there is an architecture with + support for more parameters a new version of this file needs to + be created. */ + struct + { + sigset_t *ss; + size_t ss_len; + } data; + + data.ss = sigmask; + data.ss_len = _NSIG / 8; + + int result; + + if (SINGLE_THREAD_P) + result = INLINE_SYSCALL (pselect6, 6, nfds, readfds, writefds, exceptfds, + timeout, &data); + else + { + int oldtype = LIBC_CANCEL_ASYNC (); + + result = INLINE_SYSCALL (pselect6, 6, nfds, readfds, writefds, exceptfds, + timeout, &data); + + LIBC_CANCEL_RESET (oldtype); + } + +# ifndef __ASSUME_PSELECT + if (result == -1 && errno == ENOSYS) + result = __generic_pselect (nfds, readfds, writefds, exceptfds, timeout, + sigmask); +# endif + + return result; +} + +# ifndef __ASSUME_PSELECT +# define __pselect static __generic_pselect +# endif +#endif + +#ifndef __ASSUME_PSELECT +# include +#endif diff --git a/sysdeps/unix/sysv/linux/readlinkat.c b/sysdeps/unix/sysv/linux/readlinkat.c index 42c3877bd7..c2f21ee4ca 100644 --- a/sysdeps/unix/sysv/linux/readlinkat.c +++ b/sysdeps/unix/sysv/linux/readlinkat.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2005 Free Software Foundation, Inc. +/* Copyright (C) 2005, 2006 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 @@ -24,6 +24,7 @@ #include #include #include +#include /* Read the contents of the symbolic link PATH relative to FD into no @@ -35,6 +36,24 @@ readlinkat (fd, path, buf, len) char *buf; size_t len; { + int result; + +#ifdef __NR_readlinkat +# ifndef __ASSUME_ATFCTS + if (__have_atfcts >= 0) +# endif + { + result = INLINE_SYSCALL (readlinkat, 4, fd, path, buf, len); +# ifndef __ASSUME_ATFCTS + if (result == -1 && errno == ENOSYS) + __have_atfcts = -1; + else +# endif + return result; + } +#endif + +#ifndef __ASSUME_ATFCTS char *pathbuf = NULL; if (fd != AT_FDCWD && path[0] != '/') @@ -57,7 +76,7 @@ readlinkat (fd, path, buf, len) INTERNAL_SYSCALL_DECL (err); - int result = INTERNAL_SYSCALL (readlink, err, 3, path, buf, len); + result = INTERNAL_SYSCALL (readlink, err, 3, path, buf, len); if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (result, err), 0)) { @@ -66,4 +85,5 @@ readlinkat (fd, path, buf, len) } return result; +#endif } diff --git a/sysdeps/unix/sysv/linux/renameat.c b/sysdeps/unix/sysv/linux/renameat.c index 849c67b5d6..bc8ced42df 100644 --- a/sysdeps/unix/sysv/linux/renameat.c +++ b/sysdeps/unix/sysv/linux/renameat.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2005 Free Software Foundation, Inc. +/* Copyright (C) 2005, 2006 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 @@ -20,9 +20,11 @@ #include #include #include +#include #include +#ifndef __ASSUME_ATFCTS void attribute_hidden __atfct_seterrno_2 (int errval, int fd1, const char *buf1, int fd2, @@ -67,6 +69,7 @@ __atfct_seterrno_2 (int errval, int fd1, const char *buf1, int fd2, out: __set_errno (errval); } +#endif /* Rename the file OLD relative to OLDFD to NEW relative to NEWFD. */ @@ -77,6 +80,24 @@ renameat (oldfd, old, newfd, new) int newfd; const char *new; { + int result; + +#ifdef __NR_renameat +# ifndef __ASSUME_ATFCTS + if (__have_atfcts >= 0) +# endif + { + result = INLINE_SYSCALL (renameat, 4, oldfd, old, newfd, new); +# ifndef __ASSUME_ATFCTS + if (result == -1 && errno == ENOSYS) + __have_atfcts = -1; + else +# endif + return result; + } +#endif + +#ifndef __ASSUME_ATFCTS static const char procfd[] = "/proc/self/fd/%d/%s"; char *bufold = NULL; @@ -118,7 +139,7 @@ renameat (oldfd, old, newfd, new) INTERNAL_SYSCALL_DECL (err); - int result = INTERNAL_SYSCALL (rename, err, 2, old, new); + result = INTERNAL_SYSCALL (rename, err, 2, old, new); if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (result, err), 0)) { @@ -128,4 +149,5 @@ renameat (oldfd, old, newfd, new) } return result; +#endif } diff --git a/sysdeps/unix/sysv/linux/symlinkat.c b/sysdeps/unix/sysv/linux/symlinkat.c index 211b49c299..4cfc924bfc 100644 --- a/sysdeps/unix/sysv/linux/symlinkat.c +++ b/sysdeps/unix/sysv/linux/symlinkat.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2005 Free Software Foundation, Inc. +/* Copyright (C) 2005, 2006 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 @@ -24,6 +24,7 @@ #include #include #include +#include /* Make a symbolic link to FROM named TO relative to TOFD. */ @@ -33,6 +34,24 @@ symlinkat (from, tofd, to) int tofd; const char *to; { + int result; + +#ifdef __NR_symlinkat +# ifndef __ASSUME_ATFCTS + if (__have_atfcts >= 0) +# endif + { + result = INLINE_SYSCALL (symlinkat, 3, from, tofd, to); +# ifndef __ASSUME_ATFCTS + if (result == -1 && errno == ENOSYS) + __have_atfcts = -1; + else +# endif + return result; + } +#endif + +#ifndef __ASSUME_ATFCTS char *buf = NULL; if (tofd != AT_FDCWD && to[0] != '/') @@ -55,7 +74,7 @@ symlinkat (from, tofd, to) INTERNAL_SYSCALL_DECL (err); - int result = INTERNAL_SYSCALL (symlink, err, 2, from, to); + result = INTERNAL_SYSCALL (symlink, err, 2, from, to); if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (result, err), 0)) { @@ -64,4 +83,5 @@ symlinkat (from, tofd, to) } return result; +#endif } diff --git a/sysdeps/unix/sysv/linux/unlinkat.c b/sysdeps/unix/sysv/linux/unlinkat.c index 821029f5e5..0a07a8a875 100644 --- a/sysdeps/unix/sysv/linux/unlinkat.c +++ b/sysdeps/unix/sysv/linux/unlinkat.c @@ -1,5 +1,5 @@ /* unlinkat -- Remove a link by relative name. - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005, 2006 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 @@ -25,6 +25,7 @@ #include #include #include +#include /* Remove the link named NAME. */ @@ -34,6 +35,24 @@ unlinkat (fd, file, flag) const char *file; int flag; { + int result; + +#ifdef __NR_unlinkat +# ifndef __ASSUME_ATFCTS + if (__have_atfcts >= 0) +# endif + { + result = INLINE_SYSCALL (unlinkat, 3, fd, file, flag); +# ifndef __ASSUME_ATFCTS + if (result == -1 && errno == ENOSYS) + __have_atfcts = -1; + else +# endif + return result; + } +#endif + +#ifndef __ASSUME_ATFCTS if (flag & ~AT_REMOVEDIR) { __set_errno (EINVAL); @@ -60,7 +79,6 @@ unlinkat (fd, file, flag) file = buf; } - int result; INTERNAL_SYSCALL_DECL (err); if (flag & AT_REMOVEDIR) @@ -75,4 +93,5 @@ unlinkat (fd, file, flag) } return result; +#endif } diff --git a/sysdeps/unix/sysv/linux/wordsize-64/fxstatat.c b/sysdeps/unix/sysv/linux/wordsize-64/fxstatat.c index 159301c172..0c37495575 100644 --- a/sysdeps/unix/sysv/linux/wordsize-64/fxstatat.c +++ b/sysdeps/unix/sysv/linux/wordsize-64/fxstatat.c @@ -28,15 +28,40 @@ #include #include +#include #include #include + /* Get information about the file NAME relative to FD in ST. */ int __fxstatat (int vers, int fd, const char *file, struct stat *st, int flag) { - if ((vers != _STAT_VER_KERNEL && vers != _STAT_VER_LINUX) - || (flag & ~AT_SYMLINK_NOFOLLOW) != 0) + if (vers != _STAT_VER_KERNEL && vers != _STAT_VER_LINUX) + { + __set_errno (EINVAL); + return -1; + } + + int res; + +#ifdef __NR_newfstatat +# ifndef __ASSUME_ATFCTS + if (__have_atfcts >= 0) +# endif + { + res = INLINE_SYSCALL (newfstatat, 4, fd, file, st, flag); +# ifndef __ASSUME_ATFCTS + if (res == -1 && errno == ENOSYS) + __have_atfcts = -1; + else +# endif + return res; + } +#endif + +#ifndef __ASSUME_ATFCTS + if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0) { __set_errno (EINVAL); return -1; @@ -63,7 +88,6 @@ __fxstatat (int vers, int fd, const char *file, struct stat *st, int flag) } INTERNAL_SYSCALL_DECL (err); - int res; if (flag & AT_SYMLINK_NOFOLLOW) res = INTERNAL_SYSCALL (lstat, err, 2, file, CHECK_1 (st)); @@ -77,6 +101,7 @@ __fxstatat (int vers, int fd, const char *file, struct stat *st, int flag) } return res; +#endif } #undef __fxstatat64 strong_alias (__fxstatat, __fxstatat64); diff --git a/sysdeps/unix/sysv/linux/xmknodat.c b/sysdeps/unix/sysv/linux/xmknodat.c index 9332ae683e..d6cb4ed1be 100644 --- a/sysdeps/unix/sysv/linux/xmknodat.c +++ b/sysdeps/unix/sysv/linux/xmknodat.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2005 Free Software Foundation, Inc. +/* Copyright (C) 2005, 2006 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 @@ -25,9 +25,11 @@ #include #include +#include #include #include + /* Create a device file named PATH relative to FD, with permission and special bits MODE and device number DEV (which can be constructed from major and minor device numbers with the `makedev' macro above). */ @@ -40,6 +42,30 @@ __xmknodat (int vers, int fd, const char *file, mode_t mode, dev_t *dev) return -1; } + /* We must convert the value to dev_t type used by the kernel. */ + unsigned long long int k_dev = (*dev) & ((1ULL << 32) - 1); + if (k_dev != *dev) + { + __set_errno (EINVAL); + return -1; + } + +#ifdef __NR_mknodat +# ifndef __ASSUME_ATFCTS + if (__have_atfcts >= 0) +# endif + { + int res = INLINE_SYSCALL (mknodat, 4, fd, file, mode, k_dev); +# ifndef __ASSUME_ATFCTS + if (res == -1 && errno == ENOSYS) + __have_atfcts = -1; + else +# endif + return res; + } +#endif + +#ifndef __ASSUME_ATFCTS char *buf = NULL; if (fd != AT_FDCWD && file[0] != '/') @@ -60,16 +86,9 @@ __xmknodat (int vers, int fd, const char *file, mode_t mode, dev_t *dev) file = buf; } - /* We must convert the value to dev_t type used by the kernel. */ - unsigned long long int k_dev = (*dev) & ((1ULL << 32) - 1); - if (k_dev != *dev) - { - __set_errno (EINVAL); - return -1; - } - return INLINE_SYSCALL (mknod, 3, CHECK_STRING (file), mode, (unsigned int) k_dev); +#endif } libc_hidden_def (__xmknodat) -- cgit 1.4.1