home *** CD-ROM | disk | FTP | other *** search
/ ftp.muug.mb.ca / 2014.06.ftp.muug.mb.ca.tar / ftp.muug.mb.ca / pub / src / perl / doio.c < prev    next >
C/C++ Source or Header  |  1992-04-11  |  60KB  |  2,825 lines

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