summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libc/sysdeps/linux/common/syscalls.c8
-rw-r--r--libc/unistd/getcwd.c134
2 files changed, 72 insertions, 70 deletions
diff --git a/libc/sysdeps/linux/common/syscalls.c b/libc/sysdeps/linux/common/syscalls.c
index 5d826927e..542ec1b96 100644
--- a/libc/sysdeps/linux/common/syscalls.c
+++ b/libc/sysdeps/linux/common/syscalls.c
@@ -1613,7 +1613,13 @@ _syscall3(int, chown, const char *, path, uid_t, owner, gid_t, group);
#endif
//#define __NR_getcwd 183
-// See unistd/getcwd.c -- we don't use this syscall, even when it is available...
+#ifdef L_getcwd
+# ifdef __NR_getcwd
+ _syscall2(int, getcwd, char *, buf, unsigned long, size);
+# else
+// See unistd/getcwd.c if this syscall is not available...
+# endif
+#endif
//#define __NR_capget 184
#ifdef L_capget
diff --git a/libc/unistd/getcwd.c b/libc/unistd/getcwd.c
index b5bfeaae8..fd1e29445 100644
--- a/libc/unistd/getcwd.c
+++ b/libc/unistd/getcwd.c
@@ -1,85 +1,25 @@
+/* These functions find the absolute path to the current working directory. */
+
#include <stdlib.h>
#include <errno.h>
#include <sys/stat.h>
#include <dirent.h>
#include <string.h>
+#include <sys/syscall.h>
-/* #undef FAST_DIR_SEARCH_POSSIBLE on Linux */
-
-
-/* These functions find the absolute path to the current working directory. */
-
-static char *recurser(); /* Routine to go up tree */
-static char *search_dir(); /* Routine to find the step back down */
-static char *path_buf;
-static int path_size;
-
-static dev_t root_dev;
-static ino_t root_ino;
-
-static struct stat st;
-
-char *getcwd( char *buf, int size)
-{
- path_size = size;
-
- if (size < 3) {
- __set_errno(ERANGE);
- return NULL;
- }
-
- if (buf != NULL)
- path_buf = buf;
- else
- {
- path_buf = malloc (size);
- if (path_buf == NULL)
- return NULL;
- }
-
- strcpy(path_buf, ".");
-
- if (stat("/", &st) < 0)
- return NULL;
-
- root_dev = st.st_dev;
- root_ino = st.st_ino;
-
- return recurser();
-}
-
-static char *recurser()
-{
- dev_t this_dev;
- ino_t this_ino;
-
- if (stat(path_buf, &st) < 0)
- return 0;
- this_dev = st.st_dev;
- this_ino = st.st_ino;
- if (this_dev == root_dev && this_ino == root_ino) {
- strcpy(path_buf, "/");
- return path_buf;
- }
- if (strlen(path_buf) + 4 > path_size) {
- __set_errno(ERANGE);
- return 0;
- }
- strcat(path_buf, "/..");
- if (recurser() == 0)
- return 0;
+/* if the syscall is not present, we have to recurse up */
+#ifndef __NR_getcwd
- return search_dir(this_dev, this_ino);
-}
+/* #undef FAST_DIR_SEARCH_POSSIBLE on Linux */
-static char *search_dir(this_dev, this_ino)
-dev_t this_dev;
-ino_t this_ino;
+/* Routine to find the step back down */
+static char *search_dir(dev_t this_dev, ino_t this_ino, char *path_buf, int path_size)
{
DIR *dp;
struct dirent *d;
char *ptr;
int slen;
+ struct stat st;
#ifdef FAST_DIR_SEARCH_POSSIBLE
/* The test is for ELKS lib 0.0.9, this should be fixed in the real kernel */
@@ -133,3 +73,59 @@ ino_t this_ino;
__set_errno(ENOENT);
return 0;
}
+
+/* Routine to go up tree */
+static char *recurser(char *path_buf, int path_size, dev_t root_dev, ino_t root_ino)
+{
+ struct stat st;
+ dev_t this_dev;
+ ino_t this_ino;
+
+ if (stat(path_buf, &st) < 0)
+ return 0;
+ this_dev = st.st_dev;
+ this_ino = st.st_ino;
+ if (this_dev == root_dev && this_ino == root_ino) {
+ strcpy(path_buf, "/");
+ return path_buf;
+ }
+ if (strlen(path_buf) + 4 > path_size) {
+ __set_errno(ERANGE);
+ return 0;
+ }
+ strcat(path_buf, "/..");
+ if (recurser(path_buf, path_size, root_dev, root_ino) == 0)
+ return 0;
+
+ return search_dir(this_dev, this_ino, path_buf, path_size);
+}
+
+
+char *getcwd(char *buf, int size)
+{
+ struct stat st;
+
+ if (size == 0) {
+ __set_errno(EINVAL);
+ return NULL;
+ }
+ if (size < 3) {
+ __set_errno(ERANGE);
+ return NULL;
+ }
+
+ if (buf == NULL) {
+ buf = malloc (size);
+ if (buf == NULL)
+ return NULL;
+ }
+
+ strcpy(buf, ".");
+ if (stat("/", &st) < 0) {
+ return NULL;
+ }
+
+ return recurser(buf, size, st.st_dev, st.st_ino);
+}
+
+#endif