Make complete getcwd work in rtld
authorUlrich Drepper <drepper@gmail.com>
Sun, 8 May 2011 18:53:20 +0000 (14:53 -0400)
committerUlrich Drepper <drepper@gmail.com>
Sun, 8 May 2011 18:53:20 +0000 (14:53 -0400)
ChangeLog
include/sys/stat.h
sysdeps/posix/getcwd.c
sysdeps/unix/rewinddir.c
sysdeps/unix/sysv/linux/Makefile
sysdeps/unix/sysv/linux/dl-fxstatat64.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/dl-openat64.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/dl-opendir.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/getcwd.c

index 488ce8f..3454901 100644 (file)
--- 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.
index e00df53..cca0500 100644 (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
index f683158..847abc5 100644 (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
 \f
 #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
index 89b0e6d..9672893 100644 (file)
 #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)
index 61fbfb4..3b4b63f 100644 (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
diff --git a/sysdeps/unix/sysv/linux/dl-fxstatat64.c b/sysdeps/unix/sysv/linux/dl-fxstatat64.c
new file mode 100644 (file)
index 0000000..9a17a9b
--- /dev/null
@@ -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 (file)
index 0000000..ca296fd
--- /dev/null
@@ -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
+}
diff --git a/sysdeps/unix/sysv/linux/dl-opendir.c b/sysdeps/unix/sysv/linux/dl-opendir.c
new file mode 100644 (file)
index 0000000..72d2c06
--- /dev/null
@@ -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>
index db3e292..fb0dcef 100644 (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