loksh-noxz

[discontinued] a Linux port of OpenBSD's ksh
git clone https://noxz.tech/git/loksh-noxz.git
loksh-noxz

commit: 116a1847123df86241856d5e744c0afeb35a2f78
parent: a99bdd3932b8f9f1e19ada06d6936b7d04125028
author: Chris Noxz <chris@noxz.tech>
date:   Tue, 9 Mar 2021 19:19:54 +0100
Restore suspend
Mc_sh.c21++++++++
Mjobs.c51++++++++++++++++++++
Msh.h1+
3 files changed, 73 insertions(+)
diff --git a/c_sh.c b/c_sh.c
@@ -845,6 +845,26 @@ c_exec(char **wp)
 	return 0;
 }
 
+static int
+c_suspend(char **wp)
+{
+	if (wp[1] != NULL) {
+		bi_errorf("too many arguments");
+		return 1;
+	}
+	if (Flag(FLOGIN)) {
+		/* Can't suspend an orphaned process group. */
+		pid_t parent = getppid();
+		if (getpgid(parent) == getpgid(0) ||
+		    getsid(parent) != getsid(0)) {
+			bi_errorf("can't suspend a login shell");
+			return 1;
+		}
+	}
+	j_suspend();
+	return 0;
+}
+
 /* dummy function, special case in comexec() */
 int
 c_builtin(char **wp)
@@ -883,5 +903,6 @@ const struct builtin shbuiltins [] = {
 	{"ulimit", c_ulimit},
 	{"+umask", c_umask},
 	{"*=unset", c_unset},
+	{"suspend", c_suspend},
 	{NULL, NULL}
 };
diff --git a/jobs.c b/jobs.c
@@ -193,6 +193,57 @@ j_init(int mflagset)
 		tty_init(true);
 }
 
+/* suspend the shell */
+void
+j_suspend(void)
+{
+	struct sigaction sa, osa;
+
+	/* Restore tty and pgrp. */
+	if (ttypgrp_ok) {
+		tcsetattr(tty_fd, TCSADRAIN, &tty_state);
+		if (restore_ttypgrp >= 0) {
+			if (tcsetpgrp(tty_fd, restore_ttypgrp) == -1) {
+				warningf(false, "%s: tcsetpgrp() failed: %s",
+				    __func__, strerror(errno));
+			} else {
+				if (setpgid(0, restore_ttypgrp) == -1) {
+					warningf(false,
+					    "%s: setpgid() failed: %s",
+					    __func__, strerror(errno));
+				}
+			}
+		}
+	}
+
+	/* Suspend the shell. */
+	memset(&sa, 0, sizeof(sa));
+	sigemptyset(&sa.sa_mask);
+	sa.sa_handler = SIG_DFL;
+	sigaction(SIGTSTP, &sa, &osa);
+	kill(0, SIGTSTP);
+
+	/* Back from suspend, reset signals, pgrp and tty. */
+	sigaction(SIGTSTP, &osa, NULL);
+	if (ttypgrp_ok) {
+		if (restore_ttypgrp >= 0) {
+			if (setpgid(0, kshpid) == -1) {
+				warningf(false, "%s: setpgid() failed: %s",
+				    __func__, strerror(errno));
+				ttypgrp_ok = 0;
+			} else {
+				if (tcsetpgrp(tty_fd, kshpid) == -1) {
+					warningf(false,
+					    "%s: tcsetpgrp() failed: %s",
+					    __func__, strerror(errno));
+					ttypgrp_ok = 0;
+				}
+			}
+		}
+		tty_init(true);
+	}
+}
+
 /* job cleanup before shell exit */
 void
 j_exit(void)
diff --git a/sh.h b/sh.h
@@ -501,6 +501,7 @@ void	coproc_cleanup(int);
 struct temp *maketemp(Area *, Temp_type, struct temp **);
 /* jobs.c */
 void	j_init(int);
+void	j_suspend(void);
 void	j_exit(void);
 void	j_change(void);
 int	exchild(struct op *, int, volatile int *, int);