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