1 /* getcwd.c -- stolen from the GNU C library and modified to work with bash. */
3 /* Copyright (C) 1991 Free Software Foundation, Inc.
4 This file is part of the GNU C Library.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public
17 License along with the GNU C Library; see the file COPYING.LIB. If
18 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
19 Cambridge, MA 02139, USA. */
21 #include "bashtypes.h"
24 #if defined (HAVE_LIMITS_H)
28 #if defined (HAVE_DIRENT_H)
32 # if !defined (dirent)
33 # define dirent direct
35 #endif /* !HAVE_DIRENT_H */
37 #if defined (HAVE_UNISTD_H)
41 #include "posixstat.h"
45 #if defined (HAVE_STDLIB_H)
48 # include "ansi_stdlib.h"
49 #endif /* !HAVE_STDLIB_H */
51 #if defined (HAVE_STRING_H)
55 #endif /* !HAVE_STRING_H */
57 /* Not all systems declare ERRNO in errno.h... and some systems #define it! */
62 #if defined (__STDC__)
68 #endif /* !__STDC__ */
70 #if !defined (PATH_MAX)
71 # if defined (MAXPATHLEN)
72 # define PATH_MAX MAXPATHLEN
73 # else /* !MAXPATHLEN */
74 # define PATH_MAX 1024
75 # endif /* !MAXPATHLEN */
76 #endif /* !PATH_MAX */
78 #if defined (_POSIX_VERSION) || defined (USGr3) || defined (HAVE_DIRENT_H)
79 # if !defined (HAVE_DIRENT)
81 # endif /* !HAVE_DIRENT */
82 #endif /* _POSIX_VERSION || USGr3 || HAVE_DIRENT_H */
84 #if defined (HAVE_DIRENT)
85 # define D_NAMLEN(d) (strlen ((d)->d_name))
87 # define D_NAMLEN(d) ((d)->d_namlen)
88 #endif /* ! (_POSIX_VERSION || USGr3) */
90 #if defined (USG) || defined (USGr3)
91 # define d_fileno d_ino
95 extern char *alloca ();
98 /* Heuristic to tell whether or not the current machine has lstat(2).
99 Can probably be fooled easily. */
100 #if !defined (S_ISLNK)
104 /* Get the pathname of the current working directory,
105 and put it in SIZE bytes of BUF. Returns NULL if the
106 directory couldn't be determined or SIZE was too small.
107 If successful, returns BUF. In GNU, if BUF is NULL,
108 an array is allocated with `malloc'; the array is SIZE
109 bytes long, unless SIZE <= 0, in which case it is as
111 #if defined (__STDC__)
113 getcwd (char *buf, size_t size)
114 #else /* !__STDC__ */
119 #endif /* !__STDC__ */
121 static CONST char dots[]
122 = "../../../../../../../../../../../../../../../../../../../../../../../\
123 ../../../../../../../../../../../../../../../../../../../../../../../../../../\
124 ../../../../../../../../../../../../../../../../../../../../../../../../../..";
125 CONST char *dotp, *dotlist;
127 dev_t rootdev, thisdev;
128 ino_t rootino, thisino;
129 char path[PATH_MAX + 1];
130 register char *pathp;
135 if (buf != NULL && size == 0)
138 return ((char *)NULL);
141 pathsize = sizeof (path);
142 pathp = &path[pathsize];
146 if (stat (".", &st) < 0)
147 return ((char *)NULL);
151 if (stat ("/", &st) < 0)
152 return ((char *)NULL);
156 dotsize = sizeof (dots) - 1;
157 dotp = &dots[sizeof (dots)];
159 while (!(thisdev == rootdev && thisino == rootino))
161 register DIR *dirstream;
162 register struct dirent *d;
168 /* Look at the parent directory. */
171 /* My, what a deep directory tree you have, Grandma. */
175 new = malloc (dotsize * 2 + 1);
178 memcpy (new, dots, dotsize);
182 new = realloc ((PTR) dotlist, dotsize * 2 + 1);
186 memcpy (&new[dotsize], new, dotsize);
187 dotp = &new[dotsize];
195 /* Figure out if this directory is a mount point. */
196 if (stat (dotp, &st) < 0)
200 mount_point = dotdev != thisdev;
202 /* Search for the last directory. */
203 dirstream = opendir (dotp);
204 if (dirstream == NULL)
206 while ((d = readdir (dirstream)) != NULL)
208 if (d->d_name[0] == '.' &&
209 (d->d_name[1] == '\0' ||
210 (d->d_name[1] == '.' && d->d_name[2] == '\0')))
212 if (mount_point || d->d_fileno == thisino)
216 namlen = D_NAMLEN(d);
218 alloca (dotlist + dotsize - dotp + 1 + namlen + 1);
219 memcpy (name, dotp, dotlist + dotsize - dotp);
220 name[dotlist + dotsize - dotp] = '/';
221 memcpy (&name[dotlist + dotsize - dotp + 1],
222 d->d_name, namlen + 1);
223 if (lstat (name, &st) < 0)
226 (void) closedir (dirstream);
230 if (st.st_dev == thisdev && st.st_ino == thisino)
237 (void) closedir (dirstream);
245 while ((space = pathp - pathbuf) <= namlen)
251 new = malloc (pathsize * 2);
257 new = realloc ((PTR) pathbuf, (pathsize * 2));
262 (void) memcpy (new + pathsize + space, pathp, pathsize - space);
263 pathp = new + pathsize + space;
269 (void) memcpy (pathp, d->d_name, namlen);
271 (void) closedir (dirstream);
278 if (pathp == &path[sizeof(path) - 1])
282 free ((PTR) dotlist);
285 size_t len = pathbuf + pathsize - pathp;
288 if (len < (size_t) size)
290 buf = (char *) malloc (len);
294 else if ((size_t) size < len)
299 (void) memcpy((PTR) buf, (PTR) pathp, len);
308 if ((dotlist != dots) && dotlist)
311 free ((PTR) dotlist);
316 if ((pathbuf != path) && pathbuf)
319 free ((PTR) pathbuf);
322 return ((char *)NULL);
333 if (getcwd(b, sizeof(b)))
340 perror ("cwd: getcwd");