Make cd (really) do cd -P, and not just claim that is what it is doing
while doing a half-hearted, broken, partial, version of cd -L instead. The latter (as the manual says) is not supported, what's more, it is an abomination, and should never be supported (anywhere.) Fix the doc so that the pretense that we notice when a path given crosses a symlink (and turns on printing of the destination directory) is claimed no more (that used to be true until late Dec 2016, but was changed). Now the print happens if -o cdprint is set, or if an entry from CDPATH that is not "" or "." is used (or if the "cd dest repl" cd cmd variant is used.) Fix CDPATH processing: avoid the magic '%' processing that is used for PATH and MAILPATH from corrupting CDPATH. The % magic (both variants) remains undocumented. Also, don't double the '/' if an entry in PATH or CDPATH ends in '/' (as in CDPATH=":/usr/src/"). A "cd usr.bin" used to do chdir("/usr/src//usr.bin"). No more. This is almost invisible, and relatively harmless, either way.... Also fix a bug where if a plausible destination directory in CDPATH was located, but the chdir() failed (eg: permission denied) and then a later "." or "" CDPATH entry succeeded, "print" mode was turned on. That is: cd /tmp; mkdir bin mkdir -p P/bin; chmod 0 P/bin CDPATH=/tmp/P: cd bin would cd to /tmp/bin (correctly) but print it (incorrectly). Also when in "cd dest replace" mode, if the result of the replacement generates '-' as the path named, as in: cd $PWD - then simply change to '-' (or attempt to, with CDPATH search), rather than having this being equivalent to "cd -") Because of these changes, the pwd command (and $PWD) essentially always acts as pwd -P, even when called as pwd -L (which is still the default.) That is, even more than it did before. Also fixed a (kind of minor) mem management error (CDPATH related) "whosoever shall padvance must stunalloc before repeating" (and the same for MAILPATH).
This commit is contained in:
parent
f56828e47e
commit
1676135e1a
65
bin/sh/cd.c
65
bin/sh/cd.c
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: cd.c,v 1.47 2016/12/26 02:27:57 christos Exp $ */
|
||||
/* $NetBSD: cd.c,v 1.48 2017/06/04 20:27:14 kre Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
@ -37,7 +37,7 @@
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)cd.c 8.2 (Berkeley) 5/4/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: cd.c,v 1.47 2016/12/26 02:27:57 christos Exp $");
|
||||
__RCSID("$NetBSD: cd.c,v 1.48 2017/06/04 20:27:14 kre Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
@ -80,10 +80,11 @@ int
|
||||
cdcmd(int argc, char **argv)
|
||||
{
|
||||
const char *dest;
|
||||
const char *path, *p;
|
||||
const char *path, *cp;
|
||||
char *p;
|
||||
char *d;
|
||||
struct stat statb;
|
||||
int print = cdprint; /* set -cdprint to enable */
|
||||
int print = cdprint; /* set -o cdprint to enable */
|
||||
|
||||
while (nextopt("P") != '\0')
|
||||
;
|
||||
@ -98,46 +99,46 @@ cdcmd(int argc, char **argv)
|
||||
dest = bltinlookup("HOME", 1);
|
||||
if (dest == NULL)
|
||||
error("HOME not set");
|
||||
} else {
|
||||
if (argptr[1]) {
|
||||
/* Do 'ksh' style substitution */
|
||||
if (!curdir)
|
||||
error("PWD not set");
|
||||
p = strstr(curdir, dest);
|
||||
if (!p)
|
||||
error("bad substitution");
|
||||
d = stalloc(strlen(curdir) + strlen(argptr[1]) + 1);
|
||||
memcpy(d, curdir, p - curdir);
|
||||
strcpy(d + (p - curdir), argptr[1]);
|
||||
strcat(d, p + strlen(dest));
|
||||
dest = d;
|
||||
print = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (dest[0] == '-' && dest[1] == '\0') {
|
||||
} else if (argptr[1]) {
|
||||
/* Do 'ksh' style substitution */
|
||||
if (!curdir)
|
||||
error("PWD not set");
|
||||
p = strstr(curdir, dest);
|
||||
if (!p)
|
||||
error("bad substitution");
|
||||
d = stalloc(strlen(curdir) + strlen(argptr[1]) + 1);
|
||||
memcpy(d, curdir, p - curdir);
|
||||
strcpy(d + (p - curdir), argptr[1]);
|
||||
strcat(d, p + strlen(dest));
|
||||
dest = d;
|
||||
print = 1;
|
||||
} else if (dest[0] == '-' && dest[1] == '\0') {
|
||||
dest = prevdir ? prevdir : curdir;
|
||||
print = 1;
|
||||
}
|
||||
if (*dest == '\0')
|
||||
dest = ".";
|
||||
p = dest;
|
||||
if (*p == '.' && *++p == '.')
|
||||
p++;
|
||||
if (*p == 0 || *p == '/' || (path = bltinlookup("CDPATH", 1)) == NULL)
|
||||
|
||||
cp = dest;
|
||||
if (*cp == '.' && *++cp == '.')
|
||||
cp++;
|
||||
if (*cp == 0 || *cp == '/' || (path = bltinlookup("CDPATH", 1)) == NULL)
|
||||
path = nullstr;
|
||||
while ((p = padvance(&path, dest)) != NULL) {
|
||||
while ((p = padvance(&path, dest, 0)) != NULL) {
|
||||
stunalloc(p);
|
||||
if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
|
||||
int dopr = print;
|
||||
|
||||
if (!print) {
|
||||
/*
|
||||
* XXX - rethink
|
||||
*/
|
||||
if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
|
||||
print = strcmp(p + 2, dest);
|
||||
dopr = strcmp(p + 2, dest);
|
||||
else
|
||||
print = strcmp(p, dest);
|
||||
dopr = strcmp(p, dest);
|
||||
}
|
||||
if (docd(p, print) >= 0)
|
||||
if (docd(p, dopr) >= 0)
|
||||
return 0;
|
||||
|
||||
}
|
||||
@ -155,6 +156,7 @@ cdcmd(int argc, char **argv)
|
||||
STATIC int
|
||||
docd(const char *dest, int print)
|
||||
{
|
||||
#if 0 /* no "cd -L" (ever) so all this is just a waste of time ... */
|
||||
char *p;
|
||||
char *q;
|
||||
char *component;
|
||||
@ -195,13 +197,14 @@ docd(const char *dest, int print)
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
INTOFF;
|
||||
if (chdir(dest) < 0) {
|
||||
INTON;
|
||||
return -1;
|
||||
}
|
||||
updatepwd(badstat ? NULL : dest);
|
||||
updatepwd(NULL); /* only do cd -P, no "pretend" -L mode */
|
||||
INTON;
|
||||
if (print && iflag == 1 && curdir)
|
||||
out1fmt("%s\n", curdir);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: eval.c,v 1.140 2017/05/13 03:26:03 kre Exp $ */
|
||||
/* $NetBSD: eval.c,v 1.141 2017/06/04 20:27:14 kre Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1993
|
||||
@ -37,7 +37,7 @@
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)eval.c 8.9 (Berkeley) 6/8/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: eval.c,v 1.140 2017/05/13 03:26:03 kre Exp $");
|
||||
__RCSID("$NetBSD: eval.c,v 1.141 2017/06/04 20:27:14 kre Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
@ -1300,7 +1300,7 @@ find_dot_file(char *basename)
|
||||
error("%s: is a block device", basename);
|
||||
return basename;
|
||||
}
|
||||
} else while ((fullname = padvance(&path, basename)) != NULL) {
|
||||
} else while ((fullname = padvance(&path, basename, 1)) != NULL) {
|
||||
if ((stat(fullname, &statb) == 0)) {
|
||||
/* weird format is to ease future code... */
|
||||
if (S_ISDIR(statb.st_mode) || S_ISBLK(statb.st_mode))
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: exec.c,v 1.47 2017/05/15 19:55:20 kre Exp $ */
|
||||
/* $NetBSD: exec.c,v 1.48 2017/06/04 20:27:14 kre Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
@ -37,7 +37,7 @@
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)exec.c 8.4 (Berkeley) 6/8/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: exec.c,v 1.47 2017/05/15 19:55:20 kre Exp $");
|
||||
__RCSID("$NetBSD: exec.c,v 1.48 2017/06/04 20:27:14 kre Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
@ -130,7 +130,7 @@ shellexec(char **argv, char **envp, const char *path, int idx, int vforked)
|
||||
e = errno;
|
||||
} else {
|
||||
e = ENOENT;
|
||||
while ((cmdname = padvance(&path, argv[0])) != NULL) {
|
||||
while ((cmdname = padvance(&path, argv[0], 1)) != NULL) {
|
||||
if (--idx < 0 && pathopt == NULL) {
|
||||
tryexec(cmdname, argv, envp, vforked);
|
||||
if (errno != ENOENT && errno != ENOTDIR)
|
||||
@ -296,7 +296,7 @@ break2:;
|
||||
const char *pathopt;
|
||||
|
||||
char *
|
||||
padvance(const char **path, const char *name)
|
||||
padvance(const char **path, const char *name, int magic_percent)
|
||||
{
|
||||
const char *p;
|
||||
char *q;
|
||||
@ -305,8 +305,12 @@ padvance(const char **path, const char *name)
|
||||
|
||||
if (*path == NULL)
|
||||
return NULL;
|
||||
if (magic_percent)
|
||||
magic_percent = '%';
|
||||
|
||||
start = *path;
|
||||
for (p = start ; *p && *p != ':' && *p != '%' ; p++);
|
||||
for (p = start ; *p && *p != ':' && *p != magic_percent ; p++)
|
||||
;
|
||||
len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
|
||||
while (stackblocksize() < len)
|
||||
growstackblock();
|
||||
@ -314,13 +318,15 @@ padvance(const char **path, const char *name)
|
||||
if (p != start) {
|
||||
memcpy(q, start, p - start);
|
||||
q += p - start;
|
||||
*q++ = '/';
|
||||
if (q[-1] != '/')
|
||||
*q++ = '/';
|
||||
}
|
||||
strcpy(q, name);
|
||||
pathopt = NULL;
|
||||
if (*p == '%') {
|
||||
if (*p == magic_percent) {
|
||||
pathopt = ++p;
|
||||
while (*p && *p != ':') p++;
|
||||
while (*p && *p != ':')
|
||||
p++;
|
||||
}
|
||||
if (*p == ':')
|
||||
*path = p + 1;
|
||||
@ -441,7 +447,7 @@ printentry(struct tblentry *cmdp, int verbose)
|
||||
idx = cmdp->param.index;
|
||||
path = pathval();
|
||||
do {
|
||||
name = padvance(&path, cmdp->cmdname);
|
||||
name = padvance(&path, cmdp->cmdname, 1);
|
||||
stunalloc(name);
|
||||
} while (--idx >= 0);
|
||||
if (verbose)
|
||||
@ -574,7 +580,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
|
||||
e = ENOENT;
|
||||
idx = -1;
|
||||
loop:
|
||||
while ((fullname = padvance(&path, name)) != NULL) {
|
||||
while ((fullname = padvance(&path, name, 1)) != NULL) {
|
||||
stunalloc(fullname);
|
||||
idx++;
|
||||
if (pathopt) {
|
||||
@ -1075,7 +1081,7 @@ typecmd(int argc, char **argv)
|
||||
char *name;
|
||||
int j = entry.u.index;
|
||||
do {
|
||||
name = padvance(&path, arg);
|
||||
name = padvance(&path, arg, 1);
|
||||
stunalloc(name);
|
||||
} while (--j >= 0);
|
||||
if (!v_flag)
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: exec.h,v 1.24 2016/05/03 13:47:58 kre Exp $ */
|
||||
/* $NetBSD: exec.h,v 1.25 2017/06/04 20:27:14 kre Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
@ -62,7 +62,7 @@ struct cmdentry {
|
||||
extern const char *pathopt; /* set by padvance */
|
||||
|
||||
void shellexec(char **, char **, const char *, int, int) __dead;
|
||||
char *padvance(const char **, const char *);
|
||||
char *padvance(const char **, const char *, int);
|
||||
void find_command(char *, struct cmdentry *, int, const char *);
|
||||
int (*find_builtin(char *))(int, char **);
|
||||
int (*find_splbltin(char *))(int, char **);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: mail.c,v 1.16 2003/08/07 09:05:33 agc Exp $ */
|
||||
/* $NetBSD: mail.c,v 1.17 2017/06/04 20:27:14 kre Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
@ -37,7 +37,7 @@
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)mail.c 8.2 (Berkeley) 5/4/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: mail.c,v 1.16 2003/08/07 09:05:33 agc Exp $");
|
||||
__RCSID("$NetBSD: mail.c,v 1.17 2017/06/04 20:27:14 kre Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
@ -88,9 +88,10 @@ chkmail(int silent)
|
||||
setstackmark(&smark);
|
||||
mpath = mpathset() ? mpathval() : mailval();
|
||||
for (i = 0 ; i < nmboxes ; i++) {
|
||||
p = padvance(&mpath, nullstr);
|
||||
p = padvance(&mpath, nullstr, 1);
|
||||
if (p == NULL)
|
||||
break;
|
||||
stunalloc(p);
|
||||
if (*p == '\0')
|
||||
continue;
|
||||
for (q = p ; *q ; q++);
|
||||
|
24
bin/sh/sh.1
24
bin/sh/sh.1
@ -1,4 +1,4 @@
|
||||
.\" $NetBSD: sh.1,v 1.146 2017/06/02 17:42:51 abhinav Exp $
|
||||
.\" $NetBSD: sh.1,v 1.147 2017/06/04 20:27:14 kre Exp $
|
||||
.\" Copyright (c) 1991, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
@ -31,7 +31,7 @@
|
||||
.\"
|
||||
.\" @(#)sh.1 8.6 (Berkeley) 5/4/95
|
||||
.\"
|
||||
.Dd May 12, 2017
|
||||
.Dd June 4, 2017
|
||||
.Dt SH 1
|
||||
.ds flags abCEeFfhnuvxIimpqV
|
||||
.Os
|
||||
@ -362,6 +362,7 @@ Make an interactive shell always print the new directory name when
|
||||
changed by the
|
||||
.Ic cd
|
||||
command.
|
||||
In a non-interactive shell this option has no effect.
|
||||
.It "\ \ " Em nolog
|
||||
Prevent the entry of function definitions into the command history (see
|
||||
.Ic fc
|
||||
@ -1669,11 +1670,11 @@ Switch to the specified directory (default
|
||||
If
|
||||
.Ar replace
|
||||
is specified, then the new directory name is generated by replacing
|
||||
the first occurrence of
|
||||
the first occurrence of the string
|
||||
.Ar directory
|
||||
in the current directory name with
|
||||
.Ar replace .
|
||||
If
|
||||
Otherwise if
|
||||
.Ar directory
|
||||
is
|
||||
.Sq - ,
|
||||
@ -1687,7 +1688,7 @@ appears in the environment of the
|
||||
command or the shell variable
|
||||
.Ev CDPATH
|
||||
is set and the directory name does not begin with a slash,
|
||||
or its first (or only) component isn't dot or dot dot,
|
||||
and its first (or only) component isn't dot or dot dot,
|
||||
then the directories listed in
|
||||
.Ev CDPATH
|
||||
will be searched for the specified directory.
|
||||
@ -1719,10 +1720,17 @@ In an interactive shell, the
|
||||
.Ic cd
|
||||
command will print out the name of the
|
||||
directory that it actually switched to if this is different from the name
|
||||
that the user gave.
|
||||
These may be different either because the
|
||||
that the user gave,
|
||||
or always if the
|
||||
.Ic cdprint
|
||||
option is set.
|
||||
The destination may be different either because the
|
||||
.Ev CDPATH
|
||||
mechanism was used or because a symbolic link was crossed.
|
||||
mechanism was used
|
||||
.\" or because a symbolic link was crossed.
|
||||
or if the
|
||||
.Ar replace
|
||||
argument was used.
|
||||
.It eval Ar string ...
|
||||
Concatenate all the arguments with spaces.
|
||||
Then re-parse and execute the command.
|
||||
|
Loading…
Reference in New Issue
Block a user