]> git.ipfire.org Git - thirdparty/bash.git/blobdiff - builtins/cd.def
Imported from ../bash-3.1.tar.gz.
[thirdparty/bash.git] / builtins / cd.def
index 2be86d11fd9006dc4d92c5bac67689f4ce9a6ac5..025e4f5e1f1209afe6700899aa7d89ec0ef128be 100644 (file)
@@ -1,7 +1,7 @@
 This file is cd.def, from which is created cd.c.  It implements the
 builtins "cd" and "pwd" in Bash.
 
-Copyright (C) 1987-2003 Free Software Foundation, Inc.
+Copyright (C) 1987-2005 Free Software Foundation, Inc.
 
 This file is part of GNU Bash, the Bourne Again SHell.
 
@@ -59,6 +59,7 @@ extern int array_needs_making;
 extern char *bash_getcwd_errstr;
 
 static int bindpwd __P((int));
+static void setpwd __P((char *));
 static int change_to_directory __P((char *, int));
 
 static char *cdspell __P((char *));
@@ -84,6 +85,23 @@ instead of following symbolic links; the -L option forces symbolic links
 to be followed.
 $END
 
+/* Just set $PWD, don't change OLDPWD.  Used by `pwd -P' in posix mode. */
+static void
+setpwd (dirname)
+     char *dirname;
+{
+  int old_anm;
+  SHELL_VAR *tvar;
+
+  old_anm = array_needs_making;
+  tvar = bind_variable ("PWD", dirname ? dirname : "", 0);
+  if (old_anm == 0 && array_needs_making && exported_p (tvar))
+    {
+      update_export_env_inplace ("PWD=", 4, dirname ? dirname : "");
+      array_needs_making = 0;
+    }
+}
+
 static int
 bindpwd (no_symlinks)
      int no_symlinks;
@@ -100,19 +118,14 @@ bindpwd (no_symlinks)
   old_anm = array_needs_making;
   pwdvar = get_string_value ("PWD");
 
-  tvar = bind_variable ("OLDPWD", pwdvar);
+  tvar = bind_variable ("OLDPWD", pwdvar, 0);
   if (old_anm == 0 && array_needs_making && exported_p (tvar))
     {
       update_export_env_inplace ("OLDPWD=", 7, pwdvar);
       array_needs_making = 0;
     }
 
-  tvar = bind_variable ("PWD", dirname ? dirname : "");
-  if (old_anm == 0 && array_needs_making && exported_p (tvar))
-    {
-      update_export_env_inplace ("PWD=", 4, dirname ? dirname : "");
-      array_needs_making = 0;
-    }
+  setpwd (dirname);
 
   if (dirname && dirname != the_current_working_directory)
     free (dirname);
@@ -233,9 +246,13 @@ cd_builtin (list)
                printf ("%s\n", path);
 
              free (temp);
+#if 0
              /* Posix.2 says that after using CDPATH, the resultant
                 value of $PWD will not contain `.' or `..'. */
              return (bindpwd (posixly_correct || no_symlinks));
+#else
+             return (bindpwd (no_symlinks));
+#endif
            }
          else
            free (temp);
@@ -298,7 +315,7 @@ cd_builtin (list)
 
 $BUILTIN pwd
 $FUNCTION pwd_builtin
-$SHORT_DOC pwd [-PL]
+$SHORT_DOC pwd [-LP]
 Print the current working directory.  With the -P option, pwd prints
 the physical directory, without any symbolic links; the -L option
 makes pwd follow symbolic links.
@@ -314,16 +331,17 @@ pwd_builtin (list)
      WORD_LIST *list;
 {
   char *directory;
-  int opt;
+  int opt, pflag;
 
   verbatim_pwd = no_symbolic_links;
+  pflag = 0;
   reset_internal_getopt ();
   while ((opt = internal_getopt (list, "LP")) != -1)
     {
       switch (opt)
        {
        case 'P':
-         verbatim_pwd = 1;
+         verbatim_pwd = pflag = 1;
          break;
        case 'L':
          verbatim_pwd = 0;
@@ -342,7 +360,8 @@ pwd_builtin (list)
 
   /* Try again using getcwd() if canonicalization fails (for instance, if
      the file system has changed state underneath bash). */
-  if (tcwd && directory == 0)
+  if ((tcwd && directory == 0) ||
+      (posixly_correct && same_file (".", tcwd, (struct stat *)0, (struct stat *)0) == 0))
     directory = resetpwd ("pwd");
 
 #undef tcwd
@@ -350,12 +369,15 @@ pwd_builtin (list)
   if (directory)
     {
       printf ("%s\n", directory);
+      /* This is dumb but posix-mandated. */
+      if (posixly_correct && pflag)
+       setpwd (directory);
       if (directory != the_current_working_directory)
        free (directory);
       fflush (stdout);
       if (ferror (stdout))
        {
-         builtin_error (_("write error: %s"), strerror (errno));
+         sh_wrerror ();
          clearerr (stdout);
          return (EXECUTION_FAILURE);
        }
@@ -378,7 +400,7 @@ change_to_directory (newdir, nolinks)
      int nolinks;
 {
   char *t, *tdir;
-  int err, canon_failed, r;
+  int err, canon_failed, r, ndlen, dlen;
 
   tdir = (char *)NULL;
 
@@ -396,6 +418,9 @@ change_to_directory (newdir, nolinks)
   tdir = nolinks ? sh_physpath (t, 0)
                 : sh_canonpath (t, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
 
+  ndlen = strlen (newdir);
+  dlen = strlen (t);
+
   /* Use the canonicalized version of NEWDIR, or, if canonicalization
      failed, use the non-canonical form. */
   canon_failed = 0;
@@ -411,7 +436,7 @@ change_to_directory (newdir, nolinks)
   /* In POSIX mode, if we're resolving symlinks logically and sh_canonpath
      returns NULL (because it checks the path, it will return NULL if the
      resolved path doesn't exist), fail immediately. */
-  if (posixly_correct && nolinks == 0 && canon_failed)
+  if (posixly_correct && nolinks == 0 && canon_failed && (errno != ENAMETOOLONG || ndlen > PATH_MAX))
     {
 #if defined ENAMETOOLONG
       if (errno != ENOENT && errno != ENAMETOOLONG)
@@ -419,6 +444,7 @@ change_to_directory (newdir, nolinks)
       if (errno != ENOENT)
 #endif
        errno = ENOTDIR;
+      free (tdir);
       return (0);
     }
 
@@ -436,13 +462,17 @@ change_to_directory (newdir, nolinks)
       else
        set_working_directory (tdir);
 
+      free (tdir);
       return (1);
     }
 
   /* We failed to change to the appropriate directory name.  If we tried
      what the user passed (nolinks != 0), punt now. */
   if (nolinks)
-    return (0);
+    {
+      free (tdir);
+      return (0);
+    }
 
   err = errno;