1 /* $XConsortium: io.c /main/3 1995/11/01 16:48:07 rswiston $ */
2 /***************************************************************
6 * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF *
7 * AT&T BELL LABORATORIES *
8 * AND IS NOT TO BE DISCLOSED OR USED EXCEPT IN *
9 * ACCORDANCE WITH APPLICABLE AGREEMENTS *
11 * Copyright (c) 1995 AT&T Corp. *
12 * Unpublished & Not for Publication *
13 * All Rights Reserved *
15 * The copyright notice above does not evidence any *
16 * actual or intended publication of such source code *
18 * This software was created by the *
19 * Advanced Software Technology Department *
20 * AT&T Bell Laboratories *
22 * For further information contact *
23 * {research,attmail}!dgk *
25 ***************************************************************/
27 /* : : generated by proto : : */
29 #if !defined(__PROTO__)
30 #if defined(__STDC__) || defined(__cplusplus) || defined(_proto) || defined(c_plusplus)
31 #if defined(__cplusplus)
32 #define __MANGLE__ "C"
37 #define __PROTO__(x) x
39 #define __PARAM__(n,o) n
40 #if !defined(__STDC__) && !defined(__cplusplus)
41 #if !defined(c_plusplus)
52 #define __PROTO__(x) ()
53 #define __OTORP__(x) x
54 #define __PARAM__(n,o) o
62 #if defined(__cplusplus) || defined(c_plusplus)
63 #define __VARARG__ ...
67 #if defined(__STDARG__)
68 #define __VA_START__(p,a) va_start(p,a)
70 #define __VA_START__(p,a) va_start(p)
76 #if !defined(va_start)
77 #if defined(__STDARG__)
84 #include "variables.h"
91 #include "FEATURE/externs"
92 #include "FEATURE/dynamic"
93 #include "FEATURE/poll"
97 # if EAGAIN!=EWOULDBLOCK
99 # define EAGAIN EWOULDBLOCK
102 # define EAGAIN EWOULDBLOCK
105 # define O_NONBLOCK FNDELAY
106 # endif /* !O_NONBLOCK */
108 #define RW_ALL (S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH)
110 static __V_ *timeout;
112 #if defined(_lib_socket) && defined(_sys_socket) && defined(_hdr_netinet_in)
113 # include <sys/socket.h>
114 # include <netinet/in.h>
115 static int str2inet __PROTO__((const char*, struct sockaddr_in*));
123 int orig_fd; /* original file descriptor */
124 int save_fd; /* saved file descriptor */
128 static int eval_exceptf __PROTO__((Sfio_t*, int, Sfdisc_t*));
129 static int piperead __PROTO__((Sfio_t*, __V_*, int, Sfdisc_t*));
130 static int slowread __PROTO__((Sfio_t*, __V_*, int, Sfdisc_t*));
131 static int slowexcept __PROTO__((Sfio_t*, int, Sfdisc_t*));
132 static int pipeexcept __PROTO__((Sfio_t*, int, Sfdisc_t*));
133 static int io_prompt __PROTO__((int));
134 static int io_heredoc __PROTO__((register struct ionod*));
135 static void sftrack __PROTO__((Sfio_t*,int,int));
136 static int tee_write __PROTO__((Sfio_t*,const __V_*,int,Sfdisc_t*));
137 static const Sfdisc_t eval_disc = { NULL, NULL, NULL, eval_exceptf, NULL};
138 static Sfdisc_t tee_disc = {NULL,tee_write,NULL,NULL,NULL};
139 static Sfio_t *subopen __PROTO__((Sfio_t*, off_t, long));
140 static int subread __PROTO__((Sfio_t*, __V_*, int, Sfdisc_t*));
141 static int subexcept __PROTO__((Sfio_t*, int, Sfdisc_t*));
142 static const Sfdisc_t sub_disc = { subread, 0, 0, subexcept, 0 };
153 static struct fdsave *filemap;
154 static short filemapsize;
156 /* ======== input output and file copying ======== */
158 void sh_ioinit __PARAM__((void), ()){
161 filemap = (struct fdsave*)malloc(8*sizeof(struct fdsave));
162 #ifdef SHOPT_FASTPIPE
163 n = sh.lim.open_max+2;
166 #endif /* SHOPT_FASTPIPE */
167 sh.fdstatus = (unsigned char*)malloc((unsigned)n);
168 memset((char*)sh.fdstatus,0,n);
169 sh.fdptrs = (int**)malloc(n*sizeof(int*));
170 memset((char*)sh.fdptrs,0,n*sizeof(int*));
171 sh.sftable = (Sfio_t**)malloc(n*sizeof(Sfio_t*));
172 memset((char*)sh.sftable,0,n*sizeof(Sfio_t*));
173 sh.sftable[0] = sfstdin;
174 sh.sftable[1] = sfstdout;
175 sh.sftable[2] = sfstderr;
178 /* all write steams are in the same pool and share outbuff */
179 sh.outpool = sfopen(NIL(Sfio_t*),NIL(char*),"sw"); /* pool identifier */
180 sh.outbuff = (char*)malloc(IOBSIZE);
181 sh.errbuff = (char*)malloc(IOBSIZE/4);
182 sfsetbuf(sfstderr,sh.errbuff,IOBSIZE/4);
183 sfsetbuf(sfstdout,sh.outbuff,IOBSIZE);
184 sfpool(sfstdout,sh.outpool,SF_WRITE);
185 sfpool(sfstderr,sh.outpool,SF_WRITE);
186 sfset(sfstdout,SF_LINE,0);
190 * create or initialize a stream corresponding to descriptor <fd>
191 * a buffer with room for a sentinal is allocated for a read stream.
192 * A discipline is inserted when read stream is a tty or a pipe
193 * For output streams, the buffer is set to sh.output and put into
194 * the sh.outpool synchronization pool
196 Sfio_t *sh_iostream __PARAM__((register int fd), (fd)) __OTORP__(register int fd;){
197 register Sfio_t *iop;
198 register int status = sh_iocheckfd(fd);
199 register int flags = SF_WRITE;
202 #ifdef SHOPT_FASTPIPE
203 if(fd>=sh.lim.open_max)
204 return(sh.sftable[fd]);
205 #endif /* SHOPT_FASTPIPE */
217 return(NIL(Sfio_t*));
221 size=roundof(IOBSIZE+1,sizeof(__V_*)) + sizeof(Sfdisc_t);
222 if(!(bp = (char *)malloc(size)))
223 return(NIL(Sfio_t*));
225 if(!(status&IOWRITE))
231 flags |= SF_SHARE|SF_PUBLIC;
232 if((iop = sh.sftable[fd]) && sffileno(iop)>=0)
233 sfsetbuf(iop, bp, IOBSIZE);
234 else if(!(iop=sfnew((fd<=2?iop:0),bp,IOBSIZE,fd,flags)))
235 return(NIL(Sfio_t*));
239 sfset(iop,SF_MALLOC,1);
241 dp = (Sfdisc_t*)(bp+roundof(IOBSIZE+1,sizeof(__V_*)));
243 dp->readf = slowread;
244 else if(status&IONOSEEK)
245 dp->readf = piperead;
250 dp->exceptf = slowexcept;
255 sfpool(iop,sh.outpool,SF_WRITE);
256 sh.sftable[fd] = iop;
261 * preserve the file descriptor or stream by moving it
263 static void io_preserve __PARAM__((register Sfio_t *sp, register int f2), (sp, f2)) __OTORP__(register Sfio_t *sp; register int f2;){
268 fd = fcntl(f2,F_DUPFD,10);
272 error(ERROR_system(1),e_toomany);
273 if(sh.fdptrs[fd]=sh.fdptrs[f2])
281 sh.fdstatus[fd] = sh.fdstatus[f2];
282 if(fcntl(f2,F_GETFD,0)&1)
284 fcntl(fd,F_SETFD,FD_CLOEXEC);
285 sh.fdstatus[fd] |= IOCLEX;
291 * Given a file descriptor <f1>, move it to a file descriptor number <f2>
292 * If <f2> is needed move it, otherwise it is closed first.
293 * The original stream <f1> is closed.
294 * The new file descriptor <f2> is returned;
296 int sh_iorenumber __PARAM__((register int f1,register int f2), (f1, f2)) __OTORP__(register int f1;register int f2;){
297 register Sfio_t *sp = sh.sftable[f2];
300 /* see whether file descriptor is in use */
301 if(sh_inuse(f2) || (f2>2 && sp))
311 register Sfio_t *spnew = sh_iostream(f1);
312 sh.fdstatus[f2] = (sh.fdstatus[f1]&~IOCLEX);
315 sfset(sp,SF_SHARE|SF_PUBLIC,1);
319 sh.fdstatus[f2] = (sh.fdstatus[f1]&~IOCLEX);
320 if((f2 = fcntl(f1,F_DUPFD, f2)) < 0)
321 error(ERROR_system(1),e_file+4);
333 * close a file descriptor and update stream table and attributes
335 int sh_close __PARAM__((register int fd), (fd)) __OTORP__(register int fd;){
345 if(!(sp=sh.sftable[fd]) || sfclose(sp) < 0)
349 sh.fdstatus[fd] = IOCLOSE;
357 * Open a file for reading
358 * On failure, print message.
360 int sh_open __PARAM__((register const char *path, int flags, ...), (va_alist)) __OTORP__(va_dcl)
361 { __OTORP__(register const char *path; int flags; )
365 struct sockaddr_in addr;
368 __VA_START__(ap, flags); __OTORP__(path = va_arg(ap, const char *);flags = va_arg(ap, int );)
369 mode = (flags & O_CREAT) ? va_arg(ap, int) : 0;
377 if (strmatch(path,e_devfdNN))
380 if((mode=sh_iocheckfd(fd))==IOCLOSE)
382 flags &= (O_RDWR|O_WRONLY|O_RDONLY);
383 if(!(mode&IOWRITE) && ((flags==O_WRONLY) || (flags==O_RDWR)))
385 if(!(mode&IOREAD) && ((flags==O_RDONLY) || (flags==O_RDWR)))
391 if (strmatch(path, "/dev/@(tcp|udp)/*/*") && str2inet(path + 9, &addr))
393 if ((fd = socket(AF_INET, path[5] == 't' ? SOCK_STREAM : SOCK_DGRAM, 0)) >= 0 && connect(fd, (struct sockaddr*)&addr, sizeof(addr)))
401 if((fd = open(path, flags, mode)) < 0)
405 else if(flags&O_RDWR)
406 mode = (IOREAD|IOWRITE);
409 sh.fdstatus[fd] = mode;
413 int sh_chkopen __PARAM__((register const char *name), (name)) __OTORP__(register const char *name;){
414 register int fd = sh_open(name,O_RDONLY,0);
416 error(ERROR_system(1),e_open,name);
421 * move open file descriptor to a number > 2
423 int sh_iomovefd __PARAM__((register int fdold), (fdold)) __OTORP__(register int fdold;){
425 if(fdold<0 || fdold>2)
427 fdnew = sh_iomovefd(dup(fdold));
428 sh.fdstatus[fdnew] = (sh.fdstatus[fdold]&~IOCLEX);
430 sh.fdstatus[fdold] = IOCLOSE;
435 * create a pipe and print message on failure
437 int sh_pipe __PARAM__((register int pv[]), (pv)) __OTORP__(register int pv[];){
439 if(pipe(fd)<0 || (pv[0]=fd[0])<0 || (pv[1]=fd[1])<0)
440 error(ERROR_system(1),e_pipe);
441 pv[0] = sh_iomovefd(pv[0]);
442 pv[1] = sh_iomovefd(pv[1]);
443 sh.fdstatus[pv[0]] = IONOSEEK|IOREAD|IODUP;
444 sh.fdstatus[pv[1]] = IONOSEEK|IOWRITE;
451 void sh_pclose __PARAM__((register int pv[]), (pv)) __OTORP__(register int pv[];){
461 * flag = 0 if files are to be restored
462 * flag = 2 if files are to be closed on exec
463 * flag = 3 when called from $( < ...), just open file and return
465 int sh_redirect __PARAM__((struct ionod *iop, int flag), (iop, flag)) __OTORP__(struct ionod *iop; int flag;){
466 register char *fname;
467 register int fd, iof;
468 register Namval_t *np=0;
469 const char *message = e_open;
470 int o_mode; /* mode flag for open */
471 static char io_op[5]; /* used for -x trace info */
472 int clexec=0, fn, traceon;
477 traceon = sh_trace(NIL(char**),0);
478 for(;iop;iop=iop->ionxt)
483 io_op[0] = '0'+(iof&IOUFD);
487 o_mode = O_WRONLY|O_CREAT;
492 o_mode = O_RDONLY|O_NONBLOCK;
498 fname=sh_mactrim(fname,sh_isoption(SH_INTERACTIVE)?2:0);
507 sfputr(sfstderr,io_op,'\n');
509 fd = io_heredoc(iop);
514 int dupfd,toclose= -1;
516 if((fd=fname[0])>='0' && fd<='9')
518 char *number = fname;
519 dupfd = strtol(fname,&number,10);
525 if(*number || dupfd > IOUFD)
530 if(sh.subshell && dupfd==1)
533 dupfd = sffileno(sfstdout);
536 else if(fd=='-' && fname[1]==0)
541 else if(fd=='p' && fname[1]==0)
544 toclose = dupfd = sh.coutpipe;
546 toclose = dupfd = sh.cpipe[0];
553 if((fd=fcntl(dupfd,F_DUPFD,3))<0)
556 sh.fdstatus[fd] = (sh.fdstatus[dupfd]&~IOCLEX);
557 if(toclose<0 && sh.fdstatus[fd]&IOREAD)
558 sh.fdstatus[fd] |= IODUP;
559 else if(dupfd==sh.cpipe[0])
564 sh_iosave(toclose,indx); /* save file descriptor */
571 o_mode = O_RDWR|O_CREAT;
574 else if(!(iof&IOPUT))
575 fd=sh_chkopen(fname);
576 else if(sh_isoption(SH_RESTRICTED))
577 error(ERROR_exit(1),e_restricted,fname);
590 else if(sh_isoption(SH_NOCLOBBER))
593 if(stat(fname,&sb)>=0)
596 if(S_ISREG(sb.st_mode)&&
597 (!sh.lim.fs3d || iview(&sb)==0))
599 if(S_ISREG(sb.st_mode))
600 #endif /* SHOPT_FS_3D */
603 error(ERROR_system(1),e_exists,fname);
611 if((fd=sh_open(fname,o_mode,RW_ALL)) <0)
612 error(ERROR_system(1),((o_mode&O_CREAT)?e_create:e_open),fname);
616 sfprintf(sfstderr,"%s %s%c",io_op,fname,iop->ionxt?' ':'\n');
618 sh_iosave(fn,indx); /* save file descriptor */
621 if(sh_inuse(fn) || fn==sh.infd)
622 io_preserve(sh.sftable[fn],fn);
628 fd = sh_iorenumber(sh_iomovefd(fd),fn);
631 fcntl(fd,F_SETFD,FD_CLOEXEC);
632 sh.fdstatus[fd] |= IOCLEX;
638 error(ERROR_system(1),message,fname);
642 * Create a tmp file for the here-document
644 static int io_heredoc __PARAM__((register struct ionod *iop), (iop)) __OTORP__(register struct ionod *iop;){
645 register Sfio_t *infile = 0, *outfile;
647 /* create an unnamed temporary file */
648 if(!(outfile=sftmp(0)))
649 error(ERROR_system(1),e_tmpcreate);
650 if(!(iop->iofile&IOSTRG))
652 if(!sh.heredocs || iop->iosize==0)
653 return(sh_open(e_devnull,O_RDONLY));
654 infile = subopen(sh.heredocs,iop->iooffset,iop->iosize);
656 if(iop->iofile&IOQUOTE)
658 /* This is a quoted here-document, not expansion */
660 infile = sfopen(NIL(Sfio_t*),iop->ioname,"s");
661 sfmove(infile,outfile,SF_UNBOUND,-1);
666 if(sh_isoption(SH_XTRACE))
667 sfdisc(outfile,&tee_disc);
668 sh_machere(infile,outfile,iop->ioname);
672 /* close stream outfile, but save file descriptor */
673 fd = sffileno(outfile);
676 lseek(fd,(off_t)0,SEEK_SET);
677 sh.fdstatus[fd] = IOREAD;
682 * This write discipline also writes the output on standard error
683 * This is used when tracing here-documents
685 static int tee_write __PARAM__((Sfio_t *iop,const __V_ *buff,int n,Sfdisc_t *unused), (iop, buff, n, unused)) __OTORP__(Sfio_t *iop;const __V_ *buff;int n;Sfdisc_t *unused;){
687 sfwrite(sfstderr,buff,n);
688 return(write(sffileno(iop),buff,n));
692 * copy file <origfd> into a save place
693 * The saved file is set close-on-exec
694 * if <origfd> < 0, then -origfd is saved, but not duped so that it
695 * will be closed with sh_iorestore.
697 void sh_iosave __PARAM__((register int origfd, int oldtop), (origfd, oldtop)) __OTORP__(register int origfd; int oldtop;){
699 assume oldtop>=0 && oldtop<sh.lim.open_max;
703 /* see if already saved, only save once */
704 for(savefd=sh.topfd; --savefd>=oldtop; )
706 if(filemap[savefd].orig_fd == origfd)
709 /* make sure table is large enough */
710 if(sh.topfd >= filemapsize)
713 if(!(filemap = (struct fdsave*)realloc(filemap,filemapsize*sizeof(struct fdsave))))
714 error(ERROR_exit(4),e_nospace);
724 #endif /* SHOPT_DEVFD */
726 if((savefd = fcntl(origfd, F_DUPFD, 3)) < 0 && errno!=EBADF)
727 error(ERROR_system(1),e_toomany);
729 filemap[sh.topfd].orig_fd = origfd;
730 filemap[sh.topfd++].save_fd = savefd;
733 register Sfio_t* sp = sh.sftable[origfd];
734 /* make saved file close-on-exec */
735 fcntl(savefd,F_SETFD,FD_CLOEXEC);
738 sh.fdstatus[savefd] = sh.fdstatus[origfd];
739 sh.fdptrs[savefd] = &filemap[sh.topfd-1].save_fd;
740 if(!(sh.sftable[savefd]=sp))
745 /* copy standard stream to new stream */
746 sp = sfswap(sp,NIL(Sfio_t*));
747 sh.sftable[savefd] = sp;
750 sh.sftable[origfd] = 0;
755 * close all saved file descriptors
757 void sh_iounsave __PARAM__((void), ()){
758 register int fd, savefd, newfd;
759 for(newfd=fd=0; fd < sh.topfd; fd++)
761 if((savefd = filemap[fd].save_fd)< 0)
762 filemap[newfd++] = filemap[fd];
765 sh.sftable[savefd] = 0;
773 * restore saved file descriptors from <last> on
775 void sh_iorestore __PARAM__((int last), (last)) __OTORP__(int last;){
776 register int origfd, savefd, fd;
777 for (fd = sh.topfd - 1; fd >= last; fd--)
779 origfd = filemap[fd].orig_fd;
781 if ((savefd = filemap[fd].save_fd) >= 0)
783 fcntl(savefd, F_DUPFD, origfd);
786 sh.fdstatus[origfd] = sh.fdstatus[savefd];
787 /* turn off close-on-exec if flag if necessary */
788 if(sh.fdstatus[origfd]&IOCLEX)
789 fcntl(origfd,F_SETFD,FD_CLOEXEC);
792 sfswap(sh.sftable[savefd],sh.sftable[origfd]);
797 sh.sftable[origfd] = sh.sftable[savefd];
798 sh.sftable[savefd] = 0;
807 * returns access information on open file <fd>
808 * returns -1 for failure, 0 for success
809 * <mode> is the same as for access()
811 sh_ioaccess __PARAM__((int fd,register int mode), (fd, mode)) __OTORP__(int fd;register int mode;){
815 if((flags=sh_iocheckfd(fd))!=IOCLOSE)
819 if(mode==R_OK && (flags&IOREAD))
821 if(mode==W_OK && (flags&IOWRITE))
829 * convert string to sockaddr_in
830 * 0 returned on error
833 static int str2inet __PARAM__((register const char *sp, struct sockaddr_in *addr), (sp, addr)) __OTORP__(register const char *sp; struct sockaddr_in *addr;){
834 register int n=0,c,v;
841 while ((c = *sp++) >= '0' && c <= '9')
842 v = v * 10 + c - '0';
843 if (++n <= 4) a = (a << 8) | (v & 0xff);
850 if (c != '.' && c != '/') return(0);
852 memset((char*)addr, 0, sizeof(*addr));
853 addr->sin_family = AF_INET;
854 addr->sin_addr.s_addr = htonl(a);
855 addr->sin_port = htons(p);
862 * Handle interrupts for slow streams
864 static int slowexcept __PARAM__((register Sfio_t *iop, int type, Sfdisc_t *handle), (iop, type, handle)) __OTORP__(register Sfio_t *iop; int type; Sfdisc_t *handle;){
869 if((sh.trapnote&(SH_SIGSET|SH_SIGTRAP)) && errno!=EIO && errno!=ENXIO)
876 if(errno==0 && (n=fcntl(fno,F_GETFL,0))&O_NDELAY)
879 fcntl(fno, F_SETFL, n);
882 # endif /* O_NDELAY */
883 #endif /* !FNDELAY */
887 n = fcntl(fno,F_GETFL,0);
889 fcntl(fno, F_SETFL, n);
892 #endif /* O_NONBLOCK */
898 if(sh.trapnote&SH_SIGSET)
900 sfputc(sfstderr,'\n');
903 if(sh.trapnote&SH_SIGTRAP)
909 * called when slowread times out
911 static void time_grace __PARAM__((__V_ *handle), (handle)) __OTORP__(__V_ *handle;){
914 if(sh_isstate(SH_GRACE))
916 sh_offstate(SH_GRACE);
917 if(!sh_isstate(SH_INTERACTIVE))
919 ((struct checkpt*)sh.jmplist)->mode = SH_JMPEXIT;
921 sh.trapnote |= SH_SIGSET;
925 sh_onstate(SH_GRACE);
927 sh.trapnote |= SH_SIGTRAP;
930 static int piperead __PARAM__((Sfio_t *iop,__V_ *buff,register int size,Sfdisc_t *handle), (iop, buff, size, handle)) __OTORP__(Sfio_t *iop;__V_ *buff;register int size;Sfdisc_t *handle;){
932 size = ed_read(sffileno(iop), (char*)buff, size);
936 * This is the read discipline that is applied to slow devices
937 * This routine takes care of prompting for input
939 static int slowread __PARAM__((Sfio_t *iop,__V_ *buff,register int size,Sfdisc_t *handle), (iop, buff, size, handle)) __OTORP__(Sfio_t *iop;__V_ *buff;register int size;Sfdisc_t *handle;){
940 int (*readf) __PROTO__((int, char*, int));
942 if(io_prompt(sh.nextprompt)<0 && errno==EIO)
945 timeout = (__V_*)timeradd(sh_isstate(SH_GRACE)?1000L*TGRACE:1000L*sh.timeout,0,time_grace,NIL(__V_*));
947 if(sh_isoption(SH_EMACS|SH_GMACS))
948 readf = ed_emacsread;
950 # endif /* SHOPT_ESH */
952 if(sh_isoption(SH_VI))
955 # endif /* SHOPT_VSH */
957 size = (*readf)(sffileno(iop), (char*)buff, size);
965 * check and return the attributes for a file descriptor
968 int sh_iocheckfd __PARAM__((register int fd), (fd)) __OTORP__(register int fd;){
969 register int flags, n;
970 if((n=sh.fdstatus[fd])&IOCLOSE)
972 if(!(n&(IOREAD|IOWRITE)))
975 if((flags=fcntl(fd,F_GETFL,0)) < 0)
976 return(sh.fdstatus[fd]=IOCLOSE);
977 if(!(flags&O_WRONLY))
979 if(flags&(O_WRONLY|O_RDWR))
983 if((flags = fstat(fd,&statb))< 0)
984 return(sh.fdstatus[fd]=IOCLOSE);
985 n |= (IOREAD|IOWRITE);
986 if(read(fd,"",0) < 0)
990 if(!(n&(IOSEEK|IONOSEEK)))
993 /* /dev/null check is a workaround for select bug */
994 static ino_t null_ino;
995 static dev_t null_dev;
996 if(null_ino==0 && stat(e_devnull,&statb) >=0)
998 null_ino = statb.st_ino;
999 null_dev = statb.st_dev;
1003 if(lseek(fd,NIL(off_t),SEEK_CUR)<0)
1007 if((fstat(fd,&statb)>=0) && S_ISSOCK(statb.st_mode))
1008 n |= IOREAD|IOWRITE;
1009 #endif /* S_ISSOCK */
1011 else if((fstat(fd,&statb)>=0) && (
1012 S_ISFIFO(statb.st_mode) ||
1014 S_ISSOCK(statb.st_mode) ||
1015 #endif /* S_ISSOCK */
1016 /* The following is for sockets on the sgi */
1017 (statb.st_ino==0 && (statb.st_mode & ~(S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH|S_IXUSR|S_IXGRP|S_IXOTH|S_ISUID|S_ISGID))==0) ||
1018 (S_ISCHR(statb.st_mode) && (statb.st_ino!=null_ino || statb.st_dev!=null_dev))
1024 sh.fdstatus[fd] = n;
1029 * Display prompt PS<flag> on standard error
1032 static int io_prompt __PARAM__((register int flag), (flag)) __OTORP__(register int flag;){
1037 if(flag<3 && !sh_isstate(SH_INTERACTIVE))
1040 return(sfsync(sfstderr));
1041 sfflags = sfset(sfstderr,SF_SHARE|SF_PUBLIC|SF_READ,0);
1042 if(!(sh.prompt=(char*)sfreserve(sfstderr,0,0)))
1049 #if defined(TIOCLBIC) && defined(LFLUSHO)
1050 if(!sh_isoption(SH_VI|SH_EMACS|SH_GMACS))
1053 * re-enable output in case the user has
1054 * disabled it. Not needed with edit mode
1057 ioctl(sffileno(sfstderr),TIOCLBIC,&mode);
1059 #endif /* TIOCLBIC */
1060 cp = sh_mactry(nv_getval(nv_scoped(PS1NOD)));
1065 /* look at next character */
1067 /* print out line number if not !! */
1070 sfprintf(sfstderr,"%d", sh.hist_ptr?(int)sh.hist_ptr->histind:++cmdno);
1080 cp = nv_getval(nv_scoped(PS2NOD));
1083 cp = nv_getval(nv_scoped(PS3NOD));
1089 sfputr(sfstderr,cp,-1);
1091 if(*sh.prompt && (endprompt=(char*)sfreserve(sfstderr,0,0)))
1093 sfset(sfstderr,sfflags&SF_READ|SF_SHARE|SF_PUBLIC,1);
1094 return(sfsync(sfstderr));
1098 * This discipline is inserted on write pipes to prevent SIGPIPE
1099 * from causing an infinite loop
1101 static int pipeexcept __PARAM__((Sfio_t* iop, int mode, Sfdisc_t* handle), (iop, mode, handle)) __OTORP__(Sfio_t* iop; int mode; Sfdisc_t* handle;){
1103 if(mode==SF_WRITE && errno==EINTR && sh.lastsig==SIGPIPE)
1105 else if(mode==SF_DPOP || mode==SF_CLOSE)
1106 free((__V_*)handle);
1111 * keep track of each stream that is opened and closed
1113 static void sftrack __PARAM__((Sfio_t* sp,int flag, int newfd), (sp, flag, newfd)) __OTORP__(Sfio_t* sp;int flag; int newfd;){
1114 register int fd = sffileno(sp);
1115 register struct checkpt *pp;
1117 if(flag==SF_SETFD && newfd<0)
1122 if(flag==SF_READ || flag==SF_WRITE)
1124 char *z = fmtbase((long)getpid(),0,0);
1125 write(ERRIO,z,strlen(z));
1126 write(ERRIO,": ",2);
1127 write(ERRIO,"attempt to ",11);
1129 write(ERRIO,"read from",9);
1131 write(ERRIO,"write to",8);
1132 write(ERRIO," locked stream\n",15);
1136 if((unsigned)fd >= sh.lim.open_max)
1138 if(sh_isstate(SH_NOTRACK))
1140 mode = sfset(sp,0,0);
1141 if(flag==SF_NEW && (mode&SF_WRITE) && (sh_iocheckfd(fd)&IONOSEEK))
1143 Sfdisc_t *dp = newof(0,Sfdisc_t,1,0);
1144 dp->exceptf = pipeexcept;
1151 sh.sftable[fd] = sp;
1152 if(sh.fdstatus[fd]==IOCLOSE)
1154 flag = (mode&SF_WRITE)?IOWRITE:0;
1157 sh.fdstatus[fd] = flag;
1160 if((pp=(struct checkpt*)sh.jmplist) && pp->mode==SH_JMPCMD)
1162 struct openlist *item;
1164 * record open file descriptors so they can
1165 * be closed in case a longjmp prevents
1166 * built-ins from cleanup
1168 item = new_of(struct openlist, 0);
1170 item->next = pp->olist;
1174 else if(flag==SF_CLOSE)
1177 sh.fdstatus[fd]=IOCLOSE;
1178 if(pp=(struct checkpt*)sh.jmplist)
1180 struct openlist *item;
1181 for(item=pp->olist; item; item=item->next)
1183 if(item->strm == sp)
1202 * Create a stream consisting of a space separated argv[] list
1205 Sfio_t *sh_sfeval __PARAM__((register char *argv[]), (argv)) __OTORP__(register char *argv[];){
1206 register Sfio_t *iop;
1212 iop = sfopen(NIL(Sfio_t*),(char*)cp,"s");
1215 register struct eval *ep;
1216 if(!(ep = new_of(struct eval,0)))
1217 return(NIL(Sfio_t*));
1218 ep->disc = eval_disc;
1222 sfdisc(iop,&ep->disc);
1228 * This code gets called whenever an end of string is found with eval
1231 static int eval_exceptf __PARAM__((Sfio_t *iop,int type, Sfdisc_t *handle), (iop, type, handle)) __OTORP__(Sfio_t *iop;int type; Sfdisc_t *handle;){
1232 register struct eval *ep = (struct eval*)handle;
1237 if(type!=SF_READ || !(cp = ep->argv[0]))
1241 sfdisc(iop,SF_POPDISC);
1250 /* get the length of this string */
1251 ep->slen = len = strlen(cp);
1252 /* move to next string */
1255 else /* insert space between arguments */
1260 /* insert the new string */
1261 sfsetbuf(iop,cp,len);
1262 ep->addspace = !ep->addspace;
1267 * This routine returns a stream pointer to a segment of length <size> from
1268 * the stream <sp> starting at offset <offset>
1269 * The stream can be read with the normal stream operations
1272 static Sfio_t *subopen __PARAM__((Sfio_t* sp, off_t offset, long size), (sp, offset, size)) __OTORP__(Sfio_t* sp; off_t offset; long size;){
1273 register struct subfile *disp;
1274 register int fd = sffileno(sp);
1275 if(sfseek(sp,offset,SEEK_SET) <0)
1276 return(NIL(Sfio_t*));
1277 if(!(disp = (struct subfile*)malloc(sizeof(struct subfile)+IOBSIZE+1)))
1278 return(NIL(Sfio_t*));
1279 disp->disc = sub_disc;
1281 disp->offset = offset;
1282 disp->size = disp->left = size;
1283 sp = sfnew(NIL(Sfio_t*),(char*)(disp+1),IOBSIZE,sh.lim.open_max,SF_READ);
1284 sfdisc(sp,&disp->disc);
1289 * read function for subfile discipline
1291 static int subread __PARAM__((Sfio_t* sp,__V_* buff,register int size,Sfdisc_t* handle), (sp, buff, size, handle)) __OTORP__(Sfio_t* sp;__V_* buff;register int size;Sfdisc_t* handle;){
1292 register struct subfile *disp = (struct subfile*)handle;
1296 if(size > disp->left)
1299 return(sfread(disp->oldsp,buff,size));
1303 * exception handler for subfile discipline
1305 static int subexcept __PARAM__((Sfio_t* sp,register int mode, Sfdisc_t* handle), (sp, mode, handle)) __OTORP__(Sfio_t* sp;register int mode; Sfdisc_t* handle;){
1306 register struct subfile *disp = (struct subfile*)handle;
1309 sfdisc(sp,SF_POPDISC);
1310 free((__V_*)handle);
1312 else if(mode==SF_READ)
1317 #define NROW 15 /* number of rows before going to multi-columns */
1318 #define LBLSIZ 3 /* size of label field and interfield spacing */
1320 * print a list of arguments in columns
1322 void sh_menu __PARAM__((Sfio_t *outfile,int argn,char *argv[]), (outfile, argn, argv)) __OTORP__(Sfio_t *outfile;int argn;char *argv[];){
1324 register char **arg;
1325 int nrow, ncol=1, ndigits=1;
1326 int fldsize, wsize = ed_window();
1327 char *cp = nv_getval(nv_scoped(LINES));
1328 nrow = (cp?1+2*(atoi(cp)/3):NROW);
1329 for(i=argn;i >= 10;i /= 10)
1337 for(arg=argv; *arg;arg++)
1339 if((j=strlen(*arg)) > i)
1342 i += (ndigits+LBLSIZ);
1345 if(argn > nrow*ncol)
1347 nrow = 1 + (argn-1)/ncol;
1351 ncol = 1 + (argn-1)/nrow;
1352 nrow = 1 + (argn-1)/ncol;
1355 fldsize = (wsize/ncol)-(ndigits+LBLSIZ);
1358 if(sh.trapnote&SH_SIGSET)
1364 sfprintf(outfile,"%*d) %s",ndigits,j+1,*arg);
1368 sfnputc(outfile,' ',fldsize-strlen(*arg));
1370 sfputc(outfile,'\n');
1376 * shell version of read() for user added builtins
1378 ssize_t sh_read __PARAM__((register int fd, __V_* buff, size_t n), (fd, buff, n)) __OTORP__(register int fd; __V_* buff; size_t n;){
1379 register Sfio_t *sp;
1380 if(sp=sh.sftable[fd])
1381 return(sfread(sp,buff,n));
1383 return(read(fd,buff,n));
1388 * shell version of write() for user added builtins
1390 ssize_t sh_write __PARAM__((register int fd, const __V_* buff, size_t n), (fd, buff, n)) __OTORP__(register int fd; const __V_* buff; size_t n;){
1391 register Sfio_t *sp;
1392 if(sp=sh.sftable[fd])
1393 return(sfwrite(sp,buff,n));
1395 return(write(fd,buff,n));
1400 * shell version of lseek() for user added builtins
1402 off_t sh_seek __PARAM__((register int fd, off_t offset, int whence), (fd, offset, whence)) __OTORP__(register int fd; off_t offset; int whence;){
1403 register Sfio_t *sp;
1404 if(sp=sh.sftable[fd])
1405 return(sfseek(sp,offset,whence));
1407 return(lseek(fd,offset,whence));
1411 int sh_dup __PARAM__((register int old), (old)) __OTORP__(register int old;){
1412 register int fd = dup(old);
1414 sh.fdstatus[fd] = (sh.fdstatus[old]&~IOCLEX);