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