diff -ur netbsd-sh/eval.c netbsd-sh-/eval.c --- netbsd-sh/eval.c Tue May 23 12:03:18 2000 +++ netbsd-sh-/eval.c Mon Apr 23 23:33:34 2001 @@ -442,6 +442,7 @@ case NFROM: case NTO: case NAPPEND: + case NTOOV: expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); redir->nfile.expfname = fn.list->text; break; diff -ur netbsd-sh/exec.c netbsd-sh-/exec.c --- netbsd-sh/exec.c Fri Jan 12 17:50:35 2001 +++ netbsd-sh-/exec.c Mon Apr 23 23:33:34 2001 @@ -125,6 +125,10 @@ char *cmdname; int e; + if (fd2 >= 0 && fd2 != 2) { + close(fd2); + } + if (strchr(argv[0], '/') != NULL) { tryexec(argv[0], argv, envp); e = errno; diff -ur netbsd-sh/jobs.c netbsd-sh-/jobs.c --- netbsd-sh/jobs.c Mon Apr 23 23:34:53 2001 +++ netbsd-sh-/jobs.c Mon Apr 23 23:34:30 2001 @@ -129,9 +129,9 @@ if (on) { do { /* while we are in the background */ #ifdef OLD_TTY_DRIVER - if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) { + if (ioctl(fd2, TIOCGPGRP, (char *)&initialpgrp) < 0) { #else - initialpgrp = tcgetpgrp(2); + initialpgrp = tcgetpgrp(fd2); if (initialpgrp < 0) { #endif out2str("sh: can't access tty; job control turned off\n"); @@ -146,7 +146,7 @@ } } while (0); #ifdef OLD_TTY_DRIVER - if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) { + if (ioctl(fd2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) { out2str("sh: need new tty driver to run job control; job control turned off\n"); mflag = 0; return; @@ -157,16 +157,16 @@ setsignal(SIGTTIN); setpgid(0, rootpid); #ifdef OLD_TTY_DRIVER - ioctl(2, TIOCSPGRP, (char *)&rootpid); + ioctl(fd2, TIOCSPGRP, (char *)&rootpid); #else - tcsetpgrp(2, rootpid); + tcsetpgrp(fd2, rootpid); #endif } else { /* turning job control off */ setpgid(0, initialpgrp); #ifdef OLD_TTY_DRIVER - ioctl(2, TIOCSPGRP, (char *)&initialpgrp); + ioctl(fd2, TIOCSPGRP, (char *)&initialpgrp); #else - tcsetpgrp(2, initialpgrp); + tcsetpgrp(fd2, initialpgrp); #endif setsignal(SIGTSTP); setsignal(SIGTTOU); @@ -206,9 +206,9 @@ error("job not created under job control"); pgrp = jp->ps[0].pid; #ifdef OLD_TTY_DRIVER - ioctl(2, TIOCSPGRP, (char *)&pgrp); + ioctl(fd2, TIOCSPGRP, (char *)&pgrp); #else - tcsetpgrp(2, pgrp); + tcsetpgrp(fd2, pgrp); #endif restartjob(jp); INTOFF; @@ -612,10 +612,10 @@ if (mode == FORK_FG) { /*** this causes superfluous TIOCSPGRPS ***/ #ifdef OLD_TTY_DRIVER - if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0) + if (ioctl(fd2, TIOCSPGRP, (char *)&pgrp) < 0) error("TIOCSPGRP failed, errno=%d", errno); #else - if (tcsetpgrp(2, pgrp) < 0) + if (tcsetpgrp(fd2, pgrp) < 0) error("tcsetpgrp failed, errno=%d", errno); #endif } @@ -734,10 +734,10 @@ #if JOBS if (jp->jobctl) { #ifdef OLD_TTY_DRIVER - if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0) + if (ioctl(fd2, TIOCSPGRP, (char *)&mypgrp) < 0) error("TIOCSPGRP failed, errno=%d\n", errno); #else - if (tcsetpgrp(2, mypgrp) < 0) + if (tcsetpgrp(fd2, mypgrp) < 0) error("tcsetpgrp failed, errno=%d\n", errno); #endif } @@ -1092,6 +1092,8 @@ p = ">>"; i = 1; goto redir; case NTOFD: p = ">&"; i = 1; goto redir; + case NTOOV: + p = ">|"; i = 1; goto redir; case NFROM: p = "<"; i = 0; goto redir; case NFROMFD: Only in netbsd-sh-: jobs.c.orig diff -ur netbsd-sh/nodetypes netbsd-sh-/nodetypes --- netbsd-sh/nodetypes Fri Feb 5 13:04:52 1999 +++ netbsd-sh-/nodetypes Mon Apr 23 23:33:34 2001 @@ -119,6 +119,7 @@ NFROM nfile # fd< fname NFROMTO nfile # fd<> fname NAPPEND nfile # fd>> fname +NTOOV nfile # fd>| fname type int next nodeptr # next redirection in list fd int # file descriptor being redirected diff -ur netbsd-sh/parser.c netbsd-sh-/parser.c --- netbsd-sh/parser.c Fri Jan 12 17:50:39 2001 +++ netbsd-sh-/parser.c Mon Apr 23 23:33:34 2001 @@ -1125,6 +1125,8 @@ np->type = NAPPEND; else if (c == '&') np->type = NTOFD; + else if (c == '|') + np->type = NTOOV; else { np->type = NTO; pungetc(); diff -ur netbsd-sh/redir.c netbsd-sh-/redir.c --- netbsd-sh/redir.c Tue May 23 12:03:19 2000 +++ netbsd-sh-/redir.c Mon Apr 23 23:33:34 2001 @@ -45,6 +45,7 @@ #endif #endif /* not lint */ +#include #include #include /* PIPE_BUF */ #include @@ -66,6 +67,7 @@ #include "output.h" #include "memalloc.h" #include "error.h" +#include "options.h" #define EMPTY -2 /* marks an unused slot in redirtab */ @@ -92,8 +94,15 @@ */ int fd0_redirected = 0; -STATIC void openredirect __P((union node *, char[10 ])); +/* + * We also keep track of where fd2 goes. + */ +int fd2 = 2; + +STATIC int openredirect __P((union node *)); +STATIC void dupredirect __P((union node *, int, char[10 ])); STATIC int openhere __P((union node *)); +STATIC int noclobberopen __P((const char *)); /* @@ -113,6 +122,7 @@ struct redirtab *sv = NULL; int i; int fd; + int newfd; int try; char memory[10]; /* file descriptors to write to memory */ @@ -133,36 +143,47 @@ n->ndup.dupfd == fd) continue; /* redirect from/to same file descriptor */ - if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) { - INTOFF; -again: - if ((i = fcntl(fd, F_DUPFD, 10)) == -1) { + INTOFF; + newfd = openredirect(n); + if (((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) || + (fd == fd2)) { + if (newfd == fd) { + try++; + } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) { switch (errno) { case EBADF: if (!try) { - openredirect(n, memory); + dupredirect(n, newfd, memory); try++; - goto again; + break; } /* FALLTHROUGH*/ default: + if (newfd >= 0) { + close(newfd); + } INTON; error("%d: %s", fd, strerror(errno)); /* NOTREACHED */ } } if (!try) { - sv->renamed[fd] = i; close(fd); + if (flags & REDIR_PUSH) { + sv->renamed[fd] = i; + } + if (fd == fd2) { + fd2 = i; + } } - INTON; - } else { + } else if (fd != newfd) { close(fd); } if (fd == 0) fd0_redirected++; if (!try) - openredirect(n, memory); + dupredirect(n, newfd, memory); + INTON; } if (memory[1]) out1 = &memout; @@ -171,22 +192,13 @@ } -STATIC void -openredirect(redir, memory) +STATIC int +openredirect(redir) union node *redir; - char memory[10]; { - int fd = redir->nfile.fd; char *fname; int f; - /* - * We suppress interrupts so that we won't leave open file - * descriptors around. This may not be such a good idea because - * an open of a device or a fifo can block indefinitely. - */ - INTOFF; - memory[fd] = 0; switch (redir->nfile.type) { case NFROM: fname = redir->nfile.expfname; @@ -199,6 +211,14 @@ goto ecreate; break; case NTO: + /* Take care of noclobber mode. */ + if (Cflag) { + fname = redir->nfile.expfname; + if ((f = noclobberopen(fname)) < 0) + goto ecreate; + break; + } + case NTOOV: fname = redir->nfile.expfname; #ifdef O_CREAT if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) @@ -222,32 +242,48 @@ break; case NTOFD: case NFROMFD: + f = -1; + break; + case NHERE: + case NXHERE: + f = openhere(redir); + break; + default: + abort(); + } + + return f; +ecreate: + error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); +eopen: + error("cannot open %s: %s", fname, errmsg(errno, E_OPEN)); +} + + +STATIC void +dupredirect(redir, f, memory) + union node *redir; + int f; + char memory[10]; + { + int fd = redir->nfile.fd; + + memory[fd] = 0; + if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) { if (redir->ndup.dupfd >= 0) { /* if not ">&-" */ if (memory[redir->ndup.dupfd]) memory[fd] = 1; else copyfd(redir->ndup.dupfd, fd); } - INTON; return; - case NHERE: - case NXHERE: - f = openhere(redir); - break; - default: - abort(); } if (f != fd) { copyfd(f, fd); close(f); } - INTON; return; -ecreate: - error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); -eopen: - error("cannot open %s: %s", fname, errmsg(errno, E_OPEN)); } @@ -304,6 +340,7 @@ struct redirtab *rp = redirlist; int i; + INTOFF; for (i = 0 ; i < 10 ; i++) { if (rp->renamed[i] != EMPTY) { if (i == 0) @@ -313,9 +350,11 @@ copyfd(rp->renamed[i], i); close(rp->renamed[i]); } + if (rp->renamed[i] == fd2) { + fd2 = i; + } } } - INTOFF; redirlist = rp->next; ckfree(rp); INTON; @@ -359,6 +398,9 @@ for (i = 0 ; i < 10 ; i++) { if (rp->renamed[i] >= 0) { close(rp->renamed[i]); + if (rp->renamed[i] == fd2) { + fd2 = -1; + } } rp->renamed[i] = EMPTY; } @@ -388,4 +430,63 @@ error("%d: %s", from, strerror(errno)); } return newfd; +} + +/* + * Open a file in noclobber mode. + * The code was copied from bash. + */ +int +noclobberopen(fname) + const char *fname; +{ + int r, fd; + struct stat finfo, finfo2; + + /* + * If the file exists and is a regular file, return an error + * immediately. + */ + r = stat(fname, &finfo); + if (r == 0 && S_ISREG(finfo.st_mode)) { + errno = EEXIST; + return -1; + } + + /* + * If the file was not present (r != 0), make sure we open it + * exclusively so that if it is created before we open it, our open + * will fail. Make sure that we do not truncate an existing file. + * Note that we don't turn on O_EXCL unless the stat failed -- if the + * file was not a regular file, we leave O_EXCL off. + */ + if (r != 0) + return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666); + fd = open(fname, O_WRONLY|O_CREAT, 0666); + + /* If the open failed, return the file descriptor right away. */ + if (fd < 0) + return fd; + + /* + * OK, the open succeeded, but the file may have been changed from a + * non-regular file to a regular file between the stat and the open. + * We are assuming that the O_EXCL open handles the case where FILENAME + * did not exist and is symlinked to an existing file between the stat + * and open. + */ + + /* + * If we can open it and fstat the file descriptor, and neither check + * revealed that it was a regular file, and the file has not been + * replaced, return the file descriptor. + */ + if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) && + finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino) + return fd; + + /* The file has been replaced. badness. */ + close(fd); + errno = EEXIST; + return -1; } Only in netbsd-sh-: redir.c.orig diff -ur netbsd-sh/redir.h netbsd-sh-/redir.h --- netbsd-sh/redir.h Tue May 23 12:03:19 2000 +++ netbsd-sh-/redir.h Mon Apr 23 23:33:34 2001 @@ -42,6 +42,8 @@ #define REDIR_PUSH 01 /* save previous values of file descriptors */ #define REDIR_BACKQ 02 /* save the command output in memory */ +extern int fd2; + union node; void redirect __P((union node *, int)); void popredir __P((void)); diff -ur netbsd-sh/show.c netbsd-sh-/show.c --- netbsd-sh/show.c Sat Oct 9 13:02:09 1999 +++ netbsd-sh-/show.c Mon Apr 23 23:33:34 2001 @@ -155,6 +155,7 @@ case NTO: s = ">"; dftfd = 1; break; case NAPPEND: s = ">>"; dftfd = 1; break; case NTOFD: s = ">&"; dftfd = 1; break; + case NTOOV: s = ">|"; dftfd = 1; break; case NFROM: s = "<"; dftfd = 0; break; case NFROMFD: s = "<&"; dftfd = 0; break; case NFROMTO: s = "<>"; dftfd = 0; break;