2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these libraries and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: io.c /main/3 1995/11/01 16:48:07 rswiston $ */
24 /***************************************************************
26 * AT&T - PROPRIETARY *
28 * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF *
29 * AT&T BELL LABORATORIES *
30 * AND IS NOT TO BE DISCLOSED OR USED EXCEPT IN *
31 * ACCORDANCE WITH APPLICABLE AGREEMENTS *
33 * Copyright (c) 1995 AT&T Corp. *
34 * Unpublished & Not for Publication *
35 * All Rights Reserved *
37 * The copyright notice above does not evidence any *
38 * actual or intended publication of such source code *
40 * This software was created by the *
41 * Advanced Software Technology Department *
42 * AT&T Bell Laboratories *
44 * For further information contact *
45 * {research,attmail}!dgk *
47 ***************************************************************/
49 /* : : generated by proto : : */
51 #if !defined(__PROTO__)
52 #if defined(__STDC__) || defined(__cplusplus) || defined(_proto) || defined(c_plusplus)
53 #if defined(__cplusplus)
54 #define __MANGLE__ "C"
59 #define __PROTO__(x) x
61 #define __PARAM__(n,o) n
62 #if !defined(__STDC__) && !defined(__cplusplus)
63 #if !defined(c_plusplus)
74 #define __PROTO__(x) ()
75 #define __OTORP__(x) x
76 #define __PARAM__(n,o) o
84 #if defined(__cplusplus) || defined(c_plusplus)
85 #define __VARARG__ ...
89 #if defined(__STDARG__)
90 #define __VA_START__(p,a) va_start(p,a)
92 #define __VA_START__(p,a) va_start(p)
98 #if !defined(va_start)
99 #if defined(__STDARG__)
106 #include "variables.h"
113 #include "FEATURE/externs"
114 #include "FEATURE/dynamic"
115 #include "FEATURE/poll"
119 # if EAGAIN!=EWOULDBLOCK
121 # define EAGAIN EWOULDBLOCK
124 # define EAGAIN EWOULDBLOCK
127 # define O_NONBLOCK FNDELAY
128 # endif /* !O_NONBLOCK */
130 #define RW_ALL (S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH)
132 static __V_ *timeout;
134 #if defined(_lib_socket) && defined(_sys_socket) && defined(_hdr_netinet_in)
135 # include <sys/socket.h>
136 # include <netinet/in.h>
137 static int str2inet __PROTO__((const char*, struct sockaddr_in*));
145 int orig_fd; /* original file descriptor */
146 int save_fd; /* saved file descriptor */
150 static int eval_exceptf __PROTO__((Sfio_t*, int, Sfdisc_t*));
151 static int piperead __PROTO__((Sfio_t*, __V_*, int, Sfdisc_t*));
152 static int slowread __PROTO__((Sfio_t*, __V_*, int, Sfdisc_t*));
153 static int slowexcept __PROTO__((Sfio_t*, int, Sfdisc_t*));
154 static int pipeexcept __PROTO__((Sfio_t*, int, Sfdisc_t*));
155 static int io_prompt __PROTO__((int));
156 static int io_heredoc __PROTO__((register struct ionod*));
157 static void sftrack __PROTO__((Sfio_t*,int,int));
158 static int tee_write __PROTO__((Sfio_t*,const __V_*,int,Sfdisc_t*));
159 static const Sfdisc_t eval_disc = { NULL, NULL, NULL, eval_exceptf, NULL};
160 static Sfdisc_t tee_disc = {NULL,tee_write,NULL,NULL,NULL};
161 static Sfio_t *subopen __PROTO__((Sfio_t*, off_t, long));
162 static int subread __PROTO__((Sfio_t*, __V_*, int, Sfdisc_t*));
163 static int subexcept __PROTO__((Sfio_t*, int, Sfdisc_t*));
164 static const Sfdisc_t sub_disc = { subread, 0, 0, subexcept, 0 };
175 static struct fdsave *filemap;
176 static short filemapsize;
178 /* ======== input output and file copying ======== */
180 void sh_ioinit __PARAM__((void), ()){
183 filemap = (struct fdsave*)malloc(8*sizeof(struct fdsave));
184 #ifdef SHOPT_FASTPIPE
185 n = sh.lim.open_max+2;
188 #endif /* SHOPT_FASTPIPE */
189 sh.fdstatus = (unsigned char*)malloc((unsigned)n);
190 memset((char*)sh.fdstatus,0,n);
191 sh.fdptrs = (int**)malloc(n*sizeof(int*));
192 memset((char*)sh.fdptrs,0,n*sizeof(int*));
193 sh.sftable = (Sfio_t**)malloc(n*sizeof(Sfio_t*));
194 memset((char*)sh.sftable,0,n*sizeof(Sfio_t*));
195 sh.sftable[0] = sfstdin;
196 sh.sftable[1] = sfstdout;
197 sh.sftable[2] = sfstderr;
200 /* all write steams are in the same pool and share outbuff */
201 sh.outpool = sfopen(NIL(Sfio_t*),NIL(char*),"sw"); /* pool identifier */
202 sh.outbuff = (char*)malloc(IOBSIZE);
203 sh.errbuff = (char*)malloc(IOBSIZE/4);
204 sfsetbuf(sfstderr,sh.errbuff,IOBSIZE/4);
205 sfsetbuf(sfstdout,sh.outbuff,IOBSIZE);
206 sfpool(sfstdout,sh.outpool,SF_WRITE);
207 sfpool(sfstderr,sh.outpool,SF_WRITE);
208 sfset(sfstdout,SF_LINE,0);
212 * create or initialize a stream corresponding to descriptor <fd>
213 * a buffer with room for a sentinal is allocated for a read stream.
214 * A discipline is inserted when read stream is a tty or a pipe
215 * For output streams, the buffer is set to sh.output and put into
216 * the sh.outpool synchronization pool
218 Sfio_t *sh_iostream __PARAM__((register int fd), (fd)) __OTORP__(register int fd;){
219 register Sfio_t *iop;
220 register int status = sh_iocheckfd(fd);
221 register int flags = SF_WRITE;
224 #ifdef SHOPT_FASTPIPE
225 if(fd>=sh.lim.open_max)
226 return(sh.sftable[fd]);
227 #endif /* SHOPT_FASTPIPE */
239 return(NIL(Sfio_t*));
243 size=roundof(IOBSIZE+1,sizeof(__V_*)) + sizeof(Sfdisc_t);
244 if(!(bp = (char *)malloc(size)))
245 return(NIL(Sfio_t*));
247 if(!(status&IOWRITE))
253 flags |= SF_SHARE|SF_PUBLIC;
254 if((iop = sh.sftable[fd]) && sffileno(iop)>=0)
255 sfsetbuf(iop, bp, IOBSIZE);
256 else if(!(iop=sfnew((fd<=2?iop:0),bp,IOBSIZE,fd,flags)))
257 return(NIL(Sfio_t*));
261 sfset(iop,SF_MALLOC,1);
263 dp = (Sfdisc_t*)(bp+roundof(IOBSIZE+1,sizeof(__V_*)));
265 dp->readf = slowread;
266 else if(status&IONOSEEK)
267 dp->readf = piperead;
272 dp->exceptf = slowexcept;
277 sfpool(iop,sh.outpool,SF_WRITE);
278 sh.sftable[fd] = iop;
283 * preserve the file descriptor or stream by moving it
285 static void io_preserve __PARAM__((register Sfio_t *sp, register int f2), (sp, f2)) __OTORP__(register Sfio_t *sp; register int f2;){
290 fd = fcntl(f2,F_DUPFD,10);
294 error(ERROR_system(1),e_toomany);
295 if(sh.fdptrs[fd]=sh.fdptrs[f2])
303 sh.fdstatus[fd] = sh.fdstatus[f2];
304 if(fcntl(f2,F_GETFD,0)&1)
306 fcntl(fd,F_SETFD,FD_CLOEXEC);
307 sh.fdstatus[fd] |= IOCLEX;
313 * Given a file descriptor <f1>, move it to a file descriptor number <f2>
314 * If <f2> is needed move it, otherwise it is closed first.
315 * The original stream <f1> is closed.
316 * The new file descriptor <f2> is returned;
318 int sh_iorenumber __PARAM__((register int f1,register int f2), (f1, f2)) __OTORP__(register int f1;register int f2;){
319 register Sfio_t *sp = sh.sftable[f2];
322 /* see whether file descriptor is in use */
323 if(sh_inuse(f2) || (f2>2 && sp))
333 register Sfio_t *spnew = sh_iostream(f1);
334 sh.fdstatus[f2] = (sh.fdstatus[f1]&~IOCLEX);
337 sfset(sp,SF_SHARE|SF_PUBLIC,1);
341 sh.fdstatus[f2] = (sh.fdstatus[f1]&~IOCLEX);
342 if((f2 = fcntl(f1,F_DUPFD, f2)) < 0)
343 error(ERROR_system(1),e_file+4);
355 * close a file descriptor and update stream table and attributes
357 int sh_close __PARAM__((register int fd), (fd)) __OTORP__(register int fd;){
367 if(!(sp=sh.sftable[fd]) || sfclose(sp) < 0)
371 sh.fdstatus[fd] = IOCLOSE;
379 * Open a file for reading
380 * On failure, print message.
382 int sh_open __PARAM__((register const char *path, int flags, ...), (va_alist)) __OTORP__(va_dcl)
383 { __OTORP__(register const char *path; int flags; )
387 struct sockaddr_in addr;
390 __VA_START__(ap, flags); __OTORP__(path = va_arg(ap, const char *);flags = va_arg(ap, int );)
391 mode = (flags & O_CREAT) ? va_arg(ap, int) : 0;
399 if (strmatch(path,e_devfdNN))
402 if((mode=sh_iocheckfd(fd))==IOCLOSE)
404 flags &= (O_RDWR|O_WRONLY|O_RDONLY);
405 if(!(mode&IOWRITE) && ((flags==O_WRONLY) || (flags==O_RDWR)))
407 if(!(mode&IOREAD) && ((flags==O_RDONLY) || (flags==O_RDWR)))
413 if (strmatch(path, "/dev/@(tcp|udp)/*/*") && str2inet(path + 9, &addr))
415 if ((fd = socket(AF_INET, path[5] == 't' ? SOCK_STREAM : SOCK_DGRAM, 0)) >= 0 && connect(fd, (struct sockaddr*)&addr, sizeof(addr)))
423 if((fd = open(path, flags, mode)) < 0)
427 else if(flags&O_RDWR)
428 mode = (IOREAD|IOWRITE);
431 sh.fdstatus[fd] = mode;
435 int sh_chkopen __PARAM__((register const char *name), (name)) __OTORP__(register const char *name;){
436 register int fd = sh_open(name,O_RDONLY,0);
438 error(ERROR_system(1),e_open,name);
443 * move open file descriptor to a number > 2
445 int sh_iomovefd __PARAM__((register int fdold), (fdold)) __OTORP__(register int fdold;){
447 if(fdold<0 || fdold>2)
449 fdnew = sh_iomovefd(dup(fdold));
450 sh.fdstatus[fdnew] = (sh.fdstatus[fdold]&~IOCLEX);
452 sh.fdstatus[fdold] = IOCLOSE;
457 * create a pipe and print message on failure
459 int sh_pipe __PARAM__((register int pv[]), (pv)) __OTORP__(register int pv[];){
461 if(pipe(fd)<0 || (pv[0]=fd[0])<0 || (pv[1]=fd[1])<0)
462 error(ERROR_system(1),e_pipe);
463 pv[0] = sh_iomovefd(pv[0]);
464 pv[1] = sh_iomovefd(pv[1]);
465 sh.fdstatus[pv[0]] = IONOSEEK|IOREAD|IODUP;
466 sh.fdstatus[pv[1]] = IONOSEEK|IOWRITE;
473 void sh_pclose __PARAM__((register int pv[]), (pv)) __OTORP__(register int pv[];){
483 * flag = 0 if files are to be restored
484 * flag = 2 if files are to be closed on exec
485 * flag = 3 when called from $( < ...), just open file and return
487 int sh_redirect __PARAM__((struct ionod *iop, int flag), (iop, flag)) __OTORP__(struct ionod *iop; int flag;){
488 register char *fname;
489 register int fd, iof;
490 register Namval_t *np=0;
491 const char *message = e_open;
492 int o_mode; /* mode flag for open */
493 static char io_op[5]; /* used for -x trace info */
494 int clexec=0, fn, traceon;
499 traceon = sh_trace(NIL(char**),0);
500 for(;iop;iop=iop->ionxt)
505 io_op[0] = '0'+(iof&IOUFD);
509 o_mode = O_WRONLY|O_CREAT;
514 o_mode = O_RDONLY|O_NONBLOCK;
520 fname=sh_mactrim(fname,sh_isoption(SH_INTERACTIVE)?2:0);
529 sfputr(sfstderr,io_op,'\n');
531 fd = io_heredoc(iop);
536 int dupfd,toclose= -1;
538 if((fd=fname[0])>='0' && fd<='9')
540 char *number = fname;
541 dupfd = strtol(fname,&number,10);
547 if(*number || dupfd > IOUFD)
552 if(sh.subshell && dupfd==1)
555 dupfd = sffileno(sfstdout);
558 else if(fd=='-' && fname[1]==0)
563 else if(fd=='p' && fname[1]==0)
566 toclose = dupfd = sh.coutpipe;
568 toclose = dupfd = sh.cpipe[0];
575 if((fd=fcntl(dupfd,F_DUPFD,3))<0)
578 sh.fdstatus[fd] = (sh.fdstatus[dupfd]&~IOCLEX);
579 if(toclose<0 && sh.fdstatus[fd]&IOREAD)
580 sh.fdstatus[fd] |= IODUP;
581 else if(dupfd==sh.cpipe[0])
586 sh_iosave(toclose,indx); /* save file descriptor */
593 o_mode = O_RDWR|O_CREAT;
596 else if(!(iof&IOPUT))
597 fd=sh_chkopen(fname);
598 else if(sh_isoption(SH_RESTRICTED))
599 error(ERROR_exit(1),e_restricted,fname);
612 else if(sh_isoption(SH_NOCLOBBER))
615 if(stat(fname,&sb)>=0)
618 if(S_ISREG(sb.st_mode)&&
619 (!sh.lim.fs3d || iview(&sb)==0))
621 if(S_ISREG(sb.st_mode))
622 #endif /* SHOPT_FS_3D */
625 error(ERROR_system(1),e_exists,fname);
633 if((fd=sh_open(fname,o_mode,RW_ALL)) <0)
634 error(ERROR_system(1),((o_mode&O_CREAT)?e_create:e_open),fname);
638 sfprintf(sfstderr,"%s %s%c",io_op,fname,iop->ionxt?' ':'\n');
640 sh_iosave(fn,indx); /* save file descriptor */
643 if(sh_inuse(fn) || fn==sh.infd)
644 io_preserve(sh.sftable[fn],fn);
650 fd = sh_iorenumber(sh_iomovefd(fd),fn);
653 fcntl(fd,F_SETFD,FD_CLOEXEC);
654 sh.fdstatus[fd] |= IOCLEX;
660 error(ERROR_system(1),message,fname);
664 * Create a tmp file for the here-document
666 static int io_heredoc __PARAM__((register struct ionod *iop), (iop)) __OTORP__(register struct ionod *iop;){
667 register Sfio_t *infile = 0, *outfile;
669 /* create an unnamed temporary file */
670 if(!(outfile=sftmp(0)))
671 error(ERROR_system(1),e_tmpcreate);
672 if(!(iop->iofile&IOSTRG))
674 if(!sh.heredocs || iop->iosize==0)
675 return(sh_open(e_devnull,O_RDONLY));
676 infile = subopen(sh.heredocs,iop->iooffset,iop->iosize);
678 if(iop->iofile&IOQUOTE)
680 /* This is a quoted here-document, not expansion */
682 infile = sfopen(NIL(Sfio_t*),iop->ioname,"s");
683 sfmove(infile,outfile,SF_UNBOUND,-1);
688 if(sh_isoption(SH_XTRACE))
689 sfdisc(outfile,&tee_disc);
690 sh_machere(infile,outfile,iop->ioname);
694 /* close stream outfile, but save file descriptor */
695 fd = sffileno(outfile);
698 lseek(fd,(off_t)0,SEEK_SET);
699 sh.fdstatus[fd] = IOREAD;
704 * This write discipline also writes the output on standard error
705 * This is used when tracing here-documents
707 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;){
709 sfwrite(sfstderr,buff,n);
710 return(write(sffileno(iop),buff,n));
714 * copy file <origfd> into a save place
715 * The saved file is set close-on-exec
716 * if <origfd> < 0, then -origfd is saved, but not duped so that it
717 * will be closed with sh_iorestore.
719 void sh_iosave __PARAM__((register int origfd, int oldtop), (origfd, oldtop)) __OTORP__(register int origfd; int oldtop;){
721 assume oldtop>=0 && oldtop<sh.lim.open_max;
725 /* see if already saved, only save once */
726 for(savefd=sh.topfd; --savefd>=oldtop; )
728 if(filemap[savefd].orig_fd == origfd)
731 /* make sure table is large enough */
732 if(sh.topfd >= filemapsize)
735 if(!(filemap = (struct fdsave*)realloc(filemap,filemapsize*sizeof(struct fdsave))))
736 error(ERROR_exit(4),e_nospace);
746 #endif /* SHOPT_DEVFD */
748 if((savefd = fcntl(origfd, F_DUPFD, 3)) < 0 && errno!=EBADF)
749 error(ERROR_system(1),e_toomany);
751 filemap[sh.topfd].orig_fd = origfd;
752 filemap[sh.topfd++].save_fd = savefd;
755 register Sfio_t* sp = sh.sftable[origfd];
756 /* make saved file close-on-exec */
757 fcntl(savefd,F_SETFD,FD_CLOEXEC);
760 sh.fdstatus[savefd] = sh.fdstatus[origfd];
761 sh.fdptrs[savefd] = &filemap[sh.topfd-1].save_fd;
762 if(!(sh.sftable[savefd]=sp))
767 /* copy standard stream to new stream */
768 sp = sfswap(sp,NIL(Sfio_t*));
769 sh.sftable[savefd] = sp;
772 sh.sftable[origfd] = 0;
777 * close all saved file descriptors
779 void sh_iounsave __PARAM__((void), ()){
780 register int fd, savefd, newfd;
781 for(newfd=fd=0; fd < sh.topfd; fd++)
783 if((savefd = filemap[fd].save_fd)< 0)
784 filemap[newfd++] = filemap[fd];
787 sh.sftable[savefd] = 0;
795 * restore saved file descriptors from <last> on
797 void sh_iorestore __PARAM__((int last), (last)) __OTORP__(int last;){
798 register int origfd, savefd, fd;
799 for (fd = sh.topfd - 1; fd >= last; fd--)
801 origfd = filemap[fd].orig_fd;
803 if ((savefd = filemap[fd].save_fd) >= 0)
805 fcntl(savefd, F_DUPFD, origfd);
808 sh.fdstatus[origfd] = sh.fdstatus[savefd];
809 /* turn off close-on-exec if flag if necessary */
810 if(sh.fdstatus[origfd]&IOCLEX)
811 fcntl(origfd,F_SETFD,FD_CLOEXEC);
814 sfswap(sh.sftable[savefd],sh.sftable[origfd]);
819 sh.sftable[origfd] = sh.sftable[savefd];
820 sh.sftable[savefd] = 0;
829 * returns access information on open file <fd>
830 * returns -1 for failure, 0 for success
831 * <mode> is the same as for access()
833 sh_ioaccess __PARAM__((int fd,register int mode), (fd, mode)) __OTORP__(int fd;register int mode;){
837 if((flags=sh_iocheckfd(fd))!=IOCLOSE)
841 if(mode==R_OK && (flags&IOREAD))
843 if(mode==W_OK && (flags&IOWRITE))
851 * convert string to sockaddr_in
852 * 0 returned on error
855 static int str2inet __PARAM__((register const char *sp, struct sockaddr_in *addr), (sp, addr)) __OTORP__(register const char *sp; struct sockaddr_in *addr;){
856 register int n=0,c,v;
863 while ((c = *sp++) >= '0' && c <= '9')
864 v = v * 10 + c - '0';
865 if (++n <= 4) a = (a << 8) | (v & 0xff);
872 if (c != '.' && c != '/') return(0);
874 memset((char*)addr, 0, sizeof(*addr));
875 addr->sin_family = AF_INET;
876 addr->sin_addr.s_addr = htonl(a);
877 addr->sin_port = htons(p);
884 * Handle interrupts for slow streams
886 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;){
891 if((sh.trapnote&(SH_SIGSET|SH_SIGTRAP)) && errno!=EIO && errno!=ENXIO)
898 if(errno==0 && (n=fcntl(fno,F_GETFL,0))&O_NDELAY)
901 fcntl(fno, F_SETFL, n);
904 # endif /* O_NDELAY */
905 #endif /* !FNDELAY */
909 n = fcntl(fno,F_GETFL,0);
911 fcntl(fno, F_SETFL, n);
914 #endif /* O_NONBLOCK */
920 if(sh.trapnote&SH_SIGSET)
922 sfputc(sfstderr,'\n');
925 if(sh.trapnote&SH_SIGTRAP)
931 * called when slowread times out
933 static void time_grace __PARAM__((__V_ *handle), (handle)) __OTORP__(__V_ *handle;){
936 if(sh_isstate(SH_GRACE))
938 sh_offstate(SH_GRACE);
939 if(!sh_isstate(SH_INTERACTIVE))
941 ((struct checkpt*)sh.jmplist)->mode = SH_JMPEXIT;
943 sh.trapnote |= SH_SIGSET;
947 sh_onstate(SH_GRACE);
949 sh.trapnote |= SH_SIGTRAP;
952 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;){
954 size = ed_read(sffileno(iop), (char*)buff, size);
958 * This is the read discipline that is applied to slow devices
959 * This routine takes care of prompting for input
961 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;){
962 int (*readf) __PROTO__((int, char*, int));
964 if(io_prompt(sh.nextprompt)<0 && errno==EIO)
967 timeout = (__V_*)kshtimeradd(sh_isstate(SH_GRACE)?1000L*TGRACE:1000L*sh.timeout,0,time_grace,NIL(__V_*));
969 if(sh_isoption(SH_EMACS|SH_GMACS))
970 readf = ed_emacsread;
972 # endif /* SHOPT_ESH */
974 if(sh_isoption(SH_VI))
977 # endif /* SHOPT_VSH */
979 size = (*readf)(sffileno(iop), (char*)buff, size);
987 * check and return the attributes for a file descriptor
990 int sh_iocheckfd __PARAM__((register int fd), (fd)) __OTORP__(register int fd;){
991 register int flags, n;
992 if((n=sh.fdstatus[fd])&IOCLOSE)
994 if(!(n&(IOREAD|IOWRITE)))
997 if((flags=fcntl(fd,F_GETFL,0)) < 0)
998 return(sh.fdstatus[fd]=IOCLOSE);
999 if(!(flags&O_WRONLY))
1001 if(flags&(O_WRONLY|O_RDWR))
1005 if((flags = fstat(fd,&statb))< 0)
1006 return(sh.fdstatus[fd]=IOCLOSE);
1007 n |= (IOREAD|IOWRITE);
1008 if(read(fd,"",0) < 0)
1010 #endif /* F_GETFL */
1012 if(!(n&(IOSEEK|IONOSEEK)))
1015 /* /dev/null check is a workaround for select bug */
1016 static ino_t null_ino;
1017 static dev_t null_dev;
1018 if(null_ino==0 && stat(e_devnull,&statb) >=0)
1020 null_ino = statb.st_ino;
1021 null_dev = statb.st_dev;
1025 if(lseek(fd,NIL(off_t),SEEK_CUR)<0)
1029 if((fstat(fd,&statb)>=0) && S_ISSOCK(statb.st_mode))
1030 n |= IOREAD|IOWRITE;
1031 #endif /* S_ISSOCK */
1033 else if((fstat(fd,&statb)>=0) && (
1034 S_ISFIFO(statb.st_mode) ||
1036 S_ISSOCK(statb.st_mode) ||
1037 #endif /* S_ISSOCK */
1038 /* The following is for sockets on the sgi */
1039 (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) ||
1040 (S_ISCHR(statb.st_mode) && (statb.st_ino!=null_ino || statb.st_dev!=null_dev))
1046 sh.fdstatus[fd] = n;
1051 * Display prompt PS<flag> on standard error
1054 static int io_prompt __PARAM__((register int flag), (flag)) __OTORP__(register int flag;){
1059 if(flag<3 && !sh_isstate(SH_INTERACTIVE))
1062 return(sfsync(sfstderr));
1063 sfflags = sfset(sfstderr,SF_SHARE|SF_PUBLIC|SF_READ,0);
1064 if(!(sh.prompt=(char*)sfreserve(sfstderr,0,0)))
1071 #if defined(TIOCLBIC) && defined(LFLUSHO)
1072 if(!sh_isoption(SH_VI|SH_EMACS|SH_GMACS))
1075 * re-enable output in case the user has
1076 * disabled it. Not needed with edit mode
1079 ioctl(sffileno(sfstderr),TIOCLBIC,&mode);
1081 #endif /* TIOCLBIC */
1082 cp = sh_mactry(nv_getval(nv_scoped(PS1NOD)));
1087 /* look at next character */
1089 /* print out line number if not !! */
1092 sfprintf(sfstderr,"%d", sh.hist_ptr?(int)sh.hist_ptr->histind:++cmdno);
1102 cp = nv_getval(nv_scoped(PS2NOD));
1105 cp = nv_getval(nv_scoped(PS3NOD));
1111 sfputr(sfstderr,cp,-1);
1113 if(*sh.prompt && (endprompt=(char*)sfreserve(sfstderr,0,0)))
1115 sfset(sfstderr,sfflags&SF_READ|SF_SHARE|SF_PUBLIC,1);
1116 return(sfsync(sfstderr));
1120 * This discipline is inserted on write pipes to prevent SIGPIPE
1121 * from causing an infinite loop
1123 static int pipeexcept __PARAM__((Sfio_t* iop, int mode, Sfdisc_t* handle), (iop, mode, handle)) __OTORP__(Sfio_t* iop; int mode; Sfdisc_t* handle;){
1125 if(mode==SF_WRITE && errno==EINTR && sh.lastsig==SIGPIPE)
1127 else if(mode==SF_DPOP || mode==SF_CLOSE)
1128 free((__V_*)handle);
1133 * keep track of each stream that is opened and closed
1135 static void sftrack __PARAM__((Sfio_t* sp,int flag, int newfd), (sp, flag, newfd)) __OTORP__(Sfio_t* sp;int flag; int newfd;){
1136 register int fd = sffileno(sp);
1137 register struct checkpt *pp;
1139 if(flag==SF_SETFD && newfd<0)
1144 if(flag==SF_READ || flag==SF_WRITE)
1146 char *z = fmtbase((long)getpid(),0,0);
1147 write(ERRIO,z,strlen(z));
1148 write(ERRIO,": ",2);
1149 write(ERRIO,"attempt to ",11);
1151 write(ERRIO,"read from",9);
1153 write(ERRIO,"write to",8);
1154 write(ERRIO," locked stream\n",15);
1158 if((unsigned)fd >= sh.lim.open_max)
1160 if(sh_isstate(SH_NOTRACK))
1162 mode = sfset(sp,0,0);
1163 if(flag==SF_NEW && (mode&SF_WRITE) && (sh_iocheckfd(fd)&IONOSEEK))
1165 Sfdisc_t *dp = newof(0,Sfdisc_t,1,0);
1166 dp->exceptf = pipeexcept;
1173 sh.sftable[fd] = sp;
1174 if(sh.fdstatus[fd]==IOCLOSE)
1176 flag = (mode&SF_WRITE)?IOWRITE:0;
1179 sh.fdstatus[fd] = flag;
1182 if((pp=(struct checkpt*)sh.jmplist) && pp->mode==SH_JMPCMD)
1184 struct openlist *item;
1186 * record open file descriptors so they can
1187 * be closed in case a longjmp prevents
1188 * built-ins from cleanup
1190 item = new_of(struct openlist, 0);
1192 item->next = pp->olist;
1196 else if(flag==SF_CLOSE)
1199 sh.fdstatus[fd]=IOCLOSE;
1200 if(pp=(struct checkpt*)sh.jmplist)
1202 struct openlist *item;
1203 for(item=pp->olist; item; item=item->next)
1205 if(item->strm == sp)
1224 * Create a stream consisting of a space separated argv[] list
1227 Sfio_t *sh_sfeval __PARAM__((register char *argv[]), (argv)) __OTORP__(register char *argv[];){
1228 register Sfio_t *iop;
1234 iop = sfopen(NIL(Sfio_t*),(char*)cp,"s");
1237 register struct eval *ep;
1238 if(!(ep = new_of(struct eval,0)))
1239 return(NIL(Sfio_t*));
1240 ep->disc = eval_disc;
1244 sfdisc(iop,&ep->disc);
1250 * This code gets called whenever an end of string is found with eval
1253 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;){
1254 register struct eval *ep = (struct eval*)handle;
1259 if(type!=SF_READ || !(cp = ep->argv[0]))
1263 sfdisc(iop,SF_POPDISC);
1272 /* get the length of this string */
1273 ep->slen = len = strlen(cp);
1274 /* move to next string */
1277 else /* insert space between arguments */
1282 /* insert the new string */
1283 sfsetbuf(iop,cp,len);
1284 ep->addspace = !ep->addspace;
1289 * This routine returns a stream pointer to a segment of length <size> from
1290 * the stream <sp> starting at offset <offset>
1291 * The stream can be read with the normal stream operations
1294 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;){
1295 register struct subfile *disp;
1296 register int fd = sffileno(sp);
1297 if(sfseek(sp,offset,SEEK_SET) <0)
1298 return(NIL(Sfio_t*));
1299 if(!(disp = (struct subfile*)malloc(sizeof(struct subfile)+IOBSIZE+1)))
1300 return(NIL(Sfio_t*));
1301 disp->disc = sub_disc;
1303 disp->offset = offset;
1304 disp->size = disp->left = size;
1305 sp = sfnew(NIL(Sfio_t*),(char*)(disp+1),IOBSIZE,sh.lim.open_max,SF_READ);
1306 sfdisc(sp,&disp->disc);
1311 * read function for subfile discipline
1313 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;){
1314 register struct subfile *disp = (struct subfile*)handle;
1318 if(size > disp->left)
1321 return(sfread(disp->oldsp,buff,size));
1325 * exception handler for subfile discipline
1327 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;){
1328 register struct subfile *disp = (struct subfile*)handle;
1331 sfdisc(sp,SF_POPDISC);
1332 free((__V_*)handle);
1334 else if(mode==SF_READ)
1339 #define NROW 15 /* number of rows before going to multi-columns */
1340 #define LBLSIZ 3 /* size of label field and interfield spacing */
1342 * print a list of arguments in columns
1344 void sh_menu __PARAM__((Sfio_t *outfile,int argn,char *argv[]), (outfile, argn, argv)) __OTORP__(Sfio_t *outfile;int argn;char *argv[];){
1346 register char **arg;
1347 int nrow, ncol=1, ndigits=1;
1348 int fldsize, wsize = ed_window();
1349 char *cp = nv_getval(nv_scoped(LINES));
1350 nrow = (cp?1+2*(atoi(cp)/3):NROW);
1351 for(i=argn;i >= 10;i /= 10)
1359 for(arg=argv; *arg;arg++)
1361 if((j=strlen(*arg)) > i)
1364 i += (ndigits+LBLSIZ);
1367 if(argn > nrow*ncol)
1369 nrow = 1 + (argn-1)/ncol;
1373 ncol = 1 + (argn-1)/nrow;
1374 nrow = 1 + (argn-1)/ncol;
1377 fldsize = (wsize/ncol)-(ndigits+LBLSIZ);
1380 if(sh.trapnote&SH_SIGSET)
1386 sfprintf(outfile,"%*d) %s",ndigits,j+1,*arg);
1390 sfnputc(outfile,' ',fldsize-strlen(*arg));
1392 sfputc(outfile,'\n');
1398 * shell version of read() for user added builtins
1400 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;){
1401 register Sfio_t *sp;
1402 if(sp=sh.sftable[fd])
1403 return(sfread(sp,buff,n));
1405 return(read(fd,buff,n));
1410 * shell version of write() for user added builtins
1412 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;){
1413 register Sfio_t *sp;
1414 if(sp=sh.sftable[fd])
1415 return(sfwrite(sp,buff,n));
1417 return(write(fd,buff,n));
1422 * shell version of lseek() for user added builtins
1424 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;){
1425 register Sfio_t *sp;
1426 if(sp=sh.sftable[fd])
1427 return(sfseek(sp,offset,whence));
1429 return(lseek(fd,offset,whence));
1433 int sh_dup __PARAM__((register int old), (old)) __OTORP__(register int old;){
1434 register int fd = dup(old);
1436 sh.fdstatus[fd] = (sh.fdstatus[old]&~IOCLEX);