Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/bin/sh PR bin/45390 - fix for folly four



details:   https://anonhg.NetBSD.org/src/rev/7c353a2c5dfd
branches:  trunk
changeset: 990605:7c353a2c5dfd
user:      kre <kre%NetBSD.org@localhost>
date:      Sun Oct 31 02:12:01 2021 +0000

description:
PR bin/45390 - fix for folly four

In the pwd builtin, verify that curdir names '.' before
simply printing it.   Never alter PWD or OLDPWD in the
pwd command.

Also while here, implement the (new: coming in POSIX, but has existed
for a while in several other shells) -e option to cd (with -e, cd -P
will exit(1) if the chdir() succeeds, but PWD cannot be discovered).

cd now prints the directory name used (if different from that given,
or cdprint is on) if interactive or (the new bit)in posix mode.

Some additional/changed comments added, and a DEBUG mode trace call
that was accidentally put inside an #if 0 block moved to where it
can do some good.

XXX pullup -9

diffstat:

 bin/sh/cd.c |  100 ++++++++++++++++++++++++++++++++++++++++-------------------
 1 files changed, 68 insertions(+), 32 deletions(-)

diffs (235 lines):

diff -r e59713ece076 -r 7c353a2c5dfd bin/sh/cd.c
--- a/bin/sh/cd.c       Sun Oct 31 00:31:48 2021 +0000
+++ b/bin/sh/cd.c       Sun Oct 31 02:12:01 2021 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: cd.c,v 1.50 2017/07/05 20:00:27 kre Exp $      */
+/*     $NetBSD: cd.c,v 1.51 2021/10/31 02:12:01 kre Exp $      */
 
 /*-
  * Copyright (c) 1991, 1993
@@ -37,12 +37,13 @@
 #if 0
 static char sccsid[] = "@(#)cd.c       8.2 (Berkeley) 5/4/95";
 #else
-__RCSID("$NetBSD: cd.c,v 1.50 2017/07/05 20:00:27 kre Exp $");
+__RCSID("$NetBSD: cd.c,v 1.51 2021/10/31 02:12:01 kre Exp $");
 #endif
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <stdbool.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
@@ -67,10 +68,11 @@
 #include "show.h"
 #include "cd.h"
 
-STATIC int docd(const char *, int);
+STATIC int docd(const char *, bool, bool);
 STATIC char *getcomponent(void);
-STATIC void updatepwd(const char *);
+STATIC bool updatepwd(const char *);
 STATIC void find_curdir(int noerror);
+STATIC bool is_curdir(const char *);
 
 char *curdir = NULL;           /* current working directory */
 char *prevdir;                 /* previous working directory */
@@ -84,10 +86,13 @@
        char *p;
        char *d;
        struct stat statb;
+       char opt;
+       bool eopt = false;
        int print = cdprint;    /* set -o cdprint to enable */
 
-       while (nextopt("P") != '\0')
-               ;
+       while ((opt = nextopt("Pe")) != '\0')
+               if (opt == 'e')
+                       eopt = true;
 
        /*
         * Try (quite hard) to have 'curdir' defined, nothing has set
@@ -128,19 +133,13 @@
                stunalloc(p);
                if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
                        int dopr = print;
+                       int x;
 
-                       if (!print) {
-                               /*
-                                * XXX - rethink
-                                */
-                               if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
-                                       dopr = strcmp(p + 2, dest);
-                               else
-                                       dopr = strcmp(p, dest);
-                       }
-                       if (docd(p, dopr) >= 0)
-                               return 0;
+                       if (!print)
+                               dopr = strcmp(p, dest);
 
+                       if ((x = docd(p, dopr != 0, eopt)) >= 0)
+                               return x;
                }
        }
        error("can't cd to %s", dest);
@@ -154,8 +153,10 @@
  */
 
 STATIC int
