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