Example #1
0
int bbcp_File::Write_All(bbcp_BuffPool &inPool, int nstrms)
{
    bbcp_FileChkSum *csP = 0;
    bbcp_BuffPool   *iBP;
    pthread_t tid;
    int rc, csType;

// If we have no IOB, then do a simple in-line passthru
//
   if (!IOB) return Passthru(&inPool, &bbcp_CPool, 0, nstrms);

// Establish checksum options as well as ordering options. Note that we do
// not support checksums in unordered streams and should have been prohibited.
//
   csType = bbcp_Config.csOpts & bbcp_csVerOut ? bbcp_Config.csType:bbcp_csNOP;
   if (bbcp_Config.csOpts & bbcp_csVerOut || bbcp_Config.Options & bbcp_ORDER)
      {csP = new bbcp_FileChkSum(&inPool, this, csType,
                                 bbcp_Config.csOpts & bbcp_csVerIO,nstrms);
       nstrms = 1;
       if ((rc = bbcp_Thread_Start(bbcp_FileCSY, (void *)csP, &tid)) < 0)
           {bbcp_Emsg("File", rc, "starting file checksum thread.");
            if (csP) delete csP;
            return 201;
           } else iBP = &(csP->csPool);
      }      else iBP = &inPool;

// Establish logging options
//
   if (bbcp_Config.Options & bbcp_LOGRD) IOB->Log(0, "DISK");

// Determine what kind of writing we will do here and do it
//
   rc = (blockSize ? Write_Direct(iBP, &inPool, nstrms)
                   : Write_Normal(iBP, &inPool, nstrms));

// Check if we ended because of an error or end of file
//
   if (rc < 0 && rc != -ENOBUFS) bbcp_Emsg("Write", -rc, "writing", iofn);

// Check if we should verify a checksum
//
   if (csP)
      {bbcp_Thread_Wait(tid);
       if (!rc && csP->csObj) rc = verChkSum(csP);
       delete csP;
      }

// If checksums are being printed, send off ours if we have it
//
   if (bbcp_Config.csOpts & bbcp_csPrint && *bbcp_Config.csString)
      cout <<"200 cks: " <<bbcp_Config.csString <<' ' <<iofn <<endl;

// Finish up
//
   if (IOB) IOB->Close();
   return rc;
}
Example #2
0
void *bbcp_RTCopy::Lock(bbcp_Semaphore *semP)
{
   struct flock fl;
   long long lfSize = 1;
   int rc;

// Initialize the lock structure
//
   fl.l_type = F_RDLCK;
   fl.l_whence = SEEK_SET;
   fl.l_start = 0;
   fl.l_len = 0;

// Indicate that we are all initialized
//
   if (semP) semP->Post();

// Obtain a shared lock on the file
//
   do {rc = fcntl(lkFD, F_SETLKW, &fl);} while(rc < 0 && errno == EINTR);

// Check how we ended here. Note that since we are permanent object, thread
// locking considerations do not apply here.
//
   if (rc && Grow)
      {rc = errno;
       bbcp_Emsg("RTCopy", rc, "locking", lkFN);
       Grow = -rc;
       return 0;
      }

// Check if we should verify this copy
//
   if (Grow && bbcp_Config.Options & bbcp_RTCVERC)
      {lfSize = FSp->getSize(lkFD);
       if (lfSize < 0)
          {rc = static_cast<int>(-lfSize);
           bbcp_Emsg("RTCopy", rc, "stating", lkFN);
           Grow = -rc;
           return 0;
          }
        if (!lfSize) {Grow = -EADV; return 0;}
      }

// Obtain the final size of the source file
//
   if ((xLim = FSp->getSize(ioFD)) < 0) Grow = static_cast<int>(xLim);
      else Grow = 0;

// All done
//
   return 0;
}
Example #3
0
void bbcp_LogFile::Record(bbcp_LogFiler *lrP)
{
   static bbcp_Mutex logMutex;
   bbcp_Timer  Mytime;
   bbcp_Stream inData;
   char *inLine, tbuff[24];
   struct iovec iolist[3] = {{(caddr_t)tbuff, 0}, {0,0}, {(char *)"\n", 1}};
   int LogFD = lrP->LogF->Logfd;

// Attach the file descriptor to the stream
//
   inData.Attach(lrP->ErFD);

// Get a full line from the stream to avoid line splittage in the log and
// write it out to the lof file adding appropriate headers.
//
   while((inLine = inData.GetLine()))
        {if (!(*inLine)) continue;
         logMutex.Lock();
         if (LogFD)
            {tbuff[0] = '\0';
             iolist[0].iov_len   = Mytime.Format(tbuff);
             iolist[1].iov_base  = inLine;
             iolist[1].iov_len   = strlen(inLine);

             if (writev(LogFD, (const struct iovec *)&iolist, 3) < 0)
                {bbcp_Emsg("LogFile",errno,"writing log to",lrP->LogF->Logfn);
                 LogFD = 0;
                }
            } else cerr <<inLine <<endl;
         logMutex.UnLock();
        }
}
Example #4
0
int bbcp_Stream::Attach(int FileDescriptor, int bsz) 
{

    // Close the current stream. Close will handle unopened streams.
    //
    Close();

    // Allocate a new buffer for this stream
    //
    if (!bsz) buff = 0;
       else if (!(buff = (char *)malloc(bsz+1)))
               return bbcp_Emsg("Attach", errno, "allocating stream buffer.");

    // Initialize the stream
    //
    FD = FE= FileDescriptor;
    bnext  = buff;
    bsize  = bsz+1;
    bleft  = 0;
    recp   = 0;
    token  = 0;
    flags  = 0;
    ecode  = 0;
    xcont  = 1;
    xline  = 0;
    return  0;
}
Example #5
0
int bbcp_Protocol::SendArgs(bbcp_Node *Node, bbcp_FileSpec *fsp,
                            char *cbhost, int cbport, char *addOpt)
{
   char buff[512], *apnt[6];
   int alen[6], i = 0;

// The remote program should be running at this point, setup the args
//
   if (bbcp_Config.CopyOpts)
      {apnt[i]   = bbcp_Config.CopyOpts;
       alen[i++] = strlen(bbcp_Config.CopyOpts);
      }
   if (addOpt) {apnt[i] = addOpt; alen[i++] = strlen(addOpt);}
   apnt[i]   = buff;
   alen[i++] = snprintf(buff, sizeof(buff)-1, " -H %s:%d\n", cbhost, cbport);
   apnt[i] = 0; alen[i] = 0;

// Send the argumnets via the stdout/stdin stream for the node
//
   if (Node->Put(apnt, alen) < 0)
      return bbcp_Emsg("Protocol", errno, "sending arguments to",
                        Node->NodeName());

// Send the file arguments now
//
   apnt[1] = (char *)"\n"; alen[1] = 1; apnt[2] = 0; alen[2] = 0;
   while(fsp)
        {apnt[0] = fsp->pathname; alen[0] = strlen(fsp->pathname);
         if (Node->Put(apnt, alen) < 0)
             return bbcp_Emsg("Protocol", errno, "sending file arguments to",
                               Node->NodeName());
         fsp = fsp->next;
        }

// Send eol
//
   apnt[0] = (char *)"\0"; alen[0] = 1; apnt[1] = 0; alen[1] = 0;
   if (Node->Put(apnt, alen) < 0)
      return bbcp_Emsg("Protocol", errno, "sending eol to", Node->NodeName());

// All done
//
   return 0;
}
Example #6
0
int bbcp_Node::Outgoing(bbcp_Protocol *protocol)
{
   int i, retc;
   bbcp_Link *link;

// Establish the control connection first
//
   if (link = bbcp_Net.Connect(bbcp_Config.CBhost, bbcp_Config.CBport, 3))
      if ((retc = protocol->Login(link, 0)) < 0)
         {delete link; link = 0;}

// Now establish all data channels if we have a control channel
//
   if (link)
      {pthread_t tid, T_id[BBCP_MAXSTREAMS];

       // Start threads for data connections
       //
       for (i = 0; i < bbcp_Config.Streams; i++)
           {if ((retc=bbcp_Thread_Start(bbcp_Connect,(void *)protocol,&tid))<0)
               {bbcp_Emsg("Outgoing", retc, "starting connect thread");
                _exit(100);
               }
            T_id[i] = tid;
#ifdef CRAY_X1E
            usleep(1);
#endif
           }
       for (i = 0; i < bbcp_Config.Streams; i++)
           {if (!(link = (bbcp_Link *)bbcp_Thread_Wait(T_id[i]))) break;
            link->LinkNum = dlcount; data_link[dlcount++] = link;
           }
       }
   iocount = dlcount;

// Make sure we have all of the required links
//
   if (dlcount < bbcp_Config.Streams) return Recover("Connect");

// Determine what the actual window size is (only if verbose)
//
   if (bbcp_Config.Options & bbcp_BLAB) chkWsz(data_link[0]->FD());

// Initialize the buddy pipeline; a patented way of ensuring maximum parallelism
//
   if (dlcount > 1 && (bbcp_Config.Options & (bbcp_SRC|bbcp_ORDER)))
      {i = dlcount-1;
       data_link[i]->setBuddy(data_link[0]);
       while(i--) data_link[i]->setBuddy(data_link[i+1]);
       bbcp_Link::setNudge();
      }
   return 0;
}
Example #7
0
int bbcp_Protocol::Request_login(bbcp_Link *Net)
{
   const char *CtlLogin = "******";
   const char *DatLogin = "******";
   char buff[512], *id, *wp;
   int retc, blen;
   bbcp_Login_Stream loginStream(Net);
   bbcp_Node *np = loginStream.np;

// Determine wether this is a control or data path
//
   id = (Remote ? (char *)DatLogin : (char *)CtlLogin);

// Prepare the login request
//
   blen = sprintf(buff,id,bbcp_Config.SecToken,(bbcp_Net.AutoTune() ? "+" : ""),
                          bbcp_Config.Wsize, bbcp_Version.VData,
                          bbcp_Config.RWBsz);

// Send the request
//
   if ((retc = np->Put(buff, (ssize_t)blen)) < 0)
      return bbcp_Emsg( "Request_Login",-(np->LastError()),
                        "requesting", id, (char *)"path.");

// If this is a data stream, then tell caller to hold on to the net link
//
   if (Remote) {np->Detach(); return 0;}

// For a control connection, read the acknowledgement below
// nnn loginok wsz: <num> [<dsz>]
//
   if (np->GetLine())
      {if (np->GetToken()        && (wp = np->GetToken())
       && !strcmp(wp, "loginok") && (wp = np->GetToken())
       && !strcmp(wp, "wsz:")    && (wp = np->GetToken())
       &&  AdjustWS(wp, np->GetToken(), 1))
          {Remote = np;
           loginStream.np = 0;
           return 1;
          }
      }

// Invalid response
//
   return bbcp_Fmsg("Request_Login", "Invalid login ack sequence.");
}
Example #8
0
bbcp_ZCX *bbcp_Node::setup_CX(int deflating, int iofd)
{
   int retc, clvl;
   bbcp_BuffPool *ibp, *rbp, *obp;
   bbcp_ZCX *cxp;
   pthread_t tid;

// Initialize the processing parameters
//
   if (deflating)
      {ibp = &bbcp_APool;
       rbp = &bbcp_APool;
       obp = &bbcp_BPool;
       clvl = (bbcp_Config.Complvl ? bbcp_Config.Complvl : 1);
      } else {
       ibp = &bbcp_CPool;
       rbp = &bbcp_BPool;
       obp = &bbcp_APool;
       clvl = 0;
      }

// Allocate buffers in the A pool
//
   if (bbcp_APool.Allocate(bbcp_Config.BNum, bbcp_Config.RWBsz, !deflating))
      return 0;

// Allocate a new compression/expansion object
//
   cxp = new bbcp_ZCX(ibp, rbp, obp, clvl, iofd,
             (int)(bbcp_Config.Options & (clvl ? bbcp_LOGCMP : bbcp_LOGEXP)));

// Start the compression/expansion thread
//
   if ((retc = bbcp_Thread_Start(bbcp_doCX, (void *)cxp, &tid))<0)
      {bbcp_Emsg("File", retc, "starting", 
                 (char *)(deflating ? "compression" : "expansion"),
                 (char *)" thread.");
       _exit(100);
      }
   cxp->TID = tid;
   DEBUG("Thread " <<tid <<" assigned to cx stage.");

// Return the compression object
//
   return cxp;
}
Example #9
0
int bbcp_Stream::Put(const char *data, int dlen) {
    int dcnt = dlen, retc;

    if (flags & bbcp_Stream_BUSY) {ecode = ETXTBSY; return -1;}

    while(dcnt)
         {do { retc = write(FE, (const void *)data, (size_t)dlen);}
              while (retc < 0 && errno == EINTR);
          if (retc >= 0) dcnt -= retc;
             else {flags |= bbcp_Stream_BUSY;
                   bbcp_Emsg("Put", errno, "writing to stream.");
                   flags &= ~bbcp_Stream_BUSY;
                   return -1;
                  }
         }
    return 0;
}
Example #10
0
void bbcp_LogFile::Monitor(int fdnum, char *fdname)
{
   bbcp_LogFiler *lrP = new bbcp_LogFiler(this, fdname, fdnum);
   int retc;

// Start a log file thread (we loose storage upon failure)
//
   if ((retc = bbcp_Thread_Run(bbcp_FileLog, (void *)lrP, &(lrP->LogT))))
      {bbcp_Emsg("LogFile", errno, "start logging thread to", Logfn);
       return;
      }

// Chain this logger into out list of loggers
//
   Flog.Lock();
   lrP->Next = Loggers; Loggers = lrP;
   Flog.UnLock();
   DEBUG("Thread " <<lrP->LogT <<" assigned to logging " <<fdname);
}
Example #11
0
void bbcp_Protocol::putCSV(char *Host, char *csFn, char *csVal, int csVsz)
{                                //1234567890123
   struct iovec iov[] = {{(char *)"Checksum: ", 10},
                        {bbcp_Config.csName,strlen(bbcp_Config.csName)},
                        {(char *)" ", 1}, {csVal, csVsz},
                        {(char *)" ", 1}, {Host, strlen(Host)},
                        {(char *)":", 1}, {csFn, strlen(csFn)},
                        {(char *)"\n",1}};
   int n = sizeof(iov)/sizeof(iov[0]);

// Write the checksum to a special file if it exists
//
   if (bbcp_Config.csPath)
      {if (writev(bbcp_Config.csFD, iov, n) < 0)
          {bbcp_Emsg("Protocol",errno,"writing checksum to",bbcp_Config.csPath);
           close(bbcp_Config.csFD); bbcp_Config.csFD = -1;
          }
      } else writev(STDERR_FILENO, iov, n);
}
Example #12
0
int bbcp_LogFile::Open(const char *fname)
{

// Check if we have a logfile already
//
   if (Logfd >= 0) return -ETXTBSY;

// Open the log file
//
   if ((Logfd = open(fname, O_WRONLY | O_CREAT | O_APPEND | O_DSYNC, 0644)) < 0)
      return bbcp_Emsg("LogFile", -errno, "opening", fname);

// Set up for logging
//
   Logfn = strdup(fname);

// All done
//
   return 0;
}
Example #13
0
int bbcp_Stream::Put(char *datavec[], int dlenvec[]) {
    int i, retc, dlen;
    const char *data;

    if (flags & bbcp_Stream_BUSY) {ecode = ETXTBSY; return -1;}

    for (i = 0; datavec[i]; i++)
        {data = datavec[i]; dlen = dlenvec[i];
         while(dlen)
              {do { retc = write(FE, (const void *)data, (size_t)dlen);}
                   while (retc < 0 && errno == EINTR);
               if (retc >= 0) {data += retc; dlen -= retc;}
                  else {flags |= bbcp_Stream_BUSY;
                        bbcp_Emsg("Put", errno, "writing to stream.");
                        flags &= ~bbcp_Stream_BUSY;
                        return -1;
                       }
              }
        }
    return 0;
}
Example #14
0
int bbcp_Link::Control_In(bbcp_Buffer *bp)
{
    int  newsz;
    bbcp_Header *hp = &bp->bHdr;

// Check if this is a vanilla close request.
//
   if (hp->cmnd == (char)BBCP_CLOSE)
      {DEBUG("Close request received on link " <<LinkNum);
       bp->blen = 0;
       bbcp_BPool.putFullBuff(bp);
       return 0;
      }

// Check if this is a checksum close request.
//
   if (hp->cmnd == (char)BBCP_CLCKS)
      {DEBUG("Checksum close request received on link " <<LinkNum);
       if (bbcp_Config.csOpts & bbcp_csSend)
          {DEBUG("Setting checksum from link " <<LinkNum);
           bbcp_Config.setCS(bp->bHdr.cksm);
           bp->blen = 0;
          }
       bbcp_BPool.putFullBuff(bp);
       return 0;
      }

// Check if this is an abort equest. If so, queue the message and terminate
//
   if (hp->cmnd == (char)BBCP_ABORT)
      {DEBUG("Abort request received on link " <<LinkNum);
       bbcp_BPool.putFullBuff(bp);
       return -1;
      }

// Unknown command here
//
   return bbcp_Emsg("Control_In", EINVAL, "invalid command code", Lname);
}
Example #15
0
int bbcp_RTCopy::Start(bbcp_FileSystem *fsp, const char *iofn, int iofd)
{
   bbcp_Semaphore xSem(0);
   int rc;

// Initialize the common variables
//
   ioFD = iofd;
   Grow = 1;
   Left = 0;
   Blok = (bbcp_Config.Options & bbcp_RTCBLOK ? bbcp_Config.Streams : 0);
   FSp  = fsp;

// Initialize variable dependent on how we will do locking
//
   if (bbcp_Config.rtLockf)
      {lkFN = bbcp_Config.rtLockf;
       lkFD = bbcp_Config.rtLockd;
      } else {
       lkFN = iofn;
       lkFD = dup(iofd);
      }

// Now start a thread that will try to obtain a shared lock
//
   if ((rc = bbcp_Thread_Run(bbcp_RTCopyLK, (void *)&xSem, &Tid)) < 0)
      {bbcp_Emsg("RTCopy", rc, "starting file r/t lock thread.");
       Grow = -rc;
       return 0;
      }

// Wait for the thread to set up
//
   xSem.Wait();
   return (Grow >= 0);
}
Example #16
0
int bbcp_Protocol::Process(bbcp_Node *Node)
{
   bbcp_FileSpec *fp = bbcp_Config.srcSpec;
   pthread_t Tid;
   int rc, NoGo = 0;
   char *cp;

// If there is a r/t lock file, make sure it exists
//
   if ((bbcp_Config.Options & bbcp_RTCSRC) && bbcp_Config.rtLockf
   &&  (bbcp_Config.rtLockd = open(bbcp_Config.rtLockf, O_RDONLY)) < 0)
      {rc = errno, NoGo = 1;
       bbcp_Emsg("Config", rc, "opening lock file", bbcp_Config.rtLockf);
      }

// Make sure all of the source files exist at this location. If there is an
// error, defer exiting until after connecting to prevent a hang-up. We
// make sure that we are not trying to copy a directory.
//
   while(fp)
        {NoGo |= fp->Stat();
         if (fp->Info.Otype == 'd' && !(bbcp_Config.Options & bbcp_RECURSE))
            {bbcp_Fmsg("Source", fp->pathname, "is a directory.");
             NoGo = 1; break;
            }

         fp = fp->next;
        }

// If this is a recursive list, do it in the bacground while we try to connect.
// This avoids time-outs when large number of files are enumerated.
//
   if (!NoGo && bbcp_Config.Options & bbcp_RECURSE)
      if ((rc = bbcp_Thread_Start(bbcp_ProtocolLS, 0, &Tid)) < 0)
         {bbcp_Emsg("Protocol", rc, "starting file enumeration thread.");
          NoGo = 1;
         }

// Establish all connections
//
   if (Node->Start(this, (bbcp_Config.Options & bbcp_CON2SRC))
   ||  Node->getBuffers(0)) return 2;
   Local = Node;

// At this point, if we're running with the -r recursive option, our list of
// file specs (bbcp_Config.srcSpec) is being extended recursively to include
// all subdirs and their contents. We must wait for the thread to finish.
//
   if (!NoGo && bbcp_Config.Options & bbcp_RECURSE) bbcp_Thread_Wait(Tid);

// If there was a fatal error, we can exit now, the remote side will exit
//
   if (NoGo)
      {char buff[8];
       strcpy(buff, "eol\n");
       Remote->Put(buff, (ssize_t)4);
       Node->Stop();
       return 2;
      }
   rc = 0;

// Process all control connection requests and return
//
   while(!rc && Remote->GetLine())
      {if (!(cp = Remote->GetToken())) continue;
            if (!strcmp(cp, "flist")) rc = Process_flist();
       else if (!strcmp(cp, "get"))   rc = Process_get();
       else if (!strcmp(cp, "exit")) {rc = Process_exit(); break;}
       else {bbcp_Fmsg("Process", "Invalid command, '", cp, "'.");
             rc = 1;
            }
      }

// Dismantle this node and return
//
   Node->Stop();
   if (cp) return rc;
   bbcp_Fmsg("Source", "Unexpected end of control stream from",
                             Remote->NodeName());
   return 32;
}
Example #17
0
char *bbcp_Stream::GetLine()
{
   int bcnt, retc;
   char *bp;

// Check if end of message has been reached.
//
   if (flags & bbcp_Stream_EOM) return (char *)NULL;

// Find the next record in the buffer
//
   if (bleft > 0)
      {recp = bnext; bcnt = bleft;
       for (bp = bnext; bcnt--; bp++)
           if (!*bp || *bp == '\n')
               {if (!*bp) flags |= bbcp_Stream_EOM;
                *bp = '\0';
                bnext = ++bp;
                bleft = bcnt;
                token = recp;
                return recp;
               }
               else if (notabs && *bp == '\t') *bp = ' ';
  
   // There is no next record, so move up data in the buffer.
   //
      strncpy(buff, bnext, bleft);
      bnext = buff + bleft;
      }
      else bnext = buff;

// Prepare to read in more data.
//
    bcnt = bsize - (bnext - buff) -1;
    bp = bnext;

// Read up to the maximum number of bytes. Stop reading should we see a
// new-line character or a null byte -- the end of a record.
//
   ecode = 0;
   recp  = token = buff; // This will always be true at this point
   while(bcnt)
        {do { retc = read(FD, (void *)bp, (size_t)bcnt); }
            while (retc < 0 && errno == EINTR);

         if (retc < 0) {bbcp_Emsg("GetLine", errno, "reading request.");
                        return (char *)0;}
         if (!retc)
            {*bp = '\0';
             flags |= bbcp_Stream_EOM;
             bnext = ++bp;
             bleft = 0;
             return buff;
            }

         bcnt -= retc;
         while(retc--)
             if (!*bp || *bp == '\n')
                {if (!*bp) flags |= bbcp_Stream_EOM;
                    else *bp = '\0';
                 bnext = ++bp;
                 bleft = retc;
                 return buff;
                } else {
                 if (notabs && *bp == '\t') *bp = ' ';
                 bp++;
                }
         }

// All done, force an end of record.
//
   bbcp_Emsg("GetLine", EMSGSIZE, "record truncated.");
   buff[bsize-1] = '\0';
   return buff;
}
Example #18
0
int bbcp_Stream::Exec(char **parm, int inrd, int inerr)
{
    int fildes_In[2], fildes_Out[2] = {-1,-1}, fildes_Err[2] = {0,0};
    int retc, Child_Out = FD, Child_In = FE, Child_Err = 0;

    // Wait for any previous command to finish on this stream
    //
    Drain();

    // Create a pipe if we have no attached FD. Recall that FD is the
    // descriptor we read from and FE is the one we write to. This is
    // true for sockets. For pipes, the relationship is reversed in
    // the child. Plus, we need to get two pipes if the child's STDIN
    // is to be redirected. This is because pipes suffer from backflow.
    //
    if (FD < 0)
       {if (pipe(fildes_Out) || (inrd  && pipe(fildes_In))
                            || (inerr && pipe(fildes_Err)))
           return bbcp_Emsg("Exec",errno,"creating a pipe for",parm[0]);
        Child_In=fildes_In[0]; Child_Out=fildes_Out[1]; Child_Err=fildes_Err[1];
        fildes_Out[1] = (inrd ? fildes_In[1] : -1);
        if (retc = Attach(fildes_Out)) return retc;
       }

    // Fork a process first so we can pick up the next request.
    //
    if ((child = bbcp_OS.Fork()) != 0)
       {close(Child_Out); retc = -errno;
        if (inrd)  close(Child_In);
        if (inerr) close(Child_Err);
        if (child > 0) return fildes_Err[0];
        retc=bbcp_Emsg("Exec", retc,"forking request process for",parm[0]);
                   close(fildes_In[1]);
        if (inrd)  close(fildes_Out[0]);
        if (inerr) close(fildes_Err[0]);
        return retc;
       }

    /*****************************************************************/
    /*                  C h i l d   P r o c e s s                    */
    /*****************************************************************/

    // Close the parent end of the pipe
    //
    if (fildes_In[1]  >= 0) close(fildes_In[1]);
    if (fildes_Out[0] >= 0) close(fildes_Out[0]);
    if (fildes_Err[0] >  0) close(fildes_Err[0]);


    // Redirect standard in if so requested
    //
    if (inrd)
       {if (dup2(Child_In, STDIN_FILENO) < 0)
           {bbcp_Emsg("Exec", errno, "setting up standard in for", parm[0]);
            exit(255);
           } else close(Child_In);
       }

    // Reassign the stream to be standard out to capture all of the output.
    //
    if (dup2(Child_Out, STDOUT_FILENO) < 0)
       {bbcp_Emsg("Exec", errno, "setting up standard out for", parm[0]);
        exit(255);
       } else close(Child_Out);

    // Reassign the stream to be standard err to capture all of the output.
    //
    if (inerr && Child_Err)
       {if (dup2(Child_Err, STDERR_FILENO) < 0)
           {bbcp_Emsg("Exec", errno, "setting up standard err for", parm[0]);
            exit(255);
           } else close(Child_Err);
       }

    // Invoke the command never to return
    //
    DEBUG("PATH=" <<getenv("PATH"));
    execvp(parm[0], parm);
    bbcp_Emsg("Exec", errno, "executing", parm[0], parm[1]);
    exit(255);
    return(255);  // some compilers demand a return in int functions
}
Example #19
0
int bbcp_Link::Buff2Net()
{
    bbcp_Buffer *outbuff;
    ssize_t wrsz, wlen = 0;
    const ssize_t hdrsz = (ssize_t)sizeof(bbcp_Header);
    int retc = 0, NotDone = 1, csLen = (csObj ? csObj->csSize() : 0);
    struct iovec iov[2] = {0, hdrsz, 0, 0};

// Establish logging options
//
   if (bbcp_Config.Options & bbcp_LOGOUT) IOB.Log(0, "NET");

// Do this until an error of eof
//
   while(NotDone)
      {
      // Obtain a buffer
      //
         if (!(outbuff = bbcp_BPool.getFullBuff()))
            {NotDone = -1; retc = ENOBUFS; break;}

      // Compose the header and see if control operation required
      //
         if (outbuff->blen <= 0)
            {if ((NotDone = Control_Out(outbuff)) < 0) {retc = 255; break;}}
            else bbcp_BPool.Encode(outbuff, BBCP_IO);

      // Check if we should generate a checksum
      //
         if (csObj && outbuff->blen) memcpy(outbuff->bHdr.cksm,
            csObj->Calc(outbuff->data,outbuff->blen), csLen);

      // Write all of the data (header & data are sequential)
      //
         iov[0].iov_base = (char *)&outbuff->bHdr;
         iov[1].iov_base =  outbuff->data; iov[1].iov_len = outbuff->blen;
         wrsz = (ssize_t)outbuff->blen + hdrsz;
         if ((wlen = IOB.Write(iov, 2)) != wrsz) break;

      // Queue buffer for re-use
      //
         if (NotDone) bbcp_BPool.putEmptyBuff(outbuff);
            else      bbcp_BPool.putFullBuff(outbuff);
         outbuff = 0;

      // Tell our buddy that it's ok to continue then do a rendezvous
      //
         if (Nudge) {Buddy->Rendezvous.Post(); if (Wait) Rendezvous.Wait();}
      }

// Check how we ended this loop
//
   if (outbuff) bbcp_BPool.putEmptyBuff(outbuff);
   if (NotDone > 0 && !wlen)
      {bbcp_BPool.Abort();
       if (wlen < 0)  retc=bbcp_Emsg("Link",-wlen,"writing data for",Lname);
          else if (wlen > 0) {bbcp_Fmsg("Link","Data lost on link", Lname);
                              retc = 100;
                             }
      } else if (NotDone) bbcp_BPool.Abort();

// All done
//
   if (Nudge) {Wait = 0; Buddy->Rendezvous.Post();}
   return (retc < 0 ? -retc : retc);
}
Example #20
0
int bbcp_Node::Run(char *user, char *host, char *prog, char *parg)
{
   static char ipv4[] = {'-','4','\0'};
   int fderr, numa = 0;
   char *username, *sshDest, bufDest[264], *Argv[1024], *ap, *pp = prog;
   const int ArgvSize = sizeof(Argv)/sizeof(char *)-2;

// Free up any node name here
//
   if (nodename) free(nodename);
   nodename = strdup(host ? host : bbcp_Config.MyHost);
   username = (user ? user : bbcp_Config.MyUser);

// Check for an IPV6 address as ssh does not follow the rfc standard
//
   if (*nodename != '[') sshDest = nodename;
      else {int i = strlen(nodename);
            if (i > (int)sizeof(bufDest)) return -EHOSTUNREACH;
            strcpy(bufDest, nodename+1);
            bufDest[i-2] = 0; sshDest= bufDest;
           }

// Break up the command line and perform substitutions
//
   if (!(user || host)) {Argv[0] = bbcp_Config.MyProg; numa = 1;}
      else for (numa = 0; *pp && numa < ArgvSize; numa++)
               {while(*pp && *pp == ' ') pp++;
                ap = pp;
                while(*pp && *pp != ' ') pp++;
                if (*pp) {*pp = '\0'; pp++;}
                if (*ap == '%' && !ap[2])
                   {     if (ap[1] == 'I')
                            {if (bbcp_Config.IDfn)
                                {Argv[numa++] = (char *)"-i";
                                 Argv[numa] = bbcp_Config.IDfn;}
                                else numa--;
                            }
                    else if (ap[1] == 'U') Argv[numa] = username;
                    else if (ap[1] == 'H') Argv[numa] = sshDest;
                    else if (ap[1] == '4')
                            {if (bbcp_Config.Options & bbcp_IPV4)
                                           Argv[numa] = ipv4;
                                else numa--;
                            }
                    else                   Argv[numa] = ap;
                   }
                    else Argv[numa] = ap;
               }

// Complete argument list to start the actual copy program
//
   if (numa >= ArgvSize) return bbcp_Emsg("Run", -E2BIG, "starting", prog);
   Argv[numa++] = parg;
   Argv[numa]   = 0;

// Invoke the program
//
   if ((fderr=NStream.Exec(Argv, 1, bbcp_Config.MLog != 0)) < 0) return -fderr;

// Perform logging function here
//
   if (bbcp_Config.MLog) bbcp_Config.MLog->Monitor(fderr, parg);

// Perform debugging here
//
   if (DEBUGON)
      {int i;
       cerr <<"bbcp_" <<bbcp_Debug.Who <<": Running as pid " <<NStream.getPID() <<": ";
       for (i = 0; i < numa; i++) if (Argv[i]) cerr <<Argv[i] <<' ';
       cerr <<endl;
      }

// All done
//
   return 0;
}
Example #21
0
int bbcp_Link::Net2Buff()
{
    static const char *Etxt[] = {"",
                                 "Invalid header length",   // 1
                                 "Invalid buffer length",   // 2
                                 "Invalid data length",     // 3
                                 "Invalid checksum",        // 4
                                 "Invalid hdr checksum"     // 5
                                };
    enum err_type {NONE = 0, IHL = 1, IBL = 2, IDL = 3, ICS = 4, IHS = 5};
    err_type ecode = NONE;
    bbcp_Buffer *inbuff;
    ssize_t rdsz, rlen = 0;
    ssize_t hdrsz = (ssize_t)sizeof(bbcp_Header);
    int  maxrdsz  = bbcp_BPool.DataSize();
    int i, notdone = 1, csLen = (csObj ? csObj->csSize() : 0);

// Establish logging options
//
   if (bbcp_Config.Options & bbcp_LOGIN) IOB.Log("NET", 0);

// Do this until an error of eof
//
   while(notdone)
      {
      // Obtain a buffer
      //
         if (!(inbuff = bbcp_BPool.getEmptyBuff()))
            {rlen = ENOBUFS; notdone = 0; break;}

      // Read the header information into the header buffer
      //
         if ((rlen = IOB.Read((char *)&inbuff->bHdr, hdrsz)) != hdrsz)
            {if (rlen > 0) {ecode = IHL; rlen = EINVAL;} break;}

      // Decode the header and make sure it decoded correctly
      //
         if (!bbcp_BPool.Decode(inbuff)) {ecode = IHS; break;}

      // Make sure the read length does not overflow our buffer
      //
         if ((rdsz = inbuff->blen) > maxrdsz) {ecode = IBL; break;}

      // Read data into the buffer and do checksum if needed
      //
         if (rdsz)
            {if ((rlen = IOB.Read(inbuff->data, rdsz)) != rdsz)
                {if (rlen > 0) ecode = IDL; break;}
             if (csObj && memcmp(csObj->Calc(inbuff->data,inbuff->blen),
                                 inbuff->bHdr.cksm,csLen)) {ecode = ICS; break;}
            }

      // Check if this is a control operation or data operation
      //
         if (inbuff->bHdr.cmnd == (char)BBCP_IO)
            bbcp_BPool.putFullBuff(inbuff);
            else if ((notdone = Control_In(inbuff)) <= 0) break;

      // Tell our buddy that it's ok to continue then do a rendezvous
      //
         if (Nudge) {Buddy->Rendezvous.Post(); if (Wait) Rendezvous.Wait();}
      }

// If we ended the loop with an error, abort the buffer pool to force all
// threads dependent on the queue to abnormally terminate. Otherwise, post
// the buddy thread twice since that is the most that it may need to read.
//

   if (Nudge) {Wait = 0; i = bbcp_Config.Streams;
               do {Buddy->Rendezvous.Post();} while(i--);
              }
   if (notdone)
      {bbcp_BPool.Abort();
      if (ecode != NONE)
         {bbcp_Fmsg("Net2Buff", Etxt[(int)ecode], "from", Lname);
          return 128;
         }
      if (rlen >=0) return EPIPE;
      bbcp_Emsg("Net2Buff", rlen, "reading data from", Lname);
      return -rlen;
      }
   return 0;
}
Example #22
0
int bbcp_Node::RecvFile(bbcp_FileSpec *fp, bbcp_Node *Remote)
{
   static const int wOnly = S_IWUSR;

   const char *Args = 0, *Act = "opening", *Path = fp->targpath;
   long tretc = 0;
   int i, oflag, retc, Mode = wOnly, progtid = 0;
   long long startoff = 0;
   pid_t Child[2] = {0,0};
   bbcp_File *outFile, *seqFile = 0;
   bbcp_ZCX *cxp = 0;
   pthread_t tid, link_tid[BBCP_MAXSTREAMS+4];
   bbcp_Timer Elapsed_Timer;
   bbcp_ProgMon *pmp = 0;
   float CRatio;

// Perform Force or Append processing
//
        if (bbcp_Config.Options & bbcp_XPIPE)
           {oflag = O_WRONLY;
            Path = bbcp_Config.snkSpec->pathname;
            Args = bbcp_Config.snkSpec->fileargs;
            if (bbcp_Config.snkSpec->Info.Otype != 'p') Act = "running";
               else {Mode |= S_IFIFO;
                     if (Args)
                        {bbcp_Fmsg("RecvFile",
                                   "Spaces disallowed in named output pipe",Path);
                         return -EINVAL;
                        }
                    }
           }
   else if (bbcp_Config.Options & bbcp_FORCE)
           {if (!(bbcp_Config.Options & bbcp_NOUNLINK))
               fp->FSys()->RM(Path);
            oflag = O_WRONLY | O_CREAT | O_TRUNC;
           }
   else if (bbcp_Config.Options & bbcp_APPEND)
           {if (retc = fp->WriteSigFile()) return retc;
            if (startoff = fp->targetsz) oflag = O_WRONLY;
               else oflag = O_CREAT | O_WRONLY;
           }
   else    oflag = O_WRONLY | O_CREAT | O_EXCL;

// Establish mode, we normally make the file write-only
//
   if ( bbcp_Config.Options &  bbcp_RTCSNK
   && !(bbcp_Config.Options & (bbcp_RTCHIDE|bbcp_XPIPE)))
      Mode = bbcp_Config.Mode|S_IWUSR|S_ISUID;

// Tell the user what we are bout to do
//
   if (bbcp_Config.Options & bbcp_BLAB | bbcp_Config.Progint)
      if (bbcp_Config.Options & bbcp_APPEND) 
         {char buff[32];
          sprintf(buff, "%lld", startoff);
          bbcp_Fmsg("RecvFile","Appending to",Path,"at offset",buff);
         }
         else bbcp_Fmsg("RecvFile", "Creating", Path);
      else DEBUG("Receiving " <<fp->pathname <<" as " <<Path <<" offset=" <<startoff);

// Receive the file in a sub-process so that we don't muck with this one
//
   if ((Child[0] = bbcp_OS.Fork()) < 0)
      return bbcp_Emsg("RecvFile", errno, "forking to create", Path);
   if (Child[0]) 
      {char buff[128];
       Parent_Monitor.Start(0,Remote);
       DEBUG("Waiting for child " <<Child[0] <<" to finish");
       retc = bbcp_OS.Waitpid(Child);
       Parent_Monitor.Stop();
       if (bbcp_Config.Options & bbcp_BLAB)
          write(STDERR_FILENO, buff, Usage("Target", buff, sizeof(buff)));
       return retc;
      }

/*******************************************************************************
   (net)->data_link[i]->BPool->CStage[1]->CStage[0]->CPool->outFile->(file)
*******************************************************************************/

// Set Concurrency
//
   bbcp_Thread_MT(bbcp_Config.MTLevel);

// Request direct I/O if so wanted
//
   if (bbcp_Config.Options & bbcp_ODIO) {fp->FSys()->DirectIO(1);
       DEBUG("Direct output requested.");}

// Open the file and set the starting offset
//
   Elapsed_Timer.Start();
   if (!(outFile = fp->FSys()->Open(Path, oflag, Mode, Args)))
      return bbcp_Emsg("RecvFile", errno, Act, Path);
   if (startoff && ((retc = outFile->Seek(startoff)) < 0))
      return bbcp_Emsg("RecvFile",retc,"setting write offset for",Path);
   outFile->setSize(fp->Info.size);

// If compression is wanted, set up the compression objects
//
   if (bbcp_Config.Options & bbcp_COMPRESS 
   && !(cxp = setup_CX(0, outFile->ioFD()))) return -ECANCELED;

// Start a thread for each data link we have
//
   for (i = 0; i < dlcount; i++)
       {if ((retc = bbcp_Thread_Start(bbcp_Net2Buff, 
                                (void *)data_link[i], &tid))<0)
           {bbcp_Emsg("RecvFile",retc,"starting net thread for",Path);
            _exit(100);
           }
        link_tid[i] = tid;
        DEBUG("Thread " <<tid <<" assigned to stream " <<i);
       }

// If we are compressing start the sequence thread now
//
   if (bbcp_Config.Options & bbcp_COMPRESS)
      {seqFile = new bbcp_File(Path, 0, 0);
       if ((retc = bbcp_Thread_Start(bbcp_doWrite, (void *)seqFile, &tid))<0)
          {bbcp_Emsg("RecvFile",retc,"starting disk thread for",Path);
           _exit(100);
          }
       link_tid[dlcount++] = tid;
       DEBUG("Thread " <<tid <<" assigned to sequencer as stream " <<i);
      }

// Start the parent process monitor. It is stopped at exit.
//
   Parent_Monitor.Start();

// If a periodic progress message is wanted, start a progress thread
//
   if (bbcp_Config.Progint) 
      {pmp = new bbcp_ProgMon();
       pmp->Start(outFile, cxp, bbcp_Config.Progint, fp->Info.size-startoff);
      }

// Write the whole file
//
   if (bbcp_Config.Options & bbcp_COMPRESS)
           retc = outFile->Write_All(bbcp_APool, 1);
      else retc = outFile->Write_All(bbcp_BPool, bbcp_Config.Streams);
   DEBUG("File write ended; rc=" <<retc);

// Wait for the expansion thread to end
//
   if (bbcp_Config.Options & bbcp_COMPRESS)
      {if (tretc = (long)bbcp_Thread_Wait(cxp->TID)) retc = 128;
       DEBUG("File expansion ended; rc=" <<tretc);
      }

// Kill the progress monitor
//
   if (pmp) 
      {DEBUG("Deleting progress monitor");
       delete pmp;
      }

// Make sure each thread has terminated normally
//
   for (i = 0; i < dlcount; i++)
       {if (tretc = (long)bbcp_Thread_Wait(link_tid[i])) retc = 128;
        DEBUG("Thread " <<link_tid[i] <<" stream " <<i <<" ended; rc=" <<tretc);
       }

// Make sure that all of the bytes were transfered
//
   if (!retc && strncmp(Path, "/dev/null/", 10))
      {bbcp_FileInfo Info;
       if ((retc = fp->FSys()->Stat(Path, &Info)) < 0)
          {retc = -retc;
           bbcp_Emsg("RecvFile", retc, "finding", Path);
          }
          else if (Info.size != fp->Info.size && Info.mode
               &&  !(bbcp_Config.Options & bbcp_NOFSZCHK))
                  {const char *What = (Info.size < fp->Info.size
                                    ?  "Not all" : "Too much");
                   retc = 29;
                   bbcp_Fmsg("RecvFile",What,"data was transfered for",Path);
                   DEBUG("src size=" <<fp->Info.size <<" snk size=" <<Info.size);
                  }
      } DEBUG("Outfile " <<Path <<" closed");

// Report detailed I/O stats, if so wanted
//
   Elapsed_Timer.Stop();
   if (!retc && bbcp_Config.Options & bbcp_VERBOSE)
      {double ttime;
       Elapsed_Timer.Report(ttime);
       Report(ttime, fp, outFile, cxp);
      }

// All done
//
   Parent_Monitor.Stop();
                delete outFile;
   if (cxp)     delete(cxp);
   if (seqFile) delete(seqFile);
   retc = fp->Finalize(retc);
   close(1); close(2);
   DEBUG("Process " <<getpid() <<" exiting with rc=" <<retc);
   exit(retc);
   return(retc);  // some compilers insist on a return in int functions
}
Example #23
0
int bbcp_Node::SendFile(bbcp_FileSpec *fp)
{
   const char *Act = "opening";
   int i, retc, tretc = 0, Mode = 0;
   pid_t Child[2] = {0,0};
   bbcp_File *inFile;
   bbcp_ProcMon *TLimit = 0;
   bbcp_ZCX *cxp;
   pthread_t tid, link_tid[BBCP_MAXSTREAMS+1];

// Set open options (check for pipes)
//
   if (bbcp_Config.Options & bbcp_XPIPE)
      {if (fp->Info.Otype == 'p') Mode = S_IFIFO;
          else Act = "running";
      }

// Send the file in a sub-process so that we don't muck with this one
//
   DEBUG("Sending file " <<fp->targpath <<"; offset=" <<fp->targetsz);
   if ((Child[0] = bbcp_OS.Fork()) < 0)
      return bbcp_Emsg("SendFile", errno, "forking to send", fp->pathname);
   if (Child[0])
      {char buff[128];
       Parent_Monitor.Start();
       retc = bbcp_OS.Waitpid(Child);
       Parent_Monitor.Stop();
       if (bbcp_Config.Options & bbcp_BLAB)
          write(STDERR_FILENO, buff, Usage("Source", buff, sizeof(buff)));
       return retc;
      }

/*******************************************************************************
    (file)->inFile->CPool->CStage[0]->CStage[1]->BPool->data_link[i]->(net)
*******************************************************************************/

// Set Concurrency
//
   bbcp_Thread_MT(bbcp_Config.MTLevel);

// Request direct I/O if so wanted
//
   if (bbcp_Config.Options & bbcp_IDIO) {fp->FSys()->DirectIO(1);
       DEBUG("Direct input requested.");}

// Open the input file and set starting offset
//
   if (!(inFile = fp->FSys()->Open(fp->pathname,O_RDONLY,Mode,fp->fileargs)))
      {bbcp_Emsg("SendFile", errno, Act, fp->pathname);
       exit(2);
      }
   if (fp->targetsz && ((retc = inFile->Seek(fp->targetsz)) < 0))
      return bbcp_Emsg("SendFile",retc,"setting read offset for",fp->pathname);

// If compression is wanted, set up the compression objects
//
   if (bbcp_Config.Options & bbcp_COMPRESS 
   && !(cxp = setup_CX(1, inFile->ioFD()))) return -ECANCELED;

// Start a thread for each data link we have
//
   for (i = 0; i < dlcount; i++)
       {if ((retc = bbcp_Thread_Start(bbcp_Buff2Net, 
                                (void *)data_link[i], &tid))<0)
           {bbcp_Emsg("SendFile",retc,"starting net thread for",fp->pathname);
            _exit(100);
           }
        link_tid[i] = tid;
        if (i >= iocount) {DEBUG("Thread " <<tid <<" assigned to data clocker");}
           else {DEBUG("Thread " <<tid <<" assigned to stream " <<i);}
       }

// Start the parent monitor
//
   Parent_Monitor.Start();

// Start the Transfer Time Limit
//
   if (bbcp_Config.TimeLimit)
      {TLimit = new bbcp_ProcMon();
       TLimit->Start(bbcp_Config.TimeLimit, &bbcp_BPool);
      }

// Read the whole file
//
   if (bbcp_Config.Options & bbcp_COMPRESS) retc=inFile->Read_All(bbcp_APool,1);
      else retc = inFile->Read_All(bbcp_BPool, bbcp_Config.Bfact);
   DEBUG("File read ended; rc=" <<retc);

// Wait for compression thread to end
//
   if (bbcp_Config.Options & bbcp_COMPRESS)
      {if (tretc = (long)bbcp_Thread_Wait(cxp->TID)) retc = 128;
       DEBUG("File compression ended; rc=" <<tretc);
       delete cxp;
      }

// Make sure each link thread has terminated normally.
//
   for (i = 0; i < iocount; i++)
       {if (tretc = (long)bbcp_Thread_Wait(link_tid[i])) retc = 128;
        DEBUG("Thread " <<link_tid[i] <<" stream " <<i <<" ended; rc=" <<tretc);
       }

// All done
//
   if (TLimit) delete TLimit;
   Parent_Monitor.Stop();
   delete inFile;
   close(1); close(2);
   DEBUG("Process " <<getpid() <<" exiting with rc=" <<retc);
   exit(retc);
   return(retc);  // some compilers insist on a return in int functions
}
Example #24
0
// The following class is here to allow graceful error exits
//
int bbcp_Protocol::Process_login(bbcp_Link *Net)
{
   char buff[256], *tp, *bp, *vp, *wp, *id;
   int retc, blen, respWS;
   bbcp_Login_Stream loginStream(Net);
   bbcp_Node *np = loginStream.np;

// Get the first line of the login stream
//
   if (!(np->GetLine()))
      {if (retc = np->LastError())
          return bbcp_Emsg("Process_Login", retc, "processing login from",
                                 Net->LinkName());
       return bbcp_Fmsg("Process_Login", "Bad login from", Net->LinkName());
     }

// Determine the id we want (the control stream must login first)
//
   id = (Remote ? (char *)"data" : (char *)"ctlr");

// Process the login request: login <id> <password>
//
   if (!(wp = np->GetToken()) || strcmp(wp, "login")
   ||  !(wp = np->GetToken()) || strcmp(wp, id)
   ||  !(wp = np->GetToken()) || strcmp(wp, bbcp_Config.SecToken))
      return bbcp_Fmsg("Process_Login", "Invalid login from", Net->LinkName());

// We are all done if this is not a control stream
//
   if (*id != 'c') {np->Detach(); return 0;}

// Pickup all parameters.
//
   bp = vp = wp = 0;
   while((tp = np->GetToken()))
        {     if (!strcmp(tp, "wsz:"))
                 {if (!(wp = np->GetToken()))
                     return bbcp_Fmsg("Login", "Window size is missing.");
                 }
         else if (!strcmp(tp, "ver:"))
                 {if (!(vp = np->GetToken()))
                     return bbcp_Fmsg("Login", "Version is missing.");
                 }
         else if (!strcmp(tp, "bsz:"))
                 {if (!(bp = np->GetToken()))
                     return bbcp_Fmsg("Login", "Buffer size is missing.");
                 }
        }

// Verify that our version is the same on the other side
//
   if (vp) bbcp_Version.Verify(Net->LinkName(), vp);
      else bbcp_Version.Verify(Net->LinkName(),(char *)"02.01.12.00.0");

// We can now do a window/buffer adjustment
//
   if (!wp) respWS = bbcp_Config.Wsize;
      else if (!(respWS = AdjustWS(wp, bp, 0))) return -1;

// Respond to this login request (control only gets a response)
//
   blen = sprintf(buff, "204 loginok wsz: %d %d\n",respWS,bbcp_Config.RWBsz);
   if ((retc = np->Put(buff, blen)) < 0) return -1;

// All done
//
   Remote = np;
   loginStream.np = 0;
   return 1;
}
Example #25
0
int bbcp_File::Passthru(bbcp_BuffPool *iBP, bbcp_BuffPool *oBP, 
                        bbcp_FileChkSum *csP, int nstrms)
{
    bbcp_Buffer *outbuff;
    bbcp_ChkSum *csObj;
    long long Offset = nextoffset;
    int csLen, csVer, numadd, maxbufs, maxadds = nstrms;
    int rc = 0, unordered = !(bbcp_Config.Options & bbcp_ORDER);

// Determine if we will be piggy-backing checksumming here
//
   if (csP && (csObj = csP->csObj))
      {csVer = csP->csVer; csLen = csObj->csSize();}
      else csVer = csLen = 0;

// Record the maximum number of buffers we have here
//
   maxbufs = iBP->BuffCount();
   if (!(numadd = nstrms)) numadd = 1;

// Read all of the data until eof (note that we are single threaded)
//
   while(nstrms)
      {
      // Obtain a full buffer
      //
         if (!(outbuff = iBP->getFullBuff())) break;

     // Check if this is an eof marker
     //
     //  cerr <<nstrms <<" Passt " <<outbuff->blen <<'@' <<outbuff->boff <<endl;
        if (!(outbuff->blen))
           {iBP->putEmptyBuff(outbuff); nstrms--; continue;}

      // Do an unordered write if allowed
      //
         if (unordered) {oBP->putFullBuff(outbuff); continue;}

      // Check if this buffer is in the correct sequence
      //
         if (outbuff->boff != Offset)
            {if (outbuff->boff < 0) {rc = -ESPIPE; break;}
             outbuff->next = nextbuff;
             nextbuff = outbuff;
             bufreorders++;
             if (++curq > maxreorders) 
                {maxreorders = curq;
                 DEBUG("Buff disorder " <<curq <<" rcvd " <<outbuff->boff <<" want " <<Offset);
                }
             if (curq >= maxbufs)
                {if (!(--maxadds)) {rc = -ENOBUFS; break;}
                 DEBUG("Too few buffs; adding " <<numadd <<" more.");
                 bbcp_BPool.Allocate(numadd);
                 maxbufs += numadd;
                }
             continue;
            }

      // Pass through any queued buffers
      //
      do {Offset += outbuff->blen;
          if (csObj)
             {csObj->Update(outbuff->data, outbuff->blen);
              if (csVer && memcmp(outbuff->bHdr.cksm, csObj->csCurr(), csLen))
                 {char buff[32];
                  sprintf(buff, "%lld", outbuff->boff);
                  bbcp_Fmsg("Write",iofn, "xfr checksum error at offset",buff);
                  rc = -EILSEQ; nstrms = 0; break;
                 }
             }
          oBP->putFullBuff(outbuff);
         } while(nextbuff && (outbuff = getBuffer(Offset)));
      }

// Check if we should print an error here
//
   if (rc && rc != -EILSEQ) bbcp_Emsg("Write",rc, "unable to write", iofn);

// Queue an empty buffer indicating eof or abort the stream
//
   if (!rc && (outbuff = iBP->getEmptyBuff()))
      {outbuff->blen = 0; outbuff->boff = Offset;
       oBP->putFullBuff(outbuff);
      } else {
       if (!rc) rc = -ENOBUFS;
       oBP->Abort(); iBP->Abort();
      }

// All done
//
   return rc;
}
Example #26
0
int bbcp_File::Read_All(bbcp_BuffPool &inPool, int Vn)
{
    bbcp_FileChkSum *csP = 0;
    bbcp_BuffPool *outPool;
    bbcp_Buffer   *bP;
    pthread_t tid;
    int rc = 0;

// Get the size of the file
//
   if ((bytesLeft = FSp->getSize(IOB->FD())) < 0)
      {bbcp_Emsg("Read", static_cast<int>(-bytesLeft), "stat", iofn);
       inPool.Abort(); return 200;
      }

// Adjust bytes left based on where we will be reading from
//
   bytesLeft -= nextoffset;
   if (bytesLeft < 0)
      {bbcp_Emsg("Read", ESPIPE, "stat", iofn);
       inPool.Abort(); return 200;
      }

// If this is a real-time copy operation, start the rtcopy object
//
   if (rtCopy && !bbcp_RTCopy.Start(FSp, iofn, IOB->FD()))
      {inPool.Abort(); return 200;
      }

// Set up checksumming. We would prefer to do this in the calling thread but
// this is easier. One day we will generalize buffer piping.
//
   if (bbcp_Config.csOpts & bbcp_csVerIn)
      {csP = new bbcp_FileChkSum(&inPool, this, bbcp_Config.csType,
                                 bbcp_Config.csOpts & bbcp_csVerIO);
       if ((rc = bbcp_Thread_Start(bbcp_FileCSX, (void *)csP, &tid)) < 0)
           {bbcp_Emsg("File", rc, "starting file checksum thread.");
            delete csP;
            if (rtCopy) bbcp_RTCopy.Stop();
            inPool.Abort(); return 201;
           }
       outPool =  &csP->csPool;
      } else outPool = &inPool;

// Establish logging options
//
   if (bbcp_Config.Options & bbcp_LOGRD) IOB->Log("DISK", 0);

// Determine what kind of reading we will do here and do it
//
// cerr <<"BLOCKSIZE " <<blockSize <<endl;
   if (blockSize ) rc = Read_Direct(&inPool, outPool);
      else rc=(Vn > 1 ? Read_Vector(&inPool, outPool, Vn)
                      : Read_Normal(&inPool, outPool));

// Delete the real-time copy object if we have one to kill possible thread
//
   if (rtCopy) bbcp_RTCopy.Stop();

// Check if we ended because with an error
//
   IOB->Close();
   if (rc && rc != -ENOBUFS) bbcp_Emsg("Read", -rc, "reading", iofn);

// Prepare an empty buffer to shutdown the buffer pipeline. The offet indicates
// how much data should have been sent and received. A negative offset implies
// that we encountered an error.
//
   if (!(bP = inPool.getEmptyBuff())) return 255;
   bP->blen = 0;
   bP->boff = (rc ? -1 : nextoffset);

// Verify check sum if so wanted. Note that is link-level check summing is in
//
   if (csP)
      {csP->csPool.putFullBuff(bP);
       bbcp_Thread_Wait(tid);
       if (!rc && *bbcp_Config.csString)
          {char *csTxt, *csVal = csP->csObj->Final(&csTxt);
           if (memcmp(csVal, bbcp_Config.csValue, csP->csObj->csSize()))
              {bbcp_Fmsg("Read", iofn, "source checksum", bbcp_Config.csString,
                         "does not match", csTxt);
               rc = EILSEQ;
              } else {DEBUG(csP->csObj->Type() <<": " <<csTxt <<' ' <<iofn);}
          }
       delete csP;
      } else inPool.putFullBuff(bP);

// All done
//
   DEBUG("EOF offset=" <<nextoffset <<" rc=" <<rc <<" fn=" <<iofn);
   return rc;
}