home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional / OS2PRO194.ISO / os2 / prgramer / perl / doio.c < prev    next >
C/C++ Source or Header  |  1991-06-11  |  61KB  |  2,774 lines

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