summaryrefslogtreecommitdiffstats
path: root/bin/sh
diff options
context:
space:
mode:
authorjilles <jilles@FreeBSD.org>2014-09-04 21:48:33 +0000
committerjilles <jilles@FreeBSD.org>2014-09-04 21:48:33 +0000
commit714c76939dde60292a6712472b3b85c53292e3c1 (patch)
treea0860d129718a6d0d794db98ff77b1da186b38d8 /bin/sh
parent9099058799f5cd600b4cccdc36f17fe567fbee2b (diff)
downloadFreeBSD-src-714c76939dde60292a6712472b3b85c53292e3c1.zip
FreeBSD-src-714c76939dde60292a6712472b3b85c53292e3c1.tar.gz
sh: Allow enabling job control without a tty in non-interactive mode.
If no tty is available, 'set -m' is still useful to put jobs in their own process groups.
Diffstat (limited to 'bin/sh')
-rw-r--r--bin/sh/jobs.c53
-rw-r--r--bin/sh/sh.18
2 files changed, 47 insertions, 14 deletions
diff --git a/bin/sh/jobs.c b/bin/sh/jobs.c
index 93553c1..e58310b 100644
--- a/bin/sh/jobs.c
+++ b/bin/sh/jobs.c
@@ -118,6 +118,24 @@ static void showjob(struct job *, int);
static int jobctl;
#if JOBS
+static void
+jobctl_notty(void)
+{
+ if (ttyfd >= 0) {
+ close(ttyfd);
+ ttyfd = -1;
+ }
+ if (!iflag) {
+ setsignal(SIGTSTP);
+ setsignal(SIGTTOU);
+ setsignal(SIGTTIN);
+ jobctl = 1;
+ return;
+ }
+ out2fmt_flush("sh: can't access tty; job control turned off\n");
+ mflag = 0;
+}
+
void
setjobctl(int on)
{
@@ -133,8 +151,10 @@ setjobctl(int on)
while (i <= 2 && !isatty(i))
i++;
if (i > 2 ||
- (ttyfd = fcntl(i, F_DUPFD_CLOEXEC, 10)) < 0)
- goto out;
+ (ttyfd = fcntl(i, F_DUPFD_CLOEXEC, 10)) < 0) {
+ jobctl_notty();
+ return;
+ }
}
if (ttyfd < 10) {
/*
@@ -142,9 +162,8 @@ setjobctl(int on)
* the user's redirections.
*/
if ((i = fcntl(ttyfd, F_DUPFD_CLOEXEC, 10)) < 0) {
- close(ttyfd);
- ttyfd = -1;
- goto out;
+ jobctl_notty();
+ return;
}
close(ttyfd);
ttyfd = i;
@@ -152,11 +171,15 @@ setjobctl(int on)
do { /* while we are in the background */
initialpgrp = tcgetpgrp(ttyfd);
if (initialpgrp < 0) {
-out: out2fmt_flush("sh: can't access tty; job control turned off\n");
- mflag = 0;
+ jobctl_notty();
return;
}
if (initialpgrp != getpgrp()) {
+ if (!iflag) {
+ initialpgrp = -1;
+ jobctl_notty();
+ return;
+ }
kill(0, SIGTTIN);
continue;
}
@@ -168,9 +191,11 @@ out: out2fmt_flush("sh: can't access tty; job control turned off\n");
tcsetpgrp(ttyfd, rootpid);
} else { /* turning job control off */
setpgid(0, initialpgrp);
- tcsetpgrp(ttyfd, initialpgrp);
- close(ttyfd);
- ttyfd = -1;
+ if (ttyfd >= 0) {
+ tcsetpgrp(ttyfd, initialpgrp);
+ close(ttyfd);
+ ttyfd = -1;
+ }
setsignal(SIGTSTP);
setsignal(SIGTTOU);
setsignal(SIGTTIN);
@@ -195,7 +220,8 @@ fgcmd(int argc __unused, char **argv __unused)
printjobcmd(jp);
flushout(&output);
pgrp = jp->ps[0].pid;
- tcsetpgrp(ttyfd, pgrp);
+ if (ttyfd >= 0)
+ tcsetpgrp(ttyfd, pgrp);
restartjob(jp);
jp->foreground = 1;
INTOFF;
@@ -847,7 +873,8 @@ forkshell(struct job *jp, union node *n, int mode)
pgrp = getpid();
else
pgrp = jp->ps[0].pid;
- if (setpgid(0, pgrp) == 0 && mode == FORK_FG) {
+ if (setpgid(0, pgrp) == 0 && mode == FORK_FG &&
+ ttyfd >= 0) {
/*** this causes superfluous TIOCSPGRPS ***/
if (tcsetpgrp(ttyfd, pgrp) < 0)
error("tcsetpgrp failed, errno=%d", errno);
@@ -1007,7 +1034,7 @@ waitforjob(struct job *jp, int *origstatus)
dotrap();
#if JOBS
if (jp->jobctl) {
- if (tcsetpgrp(ttyfd, rootpid) < 0)
+ if (ttyfd >= 0 && tcsetpgrp(ttyfd, rootpid) < 0)
error("tcsetpgrp failed, errno=%d\n", errno);
}
if (jp->state == JOBSTOPPED)
diff --git a/bin/sh/sh.1 b/bin/sh/sh.1
index 1c3f8fb..4679d45 100644
--- a/bin/sh/sh.1
+++ b/bin/sh/sh.1
@@ -32,7 +32,7 @@
.\" from: @(#)sh.1 8.6 (Berkeley) 5/4/95
.\" $FreeBSD$
.\"
-.Dd January 26, 2014
+.Dd September 4, 2014
.Dt SH 1
.Os
.Sh NAME
@@ -259,6 +259,12 @@ from input when in interactive mode.
Force the shell to behave interactively.
.It Fl m Li monitor
Turn on job control (set automatically when interactive).
+A new process group is created for each pipeline (called a job).
+It is possible to suspend jobs or to have them run in the foreground or
+in the background.
+In a non-interactive shell,
+this option can be set even if no terminal is available
+and is useful to place processes in separate process groups.
.It Fl n Li noexec
If not interactive, read commands but do not
execute them.
OpenPOWER on IntegriCloud