Back to index

glibc  2.9
getcwd.c
Go to the documentation of this file.
00001 /* Determine current working directory.  Linux version.
00002    Copyright (C) 1997,1998,1999,2000,2002,2003,2006
00003        Free Software Foundation, Inc.
00004    This file is part of the GNU C Library.
00005    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
00006 
00007    The GNU C Library is free software; you can redistribute it and/or
00008    modify it under the terms of the GNU Lesser General Public
00009    License as published by the Free Software Foundation; either
00010    version 2.1 of the License, or (at your option) any later version.
00011 
00012    The GNU C Library is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015    Lesser General Public License for more details.
00016 
00017    You should have received a copy of the GNU Lesser General Public
00018    License along with the GNU C Library; if not, write to the Free
00019    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00020    02111-1307 USA.  */
00021 
00022 #include <assert.h>
00023 #include <errno.h>
00024 #include <limits.h>
00025 #include <stdlib.h>
00026 #include <unistd.h>
00027 
00028 #include <sysdep.h>
00029 #include <sys/syscall.h>
00030 #include <bp-checks.h>
00031 
00032 #include <kernel-features.h>
00033 
00034 
00035 /* If we compile the file for use in ld.so we don't need the feature
00036    that getcwd() allocates the buffers itself.  */
00037 #ifdef IS_IN_rtld
00038 # define NO_ALLOCATION      1
00039 #endif
00040 
00041 
00042 #if __ASSUME_GETCWD_SYSCALL > 0
00043 /* Kernel 2.1.92 introduced a third way to get the current working
00044    directory: a syscall.  We've got to be careful that even when
00045    compiling under 2.1.92+ the libc still runs under older kernels. */
00046 # define no_syscall_getcwd 0
00047 # define have_new_dcache 1
00048 /* This is a trick since we don't define generic_getcwd.  */
00049 # define generic_getcwd getcwd
00050 #else
00051 /* The "proc" filesystem provides an easy method to retrieve the value.
00052    For each process, the corresponding directory contains a symbolic link
00053    named `cwd'.  Reading the content of this link immediate gives us the
00054    information.  But we have to take care for systems which do not have
00055    the proc filesystem mounted.  Use the POSIX implementation in this case.  */
00056 static char *generic_getcwd (char *buf, size_t size) internal_function;
00057 
00058 # if __NR_getcwd
00059 /* Kernel 2.1.92 introduced a third way to get the current working
00060    directory: a syscall.  We've got to be careful that even when
00061    compiling under 2.1.92+ the libc still runs under older kernels. */
00062 static int no_syscall_getcwd;
00063 static int have_new_dcache;
00064 # else
00065 #  define no_syscall_getcwd 1
00066 static int have_new_dcache = 1;
00067 # endif
00068 #endif
00069 
00070 char *
00071 __getcwd (char *buf, size_t size)
00072 {
00073   char *path;
00074   int n;
00075   char *result;
00076 
00077   if (no_syscall_getcwd && !have_new_dcache)
00078     return generic_getcwd (buf, size);
00079 
00080 #ifndef NO_ALLOCATION
00081   size_t alloc_size = size;
00082   if (size == 0)
00083     {
00084       if (buf != NULL)
00085        {
00086          __set_errno (EINVAL);
00087          return NULL;
00088        }
00089 
00090       alloc_size = MAX (PATH_MAX, __getpagesize ());
00091     }
00092 
00093   if (buf == NULL)
00094     {
00095       path = malloc (alloc_size);
00096       if (path == NULL)
00097        return NULL;
00098     }
00099   else
00100 #else
00101 # define alloc_size size
00102 #endif
00103     path = buf;
00104 
00105 #if defined __NR_getcwd || __LINUX_GETCWD_SYSCALL > 0
00106   if (!no_syscall_getcwd)
00107     {
00108       int retval;
00109 
00110       retval = INLINE_SYSCALL (getcwd, 2, CHECK_STRING (path), alloc_size);
00111       if (retval >= 0)
00112        {
00113 # ifndef NO_ALLOCATION
00114          if (buf == NULL && size == 0)
00115            /* Ensure that the buffer is only as large as necessary.  */
00116            buf = realloc (path, (size_t) retval);
00117 
00118          if (buf == NULL)
00119            /* Either buf was NULL all along, or `realloc' failed but
00120               we still have the original string.  */
00121            buf = path;
00122 # endif
00123 
00124          return buf;
00125        }
00126 
00127 # if __ASSUME_GETCWD_SYSCALL
00128       /* It should never happen that the `getcwd' syscall failed because
00129         the buffer is too small if we allocated the buffer ourselves
00130         large enough.  */
00131       assert (errno != ERANGE || buf != NULL || size != 0);
00132 
00133 #  ifndef NO_ALLOCATION
00134       if (buf == NULL)
00135        free (path);
00136 #  endif
00137 
00138       return NULL;
00139 # else
00140       if (errno == ENOSYS)
00141        {
00142           no_syscall_getcwd = 1;
00143           have_new_dcache = 1;     /* Now we will try the /proc method.  */
00144        }
00145       else if (errno != ERANGE || buf != NULL)
00146        {
00147 #  ifndef NO_ALLOCATION
00148          if (buf == NULL)
00149            free (path);
00150 #  endif
00151          return NULL;
00152        }
00153 # endif
00154     }
00155 #endif
00156 
00157   n = __readlink ("/proc/self/cwd", path, alloc_size - 1);
00158   if (n != -1)
00159     {
00160       if (path[0] == '/')
00161        {
00162          if ((size_t) n >= alloc_size - 1)
00163            {
00164 #ifndef NO_ALLOCATION
00165              if (buf == NULL)
00166               free (path);
00167 #endif
00168              return NULL;
00169            }
00170 
00171          path[n] = '\0';
00172 #ifndef NO_ALLOCATION
00173          if (buf == NULL && size == 0)
00174            /* Ensure that the buffer is only as large as necessary.  */
00175            buf = realloc (path, (size_t) n + 1);
00176          if (buf == NULL)
00177            /* Either buf was NULL all along, or `realloc' failed but
00178               we still have the original string.  */
00179            buf = path;
00180 #endif
00181 
00182          return buf;
00183        }
00184 #ifndef have_new_dcache
00185       else
00186        have_new_dcache = 0;
00187 #endif
00188     }
00189 
00190 #if __ASSUME_GETCWD_SYSCALL == 0
00191   /* Set to have_new_dcache only if error indicates that proc doesn't
00192      exist.  */
00193   if (errno != EACCES && errno != ENAMETOOLONG)
00194     have_new_dcache = 0;
00195 #endif
00196 
00197 #ifndef NO_ALLOCATION
00198   /* Don't put restrictions on the length of the path unless the user does.  */
00199   if (size == 0)
00200     {
00201       free (path);
00202       path = NULL;
00203     }
00204 #endif
00205 
00206   result = generic_getcwd (path, size);
00207 
00208 #ifndef NO_ALLOCATION
00209   if (result == NULL && buf == NULL && size != 0)
00210     free (path);
00211 #endif
00212 
00213   return result;
00214 }
00215 weak_alias (__getcwd, getcwd)
00216 
00217 #if __ASSUME_GETCWD_SYSCALL == 0
00218 /* Get the code for the generic version.  */
00219 # define GETCWD_RETURN_TYPE static char * internal_function
00220 # define __getcwd           generic_getcwd
00221 # include <sysdeps/posix/getcwd.c>
00222 #endif