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