[0001]
[0002]
[0003]
[0004]
[0005]
[0006]
[0007]
[0008]
[0009]
[0010]
[0011]
[0012]
[0013]
[0014]
[0015]
[0016]
[0017]
[0018]
[0019]
[0020]
[0021]
[0022]
[0023]
[0024]
[0025]
[0026]
[0027]
[0028]
[0029]
[0030]
[0031]
[0032]
[0033]
[0034]
[0035]
[0036]
[0037]
[0038]
[0039]
[0040]
[0041]
[0042]
[0043]
[0044]
[0045]
[0046]
[0047]
[0048]
[0049]
[0050]
[0051]
[0052]
[0053]
[0054]
[0055]
[0056]
[0057]
[0058]
[0059]
[0060]
[0061]
[0062]
[0063]
[0064]
[0065]
[0066]
[0067]
[0068]
[0069]
[0070]
[0071]
[0072]
[0073]
[0074]
[0075]
[0076]
[0077]
[0078]
[0079]
[0080]
[0081]
[0082]
[0083]
[0084]
[0085]
[0086]
[0087]
[0088]
[0089]
[0090]
[0091]
[0092]
[0093]
[0094]
[0095]
[0096]
[0097]
[0098]
[0099]
[0100]
[0101]
[0102]
[0103]
[0104]
[0105]
[0106]
[0107]
[0108]
[0109]
[0110]
[0111]
[0112]
[0113]
[0114]
[0115]
[0116]
[0117]
[0118]
[0119]
[0120]
[0121]
[0122]
[0123]
[0124]
[0125]
[0126]
[0127]
[0128]
[0129]
[0130]
[0131]
[0132]
[0133]
[0134]
[0135]
[0136]
[0137]
[0138]
[0139]
[0140]
[0141]
[0142]
[0143]
[0144]
[0145]
[0146]
[0147]
[0148]
[0149]
[0150]
[0151]
[0152]
[0153]
[0154]
[0155]
[0156]
[0157]
[0158]
[0159]
[0160]
[0161]
[0162]
[0163]
[0164]
[0165]
[0166]
[0167]
[0168]
[0169]
[0170]
[0171]
[0172]
[0173]
[0174]
[0175]
[0176]
[0177]
[0178]
[0179]
[0180]
[0181]
[0182]
[0183]
[0184]
[0185]
[0186]
[0187]
[0188]
[0189]
[0190]
[0191]
[0192]
[0193]
[0194]
[0195]
[0196]
[0197]
[0198]
[0199]
[0200]
[0201]
[0202]
[0203]
[0204]
[0205]
[0206]
[0207]
[0208]
[0209]
[0210]
[0211]
[0212]
[0213]
[0214]
[0215]
[0216]
[0217]
[0218]
[0219]
[0220]
[0221]
[0222]
[0223]
[0224]
[0225]
[0226]
[0227]
[0228]
[0229]
[0230]
[0231]
[0232]
[0233]
[0234]
[0235]
[0236]
[0237]
[0238]
[0239]
[0240]
[0241]
[0242]
[0243]
[0244]
[0245]
[0246]
[0247]
[0248]
[0249]
[0250]
[0251]
[0252]
[0253]
[0254]
[0255]
[0256]
[0257]
[0258]
[0259]
[0260]
[0261]
[0262]
[0263]
[0264]
[0265]
[0266]
[0267]
[0268]
[0269]
[0270]
[0271]
[0272]
[0273]
[0274]
[0275]
[0276]
[0277]
[0278]
[0279]
[0280]
[0281]
[0282]
[0283]
[0284]
[0285]
[0286]
[0287]
[0288]
[0289]
[0290]
[0291]
[0292]
[0293]
[0294]
[0295]
[0296]
[0297]
[0298]
[0299]
[0300]
[0301]
[0302]
[0303]
[0304]
[0305]
[0306]
[0307]
[0308]
[0309]
[0310]
[0311]
[0312]
[0313]
[0314]
[0315]
[0316]
[0317]
[0318]
[0319]
/*****************************************************************************/
/*
                                   spawn.c

Spawn a (sub)process and retrieve its output to an internal buffer.


VERSION HISTORY
---------------
21-FEB-2019  MGD  initial
*/
/*****************************************************************************/

#include "wasdoc.h"

#include <descrip.h>
#include <iodef.h>
#include <lnmdef.h>
#include <starlet.h>
#include <lib$routines.h>

#define SPAWN_MAXMSG  2048
#define SPAWN_BUFQUO 65000  /* VAX limit? */
#define SPAWN_MBX_LNM "WASDOC_SPAWN_OUTPUT"

extern int  dbug, isCgi, isCgiPlus;

/*****************************************************************************/
/*
Spawn a subprocess to execute the supplied command.  Use NOWAIT flag and
explicitly hibernate at USER mode otherwise the USER mode output ASTs won't be
delivered.  Insert the output into the document as required.  Bit convoluted
but return negative for test true, 0 for test false and output OK, or positive
vaxc$errno number.
*/

