[prev in list] [next in list] [prev in thread] [next in thread] 

List:       busybox
Subject:    ash: support "set -m" monitor mode even when not interactive
From:       Steffen Nurpmeso <steffen () sdaoden ! eu>
Date:       2023-01-17 20:27:31
Message-ID: 20230117202731.6q006%steffen () sdaoden ! eu
[Download RAW message or body]

Hello.

This came up on the dash list, and so i took over Jilles
Tjoelker's FreeBSD commit from 2014 to busybox ash.
Note i have no idea of what i am doing, but from testing it seems
to work; i have simply taken it over, which is a cleanup really.
(This is on top of my arithmetic patch but it should not really
interfere, .. in case linenumber shifts are seen.)

Ciao!

--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)

["ash_monitor_non_imode.patch" (text/x-diff)]

From e63ede983a138a3fc86fb51428b957dda1ae9157 Mon Sep 17 00:00:00 2001
Message-Id: <e63ede983a138a3fc86fb51428b957dda1ae9157.1673986875.git.steffen@sdaoden.eu>
From: Steffen Nurpmeso <steffen@sdaoden.eu>
Date: Tue, 17 Jan 2023 21:07:07 +0100
Subject: [PATCH] ash: Allow enabling job control without a tty in
 non-interactive mode..

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.

and makes a script of

  #!/bin/bash
  #!/tmp/busybox ash
  set -m
  (
  echo >&2 "inner shell has: $(ps -o pid,pgid $$ | tail -n1)"
  ) &
  echo >&2 "outer shell has: $(ps -o pid,pgid $$ | tail -n1)"
  echo >&2 "x is $$, job is $!: $(ps -o pid,pgid $! | tail -n1)"

behave identical (including $(|) pipe races) when invoked in the
background via "./SCRIPT &".
---
 shell/ash.c | 135 +++++++++++++++++++++++++++++++---------------------
 1 file changed, 80 insertions(+), 55 deletions(-)

diff --git a/shell/ash.c b/shell/ash.c
index 342cbadd92..b9eb0bfc86 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -4058,9 +4058,9 @@ freejob(struct job *jp)
 
 #if JOBS
 static void
-xtcsetpgrp(int fd, pid_t pgrp)
+xtcsetpgrp(pid_t pgrp)
 {
-	if (tcsetpgrp(fd, pgrp))
+	if (ttyfd >= 0 && tcsetpgrp(ttyfd, pgrp))
 		ash_msg_and_raise_perror("can't set tty process group");
 }
 
@@ -4074,71 +4074,93 @@ xtcsetpgrp(int fd, pid_t pgrp)
  * Called with interrupts off.
  */
 static void
