From 6fb2dde3f1aa3a1419cb6c2dfa53dd1d506722a4 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Sun, 8 May 2011 14:53:20 -0400 Subject: [PATCH] Make complete getcwd work in rtld --- ChangeLog | 13 +++++++--- include/sys/stat.h | 4 +++ sysdeps/posix/getcwd.c | 43 +++++++++++++++++---------------- sysdeps/unix/rewinddir.c | 5 +++- sysdeps/unix/sysv/linux/Makefile | 3 ++- sysdeps/unix/sysv/linux/dl-fxstatat64.c | 6 +++++ sysdeps/unix/sysv/linux/dl-openat64.c | 40 ++++++++++++++++++++++++++++++ sysdeps/unix/sysv/linux/dl-opendir.c | 6 +++++ sysdeps/unix/sysv/linux/getcwd.c | 8 ------ 9 files changed, 93 insertions(+), 35 deletions(-) create mode 100644 sysdeps/unix/sysv/linux/dl-fxstatat64.c create mode 100644 sysdeps/unix/sysv/linux/dl-openat64.c create mode 100644 sysdeps/unix/sysv/linux/dl-opendir.c diff --git a/ChangeLog b/ChangeLog index 488ce8f..3454901 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,15 +3,20 @@ [BZ #12713] * sysdeps/unix/sysv/linux/getcwd.c: If getcwd syscall report ENAMETOOLONG use generic getcwd. - * sysdeps/posix/getcwd.c: Add support to use openat. + * sysdeps/posix/getcwd.c: Add support to use openat. Make usable + in rtld. Use *stat64. * sysdeps/unix/sysv/linux/Makefile [subdir=elf] (sysdep-rtld-routines): - Add dl-getcwd. + Add dl-getcwd, dl-openat64, dl-opendir, dl-fxstatat64. * sysdeps/unix/sysv/linux/dl-getcwd.c: New file. - * include/sys/stat.h: Define __fstatat macro. + * sysdeps/unix/sysv/linux/dl-openat64.c: New file. + * sysdeps/unix/sysv/linux/dl-opendir.c: New file. + * sysdeps/unix/sysv/linux/dl-fxstat64.c: New file. + * include/sys/stat.h: Define __fstatat, __lstat64, __fstat64, and + __fstatat64 macros. * include/dirent.h: Add libc_hidden_proto for rewinddir. * dirent/rewinddir.c: Add libc_hidden_def. * sysdeps/mach/hurd/rewinddir.c: Likewise. - * sysdeps/unix/rewinddir.c: Likewise. + * sysdeps/unix/rewinddir.c: Likewise. Don't do locking outside libc. * include/dirent.h (__alloc_dir): Add flags parameter. * sysdeps/unix/fdopendir.c (__fdopendir): Pass flags to __alloc_dir. diff --git a/include/sys/stat.h b/include/sys/stat.h index e00df53..cca0500 100644 --- a/include/sys/stat.h +++ b/include/sys/stat.h @@ -44,10 +44,14 @@ libc_hidden_proto (__fxstatat64) #define lstat(fname, buf) __lxstat (_STAT_VER, fname, buf) #define __lstat(fname, buf) __lxstat (_STAT_VER, fname, buf) #define lstat64(fname, buf) __lxstat64 (_STAT_VER, fname, buf) +#define __lstat64(fname, buf) __lxstat64 (_STAT_VER, fname, buf) #define stat64(fname, buf) __xstat64 (_STAT_VER, fname, buf) #define fstat64(fd, buf) __fxstat64 (_STAT_VER, fd, buf) +#define __fstat64(fd, buf) __fxstat64 (_STAT_VER, fd, buf) #define fstat(fd, buf) __fxstat (_STAT_VER, fd, buf) #define __fstat(fd, buf) __fxstat (_STAT_VER, fd, buf) #define __fstatat(dfd, fname, buf, flag) \ __fxstatat (_STAT_VER, dfd, fname, buf, flag) +#define __fstatat64(dfd, fname, buf, flag) \ + __fxstatat64 (_STAT_VER, dfd, fname, buf, flag) #endif diff --git a/sysdeps/posix/getcwd.c b/sysdeps/posix/getcwd.c index f683158..847abc5 100644 --- a/sysdeps/posix/getcwd.c +++ b/sysdeps/posix/getcwd.c @@ -172,10 +172,10 @@ extern char *alloca (); # include #endif -#if defined _LIBC && !defined NOT_IN_libc +#if defined _LIBC # include #else -# define openat_not_cancel_3(dfd, name, mode) openat (dfd, name, mode) +# define openat64_not_cancel_3(dfd, name, mode) openat64 (dfd, name, mode) # define close_not_cancel_no_status(fd) close (fd) #endif @@ -197,7 +197,7 @@ extern char *alloca (); #endif #ifndef __GNU_LIBRARY__ -# define __lstat stat +# define __lstat64 stat64 #endif #ifndef _LIBC @@ -209,9 +209,10 @@ extern char *alloca (); #endif #ifdef __ASSUME_ATFCTS -# define have_openat 1 -#else -static int have_openat = 0; +# define __have_atfcts 1 +#elif defined NOT_IN_libc && defined IS_IN_rtld +static int __rtld_have_atfcts; +# define __have_atfcts __rtld_have_atfcts #endif /* Get the pathname of the current working directory, and put it in SIZE @@ -268,39 +269,39 @@ __getcwd (buf, size) char *pathp = path + allocated; *--pathp = '\0'; - struct stat st; - if (__lstat (".", &st) < 0) + struct stat64 st; + if (__lstat64 (".", &st) < 0) goto lose; dev_t thisdev = st.st_dev; ino_t thisino = st.st_ino; - if (__lstat ("/", &st) < 0) + if (__lstat64 ("/", &st) < 0) goto lose; dev_t rootdev = st.st_dev; ino_t rootino = st.st_ino; while (!(thisdev == rootdev && thisino == rootino)) { - if (have_openat >= 0) + if (__have_atfcts >= 0) { int mode = O_RDONLY; #ifdef O_CLOEXEC mode |= O_CLOEXEC; #endif - fd = openat_not_cancel_3 (fd, "..", mode); + fd = openat64_not_cancel_3 (fd, "..", mode); } else fd = -1; if (fd >= 0) { fd_needs_closing = true; - if (__fstat (fd, &st) < 0) + if (__fstat64 (fd, &st) < 0) goto lose; } #ifndef __ASSUME_ATFCTS else if (errno == ENOSYS) { - have_openat = -1; + __have_atfcts = -1; /* Look at the parent directory. */ if (dotp == dotlist) @@ -345,7 +346,7 @@ __getcwd (buf, size) dotp -= 3; /* Figure out if this directory is a mount point. */ - if (__lstat (dotp, &st) < 0) + if (__lstat64 (dotp, &st) < 0) goto lose; } #endif @@ -363,7 +364,7 @@ __getcwd (buf, size) bool mount_point = dotdev != thisdev; /* Search for the last directory. */ - if (have_openat >= 0) + if (__have_atfcts >= 0) dirstream = __fdopendir (fd); #ifndef __ASSUME_ATFCTS else @@ -388,7 +389,7 @@ __getcwd (buf, size) /* When we've iterated through all directory entries without finding one with a matching d_ino, rewind the stream and consider each name again, but this time, using - lstat. This is necessary in a chroot on at least one + lstat64. This is necessary in a chroot on at least one system. */ if (use_d_ino) { @@ -413,14 +414,14 @@ __getcwd (buf, size) if (use_d_ino && !mount_point && (ino_t) d->d_ino != thisino) continue; - if (have_openat >= 0) + if (__have_atfcts >= 0) { - /* We don't fail here if we cannot stat() a directory entry. + /* We don't fail here if we cannot stat64() a directory entry. This can happen when (network) filesystems fail. If this entry is in fact the one we are looking for we will find out soon as we reach the end of the directory without having found anything. */ - if (__fstatat (fd, d->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) + if (__fstatat64 (fd, d->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) continue; } #ifndef __ASSUME_ATFCTS @@ -436,12 +437,12 @@ __getcwd (buf, size) name[dotlist + dotsize - dotp] = '/'; strcpy (&name[dotlist + dotsize - dotp + 1], d->d_name); # endif - /* We don't fail here if we cannot stat() a directory entry. + /* We don't fail here if we cannot stat64() a directory entry. This can happen when (network) filesystems fail. If this entry is in fact the one we are looking for we will find out soon as we reach the end of the directory without having found anything. */ - if (__lstat (name, &st) < 0) + if (__lstat64 (name, &st) < 0) continue; } #endif diff --git a/sysdeps/unix/rewinddir.c b/sysdeps/unix/rewinddir.c index 89b0e6d..9672893 100644 --- a/sysdeps/unix/rewinddir.c +++ b/sysdeps/unix/rewinddir.c @@ -23,16 +23,19 @@ #include /* Rewind DIRP to the beginning of the directory. */ -/* XXX should be __rewinddir ? */ void rewinddir (dirp) DIR *dirp; { +#ifndef NOT_IN_libc __libc_lock_lock (dirp->lock); +#endif (void) __lseek (dirp->fd, (off_t) 0, SEEK_SET); dirp->filepos = 0; dirp->offset = 0; dirp->size = 0; +#ifndef NOT_IN_libc __libc_lock_unlock (dirp->lock); +#endif } libc_hidden_def (rewinddir) diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile index 61fbfb4..3b4b63f 100644 --- a/sysdeps/unix/sysv/linux/Makefile +++ b/sysdeps/unix/sysv/linux/Makefile @@ -147,7 +147,8 @@ sysdep_routines += xstatconv internal_statvfs internal_statvfs64 \ endif ifeq ($(subdir),elf) -sysdep-rtld-routines += dl-brk dl-sbrk dl-getcwd +sysdep-rtld-routines += dl-brk dl-sbrk dl-getcwd dl-openat64 dl-opendir \ + dl-fxstatat64 CPPFLAGS-lddlibc4 += -DNOT_IN_libc endif diff --git a/sysdeps/unix/sysv/linux/dl-fxstatat64.c b/sysdeps/unix/sysv/linux/dl-fxstatat64.c new file mode 100644 index 0000000..9a17a9b --- /dev/null +++ b/sysdeps/unix/sysv/linux/dl-fxstatat64.c @@ -0,0 +1,6 @@ +/* In this implementation we do not really care whether the call fails + because of missing kernel support since we do not even call the + function in this case. */ +#undef __ASSUME_ATFCTS +#define __ASSUME_ATFCTS 1 +#include "fxstatat64.c" diff --git a/sysdeps/unix/sysv/linux/dl-openat64.c b/sysdeps/unix/sysv/linux/dl-openat64.c new file mode 100644 index 0000000..ca296fd --- /dev/null +++ b/sysdeps/unix/sysv/linux/dl-openat64.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2011 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 2003. + + 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 + + +int +openat64 (dfd, file, oflag) + int dfd; + const char *file; + int oflag; +{ + assert ((oflag & O_CREAT) == 0); + +#ifdef __NR_openat + return INLINE_SYSCALL (openat, 3, dfd, file, oflag | O_LARGEFILE); +#else + __set_errno (ENOSYS); + return -1; +#endif +} diff --git a/sysdeps/unix/sysv/linux/dl-opendir.c b/sysdeps/unix/sysv/linux/dl-opendir.c new file mode 100644 index 0000000..72d2c06 --- /dev/null +++ b/sysdeps/unix/sysv/linux/dl-opendir.c @@ -0,0 +1,6 @@ +/* In this implementation we do not really care whether the opened + file descriptor has the CLOEXEC bit set. The only call happens + long before there is a call to fork or exec. */ +#undef __ASSUME_O_CLOEXEC +#define __ASSUME_O_CLOEXEC 1 +#include diff --git a/sysdeps/unix/sysv/linux/getcwd.c b/sysdeps/unix/sysv/linux/getcwd.c index db3e292..fb0dcef 100644 --- a/sysdeps/unix/sysv/linux/getcwd.c +++ b/sysdeps/unix/sysv/linux/getcwd.c @@ -124,9 +124,6 @@ __getcwd (char *buf, size_t size) return buf; } - // XXX This should not be necessary but the full getcwd implementation - // drags in too much for the current build proces of ld.so to handle -#ifndef NOT_IN_libc /* The system call cannot handle paths longer than a page. Neither can the magic symlink in /proc/self. Just use the generic implementation right away. */ @@ -149,7 +146,6 @@ __getcwd (char *buf, size_t size) return result; } -#endif # if __ASSUME_GETCWD_SYSCALL /* It should never happen that the `getcwd' syscall failed because @@ -241,11 +237,7 @@ __getcwd (char *buf, size_t size) } weak_alias (__getcwd, getcwd) - // XXX This should not be necessary but the full getcwd implementation - // drags in too much for the current build proces of ld.so to handle -#ifndef NOT_IN_libc /* Get the code for the generic version. */ #define GETCWD_RETURN_TYPE static char * internal_function #define __getcwd generic_getcwd #include -#endif -- 2.7.4