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