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