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