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, 1989, 1991 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"
44 #include <tilde/tilde.h>
50 #include "bashgetopt.h"
56 extern int posixly_correct;
57 extern int array_needs_making;
58 extern char *bash_getcwd_errstr;
60 static int bindpwd __P((int));
61 static int change_to_directory __P((char *, int));
63 static char *cdspell __P((char *));
65 /* Change this to 1 to get cd spelling correction by default. */
72 $SHORT_DOC cd [-L|-P] [dir]
73 Change the current directory to DIR. The variable $HOME is the
74 default DIR. The variable CDPATH defines the search path for
75 the directory containing DIR. Alternative directory names in CDPATH
76 are separated by a colon (:). A null directory name is the same as
77 the current directory, i.e. `.'. If DIR begins with a slash (/),
78 then CDPATH is not used. If the directory is not found, and the
79 shell option `cdable_vars' is set, then try the word as a variable
80 name. If that variable has a value, then cd to the value of that
81 variable. The -P option says to use the physical directory structure
82 instead of following symbolic links; the -L option forces symbolic links
90 char *dirname, *pwdvar;
94 #define tcwd the_current_working_directory
95 dirname = tcwd ? (no_symlinks ? sh_physpath (tcwd, 0) : tcwd)
96 : get_working_directory ("cd");
99 old_anm = array_needs_making;
100 pwdvar = get_string_value ("PWD");
102 tvar = bind_variable ("OLDPWD", pwdvar);
103 if (old_anm == 0 && array_needs_making && exported_p (tvar))
105 update_export_env_inplace ("OLDPWD=", 7, pwdvar);
106 array_needs_making = 0;
109 tvar = bind_variable ("PWD", dirname);
110 if (old_anm == 0 && array_needs_making && exported_p (tvar))
112 update_export_env_inplace ("PWD=", 4, dirname);
113 array_needs_making = 0;
116 if (dirname && dirname != the_current_working_directory)
118 return (EXECUTION_SUCCESS);
121 /* Call get_working_directory to reset the value of
122 the_current_working_directory () */
128 FREE (the_current_working_directory);
129 the_current_working_directory = (char *)NULL;
130 tdir = get_working_directory ("cd");
134 #define LCD_DOVARS 0x001
135 #define LCD_DOSPELL 0x002
136 #define LCD_PRINTPATH 0x004
137 #define LCD_FREEDIRNAME 0x010
139 /* This builtin is ultimately the way that all user-visible commands should
140 change the current working directory. It is called by cd_to_string (),
141 so the programming interface is simple, and it handles errors and
142 restrictions properly. */
147 char *dirname, *cdpath, *path, *temp;
148 int path_index, no_symlinks, opt, lflag;
150 #if defined (RESTRICTED_SHELL)
153 sh_restricted ((char *)NULL);
154 return (EXECUTION_FAILURE);
156 #endif /* RESTRICTED_SHELL */
158 no_symlinks = no_symbolic_links;
159 reset_internal_getopt ();
160 while ((opt = internal_getopt (list, "LP")) != -1)
172 return (EXECUTION_FAILURE);
177 lflag = (cdable_vars ? LCD_DOVARS : 0) |
178 ((interactive && cdspelling) ? LCD_DOSPELL : 0);
182 /* `cd' without arguments is equivalent to `cd $HOME' */
183 dirname = get_string_value ("HOME");
187 builtin_error ("HOME not set");
188 return (EXECUTION_FAILURE);
192 else if (list->word->word[0] == '-' && list->word->word[1] == '\0')
194 /* This is `cd -', equivalent to `cd $OLDPWD' */
195 dirname = get_string_value ("OLDPWD");
199 builtin_error ("OLDPWD not set");
200 return (EXECUTION_FAILURE);
202 lflag = interactive ? LCD_PRINTPATH : 0;
204 else if (absolute_pathname (list->word->word))
205 dirname = list->word->word;
206 else if (cdpath = get_string_value ("CDPATH"))
208 dirname = list->word->word;
210 /* Find directory in $CDPATH. */
212 while (path = extract_colon_unit (cdpath, &path_index))
214 /* OPT is 1 if the path element is non-empty */
215 opt = path[0] != '\0';
216 temp = sh_makepath (path, dirname, MP_DOTILDE);
219 if (change_to_directory (temp, no_symlinks))
221 /* POSIX.2 says that if a nonempty directory from CDPATH
222 is used to find the directory to change to, the new
223 directory name is echoed to stdout, whether or not
224 the shell is interactive. */
226 printf ("%s\n", no_symlinks ? temp : the_current_working_directory);
229 /* Posix.2 says that after using CDPATH, the resultant
230 value of $PWD will not contain `.' or `..'. */
231 return (bindpwd (posixly_correct || no_symlinks));
237 /* POSIX.2 says that if `.' does not appear in $CDPATH, we don't
238 try the current directory, so we just punt now with an error
239 message if POSIXLY_CORRECT is non-zero. The check for cdpath[0]
240 is so we don't mistakenly treat a CDPATH value of "" as not
241 specifying the current directory. */
242 if (posixly_correct && cdpath[0])
244 builtin_error ("%s: %s", dirname, strerror (ENOENT));
245 return (EXECUTION_FAILURE);
249 dirname = list->word->word;
251 /* When we get here, DIRNAME is the directory to change to. If we
252 chdir successfully, just return. */
253 if (change_to_directory (dirname, no_symlinks))
255 if (lflag & LCD_PRINTPATH)
256 printf ("%s\n", dirname);
257 return (bindpwd (no_symlinks));
260 /* If the user requests it, then perhaps this is the name of
261 a shell variable, whose value contains the directory to
263 if (lflag & LCD_DOVARS)
265 temp = get_string_value (dirname);
266 if (temp && change_to_directory (temp, no_symlinks))
268 printf ("%s\n", temp);
269 return (bindpwd (no_symlinks));
273 /* If the user requests it, try to find a directory name similar in
274 spelling to the one requested, in case the user made a simple
275 typo. This is similar to the UNIX 8th and 9th Edition shells. */
276 if (lflag & LCD_DOSPELL)
278 temp = cdspell (dirname);
279 if (temp && change_to_directory (temp, no_symlinks))
281 printf ("%s\n", temp);
282 return (bindpwd (no_symlinks));
288 builtin_error ("%s: %s", dirname, strerror (errno));
289 return (EXECUTION_FAILURE);
293 $FUNCTION pwd_builtin
295 Print the current working directory. With the -P option, pwd prints
296 the physical directory, without any symbolic links; the -L option
297 makes pwd follow symbolic links.
300 /* Non-zero means that pwd always prints the physical directory, without
302 static int verbatim_pwd;
304 /* Print the name of the current working directory. */
312 verbatim_pwd = no_symbolic_links;
313 reset_internal_getopt ();
314 while ((opt = internal_getopt (list, "LP")) != -1)
326 return (EXECUTION_FAILURE);
331 #define tcwd the_current_working_directory
333 directory = tcwd ? (verbatim_pwd ? sh_physpath (tcwd, 0) : tcwd)
334 : get_working_directory ("pwd");
339 printf ("%s\n", directory);
340 if (directory != the_current_working_directory)
345 builtin_error ("write error: %s", strerror (errno));
346 return (EXECUTION_FAILURE);
348 return (EXECUTION_SUCCESS);
351 return (EXECUTION_FAILURE);
354 /* Do the work of changing to the directory NEWDIR. Handle symbolic
355 link following, etc. This function *must* return with
356 the_current_working_directory either set to NULL (in which case
357 getcwd() will eventually be called), or set to a string corresponding
358 to the working directory. Return 1 on success, 0 on failure. */
361 change_to_directory (newdir, nolinks)
366 int err, canon_failed;
370 if (the_current_working_directory == 0)
372 t = get_working_directory ("chdir");
376 t = make_absolute (newdir, the_current_working_directory);
378 /* TDIR is either the canonicalized absolute pathname of NEWDIR
379 (nolinks == 0) or the absolute physical pathname of NEWDIR
381 tdir = nolinks ? sh_physpath (t, 0)
382 : sh_canonpath (t, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
384 /* Use the canonicalized version of NEWDIR, or, if canonicalization
385 failed, use the non-canonical form. */
396 /* In POSIX mode, if we're resolving symlinks logically and sh_canonpath
397 returns NULL (because it checks the path, it will return NULL if the
398 resolved path doesn't exist), fail immediately. */
399 if (posixly_correct && nolinks == 0 && canon_failed)
405 /* If the chdir succeeds, update the_current_working_directory. */
406 if (chdir (nolinks ? newdir : tdir) == 0)
408 /* If canonicalization failed, but the chdir succeeded, reset the
409 shell's idea of the_current_working_directory. */
414 FREE (the_current_working_directory);
415 the_current_working_directory = tdir;
421 /* We failed to change to the appropriate directory name. If we tried
422 what the user passed (nolinks != 0), punt now. */
429 /* We're not in physical mode (nolinks == 0), but we failed to change to
430 the canonicalized directory name (TDIR). Try what the user passed
431 verbatim. If we succeed, reinitialize the_current_working_directory. */
432 if (chdir (newdir) == 0)
446 /* Code for cd spelling correction. Original patch submitted by
447 Neil Russel (caret@c-side.com). */
456 n = (strlen (dirname) * 3 + 1) / 2 + 1;
457 guess = (char *)xmalloc (n);
459 switch (spname (dirname, guess))