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