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