LCOV - code coverage report
Current view: top level - builtins - cd.def (source / functions) Hit Total Coverage
Test: cov-sh.info Lines: 56 191 29.3 %
Date: 2020-10-29 14:49:55 Functions: 3 6 50.0 %

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

Generated by: LCOV version 1.14.0.6.4058