/******************************************************************************/ /* */ /* X r d C n s C o n f i g . c c */ /* */ /* (c) 2011 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 "XrdVersion.hh" #include "Xrd/XrdTrace.hh" #include "XrdClient/XrdClientConst.hh" #include "XrdClient/XrdClientEnv.hh" #include "XrdNet/XrdNetAddr.hh" #include "XrdNet/XrdNetOpts.hh" #include "XrdNet/XrdNetSocket.hh" #include "XrdOuc/XrdOuca2x.hh" #include "XrdOuc/XrdOucArgs.hh" #include "XrdOuc/XrdOucN2NLoader.hh" #include "XrdOuc/XrdOucStream.hh" #include "XrdOuc/XrdOucTList.hh" #include "XrdOuc/XrdOucTokenizer.hh" #include "XrdOuc/XrdOucUtils.hh" #include "XrdSys/XrdSysError.hh" #include "XrdSys/XrdSysHeaders.hh" #include "XrdSys/XrdSysLogger.hh" #include "XrdSys/XrdSysPlugin.hh" #include "XrdSys/XrdSysTimer.hh" #include "XrdSys/XrdSysUtils.hh" #include "XrdCns/XrdCnsConfig.hh" #include "XrdCns/XrdCnsDaemon.hh" #include "XrdCns/XrdCnsLogRec.hh" #include "XrdCns/XrdCnsLogServer.hh" #include "XrdCns/XrdCnsXref.hh" /******************************************************************************/ /* G l o b a l C o n f i g u r a t i o n O b j e c t */ /******************************************************************************/ namespace XrdCns { XrdCnsConfig Config; extern XrdCnsDaemon XrdCnsd; extern XrdSysError MLog; extern XrdOucTrace XrdTrace; } using namespace XrdCns; /******************************************************************************/ /* E x t e r n a l T h r e a d I n t e r f a c e s */ /******************************************************************************/ namespace XrdCns { void *CnsEvents(void *parg) { XrdOucStream fifoEvents; // FIFO fed events int eFD = *static_cast(parg); fifoEvents.Attach(eFD, 32*1024); XrdCnsd.getEvents(fifoEvents, "fifo"); return (void *)0; } void *CnsInt(void *parg) { XrdCnsLogRec *lrP; // Just blab out the midnight herald // while(1) {XrdSysTimer::Snooze(Config.cInt); lrP = XrdCnsLogRec::Alloc(); lrP->setType('\0'); lrP->Queue(); } return (void *)0; } } /******************************************************************************/ /* C o n f i g u r e */ /******************************************************************************/ int XrdCnsConfig::Configure(int argc, char **argv, char *argt) { /* Function: Establish configuration at start up time via arglist. Input: None. Output: 1 upon success or 0 otherwise. */ const char *TraceID = "Config"; XrdOucArgs Spec(&MLog,(argt ? "Cns_Config: ":"XrdCnsd: "), "a:b:B:c:dD:e:i:I:k:l:L:N:p:q:R:z"); XrdNetAddr netHost; const char *dnsEtxt = 0; char buff[2048], *dP, *tP, *n2n = 0, *lroot = 0, *xpl = 0; char theOpt, *theArg; int n, bPort = 0, haveArk = 0, NoGo = 0; // Setup the logger // if (argt) Spec.Set(argt); else Spec.Set(argc-1, argv+1); // Parse the options // while((theOpt = Spec.getopt()) != (char)-1) {switch(theOpt) { case 'a': if (*aPath == '/') aPath = Spec.argval; else NoGo = NAPath("'-a'", Spec.argval); break; case 'B': Opts |= optNoCns; bPath = Spec.argval; break; case 'b': bPath = Spec.argval; break; case 'c': cPath = Spec.argval; break; case 'D': NoGo |= XrdOuca2x::a2i(MLog,"-D value",Spec.argval,&n,0,4); if (!NoGo) EnvPutInt("DebugLevel", n); break; case 'd': XrdTrace.What = TRACE_ALL; XrdSysThread::setDebug(&MLog); break; case 'e': if (*ePath == '/') ePath = Spec.argval; else NoGo = NAPath("'-e'", Spec.argval); break; case 'k': if (!(bindArg = MLog.logger()->ParseKeep(optarg))) NoGo = 1; break; case 'i': NoGo |= XrdOuca2x::a2tm(MLog,"-i value",Spec.argval,&cInt,1); break; case 'I': NoGo |= XrdOuca2x::a2tm(MLog,"-I value",Spec.argval,&mInt,1); break; case 'l': logfn = Spec.argval; if (*logfn == '=') logfn++; break; case 'L': lroot = Spec.argval; break; case 'N': n2n = Spec.argval; break; case 'p': NoGo |= XrdOuca2x::a2i(MLog,"-p value",Spec.argval,&Port,1,65535); bPort = Port; break; case 'q': NoGo |= XrdOuca2x::a2i(MLog,"-q value",Spec.argval,&qLim,1,1024); break; case 'R': Opts |= optRecr; xpl = Spec.argval; break; case 'z': MLog.logger()->setHiRes(); break; default: NoGo = 1; } } // The recreate option is only valid if we are not running under an xrootd // if (Opts & optRecr) {if (getenv("XRDINSTANCE") || getenv("XRDPROG")) {MLog.Emsg("Config","'-R' is valid only for a stand-alone command."); return 0; } if (lroot) {sprintf(buff, "XRDLCLROOT=%s", lroot); putenv(strdup(buff));} if (n2n) {if ((tP=index(n2n, ' '))) {*tP++ = '\0'; while(*tP == ' ') tP++;} sprintf(buff, "XRDN2NLIB=%s", n2n); putenv(strdup(buff)); if (tP && *tP) {sprintf(buff, "XRDN2NPARMS=%s", tP); putenv(strdup(buff));} } if (xpl && *xpl) {char *Colon = xpl; while((Colon = index(Colon, ':'))) *Colon++ = ' '; sprintf(buff, "XRDEXPORTS=%s", xpl); putenv(strdup(buff)); } else {MLog.Emsg("Config","'-R' requires exports to be specified."); return 0; } Space = new XrdCnsXref("public",0); if (bPath) {free(bPath); bPath = 0;} } else { *buff = '\0'; tP = buff; if (lroot) {*tP++ = ' '; *tP++ = '-'; *tP++ = 'L';} if (n2n) {*tP++ = ' '; *tP++ = '-'; *tP++ = 'N';} if (*buff) MLog.Emsg("Config", buff+1, "options ignored; valid only with -R."); } // Handle config // if (!cPath) cPath = getenv("XRDCONFIGFN"); cPath = (cPath ? strdup(cPath) : (char *)""); // Handle the backup directory now. If there is one then we will create a // thread that periodically closes and backs up the log files. // if (bPath) {char *bHost = 0; if (!bPort) bPort = Port; if (*bPath == '/') strcpy(buff, bPath); else if (!(dP = index(bPath, '/')) || *(dP-1) != ':') *buff = 0; else {char hBuff[1024], *cP = dP-1; strncpy(hBuff+1, bPath, cP-bPath); hBuff[cP-bPath+1] = '\0'; if ((cP = index(hBuff+1, ':')) && XrdOuca2x::a2i(MLog,"-b port",cP+1,&bPort,1,65535)) *buff = 0; if (cP) *cP = '\0'; if (!(dnsEtxt = netHost.Set(hBuff+1,0))) bHost = strdup(netHost.Name("0.0.0.0", &dnsEtxt)); if (dnsEtxt) {*buff = 0; MLog.Emsg("Config", "Unable to resolve", hBuff+1, dnsEtxt); } else strcpy(buff, dP); } if (!*buff) {MLog.Emsg("Config","Backup path cannot be determined."); free(bHost); bHost = 0; NoGo=1; } else {if (buff[strlen(buff)-1] == '/') strcat(buff, "cns/"); else strcat(buff, "/cns/"); bPath = strdup(buff); if (bHost) {sprintf(buff, "%s:%d", bHost, bPort); free(bHost); bDest = new XrdOucTList(buff, -bPort); TRACE(DEBUG, "Bkp host =" <text); } TRACE(DEBUG, "Bkp path =" <text)) Dest = new XrdOucTList(buff, n, Dest); else {bDest->next = Dest; Dest = bDest; haveArk = 1;} if (Opts & optNoCns && Dest->val >= 0) {XrdOucTList *xP = Dest; Dest = xP->next; delete xP;} } // Chain in backup host if we have not done so // if (bDest && !haveArk) {bDest->next = Dest; Dest = bDest;} // All done here // return !NoGo; } /******************************************************************************/ int XrdCnsConfig::Configure() { /* Function: Establish configuration at start up time. Input: None. Output: 1 upon success or 0 otherwise. */ const char *TraceID = "Config"; static int eFD; XrdOucTokenizer mToks(0); XrdNetSocket *EventSock; pthread_t tid; int retc, NoGo = 0; const char *iP; char buff[2048], *dP, *tP, *eVar; // Put out the herald // if (!(Opts & optRecr)) MLog.Emsg("Config", "Cns initialization started."); // Set current working directory for core files // if ((iP = XrdOucUtils::InstName(-1))) {strcpy(buff,"./"); strcat(buff, iP);} else strcpy(buff, "."); strcat(buff, "/cns/"); if (!XrdOucUtils::makePath(buff,0770) && chdir(buff)) {} // Do some XrdClient specific optimizations // EnvPutInt(NAME_DATASERVERCONN_TTL, 2147483647); // Prevent timeouts // Get the directory where the meta information is to go // if (!aPath && !(aPath = getenv("XRDADMINPATH"))) aPath = (char *)"/tmp/"; strcpy(buff, aPath); if (buff[strlen(buff)-1] == '/') strcat(buff, "cns/"); else strcat(buff, "/cns/"); aPath = strdup(buff); TRACE(DEBUG, "Admin path=" <Init(Dest); if (Opts & optRecr) exit(NoGo ? 4 : 0); // Create our notification path (r/w for us and our group) and start it // if ((EventSock = XrdNetSocket::Create(&MLog, aPath, "XrdCnsd.events", 0660, XRDNET_FIFO))) {eFD = EventSock->Detach(); delete EventSock; if ((retc = XrdSysThread::Run(&tid, CnsEvents, (void *)&eFD, XRDSYSTHREAD_BIND, "FIFO event handler"))) {MLog.Emsg("Config", retc, "create FIFO event thread"); NoGo = 1;} } else NoGo = 1; // All done // MLog.Emsg("Config", "Cns initialization",(NoGo ? "failed.":"completed.")); return !NoGo; } /******************************************************************************/ /* Private: C o n f i g N 2 N */ /******************************************************************************/ int XrdCnsConfig::ConfigN2N() { static XrdVERSIONINFODEF(myVer, XrdCns, XrdVNUMBER, XrdVERSION); char *N2NLib, *N2NParms = 0; // Get local root // if ((LCLRoot = getenv("XRDLCLROOT")) && !*LCLRoot) LCLRoot = 0; // Get the library path and parameters // if ((N2NLib = getenv("XRDN2NLIB")) && !*N2NLib) N2NParms = N2NLib = 0; else N2NParms = getenv("XRDN2NPARMS"); // Skip getting plugin if there is no reason for it // if (!N2NLib && !LCLRoot) return 0; // Get the plugin // {XrdOucN2NLoader n2nLoader(&MLog, cPath, N2NParms, LCLRoot, 0); N2N = n2nLoader.Load(N2NLib, myVer); } // Cleanup and return result // return N2N == 0; } /******************************************************************************/ /* Public: L o c a l P a t h */ /******************************************************************************/ int XrdCnsConfig::LocalPath(const char *oldp, char *newp, int newpsz) { int rc = 0; if (N2N) rc = N2N->lfn2pfn(oldp, newp, newpsz); else if (((int)strlen(oldp)) >= newpsz) rc = ENAMETOOLONG; else strcpy(newp, oldp); if (rc) {MLog.Emsg("Config", rc, "generate local path from", oldp); return 0; } return 1; } /******************************************************************************/ /* Public: L o g i c P a t h */ /******************************************************************************/ int XrdCnsConfig::LogicPath(const char *oldp, char *newp, int newpsz) { int rc = 0; if (N2N) rc = N2N->pfn2lfn(oldp, newp, newpsz); else if (((int)strlen(oldp)) >= newpsz) rc = ENAMETOOLONG; else strcpy(newp, oldp); if (rc) {MLog.Emsg("Config", rc, "generate logical path from", oldp); return 0; } return 1; } /******************************************************************************/ /* Public: M o u n t P a t h */ /******************************************************************************/ int XrdCnsConfig::MountPath(const char *lfnP, char *newp, int newpsz) { XrdOucTList *xP = Exports; int n = strlen(lfnP); // Find the export path for this incomming path // while(xP) {if (n >= xP->val && !strncmp(xP->text, lfnP, xP->val)) break; xP = xP->next; } // Enter the mount path // if (!xP) {strcpy(newp, LCLRoot ? LCLRoot : "/"); return 0; } // Convert export to a physical path and use that // Config.LocalPath(xP->text, newp, newpsz); return 1; } /******************************************************************************/ /* Private: N A P a t h */ /******************************************************************************/ int XrdCnsConfig::NAPath(const char *What, const char *Path) { MLog.Emsg("Config", "Absolute path required in", What, Path); return 1; }