Date: Sun, 26 Jan 2003 10:20:02 -0800 (PST) From: Friedemann Becker <friedemann.becker@student.uni-tuebingen.de> To: freebsd-bugs@FreeBSD.org Subject: Re: bin/47136: Message-ID: <200301261820.h0QIK2KY074773@freefall.freebsd.org>
index | next in thread | raw e-mail
The following reply was made to PR bin/47136; it has been noted by GNATS.
From: Friedemann Becker <friedemann.becker@student.uni-tuebingen.de>
To: <freebsd-gnats-submit@FreeBSD.org>, <phk@critter.freebsd.dk>
Cc:
Subject: Re: bin/47136:
Date: Sun, 26 Jan 2003 19:13:44 +0100 (CET)
I found, that sh uses fd 3 for the controlling terminal. /bin/sh opens
/dev/tty and stores the resulting file descriptor in ttyfd:
jobs.c:
122: if (on) {
123: if (ttyfd != -1)
124: close(ttyfd);
125: if ((ttyfd = open(_PATH_TTY, O_RDWR)) < 0) {
126: i = 0;
127: while (i <= 2 && !isatty(i))
128: i++;
129: if (i > 2 || (ttyfd = dup(i)) < 0)
130: goto out;
131: }
ttyfd is needed for calls to tcsetpgrp.
To prevent conflicts with user-fd, ttyfd should be moved to a higher fd
like bash2 does:
jobs.c:
2911: /* Get our controlling terminal. If job_control is set, or
2912: interactive is set, then this is an interactive shell no
2913: matter where fd 2 is directed. */
2914: shell_tty = dup (fileno (stderr)); /* fd 2 */
2915:
2916: shell_tty = move_to_high_fd (shell_tty, 1, -1);
2917:
here's a patch proposal.
Sorry for sending mails twice, addresses were wrong. :/
Friedemann
--- /usr/src/bin/sh/jobs.c Wed Jan 22 02:30:07 2003
+++ jobs.c Sun Jan 26 19:05:53 2003
@@ -76,6 +76,7 @@
#include "mystring.h"
+
struct job *jobtab; /* array of jobs */
int njobs; /* size of array */
MKINIT pid_t backgndpid = -1; /* pid of last background process */
@@ -105,6 +106,9 @@
STATIC void showjob(struct job *, pid_t, int, int);
+int move_to_high_fd __P((int, int, int));
+
+
/*
* Turn job control on and off.
*/
@@ -129,6 +133,8 @@
if (i > 2 || (ttyfd = dup(i)) < 0)
goto out;
}
+ ttyfd = move_to_high_fd (ttyfd, 1, -1);
+
if (fcntl(ttyfd, F_SETFD, FD_CLOEXEC) < 0) {
close(ttyfd);
ttyfd = -1;
@@ -1227,4 +1233,48 @@
}
}
cmdnextc = q;
+}
+
+
+
+#define HIGH_FD_MAX 256
+
+/* Move FD to a number close to the maximum number of file descriptors
+ allowed in the shell process, to avoid the user stepping on it with
+ redirection and causing us extra work. If CHECK_NEW is non-zero,
+ we check whether or not the file descriptors are in use before
+ duplicating FD onto them. MAXFD says where to start checking the
+ file descriptors. If it's less than 20, we get the maximum value
+ available from getdtablesize(2). */
+int
+move_to_high_fd (fd, check_new, maxfd)
+ int fd, check_new, maxfd;
+{
+ int script_fd, nfds, ignore;
+
+ if (maxfd < 20)
+ {
+ nfds = getdtablesize ();
+ if (nfds <= 0)
+ nfds = 20;
+ if (nfds > HIGH_FD_MAX)
+ nfds = HIGH_FD_MAX; /* reasonable maximum */
+ }
+ else
+ nfds = maxfd;
+
+ for (nfds--; check_new && nfds > 3; nfds--)
+ if (fcntl (nfds, F_GETFD, &ignore) == -1)
+ break;
+
+ if (nfds > 3 && fd != nfds && (script_fd = dup2 (fd, nfds)) != -1)
+ {
+ if (check_new == 0 || fd != 2) /* don't close stderr */
+ close (fd);
+ return (script_fd);
+ }
+
+ /* OK, we didn't find one less than our artificial maximum; return the
+ original file descriptor. */
+ return (fd);
}
To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message
help
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200301261820.h0QIK2KY074773>
