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 253649 2013-07-25 13:09:17Z 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 void 74 outcslow(int c, struct output *file) 75 { 76 outc(c, file); 77 } 78 79 void 80 out1str(const char *p) 81 { 82 outstr(p, out1); 83 } 84 85 void 86 out1qstr(const char *p) 87 { 88 outqstr(p, out1); 89 } 90 91 void 92 out2str(const char *p) 93 { 94 outstr(p, out2); 95 } 96 97 void 98 out2qstr(const char *p) 99 { 100 outqstr(p, out2); 101 } 102 103 void 104 outstr(const char *p, struct output *file) 105 { 106 outbin(p, strlen(p), file); 107 } 108 109 /* Like outstr(), but quote for re-input into the shell. */ 110 void 111 outqstr(const char *p, struct output *file) 112 { 113 char ch; 114 int inquotes; 115 116 if (p[0] == '\0') { 117 outstr("''", file); 118 return; 119 } 120 /* Caller will handle '=' if necessary */ 121 if (p[strcspn(p, "|&;<>()$`\\\"' \t\n*?[~#")] == '\0' || 122 strcmp(p, "[") == 0) { 123 outstr(p, file); 124 return; 125 } 126 127 inquotes = 0; 128 while ((ch = *p++) != '\0') { 129 switch (ch) { 130 case '\'': 131 /* Can't quote single quotes inside single quotes. */ 132 if (inquotes) 133 outcslow('\'', file); 134 inquotes = 0; 135 outstr("\\'", file); 136 break; 137 default: 138 if (!inquotes) 139 outcslow('\'', file); 140 inquotes = 1; 141 outc(ch, file); 142 } 143 } 144 if (inquotes) 145 outcslow('\'', file); 146 } 147 148 void 149 outbin(const void *data, size_t len, struct output *file) 150 { 151 const char *p; 152 153 p = data; 154 while (len-- > 0) 155 outc(*p++, file); 156 } 157 158 void 159 emptyoutbuf(struct output *dest) 160 { 161 int offset; 162 163 if (dest->buf == NULL) { 164 INTOFF; 165 dest->buf = ckmalloc(dest->bufsize); 166 dest->nextc = dest->buf; 167 dest->nleft = dest->bufsize; 168 INTON; 169 } else if (dest->fd == MEM_OUT) { 170 offset = dest->bufsize; 171 INTOFF; 172 dest->bufsize <<= 1; 173 dest->buf = ckrealloc(dest->buf, dest->bufsize); 174 dest->nleft = dest->bufsize - offset; 175 dest->nextc = dest->buf + offset; 176 INTON; 177 } else { 178 flushout(dest); 179 } 180 dest->nleft--; 181 } 182 183 184 void 185 flushall(void) 186 { 187 flushout(&output); 188 flushout(&errout); 189 } 190 191 192 void 193 flushout(struct output *dest) 194 { 195 196 if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0) 197 return; 198 if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0) 199 dest->flags |= OUTPUT_ERR; 200 dest->nextc = dest->buf; 201 dest->nleft = dest->bufsize; 202 } 203 204 205 void 206 freestdout(void) 207 { 208 INTOFF; 209 if (output.buf) { 210 ckfree(output.buf); 211 output.buf = NULL; 212 output.nleft = 0; 213 } 214 INTON; 215 } 216 217 218 int 219 outiserror(struct output *file) 220 { 221 return (file->flags & OUTPUT_ERR); 222 } 223 224 225 void 226 outclearerror(struct output *file) 227 { 228 file->flags &= ~OUTPUT_ERR; 229 } 230 231 232 void 233 outfmt(struct output *file, const char *fmt, ...) 234 { 235 va_list ap; 236 237 va_start(ap, fmt); 238 doformat(file, fmt, ap); 239 va_end(ap); 240 } 241 242 243 void 244 out1fmt(const char *fmt, ...) 245 { 246 va_list ap; 247 248 va_start(ap, fmt); 249 doformat(out1, fmt, ap); 250 va_end(ap); 251 } 252 253 void 254 out2fmt_flush(const char *fmt, ...) 255 { 256 va_list ap; 257 258 va_start(ap, fmt); 259 doformat(out2, fmt, ap); 260 va_end(ap); 261 flushout(out2); 262 } 263 264 void 265 fmtstr(char *outbuf, int length, const char *fmt, ...) 266 { 267 va_list ap; 268 269 INTOFF; 270 va_start(ap, fmt); 271 vsnprintf(outbuf, length, fmt, ap); 272 va_end(ap); 273 INTON; 274 } 275 276 static int 277 doformat_wr(void *cookie, const char *buf, int len) 278 { 279 struct output *o; 280 281 o = (struct output *)cookie; 282 outbin(buf, len, o); 283 284 return (len); 285 } 286 287 void 288 doformat(struct output *dest, const char *f, va_list ap) 289 { 290 FILE *fp; 291 292 if ((fp = fwopen(dest, doformat_wr)) != NULL) { 293 vfprintf(fp, f, ap); 294 fclose(fp); 295 } 296 } 297 298 /* 299 * Version of write which resumes after a signal is caught. 300 */ 301 302 int 303 xwrite(int fd, const char *buf, int nbytes) 304 { 305 int ntry; 306 int i; 307 int n; 308 309 n = nbytes; 310 ntry = 0; 311 for (;;) { 312 i = write(fd, buf, n); 313 if (i > 0) { 314 if ((n -= i) <= 0) 315 return nbytes; 316 buf += i; 317 ntry = 0; 318 } else if (i == 0) { 319 if (++ntry > 10) 320 return nbytes - n; 321 } else if (errno != EINTR) { 322 return -1; 323 } 324 } 325 } 326