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