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.
This commit is contained in:
parent
50e7b30ffc
commit
cd60e2c67d
@ -118,6 +118,24 @@ static void showjob(struct job *, int);
|
|||||||
static int jobctl;
|
static int jobctl;
|
||||||
|
|
||||||
#if JOBS
|
#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
|
void
|
||||||
setjobctl(int on)
|
setjobctl(int on)
|
||||||
{
|
{
|
||||||
@ -133,8 +151,10 @@ setjobctl(int on)
|
|||||||
while (i <= 2 && !isatty(i))
|
while (i <= 2 && !isatty(i))
|
||||||
i++;
|
i++;
|
||||||
if (i > 2 ||
|
if (i > 2 ||
|
||||||
(ttyfd = fcntl(i, F_DUPFD_CLOEXEC, 10)) < 0)
|
(ttyfd = fcntl(i, F_DUPFD_CLOEXEC, 10)) < 0) {
|
||||||
goto out;
|
jobctl_notty();
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (ttyfd < 10) {
|
if (ttyfd < 10) {
|
||||||
/*
|
/*
|
||||||
@ -142,9 +162,8 @@ setjobctl(int on)
|
|||||||
* the user's redirections.
|
* the user's redirections.
|
||||||
*/
|
*/
|
||||||
if ((i = fcntl(ttyfd, F_DUPFD_CLOEXEC, 10)) < 0) {
|
if ((i = fcntl(ttyfd, F_DUPFD_CLOEXEC, 10)) < 0) {
|
||||||
close(ttyfd);
|
jobctl_notty();
|
||||||
ttyfd = -1;
|
return;
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
close(ttyfd);
|
close(ttyfd);
|
||||||
ttyfd = i;
|
ttyfd = i;
|
||||||
@ -152,11 +171,15 @@ setjobctl(int on)
|
|||||||
do { /* while we are in the background */
|
do { /* while we are in the background */
|
||||||
initialpgrp = tcgetpgrp(ttyfd);
|
initialpgrp = tcgetpgrp(ttyfd);
|
||||||
if (initialpgrp < 0) {
|
if (initialpgrp < 0) {
|
||||||
out: out2fmt_flush("sh: can't access tty; job control turned off\n");
|
jobctl_notty();
|
||||||
mflag = 0;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (initialpgrp != getpgrp()) {
|
if (initialpgrp != getpgrp()) {
|
||||||
|
if (!iflag) {
|
||||||
|
initialpgrp = -1;
|
||||||
|
jobctl_notty();
|
||||||
|
return;
|
||||||
|
}
|
||||||
kill(0, SIGTTIN);
|
kill(0, SIGTTIN);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -168,9 +191,11 @@ out: out2fmt_flush("sh: can't access tty; job control turned off\n");
|
|||||||
tcsetpgrp(ttyfd, rootpid);
|
tcsetpgrp(ttyfd, rootpid);
|
||||||
} else { /* turning job control off */
|
} else { /* turning job control off */
|
||||||
setpgid(0, initialpgrp);
|
setpgid(0, initialpgrp);
|
||||||
tcsetpgrp(ttyfd, initialpgrp);
|
if (ttyfd >= 0) {
|
||||||
close(ttyfd);
|
tcsetpgrp(ttyfd, initialpgrp);
|
||||||
ttyfd = -1;
|
close(ttyfd);
|
||||||
|
ttyfd = -1;
|
||||||
|
}
|
||||||
setsignal(SIGTSTP);
|
setsignal(SIGTSTP);
|
||||||
setsignal(SIGTTOU);
|
setsignal(SIGTTOU);
|
||||||
setsignal(SIGTTIN);
|
setsignal(SIGTTIN);
|
||||||
@ -195,7 +220,8 @@ fgcmd(int argc __unused, char **argv __unused)
|
|||||||
printjobcmd(jp);
|
printjobcmd(jp);
|
||||||
flushout(&output);
|
flushout(&output);
|
||||||
pgrp = jp->ps[0].pid;
|
pgrp = jp->ps[0].pid;
|
||||||
tcsetpgrp(ttyfd, pgrp);
|
if (ttyfd >= 0)
|
||||||
|
tcsetpgrp(ttyfd, pgrp);
|
||||||
restartjob(jp);
|
restartjob(jp);
|
||||||
jp->foreground = 1;
|
jp->foreground = 1;
|
||||||
INTOFF;
|
INTOFF;
|
||||||
@ -847,7 +873,8 @@ forkshell(struct job *jp, union node *n, int mode)
|
|||||||
pgrp = getpid();
|
pgrp = getpid();
|
||||||
else
|
else
|
||||||
pgrp = jp->ps[0].pid;
|
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 ***/
|
/*** this causes superfluous TIOCSPGRPS ***/
|
||||||
if (tcsetpgrp(ttyfd, pgrp) < 0)
|
if (tcsetpgrp(ttyfd, pgrp) < 0)
|
||||||
error("tcsetpgrp failed, errno=%d", errno);
|
error("tcsetpgrp failed, errno=%d", errno);
|
||||||
@ -1007,7 +1034,7 @@ waitforjob(struct job *jp, int *origstatus)
|
|||||||
dotrap();
|
dotrap();
|
||||||
#if JOBS
|
#if JOBS
|
||||||
if (jp->jobctl) {
|
if (jp->jobctl) {
|
||||||
if (tcsetpgrp(ttyfd, rootpid) < 0)
|
if (ttyfd >= 0 && tcsetpgrp(ttyfd, rootpid) < 0)
|
||||||
error("tcsetpgrp failed, errno=%d\n", errno);
|
error("tcsetpgrp failed, errno=%d\n", errno);
|
||||||
}
|
}
|
||||||
if (jp->state == JOBSTOPPED)
|
if (jp->state == JOBSTOPPED)
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
.\" from: @(#)sh.1 8.6 (Berkeley) 5/4/95
|
.\" from: @(#)sh.1 8.6 (Berkeley) 5/4/95
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd January 26, 2014
|
.Dd September 4, 2014
|
||||||
.Dt SH 1
|
.Dt SH 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -259,6 +259,12 @@ from input when in interactive mode.
|
|||||||
Force the shell to behave interactively.
|
Force the shell to behave interactively.
|
||||||
.It Fl m Li monitor
|
.It Fl m Li monitor
|
||||||
Turn on job control (set automatically when interactive).
|
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
|
.It Fl n Li noexec
|
||||||
If not interactive, read commands but do not
|
If not interactive, read commands but do not
|
||||||
execute them.
|
execute them.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user