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 *);

Reply via email to