From 3ba4900e9c40d07a29c715a406a7f7d572e295b1 Mon Sep 17 00:00:00 2001 From: Martijn Dekker Date: Mon, 22 Jun 2020 14:59:24 +0200 Subject: [PATCH] Make 'stop' and 'suspend' regular built-ins The 'stop' and 'suspend' default aliases are now converted into regular built-in commands so that 'unalias -a' does not remove them, 'suspend' can do some sanity checks, and something like cmd=stop; $cmd $! will now work. src/cmd/ksh93/bltins/trap.c: - b_kill(): Incorporate 'stop' functionality, which is simply setting the same flag and variable as '-s STOP' would have done. - b_suspend(): Add simple builtin function that sends SIGSTOP to the main shell. Check for no operands, and refuse to suspend a login shell (which would leave the user stuck with no way out). Also check that 'kill' succeeds; if we're in an asynchronous subshell, it is possible the main shell no longer exists. src/cmd/ksh93/data/aliases.c: - Remove "stop" and "suspend" default aliases. (Why were these conditional upon SIGTSTP when they actually issued SIGSTOP?) src/cmd/ksh93/include/builtins.h, src/cmd/ksh93/data/builtins.c, src/cmd/ksh93/data/msg.c: - Add declarations of "stop" and "suspend" regular built-ins. - Add option strings (AST manual/--man pages) for them. - Add e_toomanyops ("too many operands") reusable error message for b_suspend(). Other new commands may want this at some point. src/cmd/ksh93/sh.1: - Remove "stop" and "suspend" default aliases. - Document "stop" and "suspend" regular built-in commands. --- NEWS | 8 +++++++ TODO | 4 +--- src/cmd/ksh93/bltins/trap.c | 28 ++++++++++++++++++++++ src/cmd/ksh93/data/aliases.c | 4 ---- src/cmd/ksh93/data/builtins.c | 40 ++++++++++++++++++++++++++++++++ src/cmd/ksh93/data/msg.c | 1 + src/cmd/ksh93/include/builtins.h | 8 +++++++ src/cmd/ksh93/sh.1 | 26 +++++++++++++++++---- 8 files changed, 108 insertions(+), 11 deletions(-) diff --git a/NEWS b/NEWS index f357252cb..77d834152 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,14 @@ For full details, see the git log at: https://github.com/ksh93/ksh Any uppercase BUG_* names are modernish shell bug IDs. +2020-06-22: + +- The 'stop' and 'suspend' default aliases have been converted into regular + built-in commands, so that 'unalias -a' does not remove them, 'suspend' + can do a couple of sanity checks, and something like + cmd=stop; $cmd $! + will now work. See 'stop --man' and 'suspend --man' for more information. + 2020-06-20: - Fixed a bug that caused setting the following variables as readonly in diff --git a/TODO b/TODO index 56dcd386c..bb6554274 100644 --- a/TODO +++ b/TODO @@ -29,13 +29,11 @@ Fix or remove broken or misguided default aliases: - functions='typeset -f' - integer='typeset -li' - nameref='typeset -n' - - stop='kill -s STOP' - - suspend='kill -s STOP $$' Keep these default aliases for the benefit of interactive shells: + history='hist -l' + r='hist -s' To avoid interfering with shell functions by those names that POSIX - scripts may set, those should only intialise on interactive shells. + scripts may set, those should only initialise on interactive shells. ______ Fix currently known bugs affecting shell scripting. These are identified by diff --git a/src/cmd/ksh93/bltins/trap.c b/src/cmd/ksh93/bltins/trap.c index c87e435bb..1e19c2594 100644 --- a/src/cmd/ksh93/bltins/trap.c +++ b/src/cmd/ksh93/bltins/trap.c @@ -171,7 +171,16 @@ int b_kill(int argc,char *argv[],Shbltin_t *context) register Shell_t *shp = context->shp; int usemenu = 0; NOT_USED(argc); +#if defined(JOBS) && defined(SIGSTOP) + if(**argv == 's') /* top == kill -s STOP */ + { + flag |= S_FLAG; + signame = "STOP"; + } + while((n = optget(argv, **argv == 's' ? sh_optstop : sh_optkill))) switch(n) +#else while((n = optget(argv,sh_optkill))) switch(n) +#endif /* defined(JOBS) && defined(SIGSTOP) */ { case ':': if((signame=argv[opt_info.index++]) && (sig=sig_number(shp,signame+1))>=0) @@ -233,6 +242,25 @@ endopts: return(shp->exitval); } +#if defined(JOBS) && defined(SIGSTOP) +/* + * former default alias suspend='kill -s STOP $$' + */ +int b_suspend(int argc,char *argv[],Shbltin_t *context) +{ + NOT_USED(argc); + if(optget(argv, sh_optsuspend)) /* no options supported (except AST --man, etc.) */ + errormsg(SH_DICT, ERROR_exit(2), "%s", opt_info.arg); + if(argv[opt_info.index]) /* no operands supported */ + errormsg(SH_DICT, ERROR_exit(2), e_toomanyops); + if(sh_isoption(SH_LOGIN_SHELL)) + errormsg(SH_DICT, ERROR_exit(1), "cannot suspend a login shell"); + if(kill(context->shp->gd->pid, SIGSTOP) != 0) + errormsg(SH_DICT, ERROR_exit(1), "could not signal main shell at PID %d", context->shp->gd->pid); + return(0); +} +#endif /* defined(JOBS) && defined(SIGSTOP) */ + /* * Given the name or number of a signal return the signal number */ diff --git a/src/cmd/ksh93/data/aliases.c b/src/cmd/ksh93/data/aliases.c index 8fedfc5a3..10192e0bc 100644 --- a/src/cmd/ksh93/data/aliases.c +++ b/src/cmd/ksh93/data/aliases.c @@ -37,10 +37,6 @@ const struct shtable2 shtab_aliases[] = "integer", NV_NOFREE|BLT_DCL, "typeset -li", "nameref", NV_NOFREE|BLT_DCL, "typeset -n", "r", NV_NOFREE, "hist -s", -#ifdef SIGTSTP - "stop", NV_NOFREE, "kill -s STOP", - "suspend", NV_NOFREE, "kill -s STOP $$", -#endif /*SIGTSTP */ "", 0, (char*)0 }; diff --git a/src/cmd/ksh93/data/builtins.c b/src/cmd/ksh93/data/builtins.c index 01db4ac33..6947d277b 100644 --- a/src/cmd/ksh93/data/builtins.c +++ b/src/cmd/ksh93/data/builtins.c @@ -109,6 +109,10 @@ const struct shtable3 shtab_builtins[] = "/bin/kill", NV_BLTIN|BLT_ENV, bltin(kill), # endif /* SIGTSTP */ "jobs", NV_BLTIN|BLT_ENV, bltin(jobs), +# ifdef SIGSTOP + "stop", NV_BLTIN|BLT_ENV, bltin(kill), + "suspend", NV_BLTIN|BLT_ENV, bltin(suspend), +# endif /* SIGSTOP */ #endif /* JOBS */ "false", NV_BLTIN|BLT_ENV, bltin(false), "getopts", NV_BLTIN|BLT_ENV, bltin(getopts), @@ -1060,6 +1064,42 @@ _JOB_ "[+SEE ALSO?\bps\b(1), \bjobs\b(1), \bkill\b(2), \bsignal\b(2)]" ; +#if defined(JOBS) && defined(SIGSTOP) +const char sh_optstop[] = +"[-1c?\n@(#)$Id: stop (ksh93) 2020-06-22 $\n]" +"[+NAME?stop - suspend a process]" +"[+DESCRIPTION?\bstop\b sends a \bSIGSTOP\b signal to one or more processes " + "specified by \ajob\a, suspending them until they receive \bSIGCONT\b.]" +_JOB_ +"\n" +"\njob ...\n" +"\n" +"[+EXIT STATUS?]{" + "[+0?At least one matching process was found for each \ajob\a " + "operand, and \bSIGSTOP\b was successfully sent to at least one " + "matching process.]" + "[+>0?An error occurred.]" +"}" +"[+SEE ALSO?\bkill\b(1)]" +; + +const char sh_optsuspend[] = +"[-1c?\n@(#)$Id: suspend (ksh93) 2020-06-22 $\n]" +"[+NAME?suspend - stop the shell]" +"[+DESCRIPTION?\bsuspend\b sends a \bSIGSTOP\b signal to the main shell " + "process, suspending the script or child shell session until it " + "receives \bSIGCONT\b (for instance, when typing \bfg\b in the " + "parent shell).]" +"[+?\bsuspend\b is equivalent to \bkill -s STOP \"$$\"\b, except that " + "it accepts no operands and refuses to suspend a login shell.]" +"[+EXIT STATUS?]{" + "[+0?The shell was successfully suspended and continued.]" + "[+>0?An error occurred.]" +"}" +"[+SEE ALSO?\bkill\b(1)]" +; +#endif /* defined(JOBS) && defined(SIGSTOP) */ + const char sh_optlet[] = "[-1c?@(#)$Id: let (AT&T Research) 2000-04-02 $\n]" USAGE_LICENSE diff --git a/src/cmd/ksh93/data/msg.c b/src/cmd/ksh93/data/msg.c index 655e509cc..82ef3e5e1 100644 --- a/src/cmd/ksh93/data/msg.c +++ b/src/cmd/ksh93/data/msg.c @@ -53,6 +53,7 @@ const char e_option[] = "%s: bad option(s)"; const char e_toomany[] = "open file limit exceeded"; const char e_argtype[] = "invalid argument of type %c"; const char e_oneoperand[] = "one operand expected"; +const char e_toomanyops[] = "too many operands"; const char e_formspec[] = "%c: unknown format specifier"; const char e_badregexp[] = "%s: invalid regular expression"; const char e_number[] = "%s: bad number"; diff --git a/src/cmd/ksh93/include/builtins.h b/src/cmd/ksh93/include/builtins.h index 61fe247f9..f1d356a30 100644 --- a/src/cmd/ksh93/include/builtins.h +++ b/src/cmd/ksh93/include/builtins.h @@ -86,6 +86,9 @@ extern int b_unalias(int, char*[],Shbltin_t*); # ifdef SIGTSTP extern int b_bg(int, char*[],Shbltin_t*); # endif /* SIGTSTP */ +# ifdef SIGSTOP + extern int b_suspend(int, char*[],Shbltin_t*); +# endif /* SIGSTOP */ #endif /* The following utilities are built-in because of side-effects */ @@ -131,6 +134,7 @@ extern const char e_overlimit[]; extern const char e_eneedsarg[]; extern const char e_oneoperand[]; +extern const char e_toomanyops[]; extern const char e_toodeep[]; extern const char e_badname[]; extern const char e_badsyntax[]; @@ -172,6 +176,10 @@ extern const char sh_opthash[]; extern const char sh_opthist[]; extern const char sh_optjobs[]; extern const char sh_optkill[]; +#if defined(JOBS) && defined(SIGSTOP) +extern const char sh_optstop[]; +extern const char sh_optsuspend[]; +#endif /* defined(JOBS) && defined(SIGSTOP) */ extern const char sh_optksh[]; extern const char sh_optlet[]; extern const char sh_optprint[]; diff --git a/src/cmd/ksh93/sh.1 b/src/cmd/ksh93/sh.1 index e43904495..7f08028c8 100644 --- a/src/cmd/ksh93/sh.1 +++ b/src/cmd/ksh93/sh.1 @@ -803,10 +803,6 @@ but can be unset or redefined: .B "nameref=\(fmtypeset \-n\(fm" .TP .B "r=\(fmhist \-s\(fm" -.TP -.B "stop=\(fmkill \-s \s-1STOP\s+1\(fm" -.TP -.B "suspend=\(fmkill \-s \s-1STOP\s+1 $$\(fm" .PD .RE .SS Tilde Substitution. @@ -7133,6 +7129,28 @@ Same as .BR \|.\^ , except it is not treated as a special built-in command. .TP +\f3stop\fP \f2job\^\fP .\|.\|. +Sends a +.B SIGSTOP +signal to one or more processes specified by +.IR job , +suspending them until they receive +.BR SIGCONT . +The same as +.BR kill\ -s\ STOP . +.TP +\f3suspend\fP +Sends a +.B SIGSTOP +signal to the main shell process, suspending the script +or child shell session until it receives +.B SIGCONT +(for instance, when typing +.B fg +in the parent shell). Equivalent to +.BR kill\ -s\ STOP\ "$$" , +except that it accepts no operands and refuses to suspend a login shell. +.TP \f3times\fP Displays the accumulated user and system CPU times, one line with the times used by the shell and another with those used by all of the shell's child