int SpawnCommand
(
struct wasdoc_st *docptr,
char *cmd,
char *test
)
{
   static long  flags = 0x01;
   static $DESCRIPTOR (CmdDsc, "");
   static $DESCRIPTOR (MsgDsc, "");
   static $DESCRIPTOR (MbxLnmDsc, SPAWN_MBX_LNM);
   static $DESCRIPTOR (NlDsc, "NL:");

   int  ignore = 0, noescape = 0, reuse = 0, trim = 0;
   uint  status;
   ushort  slen;
   char  *cptr, *sptr;

   if (dbug>1) dbugThis (FI_LI, "SpawnCommand() |%s|", cmd);

   cptr = cmd;
   while (*cptr == '!' || *cptr == '\"' || *cptr == '-' || *cptr == '&')
   {
      if (*cptr == '!') ignore = *cptr++;
      if (*cptr == '\"') noescape = *cptr++;
      if (*cptr == '-') trim = *cptr++;
      if (*cptr == '&') reuse = *cptr++;
   }
   if (*cptr == '\\') cptr++;

   if (spawnAuth (docptr) < 0)
   {
      /* not authorised */
      if (!test) wasDocInsertStatus (docptr, SS$_AUTHFAIL);
      if (ignore) return (0);
      return (ECHILD);
   }

   if (reuse)
   {
      /* reuse previous output */
      if (!docptr->spawnOutLength) return (EINVAL);
      if (test)
         if (testCondition (docptr, docptr->spawnOutPtr, test))
            return (-1);
         else
            return (0);
      else
      if (noescape)
         wasDocAsIs (docptr, docptr->spawnOutPtr);
      else
         wasDocEntify (docptr, docptr->spawnOutPtr);
      return (0);
   }

   while (isspace(*cptr)) cptr++;
   if (!*cptr)
      if (ignore)
         return (0);
      else
         return (EINVAL);
   for (sptr = cptr; *sptr; sptr++);

   CmdDsc.dsc$a_pointer = cptr; 
   CmdDsc.dsc$w_length = sptr - cptr; 

   /* a temporary mailbox */
   status = sys$crembx (0, &docptr->spawnMbx, SPAWN_MAXMSG, SPAWN_BUFQUO,
                        0, 0, &MbxLnmDsc, 0, 0); 
   if (dbug>1) dbugThis (FI_LI, "sys$crembx() %%X%08.08X", status);

   if (!(status & 1))
   {
      if (!test) wasDocInsertStatus (docptr, SS$_AUTHFAIL);
      if (ignore) return (0);
      return (EIO);
   }

   /* initiate reads from soon-to-be spawned process */
   if (docptr->spawnOutPtr)
   {
      free (docptr->spawnOutPtr);
      docptr->spawnOutPtr = NULL;
      docptr->spawnOutLength = docptr->spawnOutSize = 0;
   }
   SpawnOutAst (docptr);

   if (docptr->insight >= 4) wasDocInsight (docptr, "%s", cptr);

   status = lib$spawn (&CmdDsc, &NlDsc, &MbxLnmDsc, &flags, 0,
                       &docptr->spawnPID, &docptr->spawnStatus,
                       0, SpawnWake, 0, 0, 0, 0);
   if (dbug>1) dbugThis (FI_LI, "lib$spawn () %08.08X %%X%08.08X\n",
                         docptr->spawnPID, status);

   /* hibernate at this (USER) mode */
   sys$hiber ();

   if (dbug>1) dbugThis (FI_LI, "lib$spawn() %08.08X", docptr->spawnStatus);

   sys$dassgn (docptr->spawnMbx);
   docptr->spawnMbx = 0;

   if ((status & 1) && !(docptr->spawnStatus & 1))
      status = docptr->spawnStatus;

   if ((status & 1) && docptr->spawnOutStatus != SS$_ENDOFFILE)
      status = docptr->spawnOutStatus;

   if (docptr->spawnOutLength)
      if (docptr->insight >= 5)
         wasDocInsight (docptr, "<pre>%s</pre>", docptr->spawnOutPtr);

   if (trim && docptr->spawnOutLength)
   {
      /* eliminate multiple blank lines and leading/trailing white-space */
      sptr = docptr->spawnOutPtr + docptr->spawnOutLength;
      while (sptr > docptr->spawnOutPtr && isspace(*(sptr-1))) sptr--;
      *sptr = '\0';
      for (sptr = cptr = docptr->spawnOutPtr; *cptr; cptr++)
         if (!isspace(*cptr)) break;
      for (; *cptr; *sptr++ = *cptr++)
      {
         if (*cptr != '\n') continue;
         if (*(USHORTPTR)(sptr-2) != '\n\n') continue;
         while (*cptr == '\n') cptr++;
      }
      *sptr = '\0';
      docptr->spawnOutLength = sptr - docptr->spawnOutPtr;
   }

   if (!(status & 1))
   {
      if (docptr->insight >= 4) wasDocInsight (docptr, "%%X%08.08X", status);
      if (!test) wasDocInsertStatus (docptr, status);
      return (ECHILD);
   }

   if (test)
      if (testCondition (docptr, docptr->spawnOutPtr, test))
         return (-1);
      else
         return (0);
   else
   if (noescape)
      wasDocAsIs (docptr, docptr->spawnOutPtr);
   else
      wasDocEntify (docptr, docptr->spawnOutPtr);

   return (0);
}

