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