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