sh: Don't treat % specially in CDPATH
This commit is contained in:
parent
f7c188aeeb
commit
4600b569bb
@ -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;
|
||||
|
@ -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, int idx)
|
||||
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, int act,
|
||||
{
|
||||
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, int act,
|
||||
|
||||
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, int act,
|
||||
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 char *path)
|
||||
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)
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
24
bin/sh/tests/builtins/cd11.0
Normal file
24
bin/sh/tests/builtins/cd11.0
Normal file
@ -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" ]
|
Loading…
Reference in New Issue
Block a user