| /* $RCSfile$$Revision$$Date$ |
| * |
| * Copyright (c) 1989, Larry Wall |
| * |
| * You may distribute under the terms of the GNU General Public License |
| * as specified in the README file that comes with the perl 3.0 kit. |
| * |
| * $Log$ |
| * Revision 1.3 2004/07/17 21:26:00 reid |
| * get rid of incorrect declaration of shmat(). If it isn't in sys/shm.h then |
| * "oh well.." |
| * |
| * Revision 1.2 2004/06/25 08:07:12 lattner |
| * fix the test on FreeBSD, contributed by Vladimir Merzliakov |
| * |
| * Revision 1.1 2004/02/17 22:21:16 criswell |
| * Initial commit of the perl Malloc Benchmark. I've cheated a little by |
| * generating the yacc output files and committing them directly, but it was |
| * easier than disabling the Bison Voodoo that gets executed by default. |
| * |
| * 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" |
| |
| #ifdef HAS_SOCKET |
| #include <sys/socket.h> |
| #include <netdb.h> |
| #endif |
| |
| #ifdef HAS_SELECT |
| #ifdef I_SYS_SELECT |
| #ifndef I_SYS_TIME |
| #include <sys/select.h> |
| #endif |
| #endif |
| #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; |
| |
| 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") */ |
| |
| 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 = mypclose(stio->ifp); |
| else if (stio->type == '-') |
| result = 0; |
| 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 > 2) |
| fprintf(stderr,"Warning: unable to close filehandle %s properly.\n", |
| stab_name(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 == '|') { |
| 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)) |
| return 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'; |
| for (; isspace(*name); name++) ; |
| fp = mypopen(name,"r"); |
| stio->type = '|'; |
| } |
| else { |
| stio->type = '<'; |
| for (; isspace(*name); name++) ; |
| if (strEQ(name,"-")) { |
| fp = stdin; |
| stio->type = '-'; |
| } |
| else |
| fp = fopen(name,"r"); |
| } |
| } |
| Safefree(myname); |
| if (!fp) |
| return FALSE; |
| if (stio->type && |
| stio->type != '|' && stio->type != '-') { |
| if (fstat(fileno(fp),&statbuf) < 0) { |
| (void)fclose(fp); |
| return FALSE; |
| } |
| if (S_ISSOCK(statbuf.st_mode)) |
| stio->type = 's'; /* in case a socket was passed in to us */ |
| #ifdef S_IFMT |
| else if (!(statbuf.st_mode & S_IFMT)) |
| stio->type = 's'; /* some OS's return 0 on fstat()ed socket */ |
| #endif |
| } |
| #if defined(HAS_FCNTL) && defined(F_SETFD) |
| fd = fileno(fp); |
| fcntl(fd,F_SETFD,fd >= 3); |
| #endif |
| stio->ifp = fp; |
| if (writing) { |
| if (stio->type != 's') |
| stio->ofp = fp; |
| else |
| if (!(stio->ofp = fdopen(fileno(fp),"w"))) { |
| fclose(fp); |
| stio->ifp = Nullfp; |
| } |
| } |
| return TRUE; |
| } |
| |
| FILE * |
| nextargv(stab) |
| register STAB *stab; |
| { |
| register STR *str; |
| int filedev; |
| int fileino; |
| 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; |
| } |
| filedev = statbuf.st_dev; |
| fileino = statbuf.st_ino; |
| 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 MSDOS |
| 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 MSDOS |
| 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) |
| return FALSE; |
| stio = stab_io(stab); |
| if (!stio) { /* never opened */ |
| if (dowarn && explicit) |
| warn("Close on unopened file <%s>",stab_name(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; |
| |
| if (feof(stio->ifp)) |
| (void)fseek (stio->ifp, 0L, 2); /* ultrix 1.2 workaround */ |
| |
| return ftell(stio->ifp); |
| |
| phooey: |
| if (dowarn) |
| warn("tell() on unopened file"); |
| 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; |
| |
| if (feof(stio->ifp)) |
| (void)fseek (stio->ifp, 0L, 2); /* ultrix 1.2 workaround */ |
| |
| return fseek(stio->ifp, pos, whence) >= 0; |
| |
| nuts: |
| if (dowarn) |
| warn("seek() on unopened file"); |
| 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) |
| return -1; |
| stio = stab_io(stab); |
| if (!stio) |
| 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 MSDOS |
| 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 MSDOS |
| 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) |
| 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 |
| 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) || |
| 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) || |
| 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"); |
| 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_fullname(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"); |
| 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; |
| |
| laststype = O_STAT; |
| 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,""); |
| 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_name(arg[1].arg_ptr.arg_stab)); |
| statstab = Nullstab; |
| str_set(statname,""); |
| return (laststatval = -1); |
| } |
| } |
| else { |
| statstab = Nullstab; |
| str_set(statname,str_get(str)); |
| return (laststatval = stat(str_get(str),&statcache)); |
| } |
| } |
| |
| 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 |
| return (laststatval = lstat(str_get(str),&statcache)); |
| #else |
| return (laststatval = stat(str_get(str),&statcache)); |
| #endif |
| } |
| |
| 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) { |
| #ifdef STDSTDIO |
| fstat(fileno(stio->ifp),&statcache); |
| 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 |
| fatal("-T and -B not implemented on filehandles\n"); |
| #endif |
| } |
| else { |
| if (dowarn) |
| warn("Test on unopened file <%s>", |
| stab_name(arg[1].arg_ptr.arg_stab)); |
| return &str_undef; |
| } |
| } |
| else { |
| statstab = Nullstab; |
| str_set(statname,str_get(str)); |
| really_filename: |
| i = open(str_get(str),0); |
| if (i < 0) |
| return &str_undef; |
| fstat(i,&statcache); |
| len = read(i,tbuf,512); |
| (void)close(i); |
| if (len <= 0) /* null file is anything */ |
| return &str_yes; |
| 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; |
| } |
| |
| 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 **argv; |
| 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); |
| Safefree(argv); |
| } |
| return FALSE; |
| } |
| |
| static char **Argv = Null(char **); |
| static char *Cmd = Nullch; |
| |
| 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]; |
| |
| #ifdef TAINT |
| taintenv(); |
| taintproper("Insecure dependency in exec"); |
| #endif |
| |
| /* 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 */ |
| |
| 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) |
| 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), (void *) addr, st[sp]->str_cur) >= 0; |
| |
| nuts: |
| if (dowarn) |
| warn("bind() on closed fd"); |
| 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), (void *) addr, st[sp]->str_cur) >= 0; |
| |
| nuts: |
| if (dowarn) |
| warn("connect() on closed fd"); |
| 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"); |
| 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),(void *)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"); |
| 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"); |
| 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; |
| int lvl; |
| int optname; |
| |
| if (!stab) |
| goto nuts; |
| |
| stio = stab_io(stab); |
| if (!stio || !stio->ifp) |
| goto nuts; |
| |
| fd = fileno(stio->ifp); |
| lvl = (int)str_gnum(st[sp+1]); |
| optname = (int)str_gnum(st[sp+2]); |
| switch (optype) { |
| case O_GSOCKOPT: |
| st[sp] = str_2mortal(str_new(257)); |
| st[sp]->str_cur = 256; |
| st[sp]->str_pok = 1; |
| if (getsockopt(fd, lvl, optname, st[sp]->str_ptr, &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; |
| 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(257)); |
| st[sp]->str_cur = 256; |
| st[sp]->str_pok = 1; |
| fd = fileno(stio->ifp); |
| switch (optype) { |
| case O_GETSOCKNAME: |
| if (getsockname(fd, (void *) st[sp]->str_ptr, &st[sp]->str_cur) < 0) |
| goto nuts2; |
| break; |
| case O_GETPEERNAME: |
| if (getpeername(fd, (void *) st[sp]->str_ptr, &st[sp]->str_cur) < 0) |
| goto nuts2; |
| break; |
| } |
| |
| return sp; |
| |
| nuts: |
| if (dowarn) |
| warn("get{sock,peer}name() on closed fd"); |
| 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 (gimme != G_ARRAY) { |
| astore(ary, ++sp, str_mortal(&str_undef)); |
| return sp; |
| } |
| |
| 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 |
| 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 (gimme != G_ARRAY) { |
| astore(ary, ++sp, str_mortal(&str_undef)); |
| return sp; |
| } |
| |
| 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 (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 (gimme != G_ARRAY) { |
| astore(ary, ++sp, str_mortal(&str_undef)); |
| return sp; |
| } |
| |
| 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 (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 (gimme != G_ARRAY) { |
| astore(ary, ++sp, str_mortal(&str_undef)); |
| return sp; |
| } |
| |
| 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 (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, |
| st[sp+1]->str_ptr, |
| st[sp+2]->str_ptr, |
| st[sp+3]->str_ptr, |
| tbuf); |
| #else |
| nfound = select( |
| maxlen * 8, |
| (void *)fd_sets[1], |
| (void *)fd_sets[2], |
| (void *)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]; |
| } |
| } |
| } |
| #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 (gimme != G_ARRAY) { |
| astore(ary, ++sp, str_mortal(&str_undef)); |
| return sp; |
| } |
| |
| 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 (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 (gimme != G_ARRAY) { |
| astore(ary, ++sp, str_mortal(&str_undef)); |
| return sp; |
| } |
| |
| 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 (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 telldir |
| long telldir(); |
| #endif |
| struct DIRENT *readdir(); |
| register struct DIRENT *dp; |
| |
| if (!stab) |
| goto nope; |
| if (!(stio = stab_io(stab))) |
| stio = stab_io(stab) = stio_new(); |
| if (!stio->dirp && optype != O_OPENDIR) |
| goto nope; |
| st[sp] = &str_yes; |
| switch (optype) { |
| case O_OPENDIR: |
| 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; |
| 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 MACH |
| case O_TELLDIR: |
| case O_SEEKDIR: |
| goto nope; |
| #else |
| case O_TELLDIR: |
| st[sp] = str_mortal(&str_undef); |
| str_numset(st[sp], (double)telldir(stio->dirp)); |
| break; |
| case O_SEEKDIR: |
| st[sp] = str_mortal(&str_undef); |
| along = (long)str_gnum(st[sp+1]); |
| (void)seekdir(stio->dirp,along); |
| break; |
| #endif |
| case O_REWINDDIR: |
| st[sp] = str_mortal(&str_undef); |
| (void)rewinddir(stio->dirp); |
| break; |
| case O_CLOSEDIR: |
| st[sp] = str_mortal(&str_undef); |
| (void)closedir(stio->dirp); |
| stio->dirp = 0; |
| break; |
| } |
| return sp; |
| |
| nope: |
| st[sp] = &str_undef; |
| return sp; |
| |
| #else |
| fatal("Unimplemented directory operation"); |
| #endif |
| } |
| |
| 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 MSDOS |
| /* [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.] |
| */ |
| |
| 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, &semds) == -1) |
| return -1; |
| getinfo = (cmd == GETALL); |
| #ifdef _POSIX_SOURCE |
| typedef ushort ushort_t; |
| infosize = semds.sem_nsems * sizeof(ushort_t); |
| #else |
| infosize = semds.sem_nsems * sizeof(ushort); |
| #endif |
| } |
| 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, a); |
| break; |
| #endif |
| #ifdef HAS_SEM |
| case O_SEMCTL: |
| ret = semctl(id, n, cmd, a); |
| break; |
| #endif |
| #ifdef HAS_SHM |
| case O_SHMCTL: |
| ret = shmctl(id, cmd, 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, 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, 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, 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; |
| |
| 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 = 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); |
| } |
| bcopy(shm + mpos, mbuf, msize); |
| mstr->str_cur = msize; |
| mstr->str_ptr[msize] = '\0'; |
| } |
| else { |
| int n; |
| |
| if ((n = mstr->str_cur) > msize) |
| n = msize; |
| bcopy(mbuf, shm + mpos, n); |
| if (n < msize) |
| bzero(shm + mpos + n, msize - n); |
| } |
| return shmdt(shm); |
| #else |
| fatal("shm I/O not implemented"); |
| #endif |
| } |
| |
| #endif /* SYSV IPC */ |