diff mbox series

[v2] jobs: Allow monitor mode without a tty in non-interactive mode

Message ID ZhJhpbIEe1RyBfk0@gondor.apana.org.au (mailing list archive)
State Accepted
Delegated to: Herbert Xu
Headers show
Series [v2] jobs: Allow monitor mode without a tty in non-interactive mode | expand

Commit Message

Herbert Xu April 7, 2024, 9:04 a.m. UTC
On Mon, Jan 30, 2023 at 10:15:40PM +0100, Steffen Nurpmeso wrote:
> This is a take-over of the FreeBSD bin/sh
> 
>   commit cd60e2c67d52e1f957841af19128c7227880743a
>   Author:     Jilles Tjoelker <jilles@FreeBSD.org>
>   AuthorDate: 2014-09-04 21:48:33 +0000
>   Commit:     Jilles Tjoelker <jilles@FreeBSD.org>
>   CommitDate: 2014-09-04 21:48:33 +0000
> 
>       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.
> ---
> 
> Dear Ganael, it seems it requires an inline patch?
> Let me try this -- thanks!!
> Ciao.
> 
>  src/jobs.c | 114 +++++++++++++++++++++++++++++++----------------------
>  1 file changed, 67 insertions(+), 47 deletions(-)

Thanks for the patch.  I've rewritten it to minimise the impact.
However, the end result should be fairly similar.

Please test this and let me know if there are any issues.

---8<---
When a tty is unavailable, or the shell is in the background,
job control could still be used for the purpose of setting
process groups.

This is based on work by Jilles Tjoelker from FreeBSD and Steffen
Nurpmeso.

Reported-by: Steffen Nurpmeso <steffen@sdaoden.eu>
Reported-by: Ganael Laplanche <ganael.laplanche@martymac.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

Comments

Steffen Nurpmeso April 8, 2024, 10:54 p.m. UTC | #1
Hello.

Sorry for the late response.

Herbert Xu wrote in
 <ZhJhpbIEe1RyBfk0@gondor.apana.org.au>:
 |On Mon, Jan 30, 2023 at 10:15:40PM +0100, Steffen Nurpmeso wrote:
 |> This is a take-over of the FreeBSD bin/sh
 |> 
 |>   commit cd60e2c67d52e1f957841af19128c7227880743a
 |>   Author:     Jilles Tjoelker <jilles@FreeBSD.org>
 |>   AuthorDate: 2014-09-04 21:48:33 +0000
 |>   Commit:     Jilles Tjoelker <jilles@FreeBSD.org>
 |>   CommitDate: 2014-09-04 21:48:33 +0000
 |> 
 |>       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.
 ...
 |Thanks for the patch.  I've rewritten it to minimise the impact.

The patch is much smaller.

 |However, the end result should be fairly similar.
 |
 |Please test this and let me know if there are any issues.

Running the script with it has the desired result.

  ..
 --End of <ZhJhpbIEe1RyBfk0@gondor.apana.org.au>

Ciao, and greetings from Germany,

--steffen
|
|Der Kragenbaer,                The moon bear,
|der holt sich munter           he cheerfully and one by one
|einen nach dem anderen runter  wa.ks himself off
|(By Robert Gernhardt)
Ganael Laplanche April 9, 2024, 10:11 a.m. UTC | #2
On 4/9/24 00:54, Steffen Nurpmeso wrote:

Hello Herbert, Steffen,

> Running the script with it has the desired result.

Sorry for the delay. Indeed, I can confirm it works like a charm:

$ cat test_pgid.sh
set -m
(
   sleep 1
) &
i=$!
echo "Main shell has: $(ps -o pid,pgid $$)"
echo "Sub-shell has: $(ps -o pid,pgid $i)"
wait $i

$ dash test_pgid.sh &
$ Main shell has:   PID  PGID
80074 80074
Sub-shell has:   PID  PGID
86666 86666
[1] + Done                       (sleep 1)
[1]   Done                    dash test_pgid.sh

