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