summaryrefslogtreecommitdiff
path: root/bin
diff options
context:
space:
mode:
authorTodd C. Miller <millert@cvs.openbsd.org>2013-09-04 15:49:20 +0000
committerTodd C. Miller <millert@cvs.openbsd.org>2013-09-04 15:49:20 +0000
commit16ee5ce2792ddb7a376520acdfc7c838817522d7 (patch)
tree6907e4e0b6a1a411035073abce91f820f1b9d0df /bin
parent2f1b90bf6ff088f860a9a69973813717afcd79c2 (diff)
Add a proper suspend builtin that saves/restores the tty and pgrp
as needed instead of an alias that just sends SIGSTOP. Login shells may be suspended if they are not running in an orphan process group. OK guenther@ jmc@
Diffstat (limited to 'bin')
-rw-r--r--bin/ksh/c_sh.c23
-rw-r--r--bin/ksh/jobs.c55
-rw-r--r--bin/ksh/ksh.119
-rw-r--r--bin/ksh/main.c3
-rw-r--r--bin/ksh/proto.h3
5 files changed, 93 insertions, 10 deletions
diff --git a/bin/ksh/c_sh.c b/bin/ksh/c_sh.c
index 3691bfde49b..7f5a8f31a04 100644
--- a/bin/ksh/c_sh.c
+++ b/bin/ksh/c_sh.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: c_sh.c,v 1.43 2013/04/19 17:39:45 deraadt Exp $ */
+/* $OpenBSD: c_sh.c,v 1.44 2013/09/04 15:49:18 millert Exp $ */
/*
* built-in Bourne commands
@@ -871,6 +871,26 @@ usage:
return 1;
}
+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)
@@ -910,5 +930,6 @@ const struct builtin shbuiltins [] = {
{"+umask", c_umask},
{"*=unset", c_unset},
{"mknod", c_mknod},
+ {"suspend", c_suspend},
{NULL, NULL}
};
diff --git a/bin/ksh/jobs.c b/bin/ksh/jobs.c
index 67d07263a81..30763443626 100644
--- a/bin/ksh/jobs.c
+++ b/bin/ksh/jobs.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: jobs.c,v 1.39 2009/12/13 04:36:48 deraadt Exp $ */
+/* $OpenBSD: jobs.c,v 1.40 2013/09/04 15:49:18 millert Exp $ */
/*
* Process and job control
@@ -186,6 +186,59 @@ 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) < 0) {
+ warningf(false,
+ "j_suspend: tcsetpgrp() failed: %s",
+ strerror(errno));
+ } else {
+ if (setpgid(0, restore_ttypgrp) < 0) {
+ warningf(false,
+ "j_suspend: setpgid() failed: %s",
+ 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) < 0) {
+ warningf(false,
+ "j_suspend: setpgid() failed: %s",
+ strerror(errno));
+ ttypgrp_ok = 0;
+ } else {
+ if (tcsetpgrp(tty_fd, kshpid) < 0) {
+ warningf(false,
+ "j_suspend: tcsetpgrp() failed: %s",
+ strerror(errno));
+ ttypgrp_ok = 0;
+ }
+ }
+ }
+ tty_init(true);
+ }
+}
+
/* job cleanup before shell exit */
void
j_exit(void)
diff --git a/bin/ksh/ksh.1 b/bin/ksh/ksh.1
index cdfdf4253c9..f42cb1b6811 100644
--- a/bin/ksh/ksh.1
+++ b/bin/ksh/ksh.1
@@ -1,8 +1,8 @@
-.\" $OpenBSD: ksh.1,v 1.147 2013/06/13 19:43:09 millert Exp $
+.\" $OpenBSD: ksh.1,v 1.148 2013/09/04 15:49:18 millert Exp $
.\"
.\" Public Domain
.\"
-.Dd $Mdocdate: June 13 2013 $
+.Dd $Mdocdate: September 4 2013 $
.Dt KSH 1
.Os
.Sh NAME
@@ -849,7 +849,6 @@ login='exec login'
nohup='nohup '
r='fc -e -'
stop='kill -STOP'
-suspend='kill -STOP $$'
type='whence -v'
.Ed
.Pp
@@ -2744,8 +2743,8 @@ Additional
regular commands
.Pp
.Ic \&[ , echo , let , mknod ,
-.Ic print , pwd , test , ulimit ,
-.Ic whence
+.Ic print , pwd , suspend , test ,
+.Ic ulimit , whence
.Pp
In the future, the additional
.Nm
@@ -3819,6 +3818,16 @@ etc.
.Ar number
defaults to 1.
.Pp
+.It Ic suspend
+Stops the shell as if it had received the suspend character from
+the terminal.
+It is not possible to suspend a login shell unless the parent process
+is a member of the same terminal session but is a member of a different
+process group.
+As a general rule, if the shell was started by another shell or via
+.Xr su 1 ,
+it can be suspended.
+.Pp
.It Ic test Ar expression
.It Ic \&[ Ar expression Ic \&]
.Ic test
diff --git a/bin/ksh/main.c b/bin/ksh/main.c
index 9467978b976..81a601a535d 100644
--- a/bin/ksh/main.c
+++ b/bin/ksh/main.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: main.c,v 1.52 2013/06/15 17:25:19 millert Exp $ */
+/* $OpenBSD: main.c,v 1.53 2013/09/04 15:49:19 millert Exp $ */
/*
* startup, main loop, environments and error handling
@@ -41,7 +41,6 @@ static const char *initcoms [] = {
"type=whence -v",
#ifdef JOBS
"stop=kill -STOP",
- "suspend=kill -STOP $$",
#endif
"autoload=typeset -fu",
"functions=typeset -f",
diff --git a/bin/ksh/proto.h b/bin/ksh/proto.h
index d51030b8704..c4e3e0802e8 100644
--- a/bin/ksh/proto.h
+++ b/bin/ksh/proto.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: proto.h,v 1.34 2012/06/27 07:17:19 otto Exp $ */
+/* $OpenBSD: proto.h,v 1.35 2013/09/04 15:49:19 millert Exp $ */
/*
* prototypes for PD-KSH
@@ -132,6 +132,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);