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