+jobctl_notty(void)
+{
+	if (ttyfd >= 0) {
+		close(ttyfd);
+		ttyfd = -1;
+	}
+	if (!iflag) {
+		/* Allow enabling job control without a tty in non-interactive mode.
+		 * 'set -m' is still useful to create per-job process groups */
+		setsignal(SIGTSTP);
+		setsignal(SIGTTOU);
+		setsignal(SIGTTIN);
+		doing_jobctl = 1;
+		return;
+	}
+	ash_msg("can't access tty; job control turned off");
+	mflag = 0;
+}
+
+void
 setjobctl(int on)
 {
-	int fd;
-	int pgrp;
+	int i;
 
 	if (on == doing_jobctl || rootshell == 0)
 		return;
 	if (on) {
-		int ofd;
-		ofd = fd = open(_PATH_TTY, O_RDWR);
-		if (fd < 0) {
-	/* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
-	 * That sometimes helps to acquire controlling tty.
-	 * Obviously, a workaround for bugs when someone
-	 * failed to provide a controlling tty to bash! :) */
-			fd = 2;
-			while (!isatty(fd))
-				if (--fd < 0)
-					goto out;
-		}
-		/* fd is a tty at this point */
-		fd = fcntl(fd, F_DUPFD_CLOEXEC, 10);
-		if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, don't */
-			close(ofd);
-		if (fd < 0)
-			goto out; /* F_DUPFD failed */
-		if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
-			close_on_exec_on(fd);
-		while (1) { /* while we are in the background */
-			pgrp = tcgetpgrp(fd);
-			if (pgrp < 0) {
- out:
-				ash_msg("can't access tty; job control turned off");
-				mflag = on = 0;
-				goto close;
+		if (ttyfd != -1)
+			close(ttyfd);
+		if ((ttyfd = open(_PATH_TTY, O_RDWR)) < 0) {
+			i = 0;
+			while (i <= 2 && !isatty(i))
+				i++;
+			if (i > 2 ||
+			    (ttyfd = fcntl(i, F_DUPFD_CLOEXEC, 10)) < 0) {
+				jobctl_notty();
+				return;
 			}
-			if (pgrp == getpgrp())
-				break;
-			killpg(0, SIGTTIN);
 		}
-		initialpgrp = pgrp;
-
+		if (ttyfd < 10) {
+			/*
+			 * Keep our TTY file descriptor out of the way of
+			 * the user's redirections.
+			 */
+			if ((i = fcntl(ttyfd, F_DUPFD_CLOEXEC, 10)) < 0) {
+				jobctl_notty();
+				return;
+			}
+			close(ttyfd);
+			ttyfd = i;
+		}
+		if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */
+			close_on_exec_on(ttyfd);
+		do { /* while we are in the background */
+			initialpgrp = tcgetpgrp(ttyfd);
+			if (initialpgrp < 0) {
+				jobctl_notty();
+				return;
+			}
+			if (initialpgrp != getpgrp()) {
+				if (!iflag) {
+					initialpgrp = -1;
+					jobctl_notty();
+					return;
+				}
+				kill(0, SIGTTIN);
+				continue;
+			}
+		} while (0);
 		setsignal(SIGTSTP);
 		setsignal(SIGTTOU);
 		setsignal(SIGTTIN);
-		pgrp = rootpid;
-		setpgid(0, pgrp);
-		xtcsetpgrp(fd, pgrp);
-	} else {
-		/* turning job control off */
-		fd = ttyfd;
-		pgrp = initialpgrp;
-		/* was xtcsetpgrp, but this can make exiting ash
-		 * loop forever if pty is already deleted */
-		tcsetpgrp(fd, pgrp);
-		setpgid(0, pgrp);
+		setpgid(0, rootpid);
+		xtcsetpgrp(rootpid);
+	} else { /* turning job control off */
+		setpgid(0, initialpgrp);
+		if (ttyfd >= 0) {
+			/* was xtcsetpgrp, but this can make exiting ash loop forever if
+			 * pty is already deleted */
+			tcsetpgrp(ttyfd, initialpgrp);
+			close(ttyfd);
+			ttyfd = -1;
+		}
 		setsignal(SIGTSTP);
 		setsignal(SIGTTOU);
 		setsignal(SIGTTIN);
- close:
-		if (fd >= 0)
-			close(fd);
-		fd = -1;
 	}
-	ttyfd = fd;
 	doing_jobctl = on;
 }
 
@@ -4225,7 +4247,7 @@ restartjob(struct job *jp, int mode)
 	pgid = jp->ps[0].ps_pid;
 	if (mode == FORK_FG) {
 		get_tty_state();
-		xtcsetpgrp(ttyfd, pgid);
+		xtcsetpgrp(pgid);
 	}
 	killpg(pgid, SIGCONT);
 	ps = jp->ps;
@@ -4492,6 +4514,9 @@ showjob(struct job *jp, int mode)
 	char s[16 + 16 + 48];
 	FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
 
+	if (!iflag)
+		return;
+
 	ps = jp->ps;
 
 	if (mode & SHOW_ONLY_PGID) { /* jobs -p */
@@ -5250,7 +5275,7 @@ forkchild(struct job *jp, union node *n, int mode)
 		/* this can fail because we are doing it in the parent also */
 		setpgid(0, pgrp);
 		if (mode == FORK_FG)
-			xtcsetpgrp(ttyfd, pgrp);
+			xtcsetpgrp(pgrp);
 		setsignal(SIGTSTP);
 		setsignal(SIGTTOU);
 	} else
@@ -5421,7 +5446,7 @@ waitforjob(struct job *jp)
 	st = getstatus(jp);
 #if JOBS
 	if (jp->jobctl) {
-		xtcsetpgrp(ttyfd, rootpid);
+		xtcsetpgrp(rootpid);
 		restore_tty_if_stopped_or_signaled(jp);
 
 		/*
-- 
2.39.0



_______________________________________________
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic