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