14b88c807SRodney W. Grimes /*- 24b88c807SRodney W. Grimes * Copyright (c) 1991, 1993 34b88c807SRodney W. Grimes * The Regents of the University of California. All rights reserved. 44b88c807SRodney W. Grimes * 54b88c807SRodney W. Grimes * This code is derived from software contributed to Berkeley by 64b88c807SRodney W. Grimes * Kenneth Almquist. 74b88c807SRodney W. Grimes * 84b88c807SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 94b88c807SRodney W. Grimes * modification, are permitted provided that the following conditions 104b88c807SRodney W. Grimes * are met: 114b88c807SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 124b88c807SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 134b88c807SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 144b88c807SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 154b88c807SRodney W. Grimes * documentation and/or other materials provided with the distribution. 164b88c807SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 174b88c807SRodney W. Grimes * may be used to endorse or promote products derived from this software 184b88c807SRodney W. Grimes * without specific prior written permission. 194b88c807SRodney W. Grimes * 204b88c807SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 214b88c807SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 224b88c807SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 234b88c807SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 244b88c807SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 254b88c807SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 264b88c807SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 274b88c807SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 284b88c807SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 294b88c807SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 304b88c807SRodney W. Grimes * SUCH DAMAGE. 314b88c807SRodney W. Grimes */ 324b88c807SRodney W. Grimes 334b88c807SRodney W. Grimes #ifndef lint 343d7b5b93SPhilippe Charnier #if 0 353d7b5b93SPhilippe Charnier static char sccsid[] = "@(#)output.c 8.2 (Berkeley) 5/4/95"; 363d7b5b93SPhilippe Charnier #endif 374b88c807SRodney W. Grimes #endif /* not lint */ 382749b141SDavid E. O'Brien #include <sys/cdefs.h> 392749b141SDavid E. O'Brien __FBSDID("$FreeBSD$"); 404b88c807SRodney W. Grimes 414b88c807SRodney W. Grimes /* 424b88c807SRodney W. Grimes * Shell output routines. We use our own output routines because: 434b88c807SRodney W. Grimes * When a builtin command is interrupted we have to discard 444b88c807SRodney W. Grimes * any pending output. 454b88c807SRodney W. Grimes * When a builtin command appears in back quotes, we want to 464b88c807SRodney W. Grimes * save the output of the command in a region obtained 474b88c807SRodney W. Grimes * via malloc, rather than doing a fork and reading the 484b88c807SRodney W. Grimes * output of the command via a pipe. 494b88c807SRodney W. Grimes */ 504b88c807SRodney W. Grimes 514b88c807SRodney W. Grimes #include <stdio.h> /* defines BUFSIZ */ 52aa9caaf6SPeter Wemm #include <string.h> 53aa9caaf6SPeter Wemm #include <stdarg.h> 54aa9caaf6SPeter Wemm #include <errno.h> 55aa9caaf6SPeter Wemm #include <unistd.h> 56aa9caaf6SPeter Wemm #include <stdlib.h> 57aa9caaf6SPeter Wemm 584b88c807SRodney W. Grimes #include "shell.h" 594b88c807SRodney W. Grimes #include "syntax.h" 604b88c807SRodney W. Grimes #include "output.h" 614b88c807SRodney W. Grimes #include "memalloc.h" 624b88c807SRodney W. Grimes #include "error.h" 63dee75cf7STim J. Robbins #include "var.h" 644b88c807SRodney W. Grimes 654b88c807SRodney W. Grimes 664b88c807SRodney W. Grimes #define OUTBUFSIZ BUFSIZ 674b88c807SRodney W. Grimes #define BLOCK_OUT -2 /* output to a fixed block of memory */ 684b88c807SRodney W. Grimes #define MEM_OUT -3 /* output to dynamically allocated memory */ 694b88c807SRodney W. Grimes #define OUTPUT_ERR 01 /* error occurred on output */ 704b88c807SRodney W. Grimes 7188328642SDavid E. O'Brien static int doformat_wr(void *, const char *, int); 724b88c807SRodney W. Grimes 734b88c807SRodney W. Grimes struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0}; 74c6204d4aSJilles Tjoelker struct output errout = {NULL, 0, NULL, 256, 2, 0}; 754b88c807SRodney W. Grimes struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0}; 764b88c807SRodney W. Grimes struct output *out1 = &output; 774b88c807SRodney W. Grimes struct output *out2 = &errout; 784b88c807SRodney W. Grimes 794b88c807SRodney W. Grimes 804b88c807SRodney W. Grimes 814b88c807SRodney W. Grimes #ifdef mkinit 824b88c807SRodney W. Grimes 834b88c807SRodney W. Grimes INCLUDE "output.h" 844b88c807SRodney W. Grimes INCLUDE "memalloc.h" 854b88c807SRodney W. Grimes 864b88c807SRodney W. Grimes RESET { 874b88c807SRodney W. Grimes out1 = &output; 884b88c807SRodney W. Grimes out2 = &errout; 894b88c807SRodney W. Grimes if (memout.buf != NULL) { 904b88c807SRodney W. Grimes ckfree(memout.buf); 914b88c807SRodney W. Grimes memout.buf = NULL; 924b88c807SRodney W. Grimes } 934b88c807SRodney W. Grimes } 944b88c807SRodney W. Grimes 954b88c807SRodney W. Grimes #endif 964b88c807SRodney W. Grimes 974b88c807SRodney W. Grimes 984b88c807SRodney W. Grimes void 99*aeb5d065SJilles Tjoelker outcslow(int c, struct output *file) 100*aeb5d065SJilles Tjoelker { 101*aeb5d065SJilles Tjoelker outc(c, file); 102*aeb5d065SJilles Tjoelker } 103*aeb5d065SJilles Tjoelker 104*aeb5d065SJilles Tjoelker void 1055134c3f7SWarner Losh out1str(const char *p) 1064b88c807SRodney W. Grimes { 1074b88c807SRodney W. Grimes outstr(p, out1); 1084b88c807SRodney W. Grimes } 1094b88c807SRodney W. Grimes 110e5341cbbSTim J. Robbins void 111e5341cbbSTim J. Robbins out1qstr(const char *p) 112e5341cbbSTim J. Robbins { 113e5341cbbSTim J. Robbins outqstr(p, out1); 114e5341cbbSTim J. Robbins } 1154b88c807SRodney W. Grimes 1164b88c807SRodney W. Grimes void 1175134c3f7SWarner Losh out2str(const char *p) 1184b88c807SRodney W. Grimes { 1194b88c807SRodney W. Grimes outstr(p, out2); 1204b88c807SRodney W. Grimes } 1214b88c807SRodney W. Grimes 122e5341cbbSTim J. Robbins void 123e5341cbbSTim J. Robbins out2qstr(const char *p) 124e5341cbbSTim J. Robbins { 125e5341cbbSTim J. Robbins outqstr(p, out2); 126e5341cbbSTim J. Robbins } 1274b88c807SRodney W. Grimes 1284b88c807SRodney W. Grimes void 1295134c3f7SWarner Losh outstr(const char *p, struct output *file) 1304b88c807SRodney W. Grimes { 131c3f57269SJilles Tjoelker outbin(p, strlen(p), file); 1324b88c807SRodney W. Grimes } 1334b88c807SRodney W. Grimes 134e5341cbbSTim J. Robbins /* Like outstr(), but quote for re-input into the shell. */ 135e5341cbbSTim J. Robbins void 136e5341cbbSTim J. Robbins outqstr(const char *p, struct output *file) 137e5341cbbSTim J. Robbins { 138e5341cbbSTim J. Robbins char ch; 139e68165a6SJilles Tjoelker int inquotes; 140e5341cbbSTim J. Robbins 1413f0131f6SStefan Farfeleder if (p[0] == '\0') { 1423f0131f6SStefan Farfeleder outstr("''", file); 1433f0131f6SStefan Farfeleder return; 1443f0131f6SStefan Farfeleder } 145e68165a6SJilles Tjoelker /* Caller will handle '=' if necessary */ 146e68165a6SJilles Tjoelker if (p[strcspn(p, "|&;<>()$`\\\"' \t\n*?[~#")] == '\0' || 147e68165a6SJilles Tjoelker strcmp(p, "[") == 0) { 148dee75cf7STim J. Robbins outstr(p, file); 149dee75cf7STim J. Robbins return; 150dee75cf7STim J. Robbins } 151dee75cf7STim J. Robbins 152e68165a6SJilles Tjoelker inquotes = 0; 153e5341cbbSTim J. Robbins while ((ch = *p++) != '\0') { 154e5341cbbSTim J. Robbins switch (ch) { 155e5341cbbSTim J. Robbins case '\'': 156e68165a6SJilles Tjoelker /* Can't quote single quotes inside single quotes. */ 157e68165a6SJilles Tjoelker if (inquotes) 158*aeb5d065SJilles Tjoelker outcslow('\'', file); 159e68165a6SJilles Tjoelker inquotes = 0; 160e68165a6SJilles Tjoelker outstr("\\'", file); 161e5341cbbSTim J. Robbins break; 162e5341cbbSTim J. Robbins default: 163e68165a6SJilles Tjoelker if (!inquotes) 164*aeb5d065SJilles Tjoelker outcslow('\'', file); 165e68165a6SJilles Tjoelker inquotes = 1; 166e5341cbbSTim J. Robbins outc(ch, file); 167e5341cbbSTim J. Robbins } 168e5341cbbSTim J. Robbins } 169e68165a6SJilles Tjoelker if (inquotes) 170*aeb5d065SJilles Tjoelker outcslow('\'', file); 171e5341cbbSTim J. Robbins } 1724b88c807SRodney W. Grimes 173c3f57269SJilles Tjoelker void 174c3f57269SJilles Tjoelker outbin(const void *data, size_t len, struct output *file) 175c3f57269SJilles Tjoelker { 176c3f57269SJilles Tjoelker const char *p; 177c3f57269SJilles Tjoelker 178c3f57269SJilles Tjoelker p = data; 179c3f57269SJilles Tjoelker while (len-- > 0) 180c3f57269SJilles Tjoelker outc(*p++, file); 181c3f57269SJilles Tjoelker } 182c3f57269SJilles Tjoelker 183aa7b6f82SDavid E. O'Brien static char out_junk[16]; 1844b88c807SRodney W. Grimes 1854b88c807SRodney W. Grimes void 1865134c3f7SWarner Losh emptyoutbuf(struct output *dest) 1874b88c807SRodney W. Grimes { 1884b88c807SRodney W. Grimes int offset; 1894b88c807SRodney W. Grimes 1904b88c807SRodney W. Grimes if (dest->fd == BLOCK_OUT) { 1914b88c807SRodney W. Grimes dest->nextc = out_junk; 1924b88c807SRodney W. Grimes dest->nleft = sizeof out_junk; 1934b88c807SRodney W. Grimes dest->flags |= OUTPUT_ERR; 1944b88c807SRodney W. Grimes } else if (dest->buf == NULL) { 1954b88c807SRodney W. Grimes INTOFF; 1964b88c807SRodney W. Grimes dest->buf = ckmalloc(dest->bufsize); 1974b88c807SRodney W. Grimes dest->nextc = dest->buf; 1984b88c807SRodney W. Grimes dest->nleft = dest->bufsize; 1994b88c807SRodney W. Grimes INTON; 2004b88c807SRodney W. Grimes } else if (dest->fd == MEM_OUT) { 2014b88c807SRodney W. Grimes offset = dest->bufsize; 2024b88c807SRodney W. Grimes INTOFF; 2034b88c807SRodney W. Grimes dest->bufsize <<= 1; 2044b88c807SRodney W. Grimes dest->buf = ckrealloc(dest->buf, dest->bufsize); 2054b88c807SRodney W. Grimes dest->nleft = dest->bufsize - offset; 2064b88c807SRodney W. Grimes dest->nextc = dest->buf + offset; 2074b88c807SRodney W. Grimes INTON; 2084b88c807SRodney W. Grimes } else { 2094b88c807SRodney W. Grimes flushout(dest); 2104b88c807SRodney W. Grimes } 2114b88c807SRodney W. Grimes dest->nleft--; 2124b88c807SRodney W. Grimes } 2134b88c807SRodney W. Grimes 2144b88c807SRodney W. Grimes 2154b88c807SRodney W. Grimes void 2165134c3f7SWarner Losh flushall(void) 2175134c3f7SWarner Losh { 2184b88c807SRodney W. Grimes flushout(&output); 2194b88c807SRodney W. Grimes flushout(&errout); 2204b88c807SRodney W. Grimes } 2214b88c807SRodney W. Grimes 2224b88c807SRodney W. Grimes 2234b88c807SRodney W. Grimes void 2245134c3f7SWarner Losh flushout(struct output *dest) 2254b88c807SRodney W. Grimes { 2264b88c807SRodney W. Grimes 2274b88c807SRodney W. Grimes if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0) 2284b88c807SRodney W. Grimes return; 2294b88c807SRodney W. Grimes if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0) 2304b88c807SRodney W. Grimes dest->flags |= OUTPUT_ERR; 2314b88c807SRodney W. Grimes dest->nextc = dest->buf; 2324b88c807SRodney W. Grimes dest->nleft = dest->bufsize; 2334b88c807SRodney W. Grimes } 2344b88c807SRodney W. Grimes 2354b88c807SRodney W. Grimes 2364b88c807SRodney W. Grimes void 2375134c3f7SWarner Losh freestdout(void) 2385134c3f7SWarner Losh { 2394b88c807SRodney W. Grimes INTOFF; 2404b88c807SRodney W. Grimes if (output.buf) { 2414b88c807SRodney W. Grimes ckfree(output.buf); 2424b88c807SRodney W. Grimes output.buf = NULL; 2434b88c807SRodney W. Grimes output.nleft = 0; 2444b88c807SRodney W. Grimes } 2454b88c807SRodney W. Grimes INTON; 2464b88c807SRodney W. Grimes } 2474b88c807SRodney W. Grimes 2484b88c807SRodney W. Grimes 2494b88c807SRodney W. Grimes void 2505134c3f7SWarner Losh outfmt(struct output *file, const char *fmt, ...) 2515134c3f7SWarner Losh { 2524b88c807SRodney W. Grimes va_list ap; 2534b88c807SRodney W. Grimes 2544b88c807SRodney W. Grimes va_start(ap, fmt); 2554b88c807SRodney W. Grimes doformat(file, fmt, ap); 2564b88c807SRodney W. Grimes va_end(ap); 2574b88c807SRodney W. Grimes } 2584b88c807SRodney W. Grimes 2594b88c807SRodney W. Grimes 2604b88c807SRodney W. Grimes void 2615134c3f7SWarner Losh out1fmt(const char *fmt, ...) 2625134c3f7SWarner Losh { 2634b88c807SRodney W. Grimes va_list ap; 2644b88c807SRodney W. Grimes 2654b88c807SRodney W. Grimes va_start(ap, fmt); 2664b88c807SRodney W. Grimes doformat(out1, fmt, ap); 2674b88c807SRodney W. Grimes va_end(ap); 2684b88c807SRodney W. Grimes } 2694b88c807SRodney W. Grimes 2704b88c807SRodney W. Grimes void 271c6204d4aSJilles Tjoelker out2fmt_flush(const char *fmt, ...) 2725134c3f7SWarner Losh { 2734b88c807SRodney W. Grimes va_list ap; 2744b88c807SRodney W. Grimes 2754b88c807SRodney W. Grimes va_start(ap, fmt); 2764b88c807SRodney W. Grimes doformat(out2, fmt, ap); 2774b88c807SRodney W. Grimes va_end(ap); 2784b88c807SRodney W. Grimes flushout(out2); 2794b88c807SRodney W. Grimes } 2804b88c807SRodney W. Grimes 2814b88c807SRodney W. Grimes void 2825134c3f7SWarner Losh fmtstr(char *outbuf, int length, const char *fmt, ...) 2835134c3f7SWarner Losh { 2844b88c807SRodney W. Grimes va_list ap; 285658a755bSTim J. Robbins struct output strout; 2864b88c807SRodney W. Grimes 287658a755bSTim J. Robbins strout.nextc = outbuf; 288658a755bSTim J. Robbins strout.nleft = length; 289658a755bSTim J. Robbins strout.fd = BLOCK_OUT; 290658a755bSTim J. Robbins strout.flags = 0; 2914b88c807SRodney W. Grimes va_start(ap, fmt); 292658a755bSTim J. Robbins doformat(&strout, fmt, ap); 2937e73d40eSTim J. Robbins va_end(ap); 294658a755bSTim J. Robbins outc('\0', &strout); 295658a755bSTim J. Robbins if (strout.flags & OUTPUT_ERR) 296658a755bSTim J. Robbins outbuf[length - 1] = '\0'; 2974b88c807SRodney W. Grimes } 2984b88c807SRodney W. Grimes 29988328642SDavid E. O'Brien static int 3007e73d40eSTim J. Robbins doformat_wr(void *cookie, const char *buf, int len) 3017e73d40eSTim J. Robbins { 3027e73d40eSTim J. Robbins struct output *o; 3034b88c807SRodney W. Grimes 3047e73d40eSTim J. Robbins o = (struct output *)cookie; 305c3f57269SJilles Tjoelker outbin(buf, len, o); 3064b88c807SRodney W. Grimes 307c3f57269SJilles Tjoelker return (len); 3087e73d40eSTim J. Robbins } 3094b88c807SRodney W. Grimes 3104b88c807SRodney W. Grimes void 3115134c3f7SWarner Losh doformat(struct output *dest, const char *f, va_list ap) 3124b88c807SRodney W. Grimes { 3137e73d40eSTim J. Robbins FILE *fp; 3144b88c807SRodney W. Grimes 3157e73d40eSTim J. Robbins if ((fp = fwopen(dest, doformat_wr)) != NULL) { 3167e73d40eSTim J. Robbins vfprintf(fp, f, ap); 3177e73d40eSTim J. Robbins fclose(fp); 3184b88c807SRodney W. Grimes } 3194b88c807SRodney W. Grimes } 3204b88c807SRodney W. Grimes 3214b88c807SRodney W. Grimes /* 3224b88c807SRodney W. Grimes * Version of write which resumes after a signal is caught. 3234b88c807SRodney W. Grimes */ 3244b88c807SRodney W. Grimes 3254b88c807SRodney W. Grimes int 3262cac6e36SJilles Tjoelker xwrite(int fd, const char *buf, int nbytes) 3274b88c807SRodney W. Grimes { 3284b88c807SRodney W. Grimes int ntry; 3294b88c807SRodney W. Grimes int i; 3304b88c807SRodney W. Grimes int n; 3314b88c807SRodney W. Grimes 3324b88c807SRodney W. Grimes n = nbytes; 3334b88c807SRodney W. Grimes ntry = 0; 3344b88c807SRodney W. Grimes for (;;) { 3354b88c807SRodney W. Grimes i = write(fd, buf, n); 3364b88c807SRodney W. Grimes if (i > 0) { 3374b88c807SRodney W. Grimes if ((n -= i) <= 0) 3384b88c807SRodney W. Grimes return nbytes; 3394b88c807SRodney W. Grimes buf += i; 3404b88c807SRodney W. Grimes ntry = 0; 3414b88c807SRodney W. Grimes } else if (i == 0) { 3424b88c807SRodney W. Grimes if (++ntry > 10) 3434b88c807SRodney W. Grimes return nbytes - n; 3444b88c807SRodney W. Grimes } else if (errno != EINTR) { 3454b88c807SRodney W. Grimes return -1; 3464b88c807SRodney W. Grimes } 3474b88c807SRodney W. Grimes } 3484b88c807SRodney W. Grimes } 349