mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-03-09 15:50:02 +00:00
Add the '-e' flag to the 'cd' builtin (#358)
This change adds the -e flag to the cd builtin, as specified in <https://www.austingroupbugs.net/view.php?id=253>. The -e flag is used to verify if the the current working directory after 'cd -P' successfully changes the directory, and returns with exit status 1 if the cwd couldn't be determined. Additionally, it causes all other errors to return with exit status >1 (i.e., status 2 unless ENOMEM occurs) if -e and -P are both active. src/cmd/ksh93/bltins/cd_pwd.c: - Add -e option to the cd builtin command. It verifies $PWD by using test_inode() to execute the equivalent of [[ . -ef $PWD ]]. - The check for restricted mode has been moved after optget to allow 'cd -eP' to return with exit status 2 when in restricted mode. To avoid changing the previous behavior of cd when -e isn't passed, extra checks have been added to prevent cd from printing usage information in restricted mode. src/cmd/ksh93/tests/builtins.sh: - Add regression tests for the exit status when using the cd -P flag with and without -e. src/cmd/ksh93/data/builtins.c, src/cmd/ksh93/sh.1: - Document the addition of -e to the cd builtin.
This commit is contained in:
parent
a3f4b5efd1
commit
cd8c48cc5a
5 changed files with 111 additions and 25 deletions
6
NEWS
6
NEWS
|
@ -8,6 +8,12 @@ Any uppercase BUG_* names are modernish shell bug IDs.
|
||||||
- Fixed an issue on illumos that caused some parameters in the getconf
|
- Fixed an issue on illumos that caused some parameters in the getconf
|
||||||
builtin to fail.
|
builtin to fail.
|
||||||
|
|
||||||
|
- The cd built-in command now supports a -e option (as specified in
|
||||||
|
https://www.austingroupbugs.net/view.php?id=253). Passing -e alongside -P
|
||||||
|
is used to guarantee the cd built-in returns with exit status 1 if the
|
||||||
|
current working directory couldn't be determined after successfully changing
|
||||||
|
the directory.
|
||||||
|
|
||||||
2021-12-01:
|
2021-12-01:
|
||||||
|
|
||||||
- Fixed a memory fault that occurred when a discipline function exited
|
- Fixed a memory fault that occurred when a discipline function exited
|
||||||
|
|
|
@ -20,8 +20,8 @@
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
#pragma prototyped
|
#pragma prototyped
|
||||||
/*
|
/*
|
||||||
* cd [-LP] [dirname]
|
* cd [-L] [-Pe] [dirname]
|
||||||
* cd [-LP] [old] [new]
|
* cd [-L] [-Pe] [old] [new]
|
||||||
* pwd [-LP]
|
* pwd [-LP]
|
||||||
*
|
*
|
||||||
* David Korn
|
* David Korn
|
||||||
|
@ -57,29 +57,39 @@ int b_cd(int argc, char *argv[],Shbltin_t *context)
|
||||||
register const char *dp;
|
register const char *dp;
|
||||||
register Shell_t *shp = context->shp;
|
register Shell_t *shp = context->shp;
|
||||||
int saverrno=0;
|
int saverrno=0;
|
||||||
int rval,flag=0;
|
int rval,pflag=0,eflag=0,ret=1;
|
||||||
char *oldpwd;
|
char *oldpwd;
|
||||||
Namval_t *opwdnod, *pwdnod;
|
Namval_t *opwdnod, *pwdnod;
|
||||||
if(sh_isoption(SH_RESTRICTED))
|
|
||||||
{
|
|
||||||
errormsg(SH_DICT,ERROR_exit(1),e_restricted+4);
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
while((rval = optget(argv,sh_optcd))) switch(rval)
|
while((rval = optget(argv,sh_optcd))) switch(rval)
|
||||||
{
|
{
|
||||||
|
case 'e':
|
||||||
|
eflag = 1;
|
||||||
|
break;
|
||||||
case 'L':
|
case 'L':
|
||||||
flag = 0;
|
pflag = 0;
|
||||||
break;
|
break;
|
||||||
case 'P':
|
case 'P':
|
||||||
flag = 1;
|
pflag = 1;
|
||||||
break;
|
break;
|
||||||
case ':':
|
case ':':
|
||||||
|
if(sh_isoption(SH_RESTRICTED))
|
||||||
|
break;
|
||||||
errormsg(SH_DICT,2, "%s", opt_info.arg);
|
errormsg(SH_DICT,2, "%s", opt_info.arg);
|
||||||
break;
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
|
if(sh_isoption(SH_RESTRICTED))
|
||||||
|
break;
|
||||||
errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
|
errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
if(pflag && eflag)
|
||||||
|
ret = 2; /* exit status is 2 if -eP are both on and chdir failed */
|
||||||
|
if(sh_isoption(SH_RESTRICTED))
|
||||||
|
{
|
||||||
|
/* restricted shells cannot change the directory */
|
||||||
|
errormsg(SH_DICT,ERROR_exit(ret),e_restricted+4);
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
argv += opt_info.index;
|
argv += opt_info.index;
|
||||||
argc -= opt_info.index;
|
argc -= opt_info.index;
|
||||||
dir = argv[0];
|
dir = argv[0];
|
||||||
|
@ -106,7 +116,7 @@ int b_cd(int argc, char *argv[],Shbltin_t *context)
|
||||||
dir = nv_getval(opwdnod);
|
dir = nv_getval(opwdnod);
|
||||||
if(!dir || *dir==0)
|
if(!dir || *dir==0)
|
||||||
{
|
{
|
||||||
errormsg(SH_DICT,ERROR_exit(1),argc==2?e_subst+4:e_direct);
|
errormsg(SH_DICT,ERROR_exit(ret),argc==2?e_subst+4:e_direct);
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
@ -179,7 +189,7 @@ int b_cd(int argc, char *argv[],Shbltin_t *context)
|
||||||
stakputs(last+PATH_OFFSET);
|
stakputs(last+PATH_OFFSET);
|
||||||
stakputc(0);
|
stakputc(0);
|
||||||
}
|
}
|
||||||
if(!flag)
|
if(!pflag)
|
||||||
{
|
{
|
||||||
register char *cp;
|
register char *cp;
|
||||||
stakseek(PATH_MAX+PATH_OFFSET);
|
stakseek(PATH_MAX+PATH_OFFSET);
|
||||||
|
@ -200,19 +210,19 @@ int b_cd(int argc, char *argv[],Shbltin_t *context)
|
||||||
{
|
{
|
||||||
if(saverrno)
|
if(saverrno)
|
||||||
errno = saverrno;
|
errno = saverrno;
|
||||||
errormsg(SH_DICT,ERROR_system(1),"%s:",dir);
|
errormsg(SH_DICT,ERROR_system(ret),"%s:",dir);
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
success:
|
success:
|
||||||
if(dir == nv_getval(opwdnod) || argc==2)
|
if(dir == nv_getval(opwdnod) || argc==2)
|
||||||
dp = dir; /* print out directory for cd - */
|
dp = dir; /* print out directory for cd - */
|
||||||
if(flag)
|
if(pflag)
|
||||||
{
|
{
|
||||||
dir = stakptr(PATH_OFFSET);
|
dir = stakptr(PATH_OFFSET);
|
||||||
if (!(dir=pathcanon(dir,PATH_PHYSICAL)))
|
if (!(dir=pathcanon(dir,PATH_PHYSICAL)))
|
||||||
{
|
{
|
||||||
dir = stakptr(PATH_OFFSET);
|
dir = stakptr(PATH_OFFSET);
|
||||||
errormsg(SH_DICT,ERROR_system(1),"%s:",dir);
|
errormsg(SH_DICT,ERROR_system(ret),"%s:",dir);
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
stakseek(dir-stakptr(0));
|
stakseek(dir-stakptr(0));
|
||||||
|
@ -223,10 +233,10 @@ success:
|
||||||
nv_putval(opwdnod,oldpwd,NV_RDONLY);
|
nv_putval(opwdnod,oldpwd,NV_RDONLY);
|
||||||
if(*dir == '/')
|
if(*dir == '/')
|
||||||
{
|
{
|
||||||
flag = strlen(dir);
|
size_t len = strlen(dir);
|
||||||
/* delete trailing '/' */
|
/* delete trailing '/' */
|
||||||
while(--flag>0 && dir[flag]=='/')
|
while(--len>0 && dir[len]=='/')
|
||||||
dir[flag] = 0;
|
dir[len] = 0;
|
||||||
nv_putval(pwdnod,dir,NV_RDONLY);
|
nv_putval(pwdnod,dir,NV_RDONLY);
|
||||||
nv_onattr(pwdnod,NV_EXPORT);
|
nv_onattr(pwdnod,NV_EXPORT);
|
||||||
if(shp->pwd)
|
if(shp->pwd)
|
||||||
|
@ -243,13 +253,18 @@ success:
|
||||||
path_pwd(shp,0);
|
path_pwd(shp,0);
|
||||||
if(*shp->pwd != '/')
|
if(*shp->pwd != '/')
|
||||||
{
|
{
|
||||||
errormsg(SH_DICT,ERROR_system(1),e_direct);
|
errormsg(SH_DICT,ERROR_system(ret),e_direct);
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nv_scan(sh_subtracktree(1),rehash,(void*)0,NV_TAGGED,NV_TAGGED);
|
nv_scan(sh_subtracktree(1),rehash,(void*)0,NV_TAGGED,NV_TAGGED);
|
||||||
path_newdir(shp,shp->pathlist);
|
path_newdir(shp,shp->pathlist);
|
||||||
path_newdir(shp,shp->cdpathlist);
|
path_newdir(shp,shp->cdpathlist);
|
||||||
|
if(pflag && eflag)
|
||||||
|
{
|
||||||
|
/* Verify the current working directory matches $PWD */
|
||||||
|
return(!test_inode(e_dot,nv_getval(pwdnod)));
|
||||||
|
}
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -441,7 +441,7 @@ const char sh_optbuiltin[] =
|
||||||
;
|
;
|
||||||
|
|
||||||
const char sh_optcd[] =
|
const char sh_optcd[] =
|
||||||
"[-1c?\n@(#)$Id: cd (ksh 93u+m) 2021-01-19 $\n]"
|
"[-1c?\n@(#)$Id: cd (ksh 93u+m) 2021-12-02 $\n]"
|
||||||
"[--catalog?" SH_DICT "]"
|
"[--catalog?" SH_DICT "]"
|
||||||
"[+NAME?cd - change working directory ]"
|
"[+NAME?cd - change working directory ]"
|
||||||
"[+DESCRIPTION?\bcd\b changes the current working directory of the "
|
"[+DESCRIPTION?\bcd\b changes the current working directory of the "
|
||||||
|
@ -482,13 +482,22 @@ const char sh_optcd[] =
|
||||||
"[P?The present working directory is first converted to an absolute pathname "
|
"[P?The present working directory is first converted to an absolute pathname "
|
||||||
"that does not contain symbolic link components and symbolic name "
|
"that does not contain symbolic link components and symbolic name "
|
||||||
"components are expanded in the resulting directory name.]"
|
"components are expanded in the resulting directory name.]"
|
||||||
|
"[e?If the \b-P\b option is in effect and the correct \bPWD\b cannot be "
|
||||||
|
"determined, exit with status 1. All other errors encountered while "
|
||||||
|
"both \b-e\b and \b-P\b are active result in exit status >1 (i.e., "
|
||||||
|
"exit status 2 unless an out of memory error occurred).]"
|
||||||
"\n"
|
"\n"
|
||||||
"\n[directory]\n"
|
"\n[directory]\n"
|
||||||
"old new\n"
|
"old new\n"
|
||||||
"\n"
|
"\n"
|
||||||
"[+EXIT STATUS?]{"
|
"[+EXIT STATUS?]{"
|
||||||
"[+0?Directory successfully changed.]"
|
"[+0?Directory successfully changed and the \bPWD\b is correct.]"
|
||||||
"[+>0?An error occurred.]"
|
"[+0?Directory successfully changed, the \bPWD\b couldn't be obtained "
|
||||||
|
"and a combination of \b-eP\b is not active.]"
|
||||||
|
"[+>0?An error occurred and a combination of \b-eP\b is not active.]"
|
||||||
|
"[+1?Directory successfully changed, the \bPWD\b couldn't be obtained "
|
||||||
|
"and a combination of \b-eP\b is active.]"
|
||||||
|
"[+>1?An error occurred and a combination of \b-eP\b is active.]"
|
||||||
"}"
|
"}"
|
||||||
"[+SEE ALSO?\bpwd\b(1), \bgetconf\b(1)]"
|
"[+SEE ALSO?\bpwd\b(1), \bgetconf\b(1)]"
|
||||||
;
|
;
|
||||||
|
|
|
@ -5772,9 +5772,9 @@ and invokes this function with an argument of
|
||||||
.BR 0 .
|
.BR 0 .
|
||||||
.TP
|
.TP
|
||||||
.PD 0
|
.PD 0
|
||||||
\f3cd\fP \*(OK \f3\-LP\fP \*(CK \*(OK \f2arg\^\fP \*(CK
|
\f3cd\fP \*(OK \f3\-L\fP \*(CK \*(OK \f3-eP\fP \*(CK \*(OK \f2arg\^\fP \*(CK
|
||||||
.TP
|
.TP
|
||||||
\f3cd\fP \*(OK \f3\-LP\fP \*(CK \f2old\^\fP \f2new\^\fP
|
\f3cd\fP \*(OK \f3\-L\fP \*(CK \*(OK \f3-eP\fP \*(CK \f2old\^\fP \f2new\^\fP
|
||||||
.PD
|
.PD
|
||||||
This command can be in either of two forms.
|
This command can be in either of two forms.
|
||||||
In the first form it
|
In the first form it
|
||||||
|
@ -5846,6 +5846,20 @@ or
|
||||||
on the command line
|
on the command line
|
||||||
determines which method is used.
|
determines which method is used.
|
||||||
.sp .5
|
.sp .5
|
||||||
|
If
|
||||||
|
.B \-e
|
||||||
|
and
|
||||||
|
.B \-P
|
||||||
|
are both in effect and the correct
|
||||||
|
.BR PWD
|
||||||
|
could not be determined after successfully changing the directory,
|
||||||
|
.B cd
|
||||||
|
will return with exit status one and produce no output.
|
||||||
|
If any other error occurs while both flags are active,
|
||||||
|
the exit status is greater than one.
|
||||||
|
This means the exit status is effectively
|
||||||
|
two unless an out of memory error occurs.
|
||||||
|
.sp .5
|
||||||
The
|
The
|
||||||
.B cd\^
|
.B cd\^
|
||||||
command may not be executed by
|
command may not be executed by
|
||||||
|
|
|
@ -1354,5 +1354,47 @@ if builtin rm 2> /dev/null; then
|
||||||
[[ -f $tmp/nonemptydir2/shouldexist || -d $tmp/nonemptydir2 ]] && err_exit 'rm builtin fails to remove all folders and files with -rd options'
|
[[ -f $tmp/nonemptydir2/shouldexist || -d $tmp/nonemptydir2 ]] && err_exit 'rm builtin fails to remove all folders and files with -rd options'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# ======
|
||||||
|
# These are regression tests for the cd command's -e and -P flags
|
||||||
|
mkdir -p "$tmp/failpwd1"
|
||||||
|
cd "$tmp/failpwd1"
|
||||||
|
rmdir ../failpwd1
|
||||||
|
cd -P .
|
||||||
|
got=$?; exp=0
|
||||||
|
(( got == exp )) || err_exit "cd -P without -e exits with error status if \$PWD doesn't exist (expected $exp, got $got)"
|
||||||
|
cd -eP .
|
||||||
|
got=$?; exp=1
|
||||||
|
(( got == exp )) || err_exit "cd -eP doesn't fail if \$PWD doesn't exist (expected $exp, got $got)"
|
||||||
|
cd "$tmp"
|
||||||
|
cd -P "$tmp/notadir" >/dev/null 2>&1
|
||||||
|
got=$?; exp=1
|
||||||
|
(( got == exp )) || err_exit "cd -P without -e fails with wrong exit status on nonexistent dir (expected $exp, got $got)"
|
||||||
|
cd -eP "$tmp/notadir" >/dev/null 2>&1
|
||||||
|
got=$?; exp=2
|
||||||
|
(( got == exp )) || err_exit "cd -eP fails with wrong exit status on nonexistent dir (expected $exp, got $got)"
|
||||||
|
OLDPWD="$tmp/baddir"
|
||||||
|
cd -P - >/dev/null 2>&1
|
||||||
|
got=$?; exp=1
|
||||||
|
(( got == exp )) || err_exit "cd -P without -e fails with wrong exit status on \$OLDPWD (expected $exp, got $got)"
|
||||||
|
cd -eP - >/dev/null 2>&1
|
||||||
|
got=$?; exp=2
|
||||||
|
(( got == exp )) || err_exit "cd -eP fails with wrong exit status on \$OLDPWD (expected $exp, got $got)"
|
||||||
|
cd "$tmp" || err_exit "couldn't change directory from nonexistent dir"
|
||||||
|
(set -o restricted; cd -P /) >/dev/null 2>&1
|
||||||
|
got=$?; exp=1
|
||||||
|
(( got == exp )) || err_exit "cd -P in restricted shell has wrong exit status (expected $exp, got $got)"
|
||||||
|
(set -o restricted; cd -eP /) >/dev/null 2>&1
|
||||||
|
got=$?; exp=2
|
||||||
|
(( got == exp )) || err_exit "cd -eP in restricted shell has wrong exit status (expected $exp, got $got)"
|
||||||
|
(set -o restricted; cd -?) >/dev/null 2>&1
|
||||||
|
got=$?; exp=1
|
||||||
|
(( got == exp )) || err_exit "cd -? shows usage info in restricted shell and has wrong exit status (expected $exp, got $got)"
|
||||||
|
(cd -P '') >/dev/null 2>&1
|
||||||
|
got=$?; exp=1
|
||||||
|
(( got == exp )) || err_exit "cd -P to empty string has wrong exit status (expected $exp, got $got)"
|
||||||
|
(cd -eP '') >/dev/null 2>&1
|
||||||
|
got=$?; exp=2
|
||||||
|
(( got == exp )) || err_exit "cd -eP to empty string has wrong exit status (expected $exp, got $got)"
|
||||||
|
|
||||||
# ======
|
# ======
|
||||||
exit $((Errors<125?Errors:125))
|
exit $((Errors<125?Errors:125))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue