commit: 116a1847123df86241856d5e744c0afeb35a2f78
parent: a99bdd3932b8f9f1e19ada06d6936b7d04125028
author: Chris Noxz <chris@noxz.tech>
date: Tue, 9 Mar 2021 19:19:54 +0100
Restore suspend
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);