1/* $NetBSD: io.c,v 1.18 2018/05/08 16:37:59 kamil Exp $ */ 2 3/* 4 * shell buffered IO and formatted output 5 */ 6#include <sys/cdefs.h> 7 8#ifndef lint 9__RCSID("$NetBSD: io.c,v 1.18 2018/05/08 16:37:59 kamil Exp $"); 10#endif 11 12#include <sys/stat.h> 13#include <ctype.h> 14#include "sh.h" 15 16static int initio_done; 17 18/* 19 * formatted output functions 20 */ 21 22 23/* A shell error occurred (eg, syntax error, etc.) */ 24void 25errorf(const char *fmt, ...) 26{ 27 va_list va; 28 29 shl_stdout_ok = 0; /* debugging: note that stdout not valid */ 30 exstat = 1; 31 if (*fmt) { 32 error_prefix(true); 33 va_start(va, fmt); 34 shf_vfprintf(shl_out, fmt, va); 35 va_end(va); 36 shf_putchar('\n', shl_out); 37 } 38 shf_flush(shl_out); 39 unwind(LERROR); 40} 41 42/* like errorf(), but no unwind is done */ 43void 44warningf(int fileline, const char *fmt, ...) 45{ 46 va_list va; 47 48 error_prefix(fileline); 49 va_start(va, fmt); 50 shf_vfprintf(shl_out, fmt, va); 51 va_end(va); 52 shf_putchar('\n', shl_out); 53 shf_flush(shl_out); 54} 55 56/* Used by built-in utilities to prefix shell and utility name to message 57 * (also unwinds environments for special builtins). 58 */ 59void 60bi_errorf(const char *fmt, ...) 61{ 62 va_list va; 63 64 shl_stdout_ok = 0; /* debugging: note that stdout not valid */ 65 exstat = 1; 66 if (*fmt) { 67 error_prefix(true); 68 /* not set when main() calls parse_args() */ 69 if (builtin_argv0) 70 shf_fprintf(shl_out, "%s: ", builtin_argv0); 71 va_start(va, fmt); 72 shf_vfprintf(shl_out, fmt, va); 73 va_end(va); 74 shf_putchar('\n', shl_out); 75 } 76 shf_flush(shl_out); 77 /* POSIX special builtins and ksh special builtins cause 78 * non-interactive shells to exit. 79 * XXX odd use of KEEPASN; also may not want LERROR here 80 */ 81 if ((builtin_flag & SPEC_BI) 82 || (Flag(FPOSIX) && (builtin_flag & KEEPASN))) 83 { 84 builtin_argv0 = (char *) 0; 85 unwind(LERROR); 86 } 87} 88 89/* Called when something that shouldn't happen does */ 90void 91internal_errorf(int jump, const char *fmt, ...) 92{ 93 va_list va; 94 95 error_prefix(true); 96 shf_fprintf(shl_out, "internal error: "); 97 va_start(va, fmt); 98 shf_vfprintf(shl_out, fmt, va); 99 va_end(va); 100 shf_putchar('\n', shl_out); 101 shf_flush(shl_out); 102 if (jump) 103 unwind(LERROR); 104} 105 106/* used by error reporting functions to print "ksh: .kshrc[25]: " */ 107void 108error_prefix(fileline) 109 int fileline; 110{ 111 /* Avoid foo: foo[2]: ... */ 112 if (!fileline || !source || !source->file 113 || strcmp(source->file, kshname) != 0) 114 shf_fprintf(shl_out, "%s: ", kshname + (*kshname == '-')); 115 if (fileline && source && source->file != NULL) { 116 shf_fprintf(shl_out, "%s[%d]: ", source->file, 117 source->errline > 0 ? source->errline : source->line); 118 source->errline = 0; 119 } 120} 121 122/* printf to shl_out (stderr) with flush */ 123void 124shellf(const char *fmt, ...) 125{ 126 va_list va; 127 128 if (!initio_done) /* shl_out may not be set up yet... */ 129 return; 130 va_start(va, fmt); 131 shf_vfprintf(shl_out, fmt, va); 132 va_end(va); 133 shf_flush(shl_out); 134} 135 136/* printf to shl_stdout (stdout) */ 137void 138shprintf(const char *fmt, ...) 139{ 140 va_list va; 141 142 if (!shl_stdout_ok) 143 internal_errorf(1, "shl_stdout not valid"); 144 va_start(va, fmt); 145 shf_vfprintf(shl_stdout, fmt, va); 146 va_end(va); 147} 148 149#ifdef KSH_DEBUG 150static struct shf *kshdebug_shf; 151 152void 153kshdebug_init_() 154{ 155 if (kshdebug_shf) 156 shf_close(kshdebug_shf); 157 kshdebug_shf = shf_open("/tmp/ksh-debug.log", 158 O_WRONLY|O_APPEND|O_CREAT, 0600, 159 SHF_WR|SHF_MAPHI); 160 if (kshdebug_shf) { 161 shf_fprintf(kshdebug_shf, "\nNew shell[pid %d]\n", getpid()); 162 shf_flush(kshdebug_shf); 163 } 164} 165 166/* print to debugging log */ 167void 168kshdebug_printf_(const char *fmt, ...) 169{ 170 va_list va; 171 172 if (!kshdebug_shf) 173 return; 174 va_start(va, fmt); 175 shf_fprintf(kshdebug_shf, "[%d] ", getpid()); 176 shf_vfprintf(kshdebug_shf, fmt, va); 177 va_end(va); 178 shf_flush(kshdebug_shf); 179} 180 181void 182kshdebug_dump_(str, mem, nbytes) 183 const char *str; 184 const void *mem; 185 int nbytes; 186{ 187 int i, j; 188 int nprow = 16; 189 190 if (!kshdebug_shf) 191 return; 192 shf_fprintf(kshdebug_shf, "[%d] %s:\n", getpid(), str); 193 for (i = 0; i < nbytes; i += nprow) { 194 char c = '\t'; 195 for (j = 0; j < nprow && i + j < nbytes; j++) { 196 shf_fprintf(kshdebug_shf, "%c%02x", 197 c, ((const unsigned char *) mem)[i + j]); 198 c = ' '; 199 } 200 shf_fprintf(kshdebug_shf, "\n"); 201 } 202 shf_flush(kshdebug_shf); 203} 204#endif /* KSH_DEBUG */ 205 206/* test if we can seek backwards fd (returns 0 or SHF_UNBUF) */ 207int 208can_seek(fd) 209 int fd; 210{ 211 struct stat statb; 212 213 return fstat(fd, &statb) == 0 && !S_ISREG(statb.st_mode) ? 214 SHF_UNBUF : 0; 215} 216 217struct shf shf_iob[3]; 218 219void 220initio() 221{ 222 shf_fdopen(1, SHF_WR, shl_stdout); /* force buffer allocation */ 223 shf_fdopen(2, SHF_WR, shl_out); 224 shf_fdopen(2, SHF_WR, shl_spare); /* force buffer allocation */ 225 initio_done = 1; 226 kshdebug_init(); 227} 228 229/* A dup2() with error checking */ 230int 231ksh_dup2(ofd, nfd, errok) 232 int ofd; 233 int nfd; 234 int errok; 235{ 236 int ret = dup2(ofd, nfd); 237 238 if (ret < 0 && errno != EBADF && !errok) 239 errorf("too many files open in shell"); 240 241 return ret; 242} 243 244/* 245 * move fd from user space (0<=fd<10) to shell space (fd>=10), 246 * set close-on-exec flag. 247 */ 248int 249savefd(fd, noclose) 250 int fd; 251 int noclose; 252{ 253 int nfd; 254 255 if (fd < FDBASE) { 256 nfd = ksh_dupbase(fd, FDBASE); 257 if (nfd < 0) { 258 if (errno == EBADF) 259 return -1; 260 else 261 errorf("too many files open in shell"); 262 } 263 if (!noclose) 264 close(fd); 265 } else 266 nfd = fd; 267 fd_clexec(nfd); 268 return nfd; 269} 270 271void 272restfd(fd, ofd) 273 int fd, ofd; 274{ 275 if (fd == 2) 276 shf_flush(&shf_iob[fd]); 277 if (ofd < 0) /* original fd closed */ 278 close(fd); 279 else if (fd != ofd) { 280 ksh_dup2(ofd, fd, true); /* XXX: what to do if this fails? */ 281 close(ofd); 282 } 283} 284 285void 286openpipe(pv) 287 int *pv; 288{ 289 if (pipe(pv) < 0) 290 errorf("can't create pipe - try again"); 291 pv[0] = savefd(pv[0], 0); 292 pv[1] = savefd(pv[1], 0); 293} 294 295void 296closepipe(pv) 297 int *pv; 298{ 299 close(pv[0]); 300 close(pv[1]); 301} 302 303/* Called by iosetup() (deals with 2>&4, etc.), c_read, c_print to turn 304 * a string (the X in 2>&X, read -uX, print -uX) into a file descriptor. 305 */ 306int 307check_fd(name, mode, emsgp) 308 char *name; 309 int mode; 310 const char **emsgp; 311{ 312 int fd, fl; 313 314 if (isdigit((unsigned char)name[0]) && !name[1]) { 315 fd = name[0] - '0'; 316 if ((fl = fcntl(fd = name[0] - '0', F_GETFL, 0)) < 0) { 317 if (emsgp) 318 *emsgp = "bad file descriptor"; 319 return -1; 320 } 321 fl &= O_ACCMODE; 322 323 /* X_OK is a kludge to disable this check for dups (x<&1): 324 * historical shells never did this check (XXX don't know what 325 * posix has to say). 326 */ 327 if (!(mode & X_OK) && fl != O_RDWR 328 && (((mode & R_OK) && fl != O_RDONLY) 329 || ((mode & W_OK) && fl != O_WRONLY))) 330 { 331 if (emsgp) 332 *emsgp = (fl == O_WRONLY) ? 333 "fd not open for reading" 334 : "fd not open for writing"; 335 return -1; 336 } 337 return fd; 338 } 339#ifdef KSH 340 else if (name[0] == 'p' && !name[1]) 341 return coproc_getfd(mode, emsgp); 342#endif /* KSH */ 343 if (emsgp) 344 *emsgp = "illegal file descriptor name"; 345 return -1; 346} 347 348#ifdef KSH 349/* Called once from main */ 350void 351coproc_init() 352{ 353 coproc.read = coproc.readw = coproc.write = -1; 354 coproc.njobs = 0; 355 coproc.id = 0; 356} 357 358/* Called by c_read() when eof is read - close fd if it is the co-process fd */ 359void 360coproc_read_close(fd) 361 int fd; 362{ 363 if (coproc.read >= 0 && fd == coproc.read) { 364 coproc_readw_close(fd); 365 close(coproc.read); 366 coproc.read = -1; 367 } 368} 369 370/* Called by c_read() and by iosetup() to close the other side of the 371 * read pipe, so reads will actually terminate. 372 */ 373void 374coproc_readw_close(fd) 375 int fd; 376{ 377 if (coproc.readw >= 0 && coproc.read >= 0 && fd == coproc.read) { 378 close(coproc.readw); 379 coproc.readw = -1; 380 } 381} 382 383/* Called by c_print when a write to a fd fails with EPIPE and by iosetup 384 * when co-process input is dup'd 385 */ 386void 387coproc_write_close(fd) 388 int fd; 389{ 390 if (coproc.write >= 0 && fd == coproc.write) { 391 close(coproc.write); 392 coproc.write = -1; 393 } 394} 395 396/* Called to check for existence of/value of the co-process file descriptor. 397 * (Used by check_fd() and by c_read/c_print to deal with -p option). 398 */ 399int 400coproc_getfd(mode, emsgp) 401 int mode; 402 const char **emsgp; 403{ 404 int fd = (mode & R_OK) ? coproc.read : coproc.write; 405 406 if (fd >= 0) 407 return fd; 408 if (emsgp) 409 *emsgp = "no coprocess"; 410 return -1; 411} 412 413/* called to close file descriptors related to the coprocess (if any) 414 * Should be called with SIGCHLD blocked. 415 */ 416void 417coproc_cleanup(reuse) 418 int reuse; 419{ 420 /* This to allow co-processes to share output pipe */ 421 if (!reuse || coproc.readw < 0 || coproc.read < 0) { 422 if (coproc.read >= 0) { 423 close(coproc.read); 424 coproc.read = -1; 425 } 426 if (coproc.readw >= 0) { 427 close(coproc.readw); 428 coproc.readw = -1; 429 } 430 } 431 if (coproc.write >= 0) { 432 close(coproc.write); 433 coproc.write = -1; 434 } 435} 436#endif /* KSH */ 437 438 439/* 440 * temporary files 441 */ 442 443struct temp * 444maketemp(ap, type, tlist) 445 Area *ap; 446 Temp_type type; 447 struct temp **tlist; 448{ 449#ifndef __NetBSD__ 450 static unsigned int inc; 451#endif 452 struct temp *tp; 453 int len; 454 int fd; 455 char *pathx; 456 const char *dir; 457 458 dir = tmpdir ? tmpdir : "/tmp"; 459 /* The 20 + 20 is a paranoid worst case for pid/inc */ 460 len = strlen(dir) + 3 + 20 + 20 + 1; 461 tp = (struct temp *) alloc(sizeof(struct temp) + len, ap); 462 tp->name = pathx = (char *) &tp[1]; 463 tp->shf = (struct shf *) 0; 464 tp->type = type; 465#ifdef __NetBSD__ 466 shf_snprintf(pathx, len, "%s/shXXXXXXXX", dir); 467 fd = mkstemp(pathx); 468 if (fd >= 0) 469 tp->shf = shf_fdopen(fd, SHF_WR, (struct shf *) 0); 470#else 471 while (1) { 472 /* Note that temp files need to fit 8.3 DOS limits */ 473 shf_snprintf(pathx, len, "%s/sh%05u.%03x", 474 dir, (unsigned) procpid, inc++); 475 /* Mode 0600 to be paranoid, O_TRUNC in case O_EXCL isn't 476 * really there. 477 */ 478 fd = open(pathx, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0600); 479 if (fd >= 0) { 480 tp->shf = shf_fdopen(fd, SHF_WR, (struct shf *) 0); 481 break; 482 } 483 if (errno != EINTR 484#ifdef EEXIST 485 && errno != EEXIST 486#endif /* EEXIST */ 487#ifdef EISDIR 488 && errno != EISDIR 489#endif /* EISDIR */ 490 ) 491 /* Error must be printed by caller: don't know here if 492 * errorf() or bi_errorf() should be used. 493 */ 494 break; 495 } 496#endif /* __NetBSD__ */ 497 tp->pid = procpid; 498 499 tp->next = *tlist; 500 *tlist = tp; 501 502 return tp; 503} 504