ea9a71f347494209c0d613e45e92ade28cd4c2dc
[p5sagit/p5-mst-13.2.git] / doio.c
1 /* $Header: doio.c,v 3.0.1.6 90/03/12 16:30:07 lwall Locked $
2  *
3  *    Copyright (c) 1989, Larry Wall
4  *
5  *    You may distribute under the terms of the GNU General Public License
6  *    as specified in the README file that comes with the perl 3.0 kit.
7  *
8  * $Log:        doio.c,v $
9  * Revision 3.0.1.6  90/03/12  16:30:07  lwall
10  * patch13: system 'FOO=bar command' didn't invoke sh as it should
11  * 
12  * Revision 3.0.1.5  90/02/28  17:01:36  lwall
13  * patch9: open(FOO,"$filename\0") will now protect trailing spaces in filename
14  * patch9: removed obsolete checks to avoid opening block devices
15  * patch9: removed references to acusec and modusec that some utime.h's have
16  * patch9: added pipe function
17  * 
18  * Revision 3.0.1.4  89/12/21  19:55:10  lwall
19  * patch7: select now works on big-endian machines
20  * patch7: errno may now be a macro with an lvalue
21  * patch7: ANSI strerror() is now supported
22  * patch7: Configure now detects DG/UX thingies like [sg]etpgrp2 and utime.h
23  * 
24  * Revision 3.0.1.3  89/11/17  15:13:06  lwall
25  * patch5: some systems have symlink() but not lstat()
26  * patch5: some systems have dirent.h but not readdir()
27  * 
28  * Revision 3.0.1.2  89/11/11  04:25:51  lwall
29  * patch2: orthogonalized the file modes some so we can have <& +<& etc.
30  * patch2: do_open() now detects sockets passed to process from parent
31  * patch2: fd's above 2 are now closed on exec
32  * patch2: csh code can now use csh from other than /bin
33  * patch2: getsockopt, get{sock,peer}name didn't define result properly
34  * patch2: warn("shutdown") was replicated
35  * patch2: gethostbyname was misdeclared
36  * patch2: telldir() is sometimes a macro
37  * 
38  * Revision 3.0.1.1  89/10/26  23:10:05  lwall
39  * patch1: Configure now checks for BSD shadow passwords
40  * 
41  * Revision 3.0  89/10/18  15:10:54  lwall
42  * 3.0 baseline
43  * 
44  */
45
46 #include "EXTERN.h"
47 #include "perl.h"
48
49 #ifdef SOCKET
50 #include <sys/socket.h>
51 #include <netdb.h>
52 #endif
53
54 #ifdef I_PWD
55 #include <pwd.h>
56 #endif
57 #ifdef I_GRP
58 #include <grp.h>
59 #endif
60 #ifdef I_UTIME
61 #include <utime.h>
62 #endif
63
64 bool
65 do_open(stab,name,len)
66 STAB *stab;
67 register char *name;
68 int len;
69 {
70     FILE *fp;
71     register STIO *stio = stab_io(stab);
72     char *myname = savestr(name);
73     int result;
74     int fd;
75     int writing = 0;
76     char mode[3];               /* stdio file mode ("r\0" or "r+\0") */
77
78     name = myname;
79     forkprocess = 1;            /* assume true if no fork */
80     while (len && isspace(name[len-1]))
81         name[--len] = '\0';
82     if (!stio)
83         stio = stab_io(stab) = stio_new();
84     else if (stio->ifp) {
85         fd = fileno(stio->ifp);
86         if (stio->type == '|')
87             result = mypclose(stio->ifp);
88         else if (stio->ifp != stio->ofp) {
89             if (stio->ofp)
90                 fclose(stio->ofp);
91             result = fclose(stio->ifp);
92         }
93         else if (stio->type != '-')
94             result = fclose(stio->ifp);
95         else
96             result = 0;
97         if (result == EOF && fd > 2)
98             fprintf(stderr,"Warning: unable to close filehandle %s properly.\n",
99               stab_name(stab));
100         stio->ofp = stio->ifp = Nullfp;
101     }
102     if (*name == '+' && len > 1 && name[len-1] != '|') {        /* scary */
103         mode[1] = *name++;
104         mode[2] = '\0';
105         --len;
106         writing = 1;
107     }
108     else  {
109         mode[1] = '\0';
110     }
111     stio->type = *name;
112     if (*name == '|') {
113         for (name++; isspace(*name); name++) ;
114 #ifdef TAINT
115         taintenv();
116         taintproper("Insecure dependency in piped open");
117 #endif
118         fp = mypopen(name,"w");
119         writing = 1;
120     }
121     else if (*name == '>') {
122 #ifdef TAINT
123         taintproper("Insecure dependency in open");
124 #endif
125         name++;
126         if (*name == '>') {
127             mode[0] = stio->type = 'a';
128             name++;
129         }
130         else
131             mode[0] = 'w';
132         writing = 1;
133         if (*name == '&') {
134           duplicity:
135             name++;
136             while (isspace(*name))
137                 name++;
138             if (isdigit(*name))
139                 fd = atoi(name);
140             else {
141                 stab = stabent(name,FALSE);
142                 if (!stab || !stab_io(stab))
143                     return FALSE;
144                 if (stab_io(stab) && stab_io(stab)->ifp) {
145                     fd = fileno(stab_io(stab)->ifp);
146                     if (stab_io(stab)->type == 's')
147                         stio->type = 's';
148                 }
149                 else
150                     fd = -1;
151             }
152             fp = fdopen(dup(fd),mode);
153         }
154         else {
155             while (isspace(*name))
156                 name++;
157             if (strEQ(name,"-")) {
158                 fp = stdout;
159                 stio->type = '-';
160             }
161             else  {
162                 fp = fopen(name,mode);
163             }
164         }
165     }
166     else {
167         if (*name == '<') {
168             mode[0] = 'r';
169             name++;
170             while (isspace(*name))
171                 name++;
172             if (*name == '&')
173                 goto duplicity;
174             if (strEQ(name,"-")) {
175                 fp = stdin;
176                 stio->type = '-';
177             }
178             else
179                 fp = fopen(name,mode);
180         }
181         else if (name[len-1] == '|') {
182 #ifdef TAINT
183             taintenv();
184             taintproper("Insecure dependency in piped open");
185 #endif
186             name[--len] = '\0';
187             while (len && isspace(name[len-1]))
188                 name[--len] = '\0';
189             for (; isspace(*name); name++) ;
190             fp = mypopen(name,"r");
191             stio->type = '|';
192         }
193         else {
194             stio->type = '<';
195             for (; isspace(*name); name++) ;
196             if (strEQ(name,"-")) {
197                 fp = stdin;
198                 stio->type = '-';
199             }
200             else
201                 fp = fopen(name,"r");
202         }
203     }
204     Safefree(myname);
205     if (!fp)
206         return FALSE;
207     if (stio->type &&
208       stio->type != '|' && stio->type != '-') {
209         if (fstat(fileno(fp),&statbuf) < 0) {
210             (void)fclose(fp);
211             return FALSE;
212         }
213         result = (statbuf.st_mode & S_IFMT);
214 #ifdef S_IFSOCK
215         if (result == S_IFSOCK || result == 0)
216             stio->type = 's';   /* in case a socket was passed in to us */
217 #endif
218     }
219 #if defined(FCNTL) && defined(F_SETFD)
220     fd = fileno(fp);
221     if (fd >= 3)
222         fcntl(fd,F_SETFD,1);
223 #endif
224     stio->ifp = fp;
225     if (writing) {
226         if (stio->type != 's')
227             stio->ofp = fp;
228         else
229             stio->ofp = fdopen(fileno(fp),"w");
230     }
231     return TRUE;
232 }
233
234 FILE *
235 nextargv(stab)
236 register STAB *stab;
237 {
238     register STR *str;
239     char *oldname;
240     int filemode,fileuid,filegid;
241
242     while (alen(stab_xarray(stab)) >= 0) {
243         str = ashift(stab_xarray(stab));
244         str_sset(stab_val(stab),str);
245         STABSET(stab_val(stab));
246         oldname = str_get(stab_val(stab));
247         if (do_open(stab,oldname,stab_val(stab)->str_cur)) {
248             if (inplace) {
249 #ifdef TAINT
250                 taintproper("Insecure dependency in inplace open");
251 #endif
252                 filemode = statbuf.st_mode;
253                 fileuid = statbuf.st_uid;
254                 filegid = statbuf.st_gid;
255                 if (*inplace) {
256                     str_cat(str,inplace);
257 #ifdef RENAME
258                     (void)rename(oldname,str->str_ptr);
259 #else
260                     (void)UNLINK(str->str_ptr);
261                     (void)link(oldname,str->str_ptr);
262                     (void)UNLINK(oldname);
263 #endif
264                 }
265                 else {
266                     (void)UNLINK(oldname);
267                 }
268
269                 str_nset(str,">",1);
270                 str_cat(str,oldname);
271                 errno = 0;              /* in case sprintf set errno */
272                 if (!do_open(argvoutstab,str->str_ptr,str->str_cur))
273                     fatal("Can't do inplace edit");
274                 defoutstab = argvoutstab;
275 #ifdef FCHMOD
276                 (void)fchmod(fileno(stab_io(argvoutstab)->ifp),filemode);
277 #else
278                 (void)chmod(oldname,filemode);
279 #endif
280 #ifdef FCHOWN
281                 (void)fchown(fileno(stab_io(argvoutstab)->ifp),fileuid,filegid);
282 #else
283                 (void)chown(oldname,fileuid,filegid);
284 #endif
285             }
286             str_free(str);
287             return stab_io(stab)->ifp;
288         }
289         else
290             fprintf(stderr,"Can't open %s\n",str_get(str));
291         str_free(str);
292     }
293     if (inplace) {
294         (void)do_close(argvoutstab,FALSE);
295         defoutstab = stabent("STDOUT",TRUE);
296     }
297     return Nullfp;
298 }
299
300 void
301 do_pipe(str, rstab, wstab)
302 STR *str;
303 STAB *rstab;
304 STAB *wstab;
305 {
306     register STIO *rstio;
307     register STIO *wstio;
308     int fd[2];
309
310     if (!rstab)
311         goto badexit;
312     if (!wstab)
313         goto badexit;
314
315     rstio = stab_io(rstab);
316     wstio = stab_io(wstab);
317
318     if (!rstio)
319         rstio = stab_io(rstab) = stio_new();
320     else if (rstio->ifp)
321         do_close(rstab,FALSE);
322     if (!wstio)
323         wstio = stab_io(wstab) = stio_new();
324     else if (wstio->ifp)
325         do_close(wstab,FALSE);
326
327     if (pipe(fd) < 0)
328         goto badexit;
329     rstio->ifp = fdopen(fd[0], "r");
330     wstio->ofp = fdopen(fd[1], "w");
331     wstio->ifp = wstio->ofp;
332     rstio->type = '<';
333     wstio->type = '>';
334
335     str_sset(str,&str_yes);
336     return;
337
338 badexit:
339     str_sset(str,&str_undef);
340     return;
341 }
342
343 bool
344 do_close(stab,explicit)
345 STAB *stab;
346 bool explicit;
347 {
348     bool retval = FALSE;
349     register STIO *stio = stab_io(stab);
350     int status;
351
352     if (!stio) {                /* never opened */
353         if (dowarn && explicit)
354             warn("Close on unopened file <%s>",stab_name(stab));
355         return FALSE;
356     }
357     if (stio->ifp) {
358         if (stio->type == '|') {
359             status = mypclose(stio->ifp);
360             retval = (status >= 0);
361             statusvalue = (unsigned)status & 0xffff;
362         }
363         else if (stio->type == '-')
364             retval = TRUE;
365         else {
366             if (stio->ofp && stio->ofp != stio->ifp)            /* a socket */
367                 fclose(stio->ofp);
368             retval = (fclose(stio->ifp) != EOF);
369         }
370         stio->ofp = stio->ifp = Nullfp;
371     }
372     if (explicit)
373         stio->lines = 0;
374     stio->type = ' ';
375     return retval;
376 }
377
378 bool
379 do_eof(stab)
380 STAB *stab;
381 {
382     register STIO *stio;
383     int ch;
384
385     if (!stab) {                        /* eof() */
386         if (argvstab)
387             stio = stab_io(argvstab);
388         else
389             return TRUE;
390     }
391     else
392         stio = stab_io(stab);
393
394     if (!stio)
395         return TRUE;
396
397     while (stio->ifp) {
398
399 #ifdef STDSTDIO                 /* (the code works without this) */
400         if (stio->ifp->_cnt > 0)        /* cheat a little, since */
401             return FALSE;               /* this is the most usual case */
402 #endif
403
404         ch = getc(stio->ifp);
405         if (ch != EOF) {
406             (void)ungetc(ch, stio->ifp);
407             return FALSE;
408         }
409         if (!stab) {                    /* not necessarily a real EOF yet? */
410             if (!nextargv(argvstab))    /* get another fp handy */
411                 return TRUE;
412         }
413         else
414             return TRUE;                /* normal fp, definitely end of file */
415     }
416     return TRUE;
417 }
418
419 long
420 do_tell(stab)
421 STAB *stab;
422 {
423     register STIO *stio;
424
425     if (!stab)
426         goto phooey;
427
428     stio = stab_io(stab);
429     if (!stio || !stio->ifp)
430         goto phooey;
431
432     if (feof(stio->ifp))
433         (void)fseek (stio->ifp, 0L, 2);         /* ultrix 1.2 workaround */
434
435     return ftell(stio->ifp);
436
437 phooey:
438     if (dowarn)
439         warn("tell() on unopened file");
440     return -1L;
441 }
442
443 bool
444 do_seek(stab, pos, whence)
445 STAB *stab;
446 long pos;
447 int whence;
448 {
449     register STIO *stio;
450
451     if (!stab)
452         goto nuts;
453
454     stio = stab_io(stab);
455     if (!stio || !stio->ifp)
456         goto nuts;
457
458     if (feof(stio->ifp))
459         (void)fseek (stio->ifp, 0L, 2);         /* ultrix 1.2 workaround */
460
461     return fseek(stio->ifp, pos, whence) >= 0;
462
463 nuts:
464     if (dowarn)
465         warn("seek() on unopened file");
466     return FALSE;
467 }
468
469 int
470 do_ctl(optype,stab,func,argstr)
471 int optype;
472 STAB *stab;
473 int func;
474 STR *argstr;
475 {
476     register STIO *stio;
477     register char *s;
478     int retval;
479
480     if (!stab || !argstr)
481         return -1;
482     stio = stab_io(stab);
483     if (!stio)
484         return -1;
485
486     if (argstr->str_pok || !argstr->str_nok) {
487         if (!argstr->str_pok)
488             s = str_get(argstr);
489
490 #ifdef IOCPARM_MASK
491 #ifndef IOCPARM_LEN
492 #define IOCPARM_LEN(x)  (((x) >> 16) & IOCPARM_MASK)
493 #endif
494 #endif
495 #ifdef IOCPARM_LEN
496         retval = IOCPARM_LEN(func);     /* on BSDish systes we're safe */
497 #else
498         retval = 256;                   /* otherwise guess at what's safe */
499 #endif
500         if (argstr->str_cur < retval) {
501             str_grow(argstr,retval+1);
502             argstr->str_cur = retval;
503         }
504
505         s = argstr->str_ptr;
506         s[argstr->str_cur] = 17;        /* a little sanity check here */
507     }
508     else {
509         retval = (int)str_gnum(argstr);
510         s = (char*)retval;              /* ouch */
511     }
512
513 #ifndef lint
514     if (optype == O_IOCTL)
515         retval = ioctl(fileno(stio->ifp), func, s);
516     else
517 #ifdef I_FCNTL
518         retval = fcntl(fileno(stio->ifp), func, s);
519 #else
520         fatal("fcntl is not implemented");
521 #endif
522 #else /* lint */
523     retval = 0;
524 #endif /* lint */
525
526     if (argstr->str_pok) {
527         if (s[argstr->str_cur] != 17)
528             fatal("Return value overflowed string");
529         s[argstr->str_cur] = 0;         /* put our null back */
530     }
531     return retval;
532 }
533
534 int
535 do_stat(str,arg,gimme,arglast)
536 STR *str;
537 register ARG *arg;
538 int gimme;
539 int *arglast;
540 {
541     register ARRAY *ary = stack;
542     register int sp = arglast[0] + 1;
543     int max = 13;
544     register int i;
545
546     if ((arg[1].arg_type & A_MASK) == A_WORD) {
547         tmpstab = arg[1].arg_ptr.arg_stab;
548         if (tmpstab != defstab) {
549             statstab = tmpstab;
550             str_set(statname,"");
551             if (!stab_io(tmpstab) ||
552               fstat(fileno(stab_io(tmpstab)->ifp),&statcache) < 0) {
553                 max = 0;
554             }
555         }
556     }
557     else {
558         str_sset(statname,ary->ary_array[sp]);
559         statstab = Nullstab;
560 #ifdef LSTAT
561         if (arg->arg_type == O_LSTAT)
562             i = lstat(str_get(statname),&statcache);
563         else
564 #endif
565             i = stat(str_get(statname),&statcache);
566         if (i < 0)
567             max = 0;
568     }
569
570     if (gimme != G_ARRAY) {
571         if (max)
572             str_sset(str,&str_yes);
573         else
574             str_sset(str,&str_undef);
575         STABSET(str);
576         ary->ary_array[sp] = str;
577         return sp;
578     }
579     sp--;
580     if (max) {
581 #ifndef lint
582         (void)astore(ary,++sp,
583           str_2static(str_nmake((double)statcache.st_dev)));
584         (void)astore(ary,++sp,
585           str_2static(str_nmake((double)statcache.st_ino)));
586         (void)astore(ary,++sp,
587           str_2static(str_nmake((double)statcache.st_mode)));
588         (void)astore(ary,++sp,
589           str_2static(str_nmake((double)statcache.st_nlink)));
590         (void)astore(ary,++sp,
591           str_2static(str_nmake((double)statcache.st_uid)));
592         (void)astore(ary,++sp,
593           str_2static(str_nmake((double)statcache.st_gid)));
594         (void)astore(ary,++sp,
595           str_2static(str_nmake((double)statcache.st_rdev)));
596         (void)astore(ary,++sp,
597           str_2static(str_nmake((double)statcache.st_size)));
598         (void)astore(ary,++sp,
599           str_2static(str_nmake((double)statcache.st_atime)));
600         (void)astore(ary,++sp,
601           str_2static(str_nmake((double)statcache.st_mtime)));
602         (void)astore(ary,++sp,
603           str_2static(str_nmake((double)statcache.st_ctime)));
604 #ifdef STATBLOCKS
605         (void)astore(ary,++sp,
606           str_2static(str_nmake((double)statcache.st_blksize)));
607         (void)astore(ary,++sp,
608           str_2static(str_nmake((double)statcache.st_blocks)));
609 #else
610         (void)astore(ary,++sp,
611           str_2static(str_make("",0)));
612         (void)astore(ary,++sp,
613           str_2static(str_make("",0)));
614 #endif
615 #else /* lint */
616         (void)astore(ary,++sp,str_nmake(0.0));
617 #endif /* lint */
618     }
619     return sp;
620 }
621
622 int
623 looks_like_number(str)
624 STR *str;
625 {
626     register char *s;
627     register char *send;
628
629     if (!str->str_pok)
630         return TRUE;
631     s = str->str_ptr; 
632     send = s + str->str_cur;
633     while (isspace(*s))
634         s++;
635     if (s >= send)
636         return FALSE;
637     if (*s == '+' || *s == '-')
638         s++;
639     while (isdigit(*s))
640         s++;
641     if (s == send)
642         return TRUE;
643     if (*s == '.') 
644         s++;
645     else if (s == str->str_ptr)
646         return FALSE;
647     while (isdigit(*s))
648         s++;
649     if (s == send)
650         return TRUE;
651     if (*s == 'e' || *s == 'E') {
652         s++;
653         if (*s == '+' || *s == '-')
654             s++;
655         while (isdigit(*s))
656             s++;
657     }
658     while (isspace(*s))
659         s++;
660     if (s >= send)
661         return TRUE;
662     return FALSE;
663 }
664
665 bool
666 do_print(str,fp)
667 register STR *str;
668 FILE *fp;
669 {
670     register char *tmps;
671
672     if (!fp) {
673         if (dowarn)
674             warn("print to unopened file");
675         return FALSE;
676     }
677     if (!str)
678         return FALSE;
679     if (ofmt &&
680       ((str->str_nok && str->str_u.str_nval != 0.0)
681        || (looks_like_number(str) && str_gnum(str) != 0.0) ) )
682         fprintf(fp, ofmt, str->str_u.str_nval);
683     else {
684         tmps = str_get(str);
685         if (*tmps == 'S' && tmps[1] == 't' && tmps[2] == 'a' && tmps[3] == 'b'
686           && str->str_cur == sizeof(STBP) && strlen(tmps) < str->str_cur) {
687             tmps = stab_name(((STAB*)str));     /* a stab value, be nice */
688             str = ((STAB*)str)->str_magic;
689             putc('*',fp);
690         }
691         if (str->str_cur && fwrite(tmps,1,str->str_cur,fp) == 0)
692             return FALSE;
693     }
694     return TRUE;
695 }
696
697 bool
698 do_aprint(arg,fp,arglast)
699 register ARG *arg;
700 register FILE *fp;
701 int *arglast;
702 {
703     register STR **st = stack->ary_array;
704     register int sp = arglast[1];
705     register int retval;
706     register int items = arglast[2] - sp;
707
708     if (!fp) {
709         if (dowarn)
710             warn("print to unopened file");
711         return FALSE;
712     }
713     st += ++sp;
714     if (arg->arg_type == O_PRTF) {
715         do_sprintf(arg->arg_ptr.arg_str,items,st);
716         retval = do_print(arg->arg_ptr.arg_str,fp);
717     }
718     else {
719         retval = (items <= 0);
720         for (; items > 0; items--,st++) {
721             if (retval && ofslen) {
722                 if (fwrite(ofs, 1, ofslen, fp) == 0) {
723                     retval = FALSE;
724                     break;
725                 }
726             }
727             if (!(retval = do_print(*st, fp)))
728                 break;
729         }
730         if (retval && orslen)
731             if (fwrite(ors, 1, orslen, fp) == 0)
732                 retval = FALSE;
733     }
734     return retval;
735 }
736
737 int
738 mystat(arg,str)
739 ARG *arg;
740 STR *str;
741 {
742     STIO *stio;
743
744     if (arg[1].arg_type & A_DONT) {
745         stio = stab_io(arg[1].arg_ptr.arg_stab);
746         if (stio && stio->ifp) {
747             statstab = arg[1].arg_ptr.arg_stab;
748             str_set(statname,"");
749             return fstat(fileno(stio->ifp), &statcache);
750         }
751         else {
752             if (arg[1].arg_ptr.arg_stab == defstab)
753                 return 0;
754             if (dowarn)
755                 warn("Stat on unopened file <%s>",
756                   stab_name(arg[1].arg_ptr.arg_stab));
757             statstab = Nullstab;
758             str_set(statname,"");
759             return -1;
760         }
761     }
762     else {
763         statstab = Nullstab;
764         str_sset(statname,str);
765         return stat(str_get(str),&statcache);
766     }
767 }
768
769 STR *
770 do_fttext(arg,str)
771 register ARG *arg;
772 STR *str;
773 {
774     int i;
775     int len;
776     int odd = 0;
777     STDCHAR tbuf[512];
778     register STDCHAR *s;
779     register STIO *stio;
780
781     if (arg[1].arg_type & A_DONT) {
782         if (arg[1].arg_ptr.arg_stab == defstab) {
783             if (statstab)
784                 stio = stab_io(statstab);
785             else {
786                 str = statname;
787                 goto really_filename;
788             }
789         }
790         else {
791             statstab = arg[1].arg_ptr.arg_stab;
792             str_set(statname,"");
793             stio = stab_io(statstab);
794         }
795         if (stio && stio->ifp) {
796 #ifdef STDSTDIO
797             fstat(fileno(stio->ifp),&statcache);
798             if (stio->ifp->_cnt <= 0) {
799                 i = getc(stio->ifp);
800                 if (i != EOF)
801                     (void)ungetc(i,stio->ifp);
802             }
803             if (stio->ifp->_cnt <= 0)   /* null file is anything */
804                 return &str_yes;
805             len = stio->ifp->_cnt + (stio->ifp->_ptr - stio->ifp->_base);
806             s = stio->ifp->_base;
807 #else
808             fatal("-T and -B not implemented on filehandles\n");
809 #endif
810         }
811         else {
812             if (dowarn)
813                 warn("Test on unopened file <%s>",
814                   stab_name(arg[1].arg_ptr.arg_stab));
815             return &str_undef;
816         }
817     }
818     else {
819         statstab = Nullstab;
820         str_sset(statname,str);
821       really_filename:
822         i = open(str_get(str),0);
823         if (i < 0)
824             return &str_undef;
825         fstat(i,&statcache);
826         len = read(i,tbuf,512);
827         if (len <= 0)           /* null file is anything */
828             return &str_yes;
829         (void)close(i);
830         s = tbuf;
831     }
832
833     /* now scan s to look for textiness */
834
835     for (i = 0; i < len; i++,s++) {
836         if (!*s) {                      /* null never allowed in text */
837             odd += len;
838             break;
839         }
840         else if (*s & 128)
841             odd++;
842         else if (*s < 32 &&
843           *s != '\n' && *s != '\r' && *s != '\b' &&
844           *s != '\t' && *s != '\f' && *s != 27)
845             odd++;
846     }
847
848     if ((odd * 10 > len) == (arg->arg_type == O_FTTEXT)) /* allow 10% odd */
849         return &str_no;
850     else
851         return &str_yes;
852 }
853
854 bool
855 do_aexec(really,arglast)
856 STR *really;
857 int *arglast;
858 {
859     register STR **st = stack->ary_array;
860     register int sp = arglast[1];
861     register int items = arglast[2] - sp;
862     register char **a;
863     char **argv;
864     char *tmps;
865
866     if (items) {
867         New(401,argv, items+1, char*);
868         a = argv;
869         for (st += ++sp; items > 0; items--,st++) {
870             if (*st)
871                 *a++ = str_get(*st);
872             else
873                 *a++ = "";
874         }
875         *a = Nullch;
876 #ifdef TAINT
877         if (*argv[0] != '/')    /* will execvp use PATH? */
878             taintenv();         /* testing IFS here is overkill, probably */
879 #endif
880         if (really && *(tmps = str_get(really)))
881             execvp(tmps,argv);
882         else
883             execvp(argv[0],argv);
884         Safefree(argv);
885     }
886     return FALSE;
887 }
888
889 bool
890 do_exec(cmd)
891 char *cmd;
892 {
893     register char **a;
894     register char *s;
895     char **argv;
896     char flags[10];
897
898 #ifdef TAINT
899     taintenv();
900     taintproper("Insecure dependency in exec");
901 #endif
902
903     /* save an extra exec if possible */
904
905 #ifdef CSH
906     if (strnEQ(cmd,cshname,cshlen) && strnEQ(cmd+cshlen," -c",3)) {
907         strcpy(flags,"-c");
908         s = cmd+cshlen+3;
909         if (*s == 'f') {
910             s++;
911             strcat(flags,"f");
912         }
913         if (*s == ' ')
914             s++;
915         if (*s++ == '\'') {
916             char *ncmd = s;
917
918             while (*s)
919                 s++;
920             if (s[-1] == '\n')
921                 *--s = '\0';
922             if (s[-1] == '\'') {
923                 *--s = '\0';
924                 execl(cshname,"csh", flags,ncmd,(char*)0);
925                 *s = '\'';
926                 return FALSE;
927             }
928         }
929     }
930 #endif /* CSH */
931
932     /* see if there are shell metacharacters in it */
933
934     for (s = cmd; *s; s++) {
935         if (*s != ' ' && !isalpha(*s) && index("$&*(){}[]'\";\\|?<>~`\n",*s)) {
936             if (*s == '\n' && !s[1]) {
937                 *s = '\0';
938                 break;
939             }
940           doshell:
941             execl("/bin/sh","sh","-c",cmd,(char*)0);
942             return FALSE;
943         }
944     }
945     for (s = cmd; *s && isalpha(*s); s++) ;     /* catch VAR=val gizmo */
946     if (*s == '=')
947         goto doshell;
948     New(402,argv, (s - cmd) / 2 + 2, char*);
949
950     a = argv;
951     for (s = cmd; *s;) {
952         while (*s && isspace(*s)) s++;
953         if (*s)
954             *(a++) = s;
955         while (*s && !isspace(*s)) s++;
956         if (*s)
957             *s++ = '\0';
958     }
959     *a = Nullch;
960     if (argv[0]) {
961         execvp(argv[0],argv);
962         if (errno == ENOEXEC)           /* for system V NIH syndrome */
963             goto doshell;
964     }
965     Safefree(argv);
966     return FALSE;
967 }
968
969 #ifdef SOCKET
970 int
971 do_socket(stab, arglast)
972 STAB *stab;
973 int *arglast;
974 {
975     register STR **st = stack->ary_array;
976     register int sp = arglast[1];
977     register STIO *stio;
978     int domain, type, protocol, fd;
979
980     if (!stab)
981         return FALSE;
982
983     stio = stab_io(stab);
984     if (!stio)
985         stio = stab_io(stab) = stio_new();
986     else if (stio->ifp)
987         do_close(stab,FALSE);
988
989     domain = (int)str_gnum(st[++sp]);
990     type = (int)str_gnum(st[++sp]);
991     protocol = (int)str_gnum(st[++sp]);
992 #ifdef TAINT
993     taintproper("Insecure dependency in socket");
994 #endif
995     fd = socket(domain,type,protocol);
996     if (fd < 0)
997         return FALSE;
998     stio->ifp = fdopen(fd, "r");        /* stdio gets confused about sockets */
999     stio->ofp = fdopen(fd, "w");
1000     stio->type = 's';
1001
1002     return TRUE;
1003 }
1004
1005 int
1006 do_bind(stab, arglast)
1007 STAB *stab;
1008 int *arglast;
1009 {
1010     register STR **st = stack->ary_array;
1011     register int sp = arglast[1];
1012     register STIO *stio;
1013     char *addr;
1014
1015     if (!stab)
1016         goto nuts;
1017
1018     stio = stab_io(stab);
1019     if (!stio || !stio->ifp)
1020         goto nuts;
1021
1022     addr = str_get(st[++sp]);
1023 #ifdef TAINT
1024     taintproper("Insecure dependency in bind");
1025 #endif
1026     return bind(fileno(stio->ifp), addr, st[sp]->str_cur) >= 0;
1027
1028 nuts:
1029     if (dowarn)
1030         warn("bind() on closed fd");
1031     return FALSE;
1032
1033 }
1034
1035 int
1036 do_connect(stab, arglast)
1037 STAB *stab;
1038 int *arglast;
1039 {
1040     register STR **st = stack->ary_array;
1041     register int sp = arglast[1];
1042     register STIO *stio;
1043     char *addr;
1044
1045     if (!stab)
1046         goto nuts;
1047
1048     stio = stab_io(stab);
1049     if (!stio || !stio->ifp)
1050         goto nuts;
1051
1052     addr = str_get(st[++sp]);
1053 #ifdef TAINT
1054     taintproper("Insecure dependency in connect");
1055 #endif
1056     return connect(fileno(stio->ifp), addr, st[sp]->str_cur) >= 0;
1057
1058 nuts:
1059     if (dowarn)
1060         warn("connect() on closed fd");
1061     return FALSE;
1062
1063 }
1064
1065 int
1066 do_listen(stab, arglast)
1067 STAB *stab;
1068 int *arglast;
1069 {
1070     register STR **st = stack->ary_array;
1071     register int sp = arglast[1];
1072     register STIO *stio;
1073     int backlog;
1074
1075     if (!stab)
1076         goto nuts;
1077
1078     stio = stab_io(stab);
1079     if (!stio || !stio->ifp)
1080         goto nuts;
1081
1082     backlog = (int)str_gnum(st[++sp]);
1083     return listen(fileno(stio->ifp), backlog) >= 0;
1084
1085 nuts:
1086     if (dowarn)
1087         warn("listen() on closed fd");
1088     return FALSE;
1089 }
1090
1091 void
1092 do_accept(str, nstab, gstab)
1093 STR *str;
1094 STAB *nstab;
1095 STAB *gstab;
1096 {
1097     register STIO *nstio;
1098     register STIO *gstio;
1099     int len = sizeof buf;
1100     int fd;
1101
1102     if (!nstab)
1103         goto badexit;
1104     if (!gstab)
1105         goto nuts;
1106
1107     gstio = stab_io(gstab);
1108     nstio = stab_io(nstab);
1109
1110     if (!gstio || !gstio->ifp)
1111         goto nuts;
1112     if (!nstio)
1113         nstio = stab_io(nstab) = stio_new();
1114     else if (nstio->ifp)
1115         do_close(nstab,FALSE);
1116
1117     fd = accept(fileno(gstio->ifp),buf,&len);
1118     if (fd < 0)
1119         goto badexit;
1120     nstio->ifp = fdopen(fd, "r");
1121     nstio->ofp = fdopen(fd, "w");
1122     nstio->type = 's';
1123
1124     str_nset(str, buf, len);
1125     return;
1126
1127 nuts:
1128     if (dowarn)
1129         warn("accept() on closed fd");
1130 badexit:
1131     str_sset(str,&str_undef);
1132     return;
1133 }
1134
1135 int
1136 do_shutdown(stab, arglast)
1137 STAB *stab;
1138 int *arglast;
1139 {
1140     register STR **st = stack->ary_array;
1141     register int sp = arglast[1];
1142     register STIO *stio;
1143     int how;
1144
1145     if (!stab)
1146         goto nuts;
1147
1148     stio = stab_io(stab);
1149     if (!stio || !stio->ifp)
1150         goto nuts;
1151
1152     how = (int)str_gnum(st[++sp]);
1153     return shutdown(fileno(stio->ifp), how) >= 0;
1154
1155 nuts:
1156     if (dowarn)
1157         warn("shutdown() on closed fd");
1158     return FALSE;
1159
1160 }
1161
1162 int
1163 do_sopt(optype, stab, arglast)
1164 int optype;
1165 STAB *stab;
1166 int *arglast;
1167 {
1168     register STR **st = stack->ary_array;
1169     register int sp = arglast[1];
1170     register STIO *stio;
1171     int fd;
1172     int lvl;
1173     int optname;
1174
1175     if (!stab)
1176         goto nuts;
1177
1178     stio = stab_io(stab);
1179     if (!stio || !stio->ifp)
1180         goto nuts;
1181
1182     fd = fileno(stio->ifp);
1183     lvl = (int)str_gnum(st[sp+1]);
1184     optname = (int)str_gnum(st[sp+2]);
1185     switch (optype) {
1186     case O_GSOCKOPT:
1187         st[sp] = str_2static(str_new(257));
1188         st[sp]->str_cur = 256;
1189         st[sp]->str_pok = 1;
1190         if (getsockopt(fd, lvl, optname, st[sp]->str_ptr, &st[sp]->str_cur) < 0)
1191             goto nuts;
1192         break;
1193     case O_SSOCKOPT:
1194         st[sp] = st[sp+3];
1195         if (setsockopt(fd, lvl, optname, st[sp]->str_ptr, st[sp]->str_cur) < 0)
1196             goto nuts;
1197         st[sp] = &str_yes;
1198         break;
1199     }
1200     
1201     return sp;
1202
1203 nuts:
1204     if (dowarn)
1205         warn("[gs]etsockopt() on closed fd");
1206     st[sp] = &str_undef;
1207     return sp;
1208
1209 }
1210
1211 int
1212 do_getsockname(optype, stab, arglast)
1213 int optype;
1214 STAB *stab;
1215 int *arglast;
1216 {
1217     register STR **st = stack->ary_array;
1218     register int sp = arglast[1];
1219     register STIO *stio;
1220     int fd;
1221
1222     if (!stab)
1223         goto nuts;
1224
1225     stio = stab_io(stab);
1226     if (!stio || !stio->ifp)
1227         goto nuts;
1228
1229     st[sp] = str_2static(str_new(257));
1230     st[sp]->str_cur = 256;
1231     st[sp]->str_pok = 1;
1232     fd = fileno(stio->ifp);
1233     switch (optype) {
1234     case O_GETSOCKNAME:
1235         if (getsockname(fd, st[sp]->str_ptr, &st[sp]->str_cur) < 0)
1236             goto nuts;
1237         break;
1238     case O_GETPEERNAME:
1239         if (getpeername(fd, st[sp]->str_ptr, &st[sp]->str_cur) < 0)
1240             goto nuts;
1241         break;
1242     }
1243     
1244     return sp;
1245
1246 nuts:
1247     if (dowarn)
1248         warn("get{sock,peer}name() on closed fd");
1249     st[sp] = &str_undef;
1250     return sp;
1251
1252 }
1253
1254 int
1255 do_ghent(which,gimme,arglast)
1256 int which;
1257 int gimme;
1258 int *arglast;
1259 {
1260     register ARRAY *ary = stack;
1261     register int sp = arglast[0];
1262     register char **elem;
1263     register STR *str;
1264     struct hostent *gethostbyname();
1265     struct hostent *gethostbyaddr();
1266 #ifdef GETHOSTENT
1267     struct hostent *gethostent();
1268 #endif
1269     struct hostent *hent;
1270     unsigned long len;
1271
1272     if (gimme != G_ARRAY) {
1273         astore(ary, ++sp, str_static(&str_undef));
1274         return sp;
1275     }
1276
1277     if (which == O_GHBYNAME) {
1278         char *name = str_get(ary->ary_array[sp+1]);
1279
1280         hent = gethostbyname(name);
1281     }
1282     else if (which == O_GHBYADDR) {
1283         STR *addrstr = ary->ary_array[sp+1];
1284         int addrtype = (int)str_gnum(ary->ary_array[sp+2]);
1285         char *addr = str_get(addrstr);
1286
1287         hent = gethostbyaddr(addr,addrstr->str_cur,addrtype);
1288     }
1289     else
1290 #ifdef GETHOSTENT
1291         hent = gethostent();
1292 #else
1293         fatal("gethostent not implemented");
1294 #endif
1295     if (hent) {
1296 #ifndef lint
1297         (void)astore(ary, ++sp, str = str_static(&str_no));
1298         str_set(str, hent->h_name);
1299         (void)astore(ary, ++sp, str = str_static(&str_no));
1300         for (elem = hent->h_aliases; *elem; elem++) {
1301             str_cat(str, *elem);
1302             if (elem[1])
1303                 str_ncat(str," ",1);
1304         }
1305         (void)astore(ary, ++sp, str = str_static(&str_no));
1306         str_numset(str, (double)hent->h_addrtype);
1307         (void)astore(ary, ++sp, str = str_static(&str_no));
1308         len = hent->h_length;
1309         str_numset(str, (double)len);
1310 #ifdef h_addr
1311         for (elem = hent->h_addr_list; *elem; elem++) {
1312             (void)astore(ary, ++sp, str = str_static(&str_no));
1313             str_nset(str, *elem, len);
1314         }
1315 #else
1316         (void)astore(ary, ++sp, str = str_static(&str_no));
1317         str_nset(str, hent->h_addr, len);
1318 #endif /* h_addr */
1319 #else /* lint */
1320         elem = Nullch;
1321         elem = elem;
1322         (void)astore(ary, ++sp, str_static(&str_no));
1323 #endif /* lint */
1324     }
1325
1326     return sp;
1327 }
1328
1329 int
1330 do_gnent(which,gimme,arglast)
1331 int which;
1332 int gimme;
1333 int *arglast;
1334 {
1335     register ARRAY *ary = stack;
1336     register int sp = arglast[0];
1337     register char **elem;
1338     register STR *str;
1339     struct netent *getnetbyname();
1340     struct netent *getnetbyaddr();
1341     struct netent *getnetent();
1342     struct netent *nent;
1343
1344     if (gimme != G_ARRAY) {
1345         astore(ary, ++sp, str_static(&str_undef));
1346         return sp;
1347     }
1348
1349     if (which == O_GNBYNAME) {
1350         char *name = str_get(ary->ary_array[sp+1]);
1351
1352         nent = getnetbyname(name);
1353     }
1354     else if (which == O_GNBYADDR) {
1355         STR *addrstr = ary->ary_array[sp+1];
1356         int addrtype = (int)str_gnum(ary->ary_array[sp+2]);
1357         char *addr = str_get(addrstr);
1358
1359         nent = getnetbyaddr(addr,addrtype);
1360     }
1361     else
1362         nent = getnetent();
1363
1364     if (nent) {
1365 #ifndef lint
1366         (void)astore(ary, ++sp, str = str_static(&str_no));
1367         str_set(str, nent->n_name);
1368         (void)astore(ary, ++sp, str = str_static(&str_no));
1369         for (elem = nent->n_aliases; *elem; elem++) {
1370             str_cat(str, *elem);
1371             if (elem[1])
1372                 str_ncat(str," ",1);
1373         }
1374         (void)astore(ary, ++sp, str = str_static(&str_no));
1375         str_numset(str, (double)nent->n_addrtype);
1376         (void)astore(ary, ++sp, str = str_static(&str_no));
1377         str_numset(str, (double)nent->n_net);
1378 #else /* lint */
1379         elem = Nullch;
1380         elem = elem;
1381         (void)astore(ary, ++sp, str_static(&str_no));
1382 #endif /* lint */
1383     }
1384
1385     return sp;
1386 }
1387
1388 int
1389 do_gpent(which,gimme,arglast)
1390 int which;
1391 int gimme;
1392 int *arglast;
1393 {
1394     register ARRAY *ary = stack;
1395     register int sp = arglast[0];
1396     register char **elem;
1397     register STR *str;
1398     struct protoent *getprotobyname();
1399     struct protoent *getprotobynumber();
1400     struct protoent *getprotoent();
1401     struct protoent *pent;
1402
1403     if (gimme != G_ARRAY) {
1404         astore(ary, ++sp, str_static(&str_undef));
1405         return sp;
1406     }
1407
1408     if (which == O_GPBYNAME) {
1409         char *name = str_get(ary->ary_array[sp+1]);
1410
1411         pent = getprotobyname(name);
1412     }
1413     else if (which == O_GPBYNUMBER) {
1414         int proto = (int)str_gnum(ary->ary_array[sp+1]);
1415
1416         pent = getprotobynumber(proto);
1417     }
1418     else
1419         pent = getprotoent();
1420
1421     if (pent) {
1422 #ifndef lint
1423         (void)astore(ary, ++sp, str = str_static(&str_no));
1424         str_set(str, pent->p_name);
1425         (void)astore(ary, ++sp, str = str_static(&str_no));
1426         for (elem = pent->p_aliases; *elem; elem++) {
1427             str_cat(str, *elem);
1428             if (elem[1])
1429                 str_ncat(str," ",1);
1430         }
1431         (void)astore(ary, ++sp, str = str_static(&str_no));
1432         str_numset(str, (double)pent->p_proto);
1433 #else /* lint */
1434         elem = Nullch;
1435         elem = elem;
1436         (void)astore(ary, ++sp, str_static(&str_no));
1437 #endif /* lint */
1438     }
1439
1440     return sp;
1441 }
1442
1443 int
1444 do_gsent(which,gimme,arglast)
1445 int which;
1446 int gimme;
1447 int *arglast;
1448 {
1449     register ARRAY *ary = stack;
1450     register int sp = arglast[0];
1451     register char **elem;
1452     register STR *str;
1453     struct servent *getservbyname();
1454     struct servent *getservbynumber();
1455     struct servent *getservent();
1456     struct servent *sent;
1457
1458     if (gimme != G_ARRAY) {
1459         astore(ary, ++sp, str_static(&str_undef));
1460         return sp;
1461     }
1462
1463     if (which == O_GSBYNAME) {
1464         char *name = str_get(ary->ary_array[sp+1]);
1465         char *proto = str_get(ary->ary_array[sp+2]);
1466
1467         if (proto && !*proto)
1468             proto = Nullch;
1469
1470         sent = getservbyname(name,proto);
1471     }
1472     else if (which == O_GSBYPORT) {
1473         int port = (int)str_gnum(ary->ary_array[sp+1]);
1474         char *proto = str_get(ary->ary_array[sp+2]);
1475
1476         sent = getservbyport(port,proto);
1477     }
1478     else
1479         sent = getservent();
1480     if (sent) {
1481 #ifndef lint
1482         (void)astore(ary, ++sp, str = str_static(&str_no));
1483         str_set(str, sent->s_name);
1484         (void)astore(ary, ++sp, str = str_static(&str_no));
1485         for (elem = sent->s_aliases; *elem; elem++) {
1486             str_cat(str, *elem);
1487             if (elem[1])
1488                 str_ncat(str," ",1);
1489         }
1490         (void)astore(ary, ++sp, str = str_static(&str_no));
1491 #ifdef NTOHS
1492         str_numset(str, (double)ntohs(sent->s_port));
1493 #else
1494         str_numset(str, (double)(sent->s_port));
1495 #endif
1496         (void)astore(ary, ++sp, str = str_static(&str_no));
1497         str_set(str, sent->s_proto);
1498 #else /* lint */
1499         elem = Nullch;
1500         elem = elem;
1501         (void)astore(ary, ++sp, str_static(&str_no));
1502 #endif /* lint */
1503     }
1504
1505     return sp;
1506 }
1507
1508 int
1509 do_select(gimme,arglast)
1510 int gimme;
1511 int *arglast;
1512 {
1513     register STR **st = stack->ary_array;
1514     register int sp = arglast[0];
1515     register int i;
1516     register int j;
1517     register char *s;
1518     register STR *str;
1519     double value;
1520     int maxlen = 0;
1521     int nfound;
1522     struct timeval timebuf;
1523     struct timeval *tbuf = &timebuf;
1524     int growsize;
1525 #if BYTEORDER != 0x1234 && BYTEORDER != 0x12345678
1526     int masksize;
1527     int offset;
1528     char *fd_sets[4];
1529     int k;
1530
1531 #if BYTEORDER & 0xf0000
1532 #define ORDERBYTE (0x88888888 - BYTEORDER)
1533 #else
1534 #define ORDERBYTE (0x4444 - BYTEORDER)
1535 #endif
1536
1537 #endif
1538
1539     for (i = 1; i <= 3; i++) {
1540         j = st[sp+i]->str_cur;
1541         if (maxlen < j)
1542             maxlen = j;
1543     }
1544
1545 #if BYTEORDER == 0x1234 || BYTEORDER == 0x12345678
1546     growsize = maxlen;          /* little endians can use vecs directly */
1547 #else
1548 #ifdef NFDBITS
1549
1550 #ifndef NBBY
1551 #define NBBY 8
1552 #endif
1553
1554     masksize = NFDBITS / NBBY;
1555 #else
1556     masksize = sizeof(long);    /* documented int, everyone seems to use long */
1557 #endif
1558     growsize = maxlen + (masksize - (maxlen % masksize));
1559     Zero(&fd_sets[0], 4, char*);
1560 #endif
1561
1562     for (i = 1; i <= 3; i++) {
1563         str = st[sp+i];
1564         j = str->str_len;
1565         if (j < growsize) {
1566             if (str->str_pok) {
1567                 str_grow(str,growsize);
1568                 s = str_get(str) + j;
1569                 while (++j <= growsize) {
1570                     *s++ = '\0';
1571                 }
1572             }
1573             else if (str->str_ptr) {
1574                 Safefree(str->str_ptr);
1575                 str->str_ptr = Nullch;
1576             }
1577         }
1578 #if BYTEORDER != 0x1234 && BYTEORDER != 0x12345678
1579         s = str->str_ptr;
1580         if (s) {
1581             New(403, fd_sets[i], growsize, char);
1582             for (offset = 0; offset < growsize; offset += masksize) {
1583                 for (j = 0, k=ORDERBYTE; j < masksize; j++, (k >>= 4))
1584                     fd_sets[i][j+offset] = s[(k % masksize) + offset];
1585             }
1586         }
1587 #endif
1588     }
1589     str = st[sp+4];
1590     if (str->str_nok || str->str_pok) {
1591         value = str_gnum(str);
1592         if (value < 0.0)
1593             value = 0.0;
1594         timebuf.tv_sec = (long)value;
1595         value -= (double)timebuf.tv_sec;
1596         timebuf.tv_usec = (long)(value * 1000000.0);
1597     }
1598     else
1599         tbuf = Null(struct timeval*);
1600
1601 #if BYTEORDER == 0x1234 || BYTEORDER == 0x12345678
1602     nfound = select(
1603         maxlen * 8,
1604         st[sp+1]->str_ptr,
1605         st[sp+2]->str_ptr,
1606         st[sp+3]->str_ptr,
1607         tbuf);
1608 #else
1609     nfound = select(
1610         maxlen * 8,
1611         fd_sets[1],
1612         fd_sets[2],
1613         fd_sets[3],
1614         tbuf);
1615     for (i = 1; i <= 3; i++) {
1616         if (fd_sets[i]) {
1617             str = st[sp+i];
1618             s = str->str_ptr;
1619             for (offset = 0; offset < growsize; offset += masksize) {
1620                 for (j = 0, k=ORDERBYTE; j < masksize; j++, (k >>= 4))
1621                     s[(k % masksize) + offset] = fd_sets[i][j+offset];
1622             }
1623         }
1624     }
1625 #endif
1626
1627     st[++sp] = str_static(&str_no);
1628     str_numset(st[sp], (double)nfound);
1629     if (gimme == G_ARRAY && tbuf) {
1630         value = (double)(timebuf.tv_sec) +
1631                 (double)(timebuf.tv_usec) / 1000000.0;
1632         st[++sp] = str_static(&str_no);
1633         str_numset(st[sp], value);
1634     }
1635     return sp;
1636 }
1637
1638 int
1639 do_spair(stab1, stab2, arglast)
1640 STAB *stab1;
1641 STAB *stab2;
1642 int *arglast;
1643 {
1644     register STR **st = stack->ary_array;
1645     register int sp = arglast[2];
1646     register STIO *stio1;
1647     register STIO *stio2;
1648     int domain, type, protocol, fd[2];
1649
1650     if (!stab1 || !stab2)
1651         return FALSE;
1652
1653     stio1 = stab_io(stab1);
1654     stio2 = stab_io(stab2);
1655     if (!stio1)
1656         stio1 = stab_io(stab1) = stio_new();
1657     else if (stio1->ifp)
1658         do_close(stab1,FALSE);
1659     if (!stio2)
1660         stio2 = stab_io(stab2) = stio_new();
1661     else if (stio2->ifp)
1662         do_close(stab2,FALSE);
1663
1664     domain = (int)str_gnum(st[++sp]);
1665     type = (int)str_gnum(st[++sp]);
1666     protocol = (int)str_gnum(st[++sp]);
1667 #ifdef TAINT
1668     taintproper("Insecure dependency in socketpair");
1669 #endif
1670 #ifdef SOCKETPAIR
1671     if (socketpair(domain,type,protocol,fd) < 0)
1672         return FALSE;
1673 #else
1674     fatal("Socketpair unimplemented");
1675 #endif
1676     stio1->ifp = fdopen(fd[0], "r");
1677     stio1->ofp = fdopen(fd[0], "w");
1678     stio1->type = 's';
1679     stio2->ifp = fdopen(fd[1], "r");
1680     stio2->ofp = fdopen(fd[1], "w");
1681     stio2->type = 's';
1682
1683     return TRUE;
1684 }
1685
1686 #endif /* SOCKET */
1687
1688 int
1689 do_gpwent(which,gimme,arglast)
1690 int which;
1691 int gimme;
1692 int *arglast;
1693 {
1694 #ifdef I_PWD
1695     register ARRAY *ary = stack;
1696     register int sp = arglast[0];
1697     register char **elem;
1698     register STR *str;
1699     struct passwd *getpwnam();
1700     struct passwd *getpwuid();
1701     struct passwd *getpwent();
1702     struct passwd *pwent;
1703     unsigned long len;
1704
1705     if (gimme != G_ARRAY) {
1706         astore(ary, ++sp, str_static(&str_undef));
1707         return sp;
1708     }
1709
1710     if (which == O_GPWNAM) {
1711         char *name = str_get(ary->ary_array[sp+1]);
1712
1713         pwent = getpwnam(name);
1714     }
1715     else if (which == O_GPWUID) {
1716         int uid = (int)str_gnum(ary->ary_array[sp+1]);
1717
1718         pwent = getpwuid(uid);
1719     }
1720     else
1721         pwent = getpwent();
1722
1723     if (pwent) {
1724         (void)astore(ary, ++sp, str = str_static(&str_no));
1725         str_set(str, pwent->pw_name);
1726         (void)astore(ary, ++sp, str = str_static(&str_no));
1727         str_set(str, pwent->pw_passwd);
1728         (void)astore(ary, ++sp, str = str_static(&str_no));
1729         str_numset(str, (double)pwent->pw_uid);
1730         (void)astore(ary, ++sp, str = str_static(&str_no));
1731         str_numset(str, (double)pwent->pw_gid);
1732         (void)astore(ary, ++sp, str = str_static(&str_no));
1733 #ifdef PWCHANGE
1734         str_numset(str, (double)pwent->pw_change);
1735 #else
1736 #ifdef PWQUOTA
1737         str_numset(str, (double)pwent->pw_quota);
1738 #else
1739 #ifdef PWAGE
1740         str_set(str, pwent->pw_age);
1741 #endif
1742 #endif
1743 #endif
1744         (void)astore(ary, ++sp, str = str_static(&str_no));
1745 #ifdef PWCLASS
1746         str_set(str,pwent->pw_class);
1747 #else
1748         str_set(str, pwent->pw_comment);
1749 #endif
1750         (void)astore(ary, ++sp, str = str_static(&str_no));
1751         str_set(str, pwent->pw_gecos);
1752         (void)astore(ary, ++sp, str = str_static(&str_no));
1753         str_set(str, pwent->pw_dir);
1754         (void)astore(ary, ++sp, str = str_static(&str_no));
1755         str_set(str, pwent->pw_shell);
1756 #ifdef PWEXPIRE
1757         (void)astore(ary, ++sp, str = str_static(&str_no));
1758         str_numset(str, (double)pwent->pw_expire);
1759 #endif
1760     }
1761
1762     return sp;
1763 #else
1764     fatal("password routines not implemented");
1765 #endif
1766 }
1767
1768 int
1769 do_ggrent(which,gimme,arglast)
1770 int which;
1771 int gimme;
1772 int *arglast;
1773 {
1774 #ifdef I_GRP
1775     register ARRAY *ary = stack;
1776     register int sp = arglast[0];
1777     register char **elem;
1778     register STR *str;
1779     struct group *getgrnam();
1780     struct group *getgrgid();
1781     struct group *getgrent();
1782     struct group *grent;
1783     unsigned long len;
1784
1785     if (gimme != G_ARRAY) {
1786         astore(ary, ++sp, str_static(&str_undef));
1787         return sp;
1788     }
1789
1790     if (which == O_GGRNAM) {
1791         char *name = str_get(ary->ary_array[sp+1]);
1792
1793         grent = getgrnam(name);
1794     }
1795     else if (which == O_GGRGID) {
1796         int gid = (int)str_gnum(ary->ary_array[sp+1]);
1797
1798         grent = getgrgid(gid);
1799     }
1800     else
1801         grent = getgrent();
1802
1803     if (grent) {
1804         (void)astore(ary, ++sp, str = str_static(&str_no));
1805         str_set(str, grent->gr_name);
1806         (void)astore(ary, ++sp, str = str_static(&str_no));
1807         str_set(str, grent->gr_passwd);
1808         (void)astore(ary, ++sp, str = str_static(&str_no));
1809         str_numset(str, (double)grent->gr_gid);
1810         (void)astore(ary, ++sp, str = str_static(&str_no));
1811         for (elem = grent->gr_mem; *elem; elem++) {
1812             str_cat(str, *elem);
1813             if (elem[1])
1814                 str_ncat(str," ",1);
1815         }
1816     }
1817
1818     return sp;
1819 #else
1820     fatal("group routines not implemented");
1821 #endif
1822 }
1823
1824 int
1825 do_dirop(optype,stab,gimme,arglast)
1826 int optype;
1827 STAB *stab;
1828 int gimme;
1829 int *arglast;
1830 {
1831 #if defined(DIRENT) && defined(READDIR)
1832     register ARRAY *ary = stack;
1833     register STR **st = ary->ary_array;
1834     register int sp = arglast[1];
1835     register STIO *stio;
1836     long along;
1837 #ifndef telldir
1838     long telldir();
1839 #endif
1840     struct DIRENT *readdir();
1841     register struct DIRENT *dp;
1842
1843     if (!stab)
1844         goto nope;
1845     if (!(stio = stab_io(stab)))
1846         stio = stab_io(stab) = stio_new();
1847     if (!stio->dirp && optype != O_OPENDIR)
1848         goto nope;
1849     st[sp] = &str_yes;
1850     switch (optype) {
1851     case O_OPENDIR:
1852         if (stio->dirp)
1853             closedir(stio->dirp);
1854         if (!(stio->dirp = opendir(str_get(st[sp+1]))))
1855             goto nope;
1856         break;
1857     case O_READDIR:
1858         if (gimme == G_ARRAY) {
1859             --sp;
1860             while (dp = readdir(stio->dirp)) {
1861 #ifdef DIRNAMLEN
1862                 (void)astore(ary,++sp,
1863                   str_2static(str_make(dp->d_name,dp->d_namlen)));
1864 #else
1865                 (void)astore(ary,++sp,
1866                   str_2static(str_make(dp->d_name,0)));
1867 #endif
1868             }
1869         }
1870         else {
1871             if (!(dp = readdir(stio->dirp)))
1872                 goto nope;
1873             st[sp] = str_static(&str_undef);
1874 #ifdef DIRNAMLEN
1875             str_nset(st[sp], dp->d_name, dp->d_namlen);
1876 #else
1877             str_set(st[sp], dp->d_name);
1878 #endif
1879         }
1880         break;
1881     case O_TELLDIR:
1882         st[sp] = str_static(&str_undef);
1883         str_numset(st[sp], (double)telldir(stio->dirp));
1884         break;
1885     case O_SEEKDIR:
1886         st[sp] = str_static(&str_undef);
1887         along = (long)str_gnum(st[sp+1]);
1888         (void)seekdir(stio->dirp,along);
1889         break;
1890     case O_REWINDDIR:
1891         st[sp] = str_static(&str_undef);
1892         (void)rewinddir(stio->dirp);
1893         break;
1894     case O_CLOSEDIR:
1895         st[sp] = str_static(&str_undef);
1896         (void)closedir(stio->dirp);
1897         stio->dirp = 0;
1898         break;
1899     }
1900     return sp;
1901
1902 nope:
1903     st[sp] = &str_undef;
1904     return sp;
1905
1906 #else
1907     fatal("Unimplemented directory operation");
1908 #endif
1909 }
1910
1911 apply(type,arglast)
1912 int type;
1913 int *arglast;
1914 {
1915     register STR **st = stack->ary_array;
1916     register int sp = arglast[1];
1917     register int items = arglast[2] - sp;
1918     register int val;
1919     register int val2;
1920     register int tot = 0;
1921     char *s;
1922
1923 #ifdef TAINT
1924     for (st += ++sp; items--; st++)
1925         tainted |= (*st)->str_tainted;
1926     st = stack->ary_array;
1927     sp = arglast[1];
1928     items = arglast[2] - sp;
1929 #endif
1930     switch (type) {
1931     case O_CHMOD:
1932 #ifdef TAINT
1933         taintproper("Insecure dependency in chmod");
1934 #endif
1935         if (--items > 0) {
1936             tot = items;
1937             val = (int)str_gnum(st[++sp]);
1938             while (items--) {
1939                 if (chmod(str_get(st[++sp]),val))
1940                     tot--;
1941             }
1942         }
1943         break;
1944     case O_CHOWN:
1945 #ifdef TAINT
1946         taintproper("Insecure dependency in chown");
1947 #endif
1948         if (items > 2) {
1949             items -= 2;
1950             tot = items;
1951             val = (int)str_gnum(st[++sp]);
1952             val2 = (int)str_gnum(st[++sp]);
1953             while (items--) {
1954                 if (chown(str_get(st[++sp]),val,val2))
1955                     tot--;
1956             }
1957         }
1958         break;
1959     case O_KILL:
1960 #ifdef TAINT
1961         taintproper("Insecure dependency in kill");
1962 #endif
1963         if (--items > 0) {
1964             tot = items;
1965             s = str_get(st[++sp]);
1966             if (isupper(*s)) {
1967                 if (*s == 'S' && s[1] == 'I' && s[2] == 'G')
1968                     s += 3;
1969                 if (!(val = whichsig(s)))
1970                     fatal("Unrecognized signal name \"%s\"",s);
1971             }
1972             else
1973                 val = (int)str_gnum(st[sp]);
1974             if (val < 0) {
1975                 val = -val;
1976                 while (items--) {
1977                     int proc = (int)str_gnum(st[++sp]);
1978 #ifdef KILLPG
1979                     if (killpg(proc,val))       /* BSD */
1980 #else
1981                     if (kill(-proc,val))        /* SYSV */
1982 #endif
1983                         tot--;
1984                 }
1985             }
1986             else {
1987                 while (items--) {
1988                     if (kill((int)(str_gnum(st[++sp])),val))
1989                         tot--;
1990                 }
1991             }
1992         }
1993         break;
1994     case O_UNLINK:
1995 #ifdef TAINT
1996         taintproper("Insecure dependency in unlink");
1997 #endif
1998         tot = items;
1999         while (items--) {
2000             s = str_get(st[++sp]);
2001             if (euid || unsafe) {
2002                 if (UNLINK(s))
2003                     tot--;
2004             }
2005             else {      /* don't let root wipe out directories without -U */
2006 #ifdef LSTAT
2007                 if (lstat(s,&statbuf) < 0 ||
2008 #else
2009                 if (stat(s,&statbuf) < 0 ||
2010 #endif
2011                   (statbuf.st_mode & S_IFMT) == S_IFDIR )
2012                     tot--;
2013                 else {
2014                     if (UNLINK(s))
2015                         tot--;
2016                 }
2017             }
2018         }
2019         break;
2020     case O_UTIME:
2021 #ifdef TAINT
2022         taintproper("Insecure dependency in utime");
2023 #endif
2024         if (items > 2) {
2025 #ifdef I_UTIME
2026             struct utimbuf utbuf;
2027 #else
2028             struct {
2029                 long    actime;
2030                 long    modtime;
2031             } utbuf;
2032 #endif
2033
2034             Zero(&utbuf, sizeof utbuf, char);
2035             utbuf.actime = (long)str_gnum(st[++sp]);    /* time accessed */
2036             utbuf.modtime = (long)str_gnum(st[++sp]);    /* time modified */
2037             items -= 2;
2038 #ifndef lint
2039             tot = items;
2040             while (items--) {
2041                 if (utime(str_get(st[++sp]),&utbuf))
2042                     tot--;
2043             }
2044 #endif
2045         }
2046         else
2047             items = 0;
2048         break;
2049     }
2050     return tot;
2051 }
2052
2053 /* Do the permissions allow some operation?  Assumes statcache already set. */
2054
2055 int
2056 cando(bit, effective, statbufp)
2057 int bit;
2058 int effective;
2059 register struct stat *statbufp;
2060 {
2061     if ((effective ? euid : uid) == 0) {        /* root is special */
2062         if (bit == S_IEXEC) {
2063             if (statbufp->st_mode & 0111 ||
2064               (statbufp->st_mode & S_IFMT) == S_IFDIR )
2065                 return TRUE;
2066         }
2067         else
2068             return TRUE;                /* root reads and writes anything */
2069         return FALSE;
2070     }
2071     if (statbufp->st_uid == (effective ? euid : uid) ) {
2072         if (statbufp->st_mode & bit)
2073             return TRUE;        /* ok as "user" */
2074     }
2075     else if (ingroup((int)statbufp->st_gid,effective)) {
2076         if (statbufp->st_mode & bit >> 3)
2077             return TRUE;        /* ok as "group" */
2078     }
2079     else if (statbufp->st_mode & bit >> 6)
2080         return TRUE;    /* ok as "other" */
2081     return FALSE;
2082 }
2083
2084 int
2085 ingroup(testgid,effective)
2086 int testgid;
2087 int effective;
2088 {
2089     if (testgid == (effective ? egid : gid))
2090         return TRUE;
2091 #ifdef GETGROUPS
2092 #ifndef NGROUPS
2093 #define NGROUPS 32
2094 #endif
2095     {
2096         GIDTYPE gary[NGROUPS];
2097         int anum;
2098
2099         anum = getgroups(NGROUPS,gary);
2100         while (--anum >= 0)
2101             if (gary[anum] == testgid)
2102                 return TRUE;
2103     }
2104 #endif
2105     return FALSE;
2106 }