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