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