diff options
author | Todd C. Miller <millert@cvs.openbsd.org> | 2013-09-04 15:49:20 +0000 |
---|---|---|
committer | Todd C. Miller <millert@cvs.openbsd.org> | 2013-09-04 15:49:20 +0000 |
commit | 16ee5ce2792ddb7a376520acdfc7c838817522d7 (patch) | |
tree | 6907e4e0b6a1a411035073abce91f820f1b9d0df | |
parent | 2f1b90bf6ff088f860a9a69973813717afcd79c2 (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@
-rw-r--r-- | bin/ksh/c_sh.c | 23 | ||||
-rw-r--r-- | bin/ksh/jobs.c | 55 | ||||
-rw-r--r-- | bin/ksh/ksh.1 | 19 | ||||
-rw-r--r-- | bin/ksh/main.c | 3 | ||||
-rw-r--r-- | bin/ksh/proto.h | 3 |
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); |