1 /*- 2 * Copyright (c) 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Kenneth Almquist. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * @(#)output.c 8.2 (Berkeley) 5/4/95 37 * $FreeBSD: src/bin/sh/output.c,v 1.28 2010/12/11 17:47:27 jilles Exp $ 38 */ 39 40 /* 41 * Shell output routines. We use our own output routines because: 42 * When a builtin command is interrupted we have to discard 43 * any pending output. 44 * When a builtin command appears in back quotes, we want to 45 * save the output of the command in a region obtained 46 * via malloc, rather than doing a fork and reading the 47 * output of the command via a pipe. 48 */ 49 50 #include <stdio.h> /* defines BUFSIZ */ 51 #include <string.h> 52 #include <stdarg.h> 53 #include <errno.h> 54 #include <unistd.h> 55 #include <stdlib.h> 56 57 #include "shell.h" 58 #include "syntax.h" 59 #include "output.h" 60 #include "memalloc.h" 61 #include "error.h" 62 #include "var.h" 63 64 65 #define OUTBUFSIZ BUFSIZ 66 #define MEM_OUT -2 /* output to dynamically allocated memory */ 67 #define OUTPUT_ERR 01 /* error occurred on output */ 68 69 static int doformat_wr(void *, const char *, int); 70 71 struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0}; 72 struct output errout = {NULL, 0, NULL, 256, 2, 0}; 73 struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0}; 74 struct output *out1 = &output; 75 struct output *out2 = &errout; 76 77 78 79 #ifdef mkinit 80 81 INCLUDE "output.h" 82 INCLUDE "memalloc.h" 83 84 RESET { 85 out1 = &output; 86 out2 = &errout; 87 if (memout.buf != NULL) { 88 ckfree(memout.buf); 89 memout.buf = NULL; 90 } 91 } 92 93 #endif 94 95 96 void 97 outcslow(int c, struct output *file) 98 { 99 outc(c, file); 100 } 101 102 void 103 out1str(const char *p) 104 { 105 outstr(p, out1); 106 } 107 108 void 109 out1qstr(const char *p) 110 { 111 outqstr(p, out1); 112 } 113 114 void 115 out2str(const char *p) 116 { 117 outstr(p, out2); 118 } 119 120 void 121 out2qstr(const char *p) 122 { 123 outqstr(p, out2); 124 } 125 126 void 127 outstr(const char *p, struct output *file) 128 { 129 outbin(p, strlen(p), file); 130 } 131 132 /* Like outstr(), but quote for re-input into the shell. */ 133 void 134 outqstr(const char *p, struct output *file) 135 { 136 char ch; 137 int inquotes; 138 139 if (p[0] == '\0') { 140 outstr("''", file); 141 return; 142 } 143 /* Caller will handle '=' if necessary */ 144 if (p[strcspn(p, "|&;<>()$`\\\"' \t\n*?[~#")] == '\0' || 145 strcmp(p, "[") == 0) { 146 outstr(p, file); 147 return; 148 } 149 150 inquotes = 0; 151 while ((ch = *p++) != '\0') { 152 switch (ch) { 153 case '\'': 154 /* Can't quote single quotes inside single quotes. */ 155 if (inquotes) 156 outcslow('\'', file); 157 inquotes = 0; 158 outstr("\\'", file); 159 break; 160 default: 161 if (!inquotes) 162 outcslow('\'', file); 163 inquotes = 1; 164 outc(ch, file); 165 } 166 } 167 if (inquotes) 168 outcslow('\'', file); 169 } 170 171 void 172 outbin(const void *data, size_t len, struct output *file) 173 { 174 const char *p; 175 176 p = data; 177 while (len-- > 0) 178 outc(*p++, file); 179 } 180 181 void 182 emptyoutbuf(struct output *dest) 183 { 184 int offset; 185 186 if (dest->buf == NULL) { 187 INTOFF; 188 dest->buf = ckmalloc(dest->bufsize); 189 dest->nextc = dest->buf; 190 dest->nleft = dest->bufsize; 191 INTON; 192 } else if (dest->fd == MEM_OUT) { 193 offset = dest->bufsize; 194 INTOFF; 195 dest->bufsize <<= 1; 196 dest->buf = ckrealloc(dest->buf, dest->bufsize); 197 dest->nleft = dest->bufsize - offset; 198 dest->nextc = dest->buf + offset; 199 INTON; 200 } else { 201 flushout(dest); 202 } 203 dest->nleft--; 204 } 205 206 207 void 208 flushall(void) 209 { 210 flushout(&output); 211 flushout(&errout); 212 } 213 214 215 void 216 flushout(struct output *dest) 217 { 218 219 if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0) 220 return; 221 if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0) 222 dest->flags |= OUTPUT_ERR; 223 dest->nextc = dest->buf; 224 dest->nleft = dest->bufsize; 225 } 226 227 228 void 229 freestdout(void) 230 { 231 INTOFF; 232 if (output.buf) { 233 ckfree(output.buf); 234 output.buf = NULL; 235 output.nleft = 0; 236 } 237 INTON; 238 } 239 240 241 void 242 outfmt(struct output *file, const char *fmt, ...) 243 { 244 va_list ap; 245 246 va_start(ap, fmt); 247 doformat(file, fmt, ap); 248 va_end(ap); 249 } 250 251 252 void 253 out1fmt(const char *fmt, ...) 254 { 255 va_list ap; 256 257 va_start(ap, fmt); 258 doformat(out1, fmt, ap); 259 va_end(ap); 260 } 261 262 void 263 out2fmt_flush(const char *fmt, ...) 264 { 265 va_list ap; 266 267 va_start(ap, fmt); 268 doformat(out2, fmt, ap); 269 va_end(ap); 270 flushout(out2); 271 } 272 273 void 274 fmtstr(char *outbuf, int length, const char *fmt, ...) 275 { 276 va_list ap; 277 278 INTOFF; 279 va_start(ap, fmt); 280 vsnprintf(outbuf, length, fmt, ap); 281 va_end(ap); 282 INTON; 283 } 284 285 static int 286 doformat_wr(void *cookie, const char *buf, int len) 287 { 288 struct output *o; 289 290 o = (struct output *)cookie; 291 outbin(buf, len, o); 292 293 return (len); 294 } 295 296 void 297 doformat(struct output *dest, const char *f, va_list ap) 298 { 299 FILE *fp; 300 301 if ((fp = fwopen(dest, doformat_wr)) != NULL) { 302 vfprintf(fp, f, ap); 303 fclose(fp); 304 } 305 } 306 307 /* 308 * Version of write which resumes after a signal is caught. 309 */ 310 311 int 312 xwrite(int fd, const char *buf, int nbytes) 313 { 314 int ntry; 315 int i; 316 int n; 317 318 n = nbytes; 319 ntry = 0; 320 for (;;) { 321 i = write(fd, buf, n); 322 if (i > 0) { 323 if ((n -= i) <= 0) 324 return nbytes; 325 buf += i; 326 ntry = 0; 327 } else if (i == 0) { 328 if (++ntry > 10) 329 return nbytes - n; 330 } else if (errno != EINTR) { 331 return -1; 332 } 333 } 334 } 335