1 /* $NetBSD: io.c,v 1.2 1997/01/12 19:11:53 tls 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 if (!noclose) 236 close(fd); 237 } else 238 nfd = fd; 239 fd_clexec(nfd); 240 return nfd; 241 } 242 243 void 244 restfd(fd, ofd) 245 int fd, ofd; 246 { 247 if (fd == 2) 248 shf_flush(&shf_iob[fd]); 249 if (ofd < 0) /* original fd closed */ 250 close(fd); 251 else { 252 ksh_dup2(ofd, fd, TRUE); /* XXX: what to do if this fails? */ 253 close(ofd); 254 } 255 } 256 257 void 258 openpipe(pv) 259 register int *pv; 260 { 261 if (pipe(pv) < 0) 262 errorf("can't create pipe - try again"); 263 pv[0] = savefd(pv[0], 0); 264 pv[1] = savefd(pv[1], 0); 265 } 266 267 void 268 closepipe(pv) 269 register int *pv; 270 { 271 close(pv[0]); 272 close(pv[1]); 273 } 274 275 /* Called by iosetup() (deals with 2>&4, etc.), c_read, c_print to turn 276 * a string (the X in 2>&X, read -uX, print -uX) into a file descriptor. 277 */ 278 int 279 check_fd(name, mode, emsgp) 280 char *name; 281 int mode; 282 const char **emsgp; 283 { 284 int fd, fl; 285 286 if (isdigit(name[0]) && !name[1]) { 287 fd = name[0] - '0'; 288 if ((fl = fcntl(fd = name[0] - '0', F_GETFL, 0)) < 0) { 289 if (emsgp) 290 *emsgp = "bad file descriptor"; 291 return -1; 292 } 293 fl &= O_ACCMODE; 294 #ifdef OS2 295 if (mode == W_OK ) { 296 if (setmode(fd, O_TEXT) == -1) { 297 if (emsgp) 298 *emsgp = "couldn't set write mode"; 299 return -1; 300 } 301 } else if (mode == R_OK) 302 if (setmode(fd, O_BINARY) == -1) { 303 if (emsgp) 304 *emsgp = "couldn't set read mode"; 305 return -1; 306 } 307 #else /* OS2 */ 308 /* X_OK is a kludge to disable this check for dups (x<&1): 309 * historical shells never did this check (XXX don't know what 310 * posix has to say). 311 */ 312 if (!(mode & X_OK) && fl != O_RDWR 313 && (((mode & R_OK) && fl != O_RDONLY) 314 || ((mode & W_OK) && fl != O_WRONLY))) 315 { 316 if (emsgp) 317 *emsgp = (fl == O_WRONLY) ? 318 "fd not open for reading" 319 : "fd not open for writing"; 320 return -1; 321 } 322 #endif /* OS2 */ 323 return fd; 324 } 325 #ifdef KSH 326 else if (name[0] == 'p' && !name[1]) 327 return coproc_getfd(mode, emsgp); 328 #endif /* KSH */ 329 if (emsgp) 330 *emsgp = "illegal file descriptor name"; 331 return -1; 332 } 333 334 #ifdef KSH 335 /* Called once from main */ 336 void 337 coproc_init() 338 { 339 coproc.read = coproc.readw = coproc.write = -1; 340 coproc.njobs = 0; 341 coproc.id = 0; 342 } 343 344 /* Called by c_read() when eof is read - close fd if it is the co-process fd */ 345 void 346 coproc_read_close(fd) 347 int fd; 348 { 349 if (coproc.read >= 0 && fd == coproc.read) { 350 coproc_readw_close(fd); 351 close(coproc.read); 352 coproc.read = -1; 353 } 354 } 355 356 /* Called by c_read() and by iosetup() to close the other side of the 357 * read pipe, so reads will actually terminate. 358 */ 359 void 360 coproc_readw_close(fd) 361 int fd; 362 { 363 if (coproc.readw >= 0 && coproc.read >= 0 && fd == coproc.read) { 364 close(coproc.readw); 365 coproc.readw = -1; 366 } 367 } 368 369 /* Called by c_print when a write to a fd fails with EPIPE and by iosetup 370 * when co-process input is dup'd 371 */ 372 void 373 coproc_write_close(fd) 374 int fd; 375 { 376 if (coproc.write >= 0 && fd == coproc.write) { 377 close(coproc.write); 378 coproc.write = -1; 379 } 380 } 381 382 /* Called to check for existance of/value of the co-process file descriptor. 383 * (Used by check_fd() and by c_read/c_print to deal with -p option). 384 */ 385 int 386 coproc_getfd(mode, emsgp) 387 int mode; 388 const char **emsgp; 389 { 390 int fd = (mode & R_OK) ? coproc.read : coproc.write; 391 392 if (fd >= 0) 393 return fd; 394 if (emsgp) 395 *emsgp = "no coprocess"; 396 return -1; 397 } 398 399 /* called to close file descriptors related to the coprocess (if any) 400 * Should be called with SIGCHLD blocked. 401 */ 402 void 403 coproc_cleanup(reuse) 404 int reuse; 405 { 406 /* This to allow co-processes to share output pipe */ 407 if (!reuse || coproc.readw < 0 || coproc.read < 0) { 408 if (coproc.read >= 0) { 409 close(coproc.read); 410 coproc.read = -1; 411 } 412 if (coproc.readw >= 0) { 413 close(coproc.readw); 414 coproc.readw = -1; 415 } 416 } 417 if (coproc.write >= 0) { 418 close(coproc.write); 419 coproc.write = -1; 420 } 421 } 422 #endif /* KSH */ 423 424 /* 425 * temporary files 426 */ 427 428 struct temp * 429 maketemp(ap) 430 Area *ap; 431 { 432 static unsigned int inc; 433 struct temp *tp; 434 int len; 435 int fd; 436 char *path; 437 const char *tmp; 438 439 tmp = tmpdir ? tmpdir : "/tmp"; 440 /* The 20 + 20 is a paranoid worst case for pid/inc */ 441 len = strlen(tmp) + 3 + 20 + 20 + 1; 442 tp = (struct temp *) alloc(sizeof(struct temp) + len, ap); 443 tp->name = path = (char *) &tp[1]; 444 tp->shf = (struct shf *) 0; 445 while (1) { 446 /* Note that temp files need to fit 8.3 DOS limits */ 447 shf_snprintf(path, len, "%s/sh%05u.%03x", 448 tmp, (unsigned) procpid, inc++); 449 /* Mode 0600 to be paranoid, O_TRUNC in case O_EXCL isn't 450 * really there. 451 */ 452 fd = open(path, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0600); 453 if (fd >= 0) { 454 tp->shf = shf_fdopen(fd, SHF_WR, (struct shf *) 0); 455 break; 456 } 457 if (errno != EINTR 458 #ifdef EEXIST 459 && errno != EEXIST 460 #endif /* EEXIST */ 461 #ifdef EISDIR 462 && errno != EISDIR 463 #endif /* EISDIR */ 464 ) 465 /* Error must be printed by called: don't know here if 466 * errorf() or bi_errorf() should be used. 467 */ 468 break; 469 } 470 tp->next = NULL; 471 tp->pid = procpid; 472 return tp; 473 } 474