aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2018-05-19 02:39:50 +0800
committerBen Hutchings <ben@decadent.org.uk>2020-03-28 21:42:55 +0000
commit604d3a0a1570f3478360913c2935ea53d18857e6 (patch)
tree2288878a12ce0004d4900ce80c4b150c01ae4cde
parenta24fb71983693cab52a3b9f5c163a54518a170a1 (diff)
downloadklibc-604d3a0a1570f3478360913c2935ea53d18857e6.tar.gz
[klibc] dash: exec: Stricter pathopt parsing
[ dash commit a068bf7aa310e8d36ae11c2aec47af1446a18827 ] This patch changes the parsing of pathopt. First of all only %builtin and %func (with arbitrary suffixes) will be recognised. Any other pathopt will be treated as a normal directory. Furthermore, pathopt can now be specified before the directory, rather than after it. In fact, a future version may remove support for pathopt suffixes. Wherever the pathopt is placed, an optional % may be placed after it to terminate the pathopt. This is so that it is less likely that a genuine directory containing a % sign is parsed as a pathopt. Users of padvance outside of exec.c have also been modified: 1) cd(1) will always treat % characters as part of the path. 2) chkmail will continue to accept arbitrary pathopt. 3) find_dot_file will ignore the %builtin pathopt instead of trying to do a stat in the accompanying directory (which is usually the current directory). The patch also removes the clearcmdentry optimisation where we attempt to only partially flush the table where possible. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
-rw-r--r--usr/dash/cd.c2
-rw-r--r--usr/dash/exec.c133
-rw-r--r--usr/dash/exec.h7
-rw-r--r--usr/dash/mail.c2
-rw-r--r--usr/dash/main.c3
5 files changed, 92 insertions, 55 deletions
diff --git a/usr/dash/cd.c b/usr/dash/cd.c
index 610a4fa889190..b6742af842361 100644
--- a/usr/dash/cd.c
+++ b/usr/dash/cd.c
@@ -128,7 +128,7 @@ dotdot:
if (!*dest)
dest = ".";
path = bltinlookup("CDPATH");
- while (p = path, (len = padvance(&path, dest)) >= 0) {
+ while (p = path, (len = padvance_magic(&path, dest, 0)) >= 0) {
c = *p;
p = stalloc(len);
diff --git a/usr/dash/exec.c b/usr/dash/exec.c
index 04ee2ba908e80..8948754bbc86d 100644
--- a/usr/dash/exec.c
+++ b/usr/dash/exec.c
@@ -92,7 +92,7 @@ STATIC int builtinloc = -1; /* index in path of %builtin, or -1 */
STATIC void tryexec(char *, char **, char **);
STATIC void printentry(struct tblentry *);
-STATIC void clearcmdentry(int);
+STATIC void clearcmdentry(void);
STATIC struct tblentry *cmdlookup(const char *, int);
STATIC void delete_cmd_entry(void);
STATIC void addcmdentry(char *, struct cmdentry *);
@@ -168,7 +168,27 @@ repeat:
}
}
+static const char *legal_pathopt(const char *opt, const char *term, int magic)
+{
+ switch (magic) {
+ case 0:
+ opt = NULL;
+ break;
+ case 1:
+ opt = prefix(opt, "builtin") ?: prefix(opt, "func");
+ break;
+
+ default:
+ opt += strcspn(opt, term);
+ break;
+ }
+
+ if (opt && *opt == '%')
+ opt++;
+
+ return opt;
+}
/*
* Do a path search. The variable path (passed by reference) should be
@@ -178,39 +198,64 @@ repeat:
* 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.
+ *
+ * If magic is 0 then pathopt recognition will be disabled. If magic is
+ * 1 we shall recognise %builtin/%func. Otherwise we shall accept any
+ * pathopt.
*/
const char *pathopt;
-int padvance(const char **path, const char *name)
+int padvance_magic(const char **path, const char *name, int magic)
{
+ const char *term = "%:";
+ const char *lpathopt;
const char *p;
char *q;
const char *start;
+ size_t qlen;
size_t len;
if (*path == NULL)
return -1;
+
+ lpathopt = NULL;
start = *path;
- for (p = start ; *p && *p != ':' && *p != '%' ; p++);
- len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
- q = growstackto(len);
- if (p != start) {
- memcpy(q, start, p - start);
- q += p - start;
- *q++ = '/';
+
+ if (*start == '%' && (p = legal_pathopt(start + 1, term, magic))) {
+ lpathopt = start + 1;
+ start = p;
+ term = ":";
}
- strcpy(q, name);
- pathopt = NULL;
+
+ len = strcspn(start, term);
+ p = start + len;
+
if (*p == '%') {
- pathopt = ++p;
- while (*p && *p != ':') p++;
+ size_t extra = strchrnul(p, ':') - p;
+
+ if (legal_pathopt(p + 1, term, magic))
+ lpathopt = p + 1;
+ else
+ len += extra;
+
+ p += extra;
+ }
+
+ pathopt = lpathopt;
+ *path = *p == ':' ? p + 1 : NULL;
+
+ /* "2" is for '/' and '\0' */
+ qlen = len + strlen(name) + 2;
+ q = growstackto(qlen);
+
+ if (likely(len)) {
+ q = mempcpy(q, start, len);
+ *q++ = '/';
}
- if (*p == ':')
- *path = p + 1;
- else
- *path = NULL;
- return len;
+ strcpy(q, name);
+
+ return qlen;
}
@@ -228,7 +273,7 @@ hashcmd(int argc, char **argv)
char *name;
while ((c = nextopt("r")) != '\0') {
- clearcmdentry(0);
+ clearcmdentry();
return 0;
}
if (*argptr == NULL) {
@@ -363,15 +408,16 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
idx = -1;
loop:
while ((len = padvance(&path, name)) >= 0) {
+ const char *lpathopt = pathopt;
+
fullname = stackblock();
idx++;
- if (pathopt) {
- if (prefix(pathopt, "builtin")) {
+ if (lpathopt) {
+ if (*lpathopt == 'b') {
if (bcmd)
goto builtin_success;
continue;
- } else if (!(act & DO_NOFUNC) &&
- prefix(pathopt, "func")) {
+ } else if (!(act & DO_NOFUNC)) {
/* handled below */
} else {
/* ignore unimplemented options */
@@ -397,7 +443,7 @@ loop:
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 (lpathopt) { /* this is a %func directory */
stalloc(len);
readcmdfile(fullname);
if ((cmdp = cmdlookup(name, 0)) == NULL ||
@@ -515,39 +561,26 @@ hashcd(void)
void
changepath(const char *newval)
{
- const char *old, *new;
+ const char *new;
int idx;
- int firstchange;
int bltin;
- old = pathval();
new = newval;
- firstchange = 9999; /* assume no change */
idx = 0;
bltin = -1;
for (;;) {
- if (*old != *new) {
- firstchange = idx;
- if ((*old == '\0' && *new == ':')
- || (*old == ':' && *new == '\0'))
- firstchange++;
- old = new; /* ignore subsequent differences */
- }
- if (*new == '\0')
- break;
- if (*new == '%' && bltin < 0 && prefix(new + 1, "builtin"))
+ if (*new == '%' && prefix(new + 1, "builtin")) {
bltin = idx;
- if (*new == ':') {
- idx++;
+ break;
}
- new++, old++;
+ new = strchr(new, ':');
+ if (!new)
+ break;
+ idx++;
+ new++;
}
- if (builtinloc < 0 && bltin >= 0)
- builtinloc = bltin; /* zap builtins */
- if (builtinloc >= 0 && bltin < 0)
- firstchange = 0;
- clearcmdentry(firstchange);
builtinloc = bltin;
+ clearcmdentry();
}
@@ -557,7 +590,7 @@ changepath(const char *newval)
*/
STATIC void
-clearcmdentry(int firstchange)
+clearcmdentry(void)
{
struct tblentry **tblp;
struct tblentry **pp;
@@ -567,10 +600,8 @@ clearcmdentry(int firstchange)
for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
pp = tblp;
while ((cmdp = *pp) != NULL) {
- if ((cmdp->cmdtype == CMDNORMAL &&
- cmdp->param.index >= firstchange)
- || (cmdp->cmdtype == CMDBUILTIN &&
- builtinloc >= firstchange)) {
+ if (cmdp->cmdtype == CMDNORMAL ||
+ (cmdp->cmdtype == CMDBUILTIN && builtinloc > 0)) {
*pp = cmdp->next;
ckfree(cmdp);
} else {
diff --git a/usr/dash/exec.h b/usr/dash/exec.h
index e241b74237b02..f394f3f735781 100644
--- a/usr/dash/exec.h
+++ b/usr/dash/exec.h
@@ -62,7 +62,7 @@ extern const char *pathopt; /* set by padvance */
void shellexec(char **, const char *, int)
__attribute__((__noreturn__));
-int padvance(const char **, const char *);
+int padvance_magic(const char **path, const char *name, int magic);
int hashcmd(int, char **);
void find_command(char *, struct cmdentry *, int, const char *);
struct builtincmd *find_builtin(const char *);
@@ -75,3 +75,8 @@ void defun(union node *);
void unsetfunc(const char *);
int typecmd(int, char **);
int commandcmd(int, char **);
+
+static inline int padvance(const char **path, const char *name)
+{
+ return padvance_magic(path, name, 1);
+}
diff --git a/usr/dash/mail.c b/usr/dash/mail.c
index 7f9e49de5cc1f..8eacb2d0578e8 100644
--- a/usr/dash/mail.c
+++ b/usr/dash/mail.c
@@ -79,7 +79,7 @@ chkmail(void)
for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
int len;
- len = padvance(&mpath, nullstr);
+ len = padvance_magic(&mpath, nullstr, 2);
if (!len)
break;
p = stackblock();
diff --git a/usr/dash/main.c b/usr/dash/main.c
index c87fbd73b2354..e8e42565e9e22 100644
--- a/usr/dash/main.c
+++ b/usr/dash/main.c
@@ -300,7 +300,8 @@ find_dot_file(char *basename)
while ((len = padvance(&path, basename)) >= 0) {
fullname = stackblock();
- if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
+ if ((!pathopt || *pathopt == 'f') &&
+ !stat(fullname, &statb) && S_ISREG(statb.st_mode)) {
/* This will be freed by the caller. */
return stalloc(len);
}