XrdFrmConfig.cc

Go to the documentation of this file.
00001 /******************************************************************************/
00002 /*                                                                            */
00003 /*                       X r d F r m C o n f i g . c c                        */
00004 /*                                                                            */
00005 /* (c) 2009 by the Board of Trustees of the Leland Stanford, Jr., University  */
00006 /*       All Rights Reserved. See XrdInfo.cc for complete License Terms       */
00007 /*   Produced by Andrew Hanushevsky for Stanford University under contract    */
00008 /*                DE-AC02-76-SFO0515 with the Deprtment of Energy             */
00009 /******************************************************************************/
00010 
00011 //         $Id: XrdFrmConfig.cc 38011 2011-02-08 18:35:57Z ganis $
00012 
00013 const char *XrdFrmConfigCVSID = "$Id: XrdFrmConfig.cc 38011 2011-02-08 18:35:57Z ganis $";
00014   
00015 #include <unistd.h>
00016 #include <ctype.h>
00017 #include <dirent.h>
00018 #include <string.h>
00019 #include <stdio.h>
00020 #include <fcntl.h>
00021 #include <sys/param.h>
00022 #include <sys/types.h>
00023 #include <sys/socket.h>
00024 #include <sys/stat.h>
00025 
00026 #include "Xrd/XrdInfo.hh"
00027 #include "XrdFrm/XrdFrmConfig.hh"
00028 #include "XrdFrm/XrdFrmMonitor.hh"
00029 #include "XrdFrm/XrdFrmTrace.hh"
00030 #include "XrdFrm/XrdFrmUtils.hh"
00031 #include "XrdNet/XrdNetCmsNotify.hh"
00032 #include "XrdNet/XrdNetDNS.hh"
00033 #include "XrdOss/XrdOss.hh"
00034 #include "XrdOss/XrdOssSpace.hh"
00035 #include "XrdOuc/XrdOuca2x.hh"
00036 #include "XrdOuc/XrdOucEnv.hh"
00037 #include "XrdOuc/XrdOucExport.hh"
00038 #include "XrdOuc/XrdOucMsubs.hh"
00039 #include "XrdOuc/XrdOucName2Name.hh"
00040 #include "XrdOuc/XrdOucProg.hh"
00041 #include "XrdOuc/XrdOucStream.hh"
00042 #include "XrdOuc/XrdOucPList.hh"
00043 #include "XrdOuc/XrdOucTList.hh"
00044 #include "XrdOuc/XrdOucTokenizer.hh" // Add to GNUmake
00045 #include "XrdOuc/XrdOucUtils.hh"
00046 #include "XrdSys/XrdSysError.hh"
00047 #include "XrdSys/XrdSysHeaders.hh"
00048 #include "XrdSys/XrdSysLogger.hh"
00049 #include "XrdSys/XrdSysPlugin.hh"
00050 #include "XrdSys/XrdSysTimer.hh"
00051 #include "XrdSys/XrdSysPlatform.hh"
00052 #include "XrdSys/XrdSysPthread.hh"
00053 
00054 using namespace XrdFrm;
00055 
00056 /******************************************************************************/
00057 /*                         L o c a l   C l a s s e s                          */
00058 /******************************************************************************/
00059   
00060 class XrdFrmConfigSE
00061 {
00062 public:
00063 
00064 XrdSysSemaphore mySem;
00065 int             myFD;
00066 int             seFD;
00067 int             BLen;
00068 char            Buff[32000];
00069 
00070                 XrdFrmConfigSE() : mySem(0), myFD(-1), seFD(-1), BLen(0) {}
00071                ~XrdFrmConfigSE() {}
00072 };
00073 
00074 /******************************************************************************/
00075 /*                     T h r e a d   I n t e r f a c e s                      */
00076 /******************************************************************************/
00077 
00078 void *XrdFrmConfigMum(void *parg)
00079 {
00080    XrdFrmConfigSE *theSE = (XrdFrmConfigSE *)parg;
00081    char *bp = theSE->Buff;
00082    int  n, bleft = sizeof(theSE->Buff)-2;
00083 
00084 // Let the calling thread continue at this point
00085 //
00086    theSE->mySem.Post();
00087 
00088 // Read everything we can
00089 //
00090    do {if ((n = read(theSE->myFD, bp, bleft)) <= 0)
00091           {if (!n || (n < 0 && errno != EINTR)) break;}
00092        bp += n;
00093       } while ((bleft -= n));
00094 
00095 // Refalgomize everything
00096 //
00097    dup2(theSE->seFD, STDERR_FILENO);
00098    close(theSE->seFD);
00099 
00100 // Check if we should add a newline character
00101 //
00102    if (theSE->Buff[bp-(theSE->Buff)-1L] != '\n') *bp++ = '\n';
00103    theSE->BLen = bp-(theSE->Buff);
00104 
00105 // All done
00106 //
00107    theSE->mySem.Post();
00108    return (void *)0;
00109 }
00110 
00111 void *XrdLogWorker(void *parg)
00112 {
00113    time_t midnite = XrdSysTimer::Midnight() + 86400;
00114    char *mememe = strdup((char *)parg);
00115 
00116    while(1)
00117         {XrdSysTimer::Snooze(midnite-time(0));
00118          Say.Say(0, XrdBANNER);
00119          Say.Say(0, mememe, " running.");
00120          midnite += 86400;
00121         }
00122    return (void *)0;
00123 }
00124 
00125 /******************************************************************************/
00126 /*                           C o n s t r u c t o r                            */
00127 /******************************************************************************/
00128   
00129 XrdFrmConfig::XrdFrmConfig(SubSys ss, const char *vopts, const char *uinfo)
00130              : dfltPolicy("*", -2, -3, 72000, 0)
00131 {
00132    char *sP, buff[128];
00133 
00134 // Preset all variables with common defaults
00135 //
00136    vOpts    = vopts;
00137    uInfo    = uinfo;
00138    ssID     = ss;
00139    AdminPath= 0;
00140    QPath    = 0;
00141    AdminMode= 0740;
00142    xfrMax   = 2;
00143    FailHold = 3*60*60;
00144    IdleHold = 10*60;
00145    WaitMigr = 60*60;
00146    WaitPurge= 600;
00147    WaitQChk = 300;
00148    MSSCmd   = 0;
00149    memset(&xfrCmd, 0, sizeof(xfrCmd));
00150    xfrCmd[0].Desc = "copycmd in";     xfrCmd[1].Desc = "copycmd out";
00151    xfrCmd[2].Desc = "copycmd in url"; xfrCmd[3].Desc = "copycmd out url";
00152    xfrIN    = xfrOUT = 0;
00153    isAgent  = (getenv("XRDADMINPATH") ? 1 : 0);
00154    ossLib   = 0;
00155    cmsPath  = 0;
00156    monStage = 0;
00157    haveCMS  = 0;
00158    isOTO    = 0;
00159    Test     = 0;
00160    Verbose  = 0;
00161    pathList = 0;
00162    spacList = 0;
00163    lockFN   = "DIR_LOCK";  // May be ".DIR_LOCK" if hidden
00164    cmdHold  = -1;
00165    cmdFree  = 0;
00166    pVecNum  = 0;
00167    pProg    = 0;
00168    Fix      = 0;
00169    dirHold  = 40*60*60;
00170 
00171    myUid    = geteuid();
00172    myGid    = getegid();
00173 
00174    LocalRoot= RemoteRoot = 0;
00175    lcl_N2N  = rmt_N2N = the_N2N = 0;
00176    N2N_Lib  = N2N_Parms         = 0;
00177 
00178 // Establish our instance name
00179 //
00180    myInst = XrdOucUtils::InstName(-1);
00181 
00182 // Establish default config file
00183 //
00184    if (!(sP = getenv("XRDCONFIGFN")) || !*sP) 
00185             ConfigFN = 0;
00186       else {ConfigFN = strdup(sP); isAgent = 1;}
00187 
00188 // Establish directive prefix
00189 //
00190         if (ss == ssAdmin) {myFrmid = "admin"; myFrmID = "ADMIN";}
00191    else if (ss == ssPurg)  {myFrmid = "purge"; myFrmID = "PURG";}
00192    else if (ss == ssXfr)   {myFrmid = "xfr";   myFrmID = "XFR"; }
00193    else                    {myFrmid = "frm";   myFrmID = "FRM";}
00194 
00195 // Set correct error prefix
00196 //
00197    strcpy(buff, myFrmid);
00198    strcat(buff, "_");
00199    Say.SetPrefix(strdup(buff));
00200 
00201 // Set correct option prefix
00202 //
00203    strcpy(buff, "frm.");
00204    strcat(buff, myFrmid);
00205    strcat(buff, ".");
00206    pfxDTS = strdup(buff); plnDTS = strlen(buff);
00207 }
00208   
00209 /******************************************************************************/
00210 /* Public:                     C o n f i g u r e                              */
00211 /******************************************************************************/
00212   
00213 int XrdFrmConfig::Configure(int argc, char **argv, int (*ppf)())
00214 {
00215    extern XrdOss *XrdOssGetSS(XrdSysLogger *, const char *, const char *);
00216    XrdFrmConfigSE theSE;
00217    int n, retc, isMum = 0, myXfrMax = -1, NoGo = 0, optBG = 0;
00218    const char *temp;
00219    char c, buff[1024], *logfn = 0;
00220    long long logkeep = 0;
00221    extern char *optarg;
00222    extern int opterr, optopt;
00223 
00224 // Obtain the program name (used for logging)
00225 //
00226     retc = strlen(argv[0]);
00227     while(retc--) if (argv[0][retc] == '/') break;
00228     myProg = &argv[0][retc+1];
00229     vectArg = argv; numcArg = argc;
00230 
00231 // Process the options
00232 //
00233    opterr = 0; nextArg = 1;
00234    if (argc > 1 && '-' == *argv[1]) 
00235       while ((c = getopt(argc,argv,vOpts)) && ((unsigned char)c != 0xff))
00236      { switch(c)
00237        {
00238        case 'b': optBG = 1;
00239                  break;
00240        case 'c': if (ConfigFN) free(ConfigFN);
00241                  ConfigFN = strdup(optarg);
00242                  break;
00243        case 'd': Trace.What |= TRACE_ALL;
00244                  XrdOucEnv::Export("XRDDEBUG","1");
00245                  break;
00246        case 'f': Fix = 1;
00247                  break;
00248        case 'h': Usage(0);
00249        case 'k': n = strlen(optarg)-1;
00250                  retc = (isalpha(optarg[n])
00251                         ? XrdOuca2x::a2sz(Say,"keep size", optarg,&logkeep)
00252                         : XrdOuca2x::a2ll(Say,"keep count",optarg,&logkeep));
00253                  if (retc) Usage(1);
00254                  if (!isalpha(optarg[n])) logkeep = -logkeep;
00255                  break;
00256        case 'l': if (logfn) free(logfn);
00257                  logfn = strdup(optarg);
00258                  break;
00259        case 'm': if (XrdOuca2x::a2i(Say,"max number",optarg,&myXfrMax))
00260                     Usage(1);
00261                  break;
00262        case 'n': myInst = optarg;
00263                  break;
00264        case 'O': isOTO = 1;
00265                  if (!ConfigOTO(optarg)) Usage(1);
00266                  break;
00267        case 'T': Test  = 1;
00268                  break;
00269        case 'v': Verbose = 1;
00270                  break;
00271        case 'w': if (XrdOuca2x::a2tm(Say,"wait time",optarg,&WaitPurge))
00272                     Usage(1);
00273                  break;
00274        default:  sprintf(buff,"'%c'", optopt);
00275                  if (c == ':') Say.Emsg("Config", buff, "value not specified.");
00276                     else Say.Emsg("Config", buff, "option is invalid");
00277                  Usage(1);
00278        }
00279      nextArg = optind;
00280      }
00281 
00282 // If we are an agent without a logfile and one is actually defined for the
00283 // underlying system, use the directory of the underlying system.
00284 //
00285    if (ssID != ssAdmin)
00286       {if (!logfn)
00287           {if (isAgent && (logfn = getenv("XRDLOGDIR")))
00288               {sprintf(buff, "%s%s%clog", logfn, myFrmid, (isAgent ? 'a' : 'd'));
00289                logfn = strdup(buff);
00290               }
00291           } else if (!(logfn=XrdOucUtils::subLogfn(Say,myInst,logfn))) _exit(16);
00292 
00293    // If undercover desired and we are not an agent, do so
00294    //
00295        if (optBG && !isAgent) XrdOucUtils::Undercover(Say, !logfn);
00296 
00297    // Bind the log file if we have one
00298    //
00299        if (logfn)
00300           {if (logkeep) Say.logger()->setKeep(logkeep);
00301            Say.logger()->Bind(logfn, 24*60*60);
00302           }
00303       }
00304 
00305 // Get the full host name. In theory, we should always get some kind of name.
00306 //
00307    if (!(myName = XrdNetDNS::getHostName()))
00308       {Say.Emsg("Config","Unable to determine host name; execution terminated.");
00309        _exit(16);
00310       }
00311 
00312 // Set the Environmental variables to hold some config information
00313 // XRDINSTANCE=<pgm> <instance name>@<host name>
00314 //
00315    sprintf(buff,"XRDINSTANCE=%s %s@%s",myProg,
00316                  XrdOucUtils::InstName(myInst), myName);
00317    putenv(strdup(buff)); // XRDINSTANCE
00318    myInstance = strdup(index(buff,'=')+1);
00319    XrdOucEnv::Export("XRDHOST", myName);
00320    XrdOucEnv::Export("XRDPROG", myProg);
00321    XrdOucEnv::Export("XRDNAME", XrdOucUtils::InstName(myInst));
00322 
00323 // We need to divert the output if we are in admin mode with no logfile
00324 //
00325    if (!logfn && (ssID == ssAdmin || isOTO) && !Trace.What)
00326       isMum = ConfigMum(theSE);
00327 
00328 // Put out the herald
00329 //
00330    sprintf(buff, "Scalla %s is starting. . .", myProg);
00331    Say.Say(0, buff);
00332    Say.Say(XrdBANNER);
00333 
00334 // Process the configuration file.
00335 //
00336    Say.Say("++++++ ", myInstance, " initialization started.");
00337    if (!ConfigFN || !*ConfigFN) ConfigFN = strdup("/opt/xrootd/etc/xrootd.cf");
00338    Say.Say("Config using configuration file ", ConfigFN);
00339    NoGo = ConfigProc();
00340 
00341 // Create the correct admin path
00342 //
00343    if (!NoGo) NoGo = ConfigPaths();
00344 
00345 // Obtain and configure the oss (lightweight option only)
00346 //
00347    if (!isAgent)
00348       {XrdOucEnv::Export("XRDREDIRECT", "Q");
00349        XrdOucEnv::Export("XRDOSSTYPE",  myFrmID);
00350        if (ssID == ssPurg) XrdOucEnv::Export("XRDOSSCSCAN", "off");
00351        if (!NoGo && !(ossFS=XrdOssGetSS(Say.logger(),ConfigFN,ossLib))) NoGo=1;
00352       }
00353 
00354 // Now we can create a home directory for core files and do a cwd to it
00355 //
00356    if (myInst) XrdOucUtils::makeHome(Say, myInst);
00357 
00358 // Configure each specific component
00359 //
00360    if (!NoGo) switch(ssID)
00361       {case ssAdmin: NoGo = (ConfigN2N() || ConfigMss());
00362                      break;
00363        case ssPurg:  if (!(NoGo = (ConfigN2N() || ConfigMP("purgeable"))))
00364                         ConfigPF("frm_purged");
00365                      break;
00366        case ssXfr:   if (!isAgent && !(NoGo = ConfigXfr()))
00367                         ConfigPF("frm_xfrd");
00368                      break;
00369        default:      break;
00370       }
00371 
00372 // If we have a post-processing routine, invoke it
00373 //
00374    if (!NoGo && ppf) NoGo = ppf();
00375 
00376 // Start the log turn-over thread
00377 //
00378    if (!NoGo && logfn)
00379       {pthread_t tid;
00380        if ((retc = XrdSysThread::Run(&tid, XrdLogWorker, (void *)myInstance,
00381                                      XRDSYSTHREAD_BIND, "midnight runner")))
00382           {Say.Emsg("Config", retc, "create logger thread"); NoGo = 1;}
00383       }
00384 
00385 // Print ending message
00386 //
00387    temp = (NoGo ? " initialization failed." : " initialization completed.");
00388    Say.Say("------ ", myInstance, temp);
00389 
00390 // Finish up mum processing
00391 //
00392    if (isMum)
00393       {close(STDERR_FILENO);
00394        theSE.mySem.Wait();
00395        if (NoGo && write(STDERR_FILENO, theSE.Buff, theSE.BLen)) {}
00396       }
00397 
00398 // All done
00399 //
00400    return !NoGo;
00401 }
00402   
00403 /******************************************************************************/
00404 /* Public:                     L o c a l P a t h                              */
00405 /******************************************************************************/
00406   
00407 int XrdFrmConfig::LocalPath(const char *oldp, char *newp, int newpsz)
00408 {
00409     int rc = 0;
00410 
00411     if (lcl_N2N) rc = lcl_N2N->lfn2pfn(oldp, newp, newpsz);
00412        else if (((int)strlen(oldp)) >= newpsz) rc = ENAMETOOLONG;
00413                else strcpy(newp, oldp);
00414     if (rc) {Say.Emsg("Config", rc, "generate local path from", oldp);
00415              return 0;
00416             }
00417     return 1;
00418 }
00419   
00420 /******************************************************************************/
00421 /* Public:                   L o g i c a l P a t h                            */
00422 /******************************************************************************/
00423   
00424 int XrdFrmConfig::LogicalPath(const char *oldp, char *newp, int newpsz)
00425 {
00426     int rc = 0;
00427 
00428     if (lcl_N2N) rc = lcl_N2N->pfn2lfn(oldp, newp, newpsz);
00429        else if (((int)strlen(oldp)) >= newpsz) rc = ENAMETOOLONG;
00430                else strcpy(newp, oldp);
00431     if (rc) {Say.Emsg("Config", rc, "generate logical path from", oldp);
00432              return 0;
00433             }
00434     return 1;
00435 }
00436 
00437 /******************************************************************************/
00438 /* Public:                      P a t h O p t s                               */
00439 /******************************************************************************/
00440 
00441 unsigned long long XrdFrmConfig::PathOpts(const char *Lfn)
00442 {
00443    extern XrdOucPListAnchor *XrdOssRPList;
00444 
00445    return XrdOssRPList->Find(Lfn);
00446 }
00447 
00448 /******************************************************************************/
00449 /* Public:                    R e m o t e P a t h                             */
00450 /******************************************************************************/
00451   
00452 int XrdFrmConfig::RemotePath(const char *oldp, char *newp, int newpsz)
00453 {
00454     int rc = 0;
00455 
00456     if (rmt_N2N) rc = rmt_N2N->lfn2rfn(oldp, newp, newpsz);
00457        else if (((int)strlen(oldp)) >= newpsz) rc = ENAMETOOLONG;
00458                else strcpy(newp, oldp);
00459     if (rc) {Say.Emsg("Config", rc, "generate rmote path from", oldp);
00460              return 0;
00461             }
00462     return 1;
00463 }
00464   
00465 /******************************************************************************/
00466 /*                                 S p a c e                                  */
00467 /******************************************************************************/
00468   
00469 XrdOucTList *XrdFrmConfig::Space(const char *Name, const char *Path)
00470 {
00471    static XrdOucTList nullEnt;
00472    struct VPInfo *vP = VPList;
00473           XrdOucTList *tP;
00474    char buff[1032];
00475    int n;
00476 
00477 // First find the space entry
00478 //
00479    while(vP && strcmp(vP->Name, Name)) vP = vP->Next;
00480    if (!vP) return 0;
00481 
00482 // Check if we should find a particular path
00483 //
00484    if (!Path) return vP->Dir;
00485 
00486 // Make sure it nds with a slash (it usually does not)
00487 //
00488    n = strlen(Path)-1;
00489    if (Path[n] != '/')
00490       {if (n >= (int)sizeof(buff)-2) return &nullEnt;
00491        strcpy(buff, Path); buff[n+1] = '/'; buff[n+2] = '\0';
00492        Path = buff;
00493       }
00494 
00495 // Find the path
00496 //
00497    tP = vP->Dir;
00498    while(tP && strcmp(Path, tP->text)) tP = tP->next;
00499    return (tP ? tP : &nullEnt);
00500 }
00501 
00502 /******************************************************************************/
00503 /*                     P r i v a t e   F u n c t i o n s                      */
00504 /******************************************************************************/
00505 /******************************************************************************/
00506 /* Private:                    C o n f i g C m d                              */
00507 /******************************************************************************/
00508   
00509 XrdOucMsubs *XrdFrmConfig::ConfigCmd(const char *cname, char *cdata)
00510 {
00511    XrdOucMsubs *msubs;
00512    char *cP;
00513 
00514    if (!cdata) {Say.Emsg("Config", cname, "not specified."); return 0;}
00515 
00516    if ((cP = index(cdata, ' '))) *cP = '\0';
00517 
00518    if (access(cdata, X_OK))
00519       {Say.Emsg("Config", errno, "set up", cdata);
00520        return 0;
00521       }
00522    if (cP) *cP = ' ';
00523 
00524    msubs = new XrdOucMsubs(&Say);
00525    if (msubs->Parse(cname, cdata)) return msubs;
00526 
00527    return 0;  // We will exit no need to delete msubs
00528 }
00529 
00530 /******************************************************************************/
00531 /* Private:                     C o n f i g M P                               */
00532 /******************************************************************************/
00533 
00534 int XrdFrmConfig::ConfigMP(const char *pType)
00535 {
00536    EPNAME("ConfigMP");
00537    extern XrdOucPListAnchor *XrdOssRPList;
00538    XrdOucTList *nP, *tP, *mypList = 0, *expList = 0;
00539    char pDir[MAXPATHLEN+1];
00540    long long pOpts, xOpt = (*pType == 'm' ? XRDEXP_MIG : XRDEXP_PURGE);
00541    int i, NoGo = 0;
00542 
00543 // Verify that we have an RPList
00544 //
00545    if (!XrdOssRPList)
00546       {Say.Emsg("Config", "Cannot determine", pType, "paths."); return 1;}
00547 
00548 // Parse the arguments which consist of space names and paths
00549 //
00550    for (i = nextArg; i < numcArg; i++)
00551        {char *psVal = vectArg[i];
00552         int   psLen = strlen(psVal);
00553         if (*psVal == '/')
00554            {pOpts = XrdOssRPList->Find(psVal);
00555             if (pOpts & xOpt) mypList = InsertPL(mypList, psVal, psLen,
00556                                                 (pOpts & XRDEXP_MAKELF ? 1:0));
00557                else {Say.Say("Config", psVal, "not marked", pType); NoGo = 1;}
00558            } else {
00559             VPInfo *vP = VPList;
00560             while(vP && strcmp(psVal, vP->Name)) vP = vP->Next;
00561             if (vP) spacList = new XrdOucTList(psVal, psLen, spacList);
00562                else {Say.Emsg("Config", "Space", psVal, "not defined.");
00563                      NoGo = 1;
00564                     }
00565            }
00566        }
00567 
00568 // Check if we should continue
00569 //
00570    if (NoGo) return 1;
00571 
00572 // Get correct path list
00573 //
00574    if (!mypList)
00575       {XrdOucPList *fP = XrdOssRPList->First();
00576        short sval[2];
00577        while(fP)
00578             {sval[0] = (fP->Flag() & XRDEXP_MAKELF ? 1 : 0);
00579              sval[1] = fP->Plen();
00580              if (fP->Flag() & xOpt)
00581                  mypList = new XrdOucTList(fP->Path(), sval, mypList);
00582                  else
00583                  expList = new XrdOucTList(fP->Path(), sval, expList);
00584              fP = fP->Next();
00585             }
00586 //     if (!mypList)
00587  //       {Say.Emsg("Config", "No", pType, "paths found."); return 1;}
00588       }
00589 
00590 // Now we need to construct a search list which may include excludes which
00591 // hapen when we get nested subtrees with different options
00592 //
00593    while((tP = mypList))
00594         {if (!LocalPath(tP->text, pDir, sizeof(pDir))) NoGo = 1;
00595             else {pathList = new VPInfo(pDir, int(tP->sval[0]), pathList);
00596                   DEBUG("Will scan " <<(tP->sval[0]?"r/w: ":"r/o: ") <<pDir);
00597                   nP = expList;
00598                   while(nP)
00599                        {if (!strncmp(tP->text, nP->text, tP->sval[1]))
00600                            InsertXD(nP->text);
00601                         nP = nP->next;
00602                        }
00603                   mypList = tP->next; delete tP;
00604                  }
00605         }
00606 
00607 // Delete the explist
00608 //
00609    while((tP = expList)) {expList = tP->next; delete tP;}
00610 
00611 // The oss would have already set NORCREATE and NOCHECK for all stageable paths.
00612 // But now, we must also off the R/O flag on every purgeable and stageable path
00613 // to prevent oss complaints. This needs to be defered to here because we need
00614 // to know which paths are actually r/o and r/w.
00615 //
00616    if (!NoGo)
00617       {XrdOucPList *fp = XrdOssRPList->First();
00618        while(fp)
00619             {if (fp->Flag() & (XRDEXP_STAGE | XRDEXP_PURGE))
00620                 fp->Set(fp->Flag() & ~XRDEXP_NOTRW);
00621              fp = fp->Next();
00622             }
00623       }
00624 
00625 // All done now
00626 //
00627    return NoGo;
00628 }
00629 
00630 /******************************************************************************/
00631 /* Private:                    C o n f i g M s s                              */
00632 /******************************************************************************/
00633   
00634 int XrdFrmConfig::ConfigMss()
00635 {
00636    if (MSSCmd)
00637       {MSSProg = new XrdOucProg(&Say);
00638        if (MSSProg->Setup(MSSCmd)) return 1;
00639       }
00640    return 0;
00641 }
00642 
00643 /******************************************************************************/
00644 /* Private:                    C o n f i g M u m                              */
00645 /******************************************************************************/
00646 
00647 int XrdFrmConfig::ConfigMum(XrdFrmConfigSE &theSE)
00648 {
00649    class Recover
00650         {public:
00651          int fdvec[2];
00652          int stdErr;
00653              Recover() : stdErr(-1) {fdvec[0] = -1; fdvec[1] = -1;}
00654             ~Recover() {if (fdvec[0] >= 0) close(fdvec[0]);
00655                         if (fdvec[1] >= 0) close(fdvec[1]);
00656                         if (stdErr >= 0)   {dup2(stdErr, STDERR_FILENO);
00657                                             close(stdErr);
00658                                            }
00659                        }
00660         };
00661    Recover FD;
00662    pthread_t tid;
00663    int rc;
00664 
00665 // Create a pipe
00666 //
00667    if (pipe(FD.fdvec) < 0) return 0;
00668    fcntl(FD.fdvec[0], F_SETFD, FD_CLOEXEC);
00669 
00670 // Save the current standard error FD
00671 //
00672    if ((FD.stdErr = dup(STDERR_FILENO)) < 0) return 0;
00673 
00674 // Now hook-up the pipe to standard error
00675 //
00676    if (dup2(FD.fdvec[1], STDERR_FILENO) < 0) return 0;
00677    close(FD.fdvec[1]); FD.fdvec[1] = -1;
00678 
00679 // Prepare arguments to the thread that will suck up the output
00680 //
00681    theSE.myFD = FD.fdvec[0];
00682    theSE.seFD = FD.stdErr;
00683 
00684 // Start a thread to read all of the output
00685 //
00686     if ((rc = XrdSysThread::Run(&tid, XrdFrmConfigMum, (void *)&theSE,
00687                                 XRDSYSTHREAD_BIND, "Mumify"))) return 0;
00688 
00689 // Now fixup to return correctly
00690 //
00691    theSE.mySem.Wait();
00692    FD.fdvec[0] = -1;
00693    FD.stdErr = -1;
00694    return 1;
00695 }
00696 
00697 /******************************************************************************/
00698 /* Private:                    C o n f i g N 2 N                              */
00699 /******************************************************************************/
00700 
00701 int XrdFrmConfig::ConfigN2N()
00702 {
00703    XrdSysPlugin    *myLib;
00704    XrdOucName2Name *(*ep)(XrdOucgetName2NameArgs);
00705 
00706 // If we have no library path then use the default method (this will always
00707 // succeed).
00708 //
00709    if (!N2N_Lib)
00710       {the_N2N = XrdOucgetName2Name(&Say, ConfigFN, "", LocalRoot, RemoteRoot);
00711        if (LocalRoot)  lcl_N2N = the_N2N;
00712        if (RemoteRoot) rmt_N2N = the_N2N;
00713        return 0;
00714       }
00715 
00716 // Create a pluin object (we will throw this away without deletion because
00717 // the library must stay open but we never want to reference it again).
00718 //
00719    if (!(myLib = new XrdSysPlugin(&Say, N2N_Lib))) return 1;
00720 
00721 // Now get the entry point of the object creator
00722 //
00723    ep = (XrdOucName2Name *(*)(XrdOucgetName2NameArgs))(myLib->getPlugin("XrdOucgetName2Name"));
00724    if (!ep) return 1;
00725 
00726 
00727 // Get the Object now
00728 //
00729    lcl_N2N = rmt_N2N = the_N2N = ep(&Say, ConfigFN, 
00730                                    (N2N_Parms ? N2N_Parms : ""),
00731                                    LocalRoot, RemoteRoot);
00732    return lcl_N2N == 0;
00733 }
00734   
00735 /******************************************************************************/
00736 /*                             C o n f i g O T O                              */
00737 /******************************************************************************/
00738   
00739 int XrdFrmConfig::ConfigOTO(char *Parms)
00740 {
00741    char *Comma;
00742 
00743 // Pick up free argument
00744 //
00745    if ((Comma = index(Parms, ','))) *Comma = '\0';
00746    if (XrdOuca2x::a2sp(Say, "free value", Parms, &cmdFree, 1)) return 0;
00747 
00748 // Pick up hold argument
00749 //
00750    if (!Comma || !(*(Comma+1))) return 1;
00751    if (*(Comma+1) == ',') Comma++;
00752       else {Parms = Comma+1;
00753             if ((Comma = index(Parms, ','))) *Comma = '\0';
00754             if (XrdOuca2x::a2i(Say,"hold value",Parms,&cmdHold,0)) return 0;
00755            }
00756 
00757 // All done
00758 //
00759    return 1;
00760 }
00761 
00762 /******************************************************************************/
00763 /*                           C o n f i g P a t h s                            */
00764 /******************************************************************************/
00765   
00766 int XrdFrmConfig::ConfigPaths()
00767 {
00768    char *xPath, buff[MAXPATHLEN];
00769    const char *insName;
00770 
00771 // Get the directory for the meta information. If we don't get it from the
00772 // config, then use XRDADMINPATH which already contains the instance name.
00773 //
00774 // Set the directory where the meta information is to go
00775 // XRDADMINPATH already contains the instance name
00776 
00777         if ((xPath = AdminPath))              insName = myInst;
00778    else if ((xPath = getenv("XRDADMINPATH"))) insName = 0;
00779    else     {xPath = (char *)"/tmp/";         insName = myInst;}
00780    
00781 // Establish the cmsd notification object. We need to do this using an
00782 // unqualified admin path that we determined above.
00783 //
00784    if (haveCMS)
00785       cmsPath = new XrdNetCmsNotify(&Say,xPath,insName,XrdNetCmsNotify::isServ);
00786 
00787 // Create the admin directory if it does not exists and set QPath
00788 //
00789    if (!(xPath = XrdFrmUtils::makePath(insName, xPath, AdminMode))) return 1;
00790    if (AdminPath) free(AdminPath); AdminPath = xPath;
00791    if (!QPath) QPath = AdminPath;
00792 
00793 // Create the purge stop file name
00794 //
00795    strcpy(buff, Config.AdminPath); strcat(buff, "STOPPURGE");
00796    StopPurge = strdup(buff);
00797 
00798 // All done
00799 //
00800    return 0;
00801 }
00802 
00803 /******************************************************************************/
00804 /*                              C o n f i g P F                               */
00805 /******************************************************************************/
00806   
00807 void XrdFrmConfig::ConfigPF(const char *pFN)
00808 {
00809    static const int Mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH;
00810    const char *ppP = (PidPath ? PidPath : "/tmp");
00811    char buff[1032], data[24];
00812    int pfFD, n;
00813 
00814 // Construct pidfile name
00815 //
00816    if (myInst) sprintf(buff, "%s/%s/%s.pid", ppP, myInst, pFN);
00817       else sprintf(buff, "%s/%s.pid", ppP, pFN);
00818 
00819 // Open the pidfile creating it if necessary
00820 //
00821    if ((pfFD = open(buff, O_WRONLY|O_CREAT|O_TRUNC, Mode)) < 0)
00822       {Say.Emsg("Config",errno,"open",buff); return;}
00823 
00824 // Write out our pid
00825 //
00826    n = sprintf(data, "%lld", static_cast<long long>(getpid()));
00827    if (write(pfFD, data, n) < 0) Say.Emsg("Config",errno,"writing",buff);
00828    close(pfFD);
00829 }
00830 
00831 /******************************************************************************/
00832 /* Private:                   C o n f i g P r o c                             */
00833 /******************************************************************************/
00834   
00835 int XrdFrmConfig::ConfigProc()
00836 {
00837   char *var;
00838   int  cfgFD, retc, mbok, NoGo = 0;
00839   XrdOucEnv myEnv;
00840   XrdOucStream cfgFile(&Say, myInstance, &myEnv, "=====> ");
00841 
00842 // Try to open the configuration file.
00843 //
00844    if ( (cfgFD = open(ConfigFN, O_RDONLY, 0)) < 0)
00845       {Say.Emsg("Config", errno, "open config file", ConfigFN);
00846        return 1;
00847       }
00848    cfgFile.Attach(cfgFD); cFile = &cfgFile;
00849 
00850 // Now start reading records until eof.
00851 //
00852    while((var = cFile->GetMyFirstWord()))
00853         {mbok = 0;
00854          if (!strncmp(var, pfxDTS, plnDTS)) {var += plnDTS; mbok = 1;}
00855          if(ConfigXeq(var, mbok)) {cfgFile.Echo(); NoGo = 1;}
00856         }
00857 
00858 // Now check if any errors occured during file i/o
00859 //
00860    if ((retc = cfgFile.LastError()))
00861       NoGo = Say.Emsg("Config", retc, "read config file", ConfigFN);
00862    cfgFile.Close(); cFile = 0;
00863 
00864 // Return final return code
00865 //
00866    return NoGo;
00867 }
00868 
00869 /******************************************************************************/
00870 /* Prvate:                     C o n f i g X e q                              */
00871 /******************************************************************************/
00872 
00873 int XrdFrmConfig::ConfigXeq(char *var, int mbok)
00874 {
00875 
00876 // Process common items to all subsystems
00877 //
00878    if (!strcmp(var, "all.adminpath" )) return xapath();
00879    if (!strcmp(var, "all.pidpath"   )) return Grab(var, &PidPath, 0);
00880    if (!strcmp(var, "all.manager"   )) {haveCMS = 1; return 0;}
00881 
00882 // Process directives specific to each subsystem
00883 //
00884    if (ssID == ssAdmin)
00885       {
00886        if (!strcmp(var, "frm.xfr.qcheck")) return xqchk();
00887        if (!strcmp(var, "ofs.osslib"    )) return Grab(var, &ossLib,    0);
00888        if (!strcmp(var, "oss.cache"     )) return xspace(0,0);
00889        if (!strcmp(var, "oss.localroot" )) return Grab(var, &LocalRoot, 0);
00890        if (!strcmp(var, "oss.namelib"   )) return xnml();
00891        if (!strcmp(var, "oss.remoteroot")) return Grab(var, &RemoteRoot, 0);
00892        if (!strcmp(var, "oss.space"     )) return xspace();
00893 //     if (!strcmp(var, "oss.mssgwcmd"  )) return Grab(var, &MSSCmd,    0);
00894 //     if (!strcmp(var, "oss.msscmd"    )) return Grab(var, &MSSCmd,    0);
00895       }
00896 
00897    if (ssID == ssXfr)
00898       {
00899        if (!strcmp(var, "qcheck"        )) return xqchk();
00900        if (isAgent) return 0;           // Server-oriented directives
00901 
00902        if (!strcmp(var, "ofs.osslib"    )) return Grab(var, &ossLib,    0);
00903        if (!strcmp(var, "oss.cache"     )) return xspace(0,0);
00904        if (!strcmp(var, "oss.localroot" )) return Grab(var, &LocalRoot, 0);
00905        if (!strcmp(var, "oss.namelib"   )) return xnml();
00906        if (!strcmp(var, "oss.remoteroot")) return Grab(var, &RemoteRoot, 0);
00907        if (!strcmp(var, "oss.xfr"       )) return xxfr();
00908        if (!strcmp(var, "xrootd.monitor")) return xmon();
00909 
00910        if (!strcmp(var, "copycmd"       )) return xcopy();
00911        if (!strcmp(var, "copymax"       )) return xcmax();
00912        if (!strcmp(var, "oss.space"     )) return xspace();
00913 
00914        if (!strncmp(var, "migr.", 5))   // xfr.migr
00915       {char *vas = var+5;
00916        if (!strcmp(vas, "idlehold"      )) return xitm("idle time", IdleHold);
00917        if (!strcmp(vas, "waittime"      )) return xitm("migr wait", WaitMigr);
00918       }
00919       }
00920 
00921    if (ssID == ssPurg)
00922       {
00923        if (!strcmp(var, "dirhold"       )) return xdpol();
00924        if (!strcmp(var, "oss.cache"     )) return xspace(1,0);
00925        if (!strcmp(var, "oss.localroot" )) return Grab(var, &LocalRoot, 0);
00926        if (!strcmp(var, "ofs.osslib"    )) return Grab(var, &ossLib,    0);
00927        if (!strcmp(var, "policy"        )) return xpol();
00928        if (!strcmp(var, "polprog"       )) return xpolprog();
00929        if (!strcmp(var, "oss.space"     )) return xspace(1);
00930        if (!strcmp(var, "waittime"      )) return xitm("purge wait",WaitPurge);
00931       }
00932 
00933    // No match found, complain.
00934    //
00935    if (!mbok) cFile->noEcho();
00936       else {Say.Say("Config warning: ignoring unknown frm directive '",var,"'.");
00937             cFile->Echo();
00938            }
00939    return 0;
00940 }
00941 
00942 /******************************************************************************/
00943 /* Private:                    C o n f i g X f r                              */
00944 /******************************************************************************/
00945   
00946 int XrdFrmConfig::ConfigXfr()
00947 {
00948    int i, isBad, ioOK[2] = {0};
00949 
00950 // Configure the name2name library and migratable paths and mass storage
00951 //
00952    isBad = ConfigN2N() || ConfigMP("migratable") ||  ConfigMss();
00953 
00954 // Make sure
00955 
00956 // Configure all of the transfer commands
00957 //
00958    for (i = 0; i < 4; i++)
00959        {if (xfrCmd[i].theCmd)
00960            {if ((xfrCmd[i].theVec=ConfigCmd(xfrCmd[i].Desc, xfrCmd[i].theCmd)))
00961                ioOK[i%2]  = 1;
00962                else isBad = 1;
00963            }
00964        }
00965 
00966 // Verify that we can actually do something
00967 //
00968    if (!(ioOK[0] | ioOK[1]))
00969       {Say.Emsg("Config",
00970                 "No copy commands specified; execution is meaningless!");
00971        return 1;
00972       }
00973 
00974 // Verify that input copies are OK
00975 //
00976    if (!(xfrIN = ioOK[0]))
00977       Say.Emsg("Config", "Input copy command not specified; "
00978                          "incoming transfers prohibited!");
00979 
00980 // Verify that input copies are OK
00981 //
00982    if (!(xfrOUT = ioOK[1]))
00983       Say.Emsg("Config", "Output copy command not specified; "
00984                          "outgoing transfers prohibited!");
00985 
00986 // Finally configure monitoring
00987 //
00988    isBad |= (monStage &&!XrdFrmMonitor::Init());
00989 
00990 // All done
00991 //
00992    return isBad;
00993 }
00994 
00995 /******************************************************************************/
00996 /* Private:                      g e t T i m e                                */
00997 /******************************************************************************/
00998 
00999 int XrdFrmConfig::getTime(const char *emsg, const char *item, int *val,
01000                           int minv, int maxv)
01001 {
01002     if (strcmp(item, "forever"))
01003        return  XrdOuca2x::a2tm(Say, emsg, item, val, minv, maxv);
01004     *val = -1;
01005     return 0;
01006 }
01007   
01008 /******************************************************************************/
01009 /* Private:                         G r a b                                   */
01010 /******************************************************************************/
01011   
01012 int XrdFrmConfig::Grab(const char *var, char **Dest, int nosubs)
01013 {
01014     char  myVar[1024], buff[2048], *val;
01015     XrdOucEnv *myEnv = 0;
01016 
01017 // Copy the variable name as this may change because it points to an
01018 // internal buffer in Config. The vagaries of effeciency.
01019 //
01020    strlcpy(myVar, var, sizeof(myVar));
01021    var = myVar;
01022 
01023 // If substitutions allowed then we need to grab a single token else grab
01024 // the remainder of the line but suppress substitutions.
01025 //
01026    if (!nosubs) val = cFile->GetWord();
01027       else {myEnv = cFile->SetEnv(0);
01028             if (!cFile->GetRest(buff, sizeof(buff)))
01029                {Say.Emsg("Config", "arguments too long for", var);
01030                 cFile->SetEnv(myEnv);
01031                 return 1;
01032                }
01033             val = buff;
01034             cFile->SetEnv(myEnv);
01035            }
01036 
01037 // At this point, make sure we have a value
01038 //
01039    if (!val || !(*val))
01040       {if (nosubs < 0) Say.Emsg("Config", "no arguments for", var);
01041           else         Say.Emsg("Config", "no value for directive", var);
01042        return 1;
01043       }
01044 
01045 // Set the value. Either this is a simple string or a compund string
01046 //
01047    if (*Dest) {free(*Dest); Dest = 0;}
01048    if (nosubs < 0)
01049       {char fBuff[2048];
01050        int n = strlen(myVar);
01051        if (n + strlen(val) > sizeof(fBuff)-1)
01052           {Say.Emsg("Config", "arguments too long for", var); return 1;}
01053        strcpy(fBuff, myVar); *(fBuff+n) = ' '; strcpy(fBuff+n+1, val);
01054        *Dest = strdup(fBuff);
01055       } else *Dest = strdup(val);
01056 
01057 // All done
01058 //
01059    return 0;
01060 }
01061 
01062 /******************************************************************************/
01063 /* Private:                     I n s e r t P L                               */
01064 /******************************************************************************/
01065   
01066 XrdOucTList *XrdFrmConfig::InsertPL(XrdOucTList *pL, const char *Path,
01067                                     int Plen, int isRW)
01068 {
01069    short sval[4] = {isRW, Plen};
01070    XrdOucTList *pP = 0, *tP = pL;
01071 
01072 // Find insertion point
01073 //
01074    while(tP && tP->sval[1] < Plen) {pP = tP; tP = tP->next;}
01075 
01076 // Insert new element
01077 //
01078    if (pP) pP->next = new XrdOucTList(Path, sval, tP);
01079       else       pL = new XrdOucTList(Path, sval, tP);
01080 
01081 // Return the new list
01082 //
01083    return pL;
01084 }
01085 
01086 /******************************************************************************/
01087 /* Private:                     I n s e r t X D                               */
01088 /******************************************************************************/
01089 
01090 void XrdFrmConfig::InsertXD(const char *Path)
01091 {
01092    EPNAME("InsertXD");
01093    char pBuff[MAXPATHLEN], *pP;
01094    int n = strlen(Path);
01095 
01096 // Make sure this does not end with a slash
01097 //
01098    strcpy(pBuff, Path);
01099    pP = pBuff + n - 1;
01100    while(*pP == '/' && pP != pBuff) {*pP-- = '\0'; n--;}
01101 
01102 // Insert this directory into the exclude list for the current path
01103 //
01104    pathList->Dir = new XrdOucTList(pBuff, n, pathList->Dir);
01105    DEBUG("Excluding '" <<pBuff <<"'");
01106 }
01107   
01108 /******************************************************************************/
01109 /* Private:                        U s a g e                                  */
01110 /******************************************************************************/
01111   
01112 void XrdFrmConfig::Usage(int rc)
01113 {
01114      cerr <<"\nUsage: " <<myProg <<" " <<uInfo <<endl;
01115      _exit(rc);
01116 }
01117 
01118 /******************************************************************************/
01119 /* Private:                       x a p a t h                                 */
01120 /******************************************************************************/
01121 
01122 /* Function: xapath
01123 
01124    Purpose:  To parse the directive: adminpath <path> [group]
01125 
01126              <path>    the path of the FIFO to use for admin requests.
01127 
01128              group     allows group access to the admin path
01129 
01130    Output: 0 upon success or !0 upon failure.
01131 */
01132 
01133 int XrdFrmConfig::xapath()
01134 {
01135     char *pval, *val;
01136     mode_t mode = S_IRWXU;
01137 
01138 // Get the path
01139 //
01140    pval = cFile->GetWord();
01141    if (!pval || !pval[0])
01142       {Say.Emsg("Config", "adminpath not specified"); return 1;}
01143 
01144 // Make sure it's an absolute path
01145 //
01146    if (*pval != '/')
01147       {Say.Emsg("Config", "adminpath not absolute"); return 1;}
01148 
01149 // Record the path
01150 //
01151    if (AdminPath) free(AdminPath);
01152    AdminPath = strdup(pval);
01153 
01154 // Get the optional access rights
01155 //
01156    if ((val = cFile->GetWord()) && val[0])
01157       {if (!strcmp("group", val)) mode |= S_IRWXG;
01158           else {Say.Emsg("Config", "invalid admin path modifier -", val);
01159                 return 1;
01160                }
01161       }
01162    AdminMode = mode;
01163    return 0;
01164 }
01165 
01166 /******************************************************************************/
01167 /* Private:                        x c o p y                                  */
01168 /******************************************************************************/
01169 
01170 /* Function: copycmd
01171 
01172    Purpose:  To parse the directive: copycmd [Options] cmd [args]
01173 
01174    Options:  [in] [out] [stats] [timeout <sec>] [url] cmd [args]
01175 
01176              in        use command for incomming copies.
01177              noalloc   do not pre-allocate space for incomming copies.
01178              out       use command for outgoing copies.
01179              stats     print transfer statistics in the log.
01180              timeout   how long the cmd can run before it is killed.
01181              url       use command for url-based transfers.
01182 
01183    Output: 0 upon success or !0 upon failure.
01184 */
01185 int XrdFrmConfig::xcopy()
01186 {  int cmdIO[2] = {0,0}, TLim=0, Stats=0, hasMDP=0, cmdUrl=0, noAlo=0;
01187    char *val, *theCmd = 0;
01188    struct copyopts {const char *opname; int *oploc;} cpopts[] =
01189          {
01190           {"in",     &cmdIO[0]},
01191           {"out",    &cmdIO[1]},
01192           {"noalloc",&noAlo},
01193           {"stats",  &Stats},
01194           {"timeout",&TLim},
01195           {"url",    &cmdUrl}
01196          };
01197    int i, n, numopts = sizeof(cpopts)/sizeof(struct copyopts);
01198 
01199 // Pick up options
01200 //
01201    val = cFile->GetWord();
01202    while(val && *val != '/')
01203         {for (i = 0; i < numopts; i++)
01204              {if (!strcmp(val,cpopts[i].opname))
01205                  {if (strcmp("timeout", val)) {*cpopts[i].oploc = 1; break;}
01206                      else if (!xcopy(TLim)) return 1;
01207                  }
01208              }
01209          if (i >= numopts)
01210             Say.Say("Config warning: ignoring invalid copycmd option '",val,"'.");
01211          val = cFile->GetWord();
01212         }
01213 
01214 // Pick up the program
01215 //
01216    if (!val || !*val)
01217       {Say.Emsg("Config", "copy command not specified"); return 1;}
01218    if (Grab(val, &theCmd, -1)) return 1;
01219 
01220 // Find if $MDP is present here
01221 //
01222    if (!cmdIO[0] && !cmdIO[1]) cmdIO[0] = cmdIO[1] = 1;
01223    if (cmdIO[1]) hasMDP = (strstr(theCmd, "$MDP") != 0);
01224 
01225 // Initialzie the appropriate command structures
01226 //
01227    n = (cmdUrl ? 3 : 1);
01228    i = 1;
01229    do {if (cmdIO[i])
01230           {if (xfrCmd[n].theCmd) free(xfrCmd[n].theCmd);
01231            xfrCmd[n].theCmd = strdup(theCmd);
01232            if (Stats)  xfrCmd[n].Opts  |= cmdStats;
01233            if (hasMDP) xfrCmd[n].Opts  |= cmdMDP;
01234            if (noAlo)  xfrCmd[n].Opts  &=~cmdAlloc;
01235               else     xfrCmd[n].Opts  |= cmdAlloc;
01236            xfrCmd[n].TLimit = TLim;
01237           }
01238        n--;
01239       } while(i--);
01240 
01241 // All done
01242 //
01243    free(theCmd);
01244    return 0;
01245 }
01246 
01247 /******************************************************************************/
01248 
01249 int XrdFrmConfig::xcopy(int &TLim)
01250 {
01251    char *val;
01252 
01253    if (!(val = cFile->GetWord()) || !*val)
01254       {Say.Emsg("Config", "copy command timeout not specified"); return 0;}
01255    if (XrdOuca2x::a2tm(Say,"copy command timeout", val, &TLim, 0)) return 0;
01256    return 1;
01257 }
01258 
01259 /******************************************************************************/
01260 /* Private:                        x c m a x                                  */
01261 /******************************************************************************/
01262 
01263 /* Function: copymax
01264 
01265    Purpose:  To parse the directive: copymax  <num>
01266 
01267              <num>     maximum number of simultaneous transfers
01268 
01269    Output: 0 upon success or !0 upon failure.
01270 */
01271 int XrdFrmConfig::xcmax()
01272 {   int xmax = 1;
01273     char *val;
01274 
01275     if (!(val = cFile->GetWord()))
01276        {Say.Emsg("Config", "maxio value not specified"); return 1;}
01277     if (XrdOuca2x::a2i(Say, "maxio", val, &xmax, 1)) return 1;
01278     xfrMax = xmax;
01279     return 0;
01280 }
01281 
01282   
01283 /******************************************************************************/
01284 /* Private:                        x d p o l                                  */
01285 /******************************************************************************/
01286   
01287 
01288 /* Function: xdpol
01289 
01290    Purpose:  To parse the directive: dirpolicy <sec>
01291 
01292              <sec>     number of seconds to hold an empty directory or the
01293                        word 'forever'.
01294 
01295    Output: 0 upon success or !0 upon failure.
01296 */
01297 int XrdFrmConfig::xdpol()
01298 {   int htm;
01299     char *val;
01300 
01301     if (!(val = cFile->GetWord()))
01302        {Say.Emsg("Config",  "dirpolicy hold time not specified"); return 1;}
01303     if (XrdOuca2x::a2tm(Say,"dirpolicy hold time", val, &htm, 0)) return 1;
01304     dirHold = htm;
01305     return 0;
01306 }
01307 
01308 /******************************************************************************/
01309 /* Private:                         x i t m                                   */
01310 /******************************************************************************/
01311 
01312 /* Function: xitm
01313 
01314    Purpose:  To parse the directive: xxxxtime <sec>
01315 
01316              <sec>     number of seconds applicable to the directive.
01317 
01318    Output: 0 upon success or !0 upon failure.
01319 */
01320 int XrdFrmConfig::xitm(const char *What, int &tDest)
01321 {   int itime;
01322     char *val;
01323 
01324     if (!(val = cFile->GetWord()))
01325        {Say.Emsg("Config", What, "not specified"); return 1;}
01326     if (XrdOuca2x::a2tm(Say, What, val, &itime)) return 1;
01327     tDest = itime;
01328     return 0;
01329 }
01330 
01331 /******************************************************************************/
01332 /*                                  x m o n                                   */
01333 /******************************************************************************/
01334 
01335 /* Function: xmon
01336 
01337    Purpose:  Parse directive: monitor [all] [mbuff <sz>] 
01338                                       [flush <sec>] [window <sec>]
01339                                       dest [Events] <host:port>
01340 
01341    Events: [files] [info] [io] [stage] [user] <host:port>
01342 
01343          all                enables monitoring for all connections.
01344          mbuff  <sz>        size of message buffer.
01345          flush  <sec>       time (seconds, M, H) between auto flushes.
01346          window <sec>       time (seconds, M, H) between timing marks.
01347          dest               specified routing information. Up to two dests
01348                             may be specified.
01349          files              only monitors file open/close events.
01350          info               monitors client appid and info requests.
01351          io                 monitors I/O requests, and files open/close events.
01352          stage              monitors file stage operations
01353          user               monitors user login and disconnect events.
01354          <host:port>        where monitor records are to be sentvia UDP.
01355 
01356    Output: 0 upon success or !0 upon failure. Ignored by master.
01357 */
01358 int XrdFrmConfig::xmon()
01359 {   char  *val, *cp, *monDest[2] = {0, 0};
01360     long long tempval;
01361     int i, monFlush=0, monMBval=0, monWWval=0, monMode[2] = {0, 0};
01362 
01363     while((val = cFile->GetWord()))
01364 
01365          {     if (!strcmp("all",  val)) {}
01366           else if (!strcmp("flush", val))
01367                 {if (!(val = cFile->GetWord()))
01368                     {Say.Emsg("Config", "monitor flush value not specified");
01369                      return 1;
01370                     }
01371                  if (XrdOuca2x::a2tm(Say,"monitor flush",val,
01372                                          &monFlush,1)) return 1;
01373                 }
01374           else if (!strcmp("mbuff",val))
01375                   {if (!(val = cFile->GetWord()))
01376                       {Say.Emsg("Config", "monitor mbuff value not specified");
01377                        return 1;
01378                       }
01379                    if (XrdOuca2x::a2sz(Say,"monitor mbuff", val,
01380                                            &tempval, 1024, 65536)) return 1;
01381                     monMBval = static_cast<int>(tempval);
01382                   }
01383           else if (!strcmp("window", val))
01384                 {if (!(val = cFile->GetWord()))
01385                     {Say.Emsg("Config", "monitor window value not specified");
01386                      return 1;
01387                     }
01388                  if (XrdOuca2x::a2tm(Say,"monitor window",val,
01389                                          &monWWval,1)) return 1;
01390                 }
01391           else break;
01392          }
01393 
01394     if (!val) {Say.Emsg("Config", "monitor dest not specified"); return 1;}
01395 
01396     for (i = 0; i < 2; i++)
01397         {if (strcmp("dest", val)) break;
01398          while((val = cFile->GetWord()))
01399                    if (!strcmp("files",val)
01400                    ||  !strcmp("info", val)
01401                    ||  !strcmp("io",   val)
01402                    ||  !strcmp("user", val)) {}
01403               else if (!strcmp("stage",val)) monMode[i] |=  XROOTD_MON_STAGE;
01404               else break;
01405           if (!val) {Say.Emsg("Config","monitor dest value not specified");
01406                      return 1;
01407                     }
01408           if (!(cp = index(val, (int)':')) || !atoi(cp+1))
01409              {Say.Emsg("Config","monitor dest port missing or invalid in",val);
01410               return 1;
01411              }
01412           monDest[i] = strdup(val);
01413          if (!(val = cFile->GetWord())) break;
01414         }
01415 
01416     if (val)
01417        {if (!strcmp("dest", val))
01418            Say.Emsg("Config", "Warning, a maximum of two dest values allowed.");
01419            else Say.Emsg("Config", "Warning, invalid monitor option", val);
01420        }
01421 
01422 // Make sure dests differ
01423 //
01424    if (monDest[0] && monDest[1] && !strcmp(monDest[0], monDest[1]))
01425       {Say.Emsg("Config", "Warning, monitor dests are identical.");
01426        monMode[0] |= monMode[1]; monMode[1] = 0;
01427        free(monDest[1]); monDest[1] = 0;
01428       }
01429 
01430 // Don't bother doing any more if staging is not enabled
01431 //
01432    if (!monMode[0] && !monMode[1]) return 0;
01433    monStage = 1;
01434 
01435 // Set the monitor defaults
01436 //
01437    XrdFrmMonitor::Defaults(monDest[0],monMode[0],monDest[1],monMode[1]);
01438    return 0;
01439 }
01440 
01441 /******************************************************************************/
01442 /* Private:                         x n m l                                   */
01443 /******************************************************************************/
01444 
01445 /* Function: xnml
01446 
01447    Purpose:  To parse the directive: namelib <path> [<parms>]
01448 
01449              <path>    the path of the filesystem library to be used.
01450              <parms>   optional parms to be passed
01451 
01452   Output: 0 upon success or !0 upon failure.
01453 */
01454 
01455 int XrdFrmConfig::xnml()
01456 {
01457     char *val, parms[1024];
01458 
01459 // Get the path
01460 //
01461    if (!(val = cFile->GetWord()) || !val[0])
01462       {Say.Emsg("Config", "namelib not specified"); return 1;}
01463 
01464 // Record the path
01465 //
01466    if (N2N_Lib) free(N2N_Lib);
01467    N2N_Lib = strdup(val);
01468 
01469 // Record any parms
01470 //
01471    if (!cFile->GetRest(parms, sizeof(parms)))
01472       {Say.Emsg("Config", "namelib parameters too long"); return 1;}
01473    if (N2N_Parms) free(N2N_Parms);
01474    N2N_Parms = (*parms ? strdup(parms) : 0);
01475    return 0;
01476 }
01477 
01478 /******************************************************************************/
01479 /* Private:                         x p o l                                   */
01480 /******************************************************************************/
01481 
01482 /* Function: xpol
01483 
01484    Purpose:  To parse the directive: policy {*|sname} {nopurge|min [max]] [opts]
01485 
01486              *         The default policy for all spaces.
01487 
01488              sname     The policy to apply for this space. Defaults apply for
01489                        unspecified values. To make sure the specified default
01490                        is used, the '*' entry must appear first.
01491 
01492              nopurge   Turns off purging.
01493 
01494              min%      Minimum free space; purge starts when less available.
01495                        Can be specified as a percentage (i.e., n%) or an
01496                        absolute size value (with k, m, g, t suffix).
01497                        Default: 5%
01498 
01499              max%      Maximum free space; purge stops  when more available.
01500                        Must be specified in the same units as min and must be
01501                        greater than min.
01502                        Default: min% + 2 or min * 1.2
01503 
01504        opts: hold <tm> Time to hold a file before it can be purged. The <tm>
01505                        can be a suffixed number or 'forever'.
01506                        Default: 20h (20*3600)s
01507 
01508              polprog   Invoke the policy program to do final determination.
01509 
01510 
01511    Output: 0 upon success or !0 upon failure.
01512 */
01513 int XrdFrmConfig::xpol()
01514 {
01515    Policy *pP = &dfltPolicy;
01516    char *val, sname[XrdOssSpace::minSNbsz];
01517    long long minP = dfltPolicy.minFree, maxP = dfltPolicy.maxFree;
01518    int       Hold = dfltPolicy.Hold, Ext = 0;
01519    struct purgeopts {const char *opname; int isTime; int *oploc;} pgopts[] =
01520       {
01521        {"polprog", -1, &Ext},
01522        {"hold",     1, &Hold}
01523       };
01524    int i, rc, numopts = sizeof(pgopts)/sizeof(struct purgeopts);
01525 
01526 // Get the space name
01527 //
01528    if (!(val = cFile->GetWord()))
01529       {Say.Emsg("Config", "space name not specified"); return 1;}
01530    if (strlen(val) >= sizeof(sname))
01531       {Say.Emsg("Config", "space name '", val, "' too long"); return 1;}
01532 
01533 // If we have an equal sign then an external policy is being defined
01534 //
01535    if (!strcmp("=", val)) return xpolprog();
01536    strcpy(sname, val);
01537 
01538 // The next item may be minimum percentage followed by a maximum percentage
01539 // Otherwise, it may be 'nopurge'.
01540 //
01541    if (    (val = cFile->GetWord()) && isdigit(*val))
01542       {if (    XrdOuca2x::a2sp(Say, "min free", val, &minP, 1)) return 1;
01543        if ((val = cFile->GetWord()) && isdigit(*val))
01544           {if (XrdOuca2x::a2sp(Say, "max free", val, &maxP, 1)) return 1;
01545            if ((minP < 0 && maxP >= 0) || (minP >= 0 && maxP < 0))
01546               {Say.Emsg("Config", "purge min/max may not differ in type.");
01547                return 1;
01548               }
01549            if (XRDABS(minP) >= XRDABS(maxP))
01550               {Say.Emsg("Config", "purge min must be < max value."); return 1;}
01551            val = cFile->GetWord();
01552           } else {
01553            if (minP < 0) maxP = (minP < -99 ? -100 : minP - 1);
01554               else       maxP = (minP * 120LL)/100LL;
01555           }
01556       } else if (val && !strcmp(val, "nopurge"))
01557                 {minP = maxP = 0;
01558                  if ((val = cFile->GetWord()))
01559                     {Say.Say("Config warning: ignoring extraneous policy option '",val,"'.");
01560                      val = 0;
01561                     }
01562                 }
01563 
01564 // Pick up the remining options
01565 //
01566    while(val)
01567         {for (i = 0; i < numopts; i++) if (!strcmp(val,pgopts[i].opname)) break;
01568          if (i >= numopts)
01569             {Say.Say("Config warning: ignoring invalid policy option '",val,"'.");
01570              val = cFile->GetWord();
01571              continue;
01572             }
01573          if (pgopts[i].isTime < 0) *(pgopts[i].oploc) = 1;
01574             else {if (!(val = cFile->GetWord()))
01575                      {Say.Emsg("Config", "policy", pgopts[i].opname,
01576                                          "argument not specified.");
01577                       return 1;
01578                      }
01579                   rc = (pgopts[i].isTime
01580                      ?         getTime(    "purge value",val,pgopts[i].oploc,0)
01581                      : XrdOuca2x::a2i (Say,"purge value",val,pgopts[i].oploc,0));
01582                   if (rc) return 1;
01583                  }
01584          val = cFile->GetWord();
01585         }
01586 
01587 // If an external policy applies, it must be present
01588 //
01589    if (Ext && !pProg)
01590       {Say.Emsg("Config", "External policy has not been pre-defined.");
01591        return 1;
01592       }
01593 
01594 // Add this policy definition
01595 //
01596    while(pP && strcmp(pP->Sname, sname)) pP = pP->Next;
01597    if (pP) {pP->minFree=minP; pP->maxFree=maxP; pP->Hold=Hold; pP->Ext=Ext;}
01598       else {pP = new Policy(sname, minP, maxP, Hold, Ext);
01599             pP->Next = dfltPolicy.Next; dfltPolicy.Next = pP;
01600            }
01601     return 0;
01602 }
01603 
01604 /******************************************************************************/
01605 /* Private:                     x p o l p r o g                               */
01606 /******************************************************************************/
01607   
01608 /* Function: xpolprog
01609 
01610    Purpose:  To parse the directive: policy = [vars] |<prog> [args]
01611 
01612    Where:
01613              =         Defines an external policy via a program, as follows:
01614 
01615              vars      The information to ship to the program via stdin:
01616                        atime   - access time
01617                        ctime   - create time
01618                        fname   - the filename itself
01619                        fsize   - file size
01620                        fspace  - free  space
01621                        mtime   - modify time
01622                        pfn     - physical file name
01623                        sname   - space name
01624                        tspace  - total space
01625 
01626              |<prog>   The name of the policy program to receive the info.
01627 
01628              args      Optional program arguments (substituted), up to 8.
01629 
01630    Output: 0 upon success or !0 upon failure.
01631 */
01632 int XrdFrmConfig::xpolprog()
01633 {
01634    char *val, pBuff[4096], *pbP = pBuff;
01635    struct polopts {const char *opname; int opval;} plopts[] =
01636       {
01637        {"atime",  PP_atime },
01638        {"ctime",  PP_ctime },
01639        {"fname",  PP_fname },
01640        {"fsize",  PP_fsize },
01641        {"fspace", PP_fspace},
01642        {"mtime",  PP_mtime },
01643        {"pfn",    PP_pfn   },
01644        {"sname",  PP_sname },
01645        {"tspace", PP_tspace},
01646        {"usage",  PP_usage}
01647       };
01648    int i, n, numopts = sizeof(plopts)/sizeof(struct polopts);
01649 
01650 // Get the first token
01651 //
01652    if (!(val = cFile->GetWord()))
01653       {Say.Emsg("Config", "policy program not specified"); return 1;}
01654    pVecNum = 0;
01655 
01656 // Pick up the remining options
01657 //
01658    while(val && *val != '|')
01659         {for (i = 0; i < numopts; i++) if (!strcmp(val,plopts[i].opname)) break;
01660          if (i >= numopts)
01661             {Say.Say("Config warning: ignoring invalid policy option '",val,"'.");
01662              val = cFile->GetWord();
01663              continue;
01664             }
01665          if (pVecNum >= pVecMax)
01666             {Say.Emsg("Config", "To many policy program variables specified.");
01667              return 1;
01668             }
01669          pVec[pVecNum++] = static_cast<char>(plopts[i].opval);
01670          val = cFile->GetWord();
01671         }
01672 
01673 // Pick up the program
01674 //
01675    if (val) val++;
01676    if (val && !(*val)) val = cFile->GetWord();
01677    if (!val)
01678       {Say.Emsg("Config", "policy program not specified."); return 1;}
01679    i = strlen(val);
01680    if (i >= (int)sizeof(pBuff)-8)
01681       {Say.Emsg("Config", "policy program name is too long."); return 1;}
01682    strcpy(pBuff, val); pbP = pBuff+i; *(pbP+1) = '\0';
01683 
01684 // Now get any optional arguments
01685 //
01686    n = sizeof(pBuff) - i - 1;
01687    if (!cFile->GetRest(pbP+1, n))
01688       {Say.Emsg("Config", "policy program args are too long."); return 1;}
01689    if (*(pbP+1)) *pbP = ' ';
01690 
01691 // Record the program
01692 //
01693    if (pProg) free(pProg);
01694    pProg = strdup(pBuff);
01695    return 0;
01696 }
01697 
01698 /******************************************************************************/
01699 /* Private:                        x q c h k                                  */
01700 /******************************************************************************/
01701 
01702 /* Function: xqchk
01703 
01704    Purpose:  To parse the directive: qcheck <sec> <path>
01705 
01706              <sec>     number of seconds between forced queue checks. This is
01707                        optional is <path> is specified.
01708              <path>    the absolute location of the queue directory.
01709 
01710    Output: 0 upon success or !0 upon failure.
01711 */
01712 int XrdFrmConfig::xqchk()
01713 {   int itime;
01714     char *val;
01715 
01716 // Get the next token, we must have one here
01717 //
01718    if (!(val = cFile->GetWord()))
01719       {Say.Emsg("Config", "qcheck time not specified"); return 1;}
01720 
01721 // If not a path, then it must be a time
01722 //
01723    if (*val != '/')
01724       {if (XrdOuca2x::a2tm(Say, "qcheck time", val, &itime)) return 1;
01725        WaitQChk = itime;
01726        if (!(val = cFile->GetWord())) return 0;
01727       }
01728 
01729 // The next token has to be an absolute path if it is present at all
01730 //
01731    if (*val != '/')
01732       {Say.Emsg("Config", "qcheck path not absolute"); return 1;}
01733    if (QPath) free(QPath);
01734    QPath = strdup(val);
01735    return 0;
01736 }
01737 
01738 /******************************************************************************/
01739 /*                                x s p a c e                                 */
01740 /******************************************************************************/
01741 
01742 /* Function: xspace
01743 
01744    Purpose:  To parse the directive: space <group> <path>
01745 
01746              <group>  logical group name for the filesystem.
01747              <path>   path to the filesystem.
01748 
01749    Output: 0 upon success or !0 upon failure.
01750 */
01751 
01752 int XrdFrmConfig::xspace(int isPrg, int isXA)
01753 {
01754    char *val, *pfxdir, *sfxdir;
01755    char grp[XrdOssSpace::minSNbsz], fn[MAXPATHLEN], dn[MAXNAMLEN];
01756    int i, k, rc, pfxln, cnum = 0;
01757    struct dirent *dp;
01758    struct stat buff;
01759    DIR *DFD;
01760 
01761    if (!(val = cFile->GetWord()))
01762       {Say.Emsg("Config", "space name not specified"); return 1;}
01763    if (strlen(val) >= (int)sizeof(grp))
01764       {Say.Emsg("Config","excessively long space name - ",val); return 1;}
01765    strcpy(grp, val);
01766 
01767    if (!(val = cFile->GetWord()))
01768       {Say.Emsg("Config", "path to space not specified"); return 1;}
01769 
01770    k = strlen(val);
01771    if (k >= (int)(sizeof(fn)-1) || val[0] != '/' || k < 2)
01772       {Say.Emsg("Config", "invalid space path - ", val); return 1;}
01773    strcpy(fn, val);
01774 
01775    if (!isXA && (val = cFile->GetWord()))
01776       {if (strcmp("xa", val))
01777           {Say.Emsg("Config","invalid cache option - ",val); return 1;}
01778           else isXA = 1;
01779       }
01780 
01781    if (fn[k-1] != '*')
01782       {for (i = k-1; i; i--) if (fn[i] != '/') break;
01783        fn[i+1] = '/'; fn[i+2] = '\0';
01784        xspaceBuild(grp, fn, isXA);
01785        return 0;
01786       }
01787 
01788    for (i = k-1; i; i--) if (fn[i] == '/') break;
01789    i++; strcpy(dn, &fn[i]); fn[i] = '\0';
01790    sfxdir = &fn[i]; pfxdir = dn; pfxln = strlen(dn)-1;
01791    if (!(DFD = opendir(fn)))
01792       {Say.Emsg("Config", errno, "open space directory", fn); return 1;}
01793 
01794    errno = 0;
01795    while((dp = readdir(DFD)))
01796         {if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")
01797          || (pfxln && strncmp(dp->d_name, pfxdir, pfxln)))
01798             continue;
01799          strcpy(sfxdir, dp->d_name);
01800          if (stat(fn, &buff)) break;
01801          if ((buff.st_mode & S_IFMT) == S_IFDIR)
01802             {val = sfxdir + strlen(sfxdir) - 1;
01803             if (*val++ != '/') {*val++ = '/'; *val = '\0';}
01804             xspaceBuild(grp, fn, isXA);
01805             cnum++;
01806             }
01807          errno = 0;
01808         }
01809 
01810    if ((rc = errno))
01811       Say.Emsg("Config", errno, "process space directory", fn);
01812       else if (!cnum) Say.Say("Config warning: no space directories found in ",val);
01813 
01814    closedir(DFD);
01815    return rc != 0;
01816 }
01817 
01818 void XrdFrmConfig::xspaceBuild(char *grp, char *fn, int isxa)
01819 {
01820    struct VPInfo *nP = VPList;
01821    XrdOucTList *tP;
01822 
01823    while(nP && strcmp(nP->Name, grp)) nP = nP->Next;
01824 
01825    if (!nP) VPList = nP = new VPInfo(grp, 0, VPList);
01826 
01827    tP = nP->Dir;
01828    while(tP && strcmp(tP->text, fn)) tP = tP->next;
01829    if (!tP) nP->Dir = new XrdOucTList(fn, isxa, nP->Dir);
01830 }
01831 
01832 /******************************************************************************/
01833 /*                                  x x f r                                   */
01834 /******************************************************************************/
01835   
01836 /* Function: xxfr
01837 
01838    Purpose:  To parse the directive: xfr [deny <sec>] [keep <sec>]
01839 
01840              deny      number of seconds that a fail file rejects a request
01841              keep      number of seconds to keep queued requests (ignored)
01842 
01843    Output: 0 upon success or !0 upon failure.
01844 */
01845 
01846 int XrdFrmConfig::xxfr()
01847 {
01848     char *val;
01849     int       htime = 3*60*60;
01850     int       haveparm = 0;
01851 
01852     while((val = cFile->GetWord()))        // deny | keep
01853          {     if (!strcmp("deny", val))
01854                   {if ((val = cFile->GetWord()))     // keep time
01855                       {if (XrdOuca2x::a2tm(Say,"xfr deny",val,&htime,0))
01856                           return 1;
01857                        FailHold = htime, haveparm=1;
01858                       }
01859                   }
01860           else if (!strcmp("keep", val))
01861                   {if ((val = cFile->GetWord()))     // keep time
01862                       {if (XrdOuca2x::a2tm(Say,"xfr keep",val,&htime,0))
01863                           return 1;
01864                        haveparm=1;
01865                       }
01866                   }
01867           else break;
01868          };
01869 
01870     if (!val)
01871       {if (haveparm)
01872           { return 0;
01873           }
01874         else
01875           {Say.Emsg("Config", "xfr parameter not specified");
01876             return 1;
01877           }
01878       }
01879 
01880     return 0;
01881 }

Generated on Tue Jul 5 14:46:35 2011 for ROOT_528-00b_version by  doxygen 1.5.1