Author: jilles
Date: Sun Jul 15 21:55:17 2018
New Revision: 336320
URL: https://svnweb.freebsd.org/changeset/base/336320

Log:
  sh: Don't treat % specially in CDPATH

Added:
  head/bin/sh/tests/builtins/cd11.0   (contents, props changed)
Modified:
  head/bin/sh/cd.c
  head/bin/sh/exec.c
  head/bin/sh/exec.h
  head/bin/sh/main.c
  head/bin/sh/tests/builtins/Makefile

Modified: head/bin/sh/cd.c
==============================================================================
--- head/bin/sh/cd.c    Sun Jul 15 21:10:19 2018        (r336319)
+++ head/bin/sh/cd.c    Sun Jul 15 21:55:17 2018        (r336320)
@@ -120,7 +120,7 @@ cdcmd(int argc __unused, char **argv __unused)
            (dest[0] == '.' && dest[1] == '.' && (dest[2] == '/' || dest[2] == 
'\0')) ||
            (path = bltinlookup("CDPATH", 1)) == NULL)
                path = "";
-       while ((p = padvance(&path, dest)) != NULL) {
+       while ((p = padvance(&path, NULL, dest)) != NULL) {
                if (stat(p, &statb) < 0) {
                        if (errno != ENOENT)
                                errno1 = errno;

Modified: head/bin/sh/exec.c
==============================================================================
--- head/bin/sh/exec.c  Sun Jul 15 21:10:19 2018        (r336319)
+++ head/bin/sh/exec.c  Sun Jul 15 21:55:17 2018        (r336320)
@@ -113,6 +113,7 @@ void
 shellexec(char **argv, char **envp, const char *path, int idx)
 {
        char *cmdname;
+       const char *opt;
        int e;
 
        if (strchr(argv[0], '/') != NULL) {
@@ -120,8 +121,8 @@ shellexec(char **argv, char **envp, const char *path, 
                e = errno;
        } else {
                e = ENOENT;
-               while ((cmdname = padvance(&path, argv[0])) != NULL) {
-                       if (--idx < 0 && pathopt == NULL) {
+               while ((cmdname = padvance(&path, &opt, argv[0])) != NULL) {
+                       if (--idx < 0 && opt == NULL) {
                                tryexec(cmdname, argv, envp);
                                if (errno != ENOENT && errno != ENOTDIR)
                                        e = errno;
@@ -174,16 +175,14 @@ tryexec(char *cmd, char **argv, char **envp)
  * Do a path search.  The variable path (passed by reference) should be
  * set to the start of the path before the first call; padvance will update
  * this value as it proceeds.  Successive calls to padvance will return
- * the possible path expansions in sequence.  If an option (indicated by
- * a percent sign) appears in the path entry then the global variable
- * pathopt will be set to point to it; otherwise pathopt will be set to
- * NULL.
+ * the possible path expansions in sequence.  If popt is not NULL, options
+ * are processed: if an option (indicated by a percent sign) appears in
+ * the path entry then *popt will be set to point to it; else *popt will be
+ * set to NULL.  If popt is NULL, percent signs are not special.
  */
 
-const char *pathopt;
-
 char *
-padvance(const char **path, const char *name)
+padvance(const char **path, const char **popt, const char *name)
 {
        const char *p, *start;
        char *q;
@@ -192,8 +191,12 @@ padvance(const char **path, const char *name)
        if (*path == NULL)
                return NULL;
        start = *path;
-       for (p = start; *p && *p != ':' && *p != '%'; p++)
-               ; /* nothing */
+       if (popt != NULL)
+               for (p = start; *p && *p != ':' && *p != '%'; p++)
+                       ; /* nothing */
+       else
+               for (p = start; *p && *p != ':'; p++)
+                       ; /* nothing */
        namelen = strlen(name);
        len = p - start + namelen + 2;  /* "2" is for '/' and '\0' */
        STARTSTACKSTR(q);
@@ -204,10 +207,12 @@ padvance(const char **path, const char *name)
                *q++ = '/';
        }
        memcpy(q, name, namelen + 1);
-       pathopt = NULL;
-       if (*p == '%') {
-               pathopt = ++p;
-               while (*p && *p != ':')  p++;
+       if (popt != NULL) {
+               if (*p == '%') {
+                       *popt = ++p;
+                       while (*p && *p != ':')  p++;
+               } else
+                       *popt = NULL;
        }
        if (*p == ':')
                *path = p + 1;
@@ -277,14 +282,14 @@ static void
 printentry(struct tblentry *cmdp, int verbose)
 {
        int idx;
-       const char *path;
+       const char *path, *opt;
        char *name;
 
        if (cmdp->cmdtype == CMDNORMAL) {
                idx = cmdp->param.index;
                path = pathval();
                do {
-                       name = padvance(&path, cmdp->cmdname);
+                       name = padvance(&path, &opt, cmdp->cmdname);
                        stunalloc(name);
                } while (--idx >= 0);
                out1str(name);
@@ -321,6 +326,7 @@ find_command(const char *name, struct cmdentry *entry,
 {
        struct tblentry *cmdp, loc_cmd;
        int idx;
+       const char *opt;
        char *fullname;
        struct stat statb;
        int e;
@@ -363,10 +369,11 @@ find_command(const char *name, struct cmdentry *entry,
 
        e = ENOENT;
        idx = -1;
-       for (;(fullname = padvance(&path, name)) != NULL; stunalloc(fullname)) {
+       for (;(fullname = padvance(&path, &opt, name)) != NULL;
+           stunalloc(fullname)) {
                idx++;
-               if (pathopt) {
-                       if (strncmp(pathopt, "func", 4) == 0) {
+               if (opt) {
+                       if (strncmp(opt, "func", 4) == 0) {
                                /* handled below */
                        } else {
                                continue; /* ignore unimplemented options */
@@ -382,7 +389,7 @@ find_command(const char *name, struct cmdentry *entry,
                e = EACCES;     /* if we fail, this will be the error */
                if (!S_ISREG(statb.st_mode))
                        continue;
-               if (pathopt) {          /* this is a %func directory */
+               if (opt) {              /* this is a %func directory */
                        readcmdfile(fullname);
                        if ((cmdp = cmdlookup(name, 0)) == NULL || 
cmdp->cmdtype != CMDFUNCTION)
                                error("%s not defined in %s", name, fullname);
@@ -703,10 +710,11 @@ typecmd_impl(int argc, char **argv, int cmd, const cha
                case CMDNORMAL: {
                        if (strchr(argv[i], '/') == NULL) {
                                const char *path2 = path;
+                               const char *opt2;
                                char *name;
                                int j = entry.u.index;
                                do {
-                                       name = padvance(&path2, argv[i]);
+                                       name = padvance(&path2, &opt2, argv[i]);
                                        stunalloc(name);
                                } while (--j >= 0);
                                if (cmd == TYPECMD_SMALLV)

Modified: head/bin/sh/exec.h
==============================================================================
--- head/bin/sh/exec.h  Sun Jul 15 21:10:19 2018        (r336319)
+++ head/bin/sh/exec.h  Sun Jul 15 21:55:17 2018        (r336320)
@@ -61,11 +61,10 @@ struct cmdentry {
 #define DO_ERR         0x01    /* prints errors */
 #define DO_NOFUNC      0x02    /* don't return shell functions, for command */
 
-extern const char *pathopt;    /* set by padvance */
 extern int exerrno;            /* last exec error */
 
 void shellexec(char **, char **, const char *, int) __dead2;
-char *padvance(const char **, const char *);
+char *padvance(const char **, const char **, const char *);
 void find_command(const char *, struct cmdentry *, int, const char *);
 int find_builtin(const char *, int *);
 void hashcd(void);

Modified: head/bin/sh/main.c
==============================================================================
--- head/bin/sh/main.c  Sun Jul 15 21:10:19 2018        (r336319)
+++ head/bin/sh/main.c  Sun Jul 15 21:55:17 2018        (r336320)
@@ -294,6 +294,7 @@ static char *
 find_dot_file(char *basename)
 {
        char *fullname;
+       const char *opt;
        const char *path = pathval();
        struct stat statb;
 
@@ -301,7 +302,7 @@ find_dot_file(char *basename)
        if( strchr(basename, '/'))
                return basename;
 
-       while ((fullname = padvance(&path, basename)) != NULL) {
+       while ((fullname = padvance(&path, &opt, basename)) != NULL) {
                if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
                        /*
                         * Don't bother freeing here, since it will

Modified: head/bin/sh/tests/builtins/Makefile
==============================================================================
--- head/bin/sh/tests/builtins/Makefile Sun Jul 15 21:10:19 2018        
(r336319)
+++ head/bin/sh/tests/builtins/Makefile Sun Jul 15 21:55:17 2018        
(r336320)
@@ -53,6 +53,7 @@ ${PACKAGE}FILES+=             cd7.0
 ${PACKAGE}FILES+=              cd8.0
 ${PACKAGE}FILES+=              cd9.0 cd9.0.stdout
 ${PACKAGE}FILES+=              cd10.0
+${PACKAGE}FILES+=              cd11.0
 ${PACKAGE}FILES+=              command1.0
 ${PACKAGE}FILES+=              command2.0
 ${PACKAGE}FILES+=              command3.0

Added: head/bin/sh/tests/builtins/cd11.0
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/bin/sh/tests/builtins/cd11.0   Sun Jul 15 21:55:17 2018        
(r336320)
@@ -0,0 +1,24 @@
+# $FreeBSD$
+
+set -e
+T=$(mktemp -d "${TMPDIR:-/tmp}/sh-test.XXXXXX")
+trap 'rm -rf "$T"' 0
+
+mkdir "$T/%?^&*"
+cd -P "$T/%?^&*"
+D=$(pwd)
+
+mkdir a a/1 b b/1 b/2
+
+CDPATH=$D/a:
+# Basic test.
+cd 1 >/dev/null
+[ "$(pwd)" = "$D/a/1" ]
+# Test that the current directory is not checked before CDPATH.
+cd "$D/b"
+cd 1 >/dev/null
+[ "$(pwd)" = "$D/a/1" ]
+# Test not using a CDPATH entry.
+cd "$D/b"
+cd 2
+[ "$(pwd)" = "$D/b/2" ]
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to