/******************************************************************************/ /* */ /* 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; }