1 /* @(#)io.c 1.1 */ 2 /* 3 * UNIX shell 4 * 5 * S. R. Bourne 6 * Rewritten by David Korn 7 * AT&T Bell Laboratories 8 * 9 */ 10 11 #include <errno.h> 12 #if BSD 13 #include <sys/types.h> 14 #include <sys/stat.h> 15 #include <sys/ioctl.h> 16 # ifdef BSD_4_2 17 # include <fcntl.h> 18 # endif /* BSD_4_2 */ 19 # define CAST (char*) 20 #else 21 # ifdef VENIX 22 # include <sys/types.h> 23 # include <sys/stat.h> 24 # define CAST (char*) 25 # else 26 # include <fcntl.h> 27 # define CAST (unsigned char*) 28 # endif /* VENIX */ 29 #endif /* BSD */ 30 #include "defs.h" 31 #include "flags.h" 32 #include "sym.h" 33 #include "io.h" 34 #include "shtype.h" 35 #ifndef F_DUPFD 36 #define F_DUPFD 0 37 #define NO_FCNTL 1 38 #endif /* F_DUPFD */ 39 40 /* This module defines the following routines */ 41 FILE *fdopen(); 42 FILE *create(); 43 FILE *chkrdwr(); 44 int ispipe(); 45 void sync_io(); 46 void settemp(); 47 void swap_iodoc_nm(); 48 void initf(); 49 void restore(); 50 int estabf(); 51 void chkpipe(); 52 53 /* This module references the following externals */ 54 extern STKPTR locstak(),cpystak(); 55 extern void chkpr(); 56 extern void failed(); 57 extern void free(); 58 extern char *heap(); 59 extern char *itos(); 60 extern long lseek(); 61 extern char *movstr(); 62 extern void p_flush(); 63 extern char *strrchr(); 64 65 66 static int qtrim(); 67 static int serial; 68 static char *temp_suffix; 69 static struct filesave fdmap[MAXFILES]; 70 71 72 /* ======== input output and file copying ======== */ 73 74 /* 75 * initialize temp file names 76 */ 77 void settemp(pid) 78 char *pid; 79 { 80 register char *sp = movstr(pid,tmpout+7); 81 *sp++ = '.'; 82 temp_suffix = sp; 83 serial = 0; 84 states &= ~NO_TMP; 85 } 86 87 /* 88 * set up a fileblk associated with the stream fd 89 */ 90 91 void initf(fd) 92 FILE *fd; 93 { 94 register SHFILE f=standin; 95 f->fdes=fd; 96 f->feval=0; 97 f->flin=1; 98 } 99 100 /* 101 * set up an I/O stream that will cause reading from a string 102 */ 103 104 int estabf(s,fd) 105 register FILE *fd; 106 register char *s; 107 { 108 register SHFILE f; 109 (f=standin)->fdes = fd; 110 fd->_flag = _IOREAD; 111 fd->_base = fd->_ptr = CAST s; 112 fd->_file = F_STRING; 113 fd->_cnt = F_INFINITE; 114 f->flin = 1; 115 fd->_flag|=(s==0?_IOEOF:0); 116 return(feof(fd)); 117 } 118 119 push(af) 120 SHFILE af; 121 { 122 register SHFILE f; 123 (f=af)->fstak=standin; 124 f->feval=0; 125 standin=f; 126 } 127 128 pop(flag) 129 register int flag; 130 { 131 register SHFILE f; 132 register FILE *fd; 133 register int fno; 134 if((f=standin)->fstak) 135 { 136 fd = f->fdes; 137 fno = fileno(fd); 138 if(flag==0 && fno>0 && fno!=F_STRING && fno!=INIO && fd!=cpipe[INPIPE]) 139 closefd(fd); 140 standin=f->fstak; 141 return(1); 142 } 143 return(0); 144 } 145 146 /* 147 * sync_io - flushes output buffer and positions stdin if necessary 148 */ 149 150 void sync_io() 151 { 152 register FILE *fp = stdin; 153 p_flush(); 154 /* position back the read-ahead characters */ 155 if(fp->_cnt) 156 { 157 lseek(fileno(fp),-((long)(fp->_cnt)),1); 158 setbuf(fp,(char*)fp->_base); 159 } 160 } 161 162 163 /* 164 * This non-standard version of fdopen makes stream numbers 165 * correspond to file unit numbers 166 */ 167 168 FILE *fdopen(fd, mode) 169 register int fd; 170 register char *mode; 171 { 172 register FILE *iop; 173 if(fd < 0) 174 return(NULL); 175 iop = file_fd(fd); 176 iop->_cnt = 0; 177 iop->_file = fd; 178 iop->_base = NULL; 179 switch(*mode) 180 { 181 182 case 'r': 183 iop->_flag |= _IOREAD; 184 break; 185 case 'a': 186 lseek(fd, 0L, 2); 187 /* No break */ 188 case 'w': 189 iop->_flag |= _IOWRT; 190 break; 191 default: 192 return(NULL); 193 } 194 195 if(mode[1] == '+') 196 { 197 iop->_flag &= ~(_IOREAD | _IOWRT); 198 iop->_flag |= _IORW; 199 } 200 return(iop); 201 } 202 203 void chkpipe(pv) 204 FILE *pv[]; 205 { 206 int ipv[2]; 207 if(pipe(ipv)<0 || ipv[INPIPE]<0 || ipv[OTPIPE]<0) 208 error(piperr); 209 pv[INPIPE] = fdopen(ipv[INPIPE],"r"); 210 pv[OTPIPE] = fdopen(ipv[OTPIPE],"w"); 211 } 212 213 /* 214 * close a pipe 215 */ 216 217 void pipe_close(pv) 218 register FILE *pv[]; 219 { 220 if(pv[INPIPE]) 221 fclose(pv[INPIPE]); 222 if(pv[OTPIPE]) 223 fclose(pv[OTPIPE]); 224 } 225 226 /* 227 * Open a stream for reading 228 * On failure, print message. 229 */ 230 231 FILE *chkopen(name) 232 register char *name; 233 { 234 register FILE *fd; 235 if((fd=fdopen(open(name,0),"r"))==NULL) 236 failed(name,badopen); 237 return(fd); 238 } 239 240 241 /* 242 * given a file stream f1, move it to a new file stream with file number 243 * f2. If f2 is open then it is closed first. 244 * If the MARK bit not set on f2, then close on exec will be set for f2>2 245 * The original stream is closed. 246 * File numbers greater than 2 are marked close on exec if frenumber is 247 * invoked by a parent shell. 248 * The new file descriptor is returned; 249 */ 250 251 FILE *frenumber(f1,f2) 252 FILE *f1; 253 register int f2; 254 { 255 register FILE *fd; 256 register int flag = (f2&MARK); 257 register int fs=0; 258 register char *type; 259 f2 &= ~MARK; 260 if(f2>2 && flag==0) 261 fs = 1; 262 fd = file_fd(f2); 263 if(fileno(f1)!=f2) 264 { 265 int fno; 266 if(fs==0) 267 fs = fcntl(f2,1,0); 268 if(fisopen(fd)) 269 { 270 closefd(fd); 271 } 272 else 273 close(f2); 274 fno = fcntl(fileno(f1),0,f2); 275 if(fno < 0) 276 error(badfile); 277 flag = f1->_flag; 278 if(flag&_IORW) 279 type="w+"; 280 else 281 type = (f1->_flag&_IOREAD?"r":"w"); 282 fclose(f1); 283 fd = fdopen(f2,type); 284 #ifdef apollo 285 fd->_file = fno; 286 #endif /* apollo */ 287 fd->_flag = flag; 288 if(fd==output) 289 setbuf(fd,(char*)_sobuf); 290 else if(fd==input && (fd->_flag&_IONBF)==0) 291 setbuf(fd,(char*)_sibuf); 292 else 293 { 294 fd->_cnt = f1->_cnt; 295 fd->_ptr = f1->_ptr; 296 fd->_base = f1->_base; 297 } 298 setbuf(f1,NIL); 299 if(f2==0) 300 ioset |= 1; 301 } 302 if(fs==1) 303 #ifdef BSD 304 ioctl(f2, FIOCLEX, NULL); 305 #else 306 fcntl(f2,2,1); 307 #endif /* BSD */ 308 return(fd); 309 } 310 311 FILE *tmp_open(fname) 312 register char *fname; 313 { 314 register int maxtry = 10; 315 register char *tmp_name = tmpout; 316 register FILE *fd; 317 if(states&NO_TMP) 318 settemp(itos(getpid())); 319 do 320 { 321 movstr(itos(++serial),temp_suffix); 322 } 323 while((fd=create(tmp_name))== NULL && maxtry--); 324 if(fname) 325 { 326 movstr(tmp_name,fname); 327 if((fd = chkrdwr(tmp_name,fd))==NULL) 328 failed(tmp_name,badcreate); 329 } 330 return(fd); 331 } 332 333 /* 334 * create the file named s and return an open stream to it 335 */ 336 337 FILE *create(s) 338 char *s; 339 { 340 register FILE *fd; 341 fd = fdopen(creat(s,0666),"w+"); 342 return(fd); 343 } 344 345 /* 346 * close file stream and reopen for reading and writing 347 */ 348 349 FILE *chkrdwr(name,fd) 350 register char *name; 351 register FILE *fd; 352 { 353 if(fd!=NULL) 354 { 355 fclose(fd); 356 fd = fdopen(open(name,2),"w+"); 357 } 358 return(fd); 359 } 360 361 closefd(fd) 362 register FILE *fd; 363 { 364 365 /* reposition seek pointer if necessary */ 366 if((fd->_flag&_IOREAD) && fd->_cnt) 367 lseek(fileno(fd),-((long)(fd->_cnt)),1); 368 free(fd->_base); 369 fclose(fd); 370 setbuf(fd,NIL); 371 } 372 373 copy(ioparg) 374 IOPTR ioparg; 375 { 376 register char c = '\n'; 377 register char *clinep; 378 register IOPTR iop; 379 register FILE *fd; 380 BOOL nosubst; 381 char *ends,*cline,obuff[BUFSIZ]; 382 if(iop=ioparg) 383 { 384 int stripflg = iop->iofile&IOSTRIP; 385 register nlflg = stripflg; 386 copy(iop->iolst); 387 ends=iop->ioname; 388 /* check for and strip quoted characters in ends */ 389 nosubst = qtrim(ends); 390 if(nosubst) 391 iop->iofile &= ~IODOC; 392 fd = tmp_open(NIL); 393 iop->ioname = (char*)cpystak(tmpout); 394 setbuf(fd,obuff); 395 iop->iolst=iotemp; iotemp=iop; 396 cline=(char*)locstak(); 397 if(stripflg) 398 while(*ends=='\t') 399 ends++; 400 clinep = cline++; 401 *cline = 0; 402 do 403 { 404 if(c=='\n') 405 { 406 *clinep = 0; 407 if(eq(ends,cline)) 408 break; 409 chkpr(0); 410 *clinep++ = '\n'; 411 *clinep = 0; 412 fputs(cline,fd); 413 clinep = cline; 414 nlflg = stripflg; 415 } 416 else if(c=='\t' && nlflg) 417 ; 418 else 419 { 420 *clinep++ = c; 421 nlflg = 0; 422 } 423 } 424 while(c=(nosubst?readc():nextc())); 425 closefd(fd); 426 } 427 } 428 429 /* 430 * trim quotes and the escapes 431 * returns non-zero if string is quoted 0 otherwise 432 */ 433 434 static int qtrim(string) 435 char *string; 436 { 437 register char *sp = string; 438 register char *dp = sp; 439 register int c; 440 register int quote = 0; 441 while(c= *sp++) 442 { 443 if(c == ESCAPE) 444 { 445 quote = 1; 446 c = *sp++; 447 } 448 else if(c == '"') 449 { 450 quote = 1; 451 continue; 452 } 453 *dp++ = c; 454 } 455 *dp = 0; 456 return(quote); 457 } 458 459 /* 460 * short version of fputs 461 */ 462 463 int fputs(s,fd) 464 register char *s; 465 register FILE *fd; 466 { 467 register char c; 468 if(s==NULL || fd==NULL) 469 return(EOF); 470 while(c = *s++) 471 putc(c,fd); 472 return(0); 473 } 474 475 476 /* 477 * create a link to iodoc for child process to use 478 */ 479 480 link_iodocs(i) 481 register struct ionod *i; 482 { 483 while(i) 484 { 485 /* generate a tempory file name */ 486 fclose(tmp_open(NIL)); 487 unlink(tmpout); 488 free(i->iolink); 489 i->iolink = heap(tmpout); 490 link(i->ioname, i->iolink); 491 i = i->iolst; 492 } 493 } 494 495 496 /* 497 * rename the file with the link name of the parent 498 */ 499 500 void swap_iodoc_nm(i) 501 register struct ionod *i; 502 { 503 while(i) 504 { 505 free(i->ioname); 506 i->ioname = i->iolink; 507 i->iolink = 0; 508 i = i->iolst; 509 } 510 } 511 512 513 /* 514 * copy file fd into a save place 515 */ 516 517 savefd(fd,oldtop) 518 register int fd; 519 { 520 register int f = topfd; 521 register FILE *f1 = file_fd(fd); 522 /* see if already saved, only save once */ 523 while(f > oldtop) 524 { 525 if(fdmap[--f].org_fd == fd) 526 return; 527 } 528 if(fiswrite(f1)) 529 fflush(f1); 530 else if(f1==stdin) 531 sync_io(); 532 f = fcntl(fd, F_DUPFD, USERIO); 533 if(topfd >= MAXFILES) 534 error(nomorefiles); 535 if(f >= 0) 536 { 537 *(file_fd(f)) = *f1; 538 setbuf(f1,NIL); 539 } 540 fdmap[topfd].org_fd = fd; 541 fdmap[topfd++].dup_fd = f; 542 return; 543 } 544 545 546 /* 547 * restore saved file descriptors from <last> on 548 */ 549 550 void restore(last) 551 register int last; 552 { 553 register int i; 554 register int dupfd; 555 556 for (i = topfd - 1; i >= last; i--) 557 { 558 if ((dupfd = fdmap[i].dup_fd) > 0) 559 { 560 (file_fd(dupfd))->_file = dupfd; 561 frenumber(file_fd(dupfd), fdmap[i].org_fd); 562 } 563 else 564 fclose(file_fd(fdmap[i].org_fd)); 565 } 566 topfd = last; 567 } 568 569 570 /* 571 * This routine returns 1 if fd corresponds to a pipe, 0 otherwise. 572 */ 573 574 int ispipe(fd) 575 FILE *fd; 576 { 577 register int fno = fileno(fd); 578 if(lseek(fno,0L,1)>=0) 579 return(0); 580 if(errno==ESPIPE) 581 return(!isatty(fno)); 582 #ifdef BSD 583 /* This may be a bug in lseek */ 584 else if(errno==EINVAL) 585 return(1); 586 #endif /* BSD */ 587 else 588 return(0); 589 } 590 591 592 #if ESH || VSH 593 /* 594 * Stripped down version of _filbuf from standard I/O library 595 */ 596 597 _filbuf(iop) 598 register FILE *iop; 599 { 600 register unsigned state = states; 601 unsigned char cc; 602 register int syncread; 603 604 if (iop->_flag & _IORW) 605 iop->_flag |= _IOREAD; 606 607 if ((iop->_flag&_IOREAD) == 0) 608 return(EOF); 609 if(fnobuff(iop)) 610 { 611 /* unbuffered reads needed for pipes */ 612 p_flush(); 613 iop->_cnt = read(fileno(iop),(char*)(&cc),1); 614 if(iop->_cnt>0) 615 { 616 iop->_cnt--; 617 return(cc); 618 } 619 goto skip; 620 } 621 syncread = ((state&PROMPT) && iop==input && (standin->fstak==0||(state&RWAIT))); 622 #ifdef ESH 623 if(is_option(EMACS|GMACS) && syncread) 624 iop->_cnt = hread(fileno(iop), (char*)iop->_base, BUFSIZ); 625 else 626 #endif /* ESH */ 627 #ifdef VSH 628 if(is_option(EDITVI) && syncread) 629 iop->_cnt = vread(fileno(iop), (unsigned char*)iop->_base, BUFSIZ); 630 else 631 #endif /* VSH */ 632 { 633 /* flush before a read */ 634 if(syncread) 635 p_flush(); 636 iop->_cnt = read(fileno(iop), (char*)iop->_base, BUFSIZ); 637 } 638 iop->_ptr = iop->_base; 639 skip: 640 if (--iop->_cnt < 0) 641 { 642 if (iop->_cnt == -1) 643 { 644 iop->_flag |= _IOEOF; 645 if (iop->_flag & _IORW) 646 iop->_flag &= ~_IOREAD; 647 } 648 else 649 iop->_flag |= _IOERR; 650 iop->_cnt = 0; 651 return(-1); 652 } 653 return(*iop->_ptr++&STRIP); 654 } 655 #endif 656 657 658 #ifdef NO_FCNTL 659 static int fcntl(f1,type,arg) 660 register int arg; 661 { 662 struct stat statbuf; 663 if(type==F_DUPFD) 664 { 665 register int fd; 666 /* find first non-open file */ 667 while(arg < _NFILE && (fstat(arg,&statbuf)>=0)) 668 arg++; 669 if(arg >= _NFILE) 670 return(-1); 671 fd = dup(f1|DUPFLG,arg); 672 return(fd); 673 } 674 else 675 return(0); 676 } 677 #endif /* NO_FCNTL */ 678 679 #if u370 || uts 680 681 extern int isatty(); 682 extern unsigned char _smbuf[][_SBFSIZ]; 683 684 void setbuf(iop, buf) 685 register FILE *iop; 686 char *buf; 687 { 688 register int fno = fileno(iop); /* file number */ 689 690 if(iop->_base != NULL && iop->_flag & _IOMYBUF) 691 free((char*)iop->_base); 692 iop->_flag &= ~(_IOMYBUF | _IONBF | _IOLBF); 693 if((iop->_base = (unsigned char*)buf) == NULL) 694 { 695 iop->_flag |= _IONBF; /* file unbuffered except in fastio */ 696 697 _bufend(iop) = (iop->_base = _smbuf[fno]) + _SBFSIZ; 698 } 699 else 700 { /* regular buffered I/O, standard buffer size */ 701 _bufend(iop) = iop->_base + BUFSIZ; 702 if (isatty(fno)) 703 iop->_flag |= _IOLBF; 704 } 705 iop->_ptr = iop->_base; 706 iop->_cnt = 0; 707 } 708 #endif /* u370 */ 709 710 #ifdef INT16 711 /* 712 * special version of fread for to save space 713 * only works if count is 1 714 */ 715 716 fread(ptr,size,count,iop) 717 register char *ptr; 718 unsigned size,count; 719 register FILE *iop; 720 { 721 register int c; 722 do 723 { 724 if((c=getc(iop))>=0) 725 *ptr++ = c; 726 else 727 return(0); 728 } 729 while(--size); 730 return(1); 731 } 732 #endif /* INT16 */ 733 734 #ifdef VENIX 735 int getppid() 736 { 737 return(1); 738 } 739 #endif /* VENIX */ 740 741 #ifdef _N_STATIC_IOBS 742 /* ULTRIX doesn't have complete _iob */ 743 FILE _myiob[FCIO+1- _N_STATIC_IOBS]; 744 745 FILE *file_fd(n) 746 { 747 if(n < _N_STATIC_IOBS) 748 return(&_iob[n]); 749 else 750 return(&_myiob[n- _N_STATIC_IOBS]); 751 } 752 #endif /* _N_STATIC_IOBS */ 753