d53b25870ad60cbc90cb6c544ac54d2096ef0e2a
[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-2009 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 void 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 $BUILTIN cd
71 $FUNCTION cd_builtin
72 $SHORT_DOC cd [-L|-P] [dir]
73 Change the shell working directory.
74
75 Change the current directory to DIR.  The default DIR is the value of the
76 HOME shell variable.
77
78 The variable CDPATH defines the search path for the directory containing
79 DIR.  Alternative directory names in CDPATH are separated by a colon (:).
80 A null directory name is the same as the current directory.  If DIR begins
81 with a slash (/), then CDPATH is not used.
82
83 If the directory is not found, and the shell option `cdable_vars' is set,
84 the word is assumed to be  a variable name.  If that variable has a value,
85 its value is used for DIR.
86
87 Options:
88     -L  force symbolic links to be followed
89     -P  use the physical directory structure without following symbolic
90         links
91
92 The default is to follow symbolic links, as if `-L' were specified.
93
94 Exit Status:
95 Returns 0 if the directory is changed; non-zero otherwise.
96 $END
97
98 /* Just set $PWD, don't change OLDPWD.  Used by `pwd -P' in posix mode. */
99 static void
100 setpwd (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
115 static int
116 bindpwd (no_symlinks)
117      int no_symlinks;
118 {
119   char *dirname, *pwdvar;
120   int old_anm, r;
121   SHELL_VAR *tvar;
122
123   r = sh_chkwrite (EXECUTION_SUCCESS);
124
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
129
130   old_anm = array_needs_making;
131   pwdvar = get_string_value ("PWD");
132
133   tvar = bind_variable ("OLDPWD", pwdvar, 0);
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
140   setpwd (dirname);
141
142   if (dirname && dirname != the_current_working_directory)
143     free (dirname);
144
145   return (r);
146 }
147
148 /* Call get_working_directory to reset the value of
149    the_current_working_directory () */
150 static char *
151 resetpwd (caller)
152      char *caller;
153 {
154   char *tdir;
155       
156   FREE (the_current_working_directory);
157   the_current_working_directory = (char *)NULL;
158   tdir = get_working_directory (caller);
159   return (tdir);
160 }
161
162 #define LCD_DOVARS      0x001
163 #define LCD_DOSPELL     0x002
164 #define LCD_PRINTPATH   0x004
165 #define LCD_FREEDIRNAME 0x010
166
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. */
171 int
172 cd_builtin (list)
173      WORD_LIST *list;
174 {
175   char *dirname, *cdpath, *path, *temp;
176   int path_index, no_symlinks, opt, lflag;
177
178 #if defined (RESTRICTED_SHELL)
179   if (restricted)
180     {
181       sh_restricted ((char *)NULL);
182       return (EXECUTION_FAILURE);
183     }
184 #endif /* RESTRICTED_SHELL */
185
186   no_symlinks = no_symbolic_links;
187   reset_internal_getopt ();
188   while ((opt = internal_getopt (list, "LP")) != -1)
189     {
190       switch (opt)
191         {
192         case 'P':
193           no_symlinks = 1;
194           break;
195         case 'L':
196           no_symlinks = 0;
197           break;
198         default:
199           builtin_usage ();
200           return (EXECUTION_FAILURE);
201         }
202     }
203   list = loptend;
204
205   lflag = (cdable_vars ? LCD_DOVARS : 0) |
206           ((interactive && cdspelling) ? LCD_DOSPELL : 0);
207
208   if (list == 0)
209     {
210       /* `cd' without arguments is equivalent to `cd $HOME' */
211       dirname = get_string_value ("HOME");
212
213       if (dirname == 0)
214         {
215           builtin_error (_("HOME not set"));
216           return (EXECUTION_FAILURE);
217         }
218       lflag = 0;
219     }
220   else if (list->word->word[0] == '-' && list->word->word[1] == '\0')
221     {
222       /* This is `cd -', equivalent to `cd $OLDPWD' */
223       dirname = get_string_value ("OLDPWD");
224
225       if (dirname == 0)
226         {
227           builtin_error (_("OLDPWD not set"));
228           return (EXECUTION_FAILURE);
229         }
230 #if 0
231       lflag = interactive ? LCD_PRINTPATH : 0;
232 #else
233       lflag = LCD_PRINTPATH;            /* According to SUSv3 */
234 #endif
235     }
236   else if (absolute_pathname (list->word->word))
237     dirname = list->word->word;
238   else if (privileged_mode == 0 && (cdpath = get_string_value ("CDPATH")))
239     {
240       dirname = list->word->word;
241
242       /* Find directory in $CDPATH. */
243       path_index = 0;
244       while (path = extract_colon_unit (cdpath, &path_index))
245         {
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);
250
251           if (change_to_directory (temp, no_symlinks))
252             {
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. */
257               if (opt && (path = no_symlinks ? temp : the_current_working_directory))
258                 printf ("%s\n", path);
259
260               free (temp);
261 #if 0
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));
265 #else
266               return (bindpwd (no_symlinks));
267 #endif
268             }
269           else
270             free (temp);
271         }
272
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])
279         {
280           builtin_error ("%s: %s", dirname, strerror (ENOENT));
281           return (EXECUTION_FAILURE);
282         }
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     }
295
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))
303         {
304           printf ("%s\n", temp);
305           return (bindpwd (no_symlinks));
306         }
307     }
308
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     {
314       temp = dirspell (dirname);
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);
322     }
323
324   builtin_error ("%s: %s", dirname, strerror (errno));
325   return (EXECUTION_FAILURE);
326 }
327
328 $BUILTIN pwd
329 $FUNCTION pwd_builtin
330 $SHORT_DOC pwd [-LP]
331 Print the name of the current working directory.
332
333 Options:
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
338 By default, `pwd' behaves as if `-L' were specified.
339
340 Exit Status:
341 Returns 0 unless an invalid option is given or the current directory
342 cannot be read.
343 $END
344
345 /* Non-zero means that pwd always prints the physical directory, without
346    symbolic links. */
347 static int verbatim_pwd;
348
349 /* Print the name of the current working directory. */
350 int
351 pwd_builtin (list)
352      WORD_LIST *list;
353 {
354   char *directory;
355   int opt, pflag;
356
357   verbatim_pwd = no_symbolic_links;
358   pflag = 0;
359   reset_internal_getopt ();
360   while ((opt = internal_getopt (list, "LP")) != -1)
361     {
362       switch (opt)
363         {
364         case 'P':
365           verbatim_pwd = pflag = 1;
366           break;
367         case 'L':
368           verbatim_pwd = 0;
369           break;
370         default:
371           builtin_usage ();
372           return (EXECUTION_FAILURE);
373         }
374     }
375   list = loptend;
376
377 #define tcwd the_current_working_directory
378
379   directory = tcwd ? (verbatim_pwd ? sh_physpath (tcwd, 0) : tcwd)
380                    : get_working_directory ("pwd");
381
382   /* Try again using getcwd() if canonicalization fails (for instance, if
383      the file system has changed state underneath bash). */
384   if ((tcwd && directory == 0) ||
385       (posixly_correct && same_file (".", tcwd, (struct stat *)0, (struct stat *)0) == 0))
386     directory = resetpwd ("pwd");
387
388 #undef tcwd
389
390   if (directory)
391     {
392       printf ("%s\n", directory);
393       /* This is dumb but posix-mandated. */
394       if (posixly_correct && pflag)
395         setpwd (directory);
396       if (directory != the_current_working_directory)
397         free (directory);
398       return (sh_chkwrite (EXECUTION_SUCCESS));
399     }
400   else
401     return (EXECUTION_FAILURE);
402 }
403
404 /* Do the work of changing to the directory NEWDIR.  Handle symbolic
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. */
409
410 static int
411 change_to_directory (newdir, nolinks)
412      char *newdir;
413      int nolinks;
414 {
415   char *t, *tdir;
416   int err, canon_failed, r, ndlen, dlen;
417
418   tdir = (char *)NULL;
419
420   if (the_current_working_directory == 0)
421     {
422       t = get_working_directory ("chdir");
423       FREE (t);
424     }
425
426   t = make_absolute (newdir, the_current_working_directory);
427
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);
433
434   ndlen = strlen (newdir);
435   dlen = strlen (t);
436
437   /* Use the canonicalized version of NEWDIR, or, if canonicalization
438      failed, use the non-canonical form. */
439   canon_failed = 0;
440   if (tdir && *tdir)
441     free (t);
442   else
443     {
444       FREE (tdir);
445       tdir = t;
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. */
452   if (posixly_correct && nolinks == 0 && canon_failed && (errno != ENAMETOOLONG || ndlen > PATH_MAX))
453     {
454 #if defined ENAMETOOLONG
455       if (errno != ENOENT && errno != ENAMETOOLONG)
456 #else
457       if (errno != ENOENT)
458 #endif
459         errno = ENOTDIR;
460       free (tdir);
461       return (0);
462     }
463
464   /* If the chdir succeeds, update the_current_working_directory. */
465   if (chdir (nolinks ? newdir : tdir) == 0)
466     {
467       /* If canonicalization failed, but the chdir succeeded, reset the
468          shell's idea of the_current_working_directory. */
469       if (canon_failed)
470         {
471           t = resetpwd ("cd");
472           if (t == 0)
473             set_working_directory (tdir);
474         }
475       else
476         set_working_directory (tdir);
477
478       free (tdir);
479       return (1);
480     }
481
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)
485     {
486       free (tdir);
487       return (0);
488     }
489
490   err = errno;
491
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     {
497       t = resetpwd ("cd");
498       if (t == 0)
499         set_working_directory (tdir);
500       else
501         free (t);
502
503       r = 1;
504     }
505   else
506     {
507       errno = err;
508       r = 0;
509     }
510
511   free (tdir);
512   return r;
513 }