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-2005 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 it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
13 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 You should have received a copy of the GNU General Public License along
19 with Bash; see the file COPYING. If not, write to the Free Software
20 Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
25 #if defined (HAVE_UNISTD_H)
27 # include <sys/types.h>
32 #include "../bashtypes.h"
34 #include "posixstat.h"
36 #include <sys/param.h>
41 #include "../bashansi.h"
42 #include "../bashintl.h"
45 #include <tilde/tilde.h>
51 #include "bashgetopt.h"
57 extern int posixly_correct;
58 extern int array_needs_making;
59 extern char *bash_getcwd_errstr;
61 static int bindpwd __P((int));
62 static void setpwd __P((char *));
63 static int change_to_directory __P((char *, int));
65 static char *cdspell __P((char *));
67 /* Change this to 1 to get cd spelling correction by default. */
74 $SHORT_DOC cd [-L|-P] [dir]
75 Change the current directory to DIR. The variable $HOME is the
76 default DIR. The variable CDPATH defines the search path for
77 the directory containing DIR. Alternative directory names in CDPATH
78 are separated by a colon (:). A null directory name is the same as
79 the current directory, i.e. `.'. If DIR begins with a slash (/),
80 then CDPATH is not used. If the directory is not found, and the
81 shell option `cdable_vars' is set, then try the word as a variable
82 name. If that variable has a value, then cd to the value of that
83 variable. The -P option says to use the physical directory structure
84 instead of following symbolic links; the -L option forces symbolic links
88 /* Just set $PWD, don't change OLDPWD. Used by `pwd -P' in posix mode. */
96 old_anm = array_needs_making;
97 tvar = bind_variable ("PWD", dirname ? dirname : "", 0);
98 if (old_anm == 0 && array_needs_making && exported_p (tvar))
100 update_export_env_inplace ("PWD=", 4, dirname ? dirname : "");
101 array_needs_making = 0;
106 bindpwd (no_symlinks)
109 char *dirname, *pwdvar;
113 #define tcwd the_current_working_directory
114 dirname = tcwd ? (no_symlinks ? sh_physpath (tcwd, 0) : tcwd)
115 : get_working_directory ("cd");
118 old_anm = array_needs_making;
119 pwdvar = get_string_value ("PWD");
121 tvar = bind_variable ("OLDPWD", pwdvar, 0);
122 if (old_anm == 0 && array_needs_making && exported_p (tvar))
124 update_export_env_inplace ("OLDPWD=", 7, pwdvar);
125 array_needs_making = 0;
130 if (dirname && dirname != the_current_working_directory)
133 return (EXECUTION_SUCCESS);
136 /* Call get_working_directory to reset the value of
137 the_current_working_directory () */
144 FREE (the_current_working_directory);
145 the_current_working_directory = (char *)NULL;
146 tdir = get_working_directory (caller);
150 #define LCD_DOVARS 0x001
151 #define LCD_DOSPELL 0x002
152 #define LCD_PRINTPATH 0x004
153 #define LCD_FREEDIRNAME 0x010
155 /* This builtin is ultimately the way that all user-visible commands should
156 change the current working directory. It is called by cd_to_string (),
157 so the programming interface is simple, and it handles errors and
158 restrictions properly. */
163 char *dirname, *cdpath, *path, *temp;
164 int path_index, no_symlinks, opt, lflag;
166 #if defined (RESTRICTED_SHELL)
169 sh_restricted ((char *)NULL);
170 return (EXECUTION_FAILURE);
172 #endif /* RESTRICTED_SHELL */
174 no_symlinks = no_symbolic_links;
175 reset_internal_getopt ();
176 while ((opt = internal_getopt (list, "LP")) != -1)
188 return (EXECUTION_FAILURE);
193 lflag = (cdable_vars ? LCD_DOVARS : 0) |
194 ((interactive && cdspelling) ? LCD_DOSPELL : 0);
198 /* `cd' without arguments is equivalent to `cd $HOME' */
199 dirname = get_string_value ("HOME");
203 builtin_error (_("HOME not set"));
204 return (EXECUTION_FAILURE);
208 else if (list->word->word[0] == '-' && list->word->word[1] == '\0')
210 /* This is `cd -', equivalent to `cd $OLDPWD' */
211 dirname = get_string_value ("OLDPWD");
215 builtin_error (_("OLDPWD not set"));
216 return (EXECUTION_FAILURE);
219 lflag = interactive ? LCD_PRINTPATH : 0;
221 lflag = LCD_PRINTPATH; /* According to SUSv3 */
224 else if (absolute_pathname (list->word->word))
225 dirname = list->word->word;
226 else if (cdpath = get_string_value ("CDPATH"))
228 dirname = list->word->word;
230 /* Find directory in $CDPATH. */
232 while (path = extract_colon_unit (cdpath, &path_index))
234 /* OPT is 1 if the path element is non-empty */
235 opt = path[0] != '\0';
236 temp = sh_makepath (path, dirname, MP_DOTILDE);
239 if (change_to_directory (temp, no_symlinks))
241 /* POSIX.2 says that if a nonempty directory from CDPATH
242 is used to find the directory to change to, the new
243 directory name is echoed to stdout, whether or not
244 the shell is interactive. */
245 if (opt && (path = no_symlinks ? temp : the_current_working_directory))
246 printf ("%s\n", path);
250 /* Posix.2 says that after using CDPATH, the resultant
251 value of $PWD will not contain `.' or `..'. */
252 return (bindpwd (posixly_correct || no_symlinks));
254 return (bindpwd (no_symlinks));
261 /* POSIX.2 says that if `.' does not appear in $CDPATH, we don't
262 try the current directory, so we just punt now with an error
263 message if POSIXLY_CORRECT is non-zero. The check for cdpath[0]
264 is so we don't mistakenly treat a CDPATH value of "" as not
265 specifying the current directory. */
266 if (posixly_correct && cdpath[0])
268 builtin_error ("%s: %s", dirname, strerror (ENOENT));
269 return (EXECUTION_FAILURE);
273 dirname = list->word->word;
275 /* When we get here, DIRNAME is the directory to change to. If we
276 chdir successfully, just return. */
277 if (change_to_directory (dirname, no_symlinks))
279 if (lflag & LCD_PRINTPATH)
280 printf ("%s\n", dirname);
281 return (bindpwd (no_symlinks));
284 /* If the user requests it, then perhaps this is the name of
285 a shell variable, whose value contains the directory to
287 if (lflag & LCD_DOVARS)
289 temp = get_string_value (dirname);
290 if (temp && change_to_directory (temp, no_symlinks))
292 printf ("%s\n", temp);
293 return (bindpwd (no_symlinks));
297 /* If the user requests it, try to find a directory name similar in
298 spelling to the one requested, in case the user made a simple
299 typo. This is similar to the UNIX 8th and 9th Edition shells. */
300 if (lflag & LCD_DOSPELL)
302 temp = cdspell (dirname);
303 if (temp && change_to_directory (temp, no_symlinks))
305 printf ("%s\n", temp);
306 return (bindpwd (no_symlinks));
312 builtin_error ("%s: %s", dirname, strerror (errno));
313 return (EXECUTION_FAILURE);
317 $FUNCTION pwd_builtin
319 Print the current working directory. With the -P option, pwd prints
320 the physical directory, without any symbolic links; the -L option
321 makes pwd follow symbolic links.
324 /* Non-zero means that pwd always prints the physical directory, without
326 static int verbatim_pwd;
328 /* Print the name of the current working directory. */
336 verbatim_pwd = no_symbolic_links;
338 reset_internal_getopt ();
339 while ((opt = internal_getopt (list, "LP")) != -1)
344 verbatim_pwd = pflag = 1;
351 return (EXECUTION_FAILURE);
356 #define tcwd the_current_working_directory
358 directory = tcwd ? (verbatim_pwd ? sh_physpath (tcwd, 0) : tcwd)
359 : get_working_directory ("pwd");
361 /* Try again using getcwd() if canonicalization fails (for instance, if
362 the file system has changed state underneath bash). */
363 if ((tcwd && directory == 0) ||
364 (posixly_correct && same_file (".", tcwd, (struct stat *)0, (struct stat *)0) == 0))
365 directory = resetpwd ("pwd");
371 printf ("%s\n", directory);
372 /* This is dumb but posix-mandated. */
373 if (posixly_correct && pflag)
375 if (directory != the_current_working_directory)
382 return (EXECUTION_FAILURE);
385 return (EXECUTION_SUCCESS);
388 return (EXECUTION_FAILURE);
391 /* Do the work of changing to the directory NEWDIR. Handle symbolic
392 link following, etc. This function *must* return with
393 the_current_working_directory either set to NULL (in which case
394 getcwd() will eventually be called), or set to a string corresponding
395 to the working directory. Return 1 on success, 0 on failure. */
398 change_to_directory (newdir, nolinks)
403 int err, canon_failed, r, ndlen, dlen;
407 if (the_current_working_directory == 0)
409 t = get_working_directory ("chdir");
413 t = make_absolute (newdir, the_current_working_directory);
415 /* TDIR is either the canonicalized absolute pathname of NEWDIR
416 (nolinks == 0) or the absolute physical pathname of NEWDIR
418 tdir = nolinks ? sh_physpath (t, 0)
419 : sh_canonpath (t, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
421 ndlen = strlen (newdir);
424 /* Use the canonicalized version of NEWDIR, or, if canonicalization
425 failed, use the non-canonical form. */
436 /* In POSIX mode, if we're resolving symlinks logically and sh_canonpath
437 returns NULL (because it checks the path, it will return NULL if the
438 resolved path doesn't exist), fail immediately. */
439 if (posixly_correct && nolinks == 0 && canon_failed && (errno != ENAMETOOLONG || ndlen > PATH_MAX))
441 #if defined ENAMETOOLONG
442 if (errno != ENOENT && errno != ENAMETOOLONG)
451 /* If the chdir succeeds, update the_current_working_directory. */
452 if (chdir (nolinks ? newdir : tdir) == 0)
454 /* If canonicalization failed, but the chdir succeeded, reset the
455 shell's idea of the_current_working_directory. */
460 set_working_directory (tdir);
463 set_working_directory (tdir);
469 /* We failed to change to the appropriate directory name. If we tried
470 what the user passed (nolinks != 0), punt now. */
479 /* We're not in physical mode (nolinks == 0), but we failed to change to
480 the canonicalized directory name (TDIR). Try what the user passed
481 verbatim. If we succeed, reinitialize the_current_working_directory. */
482 if (chdir (newdir) == 0)
486 set_working_directory (tdir);
502 /* Code for cd spelling correction. Original patch submitted by
503 Neil Russel (caret@c-side.com). */
512 n = (strlen (dirname) * 3 + 1) / 2 + 1;
513 guess = (char *)xmalloc (n);
515 switch (spname (dirname, guess))