1/* Copyright (C) 1991-2020 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <https://www.gnu.org/licenses/>. */
17
18/* Wants:
19 AC_STDC_HEADERS
20 AC_DIR_HEADER
21 AC_UNISTD_H
22 AC_MEMORY_H
23 AC_CONST
24 AC_ALLOCA
25 */
26
27/* AIX requires this to be the first thing in the file. */
28#if defined _AIX && !defined __GNUC__
29 #pragma alloca
30#endif
31
32#ifdef HAVE_CONFIG_H
33# include "config.h"
34#endif
35
36#include <errno.h>
37#include <fcntl.h>
38#include <sys/types.h>
39#include <sys/stat.h>
40
41#ifdef STDC_HEADERS
42# include <stddef.h>
43#endif
44
45#if !defined __GNU_LIBRARY__ && !defined STDC_HEADERS
46extern int errno;
47#endif
48#ifndef __set_errno
49# define __set_errno(val) errno = (val)
50#endif
51
52#ifndef NULL
53# define NULL 0
54#endif
55
56#if defined USGr3 && !defined DIRENT
57# define DIRENT
58#endif /* USGr3 */
59#if defined Xenix && !defined SYSNDIR
60# define SYSNDIR
61#endif /* Xenix */
62
63#if defined POSIX || defined DIRENT || defined __GNU_LIBRARY__
64# include <dirent.h>
65# ifndef __GNU_LIBRARY__
66# define D_NAMLEN(d) strlen((d)->d_name)
67# else
68# define HAVE_D_NAMLEN
69# define D_NAMLEN(d) ((d)->d_namlen)
70# endif
71#else /* not POSIX or DIRENT */
72# define dirent direct
73# define D_NAMLEN(d) ((d)->d_namlen)
74# define HAVE_D_NAMLEN
75# if defined USG && !defined sgi
76# if defined SYSNDIR
77# include <sys/ndir.h>
78# else /* Not SYSNDIR */
79# include "ndir.h"
80# endif /* SYSNDIR */
81# else /* not USG */
82# include <sys/dir.h>
83# endif /* USG */
84#endif /* POSIX or DIRENT or __GNU_LIBRARY__ */
85
86#if defined HAVE_UNISTD_H || defined __GNU_LIBRARY__
87# include <unistd.h>
88#endif
89
90#if defined STDC_HEADERS || defined __GNU_LIBRARY__ || defined POSIX
91# include <stdlib.h>
92# include <string.h>
93# define ANSI_STRING
94#else /* No standard headers. */
95
96# ifdef USG
97
98# include <string.h>
99# ifdef NEED_MEMORY_H
100# include <memory.h>
101# endif
102# define ANSI_STRING
103
104# else /* Not USG. */
105
106# ifdef NeXT
107
108# include <string.h>
109
110# else /* Not NeXT. */
111
112# include <strings.h>
113
114# ifndef bcmp
115extern int bcmp ();
116# endif
117# ifndef bzero
118extern void bzero ();
119# endif
120# ifndef bcopy
121extern void bcopy ();
122# endif
123
124# endif /* NeXT. */
125
126# endif /* USG. */
127
128extern char *malloc (), *realloc ();
129extern void free ();
130
131#endif /* Standard headers. */
132
133#ifndef ANSI_STRING
134# define memcpy(d, s, n) bcopy((s), (d), (n))
135# define memmove memcpy
136#endif /* Not ANSI_STRING. */
137
138#ifndef MAX
139# define MAX(a, b) ((a) < (b) ? (b) : (a))
140#endif
141
142#ifdef _LIBC
143# ifndef mempcpy
144# define mempcpy __mempcpy
145# endif
146# define HAVE_MEMPCPY 1
147#endif
148
149#if !defined __alloca && !defined __GNU_LIBRARY__
150
151# ifdef __GNUC__
152# undef alloca
153# define alloca(n) __builtin_alloca (n)
154# else /* Not GCC. */
155# if defined sparc || defined HAVE_ALLOCA_H
156# include <alloca.h>
157# else /* Not sparc or HAVE_ALLOCA_H. */
158# ifndef _AIX
159extern char *alloca ();
160# endif /* Not _AIX. */
161# endif /* sparc or HAVE_ALLOCA_H. */
162# endif /* GCC. */
163
164# define __alloca alloca
165
166#endif
167
168#if defined HAVE_LIMITS_H || defined STDC_HEADERS || defined __GNU_LIBRARY__
169# include <limits.h>
170#else
171# include <sys/param.h>
172#endif
173
174#if defined _LIBC
175# include <not-cancel.h>
176# include <kernel-features.h>
177#else
178# define __openat64_nocancel(dfd, name, mode) openat64 (dfd, name, mode)
179# define __close_nocancel_nostatus(fd) close (fd)
180#endif
181
182#ifndef PATH_MAX
183# ifdef MAXPATHLEN
184# define PATH_MAX MAXPATHLEN
185# else
186# define PATH_MAX 1024
187# endif
188#endif
189
190#if !defined STDC_HEADERS && !defined __GNU_LIBRARY__
191# undef size_t
192# define size_t unsigned int
193#endif
194
195#ifndef __GNU_LIBRARY__
196# define __lstat64 stat64
197#endif
198
199#ifndef _LIBC
200# define __rewinddir rewinddir
201#endif
202
203#ifndef _LIBC
204# define __getcwd getcwd
205#endif
206
207#ifndef GETCWD_RETURN_TYPE
208# define GETCWD_RETURN_TYPE char *
209#endif
210
211#ifdef __ASSUME_ATFCTS
212# define __have_atfcts 1
213#elif IS_IN (rtld)
214static int __rtld_have_atfcts;
215# define __have_atfcts __rtld_have_atfcts
216#endif
217
218/* Get the pathname of the current working directory, and put it in SIZE
219 bytes of BUF. Returns NULL if the directory couldn't be determined or
220 SIZE was too small. If successful, returns BUF. In GNU, if BUF is
221 NULL, an array is allocated with `malloc'; the array is SIZE bytes long,
222 unless SIZE == 0, in which case it is as big as necessary. */
223
224GETCWD_RETURN_TYPE
225__getcwd (char *buf, size_t size)
226{
227#ifndef __ASSUME_ATFCTS
228 static const char dots[]
229 = "../../../../../../../../../../../../../../../../../../../../../../../\
230../../../../../../../../../../../../../../../../../../../../../../../../../../\
231../../../../../../../../../../../../../../../../../../../../../../../../../..";
232 const char *dotp = &dots[sizeof (dots)];
233 const char *dotlist = dots;
234 size_t dotsize = sizeof (dots) - 1;
235#endif
236 int prev_errno = errno;
237 DIR *dirstream = NULL;
238 bool fd_needs_closing = false;
239 int fd = AT_FDCWD;
240
241 char *path;
242#ifndef NO_ALLOCATION
243 size_t allocated = size;
244 if (size == 0)
245 {
246 if (buf != NULL)
247 {
248 __set_errno (EINVAL);
249 return NULL;
250 }
251
252 allocated = PATH_MAX + 1;
253 }
254
255 if (buf == NULL)
256 {
257 path = malloc (allocated);
258 if (path == NULL)
259 return NULL;
260 }
261 else
262#else
263# define allocated size
264#endif
265 path = buf;
266
267 char *pathp = path + allocated;
268 *--pathp = '\0';
269
270 struct stat64 st;
271 if (__lstat64 (".", &st) < 0)
272 goto lose;
273 dev_t thisdev = st.st_dev;
274 ino_t thisino = st.st_ino;
275
276 if (__lstat64 ("/", &st) < 0)
277 goto lose;
278 dev_t rootdev = st.st_dev;
279 ino_t rootino = st.st_ino;
280
281 while (!(thisdev == rootdev && thisino == rootino))
282 {
283 if (__have_atfcts >= 0)
284 fd = __openat64_nocancel (fd, "..", O_RDONLY | O_CLOEXEC);
285 else
286 fd = -1;
287 if (fd >= 0)
288 {
289 fd_needs_closing = true;
290 if (__fstat64 (fd, &st) < 0)
291 goto lose;
292 }
293#ifndef __ASSUME_ATFCTS
294 else if (errno == ENOSYS)
295 {
296 __have_atfcts = -1;
297
298 /* Look at the parent directory. */
299 if (dotp == dotlist)
300 {
301# ifdef NO_ALLOCATION
302 __set_errno (ENOMEM);
303 goto lose;
304# else
305 /* My, what a deep directory tree you have, Grandma. */
306 char *new;
307 if (dotlist == dots)
308 {
309 new = malloc (dotsize * 2 + 1);
310 if (new == NULL)
311 goto lose;
312# ifdef HAVE_MEMPCPY
313 dotp = mempcpy (new, dots, dotsize);
314# else
315 memcpy (new, dots, dotsize);
316 dotp = &new[dotsize];
317# endif
318 }
319 else
320 {
321 new = realloc ((void *) dotlist, dotsize * 2 + 1);
322 if (new == NULL)
323 goto lose;
324 dotp = &new[dotsize];
325 }
326# ifdef HAVE_MEMPCPY
327 *((char *) mempcpy ((char *) dotp, new, dotsize)) = '\0';
328 dotsize *= 2;
329# else
330 memcpy ((char *) dotp, new, dotsize);
331 dotsize *= 2;
332 new[dotsize] = '\0';
333# endif
334 dotlist = new;
335# endif
336 }
337
338 dotp -= 3;
339
340 /* Figure out if this directory is a mount point. */
341 if (__lstat64 (dotp, &st) < 0)
342 goto lose;
343 }
344#endif
345 else
346 goto lose;
347
348 if (dirstream && __closedir (dirstream) != 0)
349 {
350 dirstream = NULL;
351 goto lose;
352 }
353
354 dev_t dotdev = st.st_dev;
355 ino_t dotino = st.st_ino;
356 bool mount_point = dotdev != thisdev;
357
358 /* Search for the last directory. */
359 if (__have_atfcts >= 0)
360 dirstream = __fdopendir (fd);
361#ifndef __ASSUME_ATFCTS
362 else
363 dirstream = __opendir (dotp);
364#endif
365 if (dirstream == NULL)
366 goto lose;
367 fd_needs_closing = false;
368
369 struct dirent *d;
370 bool use_d_ino = true;
371 while (1)
372 {
373 /* Clear errno to distinguish EOF from error if readdir returns
374 NULL. */
375 __set_errno (0);
376 d = __readdir (dirstream);
377 if (d == NULL)
378 {
379 if (errno == 0)
380 {
381 /* When we've iterated through all directory entries
382 without finding one with a matching d_ino, rewind the
383 stream and consider each name again, but this time, using
384 lstat64. This is necessary in a chroot on at least one
385 system. */
386 if (use_d_ino)
387 {
388 use_d_ino = false;
389 __rewinddir (dirstream);
390 continue;
391 }
392
393 /* EOF on dirstream, which means that the current directory
394 has been removed. */
395 __set_errno (ENOENT);
396 }
397 goto lose;
398 }
399
400#ifdef _DIRENT_HAVE_D_TYPE
401 if (d->d_type != DT_DIR && d->d_type != DT_UNKNOWN)
402 continue;
403#endif
404 if (d->d_name[0] == '.'
405 && (d->d_name[1] == '\0'
406 || (d->d_name[1] == '.' && d->d_name[2] == '\0')))
407 continue;
408 if (use_d_ino && !mount_point && (ino_t) d->d_ino != thisino)
409 continue;
410
411 if (__have_atfcts >= 0)
412 {
413 /* We don't fail here if we cannot stat64() a directory entry.
414 This can happen when (network) filesystems fail. If this
415 entry is in fact the one we are looking for we will find
416 out soon as we reach the end of the directory without
417 having found anything. */
418 if (__fstatat64 (fd, d->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0)
419 continue;
420 }
421#ifndef __ASSUME_ATFCTS
422 else
423 {
424 char name[dotlist + dotsize - dotp + 1 + _D_ALLOC_NAMLEN (d)];
425# ifdef HAVE_MEMPCPY
426 char *tmp = mempcpy (name, dotp, dotlist + dotsize - dotp);
427 *tmp++ = '/';
428 strcpy (tmp, d->d_name);
429# else
430 memcpy (name, dotp, dotlist + dotsize - dotp);
431 name[dotlist + dotsize - dotp] = '/';
432 strcpy (&name[dotlist + dotsize - dotp + 1], d->d_name);
433# endif
434 /* We don't fail here if we cannot stat64() a directory entry.
435 This can happen when (network) filesystems fail. If this
436 entry is in fact the one we are looking for we will find
437 out soon as we reach the end of the directory without
438 having found anything. */
439 if (__lstat64 (name, &st) < 0)
440 continue;
441 }
442#endif
443 if (S_ISDIR (st.st_mode)
444 && st.st_dev == thisdev && st.st_ino == thisino)
445 break;
446 }
447
448 size_t namlen = _D_EXACT_NAMLEN (d);
449
450 if ((size_t) (pathp - path) <= namlen)
451 {
452#ifndef NO_ALLOCATION
453 if (size == 0)
454 {
455 size_t oldsize = allocated;
456
457 allocated = 2 * MAX (allocated, namlen);
458 char *tmp = realloc (path, allocated);
459 if (tmp == NULL)
460 goto lose;
461
462 /* Move current contents up to the end of the buffer.
463 This is guaranteed to be non-overlapping. */
464 pathp = memcpy (tmp + allocated - (path + oldsize - pathp),
465 tmp + (pathp - path),
466 path + oldsize - pathp);
467 path = tmp;
468 }
469 else
470#endif
471 {
472 __set_errno (ERANGE);
473 goto lose;
474 }
475 }
476 pathp -= namlen;
477 (void) memcpy (pathp, d->d_name, namlen);
478 *--pathp = '/';
479
480 thisdev = dotdev;
481 thisino = dotino;
482 }
483
484 if (dirstream != NULL && __closedir (dirstream) != 0)
485 {
486 dirstream = NULL;
487 goto lose;
488 }
489
490 if (pathp == &path[allocated - 1])
491 *--pathp = '/';
492
493#ifndef __ASSUME_ATFCTS
494 if (dotlist != dots)
495 free ((void *) dotlist);
496#endif
497
498 size_t used = path + allocated - pathp;
499 memmove (path, pathp, used);
500
501 if (size == 0)
502 /* Ensure that the buffer is only as large as necessary. */
503 buf = realloc (path, used);
504
505 if (buf == NULL)
506 /* Either buf was NULL all along, or `realloc' failed but
507 we still have the original string. */
508 buf = path;
509
510 /* Restore errno on successful return. */
511 __set_errno (prev_errno);
512
513 return buf;
514
515 lose:;
516 int save_errno = errno;
517#ifndef __ASSUME_ATFCTS
518 if (dotlist != dots)
519 free ((void *) dotlist);
520#endif
521 if (dirstream != NULL)
522 __closedir (dirstream);
523 if (fd_needs_closing)
524 __close_nocancel_nostatus (fd);
525#ifndef NO_ALLOCATION
526 if (buf == NULL)
527 free (path);
528#endif
529 __set_errno (save_errno);
530 return NULL;
531}
532
533#if defined _LIBC && !defined __getcwd
534libc_hidden_def (__getcwd)
535weak_alias (__getcwd, getcwd)
536#endif
537