1 This file is cd.def, from which is created cd.c. It implements the
2 builtins "cd" and "pwd" in Bash.
4 Copyright (C) 1987-2022 Free Software Foundation, Inc.
6 This file is part of GNU Bash, the Bourne Again SHell.
8 Bash is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 Bash is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with Bash. If not, see <http://www.gnu.org/licenses/>.
24 #if defined (HAVE_UNISTD_H)
26 # include <sys/types.h>
31 #include "../bashtypes.h"
33 #include "posixstat.h"
34 #if defined (HAVE_SYS_PARAM_H)
35 #include <sys/param.h>
41 #include "../bashansi.h"
42 #include "../bashintl.h"
45 #include <tilde/tilde.h>
51 #include "bashgetopt.h"
57 extern const char * const bash_getcwd_errstr;
59 static int bindpwd PARAMS((int));
60 static int setpwd PARAMS((char *));
61 static char *resetpwd PARAMS((char *));
62 static int change_to_directory PARAMS((char *, int, int));
64 static int cdxattr PARAMS((char *, char **));
65 static void resetxattr PARAMS((void));
67 /* Change this to 1 to get cd spelling correction by default. */
72 static int eflag; /* file scope so bindpwd() can see it */
73 static int xattrflag; /* O_XATTR support for openat */
74 static int xattrfd = -1;
78 $SHORT_DOC cd [-L|[-P [-e]] [-@]] [dir]
79 Change the shell working directory.
81 Change the current directory to DIR. The default DIR is the value of the
82 HOME shell variable. If DIR is "-", it is converted to $OLDPWD.
84 The variable CDPATH defines the search path for the directory containing
85 DIR. Alternative directory names in CDPATH are separated by a colon (:).
86 A null directory name is the same as the current directory. If DIR begins
87 with a slash (/), then CDPATH is not used.
89 If the directory is not found, and the shell option `cdable_vars' is set,
90 the word is assumed to be a variable name. If that variable has a value,
91 its value is used for DIR.
94 -L force symbolic links to be followed: resolve symbolic
95 links in DIR after processing instances of `..'
96 -P use the physical directory structure without following
97 symbolic links: resolve symbolic links in DIR before
98 processing instances of `..'
99 -e if the -P option is supplied, and the current working
100 directory cannot be determined successfully, exit with
102 #if defined (O_XATTR)
103 -@ on systems that support it, present a file with extended
104 attributes as a directory containing the file attributes
107 The default is to follow symbolic links, as if `-L' were specified.
108 `..' is processed by removing the immediately previous pathname component
109 back to a slash or the beginning of DIR.
112 Returns 0 if the directory is changed, and if $PWD is set successfully when
113 -P is used; non-zero otherwise.
116 /* Just set $PWD, don't change OLDPWD. Used by `pwd -P' in posix mode. */
124 old_anm = array_needs_making;
125 tvar = bind_variable ("PWD", dirname ? dirname : "", 0);
126 if (tvar && readonly_p (tvar))
127 return EXECUTION_FAILURE;
128 if (tvar && old_anm == 0 && array_needs_making && exported_p (tvar))
130 update_export_env_inplace ("PWD=", 4, dirname ? dirname : "");
131 array_needs_making = 0;
133 return EXECUTION_SUCCESS;
137 bindpwd (no_symlinks)
140 char *dirname, *pwdvar;
141 int old_anm, r, canon_failed;
144 r = sh_chkwrite (EXECUTION_SUCCESS);
146 #define tcwd the_current_working_directory
147 dirname = tcwd ? (no_symlinks ? sh_physpath (tcwd, 0) : tcwd)
148 : get_working_directory ("cd");
151 /* If canonicalization fails, reset dirname to the_current_working_directory */
156 dirname = the_current_working_directory;
159 old_anm = array_needs_making;
160 pwdvar = get_string_value ("PWD");
162 tvar = bind_variable ("OLDPWD", pwdvar, 0);
163 if (tvar && readonly_p (tvar))
164 r = EXECUTION_FAILURE;
166 if (old_anm == 0 && array_needs_making && exported_p (tvar))
168 update_export_env_inplace ("OLDPWD=", 7, pwdvar);
169 array_needs_making = 0;
172 if (setpwd (dirname) == EXECUTION_FAILURE)
173 r = EXECUTION_FAILURE;
174 if (canon_failed && eflag)
175 r = EXECUTION_FAILURE;
177 if (dirname && dirname != the_current_working_directory)
183 /* Call get_working_directory to reset the value of
184 the_current_working_directory () */
191 FREE (the_current_working_directory);
192 the_current_working_directory = (char *)NULL;
193 tdir = get_working_directory (caller);
199 char *dir; /* don't assume we can always free DIR */
200 char **ndirp; /* return new constructed directory name */
202 #if defined (O_XATTR)
204 char buf[11+40+40]; /* construct new `fake' path for pwd */
206 apfd = openat (AT_FDCWD, dir, O_RDONLY|O_NONBLOCK);
209 fd = openat (apfd, ".", O_XATTR);
211 close (apfd); /* ignore close error for now */
215 r = fchdir (fd); /* assume fchdir exists everywhere with O_XATTR */
221 /* NFSv4 and ZFS extended attribute directories do not have names which are
222 visible in the standard Unix directory tree structure. To ensure we have
223 a valid name for $PWD, we synthesize one under /proc, but to keep that
224 path valid, we need to keep the file descriptor open as long as we are in
225 this directory. This imposes a certain structure on /proc. */
228 sprintf (buf, "/proc/%d/fd/%d", getpid(), fd);
229 *ndirp = savestring (buf);
242 /* Clean up the O_XATTR baggage. Currently only closes xattrfd */
246 #if defined (O_XATTR)
253 xattrfd = -1; /* not strictly necessary */
257 #define LCD_DOVARS 0x001
258 #define LCD_DOSPELL 0x002
259 #define LCD_PRINTPATH 0x004
260 #define LCD_FREEDIRNAME 0x008
262 /* This builtin is ultimately the way that all user-visible commands should
263 change the current working directory. It is called by cd_to_string (),
264 so the programming interface is simple, and it handles errors and
265 restrictions properly. */
270 char *dirname, *cdpath, *path, *temp;
271 int path_index, no_symlinks, opt, lflag, e;
273 #if defined (RESTRICTED_SHELL)
276 sh_restricted ((char *)NULL);
277 return (EXECUTION_FAILURE);
279 #endif /* RESTRICTED_SHELL */
282 no_symlinks = no_symbolic_links;
284 reset_internal_getopt ();
285 #if defined (O_XATTR)
286 while ((opt = internal_getopt (list, "eLP@")) != -1)
288 while ((opt = internal_getopt (list, "eLP")) != -1)
302 #if defined (O_XATTR)
315 lflag = (cdable_vars ? LCD_DOVARS : 0) |
316 ((interactive && cdspelling) ? LCD_DOSPELL : 0);
317 if (eflag && no_symlinks == 0)
322 /* `cd' without arguments is equivalent to `cd $HOME' */
323 dirname = get_string_value ("HOME");
327 builtin_error (_("HOME not set"));
328 return (EXECUTION_FAILURE);
332 #if defined (CD_COMPLAINS)
335 builtin_error (_("too many arguments"));
336 return (EXECUTION_FAILURE);
340 else if (list->word->word[0] == '\0')
342 builtin_error (_("null directory"));
343 return (EXECUTION_FAILURE);
346 else if (list->word->word[0] == '-' && list->word->word[1] == '\0')
348 /* This is `cd -', equivalent to `cd $OLDPWD' */
349 dirname = get_string_value ("OLDPWD");
353 builtin_error (_("OLDPWD not set"));
354 return (EXECUTION_FAILURE);
357 lflag = interactive ? LCD_PRINTPATH : 0;
359 lflag = LCD_PRINTPATH; /* According to SUSv3 */
362 else if (absolute_pathname (list->word->word))
363 dirname = list->word->word;
364 else if (privileged_mode == 0 && (cdpath = get_string_value ("CDPATH")))
366 dirname = list->word->word;
368 /* Find directory in $CDPATH. */
370 while (path = extract_colon_unit (cdpath, &path_index))
372 /* OPT is 1 if the path element is non-empty */
373 opt = path[0] != '\0';
374 temp = sh_makepath (path, dirname, MP_DOTILDE);
377 if (change_to_directory (temp, no_symlinks, xattrflag))
379 /* POSIX.2 says that if a nonempty directory from CDPATH
380 is used to find the directory to change to, the new
381 directory name is echoed to stdout, whether or not
382 the shell is interactive. */
383 if (opt && (path = no_symlinks ? temp : the_current_working_directory))
384 printf ("%s\n", path);
388 /* Posix.2 says that after using CDPATH, the resultant
389 value of $PWD will not contain `.' or `..'. */
390 return (bindpwd (posixly_correct || no_symlinks));
392 return (bindpwd (no_symlinks));
400 /* changed for bash-4.2 Posix cd description steps 5-6 */
401 /* POSIX.2 says that if `.' does not appear in $CDPATH, we don't
402 try the current directory, so we just punt now with an error
403 message if POSIXLY_CORRECT is non-zero. The check for cdpath[0]
404 is so we don't mistakenly treat a CDPATH value of "" as not
405 specifying the current directory. */
406 if (posixly_correct && cdpath[0])
408 builtin_error ("%s: %s", dirname, strerror (ENOENT));
409 return (EXECUTION_FAILURE);
414 dirname = list->word->word;
416 /* When we get here, DIRNAME is the directory to change to. If we
417 chdir successfully, just return. */
418 if (change_to_directory (dirname, no_symlinks, xattrflag))
420 if (lflag & LCD_PRINTPATH)
421 printf ("%s\n", dirname);
422 return (bindpwd (no_symlinks));
425 /* If the user requests it, then perhaps this is the name of
426 a shell variable, whose value contains the directory to
428 if (lflag & LCD_DOVARS)
430 temp = get_string_value (dirname);
431 if (temp && change_to_directory (temp, no_symlinks, xattrflag))
433 printf ("%s\n", temp);
434 return (bindpwd (no_symlinks));
438 /* If the user requests it, try to find a directory name similar in
439 spelling to the one requested, in case the user made a simple
440 typo. This is similar to the UNIX 8th and 9th Edition shells. */
441 if (lflag & LCD_DOSPELL)
443 temp = dirspell (dirname);
444 if (temp && change_to_directory (temp, no_symlinks, xattrflag))
446 printf ("%s\n", temp);
448 return (bindpwd (no_symlinks));
455 temp = printable_filename (dirname, 0);
456 builtin_error ("%s: %s", temp, strerror (e));
459 return (EXECUTION_FAILURE);
463 $FUNCTION pwd_builtin
465 Print the name of the current working directory.
468 -L print the value of $PWD if it names the current working
470 -P print the physical directory, without any symbolic links
472 By default, `pwd' behaves as if `-L' were specified.
475 Returns 0 unless an invalid option is given or the current directory
479 /* Non-zero means that pwd always prints the physical directory, without
481 static int verbatim_pwd;
483 /* Print the name of the current working directory. */
491 verbatim_pwd = no_symbolic_links;
493 reset_internal_getopt ();
494 while ((opt = internal_getopt (list, "LP")) != -1)
499 verbatim_pwd = pflag = 1;
512 #define tcwd the_current_working_directory
514 directory = tcwd ? (verbatim_pwd ? sh_physpath (tcwd, 0) : tcwd)
515 : get_working_directory ("pwd");
517 /* Try again using getcwd() if canonicalization fails (for instance, if
518 the file system has changed state underneath bash). */
519 if ((tcwd && directory == 0) ||
520 (posixly_correct && same_file (".", tcwd, (struct stat *)0, (struct stat *)0) == 0))
522 if (directory && directory != tcwd)
524 directory = resetpwd ("pwd");
531 opt = EXECUTION_SUCCESS;
532 printf ("%s\n", directory);
533 /* This is dumb but posix-mandated. */
534 if (posixly_correct && pflag)
535 opt = setpwd (directory);
536 if (directory != the_current_working_directory)
538 return (sh_chkwrite (opt));
541 return (EXECUTION_FAILURE);
544 /* Do the work of changing to the directory NEWDIR. Handle symbolic
545 link following, etc. This function *must* return with
546 the_current_working_directory either set to NULL (in which case
547 getcwd() will eventually be called), or set to a string corresponding
548 to the working directory. Return 1 on success, 0 on failure. */
551 change_to_directory (newdir, nolinks, xattr)
555 char *t, *tdir, *ndir;
556 int err, canon_failed, r, ndlen;
560 if (the_current_working_directory == 0)
562 t = get_working_directory ("chdir");
566 t = make_absolute (newdir, the_current_working_directory);
568 /* TDIR is either the canonicalized absolute pathname of NEWDIR
569 (nolinks == 0) or the absolute physical pathname of NEWDIR
571 tdir = nolinks ? sh_physpath (t, 0)
572 : sh_canonpath (t, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
574 ndlen = strlen (newdir);
576 /* Use the canonicalized version of NEWDIR, or, if canonicalization
577 failed, use the non-canonical form. */
588 /* In POSIX mode, if we're resolving symlinks logically and sh_canonpath
589 returns NULL (because it checks the path, it will return NULL if the
590 resolved path doesn't exist), fail immediately. */
591 #if defined (ENAMETOOLONG)
592 if (posixly_correct && nolinks == 0 && canon_failed && (errno != ENAMETOOLONG || ndlen > PATH_MAX))
594 if (posixly_correct && nolinks == 0 && canon_failed && ndlen > PATH_MAX)
597 #if defined ENAMETOOLONG
598 if (errno != ENOENT && errno != ENAMETOOLONG)
607 #if defined (O_XATTR)
610 r = cdxattr (nolinks ? newdir : tdir, &ndir);
622 return (0); /* no xattr */
628 r = chdir (nolinks ? newdir : tdir);
633 /* If the chdir succeeds, update the_current_working_directory. */
636 /* If canonicalization failed, but the chdir succeeded, reset the
637 shell's idea of the_current_working_directory. */
642 set_working_directory (tdir);
647 set_working_directory (tdir);
653 /* We failed to change to the appropriate directory name. If we tried
654 what the user passed (nolinks != 0), punt now. */
663 /* We're not in physical mode (nolinks == 0), but we failed to change to
664 the canonicalized directory name (TDIR). Try what the user passed
665 verbatim. If we succeed, reinitialize the_current_working_directory.
666 POSIX requires that we just fail here, so we do in posix mode. */
667 if (posixly_correct == 0 && chdir (newdir) == 0)
671 set_working_directory (tdir);