57306a57c54fd3ab61db5f2a4870f56f4c00709e
[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, 1989, 1991 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 it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
11 version.
12
13 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License along
19 with Bash; see the file COPYING.  If not, write to the Free Software
20 Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
21
22 $PRODUCES cd.c
23 #include <config.h>
24
25 #if defined (HAVE_UNISTD_H)
26 #  ifdef _MINIX
27 #    include <sys/types.h>
28 #  endif
29 #  include <unistd.h>
30 #endif
31
32 #include "../bashtypes.h"
33 #include "posixdir.h"
34 #include "posixstat.h"
35 #ifndef _MINIX
36 #include <sys/param.h>
37 #endif
38
39 #include <stdio.h>
40
41 #include "../bashansi.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, interactive;
57 extern int array_needs_making;
58 extern char *bash_getcwd_errstr;
59
60 static int change_to_directory ();
61
62 static char *cdspell ();
63
64 /* Change this to 1 to get cd spelling correction by default. */
65 int cdspelling = 0;
66
67 int cdable_vars;
68
69 $BUILTIN cd
70 $FUNCTION cd_builtin
71 $SHORT_DOC cd [-PL] [dir]
72 Change the current directory to DIR.  The variable $HOME is the
73 default DIR.  The variable CDPATH defines the search path for
74 the directory containing DIR.  Alternative directory names in CDPATH
75 are separated by a colon (:).  A null directory name is the same as
76 the current directory, i.e. `.'.  If DIR begins with a slash (/),
77 then CDPATH is not used.  If the directory is not found, and the
78 shell option `cdable_vars' is set, then try the word as a variable
79 name.  If that variable has a value, then cd to the value of that
80 variable.  The -P option says to use the physical directory structure
81 instead of following symbolic links; the -L option forces symbolic links
82 to be followed.
83 $END
84
85 static int
86 bindpwd (no_symlinks)
87      int no_symlinks;
88 {
89   char *dirname, *pwdvar;
90   int old_symlinks, old_anm;
91   SHELL_VAR *tvar;
92
93 #define tcwd the_current_working_directory
94   dirname = tcwd ? (no_symlinks ? sh_physpath (tcwd, 0) : tcwd)
95                  : get_working_directory ("cd");
96 #undef tcwd
97
98   old_anm = array_needs_making;
99   pwdvar = get_string_value ("PWD");
100
101   tvar = bind_variable ("OLDPWD", pwdvar);
102   if (old_anm == 0 && array_needs_making && exported_p (tvar))
103     {
104       update_export_env_inplace ("OLDPWD=", 7, pwdvar);
105       array_needs_making = 0;
106     }
107
108   tvar = bind_variable ("PWD", dirname);
109   if (old_anm == 0 && array_needs_making && exported_p (tvar))
110     {
111       update_export_env_inplace ("PWD=", 4, dirname);
112       array_needs_making = 0;
113     }
114
115   if (dirname && dirname != the_current_working_directory)
116     free (dirname);
117   return (EXECUTION_SUCCESS);
118 }
119
120 #define LCD_DOVARS      0x001
121 #define LCD_DOSPELL     0x002
122 #define LCD_PRINTPATH   0x004
123 #define LCD_FREEDIRNAME 0x010
124
125 /* This builtin is ultimately the way that all user-visible commands should
126    change the current working directory.  It is called by cd_to_string (),
127    so the programming interface is simple, and it handles errors and
128    restrictions properly. */
129 int
130 cd_builtin (list)
131      WORD_LIST *list;
132 {
133   char *dirname, *cdpath, *path, *temp;
134   int path_index, no_symlinks, opt, lflag;
135
136 #if defined (RESTRICTED_SHELL)
137   if (restricted)
138     {
139       builtin_error ("restricted");
140       return (EXECUTION_FAILURE);
141     }
142 #endif /* RESTRICTED_SHELL */
143
144   no_symlinks = no_symbolic_links;
145   reset_internal_getopt ();
146   while ((opt = internal_getopt (list, "LP")) != -1)
147     {
148       switch (opt)
149         {
150         case 'P':
151           no_symlinks = 1;
152           break;
153         case 'L':
154           no_symlinks = 0;
155           break;
156         default:
157           builtin_usage ();
158           return (EXECUTION_FAILURE);
159         }
160     }
161   list = loptend;
162
163   lflag = (cdable_vars ? LCD_DOVARS : 0) |
164           ((interactive && cdspelling) ? LCD_DOSPELL : 0);
165
166   if (list == 0)
167     {
168       /* `cd' without arguments is equivalent to `cd $HOME' */
169       dirname = get_string_value ("HOME");
170
171       if (dirname == 0)
172         {
173           builtin_error ("HOME not set");
174           return (EXECUTION_FAILURE);
175         }
176       lflag = 0;
177     }
178   else if (list->word->word[0] == '-' && list->word->word[1] == '\0')
179     {
180       /* This is `cd -', equivalent to `cd $OLDPWD' */
181       dirname = get_string_value ("OLDPWD");
182
183       if (dirname == 0)
184         {
185           builtin_error ("OLDPWD not set");
186           return (EXECUTION_FAILURE);
187         }
188       lflag = interactive ? LCD_PRINTPATH : 0;
189     }
190   else if (absolute_pathname (list->word->word))
191     dirname = list->word->word;
192   else if (cdpath = get_string_value ("CDPATH"))
193     {
194       dirname = list->word->word;
195
196       /* Find directory in $CDPATH. */
197       path_index = 0;
198       while (path = extract_colon_unit (cdpath, &path_index))
199         {
200           /* OPT is 1 if the path element is non-empty */
201           opt = path[0] != '\0';
202           temp = sh_makepath (path, dirname, MP_DOTILDE);
203           free (path);
204
205           if (change_to_directory (temp, no_symlinks))
206             {
207               /* POSIX.2 says that if a nonempty directory from CDPATH
208                  is used to find the directory to change to, the new
209                  directory name is echoed to stdout, whether or not
210                  the shell is interactive. */
211               if (opt)
212                 printf ("%s\n", no_symlinks ? temp : the_current_working_directory);
213
214               free (temp);
215               /* Posix.2 says that after using CDPATH, the resultant
216                  value of $PWD will not contain `.' or `..'. */
217               return (bindpwd (posixly_correct || no_symlinks));
218             }
219           else
220             free (temp);
221         }
222
223       /* POSIX.2 says that if `.' does not appear in $CDPATH, we don't
224          try the current directory, so we just punt now with an error
225          message if POSIXLY_CORRECT is non-zero.  The check for cdpath[0]
226          is so we don't mistakenly treat a CDPATH value of "" as not
227          specifying the current directory. */
228       if (posixly_correct && cdpath[0])
229         {
230           builtin_error ("%s: %s", dirname, strerror (ENOENT));
231           return (EXECUTION_FAILURE);
232         }
233     }
234   else
235     dirname = list->word->word;
236
237   /* When we get here, DIRNAME is the directory to change to.  If we
238      chdir successfully, just return. */
239   if (change_to_directory (dirname, no_symlinks))
240     {
241       if (lflag & LCD_PRINTPATH)
242         printf ("%s\n", dirname);
243       return (bindpwd (no_symlinks));
244     }
245
246   /* If the user requests it, then perhaps this is the name of
247      a shell variable, whose value contains the directory to
248      change to. */
249   if (lflag & LCD_DOVARS)
250     {
251       temp = get_string_value (dirname);
252       if (temp && change_to_directory (temp, no_symlinks))
253         {
254           printf ("%s\n", temp);
255           return (bindpwd (no_symlinks));
256         }
257     }
258
259   /* If the user requests it, try to find a directory name similar in
260      spelling to the one requested, in case the user made a simple
261      typo.  This is similar to the UNIX 8th and 9th Edition shells. */
262   if (lflag & LCD_DOSPELL)
263     {
264       temp = cdspell (dirname);
265       if (temp && change_to_directory (temp, no_symlinks))
266         {
267           printf ("%s\n", temp);
268           return (bindpwd (no_symlinks));
269         }
270       else
271         FREE (temp);
272     }
273
274   builtin_error ("%s: %s", dirname, strerror (errno));
275   return (EXECUTION_FAILURE);
276 }
277
278 $BUILTIN pwd
279 $FUNCTION pwd_builtin
280 $SHORT_DOC pwd [-PL]
281 Print the current working directory.  With the -P option, pwd prints
282 the physical directory, without any symbolic links; the -L option
283 makes pwd follow symbolic links.
284 $END
285
286 /* Non-zero means that pwd always prints the physical directory, without
287    symbolic links. */
288 static int verbatim_pwd;
289
290 /* Print the name of the current working directory. */
291 int
292 pwd_builtin (list)
293      WORD_LIST *list;
294 {
295   char *directory;
296   int opt;
297
298   verbatim_pwd = no_symbolic_links;
299   reset_internal_getopt ();
300   while ((opt = internal_getopt (list, "LP")) != -1)
301     {
302       switch (opt)
303         {
304         case 'P':
305           verbatim_pwd = 1;
306           break;
307         case 'L':
308           verbatim_pwd = 0;
309           break;
310         default:
311           builtin_usage ();
312           return (EXECUTION_FAILURE);
313         }
314     }
315   list = loptend;
316
317 #define tcwd the_current_working_directory
318
319   directory = tcwd ? (verbatim_pwd ? sh_physpath (tcwd, 0) : tcwd)
320                    : get_working_directory ("pwd");
321 #undef tcwd
322
323   if (directory)
324     {
325       printf ("%s\n", directory);
326       if (directory != the_current_working_directory)
327         free (directory);
328       fflush (stdout);
329       if (ferror (stdout))
330         {
331           builtin_error ("write error: %s", strerror (errno));
332           return (EXECUTION_FAILURE);
333         }
334       return (EXECUTION_SUCCESS);
335     }
336   else
337     return (EXECUTION_FAILURE);
338 }
339
340 /* Do the work of changing to the directory NEWDIR.  Handle symbolic
341    link following, etc.  This function *must* return with
342    the_current_working_directory either set to NULL (in which case
343    getcwd() will eventually be called), or set to a string corresponding
344    to the working directory.  Return 1 on success, 0 on failure. */
345
346 static int
347 change_to_directory (newdir, nolinks)
348      char *newdir;
349      int nolinks;
350 {
351   char *t, *tdir;
352   int err;
353
354   tdir = (char *)NULL;
355
356   if (the_current_working_directory == 0)
357     {
358       t = get_working_directory ("chdir");
359       FREE (t);
360     }
361
362   t = make_absolute (newdir, the_current_working_directory);
363
364   /* TDIR is either the canonicalized absolute pathname of NEWDIR
365      (nolinks == 0) or the absolute physical pathname of NEWDIR
366      (nolinks != 0). */
367   tdir = nolinks ? sh_physpath (t, 0)
368                  : sh_canonpath (t, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
369
370   /* Use the canonicalized version of NEWDIR, or, if canonicalization
371      failed, use the non-canonical form. */
372   if (tdir && *tdir)
373     free (t);
374   else
375     {
376       FREE (tdir);
377       tdir = t;
378     }
379
380   /* If the chdir succeeds, update the_current_working_directory. */
381   if (chdir (nolinks ? newdir : tdir) == 0)
382     {
383       FREE (the_current_working_directory);
384       the_current_working_directory = tdir;
385       
386       return (1);
387     }
388
389   /* We failed to change to the appropriate directory name.  If we tried
390      what the user passed (nolinks != 0), punt now. */
391   if (nolinks)
392     return (0);
393
394   err = errno;
395   free (tdir);
396
397   /* We're not in physical mode (nolinks == 0), but we failed to change to
398      the canonicalized directory name (TDIR).  Try what the user passed
399      verbatim. If we succeed, reinitialize the_current_working_directory. */
400   if (chdir (newdir) == 0)
401     {
402       FREE (the_current_working_directory);
403       the_current_working_directory = (char *)NULL;
404       tdir = get_working_directory ("cd");
405       FREE (tdir);
406
407       return (1);
408     }
409   else
410     {
411       errno = err;
412       return (0);
413     }
414 }
415
416 /* Code for cd spelling correction.  Original patch submitted by
417    Neil Russel (caret@c-side.com). */
418
419 static char *
420 cdspell (dirname)
421      char *dirname;
422 {
423   int n;
424   char *guess;
425
426   n = (strlen (dirname) * 3 + 1) / 2 + 1;
427   guess = xmalloc (n);
428
429   switch (spname (dirname, guess))
430     {
431     case -1:
432     default:
433       free (guess);
434       return (char *)NULL;
435     case 0:
436     case 1:
437       return guess;
438     }
439 }