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 16 static int initio_done; 17 18 /* 19 * formatted output functions 20 */ 21 22 23 /* A shell error occurred (eg, syntax error, etc.) */ 24 void 25 errorf(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 */ 43 void 44 warningf(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 */ 59 void 60 bi_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 */ 90 void 91 internal_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]: " */ 107 void 108 error_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 */ 123 void 124 shellf(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) */ 137 void 138 shprintf(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 150 static struct shf *kshdebug_shf; 151 152 void 153 kshdebug_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 */ 167 void 168 kshdebug_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 181 void 182 kshdebug_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) */ 207 int 208 can_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 217 struct shf shf_iob[3]; 218 219 void 220 initio() 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 */ 230 int 231 ksh_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 */ 248 int 249 savefd(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 271 void 272 restfd(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 285 void 286 openpipe(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 295 void 296 closepipe(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 */ 306 int 307 check_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 */ 350 void 351 coproc_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 */ 359 void 360 coproc_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 */ 373 void 374 coproc_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 */ 386 void 387 coproc_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 */ 399 int 400 coproc_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 */ 416 void 417 coproc_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 443 struct temp * 444 maketemp(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