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, interactive;
57 extern int array_needs_making;
58 extern char *bash_getcwd_errstr;
60 static int change_to_directory ();
62 static char *cdspell ();
64 /* Change this to 1 to get cd spelling correction by default. */
71 $SHORT_DOC cd [-PL] [dir]
72 Change the current directory to DIR. The variable $HOME is the
73 default DIR. The variable CDPATH defines the search path for
74 the directory containing DIR. Alternative directory names in CDPATH
75 are separated by a colon (:). A null directory name is the same as
76 the current directory, i.e. `.'. If DIR begins with a slash (/),
77 then CDPATH is not used. If the directory is not found, and the
78 shell option `cdable_vars' is set, then try the word as a variable
79 name. If that variable has a value, then cd to the value of that
80 variable. The -P option says to use the physical directory structure
81 instead of following symbolic links; the -L option forces symbolic links
89 char *dirname, *pwdvar;
90 int old_symlinks, old_anm;
93 #define tcwd the_current_working_directory
94 dirname = tcwd ? (no_symlinks ? sh_physpath (tcwd, 0) : tcwd)
95 : get_working_directory ("cd");
98 old_anm = array_needs_making;
99 pwdvar = get_string_value ("PWD");
101 tvar = bind_variable ("OLDPWD", pwdvar);
102 if (old_anm == 0 && array_needs_making && exported_p (tvar))
104 update_export_env_inplace ("OLDPWD=", 7, pwdvar);
105 array_needs_making = 0;
108 tvar = bind_variable ("PWD", dirname);
109 if (old_anm == 0 && array_needs_making && exported_p (tvar))
111 update_export_env_inplace ("PWD=", 4, dirname);
112 array_needs_making = 0;
115 if (dirname && dirname != the_current_working_directory)
117 return (EXECUTION_SUCCESS);
120 #define LCD_DOVARS 0x001
121 #define LCD_DOSPELL 0x002
122 #define LCD_PRINTPATH 0x004
123 #define LCD_FREEDIRNAME 0x010
125 /* This builtin is ultimately the way that all user-visible commands should
126 change the current working directory. It is called by cd_to_string (),
127 so the programming interface is simple, and it handles errors and
128 restrictions properly. */
133 char *dirname, *cdpath, *path, *temp;
134 int path_index, no_symlinks, opt, lflag;
136 #if defined (RESTRICTED_SHELL)
139 builtin_error ("restricted");
140 return (EXECUTION_FAILURE);
142 #endif /* RESTRICTED_SHELL */
144 no_symlinks = no_symbolic_links;
145 reset_internal_getopt ();
146 while ((opt = internal_getopt (list, "LP")) != -1)
158 return (EXECUTION_FAILURE);
163 lflag = (cdable_vars ? LCD_DOVARS : 0) |
164 ((interactive && cdspelling) ? LCD_DOSPELL : 0);
168 /* `cd' without arguments is equivalent to `cd $HOME' */
169 dirname = get_string_value ("HOME");
173 builtin_error ("HOME not set");
174 return (EXECUTION_FAILURE);
178 else if (list->word->word[0] == '-' && list->word->word[1] == '\0')
180 /* This is `cd -', equivalent to `cd $OLDPWD' */
181 dirname = get_string_value ("OLDPWD");
185 builtin_error ("OLDPWD not set");
186 return (EXECUTION_FAILURE);
188 lflag = interactive ? LCD_PRINTPATH : 0;
190 else if (absolute_pathname (list->word->word))
191 dirname = list->word->word;
192 else if (cdpath = get_string_value ("CDPATH"))
194 dirname = list->word->word;
196 /* Find directory in $CDPATH. */
198 while (path = extract_colon_unit (cdpath, &path_index))
200 /* OPT is 1 if the path element is non-empty */
201 opt = path[0] != '\0';
202 temp = sh_makepath (path, dirname, MP_DOTILDE);
205 if (change_to_directory (temp, no_symlinks))
207 /* POSIX.2 says that if a nonempty directory from CDPATH
208 is used to find the directory to change to, the new
209 directory name is echoed to stdout, whether or not
210 the shell is interactive. */
212 printf ("%s\n", no_symlinks ? temp : the_current_working_directory);
215 /* Posix.2 says that after using CDPATH, the resultant
216 value of $PWD will not contain `.' or `..'. */
217 return (bindpwd (posixly_correct || no_symlinks));
223 /* POSIX.2 says that if `.' does not appear in $CDPATH, we don't
224 try the current directory, so we just punt now with an error
225 message if POSIXLY_CORRECT is non-zero. The check for cdpath[0]
226 is so we don't mistakenly treat a CDPATH value of "" as not
227 specifying the current directory. */
228 if (posixly_correct && cdpath[0])
230 builtin_error ("%s: %s", dirname, strerror (ENOENT));
231 return (EXECUTION_FAILURE);
235 dirname = list->word->word;
237 /* When we get here, DIRNAME is the directory to change to. If we
238 chdir successfully, just return. */
239 if (change_to_directory (dirname, no_symlinks))
241 if (lflag & LCD_PRINTPATH)
242 printf ("%s\n", dirname);
243 return (bindpwd (no_symlinks));
246 /* If the user requests it, then perhaps this is the name of
247 a shell variable, whose value contains the directory to
249 if (lflag & LCD_DOVARS)
251 temp = get_string_value (dirname);
252 if (temp && change_to_directory (temp, no_symlinks))
254 printf ("%s\n", temp);
255 return (bindpwd (no_symlinks));
259 /* If the user requests it, try to find a directory name similar in
260 spelling to the one requested, in case the user made a simple
261 typo. This is similar to the UNIX 8th and 9th Edition shells. */
262 if (lflag & LCD_DOSPELL)
264 temp = cdspell (dirname);
265 if (temp && change_to_directory (temp, no_symlinks))
267 printf ("%s\n", temp);
268 return (bindpwd (no_symlinks));
274 builtin_error ("%s: %s", dirname, strerror (errno));
275 return (EXECUTION_FAILURE);
279 $FUNCTION pwd_builtin
281 Print the current working directory. With the -P option, pwd prints
282 the physical directory, without any symbolic links; the -L option
283 makes pwd follow symbolic links.
286 /* Non-zero means that pwd always prints the physical directory, without
288 static int verbatim_pwd;
290 /* Print the name of the current working directory. */
298 verbatim_pwd = no_symbolic_links;
299 reset_internal_getopt ();
300 while ((opt = internal_getopt (list, "LP")) != -1)
312 return (EXECUTION_FAILURE);
317 #define tcwd the_current_working_directory
319 directory = tcwd ? (verbatim_pwd ? sh_physpath (tcwd, 0) : tcwd)
320 : get_working_directory ("pwd");
325 printf ("%s\n", directory);
326 if (directory != the_current_working_directory)
331 builtin_error ("write error: %s", strerror (errno));
332 return (EXECUTION_FAILURE);
334 return (EXECUTION_SUCCESS);
337 return (EXECUTION_FAILURE);
340 /* Do the work of changing to the directory NEWDIR. Handle symbolic
341 link following, etc. This function *must* return with
342 the_current_working_directory either set to NULL (in which case
343 getcwd() will eventually be called), or set to a string corresponding
344 to the working directory. Return 1 on success, 0 on failure. */
347 change_to_directory (newdir, nolinks)
356 if (the_current_working_directory == 0)
358 t = get_working_directory ("chdir");
362 t = make_absolute (newdir, the_current_working_directory);
364 /* TDIR is either the canonicalized absolute pathname of NEWDIR
365 (nolinks == 0) or the absolute physical pathname of NEWDIR
367 tdir = nolinks ? sh_physpath (t, 0)
368 : sh_canonpath (t, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
370 /* Use the canonicalized version of NEWDIR, or, if canonicalization
371 failed, use the non-canonical form. */
380 /* If the chdir succeeds, update the_current_working_directory. */
381 if (chdir (nolinks ? newdir : tdir) == 0)
383 FREE (the_current_working_directory);
384 the_current_working_directory = tdir;
389 /* We failed to change to the appropriate directory name. If we tried
390 what the user passed (nolinks != 0), punt now. */
397 /* We're not in physical mode (nolinks == 0), but we failed to change to
398 the canonicalized directory name (TDIR). Try what the user passed
399 verbatim. If we succeed, reinitialize the_current_working_directory. */
400 if (chdir (newdir) == 0)
402 FREE (the_current_working_directory);
403 the_current_working_directory = (char *)NULL;
404 tdir = get_working_directory ("cd");
416 /* Code for cd spelling correction. Original patch submitted by
417 Neil Russel (caret@c-side.com). */
426 n = (strlen (dirname) * 3 + 1) / 2 + 1;
429 switch (spname (dirname, guess))