Make complete getcwd work in rtld

This commit is contained in:
Ulrich Drepper 2011-05-08 14:53:20 -04:00
parent 7fb90fb89b
commit 6fb2dde3f1
9 changed files with 93 additions and 35 deletions

View File

@ -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.

View File

@ -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

View File

@ -172,10 +172,10 @@ extern char *alloca ();
# include <sys/param.h>
#endif
#if defined _LIBC && !defined NOT_IN_libc
#if defined _LIBC
# include <not-cancel.h>
#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

View File

@ -23,16 +23,19 @@
#include <dirstream.h>
/* 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)

View File

@ -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

View File

@ -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"

View File

@ -0,0 +1,40 @@
/* Copyright (C) 2011 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@gmain.com>, 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 <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <sysdep.h>
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
}

View File

@ -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 <opendir.c>

View File

@ -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 <sysdeps/posix/getcwd.c>
#endif