summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjilles <jilles@FreeBSD.org>2010-04-17 14:35:46 +0000
committerjilles <jilles@FreeBSD.org>2010-04-17 14:35:46 +0000
commit286029c47836178eb034bb3cff6b884f0a4ed74d (patch)
treebb356bbe40acadf8907130038ede6c0a505c1777
parent66c04c10a0daa86550d2714dec2c47bd88f184b3 (diff)
downloadFreeBSD-src-286029c47836178eb034bb3cff6b884f0a4ed74d.zip
FreeBSD-src-286029c47836178eb034bb3cff6b884f0a4ed74d.tar.gz
sh: On startup of the shell, use PWD from the environment if it is valid.
Unset PWD if it is incorrect and no value for it can be determined. This preserves the logical current directory across shell invocations. Example (assuming /home is a symlink): $ cd $ pwd /home/foo $ sh $ pwd /home/foo Formerly the second pwd would show the physical path (symlinks resolved).
-rw-r--r--bin/sh/cd.c27
-rw-r--r--bin/sh/cd.h2
-rw-r--r--bin/sh/main.c5
-rw-r--r--tools/regression/bin/sh/parameters/pwd2.024
4 files changed, 48 insertions, 10 deletions
diff --git a/bin/sh/cd.c b/bin/sh/cd.c
index 40801ba..aee06e8 100644
--- a/bin/sh/cd.c
+++ b/bin/sh/cd.c
@@ -70,6 +70,7 @@ STATIC int docd(char *, int, int);
STATIC char *getcomponent(void);
STATIC char *findcwd(char *);
STATIC void updatepwd(char *);
+STATIC char *getpwd(void);
STATIC char *getpwd2(void);
STATIC char *curdir = NULL; /* current working directory */
@@ -351,7 +352,7 @@ pwdcmd(int argc, char **argv)
/*
* Get the current directory and cache the result in curdir.
*/
-char *
+STATIC char *
getpwd(void)
{
char *p;
@@ -374,7 +375,6 @@ getpwd(void)
STATIC char *
getpwd2(void)
{
- struct stat stdot, stpwd;
char *pwd;
int i;
@@ -387,12 +387,29 @@ getpwd2(void)
break;
}
- pwd = getenv("PWD");
+ return NULL;
+}
+
+/*
+ * Initialize PWD in a new shell.
+ * If the shell is interactive, we need to warn if this fails.
+ */
+void
+pwd_init(int warn)
+{
+ char *pwd;
+ struct stat stdot, stpwd;
+
+ pwd = lookupvar("PWD");
if (pwd && *pwd == '/' && stat(".", &stdot) != -1 &&
stat(pwd, &stpwd) != -1 &&
stdot.st_dev == stpwd.st_dev &&
stdot.st_ino == stpwd.st_ino) {
- return pwd;
+ if (curdir)
+ ckfree(curdir);
+ curdir = savestr(pwd);
}
- return NULL;
+ if (getpwd() == NULL && warn)
+ out2fmt_flush("sh: cannot determine working directory\n");
+ setvar("PWD", curdir, VEXPORT);
}
diff --git a/bin/sh/cd.h b/bin/sh/cd.h
index 0a2d489..f88ce26 100644
--- a/bin/sh/cd.h
+++ b/bin/sh/cd.h
@@ -29,6 +29,6 @@
* $FreeBSD$
*/
-char *getpwd(void);
+void pwd_init(int);
int cdcmd (int, char **);
int pwdcmd(int, char **);
diff --git a/bin/sh/main.c b/bin/sh/main.c
index 50a8813..ecbb12d 100644
--- a/bin/sh/main.c
+++ b/bin/sh/main.c
@@ -153,10 +153,7 @@ main(int argc, char *argv[])
init();
setstackmark(&smark);
procargs(argc, argv);
- if (getpwd() == NULL && iflag)
- out2fmt_flush("sh: cannot determine working directory\n");
- if (getpwd() != NULL)
- setvar ("PWD", getpwd(), VEXPORT);
+ pwd_init(iflag);
if (iflag)
chkmail(1);
if (argv[0] && argv[0][0] == '-') {
diff --git a/tools/regression/bin/sh/parameters/pwd2.0 b/tools/regression/bin/sh/parameters/pwd2.0
new file mode 100644
index 0000000..29b5531
--- /dev/null
+++ b/tools/regression/bin/sh/parameters/pwd2.0
@@ -0,0 +1,24 @@
+# $FreeBSD$
+# Check that PWD is exported and accepted from the environment.
+set -e
+
+T=$(mktemp -d ${TMPDIR:-/tmp}/sh-test.XXXXXX)
+trap 'rm -rf $T' 0
+cd -P $T
+TP=$(pwd)
+mkdir test1
+ln -s test1 link
+cd link
+[ "$PWD" = "$TP/link" ]
+[ "$(pwd)" = "$TP/link" ]
+[ "$(pwd -P)" = "$TP/test1" ]
+[ "$(sh -c pwd)" = "$TP/link" ]
+[ "$(sh -c pwd\ -P)" = "$TP/test1" ]
+cd ..
+[ "$(pwd)" = "$TP" ]
+cd -P link
+[ "$PWD" = "$TP/test1" ]
+[ "$(pwd)" = "$TP/test1" ]
+[ "$(pwd -P)" = "$TP/test1" ]
+[ "$(sh -c pwd)" = "$TP/test1" ]
+[ "$(sh -c pwd\ -P)" = "$TP/test1" ]
OpenPOWER on IntegriCloud