e93c305e7c0da91077bbb26550685f02a8604ff0
[p5sagit/p5-mst-13.2.git] / doio.c
1 /* $RCSfile: doio.c,v $$Revision: 4.0.1.2 $$Date: 91/06/07 10:53:39 $
2  *
3  *    Copyright (c) 1991, Larry Wall
4  *
5  *    You may distribute under the terms of either the GNU General Public
6  *    License or the Artistic License, as specified in the README file.
7  *
8  * $Log:        doio.c,v $
9  * Revision 4.0.1.2  91/06/07  10:53:39  lwall
10  * patch4: new copyright notice
11  * patch4: system fd's are now treated specially
12  * patch4: added $^F variable to specify maximum system fd, default 2
13  * patch4: character special files now opened with bidirectional stdio buffers
14  * patch4: taintchecks could improperly modify parent in vfork()
15  * patch4: many, many itty-bitty portability fixes
16  * 
17  * Revision 4.0.1.1  91/04/11  17:41:06  lwall
18  * patch1: hopefully straightened out some of the Xenix mess
19  * 
20  * Revision 4.0  91/03/20  01:07:06  lwall
21  * 4.0 baseline.
22  * 
23  */
24
25 #include "EXTERN.h"
26 #include "perl.h"
27
28 #ifdef HAS_SOCKET
29 #include <sys/socket.h>
30 #include <netdb.h>
31 #endif
32
33 #ifdef HAS_SELECT
34 #ifdef I_SYS_SELECT
35 #ifndef I_SYS_TIME
36 #include <sys/select.h>
37 #endif
38 #endif
39 #endif
40
41 #if defined(HAS_MSG) || defined(HAS_SEM) || defined(HAS_SHM)
42 #include <sys/ipc.h>
43 #ifdef HAS_MSG
44 #include <sys/msg.h>
45 #endif
46 #ifdef HAS_SEM
47 #include <sys/sem.h>
48 #endif
49 #ifdef HAS_SHM
50 #include <sys/shm.h>
51 #endif
52 #endif
53
54 #ifdef I_PWD
55 #include <pwd.h>
56 #endif
57 #ifdef I_GRP
58 #include <grp.h>
59 #endif
60 #ifdef I_UTIME
61 #include <utime.h>
62 #endif
63 #ifdef I_FCNTL
64 #include <fcntl.h>
65 #endif
66 #ifdef I_SYS_FILE
67 #include <sys/file.h>
68 #endif
69
70 int laststatval = -1;
71 int laststype = O_STAT;
72
73 bool
74 do_open(stab,name,len)
75 STAB *stab;
76 register char *name;
77 int len;
78 {
79     FILE *fp;
80     register STIO *stio = stab_io(stab);
81     char *myname = savestr(name);
82     int result;
83     int fd;
84     int writing = 0;
85     char mode[3];               /* stdio file mode ("r\0" or "r+\0") */
86     FILE *saveifp = Nullfp;
87     FILE *saveofp = Nullfp;
88     char savetype = ' ';
89
90     name = myname;
91     forkprocess = 1;            /* assume true if no fork */
92     while (len && isspace(name[len-1]))
93         name[--len] = '\0';
94     if (!stio)
95         stio = stab_io(stab) = stio_new();
96     else if (stio->ifp) {
97         fd = fileno(stio->ifp);
98         if (stio->type == '-')
99             result = 0;
100         else if (fd <= maxsysfd) {
101             saveifp = stio->ifp;
102             saveofp = stio->ofp;
103             savetype = stio->type;
104             result = 0;
105         }
106         else if (stio->type == '|')
107             result = mypclose(stio->ifp);
108         else if (stio->ifp != stio->ofp) {
109             if (stio->ofp) {
110                 result = fclose(stio->ofp);
111                 fclose(stio->ifp);      /* clear stdio, fd already closed */
112             }
113             else
114                 result = fclose(stio->ifp);
115         }
116         else
117             result = fclose(stio->ifp);
118         if (result == EOF && fd > maxsysfd)
119             fprintf(stderr,"Warning: unable to close filehandle %s properly.\n",
120               stab_name(stab));
121         stio->ofp = stio->ifp = Nullfp;
122     }
123     if (*name == '+' && len > 1 && name[len-1] != '|') {        /* scary */
124         mode[1] = *name++;
125         mode[2] = '\0';
126         --len;
127         writing = 1;
128     }
129     else  {
130         mode[1] = '\0';
131     }
132     stio->type = *name;
133     if (*name == '|') {
134         for (name++; isspace(*name); name++) ;
135 #ifdef TAINT
136         taintenv();
137         taintproper("Insecure dependency in piped open");
138 #endif
139         fp = mypopen(name,"w");
140         writing = 1;
141     }
142     else if (*name == '>') {
143 #ifdef TAINT
144         taintproper("Insecure dependency in open");
145 #endif
146         name++;
147         if (*name == '>') {
148             mode[0] = stio->type = 'a';
149             name++;
150         }
151         else
152             mode[0] = 'w';
153         writing = 1;
154         if (*name == '&') {
155           duplicity:
156             name++;
157             while (isspace(*name))
158                 name++;
159             if (isdigit(*name))
160                 fd = atoi(name);
161             else {
162                 stab = stabent(name,FALSE);
163                 if (!stab || !stab_io(stab)) {
164 #ifdef EINVAL
165                     errno = EINVAL;
166 #endif
167                     goto say_false;
168                 }
169                 if (stab_io(stab) && stab_io(stab)->ifp) {
170                     fd = fileno(stab_io(stab)->ifp);
171                     if (stab_io(stab)->type == 's')
172                         stio->type = 's';
173                 }
174                 else
175                     fd = -1;
176             }
177             if (!(fp = fdopen(fd = dup(fd),mode))) {
178                 close(fd);
179             }
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         goto say_false;
234     if (stio->type &&
235       stio->type != '|' && stio->type != '-') {
236         if (fstat(fileno(fp),&statbuf) < 0) {
237             (void)fclose(fp);
238             goto say_false;
239         }
240         if (S_ISSOCK(statbuf.st_mode) || (S_ISCHR(statbuf.st_mode) && writing))
241             stio->type = 's';   /* in case a socket was passed in to us */
242 #ifdef S_IFMT
243         else if (!(statbuf.st_mode & S_IFMT))
244             stio->type = 's';   /* some OS's return 0 on fstat()ed socket */
245 #endif
246     }
247 #if defined(HAS_FCNTL) && defined(F_SETFD)
248     fd = fileno(fp);
249     fcntl(fd,F_SETFD,fd > maxsysfd);
250 #endif
251     if (saveifp) {              /* must use old fp? */
252         fd = fileno(saveifp);
253         if (saveofp) {
254             fflush(saveofp);            /* emulate fclose() */
255             if (saveofp != saveifp) {   /* was a socket? */
256                 fclose(saveofp);
257                 Safefree(saveofp);
258             }
259         }
260         if (fd != fileno(fp)) {
261             dup2(fileno(fp), fd);
262             fclose(fp);
263         }
264         fp = saveifp;
265     }
266     stio->ifp = fp;
267     if (writing) {
268         if (stio->type != 's')
269             stio->ofp = fp;
270         else
271             if (!(stio->ofp = fdopen(fileno(fp),"w"))) {
272                 fclose(fp);
273                 stio->ifp = Nullfp;
274                 goto say_false;
275             }
276     }
277     return TRUE;
278
279 say_false:
280     stio->ifp = saveifp;
281     stio->ofp = saveofp;
282     stio->type = savetype;
283     return FALSE;
284 }
285
286 FILE *
287 nextargv(stab)
288 register STAB *stab;
289 {
290     register STR *str;
291     int filedev;
292     int fileino;
293     int fileuid;
294     int filegid;
295     static int filemode = 0;
296     static int lastfd;
297     static char *oldname;
298
299     if (!argvoutstab)
300         argvoutstab = stabent("ARGVOUT",TRUE);
301     if (filemode & (S_ISUID|S_ISGID)) {
302         fflush(stab_io(argvoutstab)->ifp);  /* chmod must follow last write */
303 #ifdef HAS_FCHMOD
304         (void)fchmod(lastfd,filemode);
305 #else
306         (void)chmod(oldname,filemode);
307 #endif
308     }
309     filemode = 0;
310     while (alen(stab_xarray(stab)) >= 0) {
311         str = ashift(stab_xarray(stab));
312         str_sset(stab_val(stab),str);
313         STABSET(stab_val(stab));
314         oldname = str_get(stab_val(stab));
315         if (do_open(stab,oldname,stab_val(stab)->str_cur)) {
316             if (inplace) {
317 #ifdef TAINT
318                 taintproper("Insecure dependency in inplace open");
319 #endif
320                 if (strEQ(oldname,"-")) {
321                     str_free(str);
322                     defoutstab = stabent("STDOUT",TRUE);
323                     return stab_io(stab)->ifp;
324                 }
325                 filedev = statbuf.st_dev;
326                 fileino = statbuf.st_ino;
327                 filemode = statbuf.st_mode;
328                 fileuid = statbuf.st_uid;
329                 filegid = statbuf.st_gid;
330                 if (!S_ISREG(filemode)) {
331                     warn("Can't do inplace edit: %s is not a regular file",
332                       oldname );
333                     do_close(stab,FALSE);
334                     str_free(str);
335                     continue;
336                 }
337                 if (*inplace) {
338 #ifdef SUFFIX
339                     add_suffix(str,inplace);
340 #else
341                     str_cat(str,inplace);
342 #endif
343 #ifndef FLEXFILENAMES
344                     if (stat(str->str_ptr,&statbuf) >= 0
345                       && statbuf.st_dev == filedev
346                       && statbuf.st_ino == fileino ) {
347                         warn("Can't do inplace edit: %s > 14 characters",
348                           str->str_ptr );
349                         do_close(stab,FALSE);
350                         str_free(str);
351                         continue;
352                     }
353 #endif
354 #ifdef HAS_RENAME
355 #ifndef MSDOS
356                     if (rename(oldname,str->str_ptr) < 0) {
357                         warn("Can't rename %s to %s: %s, skipping file",
358                           oldname, str->str_ptr, strerror(errno) );
359                         do_close(stab,FALSE);
360                         str_free(str);
361                         continue;
362                     }
363 #else
364                     do_close(stab,FALSE);
365                     (void)unlink(str->str_ptr);
366                     (void)rename(oldname,str->str_ptr);
367                     do_open(stab,str->str_ptr,stab_val(stab)->str_cur);
368 #endif /* MSDOS */
369 #else
370                     (void)UNLINK(str->str_ptr);
371                     if (link(oldname,str->str_ptr) < 0) {
372                         warn("Can't rename %s to %s: %s, skipping file",
373                           oldname, str->str_ptr, strerror(errno) );
374                         do_close(stab,FALSE);
375                         str_free(str);
376                         continue;
377                     }
378                     (void)UNLINK(oldname);
379 #endif
380                 }
381                 else {
382 #ifndef MSDOS
383                     if (UNLINK(oldname) < 0) {
384                         warn("Can't rename %s to %s: %s, skipping file",
385                           oldname, str->str_ptr, strerror(errno) );
386                         do_close(stab,FALSE);
387                         str_free(str);
388                         continue;
389                     }
390 #else
391                     fatal("Can't do inplace edit without backup");
392 #endif
393                 }
394
395                 str_nset(str,">",1);
396                 str_cat(str,oldname);
397                 errno = 0;              /* in case sprintf set errno */
398                 if (!do_open(argvoutstab,str->str_ptr,str->str_cur)) {
399                     warn("Can't do inplace edit on %s: %s",
400                       oldname, strerror(errno) );
401                     do_close(stab,FALSE);
402                     str_free(str);
403                     continue;
404                 }
405                 defoutstab = argvoutstab;
406                 lastfd = fileno(stab_io(argvoutstab)->ifp);
407                 (void)fstat(lastfd,&statbuf);
408 #ifdef HAS_FCHMOD
409                 (void)fchmod(lastfd,filemode);
410 #else
411                 (void)chmod(oldname,filemode);
412 #endif
413                 if (fileuid != statbuf.st_uid || filegid != statbuf.st_gid) {
414 #ifdef HAS_FCHOWN
415                     (void)fchown(lastfd,fileuid,filegid);
416 #else
417 #ifdef HAS_CHOWN
418                     (void)chown(oldname,fileuid,filegid);
419 #endif
420 #endif
421                 }
422             }
423             str_free(str);
424             return stab_io(stab)->ifp;
425         }
426         else
427             fprintf(stderr,"Can't open %s: %s\n",str_get(str), strerror(errno));
428         str_free(str);
429     }
430     if (inplace) {
431         (void)do_close(argvoutstab,FALSE);
432         defoutstab = stabent("STDOUT",TRUE);
433     }
434     return Nullfp;
435 }
436
437 #ifdef HAS_PIPE
438 void
439 do_pipe(str, rstab, wstab)
440 STR *str;
441 STAB *rstab;
442 STAB *wstab;
443 {
444     register STIO *rstio;
445     register STIO *wstio;
446     int fd[2];
447
448     if (!rstab)
449         goto badexit;
450     if (!wstab)
451         goto badexit;
452
453     rstio = stab_io(rstab);
454     wstio = stab_io(wstab);
455
456     if (!rstio)
457         rstio = stab_io(rstab) = stio_new();
458     else if (rstio->ifp)
459         do_close(rstab,FALSE);
460     if (!wstio)
461         wstio = stab_io(wstab) = stio_new();
462     else if (wstio->ifp)
463         do_close(wstab,FALSE);
464
465     if (pipe(fd) < 0)
466         goto badexit;
467     rstio->ifp = fdopen(fd[0], "r");
468     wstio->ofp = fdopen(fd[1], "w");
469     wstio->ifp = wstio->ofp;
470     rstio->type = '<';
471     wstio->type = '>';
472     if (!rstio->ifp || !wstio->ofp) {
473         if (rstio->ifp) fclose(rstio->ifp);
474         else close(fd[0]);
475         if (wstio->ofp) fclose(wstio->ofp);
476         else close(fd[1]);
477         goto badexit;
478     }
479
480     str_sset(str,&str_yes);
481     return;
482
483 badexit:
484     str_sset(str,&str_undef);
485     return;
486 }
487 #endif
488
489 bool
490 do_close(stab,explicit)
491 STAB *stab;
492 bool explicit;
493 {
494     bool retval = FALSE;
495     register STIO *stio;
496     int status;
497
498     if (!stab)
499         stab = argvstab;
500     if (!stab)
501         return FALSE;
502     stio = stab_io(stab);
503     if (!stio) {                /* never opened */
504         if (dowarn && explicit)
505             warn("Close on unopened file <%s>",stab_name(stab));
506         return FALSE;
507     }
508     if (stio->ifp) {
509         if (stio->type == '|') {
510             status = mypclose(stio->ifp);
511             retval = (status == 0);
512             statusvalue = (unsigned short)status & 0xffff;
513         }
514         else if (stio->type == '-')
515             retval = TRUE;
516         else {
517             if (stio->ofp && stio->ofp != stio->ifp) {          /* a socket */
518                 retval = (fclose(stio->ofp) != EOF);
519                 fclose(stio->ifp);      /* clear stdio, fd already closed */
520             }
521             else
522                 retval = (fclose(stio->ifp) != EOF);
523         }
524         stio->ofp = stio->ifp = Nullfp;
525     }
526     if (explicit)
527         stio->lines = 0;
528     stio->type = ' ';
529     return retval;
530 }
531
532 bool
533 do_eof(stab)
534 STAB *stab;
535 {
536     register STIO *stio;
537     int ch;
538
539     if (!stab) {                        /* eof() */
540         if (argvstab)
541             stio = stab_io(argvstab);
542         else
543             return TRUE;
544     }
545     else
546         stio = stab_io(stab);
547
548     if (!stio)
549         return TRUE;
550
551     while (stio->ifp) {
552
553 #ifdef STDSTDIO                 /* (the code works without this) */
554         if (stio->ifp->_cnt > 0)        /* cheat a little, since */
555             return FALSE;               /* this is the most usual case */
556 #endif
557
558         ch = getc(stio->ifp);
559         if (ch != EOF) {
560             (void)ungetc(ch, stio->ifp);
561             return FALSE;
562         }
563 #ifdef STDSTDIO
564         if (stio->ifp->_cnt < -1)
565             stio->ifp->_cnt = -1;
566 #endif
567         if (!stab) {                    /* not necessarily a real EOF yet? */
568             if (!nextargv(argvstab))    /* get another fp handy */
569                 return TRUE;
570         }
571         else
572             return TRUE;                /* normal fp, definitely end of file */
573     }
574     return TRUE;
575 }
576
577 long
578 do_tell(stab)
579 STAB *stab;
580 {
581     register STIO *stio;
582
583     if (!stab)
584         goto phooey;
585
586     stio = stab_io(stab);
587     if (!stio || !stio->ifp)
588         goto phooey;
589
590     if (feof(stio->ifp))
591         (void)fseek (stio->ifp, 0L, 2);         /* ultrix 1.2 workaround */
592
593     return ftell(stio->ifp);
594
595 phooey:
596     if (dowarn)
597         warn("tell() on unopened file");
598     return -1L;
599 }
600
601 bool
602 do_seek(stab, pos, whence)
603 STAB *stab;
604 long pos;
605 int whence;
606 {
607     register STIO *stio;
608
609     if (!stab)
610         goto nuts;
611
612     stio = stab_io(stab);
613     if (!stio || !stio->ifp)
614         goto nuts;
615
616     if (feof(stio->ifp))
617         (void)fseek (stio->ifp, 0L, 2);         /* ultrix 1.2 workaround */
618
619     return fseek(stio->ifp, pos, whence) >= 0;
620
621 nuts:
622     if (dowarn)
623         warn("seek() on unopened file");
624     return FALSE;
625 }
626
627 int
628 do_ctl(optype,stab,func,argstr)
629 int optype;
630 STAB *stab;
631 int func;
632 STR *argstr;
633 {
634     register STIO *stio;
635     register char *s;
636     int retval;
637
638     if (!stab || !argstr)
639         return -1;
640     stio = stab_io(stab);
641     if (!stio)
642         return -1;
643
644     if (argstr->str_pok || !argstr->str_nok) {
645         if (!argstr->str_pok)
646             s = str_get(argstr);
647
648 #ifdef IOCPARM_MASK
649 #ifndef IOCPARM_LEN
650 #define IOCPARM_LEN(x)  (((x) >> 16) & IOCPARM_MASK)
651 #endif
652 #endif
653 #ifdef IOCPARM_LEN
654         retval = IOCPARM_LEN(func);     /* on BSDish systes we're safe */
655 #else
656         retval = 256;                   /* otherwise guess at what's safe */
657 #endif
658         if (argstr->str_cur < retval) {
659             Str_Grow(argstr,retval+1);
660             argstr->str_cur = retval;
661         }
662
663         s = argstr->str_ptr;
664         s[argstr->str_cur] = 17;        /* a little sanity check here */
665     }
666     else {
667         retval = (int)str_gnum(argstr);
668 #ifdef MSDOS
669         s = (char*)(long)retval;                /* ouch */
670 #else
671         s = (char*)retval;              /* ouch */
672 #endif
673     }
674
675 #ifndef lint
676     if (optype == O_IOCTL)
677         retval = ioctl(fileno(stio->ifp), func, s);
678     else
679 #ifdef MSDOS
680         fatal("fcntl is not implemented");
681 #else
682 #ifdef HAS_FCNTL
683         retval = fcntl(fileno(stio->ifp), func, s);
684 #else
685         fatal("fcntl is not implemented");
686 #endif
687 #endif
688 #else /* lint */
689     retval = 0;
690 #endif /* lint */
691
692     if (argstr->str_pok) {
693         if (s[argstr->str_cur] != 17)
694             fatal("Return value overflowed string");
695         s[argstr->str_cur] = 0;         /* put our null back */
696     }
697     return retval;
698 }
699
700 int
701 do_stat(str,arg,gimme,arglast)
702 STR *str;
703 register ARG *arg;
704 int gimme;
705 int *arglast;
706 {
707     register ARRAY *ary = stack;
708     register int sp = arglast[0] + 1;
709     int max = 13;
710
711     if ((arg[1].arg_type & A_MASK) == A_WORD) {
712         tmpstab = arg[1].arg_ptr.arg_stab;
713         if (tmpstab != defstab) {
714             laststype = O_STAT;
715             statstab = tmpstab;
716             str_set(statname,"");
717             if (!stab_io(tmpstab) || !stab_io(tmpstab)->ifp ||
718               fstat(fileno(stab_io(tmpstab)->ifp),&statcache) < 0) {
719                 max = 0;
720                 laststatval = -1;
721             }
722         }
723         else if (laststatval < 0)
724             max = 0;
725     }
726     else {
727         str_set(statname,str_get(ary->ary_array[sp]));
728         statstab = Nullstab;
729 #ifdef HAS_LSTAT
730         laststype = arg->arg_type;
731         if (arg->arg_type == O_LSTAT)
732             laststatval = lstat(str_get(statname),&statcache);
733         else
734 #endif
735             laststatval = stat(str_get(statname),&statcache);
736         if (laststatval < 0)
737             max = 0;
738     }
739
740     if (gimme != G_ARRAY) {
741         if (max)
742             str_sset(str,&str_yes);
743         else
744             str_sset(str,&str_undef);
745         STABSET(str);
746         ary->ary_array[sp] = str;
747         return sp;
748     }
749     sp--;
750     if (max) {
751 #ifndef lint
752         (void)astore(ary,++sp,
753           str_2mortal(str_nmake((double)statcache.st_dev)));
754         (void)astore(ary,++sp,
755           str_2mortal(str_nmake((double)statcache.st_ino)));
756         (void)astore(ary,++sp,
757           str_2mortal(str_nmake((double)statcache.st_mode)));
758         (void)astore(ary,++sp,
759           str_2mortal(str_nmake((double)statcache.st_nlink)));
760         (void)astore(ary,++sp,
761           str_2mortal(str_nmake((double)statcache.st_uid)));
762         (void)astore(ary,++sp,
763           str_2mortal(str_nmake((double)statcache.st_gid)));
764         (void)astore(ary,++sp,
765           str_2mortal(str_nmake((double)statcache.st_rdev)));
766         (void)astore(ary,++sp,
767           str_2mortal(str_nmake((double)statcache.st_size)));
768         (void)astore(ary,++sp,
769           str_2mortal(str_nmake((double)statcache.st_atime)));
770         (void)astore(ary,++sp,
771           str_2mortal(str_nmake((double)statcache.st_mtime)));
772         (void)astore(ary,++sp,
773           str_2mortal(str_nmake((double)statcache.st_ctime)));
774 #ifdef STATBLOCKS
775         (void)astore(ary,++sp,
776           str_2mortal(str_nmake((double)statcache.st_blksize)));
777         (void)astore(ary,++sp,
778           str_2mortal(str_nmake((double)statcache.st_blocks)));
779 #else
780         (void)astore(ary,++sp,
781           str_2mortal(str_make("",0)));
782         (void)astore(ary,++sp,
783           str_2mortal(str_make("",0)));
784 #endif
785 #else /* lint */
786         (void)astore(ary,++sp,str_nmake(0.0));
787 #endif /* lint */
788     }
789     return sp;
790 }
791
792 #if !defined(HAS_TRUNCATE) && !defined(HAS_CHSIZE) && defined(F_FREESP)
793         /* code courtesy of William Kucharski */
794 #define HAS_CHSIZE
795
796 int chsize(fd, length)
797 int fd;                 /* file descriptor */
798 off_t length;           /* length to set file to */
799 {
800     extern long lseek();
801     struct flock fl;
802     struct stat filebuf;
803
804     if (fstat(fd, &filebuf) < 0)
805         return -1;
806
807     if (filebuf.st_size < length) {
808
809         /* extend file length */
810
811         if ((lseek(fd, (length - 1), 0)) < 0)
812             return -1;
813
814         /* write a "0" byte */
815
816         if ((write(fd, "", 1)) != 1)
817             return -1;
818     }
819     else {
820         /* truncate length */
821
822         fl.l_whence = 0;
823         fl.l_len = 0;
824         fl.l_start = length;
825         fl.l_type = F_WRLCK;    /* write lock on file space */
826
827         /*
828         * This relies on the UNDOCUMENTED F_FREESP argument to
829         * fcntl(2), which truncates the file so that it ends at the
830         * position indicated by fl.l_start.
831         *
832         * Will minor miracles never cease?
833         */
834
835         if (fcntl(fd, F_FREESP, &fl) < 0)
836             return -1;
837
838     }
839
840     return 0;
841 }
842 #endif /* F_FREESP */
843
844 int
845 do_truncate(str,arg,gimme,arglast)
846 STR *str;
847 register ARG *arg;
848 int gimme;
849 int *arglast;
850 {
851     register ARRAY *ary = stack;
852     register int sp = arglast[0] + 1;
853     off_t len = (off_t)str_gnum(ary->ary_array[sp+1]);
854     int result = 1;
855     STAB *tmpstab;
856
857 #if defined(HAS_TRUNCATE) || defined(HAS_CHSIZE)
858 #ifdef HAS_TRUNCATE
859     if ((arg[1].arg_type & A_MASK) == A_WORD) {
860         tmpstab = arg[1].arg_ptr.arg_stab;
861         if (!stab_io(tmpstab) ||
862           ftruncate(fileno(stab_io(tmpstab)->ifp), len) < 0)
863             result = 0;
864     }
865     else if (truncate(str_get(ary->ary_array[sp]), len) < 0)
866         result = 0;
867 #else
868     if ((arg[1].arg_type & A_MASK) == A_WORD) {
869         tmpstab = arg[1].arg_ptr.arg_stab;
870         if (!stab_io(tmpstab) ||
871           chsize(fileno(stab_io(tmpstab)->ifp), len) < 0)
872             result = 0;
873     }
874     else {
875         int tmpfd;
876
877         if ((tmpfd = open(str_get(ary->ary_array[sp]), 0)) < 0)
878             result = 0;
879         else {
880             if (chsize(tmpfd, len) < 0)
881                 result = 0;
882             close(tmpfd);
883         }
884     }
885 #endif
886
887     if (result)
888         str_sset(str,&str_yes);
889     else
890         str_sset(str,&str_undef);
891     STABSET(str);
892     ary->ary_array[sp] = str;
893     return sp;
894 #else
895     fatal("truncate not implemented");
896 #endif
897 }
898
899 int
900 looks_like_number(str)
901 STR *str;
902 {
903     register char *s;
904     register char *send;
905
906     if (!str->str_pok)
907         return TRUE;
908     s = str->str_ptr; 
909     send = s + str->str_cur;
910     while (isspace(*s))
911         s++;
912     if (s >= send)
913         return FALSE;
914     if (*s == '+' || *s == '-')
915         s++;
916     while (isdigit(*s))
917         s++;
918     if (s == send)
919         return TRUE;
920     if (*s == '.') 
921         s++;
922     else if (s == str->str_ptr)
923         return FALSE;
924     while (isdigit(*s))
925         s++;
926     if (s == send)
927         return TRUE;
928     if (*s == 'e' || *s == 'E') {
929         s++;
930         if (*s == '+' || *s == '-')
931             s++;
932         while (isdigit(*s))
933             s++;
934     }
935     while (isspace(*s))
936         s++;
937     if (s >= send)
938         return TRUE;
939     return FALSE;
940 }
941
942 bool
943 do_print(str,fp)
944 register STR *str;
945 FILE *fp;
946 {
947     register char *tmps;
948
949     if (!fp) {
950         if (dowarn)
951             warn("print to unopened file");
952         return FALSE;
953     }
954     if (!str)
955         return TRUE;
956     if (ofmt &&
957       ((str->str_nok && str->str_u.str_nval != 0.0)
958        || (looks_like_number(str) && str_gnum(str) != 0.0) ) ) {
959         fprintf(fp, ofmt, str->str_u.str_nval);
960         return !ferror(fp);
961     }
962     else {
963         tmps = str_get(str);
964         if (*tmps == 'S' && tmps[1] == 't' && tmps[2] == 'B' && tmps[3] == '\0'
965           && str->str_cur == sizeof(STBP) && strlen(tmps) < str->str_cur) {
966             STR *tmpstr = str_mortal(&str_undef);
967             stab_fullname(tmpstr,((STAB*)str));/* a stab value, be nice */
968             str = tmpstr;
969             tmps = str->str_ptr;
970             putc('*',fp);
971         }
972         if (str->str_cur && (fwrite(tmps,1,str->str_cur,fp) == 0 || ferror(fp)))
973             return FALSE;
974     }
975     return TRUE;
976 }
977
978 bool
979 do_aprint(arg,fp,arglast)
980 register ARG *arg;
981 register FILE *fp;
982 int *arglast;
983 {
984     register STR **st = stack->ary_array;
985     register int sp = arglast[1];
986     register int retval;
987     register int items = arglast[2] - sp;
988
989     if (!fp) {
990         if (dowarn)
991             warn("print to unopened file");
992         return FALSE;
993     }
994     st += ++sp;
995     if (arg->arg_type == O_PRTF) {
996         do_sprintf(arg->arg_ptr.arg_str,items,st);
997         retval = do_print(arg->arg_ptr.arg_str,fp);
998     }
999     else {
1000         retval = (items <= 0);
1001         for (; items > 0; items--,st++) {
1002             if (retval && ofslen) {
1003                 if (fwrite(ofs, 1, ofslen, fp) == 0 || ferror(fp)) {
1004                     retval = FALSE;
1005                     break;
1006                 }
1007             }
1008             if (!(retval = do_print(*st, fp)))
1009                 break;
1010         }
1011         if (retval && orslen)
1012             if (fwrite(ors, 1, orslen, fp) == 0 || ferror(fp))
1013                 retval = FALSE;
1014     }
1015     return retval;
1016 }
1017
1018 int
1019 mystat(arg,str)
1020 ARG *arg;
1021 STR *str;
1022 {
1023     STIO *stio;
1024
1025     laststype = O_STAT;
1026     if (arg[1].arg_type & A_DONT) {
1027         stio = stab_io(arg[1].arg_ptr.arg_stab);
1028         if (stio && stio->ifp) {
1029             statstab = arg[1].arg_ptr.arg_stab;
1030             str_set(statname,"");
1031             return (laststatval = fstat(fileno(stio->ifp), &statcache));
1032         }
1033         else {
1034             if (arg[1].arg_ptr.arg_stab == defstab)
1035                 return laststatval;
1036             if (dowarn)
1037                 warn("Stat on unopened file <%s>",
1038                   stab_name(arg[1].arg_ptr.arg_stab));
1039             statstab = Nullstab;
1040             str_set(statname,"");
1041             return (laststatval = -1);
1042         }
1043     }
1044     else {
1045         statstab = Nullstab;
1046         str_set(statname,str_get(str));
1047         return (laststatval = stat(str_get(str),&statcache));
1048     }
1049 }
1050
1051 int
1052 mylstat(arg,str)
1053 ARG *arg;
1054 STR *str;
1055 {
1056     if (arg[1].arg_type & A_DONT) {
1057         if (arg[1].arg_ptr.arg_stab == defstab) {
1058             if (laststype != O_LSTAT)
1059                 fatal("The stat preceding -l _ wasn't an lstat");
1060             return laststatval;
1061         }
1062         fatal("You can't use -l on a filehandle");
1063     }
1064
1065     laststype = O_LSTAT;
1066     statstab = Nullstab;
1067     str_set(statname,str_get(str));
1068 #ifdef HAS_LSTAT
1069     return (laststatval = lstat(str_get(str),&statcache));
1070 #else
1071     return (laststatval = stat(str_get(str),&statcache));
1072 #endif
1073 }
1074
1075 STR *
1076 do_fttext(arg,str)
1077 register ARG *arg;
1078 STR *str;
1079 {
1080     int i;
1081     int len;
1082     int odd = 0;
1083     STDCHAR tbuf[512];
1084     register STDCHAR *s;
1085     register STIO *stio;
1086
1087     if (arg[1].arg_type & A_DONT) {
1088         if (arg[1].arg_ptr.arg_stab == defstab) {
1089             if (statstab)
1090                 stio = stab_io(statstab);
1091             else {
1092                 str = statname;
1093                 goto really_filename;
1094             }
1095         }
1096         else {
1097             statstab = arg[1].arg_ptr.arg_stab;
1098             str_set(statname,"");
1099             stio = stab_io(statstab);
1100         }
1101         if (stio && stio->ifp) {
1102 #ifdef STDSTDIO
1103             fstat(fileno(stio->ifp),&statcache);
1104             if (stio->ifp->_cnt <= 0) {
1105                 i = getc(stio->ifp);
1106                 if (i != EOF)
1107                     (void)ungetc(i,stio->ifp);
1108             }
1109             if (stio->ifp->_cnt <= 0)   /* null file is anything */
1110                 return &str_yes;
1111             len = stio->ifp->_cnt + (stio->ifp->_ptr - stio->ifp->_base);
1112             s = stio->ifp->_base;
1113 #else
1114             fatal("-T and -B not implemented on filehandles\n");
1115 #endif
1116         }
1117         else {
1118             if (dowarn)
1119                 warn("Test on unopened file <%s>",
1120                   stab_name(arg[1].arg_ptr.arg_stab));
1121             return &str_undef;
1122         }
1123     }
1124     else {
1125         statstab = Nullstab;
1126         str_set(statname,str_get(str));
1127       really_filename:
1128         i = open(str_get(str),0);
1129         if (i < 0)
1130             return &str_undef;
1131         fstat(i,&statcache);
1132         len = read(i,tbuf,512);
1133         (void)close(i);
1134         if (len <= 0)           /* null file is anything */
1135             return &str_yes;
1136         s = tbuf;
1137     }
1138
1139     /* now scan s to look for textiness */
1140
1141     for (i = 0; i < len; i++,s++) {
1142         if (!*s) {                      /* null never allowed in text */
1143             odd += len;
1144             break;
1145         }
1146         else if (*s & 128)
1147             odd++;
1148         else if (*s < 32 &&
1149           *s != '\n' && *s != '\r' && *s != '\b' &&
1150           *s != '\t' && *s != '\f' && *s != 27)
1151             odd++;
1152     }
1153
1154     if ((odd * 10 > len) == (arg->arg_type == O_FTTEXT)) /* allow 10% odd */
1155         return &str_no;
1156     else
1157         return &str_yes;
1158 }
1159
1160 bool
1161 do_aexec(really,arglast)
1162 STR *really;
1163 int *arglast;
1164 {
1165     register STR **st = stack->ary_array;
1166     register int sp = arglast[1];
1167     register int items = arglast[2] - sp;
1168     register char **a;
1169     char **argv;
1170     char *tmps;
1171
1172     if (items) {
1173         New(401,argv, items+1, char*);
1174         a = argv;
1175         for (st += ++sp; items > 0; items--,st++) {
1176             if (*st)
1177                 *a++ = str_get(*st);
1178             else
1179                 *a++ = "";
1180         }
1181         *a = Nullch;
1182 #ifdef TAINT
1183         if (*argv[0] != '/')    /* will execvp use PATH? */
1184             taintenv();         /* testing IFS here is overkill, probably */
1185 #endif
1186         if (really && *(tmps = str_get(really)))
1187             execvp(tmps,argv);
1188         else
1189             execvp(argv[0],argv);
1190         Safefree(argv);
1191     }
1192     return FALSE;
1193 }
1194
1195 static char **Argv = Null(char **);
1196 static char *Cmd = Nullch;
1197
1198 void
1199 do_execfree()
1200 {
1201     if (Argv) {
1202         Safefree(Argv);
1203         Argv = Null(char **);
1204     }
1205     if (Cmd) {
1206         Safefree(Cmd);
1207         Cmd = Nullch;
1208     }
1209 }
1210
1211 bool
1212 do_exec(cmd)
1213 char *cmd;
1214 {
1215     register char **a;
1216     register char *s;
1217     char flags[10];
1218
1219     /* save an extra exec if possible */
1220
1221 #ifdef CSH
1222     if (strnEQ(cmd,cshname,cshlen) && strnEQ(cmd+cshlen," -c",3)) {
1223         strcpy(flags,"-c");
1224         s = cmd+cshlen+3;
1225         if (*s == 'f') {
1226             s++;
1227             strcat(flags,"f");
1228         }
1229         if (*s == ' ')
1230             s++;
1231         if (*s++ == '\'') {
1232             char *ncmd = s;
1233
1234             while (*s)
1235                 s++;
1236             if (s[-1] == '\n')
1237                 *--s = '\0';
1238             if (s[-1] == '\'') {
1239                 *--s = '\0';
1240                 execl(cshname,"csh", flags,ncmd,(char*)0);
1241                 *s = '\'';
1242                 return FALSE;
1243             }
1244         }
1245     }
1246 #endif /* CSH */
1247
1248     /* see if there are shell metacharacters in it */
1249
1250     for (s = cmd; *s && isalpha(*s); s++) ;     /* catch VAR=val gizmo */
1251     if (*s == '=')
1252         goto doshell;
1253     for (s = cmd; *s; s++) {
1254         if (*s != ' ' && !isalpha(*s) && index("$&*(){}[]'\";\\|?<>~`\n",*s)) {
1255             if (*s == '\n' && !s[1]) {
1256                 *s = '\0';
1257                 break;
1258             }
1259           doshell:
1260             execl("/bin/sh","sh","-c",cmd,(char*)0);
1261             return FALSE;
1262         }
1263     }
1264     New(402,Argv, (s - cmd) / 2 + 2, char*);
1265     Cmd = nsavestr(cmd, s-cmd);
1266     a = Argv;
1267     for (s = Cmd; *s;) {
1268         while (*s && isspace(*s)) s++;
1269         if (*s)
1270             *(a++) = s;
1271         while (*s && !isspace(*s)) s++;
1272         if (*s)
1273             *s++ = '\0';
1274     }
1275     *a = Nullch;
1276     if (Argv[0]) {
1277         execvp(Argv[0],Argv);
1278         if (errno == ENOEXEC) {         /* for system V NIH syndrome */
1279             do_execfree();
1280             goto doshell;
1281         }
1282     }
1283     do_execfree();
1284     return FALSE;
1285 }
1286
1287 #ifdef HAS_SOCKET
1288 int
1289 do_socket(stab, arglast)
1290 STAB *stab;
1291 int *arglast;
1292 {
1293     register STR **st = stack->ary_array;
1294     register int sp = arglast[1];
1295     register STIO *stio;
1296     int domain, type, protocol, fd;
1297
1298     if (!stab)
1299         return FALSE;
1300
1301     stio = stab_io(stab);
1302     if (!stio)
1303         stio = stab_io(stab) = stio_new();
1304     else if (stio->ifp)
1305         do_close(stab,FALSE);
1306
1307     domain = (int)str_gnum(st[++sp]);
1308     type = (int)str_gnum(st[++sp]);
1309     protocol = (int)str_gnum(st[++sp]);
1310 #ifdef TAINT
1311     taintproper("Insecure dependency in socket");
1312 #endif
1313     fd = socket(domain,type,protocol);
1314     if (fd < 0)
1315         return FALSE;
1316     stio->ifp = fdopen(fd, "r");        /* stdio gets confused about sockets */
1317     stio->ofp = fdopen(fd, "w");
1318     stio->type = 's';
1319     if (!stio->ifp || !stio->ofp) {
1320         if (stio->ifp) fclose(stio->ifp);
1321         if (stio->ofp) fclose(stio->ofp);
1322         if (!stio->ifp && !stio->ofp) close(fd);
1323         return FALSE;
1324     }
1325
1326     return TRUE;
1327 }
1328
1329 int
1330 do_bind(stab, arglast)
1331 STAB *stab;
1332 int *arglast;
1333 {
1334     register STR **st = stack->ary_array;
1335     register int sp = arglast[1];
1336     register STIO *stio;
1337     char *addr;
1338
1339     if (!stab)
1340         goto nuts;
1341
1342     stio = stab_io(stab);
1343     if (!stio || !stio->ifp)
1344         goto nuts;
1345
1346     addr = str_get(st[++sp]);
1347 #ifdef TAINT
1348     taintproper("Insecure dependency in bind");
1349 #endif
1350     return bind(fileno(stio->ifp), addr, st[sp]->str_cur) >= 0;
1351
1352 nuts:
1353     if (dowarn)
1354         warn("bind() on closed fd");
1355     return FALSE;
1356
1357 }
1358
1359 int
1360 do_connect(stab, arglast)
1361 STAB *stab;
1362 int *arglast;
1363 {
1364     register STR **st = stack->ary_array;
1365     register int sp = arglast[1];
1366     register STIO *stio;
1367     char *addr;
1368
1369     if (!stab)
1370         goto nuts;
1371
1372     stio = stab_io(stab);
1373     if (!stio || !stio->ifp)
1374         goto nuts;
1375
1376     addr = str_get(st[++sp]);
1377 #ifdef TAINT
1378     taintproper("Insecure dependency in connect");
1379 #endif
1380     return connect(fileno(stio->ifp), addr, st[sp]->str_cur) >= 0;
1381
1382 nuts:
1383     if (dowarn)
1384         warn("connect() on closed fd");
1385     return FALSE;
1386
1387 }
1388
1389 int
1390 do_listen(stab, arglast)
1391 STAB *stab;
1392 int *arglast;
1393 {
1394     register STR **st = stack->ary_array;
1395     register int sp = arglast[1];
1396     register STIO *stio;
1397     int backlog;
1398
1399     if (!stab)
1400         goto nuts;
1401
1402     stio = stab_io(stab);
1403     if (!stio || !stio->ifp)
1404         goto nuts;
1405
1406     backlog = (int)str_gnum(st[++sp]);
1407     return listen(fileno(stio->ifp), backlog) >= 0;
1408
1409 nuts:
1410     if (dowarn)
1411         warn("listen() on closed fd");
1412     return FALSE;
1413 }
1414
1415 void
1416 do_accept(str, nstab, gstab)
1417 STR *str;
1418 STAB *nstab;
1419 STAB *gstab;
1420 {
1421     register STIO *nstio;
1422     register STIO *gstio;
1423     int len = sizeof buf;
1424     int fd;
1425
1426     if (!nstab)
1427         goto badexit;
1428     if (!gstab)
1429         goto nuts;
1430
1431     gstio = stab_io(gstab);
1432     nstio = stab_io(nstab);
1433
1434     if (!gstio || !gstio->ifp)
1435         goto nuts;
1436     if (!nstio)
1437         nstio = stab_io(nstab) = stio_new();
1438     else if (nstio->ifp)
1439         do_close(nstab,FALSE);
1440
1441     fd = accept(fileno(gstio->ifp),(struct sockaddr *)buf,&len);
1442     if (fd < 0)
1443         goto badexit;
1444     nstio->ifp = fdopen(fd, "r");
1445     nstio->ofp = fdopen(fd, "w");
1446     nstio->type = 's';
1447     if (!nstio->ifp || !nstio->ofp) {
1448         if (nstio->ifp) fclose(nstio->ifp);
1449         if (nstio->ofp) fclose(nstio->ofp);
1450         if (!nstio->ifp && !nstio->ofp) close(fd);
1451         goto badexit;
1452     }
1453
1454     str_nset(str, buf, len);
1455     return;
1456
1457 nuts:
1458     if (dowarn)
1459         warn("accept() on closed fd");
1460 badexit:
1461     str_sset(str,&str_undef);
1462     return;
1463 }
1464
1465 int
1466 do_shutdown(stab, arglast)
1467 STAB *stab;
1468 int *arglast;
1469 {
1470     register STR **st = stack->ary_array;
1471     register int sp = arglast[1];
1472     register STIO *stio;
1473     int how;
1474
1475     if (!stab)
1476         goto nuts;
1477
1478     stio = stab_io(stab);
1479     if (!stio || !stio->ifp)
1480         goto nuts;
1481
1482     how = (int)str_gnum(st[++sp]);
1483     return shutdown(fileno(stio->ifp), how) >= 0;
1484
1485 nuts:
1486     if (dowarn)
1487         warn("shutdown() on closed fd");
1488     return FALSE;
1489
1490 }
1491
1492 int
1493 do_sopt(optype, stab, arglast)
1494 int optype;
1495 STAB *stab;
1496 int *arglast;
1497 {
1498     register STR **st = stack->ary_array;
1499     register int sp = arglast[1];
1500     register STIO *stio;
1501     int fd;
1502     int lvl;
1503     int optname;
1504
1505     if (!stab)
1506         goto nuts;
1507
1508     stio = stab_io(stab);
1509     if (!stio || !stio->ifp)
1510         goto nuts;
1511
1512     fd = fileno(stio->ifp);
1513     lvl = (int)str_gnum(st[sp+1]);
1514     optname = (int)str_gnum(st[sp+2]);
1515     switch (optype) {
1516     case O_GSOCKOPT:
1517         st[sp] = str_2mortal(str_new(257));
1518         st[sp]->str_cur = 256;
1519         st[sp]->str_pok = 1;
1520         if (getsockopt(fd, lvl, optname, st[sp]->str_ptr, &st[sp]->str_cur) < 0)
1521             goto nuts;
1522         break;
1523     case O_SSOCKOPT:
1524         st[sp] = st[sp+3];
1525         if (setsockopt(fd, lvl, optname, st[sp]->str_ptr, st[sp]->str_cur) < 0)
1526             goto nuts;
1527         st[sp] = &str_yes;
1528         break;
1529     }
1530     
1531     return sp;
1532
1533 nuts:
1534     if (dowarn)
1535         warn("[gs]etsockopt() on closed fd");
1536     st[sp] = &str_undef;
1537     return sp;
1538
1539 }
1540
1541 int
1542 do_getsockname(optype, stab, arglast)
1543 int optype;
1544 STAB *stab;
1545 int *arglast;
1546 {
1547     register STR **st = stack->ary_array;
1548     register int sp = arglast[1];
1549     register STIO *stio;
1550     int fd;
1551
1552     if (!stab)
1553         goto nuts;
1554
1555     stio = stab_io(stab);
1556     if (!stio || !stio->ifp)
1557         goto nuts;
1558
1559     st[sp] = str_2mortal(str_new(257));
1560     st[sp]->str_cur = 256;
1561     st[sp]->str_pok = 1;
1562     fd = fileno(stio->ifp);
1563     switch (optype) {
1564     case O_GETSOCKNAME:
1565         if (getsockname(fd, st[sp]->str_ptr, &st[sp]->str_cur) < 0)
1566             goto nuts2;
1567         break;
1568     case O_GETPEERNAME:
1569         if (getpeername(fd, st[sp]->str_ptr, &st[sp]->str_cur) < 0)
1570             goto nuts2;
1571         break;
1572     }
1573     
1574     return sp;
1575
1576 nuts:
1577     if (dowarn)
1578         warn("get{sock,peer}name() on closed fd");
1579 nuts2:
1580     st[sp] = &str_undef;
1581     return sp;
1582
1583 }
1584
1585 int
1586 do_ghent(which,gimme,arglast)
1587 int which;
1588 int gimme;
1589 int *arglast;
1590 {
1591     register ARRAY *ary = stack;
1592     register int sp = arglast[0];
1593     register char **elem;
1594     register STR *str;
1595     struct hostent *gethostbyname();
1596     struct hostent *gethostbyaddr();
1597 #ifdef HAS_GETHOSTENT
1598     struct hostent *gethostent();
1599 #endif
1600     struct hostent *hent;
1601     unsigned long len;
1602
1603     if (gimme != G_ARRAY) {
1604         astore(ary, ++sp, str_mortal(&str_undef));
1605         return sp;
1606     }
1607
1608     if (which == O_GHBYNAME) {
1609         char *name = str_get(ary->ary_array[sp+1]);
1610
1611         hent = gethostbyname(name);
1612     }
1613     else if (which == O_GHBYADDR) {
1614         STR *addrstr = ary->ary_array[sp+1];
1615         int addrtype = (int)str_gnum(ary->ary_array[sp+2]);
1616         char *addr = str_get(addrstr);
1617
1618         hent = gethostbyaddr(addr,addrstr->str_cur,addrtype);
1619     }
1620     else
1621 #ifdef HAS_GETHOSTENT
1622         hent = gethostent();
1623 #else
1624         fatal("gethostent not implemented");
1625 #endif
1626     if (hent) {
1627 #ifndef lint
1628         (void)astore(ary, ++sp, str = str_mortal(&str_no));
1629         str_set(str, hent->h_name);
1630         (void)astore(ary, ++sp, str = str_mortal(&str_no));
1631         for (elem = hent->h_aliases; *elem; elem++) {
1632             str_cat(str, *elem);
1633             if (elem[1])
1634                 str_ncat(str," ",1);
1635         }
1636         (void)astore(ary, ++sp, str = str_mortal(&str_no));
1637         str_numset(str, (double)hent->h_addrtype);
1638         (void)astore(ary, ++sp, str = str_mortal(&str_no));
1639         len = hent->h_length;
1640         str_numset(str, (double)len);
1641 #ifdef h_addr
1642         for (elem = hent->h_addr_list; *elem; elem++) {
1643             (void)astore(ary, ++sp, str = str_mortal(&str_no));
1644             str_nset(str, *elem, len);
1645         }
1646 #else
1647         (void)astore(ary, ++sp, str = str_mortal(&str_no));
1648         str_nset(str, hent->h_addr, len);
1649 #endif /* h_addr */
1650 #else /* lint */
1651         elem = Nullch;
1652         elem = elem;
1653         (void)astore(ary, ++sp, str_mortal(&str_no));
1654 #endif /* lint */
1655     }
1656
1657     return sp;
1658 }
1659
1660 int
1661 do_gnent(which,gimme,arglast)
1662 int which;
1663 int gimme;
1664 int *arglast;
1665 {
1666     register ARRAY *ary = stack;
1667     register int sp = arglast[0];
1668     register char **elem;
1669     register STR *str;
1670     struct netent *getnetbyname();
1671     struct netent *getnetbyaddr();
1672     struct netent *getnetent();
1673     struct netent *nent;
1674
1675     if (gimme != G_ARRAY) {
1676         astore(ary, ++sp, str_mortal(&str_undef));
1677         return sp;
1678     }
1679
1680     if (which == O_GNBYNAME) {
1681         char *name = str_get(ary->ary_array[sp+1]);
1682
1683         nent = getnetbyname(name);
1684     }
1685     else if (which == O_GNBYADDR) {
1686         unsigned long addr = U_L(str_gnum(ary->ary_array[sp+1]));
1687         int addrtype = (int)str_gnum(ary->ary_array[sp+2]);
1688
1689         nent = getnetbyaddr((long)addr,addrtype);
1690     }
1691     else
1692         nent = getnetent();
1693
1694     if (nent) {
1695 #ifndef lint
1696         (void)astore(ary, ++sp, str = str_mortal(&str_no));
1697         str_set(str, nent->n_name);
1698         (void)astore(ary, ++sp, str = str_mortal(&str_no));
1699         for (elem = nent->n_aliases; *elem; elem++) {
1700             str_cat(str, *elem);
1701             if (elem[1])
1702                 str_ncat(str," ",1);
1703         }
1704         (void)astore(ary, ++sp, str = str_mortal(&str_no));
1705         str_numset(str, (double)nent->n_addrtype);
1706         (void)astore(ary, ++sp, str = str_mortal(&str_no));
1707         str_numset(str, (double)nent->n_net);
1708 #else /* lint */
1709         elem = Nullch;
1710         elem = elem;
1711         (void)astore(ary, ++sp, str_mortal(&str_no));
1712 #endif /* lint */
1713     }
1714
1715     return sp;
1716 }
1717
1718 int
1719 do_gpent(which,gimme,arglast)
1720 int which;
1721 int gimme;
1722 int *arglast;
1723 {
1724     register ARRAY *ary = stack;
1725     register int sp = arglast[0];
1726     register char **elem;
1727     register STR *str;
1728     struct protoent *getprotobyname();
1729     struct protoent *getprotobynumber();
1730     struct protoent *getprotoent();
1731     struct protoent *pent;
1732
1733     if (gimme != G_ARRAY) {
1734         astore(ary, ++sp, str_mortal(&str_undef));
1735         return sp;
1736     }
1737
1738     if (which == O_GPBYNAME) {
1739         char *name = str_get(ary->ary_array[sp+1]);
1740
1741         pent = getprotobyname(name);
1742     }
1743     else if (which == O_GPBYNUMBER) {
1744         int proto = (int)str_gnum(ary->ary_array[sp+1]);
1745
1746         pent = getprotobynumber(proto);
1747     }
1748     else
1749         pent = getprotoent();
1750
1751     if (pent) {
1752 #ifndef lint
1753         (void)astore(ary, ++sp, str = str_mortal(&str_no));
1754         str_set(str, pent->p_name);
1755         (void)astore(ary, ++sp, str = str_mortal(&str_no));
1756         for (elem = pent->p_aliases; *elem; elem++) {
1757             str_cat(str, *elem);
1758             if (elem[1])
1759                 str_ncat(str," ",1);
1760         }
1761         (void)astore(ary, ++sp, str = str_mortal(&str_no));
1762         str_numset(str, (double)pent->p_proto);
1763 #else /* lint */
1764         elem = Nullch;
1765         elem = elem;
1766         (void)astore(ary, ++sp, str_mortal(&str_no));
1767 #endif /* lint */
1768     }
1769
1770     return sp;
1771 }
1772
1773 int
1774 do_gsent(which,gimme,arglast)
1775 int which;
1776 int gimme;
1777 int *arglast;
1778 {
1779     register ARRAY *ary = stack;
1780     register int sp = arglast[0];
1781     register char **elem;
1782     register STR *str;
1783     struct servent *getservbyname();
1784     struct servent *getservbynumber();
1785     struct servent *getservent();
1786     struct servent *sent;
1787
1788     if (gimme != G_ARRAY) {
1789         astore(ary, ++sp, str_mortal(&str_undef));
1790         return sp;
1791     }
1792
1793     if (which == O_GSBYNAME) {
1794         char *name = str_get(ary->ary_array[sp+1]);
1795         char *proto = str_get(ary->ary_array[sp+2]);
1796
1797         if (proto && !*proto)
1798             proto = Nullch;
1799
1800         sent = getservbyname(name,proto);
1801     }
1802     else if (which == O_GSBYPORT) {
1803         int port = (int)str_gnum(ary->ary_array[sp+1]);
1804         char *proto = str_get(ary->ary_array[sp+2]);
1805
1806         sent = getservbyport(port,proto);
1807     }
1808     else
1809         sent = getservent();
1810     if (sent) {
1811 #ifndef lint
1812         (void)astore(ary, ++sp, str = str_mortal(&str_no));
1813         str_set(str, sent->s_name);
1814         (void)astore(ary, ++sp, str = str_mortal(&str_no));
1815         for (elem = sent->s_aliases; *elem; elem++) {
1816             str_cat(str, *elem);
1817             if (elem[1])
1818                 str_ncat(str," ",1);
1819         }
1820         (void)astore(ary, ++sp, str = str_mortal(&str_no));
1821 #ifdef HAS_NTOHS
1822         str_numset(str, (double)ntohs(sent->s_port));
1823 #else
1824         str_numset(str, (double)(sent->s_port));
1825 #endif
1826         (void)astore(ary, ++sp, str = str_mortal(&str_no));
1827         str_set(str, sent->s_proto);
1828 #else /* lint */
1829         elem = Nullch;
1830         elem = elem;
1831         (void)astore(ary, ++sp, str_mortal(&str_no));
1832 #endif /* lint */
1833     }
1834
1835     return sp;
1836 }
1837
1838 #endif /* HAS_SOCKET */
1839
1840 #ifdef HAS_SELECT
1841 int
1842 do_select(gimme,arglast)
1843 int gimme;
1844 int *arglast;
1845 {
1846     register STR **st = stack->ary_array;
1847     register int sp = arglast[0];
1848     register int i;
1849     register int j;
1850     register char *s;
1851     register STR *str;
1852     double value;
1853     int maxlen = 0;
1854     int nfound;
1855     struct timeval timebuf;
1856     struct timeval *tbuf = &timebuf;
1857     int growsize;
1858 #if BYTEORDER != 0x1234 && BYTEORDER != 0x12345678
1859     int masksize;
1860     int offset;
1861     char *fd_sets[4];
1862     int k;
1863
1864 #if BYTEORDER & 0xf0000
1865 #define ORDERBYTE (0x88888888 - BYTEORDER)
1866 #else
1867 #define ORDERBYTE (0x4444 - BYTEORDER)
1868 #endif
1869
1870 #endif
1871
1872     for (i = 1; i <= 3; i++) {
1873         j = st[sp+i]->str_cur;
1874         if (maxlen < j)
1875             maxlen = j;
1876     }
1877
1878 #if BYTEORDER == 0x1234 || BYTEORDER == 0x12345678
1879     growsize = maxlen;          /* little endians can use vecs directly */
1880 #else
1881 #ifdef NFDBITS
1882
1883 #ifndef NBBY
1884 #define NBBY 8
1885 #endif
1886
1887     masksize = NFDBITS / NBBY;
1888 #else
1889     masksize = sizeof(long);    /* documented int, everyone seems to use long */
1890 #endif
1891     growsize = maxlen + (masksize - (maxlen % masksize));
1892     Zero(&fd_sets[0], 4, char*);
1893 #endif
1894
1895     for (i = 1; i <= 3; i++) {
1896         str = st[sp+i];
1897         j = str->str_len;
1898         if (j < growsize) {
1899             if (str->str_pok) {
1900                 Str_Grow(str,growsize);
1901                 s = str_get(str) + j;
1902                 while (++j <= growsize) {
1903                     *s++ = '\0';
1904                 }
1905             }
1906             else if (str->str_ptr) {
1907                 Safefree(str->str_ptr);
1908                 str->str_ptr = Nullch;
1909             }
1910         }
1911 #if BYTEORDER != 0x1234 && BYTEORDER != 0x12345678
1912         s = str->str_ptr;
1913         if (s) {
1914             New(403, fd_sets[i], growsize, char);
1915             for (offset = 0; offset < growsize; offset += masksize) {
1916                 for (j = 0, k=ORDERBYTE; j < masksize; j++, (k >>= 4))
1917                     fd_sets[i][j+offset] = s[(k % masksize) + offset];
1918             }
1919         }
1920 #endif
1921     }
1922     str = st[sp+4];
1923     if (str->str_nok || str->str_pok) {
1924         value = str_gnum(str);
1925         if (value < 0.0)
1926             value = 0.0;
1927         timebuf.tv_sec = (long)value;
1928         value -= (double)timebuf.tv_sec;
1929         timebuf.tv_usec = (long)(value * 1000000.0);
1930     }
1931     else
1932         tbuf = Null(struct timeval*);
1933
1934 #if BYTEORDER == 0x1234 || BYTEORDER == 0x12345678
1935     nfound = select(
1936         maxlen * 8,
1937         st[sp+1]->str_ptr,
1938         st[sp+2]->str_ptr,
1939         st[sp+3]->str_ptr,
1940         tbuf);
1941 #else
1942     nfound = select(
1943         maxlen * 8,
1944         fd_sets[1],
1945         fd_sets[2],
1946         fd_sets[3],
1947         tbuf);
1948     for (i = 1; i <= 3; i++) {
1949         if (fd_sets[i]) {
1950             str = st[sp+i];
1951             s = str->str_ptr;
1952             for (offset = 0; offset < growsize; offset += masksize) {
1953                 for (j = 0, k=ORDERBYTE; j < masksize; j++, (k >>= 4))
1954                     s[(k % masksize) + offset] = fd_sets[i][j+offset];
1955             }
1956         }
1957     }
1958 #endif
1959
1960     st[++sp] = str_mortal(&str_no);
1961     str_numset(st[sp], (double)nfound);
1962     if (gimme == G_ARRAY && tbuf) {
1963         value = (double)(timebuf.tv_sec) +
1964                 (double)(timebuf.tv_usec) / 1000000.0;
1965         st[++sp] = str_mortal(&str_no);
1966         str_numset(st[sp], value);
1967     }
1968     return sp;
1969 }
1970 #endif /* SELECT */
1971
1972 #ifdef HAS_SOCKET
1973 int
1974 do_spair(stab1, stab2, arglast)
1975 STAB *stab1;
1976 STAB *stab2;
1977 int *arglast;
1978 {
1979     register STR **st = stack->ary_array;
1980     register int sp = arglast[2];
1981     register STIO *stio1;
1982     register STIO *stio2;
1983     int domain, type, protocol, fd[2];
1984
1985     if (!stab1 || !stab2)
1986         return FALSE;
1987
1988     stio1 = stab_io(stab1);
1989     stio2 = stab_io(stab2);
1990     if (!stio1)
1991         stio1 = stab_io(stab1) = stio_new();
1992     else if (stio1->ifp)
1993         do_close(stab1,FALSE);
1994     if (!stio2)
1995         stio2 = stab_io(stab2) = stio_new();
1996     else if (stio2->ifp)
1997         do_close(stab2,FALSE);
1998
1999     domain = (int)str_gnum(st[++sp]);
2000     type = (int)str_gnum(st[++sp]);
2001     protocol = (int)str_gnum(st[++sp]);
2002 #ifdef TAINT
2003     taintproper("Insecure dependency in socketpair");
2004 #endif
2005 #ifdef HAS_SOCKETPAIR
2006     if (socketpair(domain,type,protocol,fd) < 0)
2007         return FALSE;
2008 #else
2009     fatal("Socketpair unimplemented");
2010 #endif
2011     stio1->ifp = fdopen(fd[0], "r");
2012     stio1->ofp = fdopen(fd[0], "w");
2013     stio1->type = 's';
2014     stio2->ifp = fdopen(fd[1], "r");
2015     stio2->ofp = fdopen(fd[1], "w");
2016     stio2->type = 's';
2017     if (!stio1->ifp || !stio1->ofp || !stio2->ifp || !stio2->ofp) {
2018         if (stio1->ifp) fclose(stio1->ifp);
2019         if (stio1->ofp) fclose(stio1->ofp);
2020         if (!stio1->ifp && !stio1->ofp) close(fd[0]);
2021         if (stio2->ifp) fclose(stio2->ifp);
2022         if (stio2->ofp) fclose(stio2->ofp);
2023         if (!stio2->ifp && !stio2->ofp) close(fd[1]);
2024         return FALSE;
2025     }
2026
2027     return TRUE;
2028 }
2029
2030 #endif /* HAS_SOCKET */
2031
2032 int
2033 do_gpwent(which,gimme,arglast)
2034 int which;
2035 int gimme;
2036 int *arglast;
2037 {
2038 #ifdef I_PWD
2039     register ARRAY *ary = stack;
2040     register int sp = arglast[0];
2041     register STR *str;
2042     struct passwd *getpwnam();
2043     struct passwd *getpwuid();
2044     struct passwd *getpwent();
2045     struct passwd *pwent;
2046
2047     if (gimme != G_ARRAY) {
2048         astore(ary, ++sp, str_mortal(&str_undef));
2049         return sp;
2050     }
2051
2052     if (which == O_GPWNAM) {
2053         char *name = str_get(ary->ary_array[sp+1]);
2054
2055         pwent = getpwnam(name);
2056     }
2057     else if (which == O_GPWUID) {
2058         int uid = (int)str_gnum(ary->ary_array[sp+1]);
2059
2060         pwent = getpwuid(uid);
2061     }
2062     else
2063         pwent = getpwent();
2064
2065     if (pwent) {
2066         (void)astore(ary, ++sp, str = str_mortal(&str_no));
2067         str_set(str, pwent->pw_name);
2068         (void)astore(ary, ++sp, str = str_mortal(&str_no));
2069         str_set(str, pwent->pw_passwd);
2070         (void)astore(ary, ++sp, str = str_mortal(&str_no));
2071         str_numset(str, (double)pwent->pw_uid);
2072         (void)astore(ary, ++sp, str = str_mortal(&str_no));
2073         str_numset(str, (double)pwent->pw_gid);
2074         (void)astore(ary, ++sp, str = str_mortal(&str_no));
2075 #ifdef PWCHANGE
2076         str_numset(str, (double)pwent->pw_change);
2077 #else
2078 #ifdef PWQUOTA
2079         str_numset(str, (double)pwent->pw_quota);
2080 #else
2081 #ifdef PWAGE
2082         str_set(str, pwent->pw_age);
2083 #endif
2084 #endif
2085 #endif
2086         (void)astore(ary, ++sp, str = str_mortal(&str_no));
2087 #ifdef PWCLASS
2088         str_set(str,pwent->pw_class);
2089 #else
2090 #ifdef PWCOMMENT
2091         str_set(str, pwent->pw_comment);
2092 #endif
2093 #endif
2094         (void)astore(ary, ++sp, str = str_mortal(&str_no));
2095         str_set(str, pwent->pw_gecos);
2096         (void)astore(ary, ++sp, str = str_mortal(&str_no));
2097         str_set(str, pwent->pw_dir);
2098         (void)astore(ary, ++sp, str = str_mortal(&str_no));
2099         str_set(str, pwent->pw_shell);
2100 #ifdef PWEXPIRE
2101         (void)astore(ary, ++sp, str = str_mortal(&str_no));
2102         str_numset(str, (double)pwent->pw_expire);
2103 #endif
2104     }
2105
2106     return sp;
2107 #else
2108     fatal("password routines not implemented");
2109 #endif
2110 }
2111
2112 int
2113 do_ggrent(which,gimme,arglast)
2114 int which;
2115 int gimme;
2116 int *arglast;
2117 {
2118 #ifdef I_GRP
2119     register ARRAY *ary = stack;
2120     register int sp = arglast[0];
2121     register char **elem;
2122     register STR *str;
2123     struct group *getgrnam();
2124     struct group *getgrgid();
2125     struct group *getgrent();
2126     struct group *grent;
2127
2128     if (gimme != G_ARRAY) {
2129         astore(ary, ++sp, str_mortal(&str_undef));
2130         return sp;
2131     }
2132
2133     if (which == O_GGRNAM) {
2134         char *name = str_get(ary->ary_array[sp+1]);
2135
2136         grent = getgrnam(name);
2137     }
2138     else if (which == O_GGRGID) {
2139         int gid = (int)str_gnum(ary->ary_array[sp+1]);
2140
2141         grent = getgrgid(gid);
2142     }
2143     else
2144         grent = getgrent();
2145
2146     if (grent) {
2147         (void)astore(ary, ++sp, str = str_mortal(&str_no));
2148         str_set(str, grent->gr_name);
2149         (void)astore(ary, ++sp, str = str_mortal(&str_no));
2150         str_set(str, grent->gr_passwd);
2151         (void)astore(ary, ++sp, str = str_mortal(&str_no));
2152         str_numset(str, (double)grent->gr_gid);
2153         (void)astore(ary, ++sp, str = str_mortal(&str_no));
2154         for (elem = grent->gr_mem; *elem; elem++) {
2155             str_cat(str, *elem);
2156             if (elem[1])
2157                 str_ncat(str," ",1);
2158         }
2159     }
2160
2161     return sp;
2162 #else
2163     fatal("group routines not implemented");
2164 #endif
2165 }
2166
2167 int
2168 do_dirop(optype,stab,gimme,arglast)
2169 int optype;
2170 STAB *stab;
2171 int gimme;
2172 int *arglast;
2173 {
2174 #if defined(DIRENT) && defined(HAS_READDIR)
2175     register ARRAY *ary = stack;
2176     register STR **st = ary->ary_array;
2177     register int sp = arglast[1];
2178     register STIO *stio;
2179     long along;
2180 #ifndef telldir
2181     long telldir();
2182 #endif
2183 #ifndef apollo
2184     struct DIRENT *readdir();
2185 #endif
2186     register struct DIRENT *dp;
2187
2188     if (!stab)
2189         goto nope;
2190     if (!(stio = stab_io(stab)))
2191         stio = stab_io(stab) = stio_new();
2192     if (!stio->dirp && optype != O_OPEN_DIR)
2193         goto nope;
2194     st[sp] = &str_yes;
2195     switch (optype) {
2196     case O_OPEN_DIR:
2197         if (stio->dirp)
2198             closedir(stio->dirp);
2199         if (!(stio->dirp = opendir(str_get(st[sp+1]))))
2200             goto nope;
2201         break;
2202     case O_READDIR:
2203         if (gimme == G_ARRAY) {
2204             --sp;
2205             while (dp = readdir(stio->dirp)) {
2206 #ifdef DIRNAMLEN
2207                 (void)astore(ary,++sp,
2208                   str_2mortal(str_make(dp->d_name,dp->d_namlen)));
2209 #else
2210                 (void)astore(ary,++sp,
2211                   str_2mortal(str_make(dp->d_name,0)));
2212 #endif
2213             }
2214         }
2215         else {
2216             if (!(dp = readdir(stio->dirp)))
2217                 goto nope;
2218             st[sp] = str_mortal(&str_undef);
2219 #ifdef DIRNAMLEN
2220             str_nset(st[sp], dp->d_name, dp->d_namlen);
2221 #else
2222             str_set(st[sp], dp->d_name);
2223 #endif
2224         }
2225         break;
2226 #if MACH
2227     case O_TELLDIR:
2228     case O_SEEKDIR:
2229         goto nope;
2230 #else
2231     case O_TELLDIR:
2232         st[sp] = str_mortal(&str_undef);
2233         str_numset(st[sp], (double)telldir(stio->dirp));
2234         break;
2235     case O_SEEKDIR:
2236         st[sp] = str_mortal(&str_undef);
2237         along = (long)str_gnum(st[sp+1]);
2238         (void)seekdir(stio->dirp,along);
2239         break;
2240 #endif
2241     case O_REWINDDIR:
2242         st[sp] = str_mortal(&str_undef);
2243         (void)rewinddir(stio->dirp);
2244         break;
2245     case O_CLOSEDIR:
2246         st[sp] = str_mortal(&str_undef);
2247         (void)closedir(stio->dirp);
2248         stio->dirp = 0;
2249         break;
2250     }
2251     return sp;
2252
2253 nope:
2254     st[sp] = &str_undef;
2255     return sp;
2256
2257 #else
2258     fatal("Unimplemented directory operation");
2259 #endif
2260 }
2261
2262 apply(type,arglast)
2263 int type;
2264 int *arglast;
2265 {
2266     register STR **st = stack->ary_array;
2267     register int sp = arglast[1];
2268     register int items = arglast[2] - sp;
2269     register int val;
2270     register int val2;
2271     register int tot = 0;
2272     char *s;
2273
2274 #ifdef TAINT
2275     for (st += ++sp; items--; st++)
2276         tainted |= (*st)->str_tainted;
2277     st = stack->ary_array;
2278     sp = arglast[1];
2279     items = arglast[2] - sp;
2280 #endif
2281     switch (type) {
2282     case O_CHMOD:
2283 #ifdef TAINT
2284         taintproper("Insecure dependency in chmod");
2285 #endif
2286         if (--items > 0) {
2287             tot = items;
2288             val = (int)str_gnum(st[++sp]);
2289             while (items--) {
2290                 if (chmod(str_get(st[++sp]),val))
2291                     tot--;
2292             }
2293         }
2294         break;
2295 #ifdef HAS_CHOWN
2296     case O_CHOWN:
2297 #ifdef TAINT
2298         taintproper("Insecure dependency in chown");
2299 #endif
2300         if (items > 2) {
2301             items -= 2;
2302             tot = items;
2303             val = (int)str_gnum(st[++sp]);
2304             val2 = (int)str_gnum(st[++sp]);
2305             while (items--) {
2306                 if (chown(str_get(st[++sp]),val,val2))
2307                     tot--;
2308             }
2309         }
2310         break;
2311 #endif
2312 #ifdef HAS_KILL
2313     case O_KILL:
2314 #ifdef TAINT
2315         taintproper("Insecure dependency in kill");
2316 #endif
2317         if (--items > 0) {
2318             tot = items;
2319             s = str_get(st[++sp]);
2320             if (isupper(*s)) {
2321                 if (*s == 'S' && s[1] == 'I' && s[2] == 'G')
2322                     s += 3;
2323                 if (!(val = whichsig(s)))
2324                     fatal("Unrecognized signal name \"%s\"",s);
2325             }
2326             else
2327                 val = (int)str_gnum(st[sp]);
2328             if (val < 0) {
2329                 val = -val;
2330                 while (items--) {
2331                     int proc = (int)str_gnum(st[++sp]);
2332 #ifdef HAS_KILLPG
2333                     if (killpg(proc,val))       /* BSD */
2334 #else
2335                     if (kill(-proc,val))        /* SYSV */
2336 #endif
2337                         tot--;
2338                 }
2339             }
2340             else {
2341                 while (items--) {
2342                     if (kill((int)(str_gnum(st[++sp])),val))
2343                         tot--;
2344                 }
2345             }
2346         }
2347         break;
2348 #endif
2349     case O_UNLINK:
2350 #ifdef TAINT
2351         taintproper("Insecure dependency in unlink");
2352 #endif
2353         tot = items;
2354         while (items--) {
2355             s = str_get(st[++sp]);
2356             if (euid || unsafe) {
2357                 if (UNLINK(s))
2358                     tot--;
2359             }
2360             else {      /* don't let root wipe out directories without -U */
2361 #ifdef HAS_LSTAT
2362                 if (lstat(s,&statbuf) < 0 || S_ISDIR(statbuf.st_mode))
2363 #else
2364                 if (stat(s,&statbuf) < 0 || S_ISDIR(statbuf.st_mode))
2365 #endif
2366                     tot--;
2367                 else {
2368                     if (UNLINK(s))
2369                         tot--;
2370                 }
2371             }
2372         }
2373         break;
2374     case O_UTIME:
2375 #ifdef TAINT
2376         taintproper("Insecure dependency in utime");
2377 #endif
2378         if (items > 2) {
2379 #ifdef I_UTIME
2380             struct utimbuf utbuf;
2381 #else
2382             struct {
2383                 long    actime;
2384                 long    modtime;
2385             } utbuf;
2386 #endif
2387
2388             Zero(&utbuf, sizeof utbuf, char);
2389             utbuf.actime = (long)str_gnum(st[++sp]);    /* time accessed */
2390             utbuf.modtime = (long)str_gnum(st[++sp]);    /* time modified */
2391             items -= 2;
2392 #ifndef lint
2393             tot = items;
2394             while (items--) {
2395                 if (utime(str_get(st[++sp]),&utbuf))
2396                     tot--;
2397             }
2398 #endif
2399         }
2400         else
2401             items = 0;
2402         break;
2403     }
2404     return tot;
2405 }
2406
2407 /* Do the permissions allow some operation?  Assumes statcache already set. */
2408
2409 int
2410 cando(bit, effective, statbufp)
2411 int bit;
2412 int effective;
2413 register struct stat *statbufp;
2414 {
2415 #ifdef MSDOS
2416     /* [Comments and code from Len Reed]
2417      * MS-DOS "user" is similar to UNIX's "superuser," but can't write
2418      * to write-protected files.  The execute permission bit is set
2419      * by the Miscrosoft C library stat() function for the following:
2420      *          .exe files
2421      *          .com files
2422      *          .bat files
2423      *          directories
2424      * All files and directories are readable.
2425      * Directories and special files, e.g. "CON", cannot be
2426      * write-protected.
2427      * [Comment by Tom Dinger -- a directory can have the write-protect
2428      *          bit set in the file system, but DOS permits changes to
2429      *          the directory anyway.  In addition, all bets are off
2430      *          here for networked software, such as Novell and
2431      *          Sun's PC-NFS.]
2432      */
2433
2434      return (bit & statbufp->st_mode) ? TRUE : FALSE;
2435
2436 #else /* ! MSDOS */
2437     if ((effective ? euid : uid) == 0) {        /* root is special */
2438         if (bit == S_IXUSR) {
2439             if (statbufp->st_mode & 0111 || S_ISDIR(statbufp->st_mode))
2440                 return TRUE;
2441         }
2442         else
2443             return TRUE;                /* root reads and writes anything */
2444         return FALSE;
2445     }
2446     if (statbufp->st_uid == (effective ? euid : uid) ) {
2447         if (statbufp->st_mode & bit)
2448             return TRUE;        /* ok as "user" */
2449     }
2450     else if (ingroup((int)statbufp->st_gid,effective)) {
2451         if (statbufp->st_mode & bit >> 3)
2452             return TRUE;        /* ok as "group" */
2453     }
2454     else if (statbufp->st_mode & bit >> 6)
2455         return TRUE;    /* ok as "other" */
2456     return FALSE;
2457 #endif /* ! MSDOS */
2458 }
2459
2460 int
2461 ingroup(testgid,effective)
2462 int testgid;
2463 int effective;
2464 {
2465     if (testgid == (effective ? egid : gid))
2466         return TRUE;
2467 #ifdef HAS_GETGROUPS
2468 #ifndef NGROUPS
2469 #define NGROUPS 32
2470 #endif
2471     {
2472         GROUPSTYPE gary[NGROUPS];
2473         int anum;
2474
2475         anum = getgroups(NGROUPS,gary);
2476         while (--anum >= 0)
2477             if (gary[anum] == testgid)
2478                 return TRUE;
2479     }
2480 #endif
2481     return FALSE;
2482 }
2483
2484 #if defined(HAS_MSG) || defined(HAS_SEM) || defined(HAS_SHM)
2485
2486 int
2487 do_ipcget(optype, arglast)
2488 int optype;
2489 int *arglast;
2490 {
2491     register STR **st = stack->ary_array;
2492     register int sp = arglast[0];
2493     key_t key;
2494     int n, flags;
2495
2496     key = (key_t)str_gnum(st[++sp]);
2497     n = (optype == O_MSGGET) ? 0 : (int)str_gnum(st[++sp]);
2498     flags = (int)str_gnum(st[++sp]);
2499     errno = 0;
2500     switch (optype)
2501     {
2502 #ifdef HAS_MSG
2503     case O_MSGGET:
2504         return msgget(key, flags);
2505 #endif
2506 #ifdef HAS_SEM
2507     case O_SEMGET:
2508         return semget(key, n, flags);
2509 #endif
2510 #ifdef HAS_SHM
2511     case O_SHMGET:
2512         return shmget(key, n, flags);
2513 #endif
2514 #if !defined(HAS_MSG) || !defined(HAS_SEM) || !defined(HAS_SHM)
2515     default:
2516         fatal("%s not implemented", opname[optype]);
2517 #endif
2518     }
2519     return -1;                  /* should never happen */
2520 }
2521
2522 int
2523 do_ipcctl(optype, arglast)
2524 int optype;
2525 int *arglast;
2526 {
2527     register STR **st = stack->ary_array;
2528     register int sp = arglast[0];
2529     STR *astr;
2530     char *a;
2531     int id, n, cmd, infosize, getinfo, ret;
2532
2533     id = (int)str_gnum(st[++sp]);
2534     n = (optype == O_SEMCTL) ? (int)str_gnum(st[++sp]) : 0;
2535     cmd = (int)str_gnum(st[++sp]);
2536     astr = st[++sp];
2537
2538     infosize = 0;
2539     getinfo = (cmd == IPC_STAT);
2540
2541     switch (optype)
2542     {
2543 #ifdef HAS_MSG
2544     case O_MSGCTL:
2545         if (cmd == IPC_STAT || cmd == IPC_SET)
2546             infosize = sizeof(struct msqid_ds);
2547         break;
2548 #endif
2549 #ifdef HAS_SHM
2550     case O_SHMCTL:
2551         if (cmd == IPC_STAT || cmd == IPC_SET)
2552             infosize = sizeof(struct shmid_ds);
2553         break;
2554 #endif
2555 #ifdef HAS_SEM
2556     case O_SEMCTL:
2557         if (cmd == IPC_STAT || cmd == IPC_SET)
2558             infosize = sizeof(struct semid_ds);
2559         else if (cmd == GETALL || cmd == SETALL)
2560         {
2561             struct semid_ds semds;
2562             if (semctl(id, 0, IPC_STAT, &semds) == -1)
2563                 return -1;
2564             getinfo = (cmd == GETALL);
2565             infosize = semds.sem_nsems * sizeof(short);
2566                 /* "short" is technically wrong but much more portable
2567                    than guessing about u_?short(_t)? */
2568         }
2569         break;
2570 #endif
2571 #if !defined(HAS_MSG) || !defined(HAS_SEM) || !defined(HAS_SHM)
2572     default:
2573         fatal("%s not implemented", opname[optype]);
2574 #endif
2575     }
2576
2577     if (infosize)
2578     {
2579         if (getinfo)
2580         {
2581             STR_GROW(astr, infosize+1);
2582             a = str_get(astr);
2583         }
2584         else
2585         {
2586             a = str_get(astr);
2587             if (astr->str_cur != infosize)
2588             {
2589                 errno = EINVAL;
2590                 return -1;
2591             }
2592         }
2593     }
2594     else
2595     {
2596         int i = (int)str_gnum(astr);
2597         a = (char *)i;          /* ouch */
2598     }
2599     errno = 0;
2600     switch (optype)
2601     {
2602 #ifdef HAS_MSG
2603     case O_MSGCTL:
2604         ret = msgctl(id, cmd, a);
2605         break;
2606 #endif
2607 #ifdef HAS_SEM
2608     case O_SEMCTL:
2609         ret = semctl(id, n, cmd, a);
2610         break;
2611 #endif
2612 #ifdef HAS_SHM
2613     case O_SHMCTL:
2614         ret = shmctl(id, cmd, a);
2615         break;
2616 #endif
2617     }
2618     if (getinfo && ret >= 0) {
2619         astr->str_cur = infosize;
2620         astr->str_ptr[infosize] = '\0';
2621     }
2622     return ret;
2623 }
2624
2625 int
2626 do_msgsnd(arglast)
2627 int *arglast;
2628 {
2629 #ifdef HAS_MSG
2630     register STR **st = stack->ary_array;
2631     register int sp = arglast[0];
2632     STR *mstr;
2633     char *mbuf;
2634     int id, msize, flags;
2635
2636     id = (int)str_gnum(st[++sp]);
2637     mstr = st[++sp];
2638     flags = (int)str_gnum(st[++sp]);
2639     mbuf = str_get(mstr);
2640     if ((msize = mstr->str_cur - sizeof(long)) < 0) {
2641         errno = EINVAL;
2642         return -1;
2643     }
2644     errno = 0;
2645     return msgsnd(id, mbuf, msize, flags);
2646 #else
2647     fatal("msgsnd not implemented");
2648 #endif
2649 }
2650
2651 int
2652 do_msgrcv(arglast)
2653 int *arglast;
2654 {
2655 #ifdef HAS_MSG
2656     register STR **st = stack->ary_array;
2657     register int sp = arglast[0];
2658     STR *mstr;
2659     char *mbuf;
2660     long mtype;
2661     int id, msize, flags, ret;
2662
2663     id = (int)str_gnum(st[++sp]);
2664     mstr = st[++sp];
2665     msize = (int)str_gnum(st[++sp]);
2666     mtype = (long)str_gnum(st[++sp]);
2667     flags = (int)str_gnum(st[++sp]);
2668     mbuf = str_get(mstr);
2669     if (mstr->str_cur < sizeof(long)+msize+1) {
2670         STR_GROW(mstr, sizeof(long)+msize+1);
2671         mbuf = str_get(mstr);
2672     }
2673     errno = 0;
2674     ret = msgrcv(id, mbuf, msize, mtype, flags);
2675     if (ret >= 0) {
2676         mstr->str_cur = sizeof(long)+ret;
2677         mstr->str_ptr[sizeof(long)+ret] = '\0';
2678     }
2679     return ret;
2680 #else
2681     fatal("msgrcv not implemented");
2682 #endif
2683 }
2684
2685 int
2686 do_semop(arglast)
2687 int *arglast;
2688 {
2689 #ifdef HAS_SEM
2690     register STR **st = stack->ary_array;
2691     register int sp = arglast[0];
2692     STR *opstr;
2693     char *opbuf;
2694     int id, opsize;
2695
2696     id = (int)str_gnum(st[++sp]);
2697     opstr = st[++sp];
2698     opbuf = str_get(opstr);
2699     opsize = opstr->str_cur;
2700     if (opsize < sizeof(struct sembuf)
2701         || (opsize % sizeof(struct sembuf)) != 0) {
2702         errno = EINVAL;
2703         return -1;
2704     }
2705     errno = 0;
2706     return semop(id, (struct sembuf *)opbuf, opsize/sizeof(struct sembuf));
2707 #else
2708     fatal("semop not implemented");
2709 #endif
2710 }
2711
2712 int
2713 do_shmio(optype, arglast)
2714 int optype;
2715 int *arglast;
2716 {
2717 #ifdef HAS_SHM
2718     register STR **st = stack->ary_array;
2719     register int sp = arglast[0];
2720     STR *mstr;
2721     char *mbuf, *shm;
2722     int id, mpos, msize;
2723     struct shmid_ds shmds;
2724 #ifndef VOIDSHMAT
2725     extern char *shmat();
2726 #endif
2727
2728     id = (int)str_gnum(st[++sp]);
2729     mstr = st[++sp];
2730     mpos = (int)str_gnum(st[++sp]);
2731     msize = (int)str_gnum(st[++sp]);
2732     errno = 0;
2733     if (shmctl(id, IPC_STAT, &shmds) == -1)
2734         return -1;
2735     if (mpos < 0 || msize < 0 || mpos + msize > shmds.shm_segsz) {
2736         errno = EFAULT;         /* can't do as caller requested */
2737         return -1;
2738     }
2739     shm = (char*)shmat(id, (char*)NULL, (optype == O_SHMREAD) ? SHM_RDONLY : 0);
2740     if (shm == (char *)-1)      /* I hate System V IPC, I really do */
2741         return -1;
2742     mbuf = str_get(mstr);
2743     if (optype == O_SHMREAD) {
2744         if (mstr->str_cur < msize) {
2745             STR_GROW(mstr, msize+1);
2746             mbuf = str_get(mstr);
2747         }
2748         bcopy(shm + mpos, mbuf, msize);
2749         mstr->str_cur = msize;
2750         mstr->str_ptr[msize] = '\0';
2751     }
2752     else {
2753         int n;
2754
2755         if ((n = mstr->str_cur) > msize)
2756             n = msize;
2757         bcopy(mbuf, shm + mpos, n);
2758         if (n < msize)
2759             bzero(shm + mpos + n, msize - n);
2760     }
2761     return shmdt(shm);
2762 #else
2763     fatal("shm I/O not implemented");
2764 #endif
2765 }
2766
2767 #endif /* SYSV IPC */