Module Name: src Committed By: kre Date: Wed Oct 9 13:43:33 UTC 2024
Modified Files: src/bin/sh: builtins.def jobs.c sh.1 shell.h trap.c trap.h Log Message: PR bin/58687 -- implement suspend as a builtin in sh Requested by uwe@ in PR bin/58687 without objections from anyone except me, here is an implementation of a suspend builtin command for /bin/sh The sh.1 man page is updated, naturally, to describe it. This new builtin does not exist in SMALL shells -- as used on (some) boot media, etc. If this turns out not to be useful, it can easily be removed. To generate a diff of this commit: cvs rdiff -u -r1.28 -r1.29 src/bin/sh/builtins.def cvs rdiff -u -r1.122 -r1.123 src/bin/sh/jobs.c cvs rdiff -u -r1.264 -r1.265 src/bin/sh/sh.1 cvs rdiff -u -r1.32 -r1.33 src/bin/sh/shell.h cvs rdiff -u -r1.57 -r1.58 src/bin/sh/trap.c cvs rdiff -u -r1.25 -r1.26 src/bin/sh/trap.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/bin/sh/builtins.def diff -u src/bin/sh/builtins.def:1.28 src/bin/sh/builtins.def:1.29 --- src/bin/sh/builtins.def:1.28 Wed Oct 9 12:27:11 2024 +++ src/bin/sh/builtins.def Wed Oct 9 13:43:32 2024 @@ -1,5 +1,5 @@ #!/bin/sh - -# $NetBSD: builtins.def,v 1.28 2024/10/09 12:27:11 kre Exp $ +# $NetBSD: builtins.def,v 1.29 2024/10/09 13:43:32 kre Exp $ # # Copyright (c) 1991, 1993 # The Regents of the University of California. All rights reserved. @@ -80,6 +80,7 @@ setvarcmd setvar shiftcmd -s shift #ifndef SMALL specialvarcmd specialvar +suspendcmd -j suspend #endif testcmd -u test -u [ timescmd -s times Index: src/bin/sh/jobs.c diff -u src/bin/sh/jobs.c:1.122 src/bin/sh/jobs.c:1.123 --- src/bin/sh/jobs.c:1.122 Tue Jun 18 07:21:31 2024 +++ src/bin/sh/jobs.c Wed Oct 9 13:43:32 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: jobs.c,v 1.122 2024/06/18 07:21:31 kre Exp $ */ +/* $NetBSD: jobs.c,v 1.123 2024/10/09 13:43:32 kre Exp $ */ /*- * Copyright (c) 1991, 1993 @@ -37,7 +37,7 @@ #if 0 static char sccsid[] = "@(#)jobs.c 8.5 (Berkeley) 5/4/95"; #else -__RCSID("$NetBSD: jobs.c,v 1.122 2024/06/18 07:21:31 kre Exp $"); +__RCSID("$NetBSD: jobs.c,v 1.123 2024/10/09 13:43:32 kre Exp $"); #endif #endif /* not lint */ @@ -980,13 +980,124 @@ jobidcmd(int argc, char **argv) return 0; } +#if JOBS +#ifndef SMALL + +static int +stop_me(int sig, int force, int pgrp, pid_t pid) +{ + if (force || (!loginsh && mflag && rootshell)) { + struct sigaction sig_dfl, sig_was; + + sig_dfl.sa_handler = SIG_DFL; + sig_dfl.sa_flags = 0; + sigemptyset(&sig_dfl.sa_mask); + + (void)sigaction(sig, &sig_dfl, &sig_was); + + if (kill(pgrp ? 0 : pid, sig) == -1) { + sh_warn("suspend myself"); + (void)sigaction(sig, &sig_was, NULL); + error(NULL); + } + + (void)sigaction(sig, &sig_was, NULL); + + return 0; + } + + if (!rootshell) + sh_warnx("subshell environment"); + else if (!mflag) + sh_warnx("job control disabled"); + else if (loginsh) + sh_warnx("login shell"); + else + sh_warnx("not possible??"); + + return 1; +} + +int +suspendcmd(int argc, char **argv) +{ + int sig = SIGTSTP; + int force = 0; + int pgrp = 0; + int status = 0; + char *target; + int c; + + while ((c = nextopt("fgs:")) != 0) { + switch (c) { + case 'f': + force = 1; + break; + case 'g': + pgrp = 1; + break; + case 's': + sig = signame_to_signum(optionarg); + + if (sig != SIGSTOP && sig != SIGTSTP && + sig != SIGTTIN && sig != SIGTTOU) + error("bad signal '%s'", optionarg); + break; + } + } + + if (!*argptr) /* suspend myself */ + return stop_me(sig, force, pgrp, getpid()); + + while ((target = *argptr++) != NULL) + { + int pid; + + if (is_number(target)) { + if ((pid = number(target)) == 0) { + sh_warnx("Cannot (yet) suspend kernel (%s)", + target); + status = 1; + continue; + } + } else if ((pid = getjobpgrp(target)) == 0) { + sh_warnx("Unknown job: %s", target); + status = 1; + continue; + } + + if (pid == rootpid || pid == getpid()) { + status |= stop_me(sig, force, pgrp, pid); + continue; + } + + if (pid == 1 || pid == -1) { + sh_warnx("Don't be funny"); + status = 1; + continue; + } + + if (pid > 0 && pgrp) + pid = -pid; + + if (kill(pid, sig) == -1) { + sh_warn("failed to suspend %s", target); + status = 1; + } + } + + return status; +} +#endif /* SMALL */ +#endif /* JOBS */ + int getjobpgrp(const char *name) { struct job *jp; if (jobs_invalid) - error("No such job: %s", name); + return 0; jp = getjob(name, 1); if (jp == 0) return 0; Index: src/bin/sh/sh.1 diff -u src/bin/sh/sh.1:1.264 src/bin/sh/sh.1:1.265 --- src/bin/sh/sh.1:1.264 Sat Sep 21 20:48:50 2024 +++ src/bin/sh/sh.1 Wed Oct 9 13:43:32 2024 @@ -1,4 +1,4 @@ -.\" $NetBSD: sh.1,v 1.264 2024/09/21 20:48:50 kre Exp $ +.\" $NetBSD: sh.1,v 1.265 2024/10/09 13:43:32 kre Exp $ .\" Copyright (c) 1991, 1993 .\" The Regents of the University of California. All rights reserved. .\" @@ -31,7 +31,7 @@ .\" .\" @(#)sh.1 8.6 (Berkeley) 5/4/95 .\" -.Dd July 13, 2024 +.Dd October 6, 2024 .Dt SH 1 .\" everything except c o and s (keep them ordered) .ds flags abCEeFfhIiLlmnpquVvXx @@ -416,7 +416,7 @@ This option defaults to .Dq on in this shell. For more details see the section -.Sx LINENO +.Sx Using Dv LINENO below. .It Fl l Em login When set on the command line, the shell will be considered @@ -3618,7 +3618,7 @@ Using is an extension not implemented by most shells. .Pp See the section -.Sx LINENO +.Sx Using Dv LINENO below for details of the effects of making the variable .Dv LINENO local. @@ -4059,6 +4059,81 @@ naming the variables required, to ensure that their special properties are available. .\" .Pp +.It Ic suspend Oo Fl fg Oc Oo Fl s Ar sig Oc Oo Ar pid Ns \&| Ns Ar job ... Oc +Causes the processes or jobs indicated to be suspended, if possible. +If no +.Ar pid +or +.Ar job +arguments are given, or if a +.Ar pid +argument refers to the shell itself, and if the +.Ic suspend +command is issued in a shell that is not a login shell, +has job control enabled, +and is not executing in a subshell environment, +then the shell will suspend itself. +The +.Fl f +(force) option causes those checks to be ignored, +the shell, when instructed to suspend itself with force, +will always attempt to do so, which may result in a subshell +environment becoming suspended. +.Pp +The +.Fl g +option indicates that each +.Ar pid +argument is to be treated as a process group identifier, +or if no targets are given, the current process group of the shell, +and that process group will be suspended, instead of just +the process identified. +This option is implied, for the one agument only, by use of a +.Ar job +specifier. +Note that, unlike other built-in commands, use of a +.Ar pid +argument causes only that process to be suspended, +even if that +.Ar pid +happens to be the process leader of a job, or another +process in a job. +.Pp +The +.Fl s Ar sig +option cause the signal +.Ar sig +to be used to suspend the process, or process group. +Only the signals that, by default, cause processes to be +suspended +.Pq Dv STOP Dv TSTP Dv TTIN No and Dv TTOU +are permitted. +The default is +.Dv SIGTSTP . +Note that except when +.Dv SIGSTOP +is sent, the target process can arrange to catch or +ignore the signal, and perhaps not become suspended, +if it so desires. +Interactive processes that suport job control +(eg: shells) +generally ignore those signals. +.Pp +The +.Ic suspend +command exits with status 0, except if an error occurs, +in which case it exits with a status greater than 0. +Possible errors include usage errors; +attempting to suspend the shell itself, when not +permitted and without the +.Fl f +option; +a target process or job not existing; +insufficient prvileges to signal the target process or job; +and more. +It is not an error if the target process decides not to comply +with a request to suspend itself. +.Pp .It Ic times Prints two lines to standard output. Each line contains two accumulated time values, expressed @@ -4542,6 +4617,7 @@ The .Ic jobid , .Ic jobs , .Ic kill , +.Ic suspend , and .Ic wait commands all accept job identifiers as arguments, in addition to @@ -4562,7 +4638,11 @@ command. To cause a foreground process to stop, enter the terminal's .Ic stop character (usually control-Z). -To cause a background process to stop, send it a +To cause a background process to stop, +use the +.Ic suspend +built in command, or +send it a .Dv STOP signal, using the kill command. A useful function to define is @@ -4638,9 +4718,11 @@ It's similar to pressing the .Aq ESC key will throw you into vi command mode. +Insert mode is re-entered in any of the usual vi ways, +using the append (a) insert (i) substitute (s) (etc) commands. Pressing the .Aq return -key while in command mode will pass the line to the shell. +key in either mode will pass the line to the shell. .Pp The emacs-mode uses commands similar to a subset available in the .Ic emacs @@ -4937,7 +5019,7 @@ See .It Dv LINENO The current line number in the script or function. See the section -.Sx LINENO +.Sx Using Dv LINENO below for more details. .It Ev MAIL The name of a mail file, that will be checked for the arrival of new mail. @@ -5317,7 +5399,7 @@ that were used when building the shell w behaves like any other variable that has the read-only and un-exportable attributes set. .El -.Ss Dv LINENO +.Ss Using Dv LINENO .Dv LINENO is in many respects a normal shell variable, containing an integer value, and can be expanded using any of the forms Index: src/bin/sh/shell.h diff -u src/bin/sh/shell.h:1.32 src/bin/sh/shell.h:1.33 --- src/bin/sh/shell.h:1.32 Fri Feb 9 22:08:30 2024 +++ src/bin/sh/shell.h Wed Oct 9 13:43:33 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: shell.h,v 1.32 2024/02/09 22:08:30 andvar Exp $ */ +/* $NetBSD: shell.h,v 1.33 2024/10/09 13:43:33 kre Exp $ */ /*- * Copyright (c) 1991, 1993 @@ -56,7 +56,7 @@ #define SHELL_H #include <sys/param.h> -#define JOBS 1 +#define JOBS 1 /* spaces in this line are important, do not alter */ #ifndef BSD #define BSD 1 #endif Index: src/bin/sh/trap.c diff -u src/bin/sh/trap.c:1.57 src/bin/sh/trap.c:1.58 --- src/bin/sh/trap.c:1.57 Sat Jul 13 13:43:58 2024 +++ src/bin/sh/trap.c Wed Oct 9 13:43:33 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: trap.c,v 1.57 2024/07/13 13:43:58 kre Exp $ */ +/* $NetBSD: trap.c,v 1.58 2024/10/09 13:43:33 kre Exp $ */ /*- * Copyright (c) 1991, 1993 @@ -37,7 +37,7 @@ #if 0 static char sccsid[] = "@(#)trap.c 8.5 (Berkeley) 6/5/95"; #else -__RCSID("$NetBSD: trap.c,v 1.57 2024/07/13 13:43:58 kre Exp $"); +__RCSID("$NetBSD: trap.c,v 1.58 2024/10/09 13:43:33 kre Exp $"); #endif #endif /* not lint */ @@ -108,7 +108,7 @@ void printsignals(struct output *, int); * or -1 if it isn't one */ -static int +int signame_to_signum(const char *p) { int i; Index: src/bin/sh/trap.h diff -u src/bin/sh/trap.h:1.25 src/bin/sh/trap.h:1.26 --- src/bin/sh/trap.h:1.25 Mon Dec 3 10:53:29 2018 +++ src/bin/sh/trap.h Wed Oct 9 13:43:33 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: trap.h,v 1.25 2018/12/03 10:53:29 martin Exp $ */ +/* $NetBSD: trap.h,v 1.26 2024/10/09 13:43:33 kre Exp $ */ /*- * Copyright (c) 1991, 1993 @@ -50,3 +50,4 @@ void setinteractive(int); void exitshell(int) __dead; void exitshell_savedstatus(void) __dead; int lastsig(void); +int signame_to_signum(const char *);