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