xref: /freebsd/bin/sh/output.c (revision aeb5d065044ee6733a7fee14edb52959a28c1ab4)
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