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 [-PL] [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 #define LCD_DOVARS 0x001
122 #define LCD_DOSPELL 0x002
123 #define LCD_PRINTPATH 0x004
124 #define LCD_FREEDIRNAME 0x010
126 /* This builtin is ultimately the way that all user-visible commands should
127 change the current working directory. It is called by cd_to_string (),
128 so the programming interface is simple, and it handles errors and
129 restrictions properly. */
134 char *dirname, *cdpath, *path, *temp;
135 int path_index, no_symlinks, opt, lflag;
137 #if defined (RESTRICTED_SHELL)
140 builtin_error ("restricted");
141 return (EXECUTION_FAILURE);
143 #endif /* RESTRICTED_SHELL */
145 no_symlinks = no_symbolic_links;
146 reset_internal_getopt ();
147 while ((opt = internal_getopt (list, "LP")) != -1)
159 return (EXECUTION_FAILURE);
164 lflag = (cdable_vars ? LCD_DOVARS : 0) |
165 ((interactive && cdspelling) ? LCD_DOSPELL : 0);
169 /* `cd' without arguments is equivalent to `cd $HOME' */
170 dirname = get_string_value ("HOME");
174 builtin_error ("HOME not set");
175 return (EXECUTION_FAILURE);
179 else if (list->word->word[0] == '-' && list->word->word[1] == '\0')
181 /* This is `cd -', equivalent to `cd $OLDPWD' */
182 dirname = get_string_value ("OLDPWD");
186 builtin_error ("OLDPWD not set");
187 return (EXECUTION_FAILURE);
189 lflag = interactive ? LCD_PRINTPATH : 0;
191 else if (absolute_pathname (list->word->word))
192 dirname = list->word->word;
193 else if (cdpath = get_string_value ("CDPATH"))
195 dirname = list->word->word;
197 /* Find directory in $CDPATH. */
199 while (path = extract_colon_unit (cdpath, &path_index))
201 /* OPT is 1 if the path element is non-empty */
202 opt = path[0] != '\0';
203 temp = sh_makepath (path, dirname, MP_DOTILDE);
206 if (change_to_directory (temp, no_symlinks))
208 /* POSIX.2 says that if a nonempty directory from CDPATH
209 is used to find the directory to change to, the new
210 directory name is echoed to stdout, whether or not
211 the shell is interactive. */
213 printf ("%s\n", no_symlinks ? temp : the_current_working_directory);
216 /* Posix.2 says that after using CDPATH, the resultant
217 value of $PWD will not contain `.' or `..'. */
218 return (bindpwd (posixly_correct || no_symlinks));
224 /* POSIX.2 says that if `.' does not appear in $CDPATH, we don't
225 try the current directory, so we just punt now with an error
226 message if POSIXLY_CORRECT is non-zero. The check for cdpath[0]
227 is so we don't mistakenly treat a CDPATH value of "" as not
228 specifying the current directory. */
229 if (posixly_correct && cdpath[0])
231 builtin_error ("%s: %s", dirname, strerror (ENOENT));
232 return (EXECUTION_FAILURE);
236 dirname = list->word->word;
238 /* When we get here, DIRNAME is the directory to change to. If we
239 chdir successfully, just return. */
240 if (change_to_directory (dirname, no_symlinks))
242 if (lflag & LCD_PRINTPATH)
243 printf ("%s\n", dirname);
244 return (bindpwd (no_symlinks));
247 /* If the user requests it, then perhaps this is the name of
248 a shell variable, whose value contains the directory to
250 if (lflag & LCD_DOVARS)
252 temp = get_string_value (dirname);
253 if (temp && change_to_directory (temp, no_symlinks))
255 printf ("%s\n", temp);
256 return (bindpwd (no_symlinks));
260 /* If the user requests it, try to find a directory name similar in
261 spelling to the one requested, in case the user made a simple
262 typo. This is similar to the UNIX 8th and 9th Edition shells. */
263 if (lflag & LCD_DOSPELL)
265 temp = cdspell (dirname);
266 if (temp && change_to_directory (temp, no_symlinks))
268 printf ("%s\n", temp);
269 return (bindpwd (no_symlinks));
275 builtin_error ("%s: %s", dirname, strerror (errno));
276 return (EXECUTION_FAILURE);
280 $FUNCTION pwd_builtin
282 Print the current working directory. With the -P option, pwd prints
283 the physical directory, without any symbolic links; the -L option
284 makes pwd follow symbolic links.
287 /* Non-zero means that pwd always prints the physical directory, without
289 static int verbatim_pwd;
291 /* Print the name of the current working directory. */
299 verbatim_pwd = no_symbolic_links;
300 reset_internal_getopt ();
301 while ((opt = internal_getopt (list, "LP")) != -1)
313 return (EXECUTION_FAILURE);
318 #define tcwd the_current_working_directory
320 directory = tcwd ? (verbatim_pwd ? sh_physpath (tcwd, 0) : tcwd)
321 : get_working_directory ("pwd");
326 printf ("%s\n", directory);
327 if (directory != the_current_working_directory)
332 builtin_error ("write error: %s", strerror (errno));
333 return (EXECUTION_FAILURE);
335 return (EXECUTION_SUCCESS);
338 return (EXECUTION_FAILURE);
341 /* Do the work of changing to the directory NEWDIR. Handle symbolic
342 link following, etc. This function *must* return with
343 the_current_working_directory either set to NULL (in which case
344 getcwd() will eventually be called), or set to a string corresponding
345 to the working directory. Return 1 on success, 0 on failure. */
348 change_to_directory (newdir, nolinks)
357 if (the_current_working_directory == 0)
359 t = get_working_directory ("chdir");
363 t = make_absolute (newdir, the_current_working_directory);
365 /* TDIR is either the canonicalized absolute pathname of NEWDIR
366 (nolinks == 0) or the absolute physical pathname of NEWDIR
368 tdir = nolinks ? sh_physpath (t, 0)
369 : sh_canonpath (t, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
371 /* Use the canonicalized version of NEWDIR, or, if canonicalization
372 failed, use the non-canonical form. */
381 /* If the chdir succeeds, update the_current_working_directory. */
382 if (chdir (nolinks ? newdir : tdir) == 0)
384 FREE (the_current_working_directory);
385 the_current_working_directory = tdir;
390 /* We failed to change to the appropriate directory name. If we tried
391 what the user passed (nolinks != 0), punt now. */
398 /* We're not in physical mode (nolinks == 0), but we failed to change to
399 the canonicalized directory name (TDIR). Try what the user passed
400 verbatim. If we succeed, reinitialize the_current_working_directory. */
401 if (chdir (newdir) == 0)
403 FREE (the_current_working_directory);
404 the_current_working_directory = (char *)NULL;
405 tdir = get_working_directory ("cd");
417 /* Code for cd spelling correction. Original patch submitted by
418 Neil Russel (caret@c-side.com). */
427 n = (strlen (dirname) * 3 + 1) / 2 + 1;
428 guess = (char *)xmalloc (n);
430 switch (spname (dirname, guess))