1/*- 2 * Copyright (c) 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * Copyright (c) 1997-2005 5 * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Kenneth Almquist. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35/* 36 * Shell output routines. We use our own output routines because: 37 * When a builtin command is interrupted we have to discard 38 * any pending output. 39 * When a builtin command appears in back quotes, we want to 40 * save the output of the command in a region obtained 41 * via malloc, rather than doing a fork and reading the 42 * output of the command via a pipe. 43 * Our output routines may be smaller than the stdio routines. 44 */ 45 46#include <sys/types.h> /* quad_t */ 47#include <sys/param.h> /* BSD4_4 */ 48#include <sys/ioctl.h> 49 50#include <stdio.h> /* defines BUFSIZ */ 51#include <string.h> 52#include <unistd.h> 53#include <stdlib.h> 54#ifdef USE_GLIBC_STDIO 55#include <fcntl.h> 56#endif 57#include <limits.h> 58 59#include "shell.h" 60#include "syntax.h" 61#include "options.h" 62#include "output.h" 63#include "memalloc.h" 64#include "error.h" 65#include "main.h" 66#include "system.h" 67 68 69#define OUTBUFSIZ BUFSIZ 70#define MEM_OUT -3 /* output to dynamically allocated memory */ 71 72 73#ifdef USE_GLIBC_STDIO 74struct output output = { 75 stream: 0, nextc: 0, end: 0, buf: 0, bufsize: 0, fd: 1, flags: 0 76}; 77struct output errout = { 78 stream: 0, nextc: 0, end: 0, buf: 0, bufsize: 0, fd: 2, flags: 0 79} 80#ifdef notyet 81struct output memout = { 82 stream: 0, nextc: 0, end: 0, buf: 0, bufsize: 0, fd: MEM_OUT, flags: 0 83}; 84#endif 85#else 86struct output output = { 87 nextc: 0, end: 0, buf: 0, bufsize: OUTBUFSIZ, fd: 1, flags: 0 88}; 89struct output errout = { 90 nextc: 0, end: 0, buf: 0, bufsize: 0, fd: 2, flags: 0 91}; 92struct output preverrout; 93#ifdef notyet 94struct output memout = { 95 nextc: 0, end: 0, buf: 0, bufsize: 0, fd: MEM_OUT, flags: 0 96}; 97#endif 98#endif 99struct output *out1 = &output; 100struct output *out2 = &errout; 101 102 103static int xvsnprintf(char *, size_t, const char *, va_list); 104 105 106#ifdef mkinit 107 108INCLUDE "output.h" 109INCLUDE "memalloc.h" 110 111INIT { 112#ifdef USE_GLIBC_STDIO 113 initstreams(); 114#endif 115} 116 117RESET { 118#ifdef notyet 119 out1 = &output; 120 out2 = &errout; 121#ifdef USE_GLIBC_STDIO 122 if (memout.stream != NULL) 123 __closememout(); 124#endif 125 if (memout.buf != NULL) { 126 ckfree(memout.buf); 127 memout.buf = NULL; 128 } 129#endif 130} 131 132#endif 133 134 135void 136outmem(const char *p, size_t len, struct output *dest) 137{ 138#ifdef USE_GLIBC_STDIO 139 INTOFF; 140 fwrite(p, 1, len, dest->stream); 141 INTON; 142#else 143 size_t bufsize; 144 size_t offset; 145 size_t nleft; 146 147 nleft = dest->end - dest->nextc; 148 if (likely(nleft >= len)) { 149buffered: 150 dest->nextc = mempcpy(dest->nextc, p, len); 151 return; 152 } 153 154 bufsize = dest->bufsize; 155 if (!bufsize) { 156 ; 157 } else if (dest->buf == NULL) { 158#ifdef notyet 159 if (dest->fd == MEM_OUT && len > bufsize) { 160 bufsize = len; 161 } 162#endif 163 offset = 0; 164#ifdef notyet 165 goto alloc; 166 } else if (dest->fd == MEM_OUT) { 167 offset = bufsize; 168 if (bufsize >= len) { 169 bufsize <<= 1; 170 } else { 171 bufsize += len; 172 } 173 if (bufsize < offset) 174 goto err; 175alloc: 176#endif 177 INTOFF; 178 dest->buf = ckrealloc(dest->buf, bufsize); 179 dest->bufsize = bufsize; 180 dest->end = dest->buf + bufsize; 181 dest->nextc = dest->buf + offset; 182 INTON; 183 } else { 184 flushout(dest); 185 } 186 187 nleft = dest->end - dest->nextc; 188 if (nleft > len) 189 goto buffered; 190 191 if ((xwrite(dest->fd, p, len))) { 192#ifdef notyet 193err: 194#endif 195 dest->flags |= OUTPUT_ERR; 196 } 197#endif 198} 199 200 201void 202outstr(const char *p, struct output *file) 203{ 204#ifdef USE_GLIBC_STDIO 205 INTOFF; 206 fputs(p, file->stream); 207 INTON; 208#else 209 size_t len; 210 211 len = strlen(p); 212 outmem(p, len, file); 213#endif 214} 215 216 217#ifndef USE_GLIBC_STDIO 218 219 220void 221outcslow(int c, struct output *dest) 222{ 223 char buf = c; 224 outmem(&buf, 1, dest); 225} 226#endif 227 228 229void 230flushall(void) 231{ 232 flushout(&output); 233#ifdef FLUSHERR 234 flushout(&errout); 235#endif 236} 237 238 239void 240flushout(struct output *dest) 241{ 242#ifdef USE_GLIBC_STDIO 243 INTOFF; 244 fflush(dest->stream); 245 INTON; 246#else 247 size_t len; 248 249 len = dest->nextc - dest->buf; 250 if (!len || dest->fd < 0) 251 return; 252 dest->nextc = dest->buf; 253 if ((xwrite(dest->fd, dest->buf, len))) 254 dest->flags |= OUTPUT_ERR; 255#endif 256} 257 258 259void 260outfmt(struct output *file, const char *fmt, ...) 261{ 262 va_list ap; 263 264 va_start(ap, fmt); 265 doformat(file, fmt, ap); 266 va_end(ap); 267} 268 269 270void 271out1fmt(const char *fmt, ...) 272{ 273 va_list ap; 274 275 va_start(ap, fmt); 276 doformat(out1, fmt, ap); 277 va_end(ap); 278} 279 280 281int 282fmtstr(char *outbuf, size_t length, const char *fmt, ...) 283{ 284 va_list ap; 285 int ret; 286 287 va_start(ap, fmt); 288 ret = xvsnprintf(outbuf, length, fmt, ap); 289 va_end(ap); 290 return ret; 291} 292 293 294static int xvasprintf(char **sp, size_t size, const char *f, va_list ap) 295{ 296 char *s; 297 int len; 298 va_list ap2; 299 300 va_copy(ap2, ap); 301 len = xvsnprintf(*sp, size, f, ap2); 302 va_end(ap2); 303 if (len < 0) 304 sh_error("xvsnprintf failed"); 305 if (len < size) 306 return len; 307 308 s = stalloc((len >= stackblocksize() ? len : stackblocksize()) + 1); 309 *sp = s; 310 len = xvsnprintf(s, len + 1, f, ap); 311 return len; 312} 313 314 315int xasprintf(char **sp, const char *f, ...) 316{ 317 va_list ap; 318 int ret; 319 320 va_start(ap, f); 321 ret = xvasprintf(sp, 0, f, ap); 322 va_end(ap); 323 return ret; 324} 325 326 327#ifndef USE_GLIBC_STDIO 328void 329doformat(struct output *dest, const char *f, va_list ap) 330{ 331 struct stackmark smark; 332 char *s; 333 int len; 334 int olen; 335 336 setstackmark(&smark); 337 s = dest->nextc; 338 olen = dest->end - dest->nextc; 339 len = xvasprintf(&s, olen, f, ap); 340 if (likely(olen > len)) { 341 dest->nextc += len; 342 goto out; 343 } 344 outmem(s, len, dest); 345out: 346 popstackmark(&smark); 347} 348#endif 349 350 351void settitle(const char* title) { 352 if (!iflag || !isatty(0)) 353 return; 354 char str[16]; 355 int n = snprintf(str, sizeof(str) - 1, "\033]2;%s", title); 356 if (n < 0) { 357 return; // error 358 } else if ((size_t)n >= sizeof(str) - 1) { 359 n = sizeof(str) - 2; // truncated 360 } 361 str[n] = '\007'; 362 str[n+1] = '\0'; 363 out2str(str); 364} 365 366 367/* 368 * Version of write which resumes after a signal is caught. 369 */ 370 371int 372xwrite(int fd, const void *p, size_t n) 373{ 374 const char *buf = p; 375 376 while (n) { 377 ssize_t i; 378 size_t m; 379 380 m = n; 381 if (m > SSIZE_MAX) 382 m = SSIZE_MAX; 383 do { 384 i = write(fd, buf, m); 385 } while (i < 0 && errno == EINTR); 386 if (i < 0) 387 return -1; 388 buf += i; 389 n -= i; 390 } 391 return 0; 392} 393 394 395#ifdef notyet 396#ifdef USE_GLIBC_STDIO 397void initstreams() { 398 output.stream = stdout; 399 errout.stream = stderr; 400} 401 402 403void 404openmemout(void) { 405 INTOFF; 406 memout.stream = open_memstream(&memout.buf, &memout.bufsize); 407 INTON; 408} 409 410 411int 412__closememout(void) { 413 int error; 414 error = fclose(memout.stream); 415 memout.stream = NULL; 416 return error; 417} 418#endif 419#endif 420 421 422static int 423xvsnprintf(char *outbuf, size_t length, const char *fmt, va_list ap) 424{ 425 int ret; 426 427#ifdef __sun 428 /* 429 * vsnprintf() on older versions of Solaris returns -1 when 430 * passed a length of 0. To avoid this, use a dummy 431 * 1-character buffer instead. 432 */ 433 char dummy[1]; 434 435 if (length == 0) { 436 outbuf = dummy; 437 length = sizeof(dummy); 438 } 439#endif 440 441 INTOFF; 442 ret = vsnprintf(outbuf, length, fmt, ap); 443 INTON; 444 return ret; 445} 446