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