Module Name: src Committed By: kre Date: Sat Apr 29 15:14:29 UTC 2017
Modified Files: src/bin/sh: input.c jobs.c redir.c redir.h Log Message: Keep track of which file descriptors the shell is using for its own purposes, and move them elsewhere whenever a user redirection happens to pick the same number. With this we can move the shell file descriptors back to lower values (be slightly kinder to the kernel) since we can no longer clash. (Also get rid of a little old unneeded code.) This also completes the fdflags command, which no longer permits access to (by way or either obtaining, or changing) the shell's internal fds. To generate a diff of this commit: cvs rdiff -u -r1.51 -r1.52 src/bin/sh/input.c cvs rdiff -u -r1.79 -r1.80 src/bin/sh/jobs.c cvs rdiff -u -r1.53 -r1.54 src/bin/sh/redir.c cvs rdiff -u -r1.22 -r1.23 src/bin/sh/redir.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/bin/sh/input.c diff -u src/bin/sh/input.c:1.51 src/bin/sh/input.c:1.52 --- src/bin/sh/input.c:1.51 Wed Jun 1 05:11:52 2016 +++ src/bin/sh/input.c Sat Apr 29 15:14:28 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: input.c,v 1.51 2016/06/01 05:11:52 kre Exp $ */ +/* $NetBSD: input.c,v 1.52 2017/04/29 15:14:28 kre Exp $ */ /*- * Copyright (c) 1991, 1993 @@ -37,7 +37,7 @@ #if 0 static char sccsid[] = "@(#)input.c 8.3 (Berkeley) 6/9/95"; #else -__RCSID("$NetBSD: input.c,v 1.51 2016/06/01 05:11:52 kre Exp $"); +__RCSID("$NetBSD: input.c,v 1.52 2017/04/29 15:14:28 kre Exp $"); #endif #endif /* not lint */ @@ -428,6 +428,24 @@ setinputfile(const char *fname, int push INTON; } +/* + * When a shell fd needs to be altered (when the user wants to use + * the same fd - rare, but happens - we need to locate the ref to + * the fd, and update it. This happens via a callback. + * This is the callback func for fd's used for shell input + */ +static void +input_fd_swap(int from, int to) +{ + struct parsefile *pf; + + pf = parsefile; + while (pf != NULL) { /* don't need to stop at basepf */ + if (pf->fd == from) + pf->fd = to; + pf = pf->prev; + } +} /* * Like setinputfile, but takes an open file descriptor. Call this with @@ -437,13 +455,14 @@ setinputfile(const char *fname, int push void setinputfd(int fd, int push) { + register_sh_fd(fd, input_fd_swap); (void) fcntl(fd, F_SETFD, FD_CLOEXEC); if (push) { pushfile(); parsefile->buf = ckmalloc(BUFSIZ); } if (parsefile->fd > 0) - close(parsefile->fd); + sh_close(parsefile->fd); parsefile->fd = fd; if (parsefile->buf == NULL) parsefile->buf = ckmalloc(BUFSIZ); @@ -502,7 +521,7 @@ popfile(void) INTOFF; if (pf->fd >= 0) - close(pf->fd); + sh_close(pf->fd); if (pf->buf) ckfree(pf->buf); while (pf->strpush) @@ -551,7 +570,7 @@ closescript(int vforked) return; popallfiles(); if (parsefile->fd > 0) { - close(parsefile->fd); + sh_close(parsefile->fd); parsefile->fd = 0; } } Index: src/bin/sh/jobs.c diff -u src/bin/sh/jobs.c:1.79 src/bin/sh/jobs.c:1.80 --- src/bin/sh/jobs.c:1.79 Sat May 7 20:07:47 2016 +++ src/bin/sh/jobs.c Sat Apr 29 15:14:28 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: jobs.c,v 1.79 2016/05/07 20:07:47 kre Exp $ */ +/* $NetBSD: jobs.c,v 1.80 2017/04/29 15:14:28 kre Exp $ */ /*- * Copyright (c) 1991, 1993 @@ -37,7 +37,7 @@ #if 0 static char sccsid[] = "@(#)jobs.c 8.5 (Berkeley) 5/4/95"; #else -__RCSID("$NetBSD: jobs.c,v 1.79 2016/05/07 20:07:47 kre Exp $"); +__RCSID("$NetBSD: jobs.c,v 1.80 2017/04/29 15:14:28 kre Exp $"); #endif #endif /* not lint */ @@ -129,6 +129,13 @@ tcsetpgrp(int fd, pid_tpgrp) } #endif +static void +ttyfd_change(int from, int to) +{ + if (ttyfd == from) + ttyfd = to; +} + /* * Turn job control on and off. * @@ -150,10 +157,10 @@ setjobctl(int on) return; if (on) { #if defined(FIOCLEX) || defined(FD_CLOEXEC) - int err; int i; + if (ttyfd != -1) - close(ttyfd); + sh_close(ttyfd); if ((ttyfd = open("/dev/tty", O_RDWR)) == -1) { for (i = 0; i < 3; i++) { if (isatty(i) && (ttyfd = dup(i)) != -1) @@ -163,24 +170,14 @@ setjobctl(int on) goto out; } ttyfd = to_upper_fd(ttyfd); /* Move to a high fd */ -#ifdef FIOCLEX - err = ioctl(ttyfd, FIOCLEX, 0); -#elif FD_CLOEXEC - err = fcntl(ttyfd, F_SETFD, - fcntl(ttyfd, F_GETFD, 0) | FD_CLOEXEC); -#endif - if (err == -1) { - close(ttyfd); - ttyfd = -1; - goto out; - } + register_sh_fd(ttyfd, ttyfd_change); #else out2str("sh: Need FIOCLEX or FD_CLOEXEC to support job control"); goto out; #endif do { /* while we are in the background */ if ((initialpgrp = tcgetpgrp(ttyfd)) < 0) { -out: + out: out2str("sh: can't access tty; job control turned off\n"); mflag = 0; return; @@ -217,7 +214,7 @@ out: if (tcsetpgrp(ttyfd, initialpgrp) == -1) error("Cannot set tty process group (%s) at %d", strerror(errno), __LINE__); - close(ttyfd); + sh_close(ttyfd); ttyfd = -1; setsignal(SIGTSTP, 0); setsignal(SIGTTOU, 0); @@ -1312,7 +1309,7 @@ cmdtxt(union node *n) goto until; case NUNTIL: cmdputs("until "); -until: + until: cmdtxt(n->nbinary.ch1); cmdputs("; do "); cmdtxt(n->nbinary.ch2); @@ -1366,7 +1363,7 @@ until: p = "<&"; i = 0; goto redir; case NFROMTO: p = "<>"; i = 0; goto redir; -redir: + redir: if (n->nfile.fd != i) cmdputi(n->nfile.fd); cmdputs(p); Index: src/bin/sh/redir.c diff -u src/bin/sh/redir.c:1.53 src/bin/sh/redir.c:1.54 --- src/bin/sh/redir.c:1.53 Sat Apr 22 16:02:39 2017 +++ src/bin/sh/redir.c Sat Apr 29 15:14:28 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: redir.c,v 1.53 2017/04/22 16:02:39 kre Exp $ */ +/* $NetBSD: redir.c,v 1.54 2017/04/29 15:14:28 kre Exp $ */ /*- * Copyright (c) 1991, 1993 @@ -37,7 +37,7 @@ #if 0 static char sccsid[] = "@(#)redir.c 8.2 (Berkeley) 5/4/95"; #else -__RCSID("$NetBSD: redir.c,v 1.53 2017/04/22 16:02:39 kre Exp $"); +__RCSID("$NetBSD: redir.c,v 1.54 2017/04/29 15:14:28 kre Exp $"); #endif #endif /* not lint */ @@ -115,6 +115,18 @@ STATIC int openhere(const union node *); STATIC int copyfd(int, int, int); STATIC void find_big_fd(void); + +struct shell_fds { /* keep track of internal shell fds */ + struct shell_fds *nxt; + void (*cb)(int, int); + int fd; +}; + +STATIC struct shell_fds *sh_fd_list; + +STATIC void renumber_sh_fd(struct shell_fds *); +STATIC struct shell_fds *sh_fd(int); + STATIC const struct renamelist * is_renamed(const struct renamelist *rl, int fd) { @@ -191,6 +203,7 @@ redirect(union node *redir, int flags) fd = n->nfile.fd; if (fd > max_user_fd) max_user_fd = fd; + renumber_sh_fd(sh_fd(fd)); if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) && n->ndup.dupfd == fd) { /* redirect from/to same file descriptor */ @@ -505,8 +518,12 @@ STATIC void find_big_fd(void) { int i, fd; + static int last_start = 6; - for (i = (1 << 10); i >= 10; i >>= 1) { + if (last_start < 10) + last_start++; + + for (i = (1 << last_start); i >= 10; i >>= 1) { if ((fd = fcntl(0, F_DUPFD, i - 1)) >= 0) { close(fd); break; @@ -514,9 +531,7 @@ find_big_fd(void) } fd = (i / 5) * 4; - if ((i - fd) > 100) - fd = i - 100; - else if (fd < 10) + if (fd < 10) fd = 10; big_sh_fd = fd; @@ -543,7 +558,7 @@ to_upper_fd(int fd) close(fd); return i; } - if (errno != EMFILE) + if (errno != EMFILE && errno != EINVAL) break; find_big_fd(); } while (big_sh_fd > 10); @@ -557,6 +572,85 @@ to_upper_fd(int fd) return fd; } +void +register_sh_fd(int fd, void (*cb)(int, int)) +{ + struct shell_fds *fp; + + fp = ckmalloc(sizeof (struct shell_fds)); + if (fp != NULL) { + fp->nxt = sh_fd_list; + sh_fd_list = fp; + + fp->fd = fd; + fp->cb = cb; + } +} + +void +sh_close(int fd) +{ + struct shell_fds **fpp, *fp; + + fpp = &sh_fd_list; + while ((fp = *fpp) != NULL) { + if (fp->fd == fd) { + *fpp = fp->nxt; + ckfree(fp); + break; + } + fpp = &fp->nxt; + } + (void)close(fd); +} + +STATIC struct shell_fds * +sh_fd(int fd) +{ + struct shell_fds *fp; + + for (fp = sh_fd_list; fp != NULL; fp = fp->nxt) + if (fp->fd == fd) + return fp; + return NULL; +} + +STATIC void +renumber_sh_fd(struct shell_fds *fp) +{ + int to; + + if (fp == NULL) + return; + +#ifndef F_DUPFD_CLOEXEC +#define F_DUPFD_CLOEXEC F_DUPFD +#define CLOEXEC(fd) (fcntl((fd), F_SETFD, fcntl((fd),F_GETFD) | FD_CLOEXEC)) +#else +#define CLOEXEC(fd) +#endif + + to = fcntl(fp->fd, F_DUPFD_CLOEXEC, big_sh_fd); + if (to == -1) + to = fcntl(fp->fd, F_DUPFD_CLOEXEC, big_sh_fd/2); + if (to == -1) + to = fcntl(fp->fd, F_DUPFD_CLOEXEC, fp->fd + 1); + if (to == -1) + to = fcntl(fp->fd, F_DUPFD_CLOEXEC, 10); + if (to == -1) + to = fcntl(fp->fd, F_DUPFD_CLOEXEC, 3); + if (to == -1) + error("insufficient file descriptors available"); + CLOEXEC(to); + + if (fp->fd == to) /* impossible? */ + return; + + (*fp->cb)(fp->fd, to); + (void)close(fp->fd); + fp->fd = to; +} + static const struct flgnames { const char *name; uint32_t value; @@ -604,6 +698,13 @@ getflags(int fd, int p) { int c, f; + if (sh_fd(fd) != NULL) { + if (!p) + return -1; + error("Can't get status for fd=%d (%s)", fd, + "Bad file descriptor"); /*XXX*/ + } + if ((c = fcntl(fd, F_GETFD)) == -1) { if (!p) return -1; Index: src/bin/sh/redir.h diff -u src/bin/sh/redir.h:1.22 src/bin/sh/redir.h:1.23 --- src/bin/sh/redir.h:1.22 Sat Apr 22 16:02:39 2017 +++ src/bin/sh/redir.h Sat Apr 29 15:14:28 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: redir.h,v 1.22 2017/04/22 16:02:39 kre Exp $ */ +/* $NetBSD: redir.h,v 1.23 2017/04/29 15:14:28 kre Exp $ */ /*- * Copyright (c) 1991, 1993 @@ -47,5 +47,7 @@ int fd0_redirected_p(void); void clearredir(int); int movefd(int, int); int to_upper_fd(int); +void register_sh_fd(int, void (*)(int, int)); +void sh_close(int); int max_user_fd; /* highest fd used by user */