home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 15 / BBS in a box XV-2.iso / Files II / Prog / M / MacPerl 4.13 source.sit / Perl Source ƒ / Perl / doio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-04  |  65.8 KB  |  3,124 lines  |  [TEXT/MPS ]

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