diff --git a/elf/dl-object.c b/elf/dl-object.c
index d2cdf135cc..bddef4485f 100644
--- a/elf/dl-object.c
+++ b/elf/dl-object.c
@@ -202,38 +202,29 @@ _dl_new_object (char *realname, const char *libname, int type,
}
else
{
- size_t len = realname_len;
- char *result = NULL;
-
- /* Get the current directory name. */
- origin = NULL;
- do
+ /* The rtld __getcwd implementation does not handle paths larger
+ than PATH_MAX (which would be invalid to be used on subsequent
+ open calls). */
+ origin = __getcwd (NULL, 0);
+ if (origin == NULL)
{
- char *new_origin;
-
- len += 128;
- new_origin = (char *) realloc (origin, len);
- if (new_origin == NULL)
- /* We exit the loop. Note that result == NULL. */
- break;
- origin = new_origin;
+ origin = (char *) -1;
+ goto out;
}
- while ((result = __getcwd (origin, len - realname_len)) == NULL
- && errno == ERANGE);
-
+ size_t len = strlen (origin);
+ char *result = realloc (origin, len + realname_len);
if (result == NULL)
{
- /* We were not able to determine the current directory.
- Note that free(origin) is OK if origin == NULL. */
free (origin);
origin = (char *) -1;
goto out;
}
+ origin = result;
+ cp = origin + len;
/* Find the end of the path and see whether we have to add a
slash. We could use rawmemchr but this need not be
fast. */
- cp = (strchr) (origin, '\0');
if (cp[-1] != '/')
*cp++ = '/';
}
diff --git a/include/unistd.h b/include/unistd.h
index f48da2c7a3..792cfdff0b 100644
--- a/include/unistd.h
+++ b/include/unistd.h
@@ -76,6 +76,8 @@ extern int __lchown (const char *__file, __uid_t __owner,
__gid_t __group);
extern int __chdir (const char *__path) attribute_hidden;
extern int __fchdir (int __fd) attribute_hidden;
+extern char *__getcwd_generic (char *__buf, size_t __size) attribute_hidden;
+extern char *__getcwd_system (char *__buf, size_t __size) attribute_hidden;
extern char *__getcwd (char *__buf, size_t __size);
libc_hidden_proto (__getcwd)
extern int __rmdir (const char *__path) attribute_hidden;
diff --git a/io/Makefile b/io/Makefile
index cf380f3516..57cb778790 100644
--- a/io/Makefile
+++ b/io/Makefile
@@ -46,7 +46,7 @@ routines := \
close dup dup2 dup3 pipe pipe2 \
creat creat64 \
chdir fchdir \
- getcwd getwd getdirname \
+ getcwd getwd getcwd-system getdirname \
chown fchown lchown fchownat \
ttyname ttyname_r isatty \
link linkat symlink symlinkat readlink readlinkat \
diff --git a/sysdeps/posix/getcwd.c b/io/getcwd-generic.c
similarity index 98%
rename from sysdeps/posix/getcwd.c
rename to io/getcwd-generic.c
index 1e6fc9b845..3b4be6bdaa 100644
--- a/sysdeps/posix/getcwd.c
+++ b/io/getcwd-generic.c
@@ -89,7 +89,7 @@
#if !_LIBC
# define __close_nocancel_nostatus close
-# define __getcwd rpl_getcwd
+# define __getcwd_generic rpl_getcwd
# define stat64 stat
# define __fstat64 fstat
# define __fstatat64 fstatat
@@ -154,7 +154,7 @@ getcwd_nothrow (char *buf, size_t size)
bytes long, unless SIZE == 0, in which case it is as big as necessary. */
char *
-__getcwd (char *buf, size_t size)
+__getcwd_generic (char *buf, size_t size)
{
/* Lengths of big file name components and entire file names, and a
deep level of file name nesting. These numbers are not upper
@@ -486,8 +486,3 @@ __getcwd (char *buf, size_t size)
}
return NULL;
}
-
-#if defined _LIBC && !defined __getcwd
-libc_hidden_def (__getcwd)
-weak_alias (__getcwd, getcwd)
-#endif
diff --git a/io/getcwd-system.c b/io/getcwd-system.c
new file mode 100644
index 0000000000..b0ae6271ab
--- /dev/null
+++ b/io/getcwd-system.c
@@ -0,0 +1,28 @@
+/* Architecture specific getcwd implementation. Generic implementation.
+ Copyright (C) 2020 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, see
+ . */
+
+#include
+
+/* This function is called by the generic 'getcwd' implementation to allow
+ a system to implement if the it provides a faster or simpler way to obtain
+ the current direction (e.g. through a syscall). */
+char *
+__getcwd_system (char *buf, size_t size)
+{
+ return NULL;
+}
diff --git a/io/getcwd.c b/io/getcwd.c
index 0fabd98131..0e0a790368 100644
--- a/io/getcwd.c
+++ b/io/getcwd.c
@@ -19,6 +19,11 @@
#include
#include
+/* The rtld does not need to handle path larger than PATH_MAX. */
+#if !IS_IN(rtld)
+#include
+#endif
+
/* Get the pathname of the current working directory,
and put it in SIZE bytes of BUF. Returns NULL if the
directory couldn't be determined or SIZE was too small.
@@ -29,11 +34,12 @@
char *
__getcwd (char *buf, size_t size)
{
- __set_errno (ENOSYS);
- return NULL;
+ char *r = __getcwd_system (buf, size);
+#if !IS_IN(rtld)
+ if (r == NULL)
+ r = __getcwd_generic (buf, size);
+#endif
+ return r;
}
libc_hidden_def (__getcwd)
weak_alias (__getcwd, getcwd)
-
-stub_warning (__getcwd)
-stub_warning (getcwd)
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index 9b2a253032..465ffe7104 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -280,8 +280,7 @@ tests += tst-fallocate tst-fallocate64 tst-o_path-locks
endif
ifeq ($(subdir),elf)
-sysdep-rtld-routines += dl-brk dl-sbrk dl-getcwd dl-openat64 dl-opendir \
- dl-fxstatat64
+sysdep-rtld-routines += dl-brk dl-sbrk dl-openat64 dl-opendir
libof-lddlibc4 = lddlibc4
diff --git a/sysdeps/unix/sysv/linux/alpha/dl-fxstatat64.c b/sysdeps/unix/sysv/linux/alpha/dl-fxstatat64.c
deleted file mode 100644
index 330b33f7c7..0000000000
--- a/sysdeps/unix/sysv/linux/alpha/dl-fxstatat64.c
+++ /dev/null
@@ -1 +0,0 @@
-#include "fxstatat.c"
diff --git a/sysdeps/unix/sysv/linux/dl-fxstatat64.c b/sysdeps/unix/sysv/linux/dl-fxstatat64.c
deleted file mode 100644
index d229d0ea0f..0000000000
--- a/sysdeps/unix/sysv/linux/dl-fxstatat64.c
+++ /dev/null
@@ -1 +0,0 @@
-#include
diff --git a/sysdeps/unix/sysv/linux/dl-getcwd.c b/sysdeps/unix/sysv/linux/dl-getcwd.c
deleted file mode 100644
index 4bd5657f1e..0000000000
--- a/sysdeps/unix/sysv/linux/dl-getcwd.c
+++ /dev/null
@@ -1 +0,0 @@
-#include "getcwd.c"
diff --git a/sysdeps/unix/sysv/linux/getcwd-system.c b/sysdeps/unix/sysv/linux/getcwd-system.c
new file mode 100644
index 0000000000..a2df688127
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/getcwd-system.c
@@ -0,0 +1,69 @@
+/* Determine current working directory. Linux version.
+ Copyright (C) 1997-2020 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper , 1997.
+
+ 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, see
+ . */
+
+#include
+#include
+#include
+
+char *
+__getcwd_system (char *buf, size_t size)
+{
+ char *path;
+
+ size_t alloc_size = size;
+ if (size == 0)
+ {
+ if (buf != NULL)
+ {
+ __set_errno (EINVAL);
+ return NULL;
+ }
+
+ alloc_size = PATH_MAX;
+ }
+
+ if (buf == NULL)
+ {
+ path = malloc (alloc_size);
+ if (path == NULL)
+ return NULL;
+ }
+ else
+ path = buf;
+
+ int r = INLINE_SYSCALL_CALL (getcwd, path, alloc_size);
+ if (r > 0 && path[0] == '/')
+ {
+ if (buf == NULL && size == 0)
+ /* Ensure that the buffer is only as large as necessary. */
+ buf = realloc (path, r);
+
+ if (buf == NULL)
+ /* Either buf was NULL all along, or `realloc' failed but
+ we still have the original string. */
+ buf = path;
+
+ return buf;
+ }
+
+ if (buf == NULL)
+ free (path);
+
+ return NULL;
+}
diff --git a/sysdeps/unix/sysv/linux/getcwd.c b/sysdeps/unix/sysv/linux/getcwd.c
deleted file mode 100644
index fabc4bb8cc..0000000000
--- a/sysdeps/unix/sysv/linux/getcwd.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/* Determine current working directory. Linux version.
- Copyright (C) 1997-2020 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper , 1997.
-
- 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, see
- . */
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-
-
-/* If we compile the file for use in ld.so we don't need the feature
- that getcwd() allocates the buffers itself. */
-#if IS_IN (rtld)
-# define NO_ALLOCATION 1
-#endif
-
-
-/* The "proc" filesystem provides an easy method to retrieve the value.
- For each process, the corresponding directory contains a symbolic link
- named `cwd'. Reading the content of this link immediate gives us the
- information. But we have to take care for systems which do not have
- the proc filesystem mounted. Use the POSIX implementation in this case. */
-static char *generic_getcwd (char *buf, size_t size);
-
-char *
-__getcwd (char *buf, size_t size)
-{
- char *path;
- char *result;
-
-#ifndef NO_ALLOCATION
- size_t alloc_size = size;
- if (size == 0)
- {
- if (buf != NULL)
- {
- __set_errno (EINVAL);
- return NULL;
- }
-
- alloc_size = MAX (PATH_MAX, __getpagesize ());
- }
-
- if (buf == NULL)
- {
- path = malloc (alloc_size);
- if (path == NULL)
- return NULL;
- }
- else
-#else
-# define alloc_size size
-#endif
- path = buf;
-
- int retval;
-
- retval = INLINE_SYSCALL (getcwd, 2, path, alloc_size);
- if (retval > 0 && path[0] == '/')
- {
-#ifndef NO_ALLOCATION
- if (buf == NULL && size == 0)
- /* Ensure that the buffer is only as large as necessary. */
- buf = realloc (path, (size_t) retval);
-
- if (buf == NULL)
- /* Either buf was NULL all along, or `realloc' failed but
- we still have the original string. */
- buf = path;
-#endif
-
- return buf;
- }
-
- /* The system call either cannot handle paths longer than a page
- or can succeed without returning an absolute path. Just use the
- generic implementation right away. */
- if (retval >= 0 || errno == ENAMETOOLONG)
- {
-#ifndef NO_ALLOCATION
- if (buf == NULL && size == 0)
- {
- free (path);
- path = NULL;
- }
-#endif
-
- result = generic_getcwd (path, size);
-
-#ifndef NO_ALLOCATION
- if (result == NULL && buf == NULL && size != 0)
- free (path);
-#endif
-
- return result;
- }
-
- /* It should never happen that the `getcwd' syscall failed because
- the buffer is too small if we allocated the buffer ourselves
- large enough. */
- assert (errno != ERANGE || buf != NULL || size != 0);
-
-#ifndef NO_ALLOCATION
- if (buf == NULL)
- free (path);
-#endif
-
- return NULL;
-}
-libc_hidden_def (__getcwd)
-weak_alias (__getcwd, getcwd)
-
-/* Get the code for the generic version. */
-#define GETCWD_RETURN_TYPE static char *
-#define __getcwd generic_getcwd
-#include
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/dl-fxstatat64.c b/sysdeps/unix/sysv/linux/sparc/sparc64/dl-fxstatat64.c
deleted file mode 100644
index 330b33f7c7..0000000000
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/dl-fxstatat64.c
+++ /dev/null
@@ -1 +0,0 @@
-#include "fxstatat.c"
diff --git a/sysdeps/unix/sysv/linux/wordsize-64/dl-fxstatat64.c b/sysdeps/unix/sysv/linux/wordsize-64/dl-fxstatat64.c
deleted file mode 100644
index 330b33f7c7..0000000000
--- a/sysdeps/unix/sysv/linux/wordsize-64/dl-fxstatat64.c
+++ /dev/null
@@ -1 +0,0 @@
-#include "fxstatat.c"