diff options
author | Otto Moerbeek <otto@cvs.openbsd.org> | 2006-12-21 21:38:18 +0000 |
---|---|---|
committer | Otto Moerbeek <otto@cvs.openbsd.org> | 2006-12-21 21:38:18 +0000 |
commit | f9f7ec707ffe7de9925e43d353e926006f955ef4 (patch) | |
tree | c00ed4debd460693efd7d984161f8e9bec109da7 /usr.bin/vi | |
parent | 97b1b0c6f8bf176bf77ee22010b7e47c32930df7 (diff) |
Fix !command piping by Alexander Bluhm in PR 5325. Tested by quite a
few on tech@.
Diffstat (limited to 'usr.bin/vi')
-rw-r--r-- | usr.bin/vi/ex/ex_filter.c | 161 |
1 files changed, 104 insertions, 57 deletions
diff --git a/usr.bin/vi/ex/ex_filter.c b/usr.bin/vi/ex/ex_filter.c index e709f6e539f..8e0ede942b7 100644 --- a/usr.bin/vi/ex/ex_filter.c +++ b/usr.bin/vi/ex/ex_filter.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ex_filter.c,v 1.8 2006/01/08 21:05:40 miod Exp $ */ +/* $OpenBSD: ex_filter.c,v 1.9 2006/12/21 21:38:17 otto Exp $ */ /*- * Copyright (c) 1991, 1993, 1994 @@ -15,6 +15,8 @@ static const char sccsid[] = "@(#)ex_filter.c 10.34 (Berkeley) 10/23/96"; #endif /* not lint */ +#include <sys/param.h> +#include <sys/stat.h> #include <sys/types.h> #include <sys/queue.h> @@ -51,8 +53,8 @@ ex_filter(sp, cmdp, fm, tm, rp, cmd, ftype) FILE *ifp, *ofp; pid_t parent_writer_pid, utility_pid; recno_t nread; - int input[2], output[2], rval; - char *name; + int input[2], output[2], fd, rval; + char *name, tname[MAXPATHLEN]; rval = 0; @@ -84,7 +86,45 @@ ex_filter(sp, cmdp, fm, tm, rp, cmd, ftype) */ ofp = NULL; input[0] = input[1] = output[0] = output[1] = -1; - if (ftype != FILTER_READ && pipe(input) < 0) { + + if (ftype == FILTER_BANG) { + if (opts_empty(sp, O_DIRECTORY, 0)) + goto err; + (void)snprintf(tname, sizeof(tname), + "%s/vi.XXXXXXXXXX", O_STR(sp, O_DIRECTORY)); + fd = mkstemp(tname); + if (fd == -1) { + msgq(sp, M_SYSERR, + "237|Unable to create temporary file"); + if (fd != -1) { + (void)close(fd); + (void)unlink(tname); + } + goto err; + } + if (unlink(tname) == -1) + msgq(sp, M_SYSERR, "unlink"); + if ((ifp = fdopen(fd, "w")) == NULL) { + msgq(sp, M_SYSERR, "fdopen"); + (void)close(fd); + goto err; + } + if ((input[0] = dup(fd)) == -1) { + msgq(sp, M_SYSERR, "dup"); + (void)fclose(ifp); + goto err; + } + /* + * Write the selected lines into the temporary file. + * This instance of ifp is closed by ex_writefp. + */ + if (ex_writefp(sp, "filter", ifp, fm, tm, NULL, NULL, 1)) + goto err; + if (lseek(input[0], 0, SEEK_SET) == -1) { + msgq(sp, M_SYSERR, "lseek"); + goto err; + } + } else if (ftype != FILTER_READ && pipe(input) < 0) { msgq(sp, M_SYSERR, "pipe"); goto err; } @@ -187,11 +227,10 @@ err: if (input[0] != -1) else rp->lno += nread; } - goto uwait; } /* - * FILTER_BANG, FILTER_WRITE + * FILTER_WRITE * * Here we need both a reader and a writer. Temporary files are * expensive and we'd like to avoid disk I/O. Using pipes has the @@ -202,74 +241,84 @@ err: if (input[0] != -1) * write lines out * exit * parent - * FILTER_BANG: - * read lines into the file - * delete old lines - * FILTER_WRITE - * read and display lines + * read and display lines * wait for child * - * XXX * We get away without locking the underlying database because we know - * that none of the records that we're reading will be modified until - * after we've read them. This depends on the fact that the current - * B+tree implementation doesn't balance pages or similar things when - * it inserts new records. When the DB code has locking, we should - * treat vi as if it were multiple applications sharing a database, and - * do the required locking. If necessary a work-around would be to do - * explicit locking in the line.c:db_get() code, based on the flag set - * here. + * that filter_ldisplay() does not modify it. When the DB code has + * locking, we should treat vi as if it were multiple applications + * sharing a database, and do the required locking. If necessary a + * work-around would be to do explicit locking in the line.c:db_get() + * code, based on the flag set here. */ - F_SET(sp->ep, F_MULTILOCK); - switch (parent_writer_pid = fork()) { - case -1: /* Error. */ - msgq(sp, M_SYSERR, "fork"); - (void)close(input[1]); - (void)close(output[0]); - rval = 1; - break; - case 0: /* Parent-writer. */ - /* - * Write the selected lines to the write end of the input - * pipe. This instance of ifp is closed by ex_writefp. - */ - (void)close(output[0]); - if ((ifp = fdopen(input[1], "w")) == NULL) - _exit (1); - _exit(ex_writefp(sp, "filter", ifp, fm, tm, NULL, NULL, 1)); - - /* NOTREACHED */ - default: /* Parent-reader. */ - (void)close(input[1]); - if (ftype == FILTER_WRITE) { + if (ftype == FILTER_WRITE) { + F_SET(sp->ep, F_MULTILOCK); + switch (parent_writer_pid = fork()) { + case -1: /* Error. */ + msgq(sp, M_SYSERR, "fork"); + (void)close(input[1]); + (void)close(output[0]); + rval = 1; + break; + case 0: /* Parent-writer. */ + /* + * Write the selected lines to the write end of the + * input pipe. This instance of ifp is closed by + * ex_writefp. + */ + (void)close(output[0]); + if ((ifp = fdopen(input[1], "w")) == NULL) + _exit (1); + _exit(ex_writefp(sp, "filter", + ifp, fm, tm, NULL, NULL, 1)); + /* NOTREACHED */ + default: /* Parent-reader. */ + (void)close(input[1]); /* * Read the output from the read end of the output * pipe and display it. Filter_ldisplay closes ofp. */ if (filter_ldisplay(sp, ofp)) rval = 1; - } else { - /* - * Read the output from the read end of the output - * pipe. Ex_readfp appends to the MARK and closes - * ofp. - */ - if (ex_readfp(sp, "filter", ofp, tm, &nread, 1)) + + /* Wait for the parent-writer. */ + if (proc_wait(sp, + parent_writer_pid, "parent-writer", 0, 1)) rval = 1; - sp->rptlines[L_ADDED] += nread; + break; } + F_CLR(sp->ep, F_MULTILOCK); + } - /* Wait for the parent-writer. */ - if (proc_wait(sp, - parent_writer_pid, "parent-writer", 0, 1)) + /* + * FILTER_BANG + * + * Here we need a temporary file because our database lacks locking. + * + * XXX + * Temporary files are expensive and we'd like to avoid disk I/O. + * When the DB code has locking, we should treat vi as if it were + * multiple applications sharing a database, and do the required + * locking. If necessary a work-around would be to do explicit + * locking in the line.c:db_get() code, based on F_MULTILOCK flag set + * here. + */ + if (ftype == FILTER_BANG) { + /* + * Read the output from the read end of the output + * pipe. Ex_readfp appends to the MARK and closes + * ofp. + */ + if (ex_readfp(sp, "filter", ofp, tm, &nread, 1)) rval = 1; + sp->rptlines[L_ADDED] += nread; /* Delete any lines written to the utility. */ - if (rval == 0 && ftype == FILTER_BANG && + if (rval == 0 && (cut(sp, NULL, fm, tm, CUT_LINEMODE) || del(sp, fm, tm, 1))) { rval = 1; - break; + goto uwait; } /* @@ -279,9 +328,7 @@ err: if (input[0] != -1) */ if (rp->lno > 1 && !db_exist(sp, rp->lno)) --rp->lno; - break; } - F_CLR(sp->ep, F_MULTILOCK); /* * !!! |