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