output.c revision 215303
11556Srgrimes/*-
21556Srgrimes * Copyright (c) 1991, 1993
31556Srgrimes *	The Regents of the University of California.  All rights reserved.
41556Srgrimes *
51556Srgrimes * This code is derived from software contributed to Berkeley by
61556Srgrimes * Kenneth Almquist.
71556Srgrimes *
81556Srgrimes * Redistribution and use in source and binary forms, with or without
91556Srgrimes * modification, are permitted provided that the following conditions
101556Srgrimes * are met:
111556Srgrimes * 1. Redistributions of source code must retain the above copyright
121556Srgrimes *    notice, this list of conditions and the following disclaimer.
131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141556Srgrimes *    notice, this list of conditions and the following disclaimer in the
151556Srgrimes *    documentation and/or other materials provided with the distribution.
161556Srgrimes * 4. Neither the name of the University nor the names of its contributors
171556Srgrimes *    may be used to endorse or promote products derived from this software
181556Srgrimes *    without specific prior written permission.
191556Srgrimes *
201556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
211556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
241556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301556Srgrimes * SUCH DAMAGE.
311556Srgrimes */
321556Srgrimes
331556Srgrimes#ifndef lint
3436150Scharnier#if 0
3536150Scharnierstatic char sccsid[] = "@(#)output.c	8.2 (Berkeley) 5/4/95";
3636150Scharnier#endif
371556Srgrimes#endif /* not lint */
3899110Sobrien#include <sys/cdefs.h>
3999110Sobrien__FBSDID("$FreeBSD: head/bin/sh/output.c 215303 2010-11-14 15:31:59Z jilles $");
401556Srgrimes
411556Srgrimes/*
421556Srgrimes * Shell output routines.  We use our own output routines because:
431556Srgrimes *	When a builtin command is interrupted we have to discard
441556Srgrimes *		any pending output.
451556Srgrimes *	When a builtin command appears in back quotes, we want to
461556Srgrimes *		save the output of the command in a region obtained
471556Srgrimes *		via malloc, rather than doing a fork and reading the
481556Srgrimes *		output of the command via a pipe.
491556Srgrimes */
501556Srgrimes
511556Srgrimes#include <stdio.h>	/* defines BUFSIZ */
5217987Speter#include <string.h>
5317987Speter#include <stdarg.h>
541556Srgrimes#include <errno.h>
5517987Speter#include <unistd.h>
5617987Speter#include <stdlib.h>
571556Srgrimes
5817987Speter#include "shell.h"
5917987Speter#include "syntax.h"
6017987Speter#include "output.h"
6117987Speter#include "memalloc.h"
6217987Speter#include "error.h"
6397909Stjr#include "var.h"
641556Srgrimes
6517987Speter
661556Srgrimes#define OUTBUFSIZ BUFSIZ
671556Srgrimes#define BLOCK_OUT -2		/* output to a fixed block of memory */
681556Srgrimes#define MEM_OUT -3		/* output to dynamically allocated memory */
691556Srgrimes#define OUTPUT_ERR 01		/* error occurred on output */
701556Srgrimes
71213811Sobrienstatic int doformat_wr(void *, const char *, int);
721556Srgrimes
731556Srgrimesstruct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
74199629Sjillesstruct output errout = {NULL, 0, NULL, 256, 2, 0};
751556Srgrimesstruct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0};
761556Srgrimesstruct output *out1 = &output;
771556Srgrimesstruct output *out2 = &errout;
781556Srgrimes
791556Srgrimes
801556Srgrimes
811556Srgrimes#ifdef mkinit
821556Srgrimes
831556SrgrimesINCLUDE "output.h"
841556SrgrimesINCLUDE "memalloc.h"
851556Srgrimes
861556SrgrimesRESET {
871556Srgrimes	out1 = &output;
881556Srgrimes	out2 = &errout;
891556Srgrimes	if (memout.buf != NULL) {
901556Srgrimes		ckfree(memout.buf);
911556Srgrimes		memout.buf = NULL;
921556Srgrimes	}
931556Srgrimes}
941556Srgrimes
951556Srgrimes#endif
961556Srgrimes
971556Srgrimes
981556Srgrimesvoid
9990111Simpout1str(const char *p)
10090111Simp{
1011556Srgrimes	outstr(p, out1);
1021556Srgrimes}
1031556Srgrimes
10497815Stjrvoid
10597815Stjrout1qstr(const char *p)
10697815Stjr{
10797815Stjr	outqstr(p, out1);
10897815Stjr}
1091556Srgrimes
1101556Srgrimesvoid
11190111Simpout2str(const char *p)
11290111Simp{
1131556Srgrimes	outstr(p, out2);
1141556Srgrimes}
1151556Srgrimes
11697815Stjrvoid
11797815Stjrout2qstr(const char *p)
11897815Stjr{
11997815Stjr	outqstr(p, out2);
12097815Stjr}
1211556Srgrimes
1221556Srgrimesvoid
12390111Simpoutstr(const char *p, struct output *file)
12490111Simp{
125215303Sjilles	outbin(p, strlen(p), file);
1261556Srgrimes}
1271556Srgrimes
12897815Stjr/* Like outstr(), but quote for re-input into the shell. */
12997815Stjrvoid
13097815Stjroutqstr(const char *p, struct output *file)
13197815Stjr{
13297815Stjr	char ch;
133194516Sjilles	int inquotes;
1341556Srgrimes
135153245Sstefanf	if (p[0] == '\0') {
136153245Sstefanf		outstr("''", file);
137153245Sstefanf		return;
138153245Sstefanf	}
139194516Sjilles	/* Caller will handle '=' if necessary */
140194516Sjilles	if (p[strcspn(p, "|&;<>()$`\\\"' \t\n*?[~#")] == '\0' ||
141194516Sjilles			strcmp(p, "[") == 0) {
14297909Stjr		outstr(p, file);
14397909Stjr		return;
14497909Stjr	}
14597909Stjr
146194516Sjilles	inquotes = 0;
14797815Stjr	while ((ch = *p++) != '\0') {
14897815Stjr		switch (ch) {
14997815Stjr		case '\'':
150194516Sjilles			/* Can't quote single quotes inside single quotes. */
151194516Sjilles			if (inquotes)
152194516Sjilles				outc('\'', file);
153194516Sjilles			inquotes = 0;
154194516Sjilles			outstr("\\'", file);
15597815Stjr			break;
15697815Stjr		default:
157194516Sjilles			if (!inquotes)
158194516Sjilles				outc('\'', file);
159194516Sjilles			inquotes = 1;
16097815Stjr			outc(ch, file);
16197815Stjr		}
16297815Stjr	}
163194516Sjilles	if (inquotes)
164194516Sjilles		outc('\'', file);
16597815Stjr}
16697815Stjr
167215303Sjillesvoid
168215303Sjillesoutbin(const void *data, size_t len, struct output *file)
169215303Sjilles{
170215303Sjilles	const char *p;
171215303Sjilles
172215303Sjilles	p = data;
173215303Sjilles	while (len-- > 0)
174215303Sjilles		outc(*p++, file);
175215303Sjilles}
176215303Sjilles
177213760Sobrienstatic char out_junk[16];
1781556Srgrimes
1791556Srgrimesvoid
18090111Simpemptyoutbuf(struct output *dest)
18190111Simp{
1821556Srgrimes	int offset;
1831556Srgrimes
1841556Srgrimes	if (dest->fd == BLOCK_OUT) {
1851556Srgrimes		dest->nextc = out_junk;
1861556Srgrimes		dest->nleft = sizeof out_junk;
1871556Srgrimes		dest->flags |= OUTPUT_ERR;
1881556Srgrimes	} else if (dest->buf == NULL) {
1891556Srgrimes		INTOFF;
1901556Srgrimes		dest->buf = ckmalloc(dest->bufsize);
1911556Srgrimes		dest->nextc = dest->buf;
1921556Srgrimes		dest->nleft = dest->bufsize;
1931556Srgrimes		INTON;
1941556Srgrimes	} else if (dest->fd == MEM_OUT) {
1951556Srgrimes		offset = dest->bufsize;
1961556Srgrimes		INTOFF;
1971556Srgrimes		dest->bufsize <<= 1;
1981556Srgrimes		dest->buf = ckrealloc(dest->buf, dest->bufsize);
1991556Srgrimes		dest->nleft = dest->bufsize - offset;
2001556Srgrimes		dest->nextc = dest->buf + offset;
2011556Srgrimes		INTON;
2021556Srgrimes	} else {
2031556Srgrimes		flushout(dest);
2041556Srgrimes	}
2051556Srgrimes	dest->nleft--;
2061556Srgrimes}
2071556Srgrimes
2081556Srgrimes
2091556Srgrimesvoid
21090111Simpflushall(void)
21190111Simp{
2121556Srgrimes	flushout(&output);
2131556Srgrimes	flushout(&errout);
2141556Srgrimes}
2151556Srgrimes
2161556Srgrimes
2171556Srgrimesvoid
21890111Simpflushout(struct output *dest)
21990111Simp{
2201556Srgrimes
2211556Srgrimes	if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0)
2221556Srgrimes		return;
2231556Srgrimes	if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0)
2241556Srgrimes		dest->flags |= OUTPUT_ERR;
2251556Srgrimes	dest->nextc = dest->buf;
2261556Srgrimes	dest->nleft = dest->bufsize;
2271556Srgrimes}
2281556Srgrimes
2291556Srgrimes
2301556Srgrimesvoid
23190111Simpfreestdout(void)
23290111Simp{
2331556Srgrimes	INTOFF;
2341556Srgrimes	if (output.buf) {
2351556Srgrimes		ckfree(output.buf);
2361556Srgrimes		output.buf = NULL;
2371556Srgrimes		output.nleft = 0;
2381556Srgrimes	}
2391556Srgrimes	INTON;
2401556Srgrimes}
2411556Srgrimes
2421556Srgrimes
2431556Srgrimesvoid
24490111Simpoutfmt(struct output *file, const char *fmt, ...)
24590111Simp{
2461556Srgrimes	va_list ap;
2471556Srgrimes
2481556Srgrimes	va_start(ap, fmt);
2491556Srgrimes	doformat(file, fmt, ap);
2501556Srgrimes	va_end(ap);
2511556Srgrimes}
2521556Srgrimes
2531556Srgrimes
2541556Srgrimesvoid
25590111Simpout1fmt(const char *fmt, ...)
25690111Simp{
2571556Srgrimes	va_list ap;
2581556Srgrimes
2591556Srgrimes	va_start(ap, fmt);
2601556Srgrimes	doformat(out1, fmt, ap);
2611556Srgrimes	va_end(ap);
2621556Srgrimes}
2631556Srgrimes
2641556Srgrimesvoid
265199629Sjillesout2fmt_flush(const char *fmt, ...)
26690111Simp{
2671556Srgrimes	va_list ap;
2681556Srgrimes
2691556Srgrimes	va_start(ap, fmt);
2701556Srgrimes	doformat(out2, fmt, ap);
2711556Srgrimes	va_end(ap);
2721556Srgrimes	flushout(out2);
2731556Srgrimes}
2741556Srgrimes
2751556Srgrimesvoid
27690111Simpfmtstr(char *outbuf, int length, const char *fmt, ...)
27790111Simp{
2781556Srgrimes	va_list ap;
279104289Stjr	struct output strout;
2801556Srgrimes
281104289Stjr	strout.nextc = outbuf;
282104289Stjr	strout.nleft = length;
283104289Stjr	strout.fd = BLOCK_OUT;
284104289Stjr	strout.flags = 0;
2851556Srgrimes	va_start(ap, fmt);
286104289Stjr	doformat(&strout, fmt, ap);
287104286Stjr	va_end(ap);
288104289Stjr	outc('\0', &strout);
289104289Stjr	if (strout.flags & OUTPUT_ERR)
290104289Stjr		outbuf[length - 1] = '\0';
2911556Srgrimes}
2921556Srgrimes
293213811Sobrienstatic int
294104286Stjrdoformat_wr(void *cookie, const char *buf, int len)
295104286Stjr{
296104286Stjr	struct output *o;
2971556Srgrimes
298104286Stjr	o = (struct output *)cookie;
299215303Sjilles	outbin(buf, len, o);
3001556Srgrimes
301215303Sjilles	return (len);
302104286Stjr}
3031556Srgrimes
3041556Srgrimesvoid
30590111Simpdoformat(struct output *dest, const char *f, va_list ap)
30690111Simp{
307104286Stjr	FILE *fp;
3081556Srgrimes
309104286Stjr	if ((fp = fwopen(dest, doformat_wr)) != NULL) {
310104286Stjr		vfprintf(fp, f, ap);
311104286Stjr		fclose(fp);
3121556Srgrimes	}
3131556Srgrimes}
3141556Srgrimes
3151556Srgrimes/*
3161556Srgrimes * Version of write which resumes after a signal is caught.
3171556Srgrimes */
3181556Srgrimes
3191556Srgrimesint
320200956Sjillesxwrite(int fd, const char *buf, int nbytes)
32190111Simp{
3221556Srgrimes	int ntry;
3231556Srgrimes	int i;
3241556Srgrimes	int n;
3251556Srgrimes
3261556Srgrimes	n = nbytes;
3271556Srgrimes	ntry = 0;
3281556Srgrimes	for (;;) {
3291556Srgrimes		i = write(fd, buf, n);
3301556Srgrimes		if (i > 0) {
3311556Srgrimes			if ((n -= i) <= 0)
3321556Srgrimes				return nbytes;
3331556Srgrimes			buf += i;
3341556Srgrimes			ntry = 0;
3351556Srgrimes		} else if (i == 0) {
3361556Srgrimes			if (++ntry > 10)
3371556Srgrimes				return nbytes - n;
3381556Srgrimes		} else if (errno != EINTR) {
3391556Srgrimes			return -1;
3401556Srgrimes		}
3411556Srgrimes	}
3421556Srgrimes}
343