blob: 31e26b74e5b5d7c9c593f0972327ac9ea59e21fc [file] [log] [blame]
Jari Aalto31859422009-01-12 13:36:28 +00001/* getcwd.c -- get pathname of current directory */
Jari Aalto726f6381996-08-26 18:22:31 +00002
3/* Copyright (C) 1991 Free Software Foundation, Inc.
Jari Aalto726f6381996-08-26 18:22:31 +00004
Jari Aalto31859422009-01-12 13:36:28 +00005 This file is part of GNU Bash, the Bourne Again SHell.
Jari Aalto726f6381996-08-26 18:22:31 +00006
Jari Aalto31859422009-01-12 13:36:28 +00007 Bash is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 Bash is distributed in the hope that it will be useful,
Jari Aalto726f6381996-08-26 18:22:31 +000013 but WITHOUT ANY WARRANTY; without even the implied warranty of
Jari Aalto31859422009-01-12 13:36:28 +000014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
Jari Aalto726f6381996-08-26 18:22:31 +000016
Jari Aalto31859422009-01-12 13:36:28 +000017 You should have received a copy of the GNU General Public License
18 along with Bash. If not, see <http://www.gnu.org/licenses/>.
19*/
Jari Aalto726f6381996-08-26 18:22:31 +000020
Jari Aaltocce855b1998-04-17 19:52:44 +000021#include <config.h>
Jari Aaltoccc6cda1996-12-23 17:02:34 +000022
23#if !defined (HAVE_GETCWD)
24
Jari Aaltob80f6442004-07-27 13:29:18 +000025#if !defined (__GNUC__) && !defined (HAVE_ALLOCA_H) && defined (_AIX)
26 #pragma alloca
27#endif /* _AIX && RISC6000 && !__GNUC__ */
28
Jari Aalto31859422009-01-12 13:36:28 +000029#if defined (__QNX__)
30# undef HAVE_LSTAT
31#endif
32
Jari Aaltocce855b1998-04-17 19:52:44 +000033#include <bashtypes.h>
Jari Aalto726f6381996-08-26 18:22:31 +000034#include <errno.h>
35
36#if defined (HAVE_LIMITS_H)
37# include <limits.h>
38#endif
39
Jari Aalto726f6381996-08-26 18:22:31 +000040#if defined (HAVE_UNISTD_H)
41# include <unistd.h>
42#endif
43
Jari Aaltocce855b1998-04-17 19:52:44 +000044#include <posixdir.h>
45#include <posixstat.h>
46#include <maxpath.h>
47#include <memalloc.h>
Jari Aalto726f6381996-08-26 18:22:31 +000048
Jari Aaltocce855b1998-04-17 19:52:44 +000049#include <bashansi.h>
Jari Aalto726f6381996-08-26 18:22:31 +000050
Chet Rameyac50fba2014-02-26 09:36:43 -050051#if !defined (D_FILENO_AVAILABLE)
Chet Ramey00018032011-11-21 20:51:19 -050052# include "command.h"
53# include "general.h"
54# include "externs.h"
55#endif
56
Jari Aaltof73dda02001-11-13 17:56:06 +000057#include <xmalloc.h>
58
Jari Aalto726f6381996-08-26 18:22:31 +000059#if !defined (errno)
Ricardo Cerqueiraa02fbff2013-07-25 22:35:34 +010060#include <errno.h>
Jari Aalto726f6381996-08-26 18:22:31 +000061#endif /* !errno */
62
Jari Aaltoccc6cda1996-12-23 17:02:34 +000063#if !defined (HAVE_LSTAT)
Jari Aalto726f6381996-08-26 18:22:31 +000064# define lstat stat
65#endif
66
Jari Aaltobb706242000-03-17 21:46:59 +000067#if !defined (NULL)
68# define NULL 0
69#endif
70
Jari Aalto31859422009-01-12 13:36:28 +000071/* If the d_fileno member of a struct dirent doesn't return anything useful,
72 we need to check inode number equivalence the hard way. Return 1 if
73 the inode corresponding to PATH/DIR is identical to THISINO. */
Chet Rameyac50fba2014-02-26 09:36:43 -050074#if !defined (D_FILENO_AVAILABLE)
Jari Aalto31859422009-01-12 13:36:28 +000075static int
76_path_checkino (dotp, name, thisino)
77 char *dotp;
78 char *name;
79 ino_t thisino;
80{
81 char *fullpath;
82 int r, e;
83 struct stat st;
84
85 e = errno;
86 fullpath = sh_makepath (dotp, name, MP_RMDOT);
87 if (stat (fullpath, &st) < 0)
88 {
89 errno = e;
90 return 0;
91 }
92 free (fullpath);
93 errno = e;
94 return (st.st_ino == thisino);
95}
96#endif
97
Jari Aalto726f6381996-08-26 18:22:31 +000098/* Get the pathname of the current working directory,
99 and put it in SIZE bytes of BUF. Returns NULL if the
100 directory couldn't be determined or SIZE was too small.
101 If successful, returns BUF. In GNU, if BUF is NULL,
102 an array is allocated with `malloc'; the array is SIZE
103 bytes long, unless SIZE <= 0, in which case it is as
104 big as necessary. */
105#if defined (__STDC__)
106char *
107getcwd (char *buf, size_t size)
108#else /* !__STDC__ */
109char *
110getcwd (buf, size)
111 char *buf;
112 size_t size;
113#endif /* !__STDC__ */
114{
Jari Aaltof73dda02001-11-13 17:56:06 +0000115 static const char dots[]
Jari Aalto726f6381996-08-26 18:22:31 +0000116 = "../../../../../../../../../../../../../../../../../../../../../../../\
117../../../../../../../../../../../../../../../../../../../../../../../../../../\
118../../../../../../../../../../../../../../../../../../../../../../../../../..";
Jari Aaltof73dda02001-11-13 17:56:06 +0000119 const char *dotp, *dotlist;
Jari Aalto726f6381996-08-26 18:22:31 +0000120 size_t dotsize;
121 dev_t rootdev, thisdev;
122 ino_t rootino, thisino;
123 char path[PATH_MAX + 1];
124 register char *pathp;
125 char *pathbuf;
126 size_t pathsize;
127 struct stat st;
Jari Aaltocce855b1998-04-17 19:52:44 +0000128 int saved_errno;
Jari Aalto726f6381996-08-26 18:22:31 +0000129
130 if (buf != NULL && size == 0)
131 {
132 errno = EINVAL;
133 return ((char *)NULL);
134 }
135
136 pathsize = sizeof (path);
137 pathp = &path[pathsize];
138 *--pathp = '\0';
139 pathbuf = path;
140
141 if (stat (".", &st) < 0)
142 return ((char *)NULL);
143 thisdev = st.st_dev;
144 thisino = st.st_ino;
145
146 if (stat ("/", &st) < 0)
147 return ((char *)NULL);
148 rootdev = st.st_dev;
149 rootino = st.st_ino;
150
Jari Aaltocce855b1998-04-17 19:52:44 +0000151 saved_errno = 0;
152
Jari Aalto726f6381996-08-26 18:22:31 +0000153 dotsize = sizeof (dots) - 1;
154 dotp = &dots[sizeof (dots)];
155 dotlist = dots;
156 while (!(thisdev == rootdev && thisino == rootino))
157 {
158 register DIR *dirstream;
159 register struct dirent *d;
160 dev_t dotdev;
161 ino_t dotino;
162 char mount_point;
163 int namlen;
164
165 /* Look at the parent directory. */
166 if (dotp == dotlist)
167 {
168 /* My, what a deep directory tree you have, Grandma. */
169 char *new;
170 if (dotlist == dots)
171 {
Jari Aaltobb706242000-03-17 21:46:59 +0000172 new = (char *)malloc (dotsize * 2 + 1);
Jari Aalto726f6381996-08-26 18:22:31 +0000173 if (new == NULL)
174 goto lose;
175 memcpy (new, dots, dotsize);
176 }
177 else
178 {
Jari Aaltof73dda02001-11-13 17:56:06 +0000179 new = (char *)realloc ((PTR_T) dotlist, dotsize * 2 + 1);
Jari Aalto726f6381996-08-26 18:22:31 +0000180 if (new == NULL)
181 goto lose;
182 }
183 memcpy (&new[dotsize], new, dotsize);
184 dotp = &new[dotsize];
185 dotsize *= 2;
186 new[dotsize] = '\0';
187 dotlist = new;
188 }
189
190 dotp -= 3;
191
192 /* Figure out if this directory is a mount point. */
193 if (stat (dotp, &st) < 0)
194 goto lose;
195 dotdev = st.st_dev;
196 dotino = st.st_ino;
197 mount_point = dotdev != thisdev;
198
199 /* Search for the last directory. */
200 dirstream = opendir (dotp);
201 if (dirstream == NULL)
202 goto lose;
203 while ((d = readdir (dirstream)) != NULL)
204 {
205 if (d->d_name[0] == '.' &&
206 (d->d_name[1] == '\0' ||
207 (d->d_name[1] == '.' && d->d_name[2] == '\0')))
208 continue;
Chet Rameyac50fba2014-02-26 09:36:43 -0500209#if defined (D_FILENO_AVAILABLE)
Jari Aalto726f6381996-08-26 18:22:31 +0000210 if (mount_point || d->d_fileno == thisino)
Jari Aalto31859422009-01-12 13:36:28 +0000211#else
212 if (mount_point || _path_checkino (dotp, d->d_name, thisino))
213#endif
Jari Aalto726f6381996-08-26 18:22:31 +0000214 {
215 char *name;
216
217 namlen = D_NAMLEN(d);
218 name = (char *)
219 alloca (dotlist + dotsize - dotp + 1 + namlen + 1);
220 memcpy (name, dotp, dotlist + dotsize - dotp);
221 name[dotlist + dotsize - dotp] = '/';
222 memcpy (&name[dotlist + dotsize - dotp + 1],
223 d->d_name, namlen + 1);
224 if (lstat (name, &st) < 0)
225 {
Jari Aaltocce855b1998-04-17 19:52:44 +0000226#if 0
Jari Aalto726f6381996-08-26 18:22:31 +0000227 int save = errno;
228 (void) closedir (dirstream);
229 errno = save;
230 goto lose;
Jari Aaltocce855b1998-04-17 19:52:44 +0000231#else
232 saved_errno = errno;
233#endif
Jari Aalto726f6381996-08-26 18:22:31 +0000234 }
235 if (st.st_dev == thisdev && st.st_ino == thisino)
236 break;
237 }
238 }
239 if (d == NULL)
240 {
Jari Aaltocce855b1998-04-17 19:52:44 +0000241#if 0
Jari Aalto726f6381996-08-26 18:22:31 +0000242 int save = errno;
Jari Aaltocce855b1998-04-17 19:52:44 +0000243#else
244 int save = errno ? errno : saved_errno;
245#endif
Jari Aalto726f6381996-08-26 18:22:31 +0000246 (void) closedir (dirstream);
247 errno = save;
248 goto lose;
249 }
250 else
251 {
252 size_t space;
253
254 while ((space = pathp - pathbuf) <= namlen)
255 {
256 char *new;
257
258 if (pathbuf == path)
259 {
Jari Aaltobb706242000-03-17 21:46:59 +0000260 new = (char *)malloc (pathsize * 2);
Jari Aalto726f6381996-08-26 18:22:31 +0000261 if (!new)
262 goto lose;
263 }
264 else
265 {
Jari Aaltof73dda02001-11-13 17:56:06 +0000266 new = (char *)realloc ((PTR_T) pathbuf, (pathsize * 2));
Jari Aalto726f6381996-08-26 18:22:31 +0000267 if (!new)
268 goto lose;
269 pathp = new + space;
270 }
271 (void) memcpy (new + pathsize + space, pathp, pathsize - space);
272 pathp = new + pathsize + space;
273 pathbuf = new;
274 pathsize *= 2;
275 }
276
277 pathp -= namlen;
278 (void) memcpy (pathp, d->d_name, namlen);
279 *--pathp = '/';
280 (void) closedir (dirstream);
281 }
282
283 thisdev = dotdev;
284 thisino = dotino;
285 }
286
287 if (pathp == &path[sizeof(path) - 1])
288 *--pathp = '/';
289
290 if (dotlist != dots)
Jari Aaltof73dda02001-11-13 17:56:06 +0000291 free ((PTR_T) dotlist);
Jari Aalto726f6381996-08-26 18:22:31 +0000292
293 {
294 size_t len = pathbuf + pathsize - pathp;
Jari Aaltof1be6662008-11-18 13:15:12 +0000295 if (buf == NULL && size <= 0)
296 size = len;
297
298 if ((size_t) size < len)
Jari Aalto726f6381996-08-26 18:22:31 +0000299 {
300 errno = ERANGE;
301 goto lose2;
302 }
Jari Aaltof1be6662008-11-18 13:15:12 +0000303 if (buf == NULL)
304 {
305 buf = (char *) malloc (size);
306 if (buf == NULL)
307 goto lose2;
308 }
309
Jari Aaltof73dda02001-11-13 17:56:06 +0000310 (void) memcpy((PTR_T) buf, (PTR_T) pathp, len);
Jari Aalto726f6381996-08-26 18:22:31 +0000311 }
312
313 if (pathbuf != path)
314 free (pathbuf);
315
316 return (buf);
317
318 lose:
319 if ((dotlist != dots) && dotlist)
320 {
321 int e = errno;
Jari Aaltof73dda02001-11-13 17:56:06 +0000322 free ((PTR_T) dotlist);
Jari Aalto726f6381996-08-26 18:22:31 +0000323 errno = e;
324 }
325
326 lose2:
327 if ((pathbuf != path) && pathbuf)
328 {
329 int e = errno;
Jari Aaltof73dda02001-11-13 17:56:06 +0000330 free ((PTR_T) pathbuf);
Jari Aalto726f6381996-08-26 18:22:31 +0000331 errno = e;
332 }
333 return ((char *)NULL);
334}
335
336#if defined (TEST)
337# include <stdio.h>
338main (argc, argv)
339 int argc;
340 char **argv;
341{
342 char b[PATH_MAX];
343
344 if (getcwd(b, sizeof(b)))
345 {
346 printf ("%s\n", b);
347 exit (0);
348 }
349 else
350 {
351 perror ("cwd: getcwd");
352 exit (1);
353 }
354}
355#endif /* TEST */
Jari Aaltoccc6cda1996-12-23 17:02:34 +0000356#endif /* !HAVE_GETCWD */