-docd(const char *dest, int print)
+docd(const char *dest, bool print, bool eopt)
 {
+       bool gotpwd;
+
 #if 0          /* no "cd -L" (ever) so all this is just a waste of time ... */
        char *p;
        char *q;
@@ -164,8 +165,6 @@
        int first;
        int badstat;
 
-       CTRACE(DBG_CMDS, ("docd(\"%s\", %d) called\n", dest, print));
-
        /*
         *  Check each component of the path. If we find a symlink or
         *  something we can't stat, clear curdir to force a getcwd()
@@ -199,16 +198,19 @@
        }
 #endif
 
+       CTRACE(DBG_CMDS, ("docd(\"%s\", %s, %s) called\n", dest,
+           print ? "true" : "false", eopt ? "true" : "false"));
+
        INTOFF;
        if (chdir(dest) < 0) {
                INTON;
                return -1;
        }
-       updatepwd(NULL);        /* only do cd -P, no "pretend" -L mode */
+       gotpwd = updatepwd(NULL);   /* only do cd -P, no "pretend" -L mode */
        INTON;
-       if (print && iflag == 1 && curdir)
-               out1fmt("%s\n", curdir);
-       return 0;
+       if (print && (iflag || posix))
+               out1fmt("%s\n", gotpwd ? curdir : dest);
+       return gotpwd || !eopt ? 0 : 1;
 }
 
 
@@ -245,7 +247,7 @@
  * that the current directory has changed.
  */
 
-STATIC void
+STATIC bool
 updatepwd(const char *dir)
 {
        char *new;
@@ -256,7 +258,7 @@
        /*
         * If our argument is NULL, we don't know the current directory
         * any more because we traversed a symbolic link or something
-        * we couldn't stat().
+        * we couldn't stat().   Or we simply don't trust what we had.
         */
        if (dir == NULL || curdir == NULL)  {
                if (prevdir)
@@ -269,10 +271,14 @@
                if (curdir) {
                        setvar("OLDPWD", prevdir, VEXPORT);
                        setvar("PWD", curdir, VEXPORT);
+                       return true;
                } else
                        unsetvar("PWD", 0);
-               return;
+               return false;
        }
+
+       /* XXX none of the following code is ever executed any more */
+
        cdcomppath = stalloc(strlen(dir) + 1);
        scopy(dir, cdcomppath);
        STARTSTACKSTR(new);
@@ -303,6 +309,25 @@
        setvar("OLDPWD", prevdir, VEXPORT);
        setvar("PWD", curdir, VEXPORT);
        INTON;
+       return true;
+}
+
+/*
+ * Test whether we are currently in the direcory given
+ * (provided it is given, and is absolute)
+ * ie: determine if path is fully qualified pathname of "."
+ */
+STATIC bool
+is_curdir(const char *path)
+{
+       struct stat stdot, stpath;
+
+       return  path != NULL &&
+               *path == '/' &&
+               stat(".", &stdot) != -1 &&
+               stat(path, &stpath) != -1 &&
+               stdot.st_dev == stpath.st_dev &&
+               stdot.st_ino == stpath.st_ino;
 }
 
 /*
@@ -329,8 +354,16 @@
        else
                find_curdir(0);
 
+#if 0  /* posix has been changed to forbid this */
        setvar("OLDPWD", prevdir, VEXPORT);
        setvar("PWD", curdir, VEXPORT);
+#endif
+
+       if (!is_curdir(curdir)) {
+               find_curdir(1);
+               if (curdir == NULL)
+                       error("Unable to find current directory");
+       }
        out1str(curdir);
        out1c('\n');
        return 0;
@@ -358,7 +391,6 @@
 getpwd(int noerror)
 {
        char *pwd;
-       struct stat stdot, stpwd;
        static int first = 1;
 
        if (curdir)
@@ -367,10 +399,7 @@
        if (first) {
                first = 0;
                pwd = getenv("PWD");
-               if (pwd && *pwd == '/' && stat(".", &stdot) != -1 &&
-                   stat(pwd, &stpwd) != -1 &&
-                   stdot.st_dev == stpwd.st_dev &&
-                   stdot.st_ino == stpwd.st_ino) {
+               if (is_curdir(pwd)) {
                        curdir = savestr(pwd);
                        return;
                }
@@ -392,6 +421,13 @@
         * getcwd, but traditionally getcwd is implemented using popen
         * to /bin/pwd. This creates a problem for us, since we cannot
         * keep track of the job if it is being ran behind our backs.
+        * XXX That's not actually the problem, a process created and
+        * XXX destroyed that we know nothing about is harmless.  The
+        * XXX problem is that old popen() implementations would use
+        * XXX wait(2) to await completion of the command, and that might
+        * XXX collect (and ignore) our children.   As long as we are
+        * XXX confident that popen() uses waitpid() (or the equv) there
+        * XXX would not be a problem.   But how do we know that?
         * So we re-implement getcwd(), and we suppress interrupts
         * throughout the process. This is not completely safe, since
         * the user can still break out of it by killing the pwd program.



Home | Main Index | Thread Index | Old Index