blob: 23e77cdd522bad2eb42185b029195552be968077 [file] [log] [blame]
xf.libdd93d52023-05-12 07:10:14 -07001/* Copyright (C) 1991-2016 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 <http://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_not_cancel_3(dfd, name, mode) openat64 (dfd, name, mode)
179# define close_not_cancel_no_status(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;
xf.li84027492024-04-09 00:17:51 -0700244
245 /* A size of 1 byte is never useful. */
246 if (allocated == 1)
247 {
248 __set_errno (ERANGE);
249 return NULL;
250 }
xf.libdd93d52023-05-12 07:10:14 -0700251 if (size == 0)
252 {
253 if (buf != NULL)
254 {
255 __set_errno (EINVAL);
256 return NULL;
257 }
258
259 allocated = PATH_MAX + 1;
260 }
261
262 if (buf == NULL)
263 {
264 path = malloc (allocated);
265 if (path == NULL)
266 return NULL;
267 }
268 else
269#else
270# define allocated size
271#endif
272 path = buf;
273
274 char *pathp = path + allocated;
275 *--pathp = '\0';
276
277 struct stat64 st;
278 if (__lstat64 (".", &st) < 0)
279 goto lose;
280 dev_t thisdev = st.st_dev;
281 ino_t thisino = st.st_ino;
282
283 if (__lstat64 ("/", &st) < 0)
284 goto lose;
285 dev_t rootdev = st.st_dev;
286 ino_t rootino = st.st_ino;
287
288 while (!(thisdev == rootdev && thisino == rootino))
289 {
290 if (__have_atfcts >= 0)
291 {
292 int mode = O_RDONLY;
293#ifdef O_CLOEXEC
294 mode |= O_CLOEXEC;
295#endif
296 fd = openat64_not_cancel_3 (fd, "..", mode);
297 }
298 else
299 fd = -1;
300 if (fd >= 0)
301 {
302 fd_needs_closing = true;
303 if (__fstat64 (fd, &st) < 0)
304 goto lose;
305 }
306#ifndef __ASSUME_ATFCTS
307 else if (errno == ENOSYS)
308 {
309 __have_atfcts = -1;
310
311 /* Look at the parent directory. */
312 if (dotp == dotlist)
313 {
314# ifdef NO_ALLOCATION
315 __set_errno (ENOMEM);
316 goto lose;
317# else
318 /* My, what a deep directory tree you have, Grandma. */
319 char *new;
320 if (dotlist == dots)
321 {
322 new = malloc (dotsize * 2 + 1);
323 if (new == NULL)
324 goto lose;
325# ifdef HAVE_MEMPCPY
326 dotp = mempcpy (new, dots, dotsize);
327# else
328 memcpy (new, dots, dotsize);
329 dotp = &new[dotsize];
330# endif
331 }
332 else
333 {
334 new = realloc ((__ptr_t) dotlist, dotsize * 2 + 1);
335 if (new == NULL)
336 goto lose;
337 dotp = &new[dotsize];
338 }
339# ifdef HAVE_MEMPCPY
340 *((char *) mempcpy ((char *) dotp, new, dotsize)) = '\0';
341 dotsize *= 2;
342# else
343 memcpy ((char *) dotp, new, dotsize);
344 dotsize *= 2;
345 new[dotsize] = '\0';
346# endif
347 dotlist = new;
348# endif
349 }
350
351 dotp -= 3;
352
353 /* Figure out if this directory is a mount point. */
354 if (__lstat64 (dotp, &st) < 0)
355 goto lose;
356 }
357#endif
358 else
359 goto lose;
360
361 if (dirstream && __closedir (dirstream) != 0)
362 {
363 dirstream = NULL;
364 goto lose;
365 }
366
367 dev_t dotdev = st.st_dev;
368 ino_t dotino = st.st_ino;
369 bool mount_point = dotdev != thisdev;
370
371 /* Search for the last directory. */
372 if (__have_atfcts >= 0)
373 dirstream = __fdopendir (fd);
374#ifndef __ASSUME_ATFCTS
375 else
376 dirstream = __opendir (dotp);
377#endif
378 if (dirstream == NULL)
379 goto lose;
380 fd_needs_closing = false;
381
382 struct dirent *d;
383 bool use_d_ino = true;
384 while (1)
385 {
386 /* Clear errno to distinguish EOF from error if readdir returns
387 NULL. */
388 __set_errno (0);
389 d = __readdir (dirstream);
390 if (d == NULL)
391 {
392 if (errno == 0)
393 {
394 /* When we've iterated through all directory entries
395 without finding one with a matching d_ino, rewind the
396 stream and consider each name again, but this time, using
397 lstat64. This is necessary in a chroot on at least one
398 system. */
399 if (use_d_ino)
400 {
401 use_d_ino = false;
402 __rewinddir (dirstream);
403 continue;
404 }
405
406 /* EOF on dirstream, which means that the current directory
407 has been removed. */
408 __set_errno (ENOENT);
409 }
410 goto lose;
411 }
412
413#ifdef _DIRENT_HAVE_D_TYPE
414 if (d->d_type != DT_DIR && d->d_type != DT_UNKNOWN)
415 continue;
416#endif
417 if (d->d_name[0] == '.'
418 && (d->d_name[1] == '\0'
419 || (d->d_name[1] == '.' && d->d_name[2] == '\0')))
420 continue;
421 if (use_d_ino && !mount_point && (ino_t) d->d_ino != thisino)
422 continue;
423
424 if (__have_atfcts >= 0)
425 {
426 /* We don't fail here if we cannot stat64() a directory entry.
427 This can happen when (network) filesystems fail. If this
428 entry is in fact the one we are looking for we will find
429 out soon as we reach the end of the directory without
430 having found anything. */
431 if (__fstatat64 (fd, d->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0)
432 continue;
433 }
434#ifndef __ASSUME_ATFCTS
435 else
436 {
437 char name[dotlist + dotsize - dotp + 1 + _D_ALLOC_NAMLEN (d)];
438# ifdef HAVE_MEMPCPY
439 char *tmp = mempcpy (name, dotp, dotlist + dotsize - dotp);
440 *tmp++ = '/';
441 strcpy (tmp, d->d_name);
442# else
443 memcpy (name, dotp, dotlist + dotsize - dotp);
444 name[dotlist + dotsize - dotp] = '/';
445 strcpy (&name[dotlist + dotsize - dotp + 1], d->d_name);
446# endif
447 /* We don't fail here if we cannot stat64() a directory entry.
448 This can happen when (network) filesystems fail. If this
449 entry is in fact the one we are looking for we will find
450 out soon as we reach the end of the directory without
451 having found anything. */
452 if (__lstat64 (name, &st) < 0)
453 continue;
454 }
455#endif
456 if (S_ISDIR (st.st_mode)
457 && st.st_dev == thisdev && st.st_ino == thisino)
458 break;
459 }
460
461 size_t namlen = _D_EXACT_NAMLEN (d);
462
463 if ((size_t) (pathp - path) <= namlen)
464 {
465#ifndef NO_ALLOCATION
466 if (size == 0)
467 {
468 size_t oldsize = allocated;
469
470 allocated = 2 * MAX (allocated, namlen);
471 char *tmp = realloc (path, allocated);
472 if (tmp == NULL)
473 goto lose;
474
475 /* Move current contents up to the end of the buffer.
476 This is guaranteed to be non-overlapping. */
477 pathp = memcpy (tmp + allocated - (path + oldsize - pathp),
478 tmp + (pathp - path),
479 path + oldsize - pathp);
480 path = tmp;
481 }
482 else
483#endif
484 {
485 __set_errno (ERANGE);
486 goto lose;
487 }
488 }
489 pathp -= namlen;
490 (void) memcpy (pathp, d->d_name, namlen);
491 *--pathp = '/';
492
493 thisdev = dotdev;
494 thisino = dotino;
495 }
496
497 if (dirstream != NULL && __closedir (dirstream) != 0)
498 {
499 dirstream = NULL;
500 goto lose;
501 }
502
503 if (pathp == &path[allocated - 1])
504 *--pathp = '/';
505
506#ifndef __ASSUME_ATFCTS
507 if (dotlist != dots)
508 free ((__ptr_t) dotlist);
509#endif
510
511 size_t used = path + allocated - pathp;
512 memmove (path, pathp, used);
513
514 if (size == 0)
515 /* Ensure that the buffer is only as large as necessary. */
516 buf = realloc (path, used);
517
518 if (buf == NULL)
519 /* Either buf was NULL all along, or `realloc' failed but
520 we still have the original string. */
521 buf = path;
522
523 /* Restore errno on successful return. */
524 __set_errno (prev_errno);
525
526 return buf;
527
528 lose:;
529 int save_errno = errno;
530#ifndef __ASSUME_ATFCTS
531 if (dotlist != dots)
532 free ((__ptr_t) dotlist);
533#endif
534 if (dirstream != NULL)
535 __closedir (dirstream);
536 if (fd_needs_closing)
537 close_not_cancel_no_status (fd);
538#ifndef NO_ALLOCATION
539 if (buf == NULL)
540 free (path);
541#endif
542 __set_errno (save_errno);
543 return NULL;
544}
545
546#if defined _LIBC && !defined __getcwd
547weak_alias (__getcwd, getcwd)
548#endif