1*3aaa63ebSderaadt /* $OpenBSD: io.c,v 1.37 2019/06/28 13:34:59 deraadt Exp $ */ 27cb960a2Sdownsj 37cb960a2Sdownsj /* 47cb960a2Sdownsj * shell buffered IO and formatted output 57cb960a2Sdownsj */ 67cb960a2Sdownsj 769b9f96bSmillert #include <sys/stat.h> 87cb960a2Sdownsj 9b608f594Smmcc #include <ctype.h> 104a010e0cStb #include <errno.h> 114a010e0cStb #include <fcntl.h> 1256018212Smmcc #include <string.h> 134a010e0cStb #include <unistd.h> 14b608f594Smmcc 15b608f594Smmcc #include "sh.h" 16b608f594Smmcc 173b015934Smillert static int initio_done; 183b015934Smillert 197cb960a2Sdownsj /* 207cb960a2Sdownsj * formatted output functions 217cb960a2Sdownsj */ 227cb960a2Sdownsj 237cb960a2Sdownsj 2461e6c220Smpech /* A shell error occurred (eg, syntax error, etc.) */ 257cb960a2Sdownsj void 267cb960a2Sdownsj errorf(const char *fmt, ...) 277cb960a2Sdownsj { 287cb960a2Sdownsj va_list va; 297cb960a2Sdownsj 307cb960a2Sdownsj shl_stdout_ok = 0; /* debugging: note that stdout not valid */ 317cb960a2Sdownsj exstat = 1; 3263ca93eaSmillert if (fmt != NULL && *fmt != '\0') { 330e7d3a01Smillert error_prefix(true); 3469b9f96bSmillert va_start(va, fmt); 357cb960a2Sdownsj shf_vfprintf(shl_out, fmt, va); 367cb960a2Sdownsj va_end(va); 377cb960a2Sdownsj shf_putchar('\n', shl_out); 387cb960a2Sdownsj } 397cb960a2Sdownsj shf_flush(shl_out); 407cb960a2Sdownsj unwind(LERROR); 417cb960a2Sdownsj } 427cb960a2Sdownsj 437cb960a2Sdownsj /* like errorf(), but no unwind is done */ 447cb960a2Sdownsj void 45504796f7Smmcc warningf(bool show_lineno, const char *fmt, ...) 467cb960a2Sdownsj { 477cb960a2Sdownsj va_list va; 487cb960a2Sdownsj 49504796f7Smmcc error_prefix(show_lineno); 5069b9f96bSmillert va_start(va, fmt); 517cb960a2Sdownsj shf_vfprintf(shl_out, fmt, va); 527cb960a2Sdownsj va_end(va); 537cb960a2Sdownsj shf_putchar('\n', shl_out); 547cb960a2Sdownsj shf_flush(shl_out); 557cb960a2Sdownsj } 567cb960a2Sdownsj 577cb960a2Sdownsj /* Used by built-in utilities to prefix shell and utility name to message 587cb960a2Sdownsj * (also unwinds environments for special builtins). 597cb960a2Sdownsj */ 607cb960a2Sdownsj void 617cb960a2Sdownsj bi_errorf(const char *fmt, ...) 627cb960a2Sdownsj { 637cb960a2Sdownsj va_list va; 647cb960a2Sdownsj 657cb960a2Sdownsj shl_stdout_ok = 0; /* debugging: note that stdout not valid */ 667cb960a2Sdownsj exstat = 1; 6763ca93eaSmillert if (fmt != NULL && *fmt != '\0') { 680e7d3a01Smillert error_prefix(true); 697cb960a2Sdownsj /* not set when main() calls parse_args() */ 707cb960a2Sdownsj if (builtin_argv0) 717cb960a2Sdownsj shf_fprintf(shl_out, "%s: ", builtin_argv0); 7269b9f96bSmillert va_start(va, fmt); 737cb960a2Sdownsj shf_vfprintf(shl_out, fmt, va); 747cb960a2Sdownsj va_end(va); 757cb960a2Sdownsj shf_putchar('\n', shl_out); 767cb960a2Sdownsj } 777cb960a2Sdownsj shf_flush(shl_out); 787cb960a2Sdownsj /* POSIX special builtins and ksh special builtins cause 797cb960a2Sdownsj * non-interactive shells to exit. 807cb960a2Sdownsj * XXX odd use of KEEPASN; also may not want LERROR here 817cb960a2Sdownsj */ 827a8124d8Sderaadt if ((builtin_flag & SPEC_BI) || 837a8124d8Sderaadt (Flag(FPOSIX) && (builtin_flag & KEEPASN))) { 84355ffa75Stedu builtin_argv0 = NULL; 857cb960a2Sdownsj unwind(LERROR); 867cb960a2Sdownsj } 877cb960a2Sdownsj } 887cb960a2Sdownsj 896c72b531Sjca static void 906c72b531Sjca internal_error_vwarn(const char *fmt, va_list va) 916c72b531Sjca { 926c72b531Sjca error_prefix(true); 936c72b531Sjca shf_fprintf(shl_out, "internal error: "); 946c72b531Sjca shf_vfprintf(shl_out, fmt, va); 956c72b531Sjca shf_putchar('\n', shl_out); 966c72b531Sjca shf_flush(shl_out); 976c72b531Sjca } 986c72b531Sjca 996c72b531Sjca /* Warn when something that shouldn't happen does */ 1007cb960a2Sdownsj void 1016c72b531Sjca internal_warningf(const char *fmt, ...) 1027cb960a2Sdownsj { 1037cb960a2Sdownsj va_list va; 1047cb960a2Sdownsj 10569b9f96bSmillert va_start(va, fmt); 1066c72b531Sjca internal_error_vwarn(fmt, va); 1077cb960a2Sdownsj va_end(va); 1086c72b531Sjca } 1096c72b531Sjca 1106c72b531Sjca /* Warn and unwind when something that shouldn't happen does */ 1116c72b531Sjca __dead void 1126c72b531Sjca internal_errorf(const char *fmt, ...) 1136c72b531Sjca { 1146c72b531Sjca va_list va; 1156c72b531Sjca 1166c72b531Sjca va_start(va, fmt); 1176c72b531Sjca internal_error_vwarn(fmt, va); 1186c72b531Sjca va_end(va); 1197cb960a2Sdownsj unwind(LERROR); 1207cb960a2Sdownsj } 1217cb960a2Sdownsj 1227cb960a2Sdownsj /* used by error reporting functions to print "ksh: .kshrc[25]: " */ 1237cb960a2Sdownsj void 124c5d5393cSotto error_prefix(int fileline) 1257cb960a2Sdownsj { 1263b015934Smillert /* Avoid foo: foo[2]: ... */ 1277a8124d8Sderaadt if (!fileline || !source || !source->file || 1287a8124d8Sderaadt strcmp(source->file, kshname) != 0) 1297cb960a2Sdownsj shf_fprintf(shl_out, "%s: ", kshname + (*kshname == '-')); 1307cb960a2Sdownsj if (fileline && source && source->file != NULL) { 1317cb960a2Sdownsj shf_fprintf(shl_out, "%s[%d]: ", source->file, 1327cb960a2Sdownsj source->errline > 0 ? source->errline : source->line); 1337cb960a2Sdownsj source->errline = 0; 1347cb960a2Sdownsj } 1357cb960a2Sdownsj } 1367cb960a2Sdownsj 1377cb960a2Sdownsj /* printf to shl_out (stderr) with flush */ 1387cb960a2Sdownsj void 1397cb960a2Sdownsj shellf(const char *fmt, ...) 1407cb960a2Sdownsj { 1417cb960a2Sdownsj va_list va; 1427cb960a2Sdownsj 1433b015934Smillert if (!initio_done) /* shl_out may not be set up yet... */ 1443b015934Smillert return; 14569b9f96bSmillert va_start(va, fmt); 1467cb960a2Sdownsj shf_vfprintf(shl_out, fmt, va); 1477cb960a2Sdownsj va_end(va); 1487cb960a2Sdownsj shf_flush(shl_out); 1497cb960a2Sdownsj } 1507cb960a2Sdownsj 1517cb960a2Sdownsj /* printf to shl_stdout (stdout) */ 1527cb960a2Sdownsj void 1537cb960a2Sdownsj shprintf(const char *fmt, ...) 1547cb960a2Sdownsj { 1557cb960a2Sdownsj va_list va; 1567cb960a2Sdownsj 1577cb960a2Sdownsj if (!shl_stdout_ok) 1586c72b531Sjca internal_errorf("shl_stdout not valid"); 15969b9f96bSmillert va_start(va, fmt); 1607cb960a2Sdownsj shf_vfprintf(shl_stdout, fmt, va); 1617cb960a2Sdownsj va_end(va); 1627cb960a2Sdownsj } 1637cb960a2Sdownsj 164945abdecSmillert #ifdef KSH_DEBUG 165945abdecSmillert static struct shf *kshdebug_shf; 166945abdecSmillert 167945abdecSmillert void 168c5d5393cSotto kshdebug_init_(void) 169945abdecSmillert { 170945abdecSmillert if (kshdebug_shf) 171945abdecSmillert shf_close(kshdebug_shf); 172945abdecSmillert kshdebug_shf = shf_open("/tmp/ksh-debug.log", 1737a8124d8Sderaadt O_WRONLY|O_APPEND|O_CREAT, 0600, SHF_WR|SHF_MAPHI); 174945abdecSmillert if (kshdebug_shf) { 175945abdecSmillert shf_fprintf(kshdebug_shf, "\nNew shell[pid %d]\n", getpid()); 176945abdecSmillert shf_flush(kshdebug_shf); 177945abdecSmillert } 178945abdecSmillert } 179945abdecSmillert 180945abdecSmillert /* print to debugging log */ 181945abdecSmillert void 182945abdecSmillert kshdebug_printf_(const char *fmt, ...) 183945abdecSmillert { 184945abdecSmillert va_list va; 185945abdecSmillert 186945abdecSmillert if (!kshdebug_shf) 187945abdecSmillert return; 18869b9f96bSmillert va_start(va, fmt); 189945abdecSmillert shf_fprintf(kshdebug_shf, "[%d] ", getpid()); 190945abdecSmillert shf_vfprintf(kshdebug_shf, fmt, va); 191945abdecSmillert va_end(va); 192945abdecSmillert shf_flush(kshdebug_shf); 193945abdecSmillert } 194945abdecSmillert 195945abdecSmillert void 196c5d5393cSotto kshdebug_dump_(const char *str, const void *mem, int nbytes) 197945abdecSmillert { 198945abdecSmillert int i, j; 199945abdecSmillert int nprow = 16; 200945abdecSmillert 201945abdecSmillert if (!kshdebug_shf) 202945abdecSmillert return; 203945abdecSmillert shf_fprintf(kshdebug_shf, "[%d] %s:\n", getpid(), str); 204945abdecSmillert for (i = 0; i < nbytes; i += nprow) { 205945abdecSmillert char c = '\t'; 2067a8124d8Sderaadt 207945abdecSmillert for (j = 0; j < nprow && i + j < nbytes; j++) { 2087a8124d8Sderaadt shf_fprintf(kshdebug_shf, "%c%02x", c, 2097a8124d8Sderaadt ((const unsigned char *) mem)[i + j]); 210945abdecSmillert c = ' '; 211945abdecSmillert } 212945abdecSmillert shf_fprintf(kshdebug_shf, "\n"); 213945abdecSmillert } 214945abdecSmillert shf_flush(kshdebug_shf); 215945abdecSmillert } 216945abdecSmillert #endif /* KSH_DEBUG */ 217945abdecSmillert 2187cb960a2Sdownsj /* test if we can seek backwards fd (returns 0 or SHF_UNBUF) */ 2197cb960a2Sdownsj int 220c5d5393cSotto can_seek(int fd) 2217cb960a2Sdownsj { 2227cb960a2Sdownsj struct stat statb; 2237cb960a2Sdownsj 2247cb960a2Sdownsj return fstat(fd, &statb) == 0 && !S_ISREG(statb.st_mode) ? 2257cb960a2Sdownsj SHF_UNBUF : 0; 2267cb960a2Sdownsj } 2277cb960a2Sdownsj 2287cb960a2Sdownsj struct shf shf_iob[3]; 2297cb960a2Sdownsj 2307cb960a2Sdownsj void 231c5d5393cSotto initio(void) 2327cb960a2Sdownsj { 2337cb960a2Sdownsj shf_fdopen(1, SHF_WR, shl_stdout); /* force buffer allocation */ 2347cb960a2Sdownsj shf_fdopen(2, SHF_WR, shl_out); 2357cb960a2Sdownsj shf_fdopen(2, SHF_WR, shl_spare); /* force buffer allocation */ 2363b015934Smillert initio_done = 1; 237945abdecSmillert kshdebug_init(); 2387cb960a2Sdownsj } 2397cb960a2Sdownsj 2407cb960a2Sdownsj /* A dup2() with error checking */ 2417cb960a2Sdownsj int 242c5d5393cSotto ksh_dup2(int ofd, int nfd, int errok) 2437cb960a2Sdownsj { 2447cb960a2Sdownsj int ret = dup2(ofd, nfd); 2457cb960a2Sdownsj 246*3aaa63ebSderaadt if (ret == -1 && errno != EBADF && !errok) 2477cb960a2Sdownsj errorf("too many files open in shell"); 2487cb960a2Sdownsj 2497cb960a2Sdownsj return ret; 2507cb960a2Sdownsj } 2517cb960a2Sdownsj 2527cb960a2Sdownsj /* 2537cb960a2Sdownsj * move fd from user space (0<=fd<10) to shell space (fd>=10), 2547cb960a2Sdownsj * set close-on-exec flag. 2557cb960a2Sdownsj */ 2567cb960a2Sdownsj int 257afe13ccaSmillert savefd(int fd) 2587cb960a2Sdownsj { 2597cb960a2Sdownsj int nfd; 2607cb960a2Sdownsj 2617cb960a2Sdownsj if (fd < FDBASE) { 262bf50f917Sguenther nfd = fcntl(fd, F_DUPFD_CLOEXEC, FDBASE); 263*3aaa63ebSderaadt if (nfd == -1) { 2647cb960a2Sdownsj if (errno == EBADF) 2657cb960a2Sdownsj return -1; 2667cb960a2Sdownsj else 2677cb960a2Sdownsj errorf("too many files open in shell"); 26818bbba6bSmillert } 269b703bf84Sguenther } else { 2707cb960a2Sdownsj nfd = fd; 271b703bf84Sguenther fcntl(nfd, F_SETFD, FD_CLOEXEC); 272b703bf84Sguenther } 2737cb960a2Sdownsj return nfd; 2747cb960a2Sdownsj } 2757cb960a2Sdownsj 2767cb960a2Sdownsj void 277c5d5393cSotto restfd(int fd, int ofd) 2787cb960a2Sdownsj { 2797cb960a2Sdownsj if (fd == 2) 2807cb960a2Sdownsj shf_flush(&shf_iob[fd]); 2817cb960a2Sdownsj if (ofd < 0) /* original fd closed */ 2827cb960a2Sdownsj close(fd); 283c06a3dc9Smillert else if (fd != ofd) { 2840e7d3a01Smillert ksh_dup2(ofd, fd, true); /* XXX: what to do if this fails? */ 2857cb960a2Sdownsj close(ofd); 2867cb960a2Sdownsj } 2877cb960a2Sdownsj } 2887cb960a2Sdownsj 2897cb960a2Sdownsj void 290c5d5393cSotto openpipe(int *pv) 2917cb960a2Sdownsj { 292afe13ccaSmillert int lpv[2]; 293afe13ccaSmillert 294*3aaa63ebSderaadt if (pipe(lpv) == -1) 2957cb960a2Sdownsj errorf("can't create pipe - try again"); 296afe13ccaSmillert pv[0] = savefd(lpv[0]); 297afe13ccaSmillert if (pv[0] != lpv[0]) 298afe13ccaSmillert close(lpv[0]); 299afe13ccaSmillert pv[1] = savefd(lpv[1]); 300afe13ccaSmillert if (pv[1] != lpv[1]) 301afe13ccaSmillert close(lpv[1]); 3027cb960a2Sdownsj } 3037cb960a2Sdownsj 3047cb960a2Sdownsj void 305c5d5393cSotto closepipe(int *pv) 3067cb960a2Sdownsj { 3077cb960a2Sdownsj close(pv[0]); 3087cb960a2Sdownsj close(pv[1]); 3097cb960a2Sdownsj } 3107cb960a2Sdownsj 3117cb960a2Sdownsj /* Called by iosetup() (deals with 2>&4, etc.), c_read, c_print to turn 3127cb960a2Sdownsj * a string (the X in 2>&X, read -uX, print -uX) into a file descriptor. 3137cb960a2Sdownsj */ 3147cb960a2Sdownsj int 315c5d5393cSotto check_fd(char *name, int mode, const char **emsgp) 3167cb960a2Sdownsj { 3177cb960a2Sdownsj int fd, fl; 3187cb960a2Sdownsj 319e569fc7cSderaadt if (isdigit((unsigned char)name[0]) && !name[1]) { 3207cb960a2Sdownsj fd = name[0] - '0'; 321*3aaa63ebSderaadt if ((fl = fcntl(fd, F_GETFL)) == -1) { 3227cb960a2Sdownsj if (emsgp) 3237cb960a2Sdownsj *emsgp = "bad file descriptor"; 3247cb960a2Sdownsj return -1; 3257cb960a2Sdownsj } 3267cb960a2Sdownsj fl &= O_ACCMODE; 3277cb960a2Sdownsj /* X_OK is a kludge to disable this check for dups (x<&1): 3287cb960a2Sdownsj * historical shells never did this check (XXX don't know what 3297cb960a2Sdownsj * posix has to say). 3307cb960a2Sdownsj */ 3317a8124d8Sderaadt if (!(mode & X_OK) && fl != O_RDWR && 3327a8124d8Sderaadt (((mode & R_OK) && fl != O_RDONLY) || 3337a8124d8Sderaadt ((mode & W_OK) && fl != O_WRONLY))) { 3347cb960a2Sdownsj if (emsgp) 3357cb960a2Sdownsj *emsgp = (fl == O_WRONLY) ? 3367a8124d8Sderaadt "fd not open for reading" : 3377a8124d8Sderaadt "fd not open for writing"; 3387cb960a2Sdownsj return -1; 3397cb960a2Sdownsj } 3407cb960a2Sdownsj return fd; 34194e42df6Smillert } else if (name[0] == 'p' && !name[1]) 342dcacb757Sdownsj return coproc_getfd(mode, emsgp); 3437cb960a2Sdownsj if (emsgp) 3447cb960a2Sdownsj *emsgp = "illegal file descriptor name"; 3457cb960a2Sdownsj return -1; 3467cb960a2Sdownsj } 3477cb960a2Sdownsj 3487cb960a2Sdownsj /* Called once from main */ 3497cb960a2Sdownsj void 350c5d5393cSotto coproc_init(void) 3517cb960a2Sdownsj { 3527cb960a2Sdownsj coproc.read = coproc.readw = coproc.write = -1; 353dcacb757Sdownsj coproc.njobs = 0; 354dcacb757Sdownsj coproc.id = 0; 3557cb960a2Sdownsj } 3567cb960a2Sdownsj 3577cb960a2Sdownsj /* Called by c_read() when eof is read - close fd if it is the co-process fd */ 3587cb960a2Sdownsj void 359c5d5393cSotto coproc_read_close(int fd) 3607cb960a2Sdownsj { 3617cb960a2Sdownsj if (coproc.read >= 0 && fd == coproc.read) { 362dcacb757Sdownsj coproc_readw_close(fd); 3637cb960a2Sdownsj close(coproc.read); 3647cb960a2Sdownsj coproc.read = -1; 3657cb960a2Sdownsj } 3667cb960a2Sdownsj } 3677cb960a2Sdownsj 3687cb960a2Sdownsj /* Called by c_read() and by iosetup() to close the other side of the 3697cb960a2Sdownsj * read pipe, so reads will actually terminate. 3707cb960a2Sdownsj */ 3717cb960a2Sdownsj void 372c5d5393cSotto coproc_readw_close(int fd) 3737cb960a2Sdownsj { 374dcacb757Sdownsj if (coproc.readw >= 0 && coproc.read >= 0 && fd == coproc.read) { 3757cb960a2Sdownsj close(coproc.readw); 3767cb960a2Sdownsj coproc.readw = -1; 3777cb960a2Sdownsj } 3787cb960a2Sdownsj } 3797cb960a2Sdownsj 3807cb960a2Sdownsj /* Called by c_print when a write to a fd fails with EPIPE and by iosetup 3817cb960a2Sdownsj * when co-process input is dup'd 3827cb960a2Sdownsj */ 3837cb960a2Sdownsj void 384c5d5393cSotto coproc_write_close(int fd) 3857cb960a2Sdownsj { 3867cb960a2Sdownsj if (coproc.write >= 0 && fd == coproc.write) { 3877cb960a2Sdownsj close(coproc.write); 3887cb960a2Sdownsj coproc.write = -1; 3897cb960a2Sdownsj } 3907cb960a2Sdownsj } 3917cb960a2Sdownsj 3922e25baf5Sdavid /* Called to check for existence of/value of the co-process file descriptor. 3937cb960a2Sdownsj * (Used by check_fd() and by c_read/c_print to deal with -p option). 3947cb960a2Sdownsj */ 3957cb960a2Sdownsj int 396c5d5393cSotto coproc_getfd(int mode, const char **emsgp) 3977cb960a2Sdownsj { 3987cb960a2Sdownsj int fd = (mode & R_OK) ? coproc.read : coproc.write; 3997cb960a2Sdownsj 4007cb960a2Sdownsj if (fd >= 0) 4017cb960a2Sdownsj return fd; 4027cb960a2Sdownsj if (emsgp) 4037cb960a2Sdownsj *emsgp = "no coprocess"; 4047cb960a2Sdownsj return -1; 4057cb960a2Sdownsj } 4067cb960a2Sdownsj 407dcacb757Sdownsj /* called to close file descriptors related to the coprocess (if any) 408dcacb757Sdownsj * Should be called with SIGCHLD blocked. 409dcacb757Sdownsj */ 4107cb960a2Sdownsj void 411c5d5393cSotto coproc_cleanup(int reuse) 4127cb960a2Sdownsj { 4137cb960a2Sdownsj /* This to allow co-processes to share output pipe */ 4147cb960a2Sdownsj if (!reuse || coproc.readw < 0 || coproc.read < 0) { 4157cb960a2Sdownsj if (coproc.read >= 0) { 4167cb960a2Sdownsj close(coproc.read); 4177cb960a2Sdownsj coproc.read = -1; 4187cb960a2Sdownsj } 4197cb960a2Sdownsj if (coproc.readw >= 0) { 4207cb960a2Sdownsj close(coproc.readw); 4217cb960a2Sdownsj coproc.readw = -1; 4227cb960a2Sdownsj } 4237cb960a2Sdownsj } 4247cb960a2Sdownsj if (coproc.write >= 0) { 4257cb960a2Sdownsj close(coproc.write); 4267cb960a2Sdownsj coproc.write = -1; 4277cb960a2Sdownsj } 4287cb960a2Sdownsj } 4297cb960a2Sdownsj 430f00c5086Smillert 4317cb960a2Sdownsj /* 4327cb960a2Sdownsj * temporary files 4337cb960a2Sdownsj */ 4347cb960a2Sdownsj 4357cb960a2Sdownsj struct temp * 436c5d5393cSotto maketemp(Area *ap, Temp_type type, struct temp **tlist) 4377cb960a2Sdownsj { 4387cb960a2Sdownsj struct temp *tp; 4397cb960a2Sdownsj int len; 4407cb960a2Sdownsj int fd; 4417cb960a2Sdownsj char *path; 442f00c5086Smillert const char *dir; 4437cb960a2Sdownsj 444f00c5086Smillert dir = tmpdir ? tmpdir : "/tmp"; 4457cb960a2Sdownsj /* The 20 + 20 is a paranoid worst case for pid/inc */ 446f00c5086Smillert len = strlen(dir) + 3 + 20 + 20 + 1; 4478c046d24Snicm tp = alloc(sizeof(struct temp) + len, ap); 4487cb960a2Sdownsj tp->name = path = (char *) &tp[1]; 449f7654a50Snicm tp->shf = NULL; 450f00c5086Smillert tp->type = type; 4514a5d53a7Smillert shf_snprintf(path, len, "%s/shXXXXXXXX", dir); 4524a5d53a7Smillert fd = mkstemp(path); 4534a5d53a7Smillert if (fd >= 0) 454f7654a50Snicm tp->shf = shf_fdopen(fd, SHF_WR, NULL); 4557cb960a2Sdownsj tp->pid = procpid; 456f00c5086Smillert 457f00c5086Smillert tp->next = *tlist; 458f00c5086Smillert *tlist = tp; 4597cb960a2Sdownsj return tp; 4607cb960a2Sdownsj } 461