diff --git a/NEWS b/NEWS index 81c063c046d0..08c0c6c039ab 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,13 @@ This documents significant changes in the dev branch of ksh 93u+m. For full details, see the git log at: https://github.com/ksh93/ksh Uppercase BUG_* IDs are shell bug IDs as used by the Modernish shell library. +2025-06-25: + +- [v1.1] Backported 'builtin -p' and 'umask -p' from ksh93v-, which + can be used to print reinputtable commands for recreating the builtin + table state and umask. +- [v1.1] Backported 'trap -l' from ksh93v- for listing signals. + 2025-06-14: - Fixed a bug occurring on systems with posix_spawn(3), spawnve(2), and diff --git a/src/cmd/ksh93/bltins/trap.c b/src/cmd/ksh93/bltins/trap.c index cf06556aadc0..a2a89ee5af8e 100644 --- a/src/cmd/ksh93/bltins/trap.c +++ b/src/cmd/ksh93/bltins/trap.c @@ -16,7 +16,7 @@ * * ***********************************************************************/ /* - * trap [-p] action sig... + * trap [-lp] action sig... * kill [-lL] [sig...] * kill [-n signum] [-s signame] pid... * stop job... @@ -44,11 +44,14 @@ static void sig_list(int); int b_trap(int argc,char *argv[],Shbltin_t *context) { char *arg = argv[1]; - int sig, clear = 0, dflag = 0, pflag = 0; + int sig, clear = 0, dflag = 0, lflag = 0, pflag = 0; NOT_USED(argc); NOT_USED(context); while (sig = optget(argv, sh_opttrap)) switch (sig) { + case 'l': + lflag=1; + break; case 'p': pflag=1; break; @@ -66,6 +69,11 @@ int b_trap(int argc,char *argv[],Shbltin_t *context) errormsg(SH_DICT,ERROR_usage(2),"%s", optusage(NULL)); UNREACHABLE(); } + if(lflag) + { + sig_list(-1); + return(0); + } if(arg = *argv) { char *action = arg; diff --git a/src/cmd/ksh93/bltins/typeset.c b/src/cmd/ksh93/bltins/typeset.c index bb5a2e8ea4f4..b15e13cb8d1c 100644 --- a/src/cmd/ksh93/bltins/typeset.c +++ b/src/cmd/ksh93/bltins/typeset.c @@ -30,7 +30,7 @@ * alias [-ptx] [arg...] * unalias [-a] [arg...] * hash [-r] [utility...] - * builtin [-dls] [-f file] [name...] + * builtin [-dlps] [-f file] [name...] * set [options] [name...] * unset [-fnv] [name...] * @@ -167,7 +167,7 @@ int b_alias(int argc,char *argv[],Shbltin_t *context) xflag = 1; break; case 'r': - rflag=1; + rflag = 1; break; case ':': if(sh.shcomp) @@ -1131,7 +1131,7 @@ int b_builtin(int argc,char *argv[],Shbltin_t *context) char *arg=0, *name; int n, r=0, flag=0; Namval_t *np; - long dlete=0; + int dlete=0; struct tdata tdata; Shbltin_f addr; Stk_t *stkp; @@ -1166,6 +1166,9 @@ int b_builtin(int argc,char *argv[],Shbltin_t *context) list = 1; #endif break; + case 'p': + tdata.prefix = argv[0]; + break; case ':': errormsg(SH_DICT,2, "%s", opt_info.arg); break; @@ -1209,6 +1212,11 @@ int b_builtin(int argc,char *argv[],Shbltin_t *context) #endif /* SHOPT_DYNAMIC */ if(*argv==0 && !dlete) { +#if SHOPT_DYNAMIC + if(tdata.prefix) + for(n = 0; n < nlib; n++) + sfprintf(sfstdout, "%s -f %s\n", tdata.prefix, liblist[n].lib); +#endif print_scan(sfstdout, flag, sh.bltin_tree, 1, &tdata); return 0; } @@ -1216,6 +1224,18 @@ int b_builtin(int argc,char *argv[],Shbltin_t *context) flag = stktell(stkp); while(arg = *argv) { + if(tdata.prefix) + { + if(np = nv_search(arg,sh.bltin_tree,0)) + sfprintf(sfstdout,"%s %s\n",tdata.prefix,arg); + else + { + errormsg(SH_DICT,ERROR_exit(0),"%s: %s",*argv,"not found"); + r = 1; + } + argv++; + continue; + } name = path_basename(arg); sfwrite(stkp,"b_",2); sfputr(stkp,name,0); @@ -1488,7 +1508,11 @@ static int print_namval(Sfio_t *file,Namval_t *np,int flag, struct tdata *tp) if(nv_isattr(np,NV_NOPRINT|NV_INTEGER)==NV_NOPRINT) { if(is_abuiltin(np)) + { + if(tp->prefix) + sfputr(file,tp->prefix,' '); sfputr(file,nv_name(np),'\n'); + } return 0; } if(nv_istable(np)) diff --git a/src/cmd/ksh93/bltins/umask.c b/src/cmd/ksh93/bltins/umask.c index 7b9819dd327d..352bb18d0f44 100644 --- a/src/cmd/ksh93/bltins/umask.c +++ b/src/cmd/ksh93/bltins/umask.c @@ -16,7 +16,7 @@ * * ***********************************************************************/ /* - * umask [-S] [mask] + * umask [-pS] [mask] * * David Korn * AT&T Labs @@ -39,12 +39,15 @@ int b_umask(int argc,char *argv[],Shbltin_t *context) { char *mask; - int flag = 0, sflag = 0; + int flag = 0, pflag = 0, sflag = 0; NOT_USED(context); while((argc = optget(argv,sh_optumask))) switch(argc) { + case 'p': + pflag = 1; + break; case 'S': - sflag++; + sflag = 1; break; case ':': errormsg(SH_DICT,2, "%s", opt_info.arg); @@ -93,11 +96,12 @@ int b_umask(int argc,char *argv[],Shbltin_t *context) } else { + char *prefix = pflag ? "umask " : ""; umask(flag=umask(0)); if(sflag) - sfprintf(sfstdout,"%s\n",fmtperm(~flag&0777)); + sfprintf(sfstdout,"%s%s\n",prefix,fmtperm(~flag&0777)); else - sfprintf(sfstdout,"%0#4o\n",flag); + sfprintf(sfstdout,"%s%0#4o\n",prefix,flag); } return 0; } diff --git a/src/cmd/ksh93/data/builtins.c b/src/cmd/ksh93/data/builtins.c index 31d6f8abbf94..c2a02b0b2cf9 100644 --- a/src/cmd/ksh93/data/builtins.c +++ b/src/cmd/ksh93/data/builtins.c @@ -392,7 +392,7 @@ const char sh_optalias[] = ; const char sh_optbuiltin[] = -"[-1c?\n@(#)$Id: builtin (ksh 93u+m) 2022-07-03 $\n]" +"[-1c?\n@(#)$Id: builtin (ksh 93u+m) 2025-06-25 $\n]" "[--catalog?" SH_DICT "]" "[+NAME?builtin - add, delete, or display shell built-ins]" "[+DESCRIPTION?\bbuiltin\b can be used to add, delete, or display " @@ -441,6 +441,9 @@ const char sh_optbuiltin[] = "[f]:[lib?Not supported.]" "[l?No effect.]" #endif /* SHOPT_DYNAMIC */ +"[p?Causes the output to be in the form of \bbuiltin\b commands that can be " + "used as input to the shell to recreate the current set of " + "builtins.]" "[s?Display only the special built-ins.]" "\n" "\n[pathname ...]\n" @@ -1758,7 +1761,7 @@ const char sh_optsleep[] = ; const char sh_opttrap[] = -"[-1c?\n@(#)$Id: trap (AT&T Research) 1999-07-17 $\n]" +"[-1c?\n@(#)$Id: trap (ksh 93u+m) 2025-06-25 $\n]" "[--catalog?" SH_DICT "]" "[+NAME?trap - trap signals and conditions]" "[+DESCRIPTION?\btrap\b is a special built-in that defines actions to be " @@ -1797,6 +1800,7 @@ const char sh_opttrap[] = "non-zero exit status, but does not terminate the invoking shell.]" "[+?If no \aaction\a or \acondition\as are specified then all the current " "trap settings are written to standard output.]" +"[l?Output the list of signals and their numbers to standard output.]" "[p?Causes the current traps to be output in a format that can be processed " "as input to the shell to recreate the current traps.]" "\n" @@ -1994,7 +1998,7 @@ const char sh_opttimes[] = ; const char sh_optumask[] = -"[-1c?\n@(#)$Id: umask (AT&T Research) 1999-04-07 $\n]" +"[-1c?\n@(#)$Id: umask (ksh 93u+m) 2025-06-25 $\n]" "[--catalog?" SH_DICT "]" "[+NAME?umask - get or set the file creation mask]" "[+DESCRIPTION?\bumask\b sets the file creation mask of the current " @@ -2009,6 +2013,7 @@ const char sh_optumask[] = "file creation mask for the current process to standard output.]" "[S?Causes the file creation mask to be written or treated as a symbolic value " "rather than an octal number.]" +"[p?Write the file creation mask in a format that can be used for reinput.]" "\n" "\n[mask]\n" "\n" diff --git a/src/cmd/ksh93/sh.1 b/src/cmd/ksh93/sh.1 index 9179004be101..118f532a0c4e 100644 --- a/src/cmd/ksh93/sh.1 +++ b/src/cmd/ksh93/sh.1 @@ -6526,6 +6526,12 @@ whose name is .B lib_init() and invokes this function with an argument of .BR 0 . +The +.B \-p +option causes the output to be in the form of +.B builtin +commands that can be used as input to the shell to recreate the current +set of builtins. .TP .PD 0 \f3cd\fP \*(OK \f3\-L\fP \*(CK \*(OK \f3-eP\fP \*(CK \*(OK \f2arg\^\fP \*(CK @@ -7041,7 +7047,7 @@ that is not found and the exit status is non-zero if any were not found. The .B \-r option empties the hash table. This can also be achieved by resetting -.BR PATH. +.BR PATH . .TP .PD 0 \f3hist\fP \*(OK \f3\-e\fP \f2ename\^\fP \ \*(CK \*(OK \f3\-N\fP \f2num\^\fP \*(CK \*(OK \f3\-Enlr\^\fP \*(CK \*(OK \f2first\^\fP \*(OK \f2last\^\fP \*(CK \*(CK @@ -8471,7 +8477,7 @@ Seconds are zero-padded unless the .B posix shell option is on. .TP -\(dg \f3trap\fP \*(OK \f3\-p\fP \*(CK \*(OK \f2action\^\fP \*(CK \*(OK \f2sig\^\fP \*(CK .\|.\|. +\(dg \f3trap\fP \*(OK \f3\-lp\fP \*(CK \*(OK \f2action\^\fP \*(CK \*(OK \f2sig\^\fP \*(CK .\|.\|. The .B \-p option causes the trap @@ -8597,6 +8603,9 @@ or .B return without an argument in a trap action will preserve the exit status of the command that invoked the trap. +The +.B \-l +option lists the signals and their numbers to standard output. .TP \f3true\fP Does nothing, and exits 0. Used with @@ -9151,7 +9160,7 @@ If no option is given, is assumed. .RE .TP -\f3umask\fP \*(OK \f3\-S\fP \*(CK \*(OK \f2mask\^\fP \*(CK +\f3umask\fP \*(OK \f3\-pS\fP \*(CK \*(OK \f2mask\^\fP \*(CK The user file-creation mask is set to .I mask\^ (see @@ -9174,6 +9183,9 @@ The option causes the mode to be printed as a symbolic value. Otherwise, the mask is printed in octal. +The +.B \-p +option writes the file creation mask in a format that can be used for reinput. .TP \f3unalias\fP \*(OK \f3\-a\fP \*(CK \f2name\^\fP .\|.\|. The aliases diff --git a/src/cmd/ksh93/tests/builtins.sh b/src/cmd/ksh93/tests/builtins.sh index 6f29ba253349..9efc23c96d6f 100755 --- a/src/cmd/ksh93/tests/builtins.sh +++ b/src/cmd/ksh93/tests/builtins.sh @@ -1644,6 +1644,17 @@ do case $bltin in [[ $got == " version "* ]] || err_exit "$bltin does not support --version (got $(printf %q "$got"))" done 3< <(builtin) +# ====== +# builtin -p must produce an error if the given builtin doesn't exist +# https://github.com/ksh93/ksh/pull/856#issuecomment-2923384587 +exp='builtin: not: not found +builtin: a: not found +builtin: built-in: not found +builtin type' +got=$(set +x; redirect 2>&1; builtin -p not a built-in type) +[[ $exp == $got ]] || err_exit "builtin -p doesn\'t function correctly when given arguments" \ + "(expected $(printf %q "$exp"), got $(printf %q "$got"))" + # ====== # https://github.com/ksh-community/ksh/issues/19 # https://github.com/ksh93/ksh/issues/602