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