]>
Commit | Line | Data |
---|---|---|
726f6388 | 1 | This file is cd.def, from which is created cd.c. It implements the |
ccc6cda3 | 2 | builtins "cd" and "pwd" in Bash. |
726f6388 | 3 | |
495aee44 | 4 | Copyright (C) 1987-2010 Free Software Foundation, Inc. |
726f6388 JA |
5 | |
6 | This file is part of GNU Bash, the Bourne Again SHell. | |
7 | ||
3185942a JA |
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. | |
726f6388 | 12 | |
3185942a JA |
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. | |
726f6388 | 17 | |
3185942a JA |
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/>. | |
726f6388 JA |
20 | |
21 | $PRODUCES cd.c | |
ccc6cda3 | 22 | #include <config.h> |
726f6388 | 23 | |
ccc6cda3 | 24 | #if defined (HAVE_UNISTD_H) |
cce855bc JA |
25 | # ifdef _MINIX |
26 | # include <sys/types.h> | |
27 | # endif | |
ccc6cda3 JA |
28 | # include <unistd.h> |
29 | #endif | |
30 | ||
31 | #include "../bashtypes.h" | |
bb70624e JA |
32 | #include "posixdir.h" |
33 | #include "posixstat.h" | |
cce855bc | 34 | #ifndef _MINIX |
726f6388 | 35 | #include <sys/param.h> |
cce855bc | 36 | #endif |
726f6388 | 37 | |
ccc6cda3 JA |
38 | #include <stdio.h> |
39 | ||
40 | #include "../bashansi.h" | |
b80f6443 | 41 | #include "../bashintl.h" |
726f6388 JA |
42 | |
43 | #include <errno.h> | |
44 | #include <tilde/tilde.h> | |
45 | ||
46 | #include "../shell.h" | |
47 | #include "../flags.h" | |
bb70624e | 48 | #include "maxpath.h" |
726f6388 | 49 | #include "common.h" |
ccc6cda3 | 50 | #include "bashgetopt.h" |
726f6388 JA |
51 | |
52 | #if !defined (errno) | |
53 | extern int errno; | |
54 | #endif /* !errno */ | |
55 | ||
f73dda09 | 56 | extern int posixly_correct; |
d166f048 | 57 | extern int array_needs_making; |
3185942a | 58 | extern const char * const bash_getcwd_errstr; |
ccc6cda3 | 59 | |
f73dda09 | 60 | static int bindpwd __P((int)); |
495aee44 | 61 | static int setpwd __P((char *)); |
0628567a | 62 | static char *resetpwd __P((char *)); |
f73dda09 | 63 | static int change_to_directory __P((char *, int)); |
ccc6cda3 | 64 | |
d166f048 JA |
65 | /* Change this to 1 to get cd spelling correction by default. */ |
66 | int cdspelling = 0; | |
ccc6cda3 JA |
67 | |
68 | int cdable_vars; | |
726f6388 | 69 | |
495aee44 CR |
70 | static int eflag; /* file scope so bindpwd() can see it */ |
71 | ||
726f6388 JA |
72 | $BUILTIN cd |
73 | $FUNCTION cd_builtin | |
495aee44 | 74 | $SHORT_DOC cd [-L|[-P [-e]]] [dir] |
3185942a JA |
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 | |
495aee44 CR |
93 | -e if the -P option is supplied, and the current working directory |
94 | cannot be determined successfully, exit with a non-zero status | |
3185942a JA |
95 | |
96 | The default is to follow symbolic links, as if `-L' were specified. | |
97 | ||
98 | Exit Status: | |
495aee44 CR |
99 | Returns 0 if the directory is changed, and if $PWD is set successfully when |
100 | -P is used; non-zero otherwise. | |
726f6388 JA |
101 | $END |
102 | ||
95732b49 | 103 | /* Just set $PWD, don't change OLDPWD. Used by `pwd -P' in posix mode. */ |
495aee44 | 104 | static int |
95732b49 JA |
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); | |
495aee44 CR |
113 | if (tvar && readonly_p (tvar)) |
114 | return EXECUTION_FAILURE; | |
115 | if (tvar && old_anm == 0 && array_needs_making && exported_p (tvar)) | |
95732b49 JA |
116 | { |
117 | update_export_env_inplace ("PWD=", 4, dirname ? dirname : ""); | |
118 | array_needs_making = 0; | |
119 | } | |
495aee44 | 120 | return EXECUTION_SUCCESS; |
95732b49 JA |
121 | } |
122 | ||
ccc6cda3 JA |
123 | static int |
124 | bindpwd (no_symlinks) | |
125 | int no_symlinks; | |
126 | { | |
d166f048 | 127 | char *dirname, *pwdvar; |
3185942a | 128 | int old_anm, r; |
d166f048 | 129 | SHELL_VAR *tvar; |
ccc6cda3 | 130 | |
3185942a JA |
131 | r = sh_chkwrite (EXECUTION_SUCCESS); |
132 | ||
28ef6c31 JA |
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 | |
ccc6cda3 | 137 | |
d166f048 | 138 | old_anm = array_needs_making; |
b72432fd JA |
139 | pwdvar = get_string_value ("PWD"); |
140 | ||
95732b49 | 141 | tvar = bind_variable ("OLDPWD", pwdvar, 0); |
495aee44 CR |
142 | if (tvar && readonly_p (tvar)) |
143 | r = EXECUTION_FAILURE; | |
144 | ||
b72432fd JA |
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 | ||
495aee44 CR |
151 | if (setpwd (dirname) == EXECUTION_FAILURE) |
152 | r = EXECUTION_FAILURE; | |
153 | if (dirname == 0 && eflag) | |
154 | r = EXECUTION_FAILURE; | |
ccc6cda3 | 155 | |
28ef6c31 JA |
156 | if (dirname && dirname != the_current_working_directory) |
157 | free (dirname); | |
b80f6443 | 158 | |
3185942a | 159 | return (r); |
ccc6cda3 JA |
160 | } |
161 | ||
7117c2d2 JA |
162 | /* Call get_working_directory to reset the value of |
163 | the_current_working_directory () */ | |
164 | static char * | |
b80f6443 JA |
165 | resetpwd (caller) |
166 | char *caller; | |
7117c2d2 JA |
167 | { |
168 | char *tdir; | |
169 | ||
170 | FREE (the_current_working_directory); | |
171 | the_current_working_directory = (char *)NULL; | |
b80f6443 | 172 | tdir = get_working_directory (caller); |
7117c2d2 JA |
173 | return (tdir); |
174 | } | |
175 | ||
28ef6c31 JA |
176 | #define LCD_DOVARS 0x001 |
177 | #define LCD_DOSPELL 0x002 | |
178 | #define LCD_PRINTPATH 0x004 | |
495aee44 | 179 | #define LCD_FREEDIRNAME 0x008 |
28ef6c31 | 180 | |
726f6388 JA |
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 | { | |
ccc6cda3 | 189 | char *dirname, *cdpath, *path, *temp; |
28ef6c31 | 190 | int path_index, no_symlinks, opt, lflag; |
726f6388 JA |
191 | |
192 | #if defined (RESTRICTED_SHELL) | |
193 | if (restricted) | |
194 | { | |
7117c2d2 | 195 | sh_restricted ((char *)NULL); |
726f6388 JA |
196 | return (EXECUTION_FAILURE); |
197 | } | |
198 | #endif /* RESTRICTED_SHELL */ | |
199 | ||
495aee44 | 200 | eflag = 0; |
ccc6cda3 JA |
201 | no_symlinks = no_symbolic_links; |
202 | reset_internal_getopt (); | |
203 | while ((opt = internal_getopt (list, "LP")) != -1) | |
726f6388 | 204 | { |
ccc6cda3 | 205 | switch (opt) |
726f6388 | 206 | { |
ccc6cda3 JA |
207 | case 'P': |
208 | no_symlinks = 1; | |
209 | break; | |
210 | case 'L': | |
211 | no_symlinks = 0; | |
212 | break; | |
495aee44 CR |
213 | case 'e': |
214 | eflag = 1; | |
215 | break; | |
ccc6cda3 JA |
216 | default: |
217 | builtin_usage (); | |
726f6388 JA |
218 | return (EXECUTION_FAILURE); |
219 | } | |
726f6388 | 220 | } |
ccc6cda3 JA |
221 | list = loptend; |
222 | ||
28ef6c31 JA |
223 | lflag = (cdable_vars ? LCD_DOVARS : 0) | |
224 | ((interactive && cdspelling) ? LCD_DOSPELL : 0); | |
495aee44 CR |
225 | if (eflag && no_symlinks == 0) |
226 | eflag = 0; | |
28ef6c31 | 227 | |
ccc6cda3 | 228 | if (list == 0) |
726f6388 | 229 | { |
ccc6cda3 | 230 | /* `cd' without arguments is equivalent to `cd $HOME' */ |
726f6388 JA |
231 | dirname = get_string_value ("HOME"); |
232 | ||
ccc6cda3 | 233 | if (dirname == 0) |
726f6388 | 234 | { |
b80f6443 | 235 | builtin_error (_("HOME not set")); |
726f6388 JA |
236 | return (EXECUTION_FAILURE); |
237 | } | |
28ef6c31 | 238 | lflag = 0; |
726f6388 | 239 | } |
ccc6cda3 | 240 | else if (list->word->word[0] == '-' && list->word->word[1] == '\0') |
726f6388 | 241 | { |
ccc6cda3 JA |
242 | /* This is `cd -', equivalent to `cd $OLDPWD' */ |
243 | dirname = get_string_value ("OLDPWD"); | |
726f6388 | 244 | |
28ef6c31 | 245 | if (dirname == 0) |
726f6388 | 246 | { |
b80f6443 | 247 | builtin_error (_("OLDPWD not set")); |
726f6388 JA |
248 | return (EXECUTION_FAILURE); |
249 | } | |
b80f6443 | 250 | #if 0 |
28ef6c31 | 251 | lflag = interactive ? LCD_PRINTPATH : 0; |
b80f6443 JA |
252 | #else |
253 | lflag = LCD_PRINTPATH; /* According to SUSv3 */ | |
254 | #endif | |
726f6388 | 255 | } |
28ef6c31 JA |
256 | else if (absolute_pathname (list->word->word)) |
257 | dirname = list->word->word; | |
3185942a | 258 | else if (privileged_mode == 0 && (cdpath = get_string_value ("CDPATH"))) |
726f6388 | 259 | { |
ccc6cda3 JA |
260 | dirname = list->word->word; |
261 | ||
28ef6c31 JA |
262 | /* Find directory in $CDPATH. */ |
263 | path_index = 0; | |
264 | while (path = extract_colon_unit (cdpath, &path_index)) | |
726f6388 | 265 | { |
28ef6c31 JA |
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); | |
cce855bc | 270 | |
28ef6c31 | 271 | if (change_to_directory (temp, no_symlinks)) |
cce855bc | 272 | { |
28ef6c31 JA |
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. */ | |
b80f6443 JA |
277 | if (opt && (path = no_symlinks ? temp : the_current_working_directory)) |
278 | printf ("%s\n", path); | |
28ef6c31 JA |
279 | |
280 | free (temp); | |
95732b49 | 281 | #if 0 |
28ef6c31 JA |
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)); | |
95732b49 JA |
285 | #else |
286 | return (bindpwd (no_symlinks)); | |
287 | #endif | |
cce855bc | 288 | } |
28ef6c31 JA |
289 | else |
290 | free (temp); | |
726f6388 JA |
291 | } |
292 | ||
495aee44 | 293 | #if 0 /* changed for bash-4.2 Posix cd description steps 5-6 */ |
28ef6c31 JA |
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]) | |
726f6388 | 300 | { |
28ef6c31 JA |
301 | builtin_error ("%s: %s", dirname, strerror (ENOENT)); |
302 | return (EXECUTION_FAILURE); | |
726f6388 | 303 | } |
495aee44 | 304 | #endif |
28ef6c31 JA |
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 | } | |
726f6388 | 317 | |
28ef6c31 JA |
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)) | |
726f6388 | 325 | { |
28ef6c31 JA |
326 | printf ("%s\n", temp); |
327 | return (bindpwd (no_symlinks)); | |
726f6388 | 328 | } |
28ef6c31 | 329 | } |
726f6388 | 330 | |
28ef6c31 JA |
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 | { | |
3185942a | 336 | temp = dirspell (dirname); |
28ef6c31 JA |
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); | |
726f6388 JA |
344 | } |
345 | ||
28ef6c31 JA |
346 | builtin_error ("%s: %s", dirname, strerror (errno)); |
347 | return (EXECUTION_FAILURE); | |
726f6388 | 348 | } |
726f6388 | 349 | |
ccc6cda3 JA |
350 | $BUILTIN pwd |
351 | $FUNCTION pwd_builtin | |
95732b49 | 352 | $SHORT_DOC pwd [-LP] |
3185942a JA |
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. | |
726f6388 JA |
365 | $END |
366 | ||
ccc6cda3 JA |
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) | |
726f6388 JA |
374 | WORD_LIST *list; |
375 | { | |
28ef6c31 | 376 | char *directory; |
95732b49 | 377 | int opt, pflag; |
726f6388 | 378 | |
ccc6cda3 | 379 | verbatim_pwd = no_symbolic_links; |
95732b49 | 380 | pflag = 0; |
ccc6cda3 JA |
381 | reset_internal_getopt (); |
382 | while ((opt = internal_getopt (list, "LP")) != -1) | |
726f6388 | 383 | { |
ccc6cda3 | 384 | switch (opt) |
726f6388 | 385 | { |
ccc6cda3 | 386 | case 'P': |
95732b49 | 387 | verbatim_pwd = pflag = 1; |
ccc6cda3 JA |
388 | break; |
389 | case 'L': | |
390 | verbatim_pwd = 0; | |
391 | break; | |
392 | default: | |
393 | builtin_usage (); | |
726f6388 JA |
394 | return (EXECUTION_FAILURE); |
395 | } | |
396 | } | |
ccc6cda3 | 397 | list = loptend; |
726f6388 | 398 | |
28ef6c31 | 399 | #define tcwd the_current_working_directory |
726f6388 | 400 | |
28ef6c31 JA |
401 | directory = tcwd ? (verbatim_pwd ? sh_physpath (tcwd, 0) : tcwd) |
402 | : get_working_directory ("pwd"); | |
b80f6443 JA |
403 | |
404 | /* Try again using getcwd() if canonicalization fails (for instance, if | |
405 | the file system has changed state underneath bash). */ | |
95732b49 JA |
406 | if ((tcwd && directory == 0) || |
407 | (posixly_correct && same_file (".", tcwd, (struct stat *)0, (struct stat *)0) == 0)) | |
b80f6443 JA |
408 | directory = resetpwd ("pwd"); |
409 | ||
28ef6c31 | 410 | #undef tcwd |
726f6388 | 411 | |
ccc6cda3 JA |
412 | if (directory) |
413 | { | |
495aee44 | 414 | opt = EXECUTION_SUCCESS; |
ccc6cda3 | 415 | printf ("%s\n", directory); |
95732b49 JA |
416 | /* This is dumb but posix-mandated. */ |
417 | if (posixly_correct && pflag) | |
495aee44 | 418 | opt = setpwd (directory); |
28ef6c31 JA |
419 | if (directory != the_current_working_directory) |
420 | free (directory); | |
495aee44 | 421 | return (sh_chkwrite (opt)); |
726f6388 | 422 | } |
ccc6cda3 JA |
423 | else |
424 | return (EXECUTION_FAILURE); | |
726f6388 | 425 | } |
726f6388 JA |
426 | |
427 | /* Do the work of changing to the directory NEWDIR. Handle symbolic | |
28ef6c31 JA |
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. */ | |
726f6388 JA |
432 | |
433 | static int | |
ccc6cda3 | 434 | change_to_directory (newdir, nolinks) |
726f6388 | 435 | char *newdir; |
ccc6cda3 | 436 | int nolinks; |
726f6388 | 437 | { |
28ef6c31 | 438 | char *t, *tdir; |
95732b49 | 439 | int err, canon_failed, r, ndlen, dlen; |
726f6388 | 440 | |
28ef6c31 | 441 | tdir = (char *)NULL; |
726f6388 | 442 | |
28ef6c31 JA |
443 | if (the_current_working_directory == 0) |
444 | { | |
445 | t = get_working_directory ("chdir"); | |
446 | FREE (t); | |
447 | } | |
726f6388 | 448 | |
28ef6c31 | 449 | t = make_absolute (newdir, the_current_working_directory); |
726f6388 | 450 | |
28ef6c31 JA |
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); | |
726f6388 | 456 | |
95732b49 JA |
457 | ndlen = strlen (newdir); |
458 | dlen = strlen (t); | |
459 | ||
28ef6c31 JA |
460 | /* Use the canonicalized version of NEWDIR, or, if canonicalization |
461 | failed, use the non-canonical form. */ | |
7117c2d2 | 462 | canon_failed = 0; |
28ef6c31 JA |
463 | if (tdir && *tdir) |
464 | free (t); | |
465 | else | |
466 | { | |
467 | FREE (tdir); | |
468 | tdir = t; | |
7117c2d2 JA |
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. */ | |
95732b49 | 475 | if (posixly_correct && nolinks == 0 && canon_failed && (errno != ENAMETOOLONG || ndlen > PATH_MAX)) |
7117c2d2 | 476 | { |
b80f6443 JA |
477 | #if defined ENAMETOOLONG |
478 | if (errno != ENOENT && errno != ENAMETOOLONG) | |
479 | #else | |
480 | if (errno != ENOENT) | |
481 | #endif | |
482 | errno = ENOTDIR; | |
95732b49 | 483 | free (tdir); |
7117c2d2 | 484 | return (0); |
28ef6c31 | 485 | } |
726f6388 | 486 | |
28ef6c31 JA |
487 | /* If the chdir succeeds, update the_current_working_directory. */ |
488 | if (chdir (nolinks ? newdir : tdir) == 0) | |
489 | { | |
7117c2d2 JA |
490 | /* If canonicalization failed, but the chdir succeeded, reset the |
491 | shell's idea of the_current_working_directory. */ | |
492 | if (canon_failed) | |
7117c2d2 | 493 | { |
b80f6443 JA |
494 | t = resetpwd ("cd"); |
495 | if (t == 0) | |
496 | set_working_directory (tdir); | |
7117c2d2 | 497 | } |
b80f6443 JA |
498 | else |
499 | set_working_directory (tdir); | |
7117c2d2 | 500 | |
95732b49 | 501 | free (tdir); |
28ef6c31 JA |
502 | return (1); |
503 | } | |
726f6388 | 504 | |
28ef6c31 JA |
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) | |
95732b49 JA |
508 | { |
509 | free (tdir); | |
510 | return (0); | |
511 | } | |
726f6388 | 512 | |
28ef6c31 | 513 | err = errno; |
726f6388 | 514 | |
28ef6c31 JA |
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 | { | |
b80f6443 JA |
520 | t = resetpwd ("cd"); |
521 | if (t == 0) | |
522 | set_working_directory (tdir); | |
523 | else | |
524 | free (t); | |
726f6388 | 525 | |
b80f6443 | 526 | r = 1; |
726f6388 JA |
527 | } |
528 | else | |
28ef6c31 JA |
529 | { |
530 | errno = err; | |
b80f6443 | 531 | r = 0; |
28ef6c31 | 532 | } |
b80f6443 JA |
533 | |
534 | free (tdir); | |
535 | return r; | |
ccc6cda3 | 536 | } |