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