• move funcs.c:do_realpath() to misc.c and make it global
⇒ consider merging simplify_path() • move funcs.c:c_cd() to misc.c • make misc.c:make_path() static, c_cd() is its only user ⇒ mark as obsolete • tweak misc.c:set_current_wd() to drop ksh_get_wd() argument should be no code change, but the entire path stuff is a mess… so expect actual implementation changes or even rewrites shortly
This commit is contained in:
parent
8d8ee0cc6a
commit
803c51914b
356
funcs.c
356
funcs.c
@ -38,7 +38,7 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.178 2011/03/23 18:47:06 tg Exp $");
|
||||
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.179 2011/03/24 19:05:47 tg Exp $");
|
||||
|
||||
#if HAVE_KILLPG
|
||||
/*
|
||||
@ -206,358 +206,6 @@ static char *kill_fmt_entry(char *, int, int, const void *);
|
||||
static void p_time(struct shf *, bool, long, int, int,
|
||||
const char *, const char *)
|
||||
MKSH_A_NONNULL((nonnull (6, 7)));
|
||||
static char *do_realpath(const char *);
|
||||
|
||||
static char *
|
||||
do_realpath(const char *upath)
|
||||
{
|
||||
char *xp, *ip, *tp, *ipath, *ldest = NULL;
|
||||
XString xs;
|
||||
ptrdiff_t pos;
|
||||
size_t len;
|
||||
int llen;
|
||||
struct stat sb;
|
||||
#ifdef NO_PATH_MAX
|
||||
size_t ldestlen = 0;
|
||||
#define pathlen sb.st_size
|
||||
#define pathcnd (ldestlen < (pathlen + 1))
|
||||
#else
|
||||
#define pathlen PATH_MAX
|
||||
#define pathcnd (!ldest)
|
||||
#endif
|
||||
/* max. recursion depth */
|
||||
int symlinks = 32;
|
||||
|
||||
if (upath[0] == '/') {
|
||||
/* upath is an absolute pathname */
|
||||
strdupx(ipath, upath, ATEMP);
|
||||
} else {
|
||||
/* upath is a relative pathname, prepend cwd */
|
||||
if ((tp = ksh_get_wd(NULL)) == NULL || tp[0] != '/')
|
||||
return (NULL);
|
||||
ipath = shf_smprintf("%s%s%s", tp, "/", upath);
|
||||
afree(tp, ATEMP);
|
||||
}
|
||||
|
||||
/* ipath and upath are in memory at the same time -> unchecked */
|
||||
Xinit(xs, xp, strlen(ip = ipath) + 1, ATEMP);
|
||||
|
||||
/* now jump into the deep of the loop */
|
||||
goto beginning_of_a_pathname;
|
||||
|
||||
while (*ip) {
|
||||
/* skip slashes in input */
|
||||
while (*ip == '/')
|
||||
++ip;
|
||||
if (!*ip)
|
||||
break;
|
||||
|
||||
/* get next pathname component from input */
|
||||
tp = ip;
|
||||
while (*ip && *ip != '/')
|
||||
++ip;
|
||||
len = ip - tp;
|
||||
|
||||
/* check input for "." and ".." */
|
||||
if (tp[0] == '.') {
|
||||
if (len == 1)
|
||||
/* just continue with the next one */
|
||||
continue;
|
||||
else if (len == 2 && tp[1] == '.') {
|
||||
/* strip off last pathname component */
|
||||
while (xp > Xstring(xs, xp))
|
||||
if (*--xp == '/')
|
||||
break;
|
||||
/* then continue with the next one */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* store output position away, then append slash to output */
|
||||
pos = Xsavepos(xs, xp);
|
||||
/* 1 for the '/' and len + 1 for tp and the NUL from below */
|
||||
XcheckN(xs, xp, 1 + len + 1);
|
||||
Xput(xs, xp, '/');
|
||||
|
||||
/* append next pathname component to output */
|
||||
memcpy(xp, tp, len);
|
||||
xp += len;
|
||||
*xp = '\0';
|
||||
|
||||
/* lstat the current output, see if it's a symlink */
|
||||
if (lstat(Xstring(xs, xp), &sb)) {
|
||||
/* lstat failed */
|
||||
if (errno == ENOENT) {
|
||||
/* because the pathname does not exist */
|
||||
while (*ip == '/')
|
||||
/* skip any trailing slashes */
|
||||
++ip;
|
||||
/* no more components left? */
|
||||
if (!*ip)
|
||||
/* we can still return successfully */
|
||||
break;
|
||||
/* more components left? fall through */
|
||||
}
|
||||
/* not ENOENT or not at the end of ipath */
|
||||
goto notfound;
|
||||
}
|
||||
|
||||
/* check if we encountered a symlink? */
|
||||
if (S_ISLNK(sb.st_mode)) {
|
||||
/* reached maximum recursion depth? */
|
||||
if (!symlinks--) {
|
||||
/* yep, prevent infinite loops */
|
||||
errno = ELOOP;
|
||||
goto notfound;
|
||||
}
|
||||
|
||||
/* get symlink(7) target */
|
||||
if (pathcnd) {
|
||||
#ifdef NO_PATH_MAX
|
||||
if (notoktoadd(pathlen, 1)) {
|
||||
errno = ENAMETOOLONG;
|
||||
goto notfound;
|
||||
}
|
||||
#endif
|
||||
ldest = aresize(ldest, pathlen + 1, ATEMP);
|
||||
}
|
||||
llen = readlink(Xstring(xs, xp), ldest, pathlen);
|
||||
if (llen < 0)
|
||||
/* oops... */
|
||||
goto notfound;
|
||||
ldest[llen] = '\0';
|
||||
|
||||
/*
|
||||
* restart if symlink target is an absolute path,
|
||||
* otherwise continue with currently resolved prefix
|
||||
*/
|
||||
/* append rest of current input path to link target */
|
||||
tp = shf_smprintf("%s%s%s", ldest, *ip ? "/" : "", ip);
|
||||
afree(ipath, ATEMP);
|
||||
ip = ipath = tp;
|
||||
if (ldest[0] != '/') {
|
||||
/* symlink target is a relative path */
|
||||
xp = Xrestpos(xs, xp, pos);
|
||||
} else {
|
||||
/* symlink target is an absolute path */
|
||||
xp = Xstring(xs, xp);
|
||||
beginning_of_a_pathname:
|
||||
/* assert: (ip == ipath)[0] == '/' */
|
||||
/* assert: xp == xs.beg => start of path */
|
||||
|
||||
if (ip[1] == '/' && ip[2] != '/') {
|
||||
/* keep UNC names, per POSIX */
|
||||
Xput(xs, xp, '/');
|
||||
}
|
||||
}
|
||||
}
|
||||
/* otherwise (no symlink) merely go on */
|
||||
}
|
||||
|
||||
/*
|
||||
* either found the target and successfully resolved it,
|
||||
* or found its parent directory and may create it
|
||||
*/
|
||||
if (Xlength(xs, xp) == 0)
|
||||
/*
|
||||
* if the resolved pathname is "", make it "/",
|
||||
* otherwise do not add a trailing slash
|
||||
*/
|
||||
Xput(xs, xp, '/');
|
||||
Xput(xs, xp, '\0');
|
||||
|
||||
/*
|
||||
* if source path had a trailing slash, check if target path
|
||||
* is not a non-directory existing file
|
||||
*/
|
||||
if (ip > ipath && ip[-1] == '/') {
|
||||
if (stat(Xstring(xs, xp), &sb)) {
|
||||
if (errno != ENOENT)
|
||||
goto notfound;
|
||||
} else if (!S_ISDIR(sb.st_mode)) {
|
||||
errno = ENOTDIR;
|
||||
goto notfound;
|
||||
}
|
||||
/* target now either does not exist or is a directory */
|
||||
}
|
||||
|
||||
/* return target path */
|
||||
if (ldest != NULL)
|
||||
afree(ldest, ATEMP);
|
||||
afree(ipath, ATEMP);
|
||||
return (Xclose(xs, xp));
|
||||
|
||||
notfound:
|
||||
/* save; freeing memory might trash it */
|
||||
llen = errno;
|
||||
if (ldest != NULL)
|
||||
afree(ldest, ATEMP);
|
||||
afree(ipath, ATEMP);
|
||||
Xfree(xs, xp);
|
||||
errno = llen;
|
||||
return (NULL);
|
||||
|
||||
#undef pathlen
|
||||
#undef pathcnd
|
||||
}
|
||||
|
||||
int
|
||||
c_cd(const char **wp)
|
||||
{
|
||||
int optc, rv, phys_path;
|
||||
bool physical = tobool(Flag(FPHYSICAL));
|
||||
/* was a node from cdpath added in? */
|
||||
int cdnode;
|
||||
/* print where we cd'd? */
|
||||
bool printpath = false;
|
||||
struct tbl *pwd_s, *oldpwd_s;
|
||||
XString xs;
|
||||
char *dir, *allocd = NULL, *tryp, *pwd, *cdpath;
|
||||
|
||||
while ((optc = ksh_getopt(wp, &builtin_opt, "LP")) != -1)
|
||||
switch (optc) {
|
||||
case 'L':
|
||||
physical = false;
|
||||
break;
|
||||
case 'P':
|
||||
physical = true;
|
||||
break;
|
||||
case '?':
|
||||
return (1);
|
||||
}
|
||||
wp += builtin_opt.optind;
|
||||
|
||||
if (Flag(FRESTRICTED)) {
|
||||
bi_errorf("restricted shell - can't cd");
|
||||
return (1);
|
||||
}
|
||||
|
||||
pwd_s = global("PWD");
|
||||
oldpwd_s = global("OLDPWD");
|
||||
|
||||
if (!wp[0]) {
|
||||
/* No arguments - go home */
|
||||
if ((dir = str_val(global("HOME"))) == null) {
|
||||
bi_errorf("no home directory (HOME not set)");
|
||||
return (1);
|
||||
}
|
||||
} else if (!wp[1]) {
|
||||
/* One argument: - or dir */
|
||||
strdupx(allocd, wp[0], ATEMP);
|
||||
if (ksh_isdash((dir = allocd))) {
|
||||
afree(allocd, ATEMP);
|
||||
allocd = NULL;
|
||||
dir = str_val(oldpwd_s);
|
||||
if (dir == null) {
|
||||
bi_errorf("no OLDPWD");
|
||||
return (1);
|
||||
}
|
||||
printpath = true;
|
||||
}
|
||||
} else if (!wp[2]) {
|
||||
/* Two arguments - substitute arg1 in PWD for arg2 */
|
||||
size_t ilen, olen, nlen, elen;
|
||||
char *cp;
|
||||
|
||||
if (!current_wd[0]) {
|
||||
bi_errorf("can't determine current directory");
|
||||
return (1);
|
||||
}
|
||||
/*
|
||||
* substitute arg1 for arg2 in current path.
|
||||
* if the first substitution fails because the cd fails
|
||||
* we could try to find another substitution. For now
|
||||
* we don't
|
||||
*/
|
||||
if ((cp = strstr(current_wd, wp[0])) == NULL) {
|
||||
bi_errorf("bad substitution");
|
||||
return (1);
|
||||
}
|
||||
/*-
|
||||
* ilen = part of current_wd before wp[0]
|
||||
* elen = part of current_wd after wp[0]
|
||||
* because current_wd and wp[1] need to be in memory at the
|
||||
* same time beforehand the addition can stay unchecked
|
||||
*/
|
||||
ilen = cp - current_wd;
|
||||
olen = strlen(wp[0]);
|
||||
nlen = strlen(wp[1]);
|
||||
elen = strlen(current_wd + ilen + olen) + 1;
|
||||
dir = allocd = alloc(ilen + nlen + elen, ATEMP);
|
||||
memcpy(dir, current_wd, ilen);
|
||||
memcpy(dir + ilen, wp[1], nlen);
|
||||
memcpy(dir + ilen + nlen, current_wd + ilen + olen, elen);
|
||||
printpath = true;
|
||||
} else {
|
||||
bi_errorf("too many arguments");
|
||||
return (1);
|
||||
}
|
||||
|
||||
#ifdef NO_PATH_MAX
|
||||
/* only a first guess; make_path will enlarge xs if necessary */
|
||||
XinitN(xs, 1024, ATEMP);
|
||||
#else
|
||||
XinitN(xs, PATH_MAX, ATEMP);
|
||||
#endif
|
||||
|
||||
cdpath = str_val(global("CDPATH"));
|
||||
do {
|
||||
cdnode = make_path(current_wd, dir, &cdpath, &xs, &phys_path);
|
||||
if (physical)
|
||||
rv = chdir(tryp = Xstring(xs, xp) + phys_path);
|
||||
else {
|
||||
simplify_path(Xstring(xs, xp));
|
||||
rv = chdir(tryp = Xstring(xs, xp));
|
||||
}
|
||||
} while (rv < 0 && cdpath != NULL);
|
||||
|
||||
if (rv < 0) {
|
||||
if (cdnode)
|
||||
bi_errorf("%s: %s", dir, "bad directory");
|
||||
else
|
||||
bi_errorf("%s: %s", tryp, strerror(errno));
|
||||
afree(allocd, ATEMP);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* allocd (above) => dir, which is no longer used */
|
||||
afree(allocd, ATEMP);
|
||||
allocd = NULL;
|
||||
|
||||
/* Clear out tracked aliases with relative paths */
|
||||
flushcom(false);
|
||||
|
||||
/*
|
||||
* Set OLDPWD (note: unsetting OLDPWD does not disable this
|
||||
* setting in AT&T ksh)
|
||||
*/
|
||||
if (current_wd[0])
|
||||
/* Ignore failure (happens if readonly or integer) */
|
||||
setstr(oldpwd_s, current_wd, KSH_RETURN_ERROR);
|
||||
|
||||
if (Xstring(xs, xp)[0] != '/') {
|
||||
pwd = NULL;
|
||||
} else if (!physical || !(pwd = allocd = do_realpath(Xstring(xs, xp))))
|
||||
pwd = Xstring(xs, xp);
|
||||
|
||||
/* Set PWD */
|
||||
if (pwd) {
|
||||
char *ptmp = pwd;
|
||||
|
||||
set_current_wd(ptmp);
|
||||
/* Ignore failure (happens if readonly or integer) */
|
||||
setstr(pwd_s, ptmp, KSH_RETURN_ERROR);
|
||||
} else {
|
||||
set_current_wd(null);
|
||||
pwd = Xstring(xs, xp);
|
||||
/* XXX unset $PWD? */
|
||||
}
|
||||
if (printpath || cdnode)
|
||||
shprintf("%s\n", pwd);
|
||||
|
||||
afree(allocd, ATEMP);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
c_pwd(const char **wp)
|
||||
@ -587,7 +235,7 @@ c_pwd(const char **wp)
|
||||
current_wd) : NULL;
|
||||
if (p && access(p, R_OK) < 0)
|
||||
p = NULL;
|
||||
if (!p && !(p = allocd = ksh_get_wd(NULL))) {
|
||||
if (!p && !(p = allocd = ksh_get_wd())) {
|
||||
bi_errorf("%s: %s", "can't determine current directory",
|
||||
strerror(errno));
|
||||
return (1);
|
||||
|
420
misc.c
420
misc.c
@ -29,7 +29,7 @@
|
||||
#include <grp.h>
|
||||
#endif
|
||||
|
||||
__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.157 2011/03/17 22:09:22 tg Exp $");
|
||||
__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.158 2011/03/24 19:05:48 tg Exp $");
|
||||
|
||||
/* type bits for unsigned char */
|
||||
unsigned char chtypes[UCHAR_MAX + 1];
|
||||
@ -43,6 +43,9 @@ static const unsigned char *cclass(const unsigned char *, int);
|
||||
static void chvt(const char *);
|
||||
#endif
|
||||
|
||||
/*XXX this should go away */
|
||||
static int make_path(const char *, const char *, char **, XString *, int *);
|
||||
|
||||
#ifdef SETUID_CAN_FAIL_WITH_EAGAIN
|
||||
/* we don't need to check for other codes, EPERM won't happen */
|
||||
#define DO_SETUID(func, argvec) do { \
|
||||
@ -1204,31 +1207,221 @@ reset_nonblock(int fd)
|
||||
return (1);
|
||||
}
|
||||
|
||||
|
||||
/* Like getcwd(), except bsize is ignored if buf is 0 (PATH_MAX is used) */
|
||||
/* getcwd(3) equivalent, allocates from ATEMP but doesn't resize */
|
||||
char *
|
||||
ksh_get_wd(size_t *dlen)
|
||||
ksh_get_wd(void)
|
||||
{
|
||||
char *ret, *b;
|
||||
size_t len = 1;
|
||||
|
||||
#ifdef NO_PATH_MAX
|
||||
if ((b = get_current_dir_name())) {
|
||||
len = strlen(b) + 1;
|
||||
strndupx(ret, b, len - 1, ATEMP);
|
||||
free_gnu_gcdn(b);
|
||||
char *rv, *cp;
|
||||
|
||||
if ((cp = get_current_dir_name())) {
|
||||
strdupx(rv, cp, ATEMP);
|
||||
free_gnu_gcdn(cp);
|
||||
} else
|
||||
ret = NULL;
|
||||
rv = NULL;
|
||||
#else
|
||||
if ((ret = getcwd((b = alloc(PATH_MAX + 1, ATEMP)), PATH_MAX)))
|
||||
ret = aresize(b, len = (strlen(b) + 1), ATEMP);
|
||||
else
|
||||
afree(b, ATEMP);
|
||||
char *rv;
|
||||
|
||||
if (!getcwd((rv = alloc(PATH_MAX + 1, ATEMP)), PATH_MAX)) {
|
||||
afree(rv, ATEMP);
|
||||
rv = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (dlen)
|
||||
*dlen = len;
|
||||
return (ret);
|
||||
return (rv);
|
||||
}
|
||||
|
||||
char *
|
||||
do_realpath(const char *upath)
|
||||
{
|
||||
char *xp, *ip, *tp, *ipath, *ldest = NULL;
|
||||
XString xs;
|
||||
ptrdiff_t pos;
|
||||
size_t len;
|
||||
int llen;
|
||||
struct stat sb;
|
||||
#ifdef NO_PATH_MAX
|
||||
size_t ldestlen = 0;
|
||||
#define pathlen sb.st_size
|
||||
#define pathcnd (ldestlen < (pathlen + 1))
|
||||
#else
|
||||
#define pathlen PATH_MAX
|
||||
#define pathcnd (!ldest)
|
||||
#endif
|
||||
/* max. recursion depth */
|
||||
int symlinks = 32;
|
||||
|
||||
if (upath[0] == '/') {
|
||||
/* upath is an absolute pathname */
|
||||
strdupx(ipath, upath, ATEMP);
|
||||
} else {
|
||||
/* upath is a relative pathname, prepend cwd */
|
||||
if ((tp = ksh_get_wd()) == NULL || tp[0] != '/')
|
||||
return (NULL);
|
||||
ipath = shf_smprintf("%s%s%s", tp, "/", upath);
|
||||
afree(tp, ATEMP);
|
||||
}
|
||||
|
||||
/* ipath and upath are in memory at the same time -> unchecked */
|
||||
Xinit(xs, xp, strlen(ip = ipath) + 1, ATEMP);
|
||||
|
||||
/* now jump into the deep of the loop */
|
||||
goto beginning_of_a_pathname;
|
||||
|
||||
while (*ip) {
|
||||
/* skip slashes in input */
|
||||
while (*ip == '/')
|
||||
++ip;
|
||||
if (!*ip)
|
||||
break;
|
||||
|
||||
/* get next pathname component from input */
|
||||
tp = ip;
|
||||
while (*ip && *ip != '/')
|
||||
++ip;
|
||||
len = ip - tp;
|
||||
|
||||
/* check input for "." and ".." */
|
||||
if (tp[0] == '.') {
|
||||
if (len == 1)
|
||||
/* just continue with the next one */
|
||||
continue;
|
||||
else if (len == 2 && tp[1] == '.') {
|
||||
/* strip off last pathname component */
|
||||
while (xp > Xstring(xs, xp))
|
||||
if (*--xp == '/')
|
||||
break;
|
||||
/* then continue with the next one */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* store output position away, then append slash to output */
|
||||
pos = Xsavepos(xs, xp);
|
||||
/* 1 for the '/' and len + 1 for tp and the NUL from below */
|
||||
XcheckN(xs, xp, 1 + len + 1);
|
||||
Xput(xs, xp, '/');
|
||||
|
||||
/* append next pathname component to output */
|
||||
memcpy(xp, tp, len);
|
||||
xp += len;
|
||||
*xp = '\0';
|
||||
|
||||
/* lstat the current output, see if it's a symlink */
|
||||
if (lstat(Xstring(xs, xp), &sb)) {
|
||||
/* lstat failed */
|
||||
if (errno == ENOENT) {
|
||||
/* because the pathname does not exist */
|
||||
while (*ip == '/')
|
||||
/* skip any trailing slashes */
|
||||
++ip;
|
||||
/* no more components left? */
|
||||
if (!*ip)
|
||||
/* we can still return successfully */
|
||||
break;
|
||||
/* more components left? fall through */
|
||||
}
|
||||
/* not ENOENT or not at the end of ipath */
|
||||
goto notfound;
|
||||
}
|
||||
|
||||
/* check if we encountered a symlink? */
|
||||
if (S_ISLNK(sb.st_mode)) {
|
||||
/* reached maximum recursion depth? */
|
||||
if (!symlinks--) {
|
||||
/* yep, prevent infinite loops */
|
||||
errno = ELOOP;
|
||||
goto notfound;
|
||||
}
|
||||
|
||||
/* get symlink(7) target */
|
||||
if (pathcnd) {
|
||||
#ifdef NO_PATH_MAX
|
||||
if (notoktoadd(pathlen, 1)) {
|
||||
errno = ENAMETOOLONG;
|
||||
goto notfound;
|
||||
}
|
||||
#endif
|
||||
ldest = aresize(ldest, pathlen + 1, ATEMP);
|
||||
}
|
||||
llen = readlink(Xstring(xs, xp), ldest, pathlen);
|
||||
if (llen < 0)
|
||||
/* oops... */
|
||||
goto notfound;
|
||||
ldest[llen] = '\0';
|
||||
|
||||
/*
|
||||
* restart if symlink target is an absolute path,
|
||||
* otherwise continue with currently resolved prefix
|
||||
*/
|
||||
/* append rest of current input path to link target */
|
||||
tp = shf_smprintf("%s%s%s", ldest, *ip ? "/" : "", ip);
|
||||
afree(ipath, ATEMP);
|
||||
ip = ipath = tp;
|
||||
if (ldest[0] != '/') {
|
||||
/* symlink target is a relative path */
|
||||
xp = Xrestpos(xs, xp, pos);
|
||||
} else {
|
||||
/* symlink target is an absolute path */
|
||||
xp = Xstring(xs, xp);
|
||||
beginning_of_a_pathname:
|
||||
/* assert: (ip == ipath)[0] == '/' */
|
||||
/* assert: xp == xs.beg => start of path */
|
||||
|
||||
if (ip[1] == '/' && ip[2] != '/') {
|
||||
/* keep UNC names, per POSIX */
|
||||
Xput(xs, xp, '/');
|
||||
}
|
||||
}
|
||||
}
|
||||
/* otherwise (no symlink) merely go on */
|
||||
}
|
||||
|
||||
/*
|
||||
* either found the target and successfully resolved it,
|
||||
* or found its parent directory and may create it
|
||||
*/
|
||||
if (Xlength(xs, xp) == 0)
|
||||
/*
|
||||
* if the resolved pathname is "", make it "/",
|
||||
* otherwise do not add a trailing slash
|
||||
*/
|
||||
Xput(xs, xp, '/');
|
||||
Xput(xs, xp, '\0');
|
||||
|
||||
/*
|
||||
* if source path had a trailing slash, check if target path
|
||||
* is not a non-directory existing file
|
||||
*/
|
||||
if (ip > ipath && ip[-1] == '/') {
|
||||
if (stat(Xstring(xs, xp), &sb)) {
|
||||
if (errno != ENOENT)
|
||||
goto notfound;
|
||||
} else if (!S_ISDIR(sb.st_mode)) {
|
||||
errno = ENOTDIR;
|
||||
goto notfound;
|
||||
}
|
||||
/* target now either does not exist or is a directory */
|
||||
}
|
||||
|
||||
/* return target path */
|
||||
if (ldest != NULL)
|
||||
afree(ldest, ATEMP);
|
||||
afree(ipath, ATEMP);
|
||||
return (Xclose(xs, xp));
|
||||
|
||||
notfound:
|
||||
/* save; freeing memory might trash it */
|
||||
llen = errno;
|
||||
if (ldest != NULL)
|
||||
afree(ldest, ATEMP);
|
||||
afree(ipath, ATEMP);
|
||||
Xfree(xs, xp);
|
||||
errno = llen;
|
||||
return (NULL);
|
||||
|
||||
#undef pathlen
|
||||
#undef pathcnd
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1246,9 +1439,9 @@ ksh_get_wd(size_t *dlen)
|
||||
* The return value indicates whether a non-null element from cdpathp
|
||||
* was appended to result.
|
||||
*/
|
||||
int
|
||||
static int
|
||||
make_path(const char *cwd, const char *file,
|
||||
/* & of : separated list */
|
||||
/* pointer to colon-separated list */
|
||||
char **cdpathp,
|
||||
XString *xsp,
|
||||
int *phys_pathp)
|
||||
@ -1386,28 +1579,181 @@ simplify_path(char *pathl)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
set_current_wd(char *pathl)
|
||||
set_current_wd(char *nwd)
|
||||
{
|
||||
size_t len = 1;
|
||||
char *p = pathl;
|
||||
char *allocd = NULL;
|
||||
|
||||
if (p == NULL) {
|
||||
if ((p = ksh_get_wd(&len)) == NULL)
|
||||
p = null;
|
||||
} else
|
||||
len = strlen(p) + 1;
|
||||
|
||||
if (len > current_wd_size) {
|
||||
afree(current_wd, APERM);
|
||||
current_wd = alloc(current_wd_size = len, APERM);
|
||||
if (nwd == NULL) {
|
||||
allocd = ksh_get_wd();
|
||||
nwd = allocd ? allocd : null;
|
||||
}
|
||||
memcpy(current_wd, p, len);
|
||||
if (p != pathl && p != null)
|
||||
afree(p, ATEMP);
|
||||
|
||||
afree(current_wd, APERM);
|
||||
strdupx(current_wd, nwd, APERM);
|
||||
|
||||
afree(allocd, ATEMP);
|
||||
}
|
||||
|
||||
int
|
||||
c_cd(const char **wp)
|
||||
{
|
||||
int optc, rv, phys_path;
|
||||
bool physical = tobool(Flag(FPHYSICAL));
|
||||
/* was a node from cdpath added in? */
|
||||
int cdnode;
|
||||
/* print where we cd'd? */
|
||||
bool printpath = false;
|
||||
struct tbl *pwd_s, *oldpwd_s;
|
||||
XString xs;
|
||||
char *dir, *allocd = NULL, *tryp, *pwd, *cdpath;
|
||||
|
||||
while ((optc = ksh_getopt(wp, &builtin_opt, "LP")) != -1)
|
||||
switch (optc) {
|
||||
case 'L':
|
||||
physical = false;
|
||||
break;
|
||||
case 'P':
|
||||
physical = true;
|
||||
break;
|
||||
case '?':
|
||||
return (1);
|
||||
}
|
||||
wp += builtin_opt.optind;
|
||||
|
||||
if (Flag(FRESTRICTED)) {
|
||||
bi_errorf("restricted shell - can't cd");
|
||||
return (1);
|
||||
}
|
||||
|
||||
pwd_s = global("PWD");
|
||||
oldpwd_s = global("OLDPWD");
|
||||
|
||||
if (!wp[0]) {
|
||||
/* No arguments - go home */
|
||||
if ((dir = str_val(global("HOME"))) == null) {
|
||||
bi_errorf("no home directory (HOME not set)");
|
||||
return (1);
|
||||
}
|
||||
} else if (!wp[1]) {
|
||||
/* One argument: - or dir */
|
||||
strdupx(allocd, wp[0], ATEMP);
|
||||
if (ksh_isdash((dir = allocd))) {
|
||||
afree(allocd, ATEMP);
|
||||
allocd = NULL;
|
||||
dir = str_val(oldpwd_s);
|
||||
if (dir == null) {
|
||||
bi_errorf("no OLDPWD");
|
||||
return (1);
|
||||
}
|
||||
printpath = true;
|
||||
}
|
||||
} else if (!wp[2]) {
|
||||
/* Two arguments - substitute arg1 in PWD for arg2 */
|
||||
size_t ilen, olen, nlen, elen;
|
||||
char *cp;
|
||||
|
||||
if (!current_wd[0]) {
|
||||
bi_errorf("can't determine current directory");
|
||||
return (1);
|
||||
}
|
||||
/*
|
||||
* substitute arg1 for arg2 in current path.
|
||||
* if the first substitution fails because the cd fails
|
||||
* we could try to find another substitution. For now
|
||||
* we don't
|
||||
*/
|
||||
if ((cp = strstr(current_wd, wp[0])) == NULL) {
|
||||
bi_errorf("bad substitution");
|
||||
return (1);
|
||||
}
|
||||
/*-
|
||||
* ilen = part of current_wd before wp[0]
|
||||
* elen = part of current_wd after wp[0]
|
||||
* because current_wd and wp[1] need to be in memory at the
|
||||
* same time beforehand the addition can stay unchecked
|
||||
*/
|
||||
ilen = cp - current_wd;
|
||||
olen = strlen(wp[0]);
|
||||
nlen = strlen(wp[1]);
|
||||
elen = strlen(current_wd + ilen + olen) + 1;
|
||||
dir = allocd = alloc(ilen + nlen + elen, ATEMP);
|
||||
memcpy(dir, current_wd, ilen);
|
||||
memcpy(dir + ilen, wp[1], nlen);
|
||||
memcpy(dir + ilen + nlen, current_wd + ilen + olen, elen);
|
||||
printpath = true;
|
||||
} else {
|
||||
bi_errorf("too many arguments");
|
||||
return (1);
|
||||
}
|
||||
|
||||
#ifdef NO_PATH_MAX
|
||||
/* only a first guess; make_path will enlarge xs if necessary */
|
||||
XinitN(xs, 1024, ATEMP);
|
||||
#else
|
||||
XinitN(xs, PATH_MAX, ATEMP);
|
||||
#endif
|
||||
|
||||
cdpath = str_val(global("CDPATH"));
|
||||
do {
|
||||
cdnode = make_path(current_wd, dir, &cdpath, &xs, &phys_path);
|
||||
if (physical)
|
||||
rv = chdir(tryp = Xstring(xs, xp) + phys_path);
|
||||
else {
|
||||
simplify_path(Xstring(xs, xp));
|
||||
rv = chdir(tryp = Xstring(xs, xp));
|
||||
}
|
||||
} while (rv < 0 && cdpath != NULL);
|
||||
|
||||
if (rv < 0) {
|
||||
if (cdnode)
|
||||
bi_errorf("%s: %s", dir, "bad directory");
|
||||
else
|
||||
bi_errorf("%s: %s", tryp, strerror(errno));
|
||||
afree(allocd, ATEMP);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* allocd (above) => dir, which is no longer used */
|
||||
afree(allocd, ATEMP);
|
||||
allocd = NULL;
|
||||
|
||||
/* Clear out tracked aliases with relative paths */
|
||||
flushcom(false);
|
||||
|
||||
/*
|
||||
* Set OLDPWD (note: unsetting OLDPWD does not disable this
|
||||
* setting in AT&T ksh)
|
||||
*/
|
||||
if (current_wd[0])
|
||||
/* Ignore failure (happens if readonly or integer) */
|
||||
setstr(oldpwd_s, current_wd, KSH_RETURN_ERROR);
|
||||
|
||||
if (Xstring(xs, xp)[0] != '/') {
|
||||
pwd = NULL;
|
||||
} else if (!physical || !(pwd = allocd = do_realpath(Xstring(xs, xp))))
|
||||
pwd = Xstring(xs, xp);
|
||||
|
||||
/* Set PWD */
|
||||
if (pwd) {
|
||||
char *ptmp = pwd;
|
||||
|
||||
set_current_wd(ptmp);
|
||||
/* Ignore failure (happens if readonly or integer) */
|
||||
setstr(pwd_s, ptmp, KSH_RETURN_ERROR);
|
||||
} else {
|
||||
set_current_wd(null);
|
||||
pwd = Xstring(xs, xp);
|
||||
/* XXX unset $PWD? */
|
||||
}
|
||||
if (printpath || cdnode)
|
||||
shprintf("%s\n", pwd);
|
||||
|
||||
afree(allocd, ATEMP);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
#ifdef TIOCSCTTY
|
||||
extern void chvt_reinit(void);
|
||||
|
||||
|
8
sh.h
8
sh.h
@ -154,7 +154,7 @@
|
||||
#endif
|
||||
|
||||
#ifdef EXTERN
|
||||
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.451 2011/03/23 18:47:07 tg Exp $");
|
||||
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.452 2011/03/24 19:05:49 tg Exp $");
|
||||
#endif
|
||||
#define MKSH_VERSION "R39 2011/03/23"
|
||||
|
||||
@ -1517,7 +1517,6 @@ int utf_wcwidth(unsigned int);
|
||||
#endif
|
||||
/* funcs.c */
|
||||
int c_hash(const char **);
|
||||
int c_cd(const char **);
|
||||
int c_pwd(const char **);
|
||||
int c_print(const char **);
|
||||
#ifdef MKSH_PRINTF_BUILTIN
|
||||
@ -1703,10 +1702,11 @@ void strip_nuls(char *, int);
|
||||
ssize_t blocking_read(int, char *, size_t)
|
||||
MKSH_A_BOUNDED(buffer, 2, 3);
|
||||
int reset_nonblock(int);
|
||||
char *ksh_get_wd(size_t *);
|
||||
int make_path(const char *, const char *, char **, XString *, int *);
|
||||
char *ksh_get_wd(void);
|
||||
char *do_realpath(const char *);
|
||||
void simplify_path(char *);
|
||||
void set_current_wd(char *);
|
||||
int c_cd(const char **);
|
||||
#ifdef MKSH_SMALL
|
||||
char *strdup_(const char *, Area *);
|
||||
char *strndup_(const char *, size_t, Area *);
|
||||
|
Loading…
x
Reference in New Issue
Block a user