As a consequence, fpsync[1] can now be started in the background, great!

Thanks a lot to both of you :)

Cheers,

Ganael.

[1] https://www.fpart.org/fpsync/
diff mbox series

Patch

diff --git a/src/jobs.c b/src/jobs.c
index a0f4d47..2a2fe22 100644
--- a/src/jobs.c
+++ b/src/jobs.c
@@ -187,11 +187,21 @@  set_curjob(struct job *jp, unsigned mode)
 
 int jobctl;
 
+static void xxtcsetpgrp(pid_t pgrp)
+{
+	int fd = ttyfd;
+
+	if (fd < 0)
+		return;
+
+	xtcsetpgrp(fd, pgrp);
+}
+
 void
 setjobctl(int on)
 {
+	int pgrp = -1;
 	int fd;
-	int pgrp;
 
 	if (on == jobctl || rootshell == 0)
 		return;
@@ -207,36 +217,43 @@  setjobctl(int on)
 		fd = savefd(fd, ofd);
 		do { /* while we are in the background */
 			if ((pgrp = tcgetpgrp(fd)) < 0) {
+close:
+				close(fd);
+				fd = -1;
 out:
+				if (!iflag)
+					break;
 				sh_warnx("can't access tty; job control turned off");
 				mflag = on = 0;
-				goto close;
+				return;
 			}
 			if (pgrp == getpgrp())
 				break;
+			if (!iflag)
+				goto close;
 			killpg(0, SIGTTIN);
 		} while (1);
 		initialpgrp = pgrp;
-
-		setsignal(SIGTSTP);
-		setsignal(SIGTTOU);
-		setsignal(SIGTTIN);
 		pgrp = rootpid;
-		setpgid(0, pgrp);
-		xtcsetpgrp(fd, pgrp);
 	} else {
 		/* turning job control off */
 		fd = ttyfd;
 		pgrp = initialpgrp;
-		xtcsetpgrp(fd, pgrp);
-		setpgid(0, pgrp);
-		setsignal(SIGTSTP);
-		setsignal(SIGTTOU);
-		setsignal(SIGTTIN);
-close:
-		close(fd);
-		fd = -1;
 	}
+
+	setsignal(SIGTSTP);
+	setsignal(SIGTTOU);
+	setsignal(SIGTTIN);
+	if (fd >= 0) {
+		setpgid(0, pgrp);
+		xtcsetpgrp(fd, pgrp);
+
+		if (!on) {
+			close(fd);
+			fd = -1;
+		}
+	}
+
 	ttyfd = fd;
 	jobctl = on;
 }
@@ -391,7 +408,7 @@  restartjob(struct job *jp, int mode)
 	jp->state = JOBRUNNING;
 	pgid = jp->ps->pid;
 	if (mode == FORK_FG)
-		xtcsetpgrp(ttyfd, pgid);
+		xxtcsetpgrp(pgid);
 	killpg(pgid, SIGCONT);
 	ps = jp->ps;
 	i = jp->nprocs;
@@ -874,7 +891,7 @@  static void forkchild(struct job *jp, union node *n, int mode)
 		/* This can fail because we are doing it in the parent also */
 		(void)setpgid(0, pgrp);
 		if (mode == FORK_FG)
-			xtcsetpgrp(ttyfd, pgrp);
+			xxtcsetpgrp(pgrp);
 		setsignal(SIGTSTP);
 		setsignal(SIGTTOU);
 	} else
@@ -1014,7 +1031,7 @@  waitforjob(struct job *jp)
 	st = getstatus(jp);
 #if JOBS
 	if (jp->jobctl) {
-		xtcsetpgrp(ttyfd, rootpid);
+		xxtcsetpgrp(rootpid);
 		/*
 		 * This is truly gross.
 		 * If we're doing job control, then we did a TIOCSPGRP which