• access(2) is broken in at least kFreeBSD 9.0 as “modern” OS, so bring

back the wrapper code as well as refactor most other code calling it
• apparently, names can’t end in ‘_’ or contain ‘__’ anywhere…
This commit is contained in:
tg
2011-09-07 15:24:22 +00:00
parent 577c918beb
commit 9782f6b4d1
16 changed files with 326 additions and 332 deletions

127
exec.c
View File

@ -22,7 +22,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.95 2011/08/27 18:06:43 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.96 2011/09/07 15:24:14 tg Exp $");
#ifndef MKSH_DEFAULT_EXECSHELL
#define MKSH_DEFAULT_EXECSHELL "/bin/sh"
@ -38,6 +38,7 @@ static const char *do_selectargs(const char **, bool);
static Test_op dbteste_isa(Test_env *, Test_meta);
static const char *dbteste_getopnd(Test_env *, Test_op, bool);
static void dbteste_error(Test_env *, int, const char *);
static int search_access(const char *, int);
/*
* execute command tree
@ -102,7 +103,7 @@ execute(struct op * volatile t,
/* set variable to its expanded value */
z = strlen(cp) + 1;
if (notoktomul(z, 2) || notoktoadd(z * 2, n))
internal_errorf(T_oomem, (unsigned long)-1);
internal_errorf(Toomem, (unsigned long)-1);
dp = alloc(z * 2 + n, ATEMP);
memcpy(dp, t->vars[0], n);
t->vars[0] = dp;
@ -481,7 +482,7 @@ execute(struct op * volatile t,
unwind(LEXIT);
if (rv != 0 && !(flags & XERROK) &&
(xerrok == NULL || !*xerrok)) {
trapsig(SIGERR_);
trapsig(ksh_SIGERR);
if (Flag(FERREXIT))
unwind(LERROR);
}
@ -546,7 +547,7 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap,
break;
}
if ((tp = findcom(cp, FC_BI)) == NULL)
errorf("%s: %s: %s", T_builtin, cp, "not a builtin");
errorf("%s: %s: %s", Tbuiltin, cp, "not a builtin");
continue;
} else if (tp->val.f == c_exec) {
if (ap[1] == NULL)
@ -678,18 +679,10 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap,
struct tbl *ftp;
if (!tp->u.fpath) {
if (tp->u2.errno_) {
warningf(true, "%s: %s %s: %s", cp,
"can't find",
"function definition file",
strerror(tp->u2.errno_));
rv = 126;
} else {
warningf(true, "%s: %s %s", cp,
"can't find",
"function definition file");
rv = 127;
}
rv = (tp->u2.errnov == ENOENT) ? 127 : 126;
warningf(true, "%s: %s %s: %s", cp,
"can't find", "function definition file",
strerror(tp->u2.errnov));
break;
}
if (include(tp->u.fpath, 0, NULL, 0) < 0) {
@ -785,20 +778,13 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap,
/* tracked alias */
case CTALIAS:
if (!(tp->flag&ISSET)) {
/*
* errno_ will be set if the named command was found
* but could not be executed (permissions, no execute
* bit, directory, etc). Print out a (hopefully)
* useful error message and set the exit status to 126.
*/
if (tp->u2.errno_) {
warningf(true, "%s: %s: %s", cp,
"can't execute", strerror(tp->u2.errno_));
/* POSIX */
rv = 126;
} else {
warningf(true, "%s: %s", cp, "not found");
if (tp->u2.errnov == ENOENT) {
rv = 127;
warningf(true, "%s: %s", cp, "not found");
} else {
rv = 126;
warningf(true, "%s: %s: %s", cp, "can't execute",
strerror(tp->u2.errnov));
}
break;
}
@ -851,7 +837,7 @@ scriptexec(struct op *tp, const char **ap)
sh = str_val(global("EXECSHELL"));
if (sh && *sh)
sh = search(sh, path, X_OK, NULL);
sh = search_path(sh, path, X_OK, NULL);
if (!sh || !*sh)
sh = MKSH_DEFAULT_EXECSHELL;
@ -1094,10 +1080,10 @@ findcom(const char *name, int flags)
if (tp && !(tp->flag & ISSET)) {
if ((fpath = str_val(global("FPATH"))) == null) {
tp->u.fpath = NULL;
tp->u2.errno_ = 0;
tp->u2.errnov = ENOENT;
} else
tp->u.fpath = search(name, fpath, R_OK,
&tp->u2.errno_);
tp->u.fpath = search_path(name, fpath, R_OK,
&tp->u2.errnov);
}
}
if (!tp && (flags & FC_REGBI) && tbi && (tbi->flag & REG_BI))
@ -1106,7 +1092,8 @@ findcom(const char *name, int flags)
tp = tbi;
if (!tp && (flags & FC_PATH) && !(flags & FC_DEFPATH)) {
tp = ktsearch(&taliases, name, h);
if (tp && (tp->flag & ISSET) && access(tp->val.s, X_OK) != 0) {
if (tp && (tp->flag & ISSET) &&
ksh_access(tp->val.s, X_OK) != 0) {
if (tp->flag & ALLOC) {
tp->flag &= ~ALLOC;
afree(tp->val.s, APERM);
@ -1129,8 +1116,9 @@ findcom(const char *name, int flags)
/* make ~ISSET */
tp->flag = DEFINED;
}
npath.ro = search(name, flags & FC_DEFPATH ? def_path : path,
X_OK, &tp->u2.errno_);
npath.ro = search_path(name,
(flags & FC_DEFPATH) ? def_path : path,
X_OK, &tp->u2.errnov);
if (npath.ro) {
strdupx(tp->val.s, npath.ro, APERM);
if (npath.ro != name)
@ -1138,8 +1126,8 @@ findcom(const char *name, int flags)
tp->flag |= ISSET|ALLOC;
} else if ((flags & FC_FUNC) &&
(fpath = str_val(global("FPATH"))) != null &&
(npath.ro = search(name, fpath, R_OK,
&tp->u2.errno_)) != NULL) {
(npath.ro = search_path(name, fpath, R_OK,
&tp->u2.errnov)) != NULL) {
/*
* An undocumented feature of AT&T ksh is that
* it searches FPATH if a command is not found,
@ -1176,37 +1164,31 @@ flushcom(bool all)
}
}
/* Check if path is something we want to find. Returns -1 for failure. */
int
search_access(const char *lpath, int mode,
/* set if candidate found, but not suitable */
int *errnop)
/* check if path is something we want to find */
static int
search_access(const char *fn, int mode)
{
int ret, err = 0;
struct stat statb;
struct stat sb;
if (stat(lpath, &statb) < 0)
return (-1);
ret = access(lpath, mode);
if (ret < 0)
/* File exists, but we can't access it */
err = errno;
else if (mode == X_OK && (!S_ISREG(statb.st_mode) ||
!(statb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)))) {
/* This 'cause access() says root can execute everything */
ret = -1;
err = S_ISDIR(statb.st_mode) ? EISDIR : EACCES;
}
if (err && errnop && !*errnop)
*errnop = err;
return (ret);
if (stat(fn, &sb) < 0)
/* file does not exist */
return (ENOENT);
/* LINTED use of access */
if (access(fn, mode) < 0)
/* file exists, but we can't access it */
return (errno);
if (mode == X_OK && (!S_ISREG(sb.st_mode) ||
!(sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH))))
/* access(2) may say root can execute everything */
return (S_ISDIR(sb.st_mode) ? EISDIR : EACCES);
return (0);
}
/*
* search for command with PATH
*/
const char *
search(const char *name, const char *lpath,
search_path(const char *name, const char *lpath,
/* R_OK or X_OK */
int mode,
/* set if candidate found, but not suitable */
@ -1216,13 +1198,16 @@ search(const char *name, const char *lpath,
char *xp;
XString xs;
size_t namelen;
int ec = 0, ev;
if (errnop)
*errnop = 0;
if (vstrchr(name, '/')) {
if (search_access(name, mode, errnop) == 0)
if ((ec = search_access(name, mode)) == 0) {
search_path_ok:
if (errnop)
*errnop = 0;
return (name);
return (NULL);
}
goto search_path_err;
}
namelen = strlen(name) + 1;
@ -1242,12 +1227,20 @@ search(const char *name, const char *lpath,
sp = p;
XcheckN(xs, xp, namelen);
memcpy(xp, name, namelen);
if (search_access(Xstring(xs, xp), mode, errnop) == 0)
return (Xclose(xs, xp + namelen));
if ((ev = search_access(Xstring(xs, xp), mode)) == 0) {
name = Xclose(xs, xp + namelen);
goto search_path_ok;
}
/* accumulate non-ENOENT errors only */
if (ev != ENOENT && ec == 0)
ec = ev;
if (*sp++ == '\0')
sp = NULL;
}
Xfree(xs, xp);
search_path_err:
if (errnop)
*errnop = ec ? ec : ENOENT;
return (NULL);
}