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.
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 *));
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;
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);
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);
$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.
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;
/* 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
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);
}
int nolinks;
{
char *t, *tdir;
- int err, canon_failed, r;
+ int err, canon_failed, r, ndlen, dlen;
tdir = (char *)NULL;
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;
/* 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)
if (errno != ENOENT)
#endif
errno = ENOTDIR;
+ free (tdir);
return (0);
}
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;