]> git.ipfire.org Git - thirdparty/bash.git/blob - builtins/cd.def
Bash-4.3 patch 39
[thirdparty/bash.git] / builtins / cd.def
1 This file is cd.def, from which is created cd.c. It implements the
2 builtins "cd" and "pwd" in Bash.
3
4 Copyright (C) 1987-2013 Free Software Foundation, Inc.
5
6 This file is part of GNU Bash, the Bourne Again SHell.
7
8 Bash is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 Bash is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with Bash. If not, see <http://www.gnu.org/licenses/>.
20
21 $PRODUCES cd.c
22 #include <config.h>
23
24 #if defined (HAVE_UNISTD_H)
25 # ifdef _MINIX
26 # include <sys/types.h>
27 # endif
28 # include <unistd.h>
29 #endif
30
31 #include "../bashtypes.h"
32 #include "posixdir.h"
33 #include "posixstat.h"
34 #if defined (HAVE_SYS_PARAM_H)
35 #include <sys/param.h>
36 #endif
37 #include <fcntl.h>
38
39 #include <stdio.h>
40
41 #include "../bashansi.h"
42 #include "../bashintl.h"
43
44 #include <errno.h>
45 #include <tilde/tilde.h>
46
47 #include "../shell.h"
48 #include "../flags.h"
49 #include "maxpath.h"
50 #include "common.h"
51 #include "bashgetopt.h"
52
53 #if !defined (errno)
54 extern int errno;
55 #endif /* !errno */
56
57 extern int posixly_correct;
58 extern int array_needs_making;
59 extern const char * const bash_getcwd_errstr;
60
61 static int bindpwd __P((int));
62 static int setpwd __P((char *));
63 static char *resetpwd __P((char *));
64 static int change_to_directory __P((char *, int, int));
65
66 static int cdxattr __P((char *, char **));
67 static void resetxattr __P((void));
68
69 /* Change this to 1 to get cd spelling correction by default. */
70 int cdspelling = 0;
71
72 int cdable_vars;
73
74 static int eflag; /* file scope so bindpwd() can see it */
75 static int xattrflag; /* O_XATTR support for openat */
76 static int xattrfd = -1;
77
78 $BUILTIN cd
79 $FUNCTION cd_builtin
80 $SHORT_DOC cd [-L|[-P [-e]] [-@]] [dir]
81 Change the shell working directory.
82
83 Change the current directory to DIR. The default DIR is the value of the
84 HOME shell variable.
85
86 The variable CDPATH defines the search path for the directory containing
87 DIR. Alternative directory names in CDPATH are separated by a colon (:).
88 A null directory name is the same as the current directory. If DIR begins
89 with a slash (/), then CDPATH is not used.
90
91 If the directory is not found, and the shell option `cdable_vars' is set,
92 the word is assumed to be a variable name. If that variable has a value,
93 its value is used for DIR.
94
95 Options:
96 -L force symbolic links to be followed: resolve symbolic links in
97 DIR after processing instances of `..'
98 -P use the physical directory structure without following symbolic
99 links: resolve symbolic links in DIR before processing instances
100 of `..'
101 -e if the -P option is supplied, and the current working directory
102 cannot be determined successfully, exit with a non-zero status
103 #if defined (O_XATTR)
104 -@ on systems that support it, present a file with extended attributes
105 as a directory containing the file attributes
106 #endif
107
108 The default is to follow symbolic links, as if `-L' were specified.
109 `..' is processed by removing the immediately previous pathname component
110 back to a slash or the beginning of DIR.
111
112 Exit Status:
113 Returns 0 if the directory is changed, and if $PWD is set successfully when
114 -P is used; non-zero otherwise.
115 $END
116
117 /* Just set $PWD, don't change OLDPWD. Used by `pwd -P' in posix mode. */
118 static int
119 setpwd (dirname)
120 char *dirname;
121 {
122 int old_anm;
123 SHELL_VAR *tvar;
124
125 old_anm = array_needs_making;
126 tvar = bind_variable ("PWD", dirname ? dirname : "", 0);
127 if (tvar && readonly_p (tvar))
128 return EXECUTION_FAILURE;
129 if (tvar && old_anm == 0 && array_needs_making && exported_p (tvar))
130 {
131 update_export_env_inplace ("PWD=", 4, dirname ? dirname : "");
132 array_needs_making = 0;
133 }
134 return EXECUTION_SUCCESS;
135 }
136
137 static int
138 bindpwd (no_symlinks)
139 int no_symlinks;
140 {
141 char *dirname, *pwdvar;
142 int old_anm, r;
143 SHELL_VAR *tvar;
144
145 r = sh_chkwrite (EXECUTION_SUCCESS);
146
147 #define tcwd the_current_working_directory
148 dirname = tcwd ? (no_symlinks ? sh_physpath (tcwd, 0) : tcwd)
149 : get_working_directory ("cd");
150 #undef tcwd
151
152 old_anm = array_needs_making;
153 pwdvar = get_string_value ("PWD");
154
155 tvar = bind_variable ("OLDPWD", pwdvar, 0);
156 if (tvar && readonly_p (tvar))
157 r = EXECUTION_FAILURE;
158
159 if (old_anm == 0 && array_needs_making && exported_p (tvar))
160 {
161 update_export_env_inplace ("OLDPWD=", 7, pwdvar);
162 array_needs_making = 0;
163 }
164
165 if (setpwd (dirname) == EXECUTION_FAILURE)
166 r = EXECUTION_FAILURE;
167 if (dirname == 0 && eflag)
168 r = EXECUTION_FAILURE;
169
170 if (dirname && dirname != the_current_working_directory)
171 free (dirname);
172
173 return (r);
174 }
175
176 /* Call get_working_directory to reset the value of
177 the_current_working_directory () */
178 static char *
179 resetpwd (caller)
180 char *caller;
181 {
182 char *tdir;
183
184 FREE (the_current_working_directory);
185 the_current_working_directory = (char *)NULL;
186 tdir = get_working_directory (caller);
187 return (tdir);
188 }
189
190 static int
191 cdxattr (dir, ndirp)
192 char *dir; /* don't assume we can always free DIR */
193 char **ndirp; /* return new constructed directory name */
194 {
195 #if defined (O_XATTR)
196 int apfd, fd, r, e;
197 char buf[11+40+40]; /* construct new `fake' path for pwd */
198
199 apfd = openat (AT_FDCWD, dir, O_RDONLY|O_NONBLOCK);
200 if (apfd < 0)
201 return -1;
202 fd = openat (apfd, ".", O_XATTR);
203 e = errno;
204 close (apfd); /* ignore close error for now */
205 errno = e;
206 if (fd < 0)
207 return -1;
208 r = fchdir (fd); /* assume fchdir exists everywhere with O_XATTR */
209 if (r < 0)
210 {
211 close (fd);
212 return -1;
213 }
214 /* NFSv4 and ZFS extended attribute directories do not have names which are
215 visible in the standard Unix directory tree structure. To ensure we have
216 a valid name for $PWD, we synthesize one under /proc, but to keep that
217 path valid, we need to keep the file descriptor open as long as we are in
218 this directory. This imposes a certain structure on /proc. */
219 if (ndirp)
220 {
221 sprintf (buf, "/proc/%d/fd/%d", getpid(), fd);
222 *ndirp = savestring (buf);
223 }
224
225 if (xattrfd >= 0)
226 close (xattrfd);
227 xattrfd = fd;
228
229 return r;
230 #else
231 return -1;
232 #endif
233 }
234
235 /* Clean up the O_XATTR baggage. Currently only closes xattrfd */
236 static void
237 resetxattr ()
238 {
239 #if defined (O_XATTR)
240 if (xattrfd >= 0)
241 {
242 close (xattrfd);
243 xattrfd = -1;
244 }
245 #else
246 xattrfd = -1; /* not strictly necessary */
247 #endif
248 }
249
250 #define LCD_DOVARS 0x001
251 #define LCD_DOSPELL 0x002
252 #define LCD_PRINTPATH 0x004
253 #define LCD_FREEDIRNAME 0x008
254
255 /* This builtin is ultimately the way that all user-visible commands should
256 change the current working directory. It is called by cd_to_string (),
257 so the programming interface is simple, and it handles errors and
258 restrictions properly. */
259 int
260 cd_builtin (list)
261 WORD_LIST *list;
262 {
263 char *dirname, *cdpath, *path, *temp;
264 int path_index, no_symlinks, opt, lflag;
265
266 #if defined (RESTRICTED_SHELL)
267 if (restricted)
268 {
269 sh_restricted ((char *)NULL);
270 return (EXECUTION_FAILURE);
271 }
272 #endif /* RESTRICTED_SHELL */
273
274 eflag = 0;
275 no_symlinks = no_symbolic_links;
276 xattrflag = 0;
277 reset_internal_getopt ();
278 #if defined (O_XATTR)
279 while ((opt = internal_getopt (list, "eLP@")) != -1)
280 #else
281 while ((opt = internal_getopt (list, "eLP")) != -1)
282 #endif
283 {
284 switch (opt)
285 {
286 case 'P':
287 no_symlinks = 1;
288 break;
289 case 'L':
290 no_symlinks = 0;
291 break;
292 case 'e':
293 eflag = 1;
294 break;
295 #if defined (O_XATTR)
296 case '@':
297 xattrflag = 1;
298 break;
299 #endif
300 default:
301 builtin_usage ();
302 return (EX_USAGE);
303 }
304 }
305 list = loptend;
306
307 lflag = (cdable_vars ? LCD_DOVARS : 0) |
308 ((interactive && cdspelling) ? LCD_DOSPELL : 0);
309 if (eflag && no_symlinks == 0)
310 eflag = 0;
311
312 if (list == 0)
313 {
314 /* `cd' without arguments is equivalent to `cd $HOME' */
315 dirname = get_string_value ("HOME");
316
317 if (dirname == 0)
318 {
319 builtin_error (_("HOME not set"));
320 return (EXECUTION_FAILURE);
321 }
322 lflag = 0;
323 }
324 #if defined (CD_COMPLAINS)
325 else if (list->next)
326 {
327 builtin_error (_("too many arguments"));
328 return (EXECUTION_FAILURE);
329 }
330 #endif
331 else if (list->word->word[0] == '-' && list->word->word[1] == '\0')
332 {
333 /* This is `cd -', equivalent to `cd $OLDPWD' */
334 dirname = get_string_value ("OLDPWD");
335
336 if (dirname == 0)
337 {
338 builtin_error (_("OLDPWD not set"));
339 return (EXECUTION_FAILURE);
340 }
341 #if 0
342 lflag = interactive ? LCD_PRINTPATH : 0;
343 #else
344 lflag = LCD_PRINTPATH; /* According to SUSv3 */
345 #endif
346 }
347 else if (absolute_pathname (list->word->word))
348 dirname = list->word->word;
349 else if (privileged_mode == 0 && (cdpath = get_string_value ("CDPATH")))
350 {
351 dirname = list->word->word;
352
353 /* Find directory in $CDPATH. */
354 path_index = 0;
355 while (path = extract_colon_unit (cdpath, &path_index))
356 {
357 /* OPT is 1 if the path element is non-empty */
358 opt = path[0] != '\0';
359 temp = sh_makepath (path, dirname, MP_DOTILDE);
360 free (path);
361
362 if (change_to_directory (temp, no_symlinks, xattrflag))
363 {
364 /* POSIX.2 says that if a nonempty directory from CDPATH
365 is used to find the directory to change to, the new
366 directory name is echoed to stdout, whether or not
367 the shell is interactive. */
368 if (opt && (path = no_symlinks ? temp : the_current_working_directory))
369 printf ("%s\n", path);
370
371 free (temp);
372 #if 0
373 /* Posix.2 says that after using CDPATH, the resultant
374 value of $PWD will not contain `.' or `..'. */
375 return (bindpwd (posixly_correct || no_symlinks));
376 #else
377 return (bindpwd (no_symlinks));
378 #endif
379 }
380 else
381 free (temp);
382 }
383
384 #if 0
385 /* changed for bash-4.2 Posix cd description steps 5-6 */
386 /* POSIX.2 says that if `.' does not appear in $CDPATH, we don't
387 try the current directory, so we just punt now with an error
388 message if POSIXLY_CORRECT is non-zero. The check for cdpath[0]
389 is so we don't mistakenly treat a CDPATH value of "" as not
390 specifying the current directory. */
391 if (posixly_correct && cdpath[0])
392 {
393 builtin_error ("%s: %s", dirname, strerror (ENOENT));
394 return (EXECUTION_FAILURE);
395 }
396 #endif
397 }
398 else
399 dirname = list->word->word;
400
401 /* When we get here, DIRNAME is the directory to change to. If we
402 chdir successfully, just return. */
403 if (change_to_directory (dirname, no_symlinks, xattrflag))
404 {
405 if (lflag & LCD_PRINTPATH)
406 printf ("%s\n", dirname);
407 return (bindpwd (no_symlinks));
408 }
409
410 /* If the user requests it, then perhaps this is the name of
411 a shell variable, whose value contains the directory to
412 change to. */
413 if (lflag & LCD_DOVARS)
414 {
415 temp = get_string_value (dirname);
416 if (temp && change_to_directory (temp, no_symlinks, xattrflag))
417 {
418 printf ("%s\n", temp);
419 return (bindpwd (no_symlinks));
420 }
421 }
422
423 /* If the user requests it, try to find a directory name similar in
424 spelling to the one requested, in case the user made a simple
425 typo. This is similar to the UNIX 8th and 9th Edition shells. */
426 if (lflag & LCD_DOSPELL)
427 {
428 temp = dirspell (dirname);
429 if (temp && change_to_directory (temp, no_symlinks, xattrflag))
430 {
431 printf ("%s\n", temp);
432 free (temp);
433 return (bindpwd (no_symlinks));
434 }
435 else
436 FREE (temp);
437 }
438
439 builtin_error ("%s: %s", dirname, strerror (errno));
440 return (EXECUTION_FAILURE);
441 }
442
443 $BUILTIN pwd
444 $FUNCTION pwd_builtin
445 $SHORT_DOC pwd [-LP]
446 Print the name of the current working directory.
447
448 Options:
449 -L print the value of $PWD if it names the current working
450 directory
451 -P print the physical directory, without any symbolic links
452
453 By default, `pwd' behaves as if `-L' were specified.
454
455 Exit Status:
456 Returns 0 unless an invalid option is given or the current directory
457 cannot be read.
458 $END
459
460 /* Non-zero means that pwd always prints the physical directory, without
461 symbolic links. */
462 static int verbatim_pwd;
463
464 /* Print the name of the current working directory. */
465 int
466 pwd_builtin (list)
467 WORD_LIST *list;
468 {
469 char *directory;
470 int opt, pflag;
471
472 verbatim_pwd = no_symbolic_links;
473 pflag = 0;
474 reset_internal_getopt ();
475 while ((opt = internal_getopt (list, "LP")) != -1)
476 {
477 switch (opt)
478 {
479 case 'P':
480 verbatim_pwd = pflag = 1;
481 break;
482 case 'L':
483 verbatim_pwd = 0;
484 break;
485 default:
486 builtin_usage ();
487 return (EX_USAGE);
488 }
489 }
490 list = loptend;
491
492 #define tcwd the_current_working_directory
493
494 directory = tcwd ? (verbatim_pwd ? sh_physpath (tcwd, 0) : tcwd)
495 : get_working_directory ("pwd");
496
497 /* Try again using getcwd() if canonicalization fails (for instance, if
498 the file system has changed state underneath bash). */
499 if ((tcwd && directory == 0) ||
500 (posixly_correct && same_file (".", tcwd, (struct stat *)0, (struct stat *)0) == 0))
501 {
502 if (directory && directory != tcwd)
503 free (directory);
504 directory = resetpwd ("pwd");
505 }
506
507 #undef tcwd
508
509 if (directory)
510 {
511 opt = EXECUTION_SUCCESS;
512 printf ("%s\n", directory);
513 /* This is dumb but posix-mandated. */
514 if (posixly_correct && pflag)
515 opt = setpwd (directory);
516 if (directory != the_current_working_directory)
517 free (directory);
518 return (sh_chkwrite (opt));
519 }
520 else
521 return (EXECUTION_FAILURE);
522 }
523
524 /* Do the work of changing to the directory NEWDIR. Handle symbolic
525 link following, etc. This function *must* return with
526 the_current_working_directory either set to NULL (in which case
527 getcwd() will eventually be called), or set to a string corresponding
528 to the working directory. Return 1 on success, 0 on failure. */
529
530 static int
531 change_to_directory (newdir, nolinks, xattr)
532 char *newdir;
533 int nolinks, xattr;
534 {
535 char *t, *tdir, *ndir;
536 int err, canon_failed, r, ndlen, dlen;
537
538 tdir = (char *)NULL;
539
540 if (the_current_working_directory == 0)
541 {
542 t = get_working_directory ("chdir");
543 FREE (t);
544 }
545
546 t = make_absolute (newdir, the_current_working_directory);
547
548 /* TDIR is either the canonicalized absolute pathname of NEWDIR
549 (nolinks == 0) or the absolute physical pathname of NEWDIR
550 (nolinks != 0). */
551 tdir = nolinks ? sh_physpath (t, 0)
552 : sh_canonpath (t, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
553
554 ndlen = strlen (newdir);
555 dlen = strlen (t);
556
557 /* Use the canonicalized version of NEWDIR, or, if canonicalization
558 failed, use the non-canonical form. */
559 canon_failed = 0;
560 if (tdir && *tdir)
561 free (t);
562 else
563 {
564 FREE (tdir);
565 tdir = t;
566 canon_failed = 1;
567 }
568
569 /* In POSIX mode, if we're resolving symlinks logically and sh_canonpath
570 returns NULL (because it checks the path, it will return NULL if the
571 resolved path doesn't exist), fail immediately. */
572 if (posixly_correct && nolinks == 0 && canon_failed && (errno != ENAMETOOLONG || ndlen > PATH_MAX))
573 {
574 #if defined ENAMETOOLONG
575 if (errno != ENOENT && errno != ENAMETOOLONG)
576 #else
577 if (errno != ENOENT)
578 #endif
579 errno = ENOTDIR;
580 free (tdir);
581 return (0);
582 }
583
584 #if defined (O_XATTR)
585 if (xattrflag)
586 {
587 r = cdxattr (nolinks ? newdir : tdir, &ndir);
588 if (r >= 0)
589 {
590 canon_failed = 0;
591 free (tdir);
592 tdir = ndir;
593 }
594 else
595 {
596 err = errno;
597 free (tdir);
598 errno = err;
599 return (0); /* no xattr */
600 }
601 }
602 else
603 #endif
604 {
605 r = chdir (nolinks ? newdir : tdir);
606 if (r >= 0)
607 resetxattr ();
608 }
609
610 /* If the chdir succeeds, update the_current_working_directory. */
611 if (r == 0)
612 {
613 /* If canonicalization failed, but the chdir succeeded, reset the
614 shell's idea of the_current_working_directory. */
615 if (canon_failed)
616 {
617 t = resetpwd ("cd");
618 if (t == 0)
619 set_working_directory (tdir);
620 else
621 free (t);
622 }
623 else
624 set_working_directory (tdir);
625
626 free (tdir);
627 return (1);
628 }
629
630 /* We failed to change to the appropriate directory name. If we tried
631 what the user passed (nolinks != 0), punt now. */
632 if (nolinks)
633 {
634 free (tdir);
635 return (0);
636 }
637
638 err = errno;
639
640 /* We're not in physical mode (nolinks == 0), but we failed to change to
641 the canonicalized directory name (TDIR). Try what the user passed
642 verbatim. If we succeed, reinitialize the_current_working_directory. */
643 if (chdir (newdir) == 0)
644 {
645 t = resetpwd ("cd");
646 if (t == 0)
647 set_working_directory (tdir);
648 else
649 free (t);
650
651 r = 1;
652 }
653 else
654 {
655 errno = err;
656 r = 0;
657 }
658
659 free (tdir);
660 return r;
661 }