/*****************************************************************************/
/*
Subprocess has completed.  Bring the parent (this process) out of hibernation.
*/

void SpawnWake ()

{
   sys$wake (0, 0);
}

/*****************************************************************************/
/*
Buffer output from subprocess. 
*/

void SpawnOutAst (struct wasdoc_st *docptr)

{
   int  status;
   char  *cptr;

   if (dbug>1) dbugThis (FI_LI, "SpawnOutAst() %%X%08.08X",
                         docptr->spawnIOsb.iosb$w_status);

   if (docptr->spawnOutPtr)
   {
      docptr->spawnOutStatus = docptr->spawnIOsb.iosb$w_status;
      if (!(docptr->spawnOutStatus & 1))
      {
         /* mailbox read failed */
         sys$dassgn (docptr->spawnMbx);
         docptr->spawnMbx = 0;
         return;
      }
      cptr = docptr->spawnOutPtr + docptr->spawnOutLength;
      cptr[docptr->spawnIOsb.iosb$w_bcnt] = '\n';
      cptr[docptr->spawnIOsb.iosb$w_bcnt+1] = '\0';
      docptr->spawnOutLength += docptr->spawnIOsb.iosb$w_bcnt + 1;
      if (dbug>1) dbugThis (FI_LI, "%d |%s|\n",
                            docptr->spawnIOsb.iosb$w_bcnt, cptr);
   }

   if (docptr->spawnOutSize - docptr->spawnOutLength <= SPAWN_MAXMSG)
   {
      if (docptr->spawnOutSize)
         docptr->spawnOutSize += SPAWN_MAXMSG;
      else
         docptr->spawnOutSize = SPAWN_MAXMSG * 2;
      docptr->spawnOutPtr = realloc (docptr->spawnOutPtr,
                                     docptr->spawnOutSize + 32);
      if (!docptr->spawnOutPtr) exit (vaxc$errno);
   }

   cptr = docptr->spawnOutPtr + docptr->spawnOutLength;

   status = sys$qio (0, docptr->spawnMbx, IO$_READLBLK, &docptr->spawnIOsb,
                     SpawnOutAst, docptr, cptr, SPAWN_MAXMSG, 0, 0, 0, 0); 

   if (!(status & 1))
   {
      /* $QIO failed */
      sys$dassgn (docptr->spawnMbx);
      docptr->spawnMbx = 0;
   }
}

/*****************************************************************************/
/*
For a dynamic document authorise the spawn.
*/

int spawnAuth (struct wasdoc_st *docptr)

{
   static unsigned short  slen;
   static unsigned long  lnmAttributes,
                         lnmIndex;
   static char  lnmValue [256];
   static $DESCRIPTOR (lnmNameDsc, SPAWN_LOGNAM);
   static $DESCRIPTOR (lnmSystemDsc, "LNM$SYSTEM");
   static struct {
      short int  buf_len;
      short int  item;
      void  *buf_addr;
      unsigned short  *ret_len;
   } lnmItems [] =
   {
      { sizeof(lnmIndex), LNM$_INDEX, &lnmIndex, 0 },
      { sizeof(lnmAttributes), LNM$_ATTRIBUTES, &lnmAttributes, 0 },
      { sizeof(lnmValue)-1, LNM$_STRING, lnmValue, &slen },
      { 0,0,0,0 }
   };

   int  status;

   /*********/
   /* begin */
   /*********/

   if (docptr->spawnAuth) return (docptr->spawnAuth);

   if (docptr->isStatic) return (docptr->spawnAuth = 1);

   for (lnmIndex = 0; lnmIndex <= 127; lnmIndex++)
   {
      status = sys$trnlnm (0, &lnmSystemDsc, &lnmNameDsc, 0, &lnmItems);
      if (dbug>1) dbugThis (FI_LI, "%%X%08.08X %d",
                            status, (lnmAttributes & LNM$M_EXISTS));
      if ((status & 1) && (lnmAttributes & LNM$M_EXISTS))
      {
         lnmValue[slen] = '\0';
         if (dbug>1) dbugThis (FI_LI, "|%s|%s|", docptr->dname, lnmValue);
         if (!strcasecmp (docptr->dname, lnmValue))
         {
            docptr->spawnAuth = 1;
            break;
         }
      }
      else
      {
         docptr->spawnAuth = -1;
         break;
      }
   }

   return (docptr->spawnAuth);
}

/*****************************************************************************/