/******************************************************************************/
/* */
/* X r d C m s P a r s e r . c c */
/* */
/* (c) 2007 by the Board of Trustees of the Leland Stanford, Jr., University */
/* All Rights Reserved */
/* Produced by Andrew Hanushevsky for Stanford University under contract */
/* DE-AC02-76-SFO0515 with the Department of Energy */
/* */
/* This file is part of the XRootD software suite. */
/* */
/* XRootD is free software: you can redistribute it and/or modify it under */
/* the terms of the GNU Lesser General Public License as published by the */
/* Free Software Foundation, either version 3 of the License, or (at your */
/* option) any later version. */
/* */
/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
/* License for more details. */
/* */
/* You should have received a copy of the GNU Lesser General Public License */
/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
/* COPYING (GPL license). If not, see . */
/* */
/* The copyright holder's institutional names and contributor's names may not */
/* be used to endorse or promote products derived from this software without */
/* specific prior written permission of the institution or contributor. */
/******************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "XrdCms/XrdCmsParser.hh"
#include "XrdCms/XrdCmsRRData.hh"
#include "XrdCms/XrdCmsTrace.hh"
#include "XrdOuc/XrdOucErrInfo.hh"
#include "XrdOuc/XrdOucBuffer.hh"
#include "XrdSfs/XrdSfsInterface.hh"
#include "XrdSys/XrdSysError.hh"
using namespace XrdCms;
/******************************************************************************/
/* L o c a l C l a s s e s */
/******************************************************************************/
class XrdCmsParseInit
{
public:
const char **nameVec() {return (const char **)PupNVec;}
XrdCmsParseInit(int mVal, ...)
{va_list ap;
int vp = mVal;
// const char *Dummy;
memset(PupNVec, 0, sizeof(PupNVec));
va_start(ap, mVal);
do { if (vp < XrdCmsRRData::Arg_Count)
PupNVec[vp] = va_arg(ap, char *);
else va_arg(ap, char *);
} while((vp = va_arg(ap, int)));
va_end(ap);
}
~XrdCmsParseInit() {}
private:
static char *PupNVec[XrdCmsRRData::Arg_Count];
};
/******************************************************************************/
/* S t a t i c O b j e c t s */
/******************************************************************************/
char *XrdCmsParseInit::PupNVec[XrdCmsRRData::Arg_Count];
XrdCmsParseInit XrdCmsParseArgN(XrdCmsRRData::Arg_Null, "",
XrdCmsRRData::Arg_AToken, "authtoken",
XrdCmsRRData::Arg_Avoid, "bad_host",
XrdCmsRRData::Arg_CGI, "CGI",
XrdCmsRRData::Arg_Datlen, "datalen",
XrdCmsRRData::Arg_Ident, "ident",
XrdCmsRRData::Arg_Ilist, "interfaces",
XrdCmsRRData::Arg_Mode, "mode",
XrdCmsRRData::Arg_Notify, "notify",
XrdCmsRRData::Arg_Opaque, "opaque",
XrdCmsRRData::Arg_Opaque2, "opaque2",
XrdCmsRRData::Arg_Opts, "opts",
XrdCmsRRData::Arg_Path, "path",
XrdCmsRRData::Arg_Path2, "path2",
XrdCmsRRData::Arg_Prty, "prty",
XrdCmsRRData::Arg_Reqid, "reqid",
XrdCmsRRData::Arg_dskFree, "diskfree",
XrdCmsRRData::Arg_dskTot, "disktotal",
XrdCmsRRData::Arg_dskMinf, "diskminf",
XrdCmsRRData::Arg_dskUtil, "diskutil",
XrdCmsRRData::Arg_theLoad, "load",
XrdCmsRRData::Arg_Info, "info",
XrdCmsRRData::Arg_Port, "port",
XrdCmsRRData::Arg_SID, "SID",
0, (const char *)0
);
// The structure that defines the item names to the packer/unpacker
//
XrdOucPupNames XrdCmsParser::PupName(XrdCmsParseArgN.nameVec(),
XrdCmsRRData::Arg_Count);
// Common protocol data unpacker
//
XrdOucPup XrdCmsParser::Pup(&Say, &XrdCmsParser::PupName);
// Reference array
//
XrdOucPupArgs *XrdCmsParser::vecArgs[kYR_MaxReq] = {0};
// The actual parser object
//
XrdCmsParser XrdCms::Parser;
/******************************************************************************/
/* S t a t i c P a r s i n g D e s i f i n i t i o n s */
/******************************************************************************/
// {chmod, mkdir, mkpath, trunc} []
//
XrdOucPupArgs XrdCmsParser::fwdArgA[] =
/*0*/ {setPUP1(XrdCmsRRData::Arg_Ident, char, XrdCmsRRData, Ident),
/*1*/ setPUP1(XrdCmsRRData::Arg_Mode, char, XrdCmsRRData, Mode),
/*2*/ setPUP1(XrdCmsRRData::Arg_Path, char, XrdCmsRRData, Path),
/*3*/ setPUP0(Fence),
/*4*/ setPUP1(XrdCmsRRData::Arg_Opaque, char, XrdCmsRRData, Opaque),
/*5*/ setPUP1(XrdCmsRRData::Arg_Datlen,EndFill,XrdCmsRRData, Request.datalen)
};
// mv [ []]
//
XrdOucPupArgs XrdCmsParser::fwdArgB[] =
/*0*/ {setPUP1(XrdCmsRRData::Arg_Ident, char, XrdCmsRRData, Ident),
/*1*/ setPUP1(XrdCmsRRData::Arg_Path, char, XrdCmsRRData, Path),
/*2*/ setPUP1(XrdCmsRRData::Arg_Path2, char, XrdCmsRRData, Path2),
/*3*/ setPUP0(Fence),
/*4*/ setPUP1(XrdCmsRRData::Arg_Opaque, char, XrdCmsRRData, Opaque),
/*5*/ setPUP1(XrdCmsRRData::Arg_Opaque2, char, XrdCmsRRData, Opaque2),
/*6*/ setPUP1(XrdCmsRRData::Arg_Datlen,EndFill,XrdCmsRRData, Request.datalen)
};
// {rm, rmdir, statfs}
//
XrdOucPupArgs XrdCmsParser::fwdArgC[] =
/*0*/ {setPUP1(XrdCmsRRData::Arg_Ident, char, XrdCmsRRData, Ident),
/*1*/ setPUP1(XrdCmsRRData::Arg_Path, char, XrdCmsRRData, Path),
/*2*/ setPUP0(Fence),
/*3*/ setPUP1(XrdCmsRRData::Arg_Opaque, char, XrdCmsRRData, Opaque),
/*4*/ setPUP1(XrdCmsRRData::Arg_Datlen,EndFill,XrdCmsRRData, Request.datalen)
};
// {locate, select} [ []]
//
XrdOucPupArgs XrdCmsParser::locArgs[] =
/*0*/ {setPUP1(XrdCmsRRData::Arg_Ident, char, XrdCmsRRData, Ident),
/*1*/ setPUP1(XrdCmsRRData::Arg_Opts, int, XrdCmsRRData, Opts),
/*2*/ setPUP1(XrdCmsRRData::Arg_Path, char, XrdCmsRRData, Path),
/*3*/ setPUP1(XrdCmsRRData::Arg_Datlen,Datlen, XrdCmsRRData, PathLen),
/*4*/ setPUP0(Fence),
/*5*/ setPUP1(XrdCmsRRData::Arg_Opaque, char, XrdCmsRRData, Opaque),
/*6*/ setPUP1(XrdCmsRRData::Arg_Avoid, char, XrdCmsRRData, Avoid),
/*7*/ setPUP1(XrdCmsRRData::Arg_Datlen,EndFill,XrdCmsRRData, Request.datalen)
};
// prepadd []
//
XrdOucPupArgs XrdCmsParser::padArgs[] =
/*0*/ {setPUP1(XrdCmsRRData::Arg_Ident, char, XrdCmsRRData, Ident),
/*1*/ setPUP1(XrdCmsRRData::Arg_Reqid, char, XrdCmsRRData, Reqid),
/*2*/ setPUP1(XrdCmsRRData::Arg_Notify, char, XrdCmsRRData, Notify),
/*3*/ setPUP1(XrdCmsRRData::Arg_Prty, char, XrdCmsRRData, Prty),
/*4*/ setPUP1(XrdCmsRRData::Arg_Mode, char, XrdCmsRRData, Mode),
/*5*/ setPUP1(XrdCmsRRData::Arg_Path, char, XrdCmsRRData, Path),
/*6*/ setPUP1(XrdCmsRRData::Arg_Datlen,Datlen, XrdCmsRRData, PathLen),
/*7*/ setPUP0(Fence),
/*8*/ setPUP1(XrdCmsRRData::Arg_Opaque, char, XrdCmsRRData, Opaque),
/*9*/ setPUP1(XrdCmsRRData::Arg_Datlen,EndFill,XrdCmsRRData, Request.datalen)
};
// prepdel
//
XrdOucPupArgs XrdCmsParser::pdlArgs[] =
/*0*/ {setPUP1(XrdCmsRRData::Arg_Ident, char, XrdCmsRRData, Ident),
/*1*/ setPUP1(XrdCmsRRData::Arg_Reqid, char, XrdCmsRRData, Reqid),
/*2*/ setPUP1(XrdCmsRRData::Arg_Datlen,EndFill,XrdCmsRRData, Request.datalen)
};
// avail
//
XrdOucPupArgs XrdCmsParser::avlArgs[] =
/*0*/ {setPUP1(XrdCmsRRData::Arg_dskFree, int, XrdCmsRRData, dskFree),
/*1*/ setPUP1(XrdCmsRRData::Arg_dskUtil, int, XrdCmsRRData, dskUtil),
/*2*/ setPUP0(End)
};
// try
//
XrdOucPupArgs XrdCmsParser::pthArgs[] =
/*0*/ {setPUP1(XrdCmsRRData::Arg_Path, char, XrdCmsRRData, Path),
/*1*/ setPUP1(XrdCmsRRData::Arg_Datlen,Datlen, XrdCmsRRData, PathLen),
/*2*/ setPUP1(XrdCmsRRData::Arg_Datlen,EndFill,XrdCmsRRData, Request.datalen)
};
// load
// 0 1 2 3 5 5
XrdOucPupArgs XrdCmsParser::lodArgs[] =
/*0*/ {setPUP1(XrdCmsRRData::Arg_theLoad, char, XrdCmsRRData, Opaque),
/*1*/ setPUP1(XrdCmsRRData::Arg_dskFree, int, XrdCmsRRData, dskFree),
/*2*/ setPUP0(End)
};
XrdOucPupArgs XrdCmsParser::logArgs[] =
/*0*/ {setPUP1(XrdCmsRRData::Arg_Ident, short, CmsLoginData, Version),
/*1*/ setPUP1(XrdCmsRRData::Arg_Mode, int, CmsLoginData, Mode),
/*2*/ setPUP1(XrdCmsRRData::Arg_Info, int, CmsLoginData, HoldTime),
/*3*/ setPUP1(XrdCmsRRData::Arg_dskTot, int, CmsLoginData, tSpace),
/*4*/ setPUP1(XrdCmsRRData::Arg_dskFree, int, CmsLoginData, fSpace),
/*5*/ setPUP1(XrdCmsRRData::Arg_dskMinf, int, CmsLoginData, mSpace),
/*6*/ setPUP1(XrdCmsRRData::Arg_Info, short, CmsLoginData, fsNum),
/*7*/ setPUP1(XrdCmsRRData::Arg_dskUtil, short, CmsLoginData, fsUtil),
/*8*/ setPUP1(XrdCmsRRData::Arg_Port, short, CmsLoginData, dPort),
/*9*/ setPUP1(XrdCmsRRData::Arg_Port, short, CmsLoginData, sPort),
/*0*/ setPUP0(Fence),
/*1*/ setPUP1(XrdCmsRRData::Arg_SID, char, CmsLoginData, SID),
/*2*/ setPUP1(XrdCmsRRData::Arg_Path, char, CmsLoginData, Paths),
/*3*/ setPUP1(XrdCmsRRData::Arg_Ilist, char, CmsLoginData, ifList),
/*4*/ setPUP1(XrdCmsRRData::Arg_CGI, char, CmsLoginData, envCGI),
/*5*/ setPUP1(XrdCmsRRData::Arg_Datlen,EndFill, CmsLoginData, Size)
};
/******************************************************************************/
/* C o n s t r u c t o r */
/******************************************************************************/
XrdCmsParser::XrdCmsParser()
{
static int Done = 0;
// Setup the Parse vector
//
if (!Done)
{vecArgs[kYR_login] = logArgs;
vecArgs[kYR_chmod] = fwdArgA;
vecArgs[kYR_locate] = locArgs;
vecArgs[kYR_mkdir] = fwdArgA;
vecArgs[kYR_mkpath] = fwdArgA;
vecArgs[kYR_mv] = fwdArgB;
vecArgs[kYR_prepadd] = padArgs;
vecArgs[kYR_prepdel] = pdlArgs;
vecArgs[kYR_rm] = fwdArgC;
vecArgs[kYR_rmdir] = fwdArgC;
vecArgs[kYR_select] = locArgs;
vecArgs[kYR_rm] = fwdArgC;
vecArgs[kYR_statfs] = pthArgs;
vecArgs[kYR_avail] = avlArgs;
vecArgs[kYR_gone] = pthArgs;
vecArgs[kYR_trunc] = fwdArgA;
vecArgs[kYR_try] = pthArgs;
vecArgs[kYR_have] = pthArgs;
vecArgs[kYR_load] = lodArgs;
vecArgs[kYR_state] = pthArgs;
Done = 1;
}
}
/******************************************************************************/
/* D e c o d e */
/******************************************************************************/
// Decode responses to the redirector. Very simple lean protocol.
int XrdCmsParser::Decode(const char *Man, CmsRRHdr &hdr, XrdOucBuffer *dBuff,
XrdOucErrInfo *eInfo)
{
EPNAME("Decode");
static const int mvsz = static_cast(sizeof(kXR_unt32));
kXR_unt32 uval;
int Result, msgval, msglen, dlen = dBuff->DataLen();
const char *Path = eInfo->getErrData(), *User = eInfo->getErrUser();
const char *Mgr = (Man ? Man : "?");
char *msg, *data = dBuff->Buffer();
// Path may be null here, fix it
//
if (!Path) Path = "";
// Responses are always in the form of
//
if (dlen < mvsz) {msgval = 0; msg = (char *)""; msglen = 0;}
else {memcpy(&uval, data, mvsz);
msgval = static_cast(ntohl(uval));
if (dlen == mvsz) {msg = (char *)""; msglen = 0;}
else {msg = data+mvsz; msglen = dlen - mvsz;}
}
// Now decode the response code
//
switch(hdr.rrCode)
{case kYR_redirect: Result = SFS_REDIRECT;
TRACE(Redirect, Mgr <<" redirects " < (int)XrdOucEI::Max_Error_Len)
{XrdOucBuffer *myBuff=dBuff->Highjack(XrdOucEI::Max_Error_Len);
if (myBuff)
{myBuff->SetLen(msglen, (msglen ? mvsz : 0));
eInfo->setErrInfo(msglen, myBuff);
return Result;
}
}
break;
case kYR_error: Result = SFS_ERROR;
if (msgval) msgval = -mapError(msgval);
TRACE(Redirect, Mgr <<" gave " <setErrInfo(msgval, msg);
return Result;
}
/******************************************************************************/
/* m a p E r r o r */
/******************************************************************************/
int XrdCmsParser::mapError(const char *ecode)
{
if (!strcmp("ENOENT", ecode)) return ENOENT;
if (!strcmp("EPERM", ecode)) return EPERM;
if (!strcmp("EACCES", ecode)) return EACCES;
if (!strcmp("EIO", ecode)) return EIO;
if (!strcmp("ENOMEM", ecode)) return ENOMEM;
if (!strcmp("ENOSPC", ecode)) return ENOSPC;
if (!strcmp("ENAMETOOLONG", ecode)) return ENAMETOOLONG;
if (!strcmp("ENETUNREACH", ecode)) return ENETUNREACH;
if (!strcmp("ENOTBLK", ecode)) return ENOTBLK;
if (!strcmp("EISDIR", ecode)) return EISDIR;
return EINVAL;
}
int XrdCmsParser::mapError(int ecode)
{
switch(ecode)
{case kYR_ENOENT: return ENOENT;
case kYR_EPERM: return EPERM;
case kYR_EACCES: return EACCES;
case kYR_EIO: return EIO;
case kYR_ENOMEM: return ENOMEM;
case kYR_ENOSPC: return ENOSPC;
case kYR_ENAMETOOLONG: return ENAMETOOLONG;
case kYR_ENETUNREACH: return ENETUNREACH;
case kYR_ENOTBLK: return ENOTBLK;
case kYR_EISDIR: return EISDIR;
case kYR_FSError: return ENODEV;
case kYR_SrvError: return EFAULT;
default: return EINVAL;
}
}
/******************************************************************************/
/* P a c k */
/******************************************************************************/
int XrdCmsParser::Pack(int rnum, struct iovec *iovP, struct iovec *iovE,
char *Base, char *Work)
{
XrdOucPupArgs *PArgs;
const char *reason;
char buff[16];
int iovcnt;
// Pack the request
//
if ((PArgs = PupArgs(rnum)))
if ((iovcnt = Pup.Pack(iovP, iovE, PArgs, Base, Work))) return iovcnt;
else reason = "too much data for code";
else reason = "invalid request code -";
// Indicate failure (we don't translate the request code as it drags in too
// many dependent object files, sigh.
//
sprintf(buff, "%d", rnum);
Say.Emsg("Pack", "Unable to pack request;", reason, buff);
return 0;
}