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 */
settemp(pid)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
initf(fd)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
estabf(s,fd)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
push(af)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
pop(flag)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
sync_io()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
fdopen(fd,mode)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
chkpipe(pv)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
pipe_close(pv)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
chkopen(name)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
frenumber(f1,f2)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
tmp_open(fname)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
create(s)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
chkrdwr(name,fd)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
closefd(fd)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
copy(ioparg)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
qtrim(string)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
fputs(s,fd)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
link_iodocs(i)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
swap_iodoc_nm(i)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
savefd(fd,oldtop)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
restore(last)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
ispipe(fd)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
_filbuf(iop)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
fcntl(f1,type,arg)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
setbuf(iop,buf)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
fread(ptr,size,count,iop)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
getppid()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
file_fd(n)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