1
0
Fork 0
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:
Johnothan King 2021-12-05 21:48:32 -08:00 committed by Martijn Dekker
parent a3f4b5efd1
commit cd8c48cc5a
5 changed files with 111 additions and 25 deletions

6
NEWS
View file

@ -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
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:
- Fixed a memory fault that occurred when a discipline function exited

View file

@ -20,8 +20,8 @@
***********************************************************************/
#pragma prototyped
/*
* cd [-LP] [dirname]
* cd [-LP] [old] [new]
* cd [-L] [-Pe] [dirname]
* cd [-L] [-Pe] [old] [new]
* pwd [-LP]
*
* David Korn
@ -57,33 +57,43 @@ int b_cd(int argc, char *argv[],Shbltin_t *context)
register const char *dp;
register Shell_t *shp = context->shp;
int saverrno=0;
int rval,flag=0;
int rval,pflag=0,eflag=0,ret=1;
char *oldpwd;
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)
{
case 'e':
eflag = 1;
break;
case 'L':
flag = 0;
pflag = 0;
break;
case 'P':
flag = 1;
pflag = 1;
break;
case ':':
if(sh_isoption(SH_RESTRICTED))
break;
errormsg(SH_DICT,2, "%s", opt_info.arg);
break;
case '?':
if(sh_isoption(SH_RESTRICTED))
break;
errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
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;
argc -= opt_info.index;
dir = argv[0];
if(error_info.errors>0 || argc >2)
if(error_info.errors>0 || argc>2)
{
errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
UNREACHABLE();
@ -106,7 +116,7 @@ int b_cd(int argc, char *argv[],Shbltin_t *context)
dir = nv_getval(opwdnod);
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();
}
/*
@ -179,7 +189,7 @@ int b_cd(int argc, char *argv[],Shbltin_t *context)
stakputs(last+PATH_OFFSET);
stakputc(0);
}
if(!flag)
if(!pflag)
{
register char *cp;
stakseek(PATH_MAX+PATH_OFFSET);
@ -200,19 +210,19 @@ int b_cd(int argc, char *argv[],Shbltin_t *context)
{
if(saverrno)
errno = saverrno;
errormsg(SH_DICT,ERROR_system(1),"%s:",dir);
errormsg(SH_DICT,ERROR_system(ret),"%s:",dir);
UNREACHABLE();
}
success:
if(dir == nv_getval(opwdnod) || argc==2)
dp = dir; /* print out directory for cd - */
if(flag)
if(pflag)
{
dir = stakptr(PATH_OFFSET);
if (!(dir=pathcanon(dir,PATH_PHYSICAL)))
{
dir = stakptr(PATH_OFFSET);
errormsg(SH_DICT,ERROR_system(1),"%s:",dir);
errormsg(SH_DICT,ERROR_system(ret),"%s:",dir);
UNREACHABLE();
}
stakseek(dir-stakptr(0));
@ -223,10 +233,10 @@ success:
nv_putval(opwdnod,oldpwd,NV_RDONLY);
if(*dir == '/')
{
flag = strlen(dir);
size_t len = strlen(dir);
/* delete trailing '/' */
while(--flag>0 && dir[flag]=='/')
dir[flag] = 0;
while(--len>0 && dir[len]=='/')
dir[len] = 0;
nv_putval(pwdnod,dir,NV_RDONLY);
nv_onattr(pwdnod,NV_EXPORT);
if(shp->pwd)
@ -243,13 +253,18 @@ success:
path_pwd(shp,0);
if(*shp->pwd != '/')
{
errormsg(SH_DICT,ERROR_system(1),e_direct);
errormsg(SH_DICT,ERROR_system(ret),e_direct);
UNREACHABLE();
}
}
nv_scan(sh_subtracktree(1),rehash,(void*)0,NV_TAGGED,NV_TAGGED);
path_newdir(shp,shp->pathlist);
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);
}

View file

@ -441,7 +441,7 @@ const char sh_optbuiltin[] =
;
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 "]"
"[+NAME?cd - change working directory ]"
"[+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 "
"that does not contain symbolic link components and symbolic 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[directory]\n"
"old new\n"
"\n"
"[+EXIT STATUS?]{"
"[+0?Directory successfully changed.]"
"[+>0?An error occurred.]"
"[+0?Directory successfully changed and the \bPWD\b is correct.]"
"[+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)]"
;

View file

@ -5772,9 +5772,9 @@ and invokes this function with an argument of
.BR 0 .
.TP
.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
\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
This command can be in either of two forms.
In the first form it
@ -5846,6 +5846,20 @@ or
on the command line
determines which method is used.
.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
.B cd\^
command may not be executed by

View file

@ -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'
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))