opnsense-src/gnu/usr.bin/perl/perl/doio.c
Nate Williams e744d38673 Added support for '-T' and '-B' (text and binary) file recognition by
peeking inside of Chris Torek's stdio library internals.  This is
similar to the code used for other systems, but didn't work on CT's new
implementation.

Submitted by:	Gary Kline <kline@tera.com>
1996-12-03 21:56:15 +00:00

2978 lines
63 KiB
C

/* $RCSfile: doio.c,v $$Revision: 1.3 $$Date: 1995/05/30 05:03:00 $
*
* Copyright (c) 1991, Larry Wall
*
* You may distribute under the terms of either the GNU General Public
* License or the Artistic License, as specified in the README file.
*
* $Log: doio.c,v $
* Revision 1.3 1995/05/30 05:03:00 rgrimes
* Remove trailing whitespace.
*
* Revision 1.2 1994/09/11 03:17:32 gclarkii
* Changed AF_LOCAL to AF_LOCAL_XX so as not to conflict with 4.4 socket.h
* Added casts to shutup warnings in doio.c
*
* Revision 1.1.1.1 1994/09/10 06:27:32 gclarkii
* Initial import of Perl 4.046 bmaked
*
* Revision 1.2 1994/03/09 22:24:27 ache
* (cast) added for last argument of semctl
*
* Revision 1.1.1.1 1993/08/23 21:29:36 nate
* PERL!
*
* Revision 4.0.1.6 92/06/11 21:08:16 lwall
* patch34: some systems don't declare h_errno extern in header files
*
* Revision 4.0.1.5 92/06/08 13:00:21 lwall
* patch20: some machines don't define ENOTSOCK in errno.h
* patch20: new warnings for failed use of stat operators on filenames with \n
* patch20: wait failed when STDOUT or STDERR reopened to a pipe
* patch20: end of file latch not reset on reopen of STDIN
* patch20: seek(HANDLE, 0, 1) went to eof because of ancient Ultrix workaround
* patch20: fixed memory leak on system() for vfork() machines
* patch20: get*by* routines now return something useful in a scalar context
* patch20: h_errno now accessible via $?
*
* Revision 4.0.1.4 91/11/05 16:51:43 lwall
* patch11: prepared for ctype implementations that don't define isascii()
* patch11: perl mistook some streams for sockets because they return mode 0 too
* patch11: reopening STDIN, STDOUT and STDERR failed on some machines
* patch11: certain perl errors should set EBADF so that $! looks better
* patch11: truncate on a closed filehandle could dump
* patch11: stats of _ forgot whether prior stat was actually lstat
* patch11: -T returned true on NFS directory
*
* Revision 4.0.1.3 91/06/10 01:21:19 lwall
* patch10: read didn't work from character special files open for writing
* patch10: close-on-exec wrongly set on system file descriptors
*
* Revision 4.0.1.2 91/06/07 10:53:39 lwall
* patch4: new copyright notice
* patch4: system fd's are now treated specially
* patch4: added $^F variable to specify maximum system fd, default 2
* patch4: character special files now opened with bidirectional stdio buffers
* patch4: taintchecks could improperly modify parent in vfork()
* patch4: many, many itty-bitty portability fixes
*
* Revision 4.0.1.1 91/04/11 17:41:06 lwall
* patch1: hopefully straightened out some of the Xenix mess
*
* Revision 4.0 91/03/20 01:07:06 lwall
* 4.0 baseline.
*
*/
#include "EXTERN.h"
#include "perl.h"
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#ifdef HAS_SOCKET
#include <sys/socket.h>
#include <netdb.h>
#ifndef ENOTSOCK
#include <net/errno.h>
#endif
#endif
#ifdef HAS_SELECT
#ifdef I_SYS_SELECT
#ifndef I_SYS_TIME
#include <sys/select.h>
#endif
#endif
#endif
#ifdef HOST_NOT_FOUND
extern int h_errno;
#endif
#if defined(HAS_MSG) || defined(HAS_SEM) || defined(HAS_SHM)
#include <sys/ipc.h>
#ifdef HAS_MSG
#include <sys/msg.h>
#endif
#ifdef HAS_SEM
#include <sys/sem.h>
#endif
#ifdef HAS_SHM
#include <sys/shm.h>
#endif
#endif
#ifdef I_PWD
#include <pwd.h>
#endif
#ifdef I_GRP
#include <grp.h>
#endif
#ifdef I_UTIME
#include <utime.h>
#endif
#ifdef I_FCNTL
#include <fcntl.h>
#endif
#ifdef I_SYS_FILE
#include <sys/file.h>
#endif
int laststatval = -1;
int laststype = O_STAT;
static char* warn_nl = "Unsuccessful %s on filename containing newline";
bool
do_open(stab,name,len)
STAB *stab;
register char *name;
int len;
{
FILE *fp;
register STIO *stio = stab_io(stab);
char *myname = savestr(name);
int result;
int fd;
int writing = 0;
char mode[3]; /* stdio file mode ("r\0" or "r+\0") */
FILE *saveifp = Nullfp;
FILE *saveofp = Nullfp;
char savetype = ' ';
mode[0] = mode[1] = mode[2] = '\0';
name = myname;
forkprocess = 1; /* assume true if no fork */
while (len && isSPACE(name[len-1]))
name[--len] = '\0';
if (!stio)
stio = stab_io(stab) = stio_new();
else if (stio->ifp) {
fd = fileno(stio->ifp);
if (stio->type == '-')
result = 0;
else if (fd <= maxsysfd) {
saveifp = stio->ifp;
saveofp = stio->ofp;
savetype = stio->type;
result = 0;
}
else if (stio->type == '|')
result = mypclose(stio->ifp);
else if (stio->ifp != stio->ofp) {
if (stio->ofp) {
result = fclose(stio->ofp);
fclose(stio->ifp); /* clear stdio, fd already closed */
}
else
result = fclose(stio->ifp);
}
else
result = fclose(stio->ifp);
if (result == EOF && fd > maxsysfd)
fprintf(stderr,"Warning: unable to close filehandle %s properly.\n",
stab_ename(stab));
stio->ofp = stio->ifp = Nullfp;
}
if (*name == '+' && len > 1 && name[len-1] != '|') { /* scary */
mode[1] = *name++;
mode[2] = '\0';
--len;
writing = 1;
}
else {
mode[1] = '\0';
}
stio->type = *name;
if (*name == '|') {
/*SUPPRESS 530*/
for (name++; isSPACE(*name); name++) ;
#ifdef TAINT
taintenv();
taintproper("Insecure dependency in piped open");
#endif
fp = mypopen(name,"w");
writing = 1;
}
else if (*name == '>') {
#ifdef TAINT
taintproper("Insecure dependency in open");
#endif
name++;
if (*name == '>') {
mode[0] = stio->type = 'a';
name++;
}
else
mode[0] = 'w';
writing = 1;
if (*name == '&') {
duplicity:
name++;
while (isSPACE(*name))
name++;
if (isDIGIT(*name))
fd = atoi(name);
else {
stab = stabent(name,FALSE);
if (!stab || !stab_io(stab)) {
#ifdef EINVAL
errno = EINVAL;
#endif
goto say_false;
}
if (stab_io(stab) && stab_io(stab)->ifp) {
fd = fileno(stab_io(stab)->ifp);
if (stab_io(stab)->type == 's')
stio->type = 's';
}
else
fd = -1;
}
if (!(fp = fdopen(fd = dup(fd),mode))) {
close(fd);
}
}
else {
while (isSPACE(*name))
name++;
if (strEQ(name,"-")) {
fp = stdout;
stio->type = '-';
}
else {
fp = fopen(name,mode);
}
}
}
else {
if (*name == '<') {
mode[0] = 'r';
name++;
while (isSPACE(*name))
name++;
if (*name == '&')
goto duplicity;
if (strEQ(name,"-")) {
fp = stdin;
stio->type = '-';
}
else
fp = fopen(name,mode);
}
else if (name[len-1] == '|') {
#ifdef TAINT
taintenv();
taintproper("Insecure dependency in piped open");
#endif
name[--len] = '\0';
while (len && isSPACE(name[len-1]))
name[--len] = '\0';
/*SUPPRESS 530*/
for (; isSPACE(*name); name++) ;
fp = mypopen(name,"r");
stio->type = '|';
}
else {
stio->type = '<';
/*SUPPRESS 530*/
for (; isSPACE(*name); name++) ;
if (strEQ(name,"-")) {
fp = stdin;
stio->type = '-';
}
else
fp = fopen(name,"r");
}
}
if (!fp) {
if (dowarn && stio->type == '<' && index(name, '\n'))
warn(warn_nl, "open");
Safefree(myname);
goto say_false;
}
Safefree(myname);
if (stio->type &&
stio->type != '|' && stio->type != '-') {
if (fstat(fileno(fp),&statbuf) < 0) {
(void)fclose(fp);
goto say_false;
}
if (S_ISSOCK(statbuf.st_mode))
stio->type = 's'; /* in case a socket was passed in to us */
#ifdef HAS_SOCKET
else if (
#ifdef S_IFMT
!(statbuf.st_mode & S_IFMT)
#else
!statbuf.st_mode
#endif
) {
int buflen = sizeof tokenbuf;
if (getsockname(fileno(fp), (struct sockaddr * )tokenbuf, &buflen) >= 0
|| errno != ENOTSOCK)
stio->type = 's'; /* some OS's return 0 on fstat()ed socket */
/* but some return 0 for streams too, sigh */
}
#endif
}
if (saveifp) { /* must use old fp? */
fd = fileno(saveifp);
if (saveofp) {
fflush(saveofp); /* emulate fclose() */
if (saveofp != saveifp) { /* was a socket? */
fclose(saveofp);
if (fd > 2)
Safefree(saveofp);
}
}
if (fd != fileno(fp)) {
int pid;
STR *str;
dup2(fileno(fp), fd);
str = afetch(fdpid,fileno(fp),TRUE);
pid = str->str_u.str_useful;
str->str_u.str_useful = 0;
str = afetch(fdpid,fd,TRUE);
str->str_u.str_useful = pid;
fclose(fp);
}
fp = saveifp;
clearerr(fp);
}
#if defined(HAS_FCNTL) && defined(F_SETFD)
fd = fileno(fp);
fcntl(fd,F_SETFD,fd > maxsysfd);
#endif
stio->ifp = fp;
if (writing) {
if (stio->type == 's'
|| (stio->type == '>' && S_ISCHR(statbuf.st_mode)) ) {
if (!(stio->ofp = fdopen(fileno(fp),"w"))) {
fclose(fp);
stio->ifp = Nullfp;
goto say_false;
}
}
else
stio->ofp = fp;
}
return TRUE;
say_false:
stio->ifp = saveifp;
stio->ofp = saveofp;
stio->type = savetype;
return FALSE;
}
FILE *
nextargv(stab)
register STAB *stab;
{
register STR *str;
#ifndef FLEXFILENAMES
int filedev;
int fileino;
#endif
int fileuid;
int filegid;
static int filemode = 0;
static int lastfd;
static char *oldname;
if (!argvoutstab)
argvoutstab = stabent("ARGVOUT",TRUE);
if (filemode & (S_ISUID|S_ISGID)) {
fflush(stab_io(argvoutstab)->ifp); /* chmod must follow last write */
#ifdef HAS_FCHMOD
(void)fchmod(lastfd,filemode);
#else
(void)chmod(oldname,filemode);
#endif
}
filemode = 0;
while (alen(stab_xarray(stab)) >= 0) {
str = ashift(stab_xarray(stab));
str_sset(stab_val(stab),str);
STABSET(stab_val(stab));
oldname = str_get(stab_val(stab));
if (do_open(stab,oldname,stab_val(stab)->str_cur)) {
if (inplace) {
#ifdef TAINT
taintproper("Insecure dependency in inplace open");
#endif
if (strEQ(oldname,"-")) {
str_free(str);
defoutstab = stabent("STDOUT",TRUE);
return stab_io(stab)->ifp;
}
#ifndef FLEXFILENAMES
filedev = statbuf.st_dev;
fileino = statbuf.st_ino;
#endif
filemode = statbuf.st_mode;
fileuid = statbuf.st_uid;
filegid = statbuf.st_gid;
if (!S_ISREG(filemode)) {
warn("Can't do inplace edit: %s is not a regular file",
oldname );
do_close(stab,FALSE);
str_free(str);
continue;
}
if (*inplace) {
#ifdef SUFFIX
add_suffix(str,inplace);
#else
str_cat(str,inplace);
#endif
#ifndef FLEXFILENAMES
if (stat(str->str_ptr,&statbuf) >= 0
&& statbuf.st_dev == filedev
&& statbuf.st_ino == fileino ) {
warn("Can't do inplace edit: %s > 14 characters",
str->str_ptr );
do_close(stab,FALSE);
str_free(str);
continue;
}
#endif
#ifdef HAS_RENAME
#ifndef DOSISH
if (rename(oldname,str->str_ptr) < 0) {
warn("Can't rename %s to %s: %s, skipping file",
oldname, str->str_ptr, strerror(errno) );
do_close(stab,FALSE);
str_free(str);
continue;
}
#else
do_close(stab,FALSE);
(void)unlink(str->str_ptr);
(void)rename(oldname,str->str_ptr);
do_open(stab,str->str_ptr,stab_val(stab)->str_cur);
#endif /* MSDOS */
#else
(void)UNLINK(str->str_ptr);
if (link(oldname,str->str_ptr) < 0) {
warn("Can't rename %s to %s: %s, skipping file",
oldname, str->str_ptr, strerror(errno) );
do_close(stab,FALSE);
str_free(str);
continue;
}
(void)UNLINK(oldname);
#endif
}
else {
#ifndef DOSISH
if (UNLINK(oldname) < 0) {
warn("Can't rename %s to %s: %s, skipping file",
oldname, str->str_ptr, strerror(errno) );
do_close(stab,FALSE);
str_free(str);
continue;
}
#else
fatal("Can't do inplace edit without backup");
#endif
}
str_nset(str,">",1);
str_cat(str,oldname);
errno = 0; /* in case sprintf set errno */
if (!do_open(argvoutstab,str->str_ptr,str->str_cur)) {
warn("Can't do inplace edit on %s: %s",
oldname, strerror(errno) );
do_close(stab,FALSE);
str_free(str);
continue;
}
defoutstab = argvoutstab;
lastfd = fileno(stab_io(argvoutstab)->ifp);
(void)fstat(lastfd,&statbuf);
#ifdef HAS_FCHMOD
(void)fchmod(lastfd,filemode);
#else
(void)chmod(oldname,filemode);
#endif
if (fileuid != statbuf.st_uid || filegid != statbuf.st_gid) {
#ifdef HAS_FCHOWN
(void)fchown(lastfd,fileuid,filegid);
#else
#ifdef HAS_CHOWN
(void)chown(oldname,fileuid,filegid);
#endif
#endif
}
}
str_free(str);
return stab_io(stab)->ifp;
}
else
fprintf(stderr,"Can't open %s: %s\n",str_get(str), strerror(errno));
str_free(str);
}
if (inplace) {
(void)do_close(argvoutstab,FALSE);
defoutstab = stabent("STDOUT",TRUE);
}
return Nullfp;
}
#ifdef HAS_PIPE
void
do_pipe(str, rstab, wstab)
STR *str;
STAB *rstab;
STAB *wstab;
{
register STIO *rstio;
register STIO *wstio;
int fd[2];
if (!rstab)
goto badexit;
if (!wstab)
goto badexit;
rstio = stab_io(rstab);
wstio = stab_io(wstab);
if (!rstio)
rstio = stab_io(rstab) = stio_new();
else if (rstio->ifp)
do_close(rstab,FALSE);
if (!wstio)
wstio = stab_io(wstab) = stio_new();
else if (wstio->ifp)
do_close(wstab,FALSE);
if (pipe(fd) < 0)
goto badexit;
rstio->ifp = fdopen(fd[0], "r");
wstio->ofp = fdopen(fd[1], "w");
wstio->ifp = wstio->ofp;
rstio->type = '<';
wstio->type = '>';
if (!rstio->ifp || !wstio->ofp) {
if (rstio->ifp) fclose(rstio->ifp);
else close(fd[0]);
if (wstio->ofp) fclose(wstio->ofp);
else close(fd[1]);
goto badexit;
}
str_sset(str,&str_yes);
return;
badexit:
str_sset(str,&str_undef);
return;
}
#endif
bool
do_close(stab,explicit)
STAB *stab;
bool explicit;
{
bool retval = FALSE;
register STIO *stio;
int status;
if (!stab)
stab = argvstab;
if (!stab) {
errno = EBADF;
return FALSE;
}
stio = stab_io(stab);
if (!stio) { /* never opened */
if (dowarn && explicit)
warn("Close on unopened file <%s>",stab_ename(stab));
return FALSE;
}
if (stio->ifp) {
if (stio->type == '|') {
status = mypclose(stio->ifp);
retval = (status == 0);
statusvalue = (unsigned short)status & 0xffff;
}
else if (stio->type == '-')
retval = TRUE;
else {
if (stio->ofp && stio->ofp != stio->ifp) { /* a socket */
retval = (fclose(stio->ofp) != EOF);
fclose(stio->ifp); /* clear stdio, fd already closed */
}
else
retval = (fclose(stio->ifp) != EOF);
}
stio->ofp = stio->ifp = Nullfp;
}
if (explicit)
stio->lines = 0;
stio->type = ' ';
return retval;
}
bool
do_eof(stab)
STAB *stab;
{
register STIO *stio;
int ch;
if (!stab) { /* eof() */
if (argvstab)
stio = stab_io(argvstab);
else
return TRUE;
}
else
stio = stab_io(stab);
if (!stio)
return TRUE;
while (stio->ifp) {
#ifdef STDSTDIO /* (the code works without this) */
if (stio->ifp->_cnt > 0) /* cheat a little, since */
return FALSE; /* this is the most usual case */
#endif
ch = getc(stio->ifp);
if (ch != EOF) {
(void)ungetc(ch, stio->ifp);
return FALSE;
}
#ifdef STDSTDIO
if (stio->ifp->_cnt < -1)
stio->ifp->_cnt = -1;
#endif
if (!stab) { /* not necessarily a real EOF yet? */
if (!nextargv(argvstab)) /* get another fp handy */
return TRUE;
}
else
return TRUE; /* normal fp, definitely end of file */
}
return TRUE;
}
long
do_tell(stab)
STAB *stab;
{
register STIO *stio;
if (!stab)
goto phooey;
stio = stab_io(stab);
if (!stio || !stio->ifp)
goto phooey;
#ifdef ULTRIX_STDIO_BOTCH
if (feof(stio->ifp))
(void)fseek (stio->ifp, 0L, 2); /* ultrix 1.2 workaround */
#endif
return ftell(stio->ifp);
phooey:
if (dowarn)
warn("tell() on unopened file");
errno = EBADF;
return -1L;
}
bool
do_seek(stab, pos, whence)
STAB *stab;
long pos;
int whence;
{
register STIO *stio;
if (!stab)
goto nuts;
stio = stab_io(stab);
if (!stio || !stio->ifp)
goto nuts;
#ifdef ULTRIX_STDIO_BOTCH
if (feof(stio->ifp))
(void)fseek (stio->ifp, 0L, 2); /* ultrix 1.2 workaround */
#endif
return fseek(stio->ifp, pos, whence) >= 0;
nuts:
if (dowarn)
warn("seek() on unopened file");
errno = EBADF;
return FALSE;
}
int
do_ctl(optype,stab,func,argstr)
int optype;
STAB *stab;
int func;
STR *argstr;
{
register STIO *stio;
register char *s;
int retval;
if (!stab || !argstr || !(stio = stab_io(stab)) || !stio->ifp) {
errno = EBADF; /* well, sort of... */
return -1;
}
if (argstr->str_pok || !argstr->str_nok) {
if (!argstr->str_pok)
s = str_get(argstr);
#ifdef IOCPARM_MASK
#ifndef IOCPARM_LEN
#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
#endif
#endif
#ifdef IOCPARM_LEN
retval = IOCPARM_LEN(func); /* on BSDish systes we're safe */
#else
retval = 256; /* otherwise guess at what's safe */
#endif
if (argstr->str_cur < retval) {
Str_Grow(argstr,retval+1);
argstr->str_cur = retval;
}
s = argstr->str_ptr;
s[argstr->str_cur] = 17; /* a little sanity check here */
}
else {
retval = (int)str_gnum(argstr);
#ifdef DOSISH
s = (char*)(long)retval; /* ouch */
#else
s = (char*)retval; /* ouch */
#endif
}
#ifndef lint
if (optype == O_IOCTL)
retval = ioctl(fileno(stio->ifp), func, s);
else
#ifdef DOSISH
fatal("fcntl is not implemented");
#else
#ifdef HAS_FCNTL
retval = fcntl(fileno(stio->ifp), func, s);
#else
fatal("fcntl is not implemented");
#endif
#endif
#else /* lint */
retval = 0;
#endif /* lint */
if (argstr->str_pok) {
if (s[argstr->str_cur] != 17)
fatal("Return value overflowed string");
s[argstr->str_cur] = 0; /* put our null back */
}
return retval;
}
int
do_stat(str,arg,gimme,arglast)
STR *str;
register ARG *arg;
int gimme;
int *arglast;
{
register ARRAY *ary = stack;
register int sp = arglast[0] + 1;
int max = 13;
if ((arg[1].arg_type & A_MASK) == A_WORD) {
tmpstab = arg[1].arg_ptr.arg_stab;
if (tmpstab != defstab) {
laststype = O_STAT;
statstab = tmpstab;
str_set(statname,"");
if (!stab_io(tmpstab) || !stab_io(tmpstab)->ifp ||
fstat(fileno(stab_io(tmpstab)->ifp),&statcache) < 0) {
max = 0;
laststatval = -1;
}
}
else if (laststatval < 0)
max = 0;
}
else {
str_set(statname,str_get(ary->ary_array[sp]));
statstab = Nullstab;
#ifdef HAS_LSTAT
laststype = arg->arg_type;
if (arg->arg_type == O_LSTAT)
laststatval = lstat(str_get(statname),&statcache);
else
#endif
laststatval = stat(str_get(statname),&statcache);
if (laststatval < 0) {
if (dowarn && index(str_get(statname), '\n'))
warn(warn_nl, "stat");
max = 0;
}
}
if (gimme != G_ARRAY) {
if (max)
str_sset(str,&str_yes);
else
str_sset(str,&str_undef);
STABSET(str);
ary->ary_array[sp] = str;
return sp;
}
sp--;
if (max) {
#ifndef lint
(void)astore(ary,++sp,
str_2mortal(str_nmake((double)statcache.st_dev)));
(void)astore(ary,++sp,
str_2mortal(str_nmake((double)statcache.st_ino)));
(void)astore(ary,++sp,
str_2mortal(str_nmake((double)statcache.st_mode)));
(void)astore(ary,++sp,
str_2mortal(str_nmake((double)statcache.st_nlink)));
(void)astore(ary,++sp,
str_2mortal(str_nmake((double)statcache.st_uid)));
(void)astore(ary,++sp,
str_2mortal(str_nmake((double)statcache.st_gid)));
(void)astore(ary,++sp,
str_2mortal(str_nmake((double)statcache.st_rdev)));
(void)astore(ary,++sp,
str_2mortal(str_nmake((double)statcache.st_size)));
(void)astore(ary,++sp,
str_2mortal(str_nmake((double)statcache.st_atime)));
(void)astore(ary,++sp,
str_2mortal(str_nmake((double)statcache.st_mtime)));
(void)astore(ary,++sp,
str_2mortal(str_nmake((double)statcache.st_ctime)));
#ifdef STATBLOCKS
(void)astore(ary,++sp,
str_2mortal(str_nmake((double)statcache.st_blksize)));
(void)astore(ary,++sp,
str_2mortal(str_nmake((double)statcache.st_blocks)));
#else
(void)astore(ary,++sp,
str_2mortal(str_make("",0)));
(void)astore(ary,++sp,
str_2mortal(str_make("",0)));
#endif
#else /* lint */
(void)astore(ary,++sp,str_nmake(0.0));
#endif /* lint */
}
return sp;
}
#if !defined(HAS_TRUNCATE) && !defined(HAS_CHSIZE) && defined(F_FREESP)
/* code courtesy of William Kucharski */
#define HAS_CHSIZE
int chsize(fd, length)
int fd; /* file descriptor */
off_t length; /* length to set file to */
{
extern long lseek();
struct flock fl;
struct stat filebuf;
if (fstat(fd, &filebuf) < 0)
return -1;
if (filebuf.st_size < length) {
/* extend file length */
if ((lseek(fd, (length - 1), 0)) < 0)
return -1;
/* write a "0" byte */
if ((write(fd, "", 1)) != 1)
return -1;
}
else {
/* truncate length */
fl.l_whence = 0;
fl.l_len = 0;
fl.l_start = length;
fl.l_type = F_WRLCK; /* write lock on file space */
/*
* This relies on the UNDOCUMENTED F_FREESP argument to
* fcntl(2), which truncates the file so that it ends at the
* position indicated by fl.l_start.
*
* Will minor miracles never cease?
*/
if (fcntl(fd, F_FREESP, &fl) < 0)
return -1;
}
return 0;
}
#endif /* F_FREESP */
int /*SUPPRESS 590*/
do_truncate(str,arg,gimme,arglast)
STR *str;
register ARG *arg;
int gimme;
int *arglast;
{
register ARRAY *ary = stack;
register int sp = arglast[0] + 1;
off_t len = (off_t)str_gnum(ary->ary_array[sp+1]);
int result = 1;
STAB *tmpstab;
#if defined(HAS_TRUNCATE) || defined(HAS_CHSIZE)
#ifdef HAS_TRUNCATE
if ((arg[1].arg_type & A_MASK) == A_WORD) {
tmpstab = arg[1].arg_ptr.arg_stab;
if (!stab_io(tmpstab) || !stab_io(tmpstab)->ifp ||
ftruncate(fileno(stab_io(tmpstab)->ifp), len) < 0)
result = 0;
}
else if (truncate(str_get(ary->ary_array[sp]), len) < 0)
result = 0;
#else
if ((arg[1].arg_type & A_MASK) == A_WORD) {
tmpstab = arg[1].arg_ptr.arg_stab;
if (!stab_io(tmpstab) || !stab_io(tmpstab)->ifp ||
chsize(fileno(stab_io(tmpstab)->ifp), len) < 0)
result = 0;
}
else {
int tmpfd;
if ((tmpfd = open(str_get(ary->ary_array[sp]), 0)) < 0)
result = 0;
else {
if (chsize(tmpfd, len) < 0)
result = 0;
close(tmpfd);
}
}
#endif
if (result)
str_sset(str,&str_yes);
else
str_sset(str,&str_undef);
STABSET(str);
ary->ary_array[sp] = str;
return sp;
#else
fatal("truncate not implemented");
#endif
}
int
looks_like_number(str)
STR *str;
{
register char *s;
register char *send;
if (!str->str_pok)
return TRUE;
s = str->str_ptr;
send = s + str->str_cur;
while (isSPACE(*s))
s++;
if (s >= send)
return FALSE;
if (*s == '+' || *s == '-')
s++;
while (isDIGIT(*s))
s++;
if (s == send)
return TRUE;
if (*s == '.')
s++;
else if (s == str->str_ptr)
return FALSE;
while (isDIGIT(*s))
s++;
if (s == send)
return TRUE;
if (*s == 'e' || *s == 'E') {
s++;
if (*s == '+' || *s == '-')
s++;
while (isDIGIT(*s))
s++;
}
while (isSPACE(*s))
s++;
if (s >= send)
return TRUE;
return FALSE;
}
bool
do_print(str,fp)
register STR *str;
FILE *fp;
{
register char *tmps;
if (!fp) {
if (dowarn)
warn("print to unopened file");
errno = EBADF;
return FALSE;
}
if (!str)
return TRUE;
if (ofmt &&
((str->str_nok && str->str_u.str_nval != 0.0)
|| (looks_like_number(str) && str_gnum(str) != 0.0) ) ) {
fprintf(fp, ofmt, str->str_u.str_nval);
return !ferror(fp);
}
else {
tmps = str_get(str);
if (*tmps == 'S' && tmps[1] == 't' && tmps[2] == 'B' && tmps[3] == '\0'
&& str->str_cur == sizeof(STBP) && strlen(tmps) < str->str_cur) {
STR *tmpstr = str_mortal(&str_undef);
stab_efullname(tmpstr,((STAB*)str));/* a stab value, be nice */
str = tmpstr;
tmps = str->str_ptr;
putc('*',fp);
}
if (str->str_cur && (fwrite(tmps,1,str->str_cur,fp) == 0 || ferror(fp)))
return FALSE;
}
return TRUE;
}
bool
do_aprint(arg,fp,arglast)
register ARG *arg;
register FILE *fp;
int *arglast;
{
register STR **st = stack->ary_array;
register int sp = arglast[1];
register int retval;
register int items = arglast[2] - sp;
if (!fp) {
if (dowarn)
warn("print to unopened file");
errno = EBADF;
return FALSE;
}
st += ++sp;
if (arg->arg_type == O_PRTF) {
do_sprintf(arg->arg_ptr.arg_str,items,st);
retval = do_print(arg->arg_ptr.arg_str,fp);
}
else {
retval = (items <= 0);
for (; items > 0; items--,st++) {
if (retval && ofslen) {
if (fwrite(ofs, 1, ofslen, fp) == 0 || ferror(fp)) {
retval = FALSE;
break;
}
}
if (!(retval = do_print(*st, fp)))
break;
}
if (retval && orslen)
if (fwrite(ors, 1, orslen, fp) == 0 || ferror(fp))
retval = FALSE;
}
return retval;
}
int
mystat(arg,str)
ARG *arg;
STR *str;
{
STIO *stio;
if (arg[1].arg_type & A_DONT) {
stio = stab_io(arg[1].arg_ptr.arg_stab);
if (stio && stio->ifp) {
statstab = arg[1].arg_ptr.arg_stab;
str_set(statname,"");
laststype = O_STAT;
return (laststatval = fstat(fileno(stio->ifp), &statcache));
}
else {
if (arg[1].arg_ptr.arg_stab == defstab)
return laststatval;
if (dowarn)
warn("Stat on unopened file <%s>",
stab_ename(arg[1].arg_ptr.arg_stab));
statstab = Nullstab;
str_set(statname,"");
return (laststatval = -1);
}
}
else {
statstab = Nullstab;
str_set(statname,str_get(str));
laststype = O_STAT;
laststatval = stat(str_get(str),&statcache);
if (laststatval < 0 && dowarn && index(str_get(str), '\n'))
warn(warn_nl, "stat");
return laststatval;
}
}
int
mylstat(arg,str)
ARG *arg;
STR *str;
{
if (arg[1].arg_type & A_DONT) {
if (arg[1].arg_ptr.arg_stab == defstab) {
if (laststype != O_LSTAT)
fatal("The stat preceding -l _ wasn't an lstat");
return laststatval;
}
fatal("You can't use -l on a filehandle");
}
laststype = O_LSTAT;
statstab = Nullstab;
str_set(statname,str_get(str));
#ifdef HAS_LSTAT
laststatval = lstat(str_get(str),&statcache);
#else
laststatval = stat(str_get(str),&statcache);
#endif
if (laststatval < 0 && dowarn && index(str_get(str), '\n'))
warn(warn_nl, "lstat");
return laststatval;
}
STR *
do_fttext(arg,str)
register ARG *arg;
STR *str;
{
int i;
int len;
int odd = 0;
STDCHAR tbuf[512];
register STDCHAR *s;
register STIO *stio;
if (arg[1].arg_type & A_DONT) {
if (arg[1].arg_ptr.arg_stab == defstab) {
if (statstab)
stio = stab_io(statstab);
else {
str = statname;
goto really_filename;
}
}
else {
statstab = arg[1].arg_ptr.arg_stab;
str_set(statname,"");
stio = stab_io(statstab);
}
if (stio && stio->ifp) {
#if defined(STDSTDIO) || defined(atarist) /* this will work with atariST */
fstat(fileno(stio->ifp),&statcache);
if (S_ISDIR(statcache.st_mode)) /* handle NFS glitch */
return arg->arg_type == O_FTTEXT ? &str_no : &str_yes;
if (stio->ifp->_cnt <= 0) {
i = getc(stio->ifp);
if (i != EOF)
(void)ungetc(i,stio->ifp);
}
if (stio->ifp->_cnt <= 0) /* null file is anything */
return &str_yes;
len = stio->ifp->_cnt + (stio->ifp->_ptr - stio->ifp->_base);
s = stio->ifp->_base;
#else
#if (defined(BSD) && (BSD >= 199103))
fstat(fileno(stio->ifp),&statcache);
if (S_ISDIR(statcache.st_mode)) /* handle NFS glitch */
return arg->arg_type == O_FTTEXT ? &str_no : &str_yes;
if (stio->ifp->_bf._size <= 0) {
i = getc(stio->ifp);
if (i != EOF)
(void)ungetc(i,stio->ifp);
}
if (stio->ifp->_bf._size <= 0)
return &str_yes;
len = stio->ifp->_bf._size+(stio->ifp->_p - stio->ifp->_bf._base);
s = stio->ifp->_bf._base;
#else
fatal("-T and -B not implemented on filehandles");
#endif
#endif
}
else {
if (dowarn)
warn("Test on unopened file <%s>",
stab_ename(arg[1].arg_ptr.arg_stab));
errno = EBADF;
return &str_undef;
}
}
else {
statstab = Nullstab;
str_set(statname,str_get(str));
really_filename:
i = open(str_get(str),0);
if (i < 0) {
if (dowarn && index(str_get(str), '\n'))
warn(warn_nl, "open");
return &str_undef;
}
fstat(i,&statcache);
len = read(i,tbuf,512);
(void)close(i);
if (len <= 0) {
if (S_ISDIR(statcache.st_mode) && arg->arg_type == O_FTTEXT)
return &str_no; /* special case NFS directories */
return &str_yes; /* null file is anything */
}
s = tbuf;
}
/* now scan s to look for textiness */
for (i = 0; i < len; i++,s++) {
if (!*s) { /* null never allowed in text */
odd += len;
break;
}
else if (*s & 128)
odd++;
else if (*s < 32 &&
*s != '\n' && *s != '\r' && *s != '\b' &&
*s != '\t' && *s != '\f' && *s != 27)
odd++;
}
if ((odd * 10 > len) == (arg->arg_type == O_FTTEXT)) /* allow 10% odd */
return &str_no;
else
return &str_yes;
}
static char **Argv = Null(char **);
static char *Cmd = Nullch;
bool
do_aexec(really,arglast)
STR *really;
int *arglast;
{
register STR **st = stack->ary_array;
register int sp = arglast[1];
register int items = arglast[2] - sp;
register char **a;
char *tmps;
if (items) {
New(401,Argv, items+1, char*);
a = Argv;
for (st += ++sp; items > 0; items--,st++) {
if (*st)
*a++ = str_get(*st);
else
*a++ = "";
}
*a = Nullch;
#ifdef TAINT
if (*Argv[0] != '/') /* will execvp use PATH? */
taintenv(); /* testing IFS here is overkill, probably */
#endif
if (really && *(tmps = str_get(really)))
execvp(tmps,Argv);
else
execvp(Argv[0],Argv);
}
do_execfree();
return FALSE;
}
void
do_execfree()
{
if (Argv) {
Safefree(Argv);
Argv = Null(char **);
}
if (Cmd) {
Safefree(Cmd);
Cmd = Nullch;
}
}
bool
do_exec(cmd)
char *cmd;
{
register char **a;
register char *s;
char flags[10];
/* save an extra exec if possible */
#ifdef CSH
if (strnEQ(cmd,cshname,cshlen) && strnEQ(cmd+cshlen," -c",3)) {
strcpy(flags,"-c");
s = cmd+cshlen+3;
if (*s == 'f') {
s++;
strcat(flags,"f");
}
if (*s == ' ')
s++;
if (*s++ == '\'') {
char *ncmd = s;
while (*s)
s++;
if (s[-1] == '\n')
*--s = '\0';
if (s[-1] == '\'') {
*--s = '\0';
execl(cshname,"csh", flags,ncmd,(char*)0);
*s = '\'';
return FALSE;
}
}
}
#endif /* CSH */
/* see if there are shell metacharacters in it */
/*SUPPRESS 530*/
for (s = cmd; *s && isALPHA(*s); s++) ; /* catch VAR=val gizmo */
if (*s == '=')
goto doshell;
for (s = cmd; *s; s++) {
if (*s != ' ' && !isALPHA(*s) && index("$&*(){}[]'\";\\|?<>~`\n",*s)) {
if (*s == '\n' && !s[1]) {
*s = '\0';
break;
}
doshell:
execl("/bin/sh","sh","-c",cmd,(char*)0);
return FALSE;
}
}
New(402,Argv, (s - cmd) / 2 + 2, char*);
Cmd = nsavestr(cmd, s-cmd);
a = Argv;
for (s = Cmd; *s;) {
while (*s && isSPACE(*s)) s++;
if (*s)
*(a++) = s;
while (*s && !isSPACE(*s)) s++;
if (*s)
*s++ = '\0';
}
*a = Nullch;
if (Argv[0]) {
execvp(Argv[0],Argv);
if (errno == ENOEXEC) { /* for system V NIH syndrome */
do_execfree();
goto doshell;
}
}
do_execfree();
return FALSE;
}
#ifdef HAS_SOCKET
int
do_socket(stab, arglast)
STAB *stab;
int *arglast;
{
register STR **st = stack->ary_array;
register int sp = arglast[1];
register STIO *stio;
int domain, type, protocol, fd;
if (!stab) {
errno = EBADF;
return FALSE;
}
stio = stab_io(stab);
if (!stio)
stio = stab_io(stab) = stio_new();
else if (stio->ifp)
do_close(stab,FALSE);
domain = (int)str_gnum(st[++sp]);
type = (int)str_gnum(st[++sp]);
protocol = (int)str_gnum(st[++sp]);
#ifdef TAINT
taintproper("Insecure dependency in socket");
#endif
fd = socket(domain,type,protocol);
if (fd < 0)
return FALSE;
stio->ifp = fdopen(fd, "r"); /* stdio gets confused about sockets */
stio->ofp = fdopen(fd, "w");
stio->type = 's';
if (!stio->ifp || !stio->ofp) {
if (stio->ifp) fclose(stio->ifp);
if (stio->ofp) fclose(stio->ofp);
if (!stio->ifp && !stio->ofp) close(fd);
return FALSE;
}
return TRUE;
}
int
do_bind(stab, arglast)
STAB *stab;
int *arglast;
{
register STR **st = stack->ary_array;
register int sp = arglast[1];
register STIO *stio;
char *addr;
if (!stab)
goto nuts;
stio = stab_io(stab);
if (!stio || !stio->ifp)
goto nuts;
addr = str_get(st[++sp]);
#ifdef TAINT
taintproper("Insecure dependency in bind");
#endif
return bind(fileno(stio->ifp), (struct sockaddr * ) addr, st[sp]->str_cur) >= 0;
nuts:
if (dowarn)
warn("bind() on closed fd");
errno = EBADF;
return FALSE;
}
int
do_connect(stab, arglast)
STAB *stab;
int *arglast;
{
register STR **st = stack->ary_array;
register int sp = arglast[1];
register STIO *stio;
char *addr;
if (!stab)
goto nuts;
stio = stab_io(stab);
if (!stio || !stio->ifp)
goto nuts;
addr = str_get(st[++sp]);
#ifdef TAINT
taintproper("Insecure dependency in connect");
#endif
return connect(fileno(stio->ifp), (struct sockaddr *) addr, st[sp]->str_cur) >= 0;
nuts:
if (dowarn)
warn("connect() on closed fd");
errno = EBADF;
return FALSE;
}
int
do_listen(stab, arglast)
STAB *stab;
int *arglast;
{
register STR **st = stack->ary_array;
register int sp = arglast[1];
register STIO *stio;
int backlog;
if (!stab)
goto nuts;
stio = stab_io(stab);
if (!stio || !stio->ifp)
goto nuts;
backlog = (int)str_gnum(st[++sp]);
return listen(fileno(stio->ifp), backlog) >= 0;
nuts:
if (dowarn)
warn("listen() on closed fd");
errno = EBADF;
return FALSE;
}
void
do_accept(str, nstab, gstab)
STR *str;
STAB *nstab;
STAB *gstab;
{
register STIO *nstio;
register STIO *gstio;
int len = sizeof buf;
int fd;
if (!nstab)
goto badexit;
if (!gstab)
goto nuts;
gstio = stab_io(gstab);
nstio = stab_io(nstab);
if (!gstio || !gstio->ifp)
goto nuts;
if (!nstio)
nstio = stab_io(nstab) = stio_new();
else if (nstio->ifp)
do_close(nstab,FALSE);
fd = accept(fileno(gstio->ifp),(struct sockaddr *)buf,&len);
if (fd < 0)
goto badexit;
nstio->ifp = fdopen(fd, "r");
nstio->ofp = fdopen(fd, "w");
nstio->type = 's';
if (!nstio->ifp || !nstio->ofp) {
if (nstio->ifp) fclose(nstio->ifp);
if (nstio->ofp) fclose(nstio->ofp);
if (!nstio->ifp && !nstio->ofp) close(fd);
goto badexit;
}
str_nset(str, buf, len);
return;
nuts:
if (dowarn)
warn("accept() on closed fd");
errno = EBADF;
badexit:
str_sset(str,&str_undef);
return;
}
int
do_shutdown(stab, arglast)
STAB *stab;
int *arglast;
{
register STR **st = stack->ary_array;
register int sp = arglast[1];
register STIO *stio;
int how;
if (!stab)
goto nuts;
stio = stab_io(stab);
if (!stio || !stio->ifp)
goto nuts;
how = (int)str_gnum(st[++sp]);
return shutdown(fileno(stio->ifp), how) >= 0;
nuts:
if (dowarn)
warn("shutdown() on closed fd");
errno = EBADF;
return FALSE;
}
int
do_sopt(optype, stab, arglast)
int optype;
STAB *stab;
int *arglast;
{
register STR **st = stack->ary_array;
register int sp = arglast[1];
register STIO *stio;
int fd;
unsigned int lvl;
unsigned int optname;
if (!stab)
goto nuts;
stio = stab_io(stab);
if (!stio || !stio->ifp)
goto nuts;
fd = fileno(stio->ifp);
lvl = (unsigned int)str_gnum(st[sp+1]);
optname = (unsigned int)str_gnum(st[sp+2]);
switch (optype) {
case O_GSOCKOPT:
st[sp] = str_2mortal(Str_new(22,257));
st[sp]->str_cur = 256;
st[sp]->str_pok = 1;
if (getsockopt(fd, lvl, optname, st[sp]->str_ptr,
(int*)&st[sp]->str_cur) < 0)
goto nuts;
break;
case O_SSOCKOPT:
st[sp] = st[sp+3];
if (setsockopt(fd, lvl, optname, st[sp]->str_ptr, st[sp]->str_cur) < 0)
goto nuts;
st[sp] = &str_yes;
break;
}
return sp;
nuts:
if (dowarn)
warn("[gs]etsockopt() on closed fd");
st[sp] = &str_undef;
errno = EBADF;
return sp;
}
int
do_getsockname(optype, stab, arglast)
int optype;
STAB *stab;
int *arglast;
{
register STR **st = stack->ary_array;
register int sp = arglast[1];
register STIO *stio;
int fd;
if (!stab)
goto nuts;
stio = stab_io(stab);
if (!stio || !stio->ifp)
goto nuts;
st[sp] = str_2mortal(Str_new(22,257));
st[sp]->str_cur = 256;
st[sp]->str_pok = 1;
fd = fileno(stio->ifp);
switch (optype) {
case O_GETSOCKNAME:
if (getsockname(fd, (struct sockaddr *) st[sp]->str_ptr, (int*)&st[sp]->str_cur) < 0)
goto nuts2;
break;
case O_GETPEERNAME:
if (getpeername(fd, (struct sockaddr *) st[sp]->str_ptr, (int*)&st[sp]->str_cur) < 0)
goto nuts2;
break;
}
return sp;
nuts:
if (dowarn)
warn("get{sock,peer}name() on closed fd");
errno = EBADF;
nuts2:
st[sp] = &str_undef;
return sp;
}
int
do_ghent(which,gimme,arglast)
int which;
int gimme;
int *arglast;
{
register ARRAY *ary = stack;
register int sp = arglast[0];
register char **elem;
register STR *str;
struct hostent *gethostbyname();
struct hostent *gethostbyaddr();
#ifdef HAS_GETHOSTENT
struct hostent *gethostent();
#endif
struct hostent *hent;
unsigned long len;
if (which == O_GHBYNAME) {
char *name = str_get(ary->ary_array[sp+1]);
hent = gethostbyname(name);
}
else if (which == O_GHBYADDR) {
STR *addrstr = ary->ary_array[sp+1];
int addrtype = (int)str_gnum(ary->ary_array[sp+2]);
char *addr = str_get(addrstr);
hent = gethostbyaddr(addr,addrstr->str_cur,addrtype);
}
else
#ifdef HAS_GETHOSTENT
hent = gethostent();
#else
fatal("gethostent not implemented");
#endif
#ifdef HOST_NOT_FOUND
if (!hent)
statusvalue = (unsigned short)h_errno & 0xffff;
#endif
if (gimme != G_ARRAY) {
astore(ary, ++sp, str = str_mortal(&str_undef));
if (hent) {
if (which == O_GHBYNAME) {
#ifdef h_addr
str_nset(str, *hent->h_addr, hent->h_length);
#else
str_nset(str, hent->h_addr, hent->h_length);
#endif
}
else
str_set(str, hent->h_name);
}
return sp;
}
if (hent) {
#ifndef lint
(void)astore(ary, ++sp, str = str_mortal(&str_no));
str_set(str, hent->h_name);
(void)astore(ary, ++sp, str = str_mortal(&str_no));
for (elem = hent->h_aliases; *elem; elem++) {
str_cat(str, *elem);
if (elem[1])
str_ncat(str," ",1);
}
(void)astore(ary, ++sp, str = str_mortal(&str_no));
str_numset(str, (double)hent->h_addrtype);
(void)astore(ary, ++sp, str = str_mortal(&str_no));
len = hent->h_length;
str_numset(str, (double)len);
#ifdef h_addr
for (elem = hent->h_addr_list; *elem; elem++) {
(void)astore(ary, ++sp, str = str_mortal(&str_no));
str_nset(str, *elem, len);
}
#else
(void)astore(ary, ++sp, str = str_mortal(&str_no));
str_nset(str, hent->h_addr, len);
#endif /* h_addr */
#else /* lint */
elem = Nullch;
elem = elem;
(void)astore(ary, ++sp, str_mortal(&str_no));
#endif /* lint */
}
return sp;
}
int
do_gnent(which,gimme,arglast)
int which;
int gimme;
int *arglast;
{
register ARRAY *ary = stack;
register int sp = arglast[0];
register char **elem;
register STR *str;
struct netent *getnetbyname();
struct netent *getnetbyaddr();
struct netent *getnetent();
struct netent *nent;
if (which == O_GNBYNAME) {
char *name = str_get(ary->ary_array[sp+1]);
nent = getnetbyname(name);
}
else if (which == O_GNBYADDR) {
unsigned long addr = U_L(str_gnum(ary->ary_array[sp+1]));
int addrtype = (int)str_gnum(ary->ary_array[sp+2]);
nent = getnetbyaddr((long)addr,addrtype);
}
else
nent = getnetent();
if (gimme != G_ARRAY) {
astore(ary, ++sp, str = str_mortal(&str_undef));
if (nent) {
if (which == O_GNBYNAME)
str_numset(str, (double)nent->n_net);
else
str_set(str, nent->n_name);
}
return sp;
}
if (nent) {
#ifndef lint
(void)astore(ary, ++sp, str = str_mortal(&str_no));
str_set(str, nent->n_name);
(void)astore(ary, ++sp, str = str_mortal(&str_no));
for (elem = nent->n_aliases; *elem; elem++) {
str_cat(str, *elem);
if (elem[1])
str_ncat(str," ",1);
}
(void)astore(ary, ++sp, str = str_mortal(&str_no));
str_numset(str, (double)nent->n_addrtype);
(void)astore(ary, ++sp, str = str_mortal(&str_no));
str_numset(str, (double)nent->n_net);
#else /* lint */
elem = Nullch;
elem = elem;
(void)astore(ary, ++sp, str_mortal(&str_no));
#endif /* lint */
}
return sp;
}
int
do_gpent(which,gimme,arglast)
int which;
int gimme;
int *arglast;
{
register ARRAY *ary = stack;
register int sp = arglast[0];
register char **elem;
register STR *str;
struct protoent *getprotobyname();
struct protoent *getprotobynumber();
struct protoent *getprotoent();
struct protoent *pent;
if (which == O_GPBYNAME) {
char *name = str_get(ary->ary_array[sp+1]);
pent = getprotobyname(name);
}
else if (which == O_GPBYNUMBER) {
int proto = (int)str_gnum(ary->ary_array[sp+1]);
pent = getprotobynumber(proto);
}
else
pent = getprotoent();
if (gimme != G_ARRAY) {
astore(ary, ++sp, str = str_mortal(&str_undef));
if (pent) {
if (which == O_GPBYNAME)
str_numset(str, (double)pent->p_proto);
else
str_set(str, pent->p_name);
}
return sp;
}
if (pent) {
#ifndef lint
(void)astore(ary, ++sp, str = str_mortal(&str_no));
str_set(str, pent->p_name);
(void)astore(ary, ++sp, str = str_mortal(&str_no));
for (elem = pent->p_aliases; *elem; elem++) {
str_cat(str, *elem);
if (elem[1])
str_ncat(str," ",1);
}
(void)astore(ary, ++sp, str = str_mortal(&str_no));
str_numset(str, (double)pent->p_proto);
#else /* lint */
elem = Nullch;
elem = elem;
(void)astore(ary, ++sp, str_mortal(&str_no));
#endif /* lint */
}
return sp;
}
int
do_gsent(which,gimme,arglast)
int which;
int gimme;
int *arglast;
{
register ARRAY *ary = stack;
register int sp = arglast[0];
register char **elem;
register STR *str;
struct servent *getservbyname();
struct servent *getservbynumber();
struct servent *getservent();
struct servent *sent;
if (which == O_GSBYNAME) {
char *name = str_get(ary->ary_array[sp+1]);
char *proto = str_get(ary->ary_array[sp+2]);
if (proto && !*proto)
proto = Nullch;
sent = getservbyname(name,proto);
}
else if (which == O_GSBYPORT) {
int port = (int)str_gnum(ary->ary_array[sp+1]);
char *proto = str_get(ary->ary_array[sp+2]);
sent = getservbyport(port,proto);
}
else
sent = getservent();
if (gimme != G_ARRAY) {
astore(ary, ++sp, str = str_mortal(&str_undef));
if (sent) {
if (which == O_GSBYNAME) {
#ifdef HAS_NTOHS
str_numset(str, (double)ntohs(sent->s_port));
#else
str_numset(str, (double)(sent->s_port));
#endif
}
else
str_set(str, sent->s_name);
}
return sp;
}
if (sent) {
#ifndef lint
(void)astore(ary, ++sp, str = str_mortal(&str_no));
str_set(str, sent->s_name);
(void)astore(ary, ++sp, str = str_mortal(&str_no));
for (elem = sent->s_aliases; *elem; elem++) {
str_cat(str, *elem);
if (elem[1])
str_ncat(str," ",1);
}
(void)astore(ary, ++sp, str = str_mortal(&str_no));
#ifdef HAS_NTOHS
str_numset(str, (double)ntohs(sent->s_port));
#else
str_numset(str, (double)(sent->s_port));
#endif
(void)astore(ary, ++sp, str = str_mortal(&str_no));
str_set(str, sent->s_proto);
#else /* lint */
elem = Nullch;
elem = elem;
(void)astore(ary, ++sp, str_mortal(&str_no));
#endif /* lint */
}
return sp;
}
#endif /* HAS_SOCKET */
#ifdef HAS_SELECT
int
do_select(gimme,arglast)
int gimme;
int *arglast;
{
register STR **st = stack->ary_array;
register int sp = arglast[0];
register int i;
register int j;
register char *s;
register STR *str;
double value;
int maxlen = 0;
int nfound;
struct timeval timebuf;
struct timeval *tbuf = &timebuf;
int growsize;
#if BYTEORDER != 0x1234 && BYTEORDER != 0x12345678
int masksize;
int offset;
char *fd_sets[4];
int k;
#if BYTEORDER & 0xf0000
#define ORDERBYTE (0x88888888 - BYTEORDER)
#else
#define ORDERBYTE (0x4444 - BYTEORDER)
#endif
#endif
for (i = 1; i <= 3; i++) {
j = st[sp+i]->str_cur;
if (maxlen < j)
maxlen = j;
}
#if BYTEORDER == 0x1234 || BYTEORDER == 0x12345678
growsize = maxlen; /* little endians can use vecs directly */
#else
#ifdef NFDBITS
#ifndef NBBY
#define NBBY 8
#endif
masksize = NFDBITS / NBBY;
#else
masksize = sizeof(long); /* documented int, everyone seems to use long */
#endif
growsize = maxlen + (masksize - (maxlen % masksize));
Zero(&fd_sets[0], 4, char*);
#endif
for (i = 1; i <= 3; i++) {
str = st[sp+i];
j = str->str_len;
if (j < growsize) {
if (str->str_pok) {
Str_Grow(str,growsize);
s = str_get(str) + j;
while (++j <= growsize) {
*s++ = '\0';
}
}
else if (str->str_ptr) {
Safefree(str->str_ptr);
str->str_ptr = Nullch;
}
}
#if BYTEORDER != 0x1234 && BYTEORDER != 0x12345678
s = str->str_ptr;
if (s) {
New(403, fd_sets[i], growsize, char);
for (offset = 0; offset < growsize; offset += masksize) {
for (j = 0, k=ORDERBYTE; j < masksize; j++, (k >>= 4))
fd_sets[i][j+offset] = s[(k % masksize) + offset];
}
}
#endif
}
str = st[sp+4];
if (str->str_nok || str->str_pok) {
value = str_gnum(str);
if (value < 0.0)
value = 0.0;
timebuf.tv_sec = (long)value;
value -= (double)timebuf.tv_sec;
timebuf.tv_usec = (long)(value * 1000000.0);
}
else
tbuf = Null(struct timeval*);
#if BYTEORDER == 0x1234 || BYTEORDER == 0x12345678
nfound = select(
maxlen * 8,
(fd_set *) st[sp+1]->str_ptr,
(fd_set *) st[sp+2]->str_ptr,
(fd_set *) st[sp+3]->str_ptr,
tbuf);
#else
nfound = select(
maxlen * 8,
fd_sets[1],
fd_sets[2],
fd_sets[3],
tbuf);
for (i = 1; i <= 3; i++) {
if (fd_sets[i]) {
str = st[sp+i];
s = str->str_ptr;
for (offset = 0; offset < growsize; offset += masksize) {
for (j = 0, k=ORDERBYTE; j < masksize; j++, (k >>= 4))
s[(k % masksize) + offset] = fd_sets[i][j+offset];
}
Safefree(fd_sets[i]);
}
}
#endif
st[++sp] = str_mortal(&str_no);
str_numset(st[sp], (double)nfound);
if (gimme == G_ARRAY && tbuf) {
value = (double)(timebuf.tv_sec) +
(double)(timebuf.tv_usec) / 1000000.0;
st[++sp] = str_mortal(&str_no);
str_numset(st[sp], value);
}
return sp;
}
#endif /* SELECT */
#ifdef HAS_SOCKET
int
do_spair(stab1, stab2, arglast)
STAB *stab1;
STAB *stab2;
int *arglast;
{
register STR **st = stack->ary_array;
register int sp = arglast[2];
register STIO *stio1;
register STIO *stio2;
int domain, type, protocol, fd[2];
if (!stab1 || !stab2)
return FALSE;
stio1 = stab_io(stab1);
stio2 = stab_io(stab2);
if (!stio1)
stio1 = stab_io(stab1) = stio_new();
else if (stio1->ifp)
do_close(stab1,FALSE);
if (!stio2)
stio2 = stab_io(stab2) = stio_new();
else if (stio2->ifp)
do_close(stab2,FALSE);
domain = (int)str_gnum(st[++sp]);
type = (int)str_gnum(st[++sp]);
protocol = (int)str_gnum(st[++sp]);
#ifdef TAINT
taintproper("Insecure dependency in socketpair");
#endif
#ifdef HAS_SOCKETPAIR
if (socketpair(domain,type,protocol,fd) < 0)
return FALSE;
#else
fatal("Socketpair unimplemented");
#endif
stio1->ifp = fdopen(fd[0], "r");
stio1->ofp = fdopen(fd[0], "w");
stio1->type = 's';
stio2->ifp = fdopen(fd[1], "r");
stio2->ofp = fdopen(fd[1], "w");
stio2->type = 's';
if (!stio1->ifp || !stio1->ofp || !stio2->ifp || !stio2->ofp) {
if (stio1->ifp) fclose(stio1->ifp);
if (stio1->ofp) fclose(stio1->ofp);
if (!stio1->ifp && !stio1->ofp) close(fd[0]);
if (stio2->ifp) fclose(stio2->ifp);
if (stio2->ofp) fclose(stio2->ofp);
if (!stio2->ifp && !stio2->ofp) close(fd[1]);
return FALSE;
}
return TRUE;
}
#endif /* HAS_SOCKET */
int
do_gpwent(which,gimme,arglast)
int which;
int gimme;
int *arglast;
{
#ifdef I_PWD
register ARRAY *ary = stack;
register int sp = arglast[0];
register STR *str;
struct passwd *getpwnam();
struct passwd *getpwuid();
struct passwd *getpwent();
struct passwd *pwent;
if (which == O_GPWNAM) {
char *name = str_get(ary->ary_array[sp+1]);
pwent = getpwnam(name);
}
else if (which == O_GPWUID) {
int uid = (int)str_gnum(ary->ary_array[sp+1]);
pwent = getpwuid(uid);
}
else
pwent = getpwent();
if (gimme != G_ARRAY) {
astore(ary, ++sp, str = str_mortal(&str_undef));
if (pwent) {
if (which == O_GPWNAM)
str_numset(str, (double)pwent->pw_uid);
else
str_set(str, pwent->pw_name);
}
return sp;
}
if (pwent) {
(void)astore(ary, ++sp, str = str_mortal(&str_no));
str_set(str, pwent->pw_name);
(void)astore(ary, ++sp, str = str_mortal(&str_no));
str_set(str, pwent->pw_passwd);
(void)astore(ary, ++sp, str = str_mortal(&str_no));
str_numset(str, (double)pwent->pw_uid);
(void)astore(ary, ++sp, str = str_mortal(&str_no));
str_numset(str, (double)pwent->pw_gid);
(void)astore(ary, ++sp, str = str_mortal(&str_no));
#ifdef PWCHANGE
str_numset(str, (double)pwent->pw_change);
#else
#ifdef PWQUOTA
str_numset(str, (double)pwent->pw_quota);
#else
#ifdef PWAGE
str_set(str, pwent->pw_age);
#endif
#endif
#endif
(void)astore(ary, ++sp, str = str_mortal(&str_no));
#ifdef PWCLASS
str_set(str,pwent->pw_class);
#else
#ifdef PWCOMMENT
str_set(str, pwent->pw_comment);
#endif
#endif
(void)astore(ary, ++sp, str = str_mortal(&str_no));
str_set(str, pwent->pw_gecos);
(void)astore(ary, ++sp, str = str_mortal(&str_no));
str_set(str, pwent->pw_dir);
(void)astore(ary, ++sp, str = str_mortal(&str_no));
str_set(str, pwent->pw_shell);
#ifdef PWEXPIRE
(void)astore(ary, ++sp, str = str_mortal(&str_no));
str_numset(str, (double)pwent->pw_expire);
#endif
}
return sp;
#else
fatal("password routines not implemented");
#endif
}
int
do_ggrent(which,gimme,arglast)
int which;
int gimme;
int *arglast;
{
#ifdef I_GRP
register ARRAY *ary = stack;
register int sp = arglast[0];
register char **elem;
register STR *str;
struct group *getgrnam();
struct group *getgrgid();
struct group *getgrent();
struct group *grent;
if (which == O_GGRNAM) {
char *name = str_get(ary->ary_array[sp+1]);
grent = getgrnam(name);
}
else if (which == O_GGRGID) {
int gid = (int)str_gnum(ary->ary_array[sp+1]);
grent = getgrgid(gid);
}
else
grent = getgrent();
if (gimme != G_ARRAY) {
astore(ary, ++sp, str = str_mortal(&str_undef));
if (grent) {
if (which == O_GGRNAM)
str_numset(str, (double)grent->gr_gid);
else
str_set(str, grent->gr_name);
}
return sp;
}
if (grent) {
(void)astore(ary, ++sp, str = str_mortal(&str_no));
str_set(str, grent->gr_name);
(void)astore(ary, ++sp, str = str_mortal(&str_no));
str_set(str, grent->gr_passwd);
(void)astore(ary, ++sp, str = str_mortal(&str_no));
str_numset(str, (double)grent->gr_gid);
(void)astore(ary, ++sp, str = str_mortal(&str_no));
for (elem = grent->gr_mem; *elem; elem++) {
str_cat(str, *elem);
if (elem[1])
str_ncat(str," ",1);
}
}
return sp;
#else
fatal("group routines not implemented");
#endif
}
int
do_dirop(optype,stab,gimme,arglast)
int optype;
STAB *stab;
int gimme;
int *arglast;
{
#if defined(DIRENT) && defined(HAS_READDIR)
register ARRAY *ary = stack;
register STR **st = ary->ary_array;
register int sp = arglast[1];
register STIO *stio;
long along;
#ifndef apollo
struct DIRENT *readdir();
#endif
register struct DIRENT *dp;
if (!stab)
goto nope;
if (!(stio = stab_io(stab)))
stio = stab_io(stab) = stio_new();
if (!stio->dirp && optype != O_OPEN_DIR)
goto nope;
st[sp] = &str_yes;
switch (optype) {
case O_OPEN_DIR:
if (stio->dirp)
closedir(stio->dirp);
if (!(stio->dirp = opendir(str_get(st[sp+1]))))
goto nope;
break;
case O_READDIR:
if (gimme == G_ARRAY) {
--sp;
/*SUPPRESS 560*/
while (dp = readdir(stio->dirp)) {
#ifdef DIRNAMLEN
(void)astore(ary,++sp,
str_2mortal(str_make(dp->d_name,dp->d_namlen)));
#else
(void)astore(ary,++sp,
str_2mortal(str_make(dp->d_name,0)));
#endif
}
}
else {
if (!(dp = readdir(stio->dirp)))
goto nope;
st[sp] = str_mortal(&str_undef);
#ifdef DIRNAMLEN
str_nset(st[sp], dp->d_name, dp->d_namlen);
#else
str_set(st[sp], dp->d_name);
#endif
}
break;
#if defined(HAS_TELLDIR) || defined(telldir)
case O_TELLDIR: {
#ifndef telldir
long telldir();
#endif
st[sp] = str_mortal(&str_undef);
str_numset(st[sp], (double)telldir(stio->dirp));
break;
}
#endif
#if defined(HAS_SEEKDIR) || defined(seekdir)
case O_SEEKDIR:
st[sp] = str_mortal(&str_undef);
along = (long)str_gnum(st[sp+1]);
(void)seekdir(stio->dirp,along);
break;
#endif
#if defined(HAS_REWINDDIR) || defined(rewinddir)
case O_REWINDDIR:
st[sp] = str_mortal(&str_undef);
(void)rewinddir(stio->dirp);
break;
#endif
case O_CLOSEDIR:
st[sp] = str_mortal(&str_undef);
(void)closedir(stio->dirp);
stio->dirp = 0;
break;
default:
goto phooey;
}
return sp;
nope:
st[sp] = &str_undef;
if (!errno)
errno = EBADF;
return sp;
#endif
phooey:
fatal("Unimplemented directory operation");
}
int
apply(type,arglast)
int type;
int *arglast;
{
register STR **st = stack->ary_array;
register int sp = arglast[1];
register int items = arglast[2] - sp;
register int val;
register int val2;
register int tot = 0;
char *s;
#ifdef TAINT
for (st += ++sp; items--; st++)
tainted |= (*st)->str_tainted;
st = stack->ary_array;
sp = arglast[1];
items = arglast[2] - sp;
#endif
switch (type) {
case O_CHMOD:
#ifdef TAINT
taintproper("Insecure dependency in chmod");
#endif
if (--items > 0) {
tot = items;
val = (int)str_gnum(st[++sp]);
while (items--) {
if (chmod(str_get(st[++sp]),val))
tot--;
}
}
break;
#ifdef HAS_CHOWN
case O_CHOWN:
#ifdef TAINT
taintproper("Insecure dependency in chown");
#endif
if (items > 2) {
items -= 2;
tot = items;
val = (int)str_gnum(st[++sp]);
val2 = (int)str_gnum(st[++sp]);
while (items--) {
if (chown(str_get(st[++sp]),val,val2))
tot--;
}
}
break;
#endif
#ifdef HAS_KILL
case O_KILL:
#ifdef TAINT
taintproper("Insecure dependency in kill");
#endif
if (--items > 0) {
tot = items;
s = str_get(st[++sp]);
if (isUPPER(*s)) {
if (*s == 'S' && s[1] == 'I' && s[2] == 'G')
s += 3;
if (!(val = whichsig(s)))
fatal("Unrecognized signal name \"%s\"",s);
}
else
val = (int)str_gnum(st[sp]);
if (val < 0) {
val = -val;
while (items--) {
int proc = (int)str_gnum(st[++sp]);
#ifdef HAS_KILLPG
if (killpg(proc,val)) /* BSD */
#else
if (kill(-proc,val)) /* SYSV */
#endif
tot--;
}
}
else {
while (items--) {
if (kill((int)(str_gnum(st[++sp])),val))
tot--;
}
}
}
break;
#endif
case O_UNLINK:
#ifdef TAINT
taintproper("Insecure dependency in unlink");
#endif
tot = items;
while (items--) {
s = str_get(st[++sp]);
if (euid || unsafe) {
if (UNLINK(s))
tot--;
}
else { /* don't let root wipe out directories without -U */
#ifdef HAS_LSTAT
if (lstat(s,&statbuf) < 0 || S_ISDIR(statbuf.st_mode))
#else
if (stat(s,&statbuf) < 0 || S_ISDIR(statbuf.st_mode))
#endif
tot--;
else {
if (UNLINK(s))
tot--;
}
}
}
break;
case O_UTIME:
#ifdef TAINT
taintproper("Insecure dependency in utime");
#endif
if (items > 2) {
#ifdef I_UTIME
struct utimbuf utbuf;
#else
struct {
long actime;
long modtime;
} utbuf;
#endif
Zero(&utbuf, sizeof utbuf, char);
utbuf.actime = (long)str_gnum(st[++sp]); /* time accessed */
utbuf.modtime = (long)str_gnum(st[++sp]); /* time modified */
items -= 2;
#ifndef lint
tot = items;
while (items--) {
if (utime(str_get(st[++sp]),&utbuf))
tot--;
}
#endif
}
else
items = 0;
break;
}
return tot;
}
/* Do the permissions allow some operation? Assumes statcache already set. */
int
cando(bit, effective, statbufp)
int bit;
int effective;
register struct stat *statbufp;
{
#ifdef DOSISH
/* [Comments and code from Len Reed]
* MS-DOS "user" is similar to UNIX's "superuser," but can't write
* to write-protected files. The execute permission bit is set
* by the Miscrosoft C library stat() function for the following:
* .exe files
* .com files
* .bat files
* directories
* All files and directories are readable.
* Directories and special files, e.g. "CON", cannot be
* write-protected.
* [Comment by Tom Dinger -- a directory can have the write-protect
* bit set in the file system, but DOS permits changes to
* the directory anyway. In addition, all bets are off
* here for networked software, such as Novell and
* Sun's PC-NFS.]
*/
/* Atari stat() does pretty much the same thing. we set x_bit_set_in_stat
* too so it will actually look into the files for magic numbers
*/
return (bit & statbufp->st_mode) ? TRUE : FALSE;
#else /* ! MSDOS */
if ((effective ? euid : uid) == 0) { /* root is special */
if (bit == S_IXUSR) {
if (statbufp->st_mode & 0111 || S_ISDIR(statbufp->st_mode))
return TRUE;
}
else
return TRUE; /* root reads and writes anything */
return FALSE;
}
if (statbufp->st_uid == (effective ? euid : uid) ) {
if (statbufp->st_mode & bit)
return TRUE; /* ok as "user" */
}
else if (ingroup((int)statbufp->st_gid,effective)) {
if (statbufp->st_mode & bit >> 3)
return TRUE; /* ok as "group" */
}
else if (statbufp->st_mode & bit >> 6)
return TRUE; /* ok as "other" */
return FALSE;
#endif /* ! MSDOS */
}
int
ingroup(testgid,effective)
int testgid;
int effective;
{
if (testgid == (effective ? egid : gid))
return TRUE;
#ifdef HAS_GETGROUPS
#ifndef NGROUPS
#define NGROUPS 32
#endif
{
GROUPSTYPE gary[NGROUPS];
int anum;
anum = getgroups(NGROUPS,gary);
while (--anum >= 0)
if (gary[anum] == testgid)
return TRUE;
}
#endif
return FALSE;
}
#if defined(HAS_MSG) || defined(HAS_SEM) || defined(HAS_SHM)
int
do_ipcget(optype, arglast)
int optype;
int *arglast;
{
register STR **st = stack->ary_array;
register int sp = arglast[0];
key_t key;
int n, flags;
key = (key_t)str_gnum(st[++sp]);
n = (optype == O_MSGGET) ? 0 : (int)str_gnum(st[++sp]);
flags = (int)str_gnum(st[++sp]);
errno = 0;
switch (optype)
{
#ifdef HAS_MSG
case O_MSGGET:
return msgget(key, flags);
#endif
#ifdef HAS_SEM
case O_SEMGET:
return semget(key, n, flags);
#endif
#ifdef HAS_SHM
case O_SHMGET:
return shmget(key, n, flags);
#endif
#if !defined(HAS_MSG) || !defined(HAS_SEM) || !defined(HAS_SHM)
default:
fatal("%s not implemented", opname[optype]);
#endif
}
return -1; /* should never happen */
}
int
do_ipcctl(optype, arglast)
int optype;
int *arglast;
{
register STR **st = stack->ary_array;
register int sp = arglast[0];
STR *astr;
char *a;
int id, n, cmd, infosize, getinfo, ret;
id = (int)str_gnum(st[++sp]);
n = (optype == O_SEMCTL) ? (int)str_gnum(st[++sp]) : 0;
cmd = (int)str_gnum(st[++sp]);
astr = st[++sp];
infosize = 0;
getinfo = (cmd == IPC_STAT);
switch (optype)
{
#ifdef HAS_MSG
case O_MSGCTL:
if (cmd == IPC_STAT || cmd == IPC_SET)
infosize = sizeof(struct msqid_ds);
break;
#endif
#ifdef HAS_SHM
case O_SHMCTL:
if (cmd == IPC_STAT || cmd == IPC_SET)
infosize = sizeof(struct shmid_ds);
break;
#endif
#ifdef HAS_SEM
case O_SEMCTL:
if (cmd == IPC_STAT || cmd == IPC_SET)
infosize = sizeof(struct semid_ds);
else if (cmd == GETALL || cmd == SETALL)
{
struct semid_ds semds;
if (semctl(id, 0, IPC_STAT, (union semun)&semds) == -1)
return -1;
getinfo = (cmd == GETALL);
infosize = semds.sem_nsems * sizeof(short);
/* "short" is technically wrong but much more portable
than guessing about u_?short(_t)? */
}
break;
#endif
#if !defined(HAS_MSG) || !defined(HAS_SEM) || !defined(HAS_SHM)
default:
fatal("%s not implemented", opname[optype]);
#endif
}
if (infosize)
{
if (getinfo)
{
STR_GROW(astr, infosize+1);
a = str_get(astr);
}
else
{
a = str_get(astr);
if (astr->str_cur != infosize)
{
errno = EINVAL;
return -1;
}
}
}
else
{
int i = (int)str_gnum(astr);
a = (char *)i; /* ouch */
}
errno = 0;
switch (optype)
{
#ifdef HAS_MSG
case O_MSGCTL:
ret = msgctl(id, cmd, (struct msqid_ds *)a);
break;
#endif
#ifdef HAS_SEM
case O_SEMCTL:
ret = semctl(id, n, cmd, (union semun)((int)a));
break;
#endif
#ifdef HAS_SHM
case O_SHMCTL:
ret = shmctl(id, cmd, (struct shmid_ds *)a);
break;
#endif
}
if (getinfo && ret >= 0) {
astr->str_cur = infosize;
astr->str_ptr[infosize] = '\0';
}
return ret;
}
int
do_msgsnd(arglast)
int *arglast;
{
#ifdef HAS_MSG
register STR **st = stack->ary_array;
register int sp = arglast[0];
STR *mstr;
char *mbuf;
int id, msize, flags;
id = (int)str_gnum(st[++sp]);
mstr = st[++sp];
flags = (int)str_gnum(st[++sp]);
mbuf = str_get(mstr);
if ((msize = mstr->str_cur - sizeof(long)) < 0) {
errno = EINVAL;
return -1;
}
errno = 0;
return msgsnd(id, (struct msgbuf *)mbuf, msize, flags);
#else
fatal("msgsnd not implemented");
#endif
}
int
do_msgrcv(arglast)
int *arglast;
{
#ifdef HAS_MSG
register STR **st = stack->ary_array;
register int sp = arglast[0];
STR *mstr;
char *mbuf;
long mtype;
int id, msize, flags, ret;
id = (int)str_gnum(st[++sp]);
mstr = st[++sp];
msize = (int)str_gnum(st[++sp]);
mtype = (long)str_gnum(st[++sp]);
flags = (int)str_gnum(st[++sp]);
mbuf = str_get(mstr);
if (mstr->str_cur < sizeof(long)+msize+1) {
STR_GROW(mstr, sizeof(long)+msize+1);
mbuf = str_get(mstr);
}
errno = 0;
ret = msgrcv(id, (struct msgbuf *)mbuf, msize, mtype, flags);
if (ret >= 0) {
mstr->str_cur = sizeof(long)+ret;
mstr->str_ptr[sizeof(long)+ret] = '\0';
}
return ret;
#else
fatal("msgrcv not implemented");
#endif
}
int
do_semop(arglast)
int *arglast;
{
#ifdef HAS_SEM
register STR **st = stack->ary_array;
register int sp = arglast[0];
STR *opstr;
char *opbuf;
int id, opsize;
id = (int)str_gnum(st[++sp]);
opstr = st[++sp];
opbuf = str_get(opstr);
opsize = opstr->str_cur;
if (opsize < sizeof(struct sembuf)
|| (opsize % sizeof(struct sembuf)) != 0) {
errno = EINVAL;
return -1;
}
errno = 0;
return semop(id, (struct sembuf *)opbuf, opsize/sizeof(struct sembuf));
#else
fatal("semop not implemented");
#endif
}
int
do_shmio(optype, arglast)
int optype;
int *arglast;
{
#ifdef HAS_SHM
register STR **st = stack->ary_array;
register int sp = arglast[0];
STR *mstr;
char *mbuf, *shm;
int id, mpos, msize;
struct shmid_ds shmds;
#ifndef VOIDSHMAT
extern char *shmat();
#endif
id = (int)str_gnum(st[++sp]);
mstr = st[++sp];
mpos = (int)str_gnum(st[++sp]);
msize = (int)str_gnum(st[++sp]);
errno = 0;
if (shmctl(id, IPC_STAT, &shmds) == -1)
return -1;
if (mpos < 0 || msize < 0 || mpos + msize > shmds.shm_segsz) {
errno = EFAULT; /* can't do as caller requested */
return -1;
}
shm = (char*)shmat(id, (char*)NULL, (optype == O_SHMREAD) ? SHM_RDONLY : 0);
if (shm == (char *)-1) /* I hate System V IPC, I really do */
return -1;
mbuf = str_get(mstr);
if (optype == O_SHMREAD) {
if (mstr->str_cur < msize) {
STR_GROW(mstr, msize+1);
mbuf = str_get(mstr);
}
Copy(shm + mpos, mbuf, msize, char);
mstr->str_cur = msize;
mstr->str_ptr[msize] = '\0';
}
else {
int n;
if ((n = mstr->str_cur) > msize)
n = msize;
Copy(mbuf, shm + mpos, n, char);
if (n < msize)
memzero(shm + mpos + n, msize - n);
}
return shmdt(shm);
#else
fatal("shm I/O not implemented");
#endif
}
#endif /* SYSV IPC */