]> git.ipfire.org Git - thirdparty/bash.git/blame - builtins/cd.def
commit bash-20100108 snapshot
[thirdparty/bash.git] / builtins / cd.def
CommitLineData
726f6388 1This file is cd.def, from which is created cd.c. It implements the
ccc6cda3 2builtins "cd" and "pwd" in Bash.
726f6388 3
012bac39 4Copyright (C) 1987-2009 Free Software Foundation, Inc.
726f6388
JA
5
6This file is part of GNU Bash, the Bourne Again SHell.
7
2e4498b3
CR
8Bash is free software: you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation, either version 3 of the License, or
11(at your option) any later version.
726f6388 12
2e4498b3
CR
13Bash is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
726f6388 17
2e4498b3
CR
18You should have received a copy of the GNU General Public License
19along with Bash. If not, see <http://www.gnu.org/licenses/>.
726f6388
JA
20
21$PRODUCES cd.c
ccc6cda3 22#include <config.h>
726f6388 23
ccc6cda3 24#if defined (HAVE_UNISTD_H)
cce855bc
JA
25# ifdef _MINIX
26# include <sys/types.h>
27# endif
ccc6cda3
JA
28# include <unistd.h>
29#endif
30
31#include "../bashtypes.h"
bb70624e
JA
32#include "posixdir.h"
33#include "posixstat.h"
cce855bc 34#ifndef _MINIX
726f6388 35#include <sys/param.h>
cce855bc 36#endif
726f6388 37
ccc6cda3
JA
38#include <stdio.h>
39
40#include "../bashansi.h"
5e13499c 41#include "../bashintl.h"
726f6388
JA
42
43#include <errno.h>
44#include <tilde/tilde.h>
45
46#include "../shell.h"
47#include "../flags.h"
bb70624e 48#include "maxpath.h"
726f6388 49#include "common.h"
ccc6cda3 50#include "bashgetopt.h"
726f6388
JA
51
52#if !defined (errno)
53extern int errno;
54#endif /* !errno */
55
f73dda09 56extern int posixly_correct;
d166f048 57extern int array_needs_making;
d3ad40de 58extern const char * const bash_getcwd_errstr;
ccc6cda3 59
f73dda09 60static int bindpwd __P((int));
2206f89a 61static void setpwd __P((char *));
d3ad40de 62static char *resetpwd __P((char *));
f73dda09 63static int change_to_directory __P((char *, int));
ccc6cda3 64
d166f048
JA
65/* Change this to 1 to get cd spelling correction by default. */
66int cdspelling = 0;
ccc6cda3
JA
67
68int cdable_vars;
726f6388
JA
69
70$BUILTIN cd
71$FUNCTION cd_builtin
7117c2d2 72$SHORT_DOC cd [-L|-P] [dir]
6a8fd0ed
CR
73Change the shell working directory.
74
9cbcc93b
CR
75Change the current directory to DIR. The default DIR is the value of the
76HOME shell variable.
77
78The variable CDPATH defines the search path for the directory containing
79DIR. Alternative directory names in CDPATH are separated by a colon (:).
80A null directory name is the same as the current directory. If DIR begins
81with a slash (/), then CDPATH is not used.
82
83If the directory is not found, and the shell option `cdable_vars' is set,
84the word is assumed to be a variable name. If that variable has a value,
85its value is used for DIR.
86
87Options:
88 -L force symbolic links to be followed
89 -P use the physical directory structure without following symbolic
90 links
91
92The default is to follow symbolic links, as if `-L' were specified.
6a8fd0ed
CR
93
94Exit Status:
95Returns 0 if the directory is changed; non-zero otherwise.
726f6388
JA
96$END
97
2206f89a
CR
98/* Just set $PWD, don't change OLDPWD. Used by `pwd -P' in posix mode. */
99static void
100setpwd (dirname)
101 char *dirname;
102{
103 int old_anm;
104 SHELL_VAR *tvar;
105
106 old_anm = array_needs_making;
107 tvar = bind_variable ("PWD", dirname ? dirname : "", 0);
108 if (old_anm == 0 && array_needs_making && exported_p (tvar))
109 {
110 update_export_env_inplace ("PWD=", 4, dirname ? dirname : "");
111 array_needs_making = 0;
112 }
113}
114
ccc6cda3
JA
115static int
116bindpwd (no_symlinks)
117 int no_symlinks;
118{
d166f048 119 char *dirname, *pwdvar;
641d8f00 120 int old_anm, r;
d166f048 121 SHELL_VAR *tvar;
ccc6cda3 122
641d8f00
CR
123 r = sh_chkwrite (EXECUTION_SUCCESS);
124
28ef6c31
JA
125#define tcwd the_current_working_directory
126 dirname = tcwd ? (no_symlinks ? sh_physpath (tcwd, 0) : tcwd)
127 : get_working_directory ("cd");
128#undef tcwd
ccc6cda3 129
d166f048 130 old_anm = array_needs_making;
b72432fd
JA
131 pwdvar = get_string_value ("PWD");
132
d11b8b46 133 tvar = bind_variable ("OLDPWD", pwdvar, 0);
b72432fd
JA
134 if (old_anm == 0 && array_needs_making && exported_p (tvar))
135 {
136 update_export_env_inplace ("OLDPWD=", 7, pwdvar);
137 array_needs_making = 0;
138 }
139
2206f89a 140 setpwd (dirname);
ccc6cda3 141
28ef6c31
JA
142 if (dirname && dirname != the_current_working_directory)
143 free (dirname);
f085a21f 144
641d8f00 145 return (r);
ccc6cda3
JA
146}
147
7117c2d2
JA
148/* Call get_working_directory to reset the value of
149 the_current_working_directory () */
150static char *
762a763b
CR
151resetpwd (caller)
152 char *caller;
7117c2d2
JA
153{
154 char *tdir;
155
156 FREE (the_current_working_directory);
157 the_current_working_directory = (char *)NULL;
762a763b 158 tdir = get_working_directory (caller);
7117c2d2
JA
159 return (tdir);
160}
161
28ef6c31
JA
162#define LCD_DOVARS 0x001
163#define LCD_DOSPELL 0x002
164#define LCD_PRINTPATH 0x004
1665e22a 165#define LCD_FREEDIRNAME 0x008
28ef6c31 166
726f6388
JA
167/* This builtin is ultimately the way that all user-visible commands should
168 change the current working directory. It is called by cd_to_string (),
169 so the programming interface is simple, and it handles errors and
170 restrictions properly. */
171int
172cd_builtin (list)
173 WORD_LIST *list;
174{
ccc6cda3 175 char *dirname, *cdpath, *path, *temp;
28ef6c31 176 int path_index, no_symlinks, opt, lflag;
726f6388
JA
177
178#if defined (RESTRICTED_SHELL)
179 if (restricted)
180 {
7117c2d2 181 sh_restricted ((char *)NULL);
726f6388
JA
182 return (EXECUTION_FAILURE);
183 }
184#endif /* RESTRICTED_SHELL */
185
ccc6cda3
JA
186 no_symlinks = no_symbolic_links;
187 reset_internal_getopt ();
188 while ((opt = internal_getopt (list, "LP")) != -1)
726f6388 189 {
ccc6cda3 190 switch (opt)
726f6388 191 {
ccc6cda3
JA
192 case 'P':
193 no_symlinks = 1;
194 break;
195 case 'L':
196 no_symlinks = 0;
197 break;
198 default:
199 builtin_usage ();
726f6388
JA
200 return (EXECUTION_FAILURE);
201 }
726f6388 202 }
ccc6cda3
JA
203 list = loptend;
204
28ef6c31
JA
205 lflag = (cdable_vars ? LCD_DOVARS : 0) |
206 ((interactive && cdspelling) ? LCD_DOSPELL : 0);
207
ccc6cda3 208 if (list == 0)
726f6388 209 {
ccc6cda3 210 /* `cd' without arguments is equivalent to `cd $HOME' */
726f6388
JA
211 dirname = get_string_value ("HOME");
212
ccc6cda3 213 if (dirname == 0)
726f6388 214 {
5e13499c 215 builtin_error (_("HOME not set"));
726f6388
JA
216 return (EXECUTION_FAILURE);
217 }
28ef6c31 218 lflag = 0;
726f6388 219 }
ccc6cda3 220 else if (list->word->word[0] == '-' && list->word->word[1] == '\0')
726f6388 221 {
ccc6cda3
JA
222 /* This is `cd -', equivalent to `cd $OLDPWD' */
223 dirname = get_string_value ("OLDPWD");
726f6388 224
28ef6c31 225 if (dirname == 0)
726f6388 226 {
5e13499c 227 builtin_error (_("OLDPWD not set"));
726f6388
JA
228 return (EXECUTION_FAILURE);
229 }
d3a24ed2 230#if 0
28ef6c31 231 lflag = interactive ? LCD_PRINTPATH : 0;
d3a24ed2
CR
232#else
233 lflag = LCD_PRINTPATH; /* According to SUSv3 */
234#endif
726f6388 235 }
28ef6c31
JA
236 else if (absolute_pathname (list->word->word))
237 dirname = list->word->word;
e77a3058 238 else if (privileged_mode == 0 && (cdpath = get_string_value ("CDPATH")))
726f6388 239 {
ccc6cda3
JA
240 dirname = list->word->word;
241
28ef6c31
JA
242 /* Find directory in $CDPATH. */
243 path_index = 0;
244 while (path = extract_colon_unit (cdpath, &path_index))
726f6388 245 {
28ef6c31
JA
246 /* OPT is 1 if the path element is non-empty */
247 opt = path[0] != '\0';
248 temp = sh_makepath (path, dirname, MP_DOTILDE);
249 free (path);
cce855bc 250
28ef6c31 251 if (change_to_directory (temp, no_symlinks))
cce855bc 252 {
28ef6c31
JA
253 /* POSIX.2 says that if a nonempty directory from CDPATH
254 is used to find the directory to change to, the new
255 directory name is echoed to stdout, whether or not
256 the shell is interactive. */
1d7ecd77
CR
257 if (opt && (path = no_symlinks ? temp : the_current_working_directory))
258 printf ("%s\n", path);
28ef6c31
JA
259
260 free (temp);
9d2b70f0 261#if 0
28ef6c31
JA
262 /* Posix.2 says that after using CDPATH, the resultant
263 value of $PWD will not contain `.' or `..'. */
264 return (bindpwd (posixly_correct || no_symlinks));
9d2b70f0
CR
265#else
266 return (bindpwd (no_symlinks));
267#endif
cce855bc 268 }
28ef6c31
JA
269 else
270 free (temp);
726f6388
JA
271 }
272
28ef6c31
JA
273 /* POSIX.2 says that if `.' does not appear in $CDPATH, we don't
274 try the current directory, so we just punt now with an error
275 message if POSIXLY_CORRECT is non-zero. The check for cdpath[0]
276 is so we don't mistakenly treat a CDPATH value of "" as not
277 specifying the current directory. */
278 if (posixly_correct && cdpath[0])
726f6388 279 {
28ef6c31
JA
280 builtin_error ("%s: %s", dirname, strerror (ENOENT));
281 return (EXECUTION_FAILURE);
726f6388 282 }
28ef6c31
JA
283 }
284 else
285 dirname = list->word->word;
286
287 /* When we get here, DIRNAME is the directory to change to. If we
288 chdir successfully, just return. */
289 if (change_to_directory (dirname, no_symlinks))
290 {
291 if (lflag & LCD_PRINTPATH)
292 printf ("%s\n", dirname);
293 return (bindpwd (no_symlinks));
294 }
726f6388 295
28ef6c31
JA
296 /* If the user requests it, then perhaps this is the name of
297 a shell variable, whose value contains the directory to
298 change to. */
299 if (lflag & LCD_DOVARS)
300 {
301 temp = get_string_value (dirname);
302 if (temp && change_to_directory (temp, no_symlinks))
726f6388 303 {
28ef6c31
JA
304 printf ("%s\n", temp);
305 return (bindpwd (no_symlinks));
726f6388 306 }
28ef6c31 307 }
726f6388 308
28ef6c31
JA
309 /* If the user requests it, try to find a directory name similar in
310 spelling to the one requested, in case the user made a simple
311 typo. This is similar to the UNIX 8th and 9th Edition shells. */
312 if (lflag & LCD_DOSPELL)
313 {
29d25b54 314 temp = dirspell (dirname);
28ef6c31
JA
315 if (temp && change_to_directory (temp, no_symlinks))
316 {
317 printf ("%s\n", temp);
318 return (bindpwd (no_symlinks));
319 }
320 else
321 FREE (temp);
726f6388
JA
322 }
323
28ef6c31
JA
324 builtin_error ("%s: %s", dirname, strerror (errno));
325 return (EXECUTION_FAILURE);
726f6388 326}
726f6388 327
ccc6cda3
JA
328$BUILTIN pwd
329$FUNCTION pwd_builtin
cdb32d45 330$SHORT_DOC pwd [-LP]
9cbcc93b
CR
331Print the name of the current working directory.
332
333Options:
334 -L print the value of $PWD if it names the current working
335 directory
336 -P print the physical directory, without any symbolic links
337
338By default, `pwd' behaves as if `-L' were specified.
6a8fd0ed
CR
339
340Exit Status:
341Returns 0 unless an invalid option is given or the current directory
342cannot be read.
726f6388
JA
343$END
344
ccc6cda3
JA
345/* Non-zero means that pwd always prints the physical directory, without
346 symbolic links. */
347static int verbatim_pwd;
348
349/* Print the name of the current working directory. */
350int
351pwd_builtin (list)
726f6388
JA
352 WORD_LIST *list;
353{
28ef6c31 354 char *directory;
2206f89a 355 int opt, pflag;
726f6388 356
ccc6cda3 357 verbatim_pwd = no_symbolic_links;
2206f89a 358 pflag = 0;
ccc6cda3
JA
359 reset_internal_getopt ();
360 while ((opt = internal_getopt (list, "LP")) != -1)
726f6388 361 {
ccc6cda3 362 switch (opt)
726f6388 363 {
ccc6cda3 364 case 'P':
2206f89a 365 verbatim_pwd = pflag = 1;
ccc6cda3
JA
366 break;
367 case 'L':
368 verbatim_pwd = 0;
369 break;
370 default:
371 builtin_usage ();
726f6388
JA
372 return (EXECUTION_FAILURE);
373 }
374 }
ccc6cda3 375 list = loptend;
726f6388 376
28ef6c31 377#define tcwd the_current_working_directory
726f6388 378
28ef6c31
JA
379 directory = tcwd ? (verbatim_pwd ? sh_physpath (tcwd, 0) : tcwd)
380 : get_working_directory ("pwd");
762a763b
CR
381
382 /* Try again using getcwd() if canonicalization fails (for instance, if
383 the file system has changed state underneath bash). */
cdb32d45
CR
384 if ((tcwd && directory == 0) ||
385 (posixly_correct && same_file (".", tcwd, (struct stat *)0, (struct stat *)0) == 0))
762a763b
CR
386 directory = resetpwd ("pwd");
387
28ef6c31 388#undef tcwd
726f6388 389
ccc6cda3
JA
390 if (directory)
391 {
392 printf ("%s\n", directory);
2206f89a
CR
393 /* This is dumb but posix-mandated. */
394 if (posixly_correct && pflag)
395 setpwd (directory);
28ef6c31
JA
396 if (directory != the_current_working_directory)
397 free (directory);
641d8f00 398 return (sh_chkwrite (EXECUTION_SUCCESS));
726f6388 399 }
ccc6cda3
JA
400 else
401 return (EXECUTION_FAILURE);
726f6388 402}
726f6388
JA
403
404/* Do the work of changing to the directory NEWDIR. Handle symbolic
28ef6c31
JA
405 link following, etc. This function *must* return with
406 the_current_working_directory either set to NULL (in which case
407 getcwd() will eventually be called), or set to a string corresponding
408 to the working directory. Return 1 on success, 0 on failure. */
726f6388
JA
409
410static int
ccc6cda3 411change_to_directory (newdir, nolinks)
726f6388 412 char *newdir;
ccc6cda3 413 int nolinks;
726f6388 414{
28ef6c31 415 char *t, *tdir;
ff247e74 416 int err, canon_failed, r, ndlen, dlen;
726f6388 417
28ef6c31 418 tdir = (char *)NULL;
726f6388 419
28ef6c31
JA
420 if (the_current_working_directory == 0)
421 {
422 t = get_working_directory ("chdir");
423 FREE (t);
424 }
726f6388 425
28ef6c31 426 t = make_absolute (newdir, the_current_working_directory);
726f6388 427
28ef6c31
JA
428 /* TDIR is either the canonicalized absolute pathname of NEWDIR
429 (nolinks == 0) or the absolute physical pathname of NEWDIR
430 (nolinks != 0). */
431 tdir = nolinks ? sh_physpath (t, 0)
432 : sh_canonpath (t, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
726f6388 433
ff247e74
CR
434 ndlen = strlen (newdir);
435 dlen = strlen (t);
436
28ef6c31
JA
437 /* Use the canonicalized version of NEWDIR, or, if canonicalization
438 failed, use the non-canonical form. */
7117c2d2 439 canon_failed = 0;
28ef6c31
JA
440 if (tdir && *tdir)
441 free (t);
442 else
443 {
444 FREE (tdir);
445 tdir = t;
7117c2d2
JA
446 canon_failed = 1;
447 }
448
449 /* In POSIX mode, if we're resolving symlinks logically and sh_canonpath
450 returns NULL (because it checks the path, it will return NULL if the
451 resolved path doesn't exist), fail immediately. */
ff247e74 452 if (posixly_correct && nolinks == 0 && canon_failed && (errno != ENAMETOOLONG || ndlen > PATH_MAX))
7117c2d2 453 {
c6d91e17
CR
454#if defined ENAMETOOLONG
455 if (errno != ENOENT && errno != ENAMETOOLONG)
456#else
5e13499c 457 if (errno != ENOENT)
c6d91e17 458#endif
5e13499c 459 errno = ENOTDIR;
7027abcb 460 free (tdir);
7117c2d2 461 return (0);
28ef6c31 462 }
726f6388 463
28ef6c31
JA
464 /* If the chdir succeeds, update the_current_working_directory. */
465 if (chdir (nolinks ? newdir : tdir) == 0)
466 {
7117c2d2
JA
467 /* If canonicalization failed, but the chdir succeeded, reset the
468 shell's idea of the_current_working_directory. */
469 if (canon_failed)
7117c2d2 470 {
c6d91e17
CR
471 t = resetpwd ("cd");
472 if (t == 0)
473 set_working_directory (tdir);
7117c2d2 474 }
c6d91e17
CR
475 else
476 set_working_directory (tdir);
7117c2d2 477
7027abcb 478 free (tdir);
28ef6c31
JA
479 return (1);
480 }
726f6388 481
28ef6c31
JA
482 /* We failed to change to the appropriate directory name. If we tried
483 what the user passed (nolinks != 0), punt now. */
484 if (nolinks)
7027abcb
CR
485 {
486 free (tdir);
487 return (0);
488 }
726f6388 489
28ef6c31 490 err = errno;
726f6388 491
28ef6c31
JA
492 /* We're not in physical mode (nolinks == 0), but we failed to change to
493 the canonicalized directory name (TDIR). Try what the user passed
494 verbatim. If we succeed, reinitialize the_current_working_directory. */
495 if (chdir (newdir) == 0)
496 {
c6d91e17
CR
497 t = resetpwd ("cd");
498 if (t == 0)
499 set_working_directory (tdir);
500 else
501 free (t);
726f6388 502
c6d91e17 503 r = 1;
726f6388
JA
504 }
505 else
28ef6c31
JA
506 {
507 errno = err;
c6d91e17 508 r = 0;
28ef6c31 509 }
c6d91e17
CR
510
511 free (tdir);
512 return r;
ccc6cda3 513}