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