XrdROOT.cxx

Go to the documentation of this file.
00001 // @(#)root/proofd:$Id: XrdROOT.cxx 35210 2010-09-08 15:29:28Z ganis $
00002 // Author: Gerardo Ganis  June 2007
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2005, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 //////////////////////////////////////////////////////////////////////////
00013 //                                                                      //
00014 // XrdROOT                                                              //
00015 //                                                                      //
00016 // Authors: G. Ganis, CERN, 2007                                        //
00017 //                                                                      //
00018 // Class describing a ROOT version                                      //
00019 //                                                                      //
00020 //////////////////////////////////////////////////////////////////////////
00021 #include "RConfigure.h"
00022 
00023 #include "XrdProofdPlatform.h"
00024 
00025 #include "XrdROOT.h"
00026 #include "XrdProofdManager.h"
00027 #include "XrdProofdProtocol.h"
00028 #include "XrdProofdProofServMgr.h"
00029 #include "Xrd/XrdScheduler.hh"
00030 #include "XrdOuc/XrdOucStream.hh"
00031 #include "XrdSys/XrdSysPriv.hh"
00032 #include "XrdSys/XrdSysLogger.hh"
00033 
00034 // Tracing
00035 #include "XrdProofdTrace.h"
00036 
00037 //__________________________________________________________________________
00038 XrdROOT::XrdROOT(const char *dir, const char *tag, const char *bindir,
00039                  const char *incdir, const char *libdir, const char *datadir)
00040 {
00041    // Constructor: validates 'dir', gets the version and defines the tag.
00042    XPDLOC(SMGR, "XrdROOT")
00043 
00044    fStatus = -1;
00045    fSrvProtVers = -1;
00046 
00047    // 'dir' must make sense
00048    if (!dir || strlen(dir) <= 0)
00049       return;
00050    if (tag && strlen(tag) > 0) {
00051       fExport = tag;
00052       fExport += " "; fExport += dir;
00053    } else
00054       fExport += dir;
00055    // ... and exist
00056    if (CheckDir(dir) != 0) return;
00057    fDir = dir;
00058 
00059    // Include dir
00060    fIncDir = incdir;
00061    if (!incdir || strlen(incdir) <= 0) {
00062       fIncDir = fDir;
00063       fIncDir += "/include";
00064    }
00065    if (CheckDir(fIncDir.c_str()) != 0) return;
00066 
00067    // Parse version info
00068    fRelease = "";
00069    fSvnRevision = -1;
00070    fVersionCode = -1;
00071    fVrsMajor = -1;
00072    fVrsMinor = -1;
00073    fVrsPatch = -1;
00074    if (ParseROOTVersionInfo() == -1) {
00075       TRACE(XERR, "unable to extract ROOT version information from path "<<fIncDir);
00076       return;
00077    }
00078 
00079    // Default tag is the version
00080    fTag = (!tag || strlen(tag) <= 0) ? fRelease : tag;
00081 
00082    // Lib dir
00083    fLibDir = libdir;
00084    if (!libdir || strlen(libdir) <= 0) {
00085       fLibDir = fDir;
00086       fLibDir += "/lib";
00087    }
00088    if (CheckDir(fLibDir.c_str()) != 0) return;
00089 
00090    // Bin dir
00091    fBinDir = bindir;
00092    if (!bindir || strlen(bindir) <= 0) {
00093       fBinDir = fDir;
00094       fBinDir += "/bin";
00095    }
00096    if (CheckDir(fBinDir.c_str()) != 0) return;
00097 
00098    // Data dir
00099    fDataDir = datadir;
00100    if (!datadir || strlen(datadir) <= 0) {
00101       fDataDir = fDir;
00102    }
00103    if (CheckDir(fDataDir.c_str()) != 0) return;
00104 
00105    // The application to be run
00106    fPrgmSrv = fBinDir;
00107    fPrgmSrv += "/proofserv";
00108 
00109    // Export string
00110    fExport = fTag;
00111    fExport += " "; fExport += fRelease;
00112    fExport += " "; fExport += dir;
00113 
00114    // First step OK
00115    fStatus = 0;
00116 }
00117 
00118 //__________________________________________________________________________
00119 int XrdROOT::CheckDir(const char *dir)
00120 {
00121    // Check if 'dir' exists
00122    // Return 0 on succes, -1 on failure
00123    XPDLOC(SMGR, "CheckDir")
00124 
00125    if (dir && strlen(dir) > 0) {
00126       // The path should exist and be statable
00127       struct stat st;
00128       if (stat(dir, &st) == -1) {
00129          TRACE(XERR, "unable to stat path "<<dir);
00130          return -1;
00131       }
00132       // ... and be a directory
00133       if (!S_ISDIR(st.st_mode)) {
00134          TRACE(XERR, "path "<<dir<<" is not a directory");
00135          return -1;
00136       }
00137       // Ok
00138       return 0;
00139    }
00140    TRACE(XERR, "path is undefined");
00141    return -1;
00142 }
00143 
00144 //__________________________________________________________________________
00145 void XrdROOT::SetValid(kXR_int16 vers)
00146 {
00147    // Set valid, save protocol and finalize the export string
00148 
00149    fStatus = 1;
00150 
00151    if (vers > 0) {
00152       // Cleanup export, if needed
00153       if (fSrvProtVers > 0) {
00154          XrdOucString vs(" ");
00155          vs += fSrvProtVers;
00156          fExport.replace(vs,XrdOucString(""));
00157       }
00158       fSrvProtVers = vers;
00159 
00160       // Finalize export string
00161       fExport += " ";
00162       fExport += (int)fSrvProtVers;
00163    }
00164 }
00165 
00166 //__________________________________________________________________________
00167 int XrdROOT::ParseROOTVersionInfo()
00168 {
00169    // Extract ROOT version information associated with 'dir'.
00170    XPDLOC(SMGR, "ParseROOTVersionInfo")
00171 
00172    int rc = -1;
00173 
00174    XrdOucString versfile = fIncDir;
00175    versfile += "/RVersion.h";
00176 
00177    // Open file
00178    FILE *fv = fopen(versfile.c_str(), "r");
00179    if (!fv) {
00180       TRACE(XERR, "unable to open "<<versfile);
00181       return rc;
00182    }
00183 
00184    // Reset the related variables
00185    fRelease = "";
00186    fSvnRevision = -1;
00187    fVersionCode = -1;
00188    fVrsMajor = -1;
00189    fVrsMinor = -1;
00190    fVrsPatch = -1;
00191 
00192    // Read the file
00193    char *pv = 0;
00194    XrdOucString tkn;
00195    char line[1024];
00196    while (fgets(line, sizeof(line), fv)) {
00197       if (fRelease.length() <= 0 && (pv = (char *) strstr(line, "ROOT_RELEASE"))) {
00198          if (line[strlen(line)-1] == '\n')
00199             line[strlen(line)-1] = 0;
00200          pv += strlen("ROOT_RELEASE") + 1;
00201          fRelease = pv;
00202          fRelease.replace("\"","");
00203       } else if ((pv = (char *) strstr(line, "ROOT_SVN_REVISION"))) {
00204          if (line[strlen(line)-1] == '\n')
00205             line[strlen(line)-1] = 0;
00206          sscanf(pv, "ROOT_SVN_REVISION %d", &fSvnRevision);
00207       } else if ((pv = (char *) strstr(line, "ROOT_VERSION_CODE"))) {
00208          if (line[strlen(line)-1] == '\n')
00209             line[strlen(line)-1] = 0;
00210          sscanf(pv, "ROOT_VERSION_CODE %d", &fVersionCode);
00211       }
00212    }
00213 
00214    // Close the file
00215    fclose(fv);
00216 
00217    // Version code must be there
00218    if (fVersionCode < 0) {
00219       TRACE(XERR, "incomplete info found in "<<versfile<<": version code missing or bad: "<<fVersionCode);
00220       return rc;
00221    }
00222 
00223    // Release tag must be there and in the right format
00224    if (fRelease.length() <= 0 ||
00225        XrdROOT::ParseReleaseString(fRelease.c_str(), fVrsMajor, fVrsMinor, fVrsPatch) < 0) {
00226       TRACE(XERR, "incomplete info found in "<<versfile<<": release tag missing or bad: "<<fRelease);
00227       return rc;
00228    }
00229 
00230    // Done
00231    return 0;
00232 }
00233 
00234 //__________________________________________________________________________
00235 int XrdROOT::GetVersionCode(const char *release)
00236 {
00237    // Translate 'release' into a version code integer following the rules
00238    // in $ROOTSYS/include/RVersion.h.
00239    // 'release' must be in the format 'M.N/PP<something else>', e.g. 5.20/04-cms
00240 
00241    int maj, min, patch;
00242    if (XrdROOT::ParseReleaseString(release, maj, min, patch) < 0) return -1;
00243    return XrdROOT::GetVersionCode(maj, min, patch);
00244 }
00245 
00246 //__________________________________________________________________________
00247 int XrdROOT::GetVersionCode(int maj, int min, int patch)
00248 {
00249    // Translate 'release' into a version code integer following the rules
00250    // in $ROOTSYS/include/RVersion.h
00251 
00252    return ((maj << 16) + (min << 8) + patch);
00253 }
00254 
00255 //__________________________________________________________________________
00256 int XrdROOT::ParseReleaseString(const char *release,
00257                                 int &maj, int &min, int &patch)
00258 {
00259    // Extract from 'release' its major, minor and patch numerical components;
00260    // 'release' must be in the format 'M.N/PP<something else>', e.g. 5.20/04-cms;
00261    // the part <something else> is ignored.
00262 
00263    if (!release || strlen(release) <= 0) return -1;
00264 
00265    XrdOucString rel(release, 7);
00266    rel.replace(".", " ");
00267    rel.replace("/", " ");
00268 
00269    sscanf(rel.c_str(), "%d %d %d", &maj, &min, &patch);
00270    return 0;
00271 }
00272 
00273 //
00274 // Manager
00275 
00276 //______________________________________________________________________________
00277 XrdROOTMgr::XrdROOTMgr(XrdProofdManager *mgr,
00278                        XrdProtocol_Config *pi, XrdSysError *e)
00279           : XrdProofdConfig(pi->ConfigFN, e)
00280 {
00281    // Constructor
00282    fMgr = mgr;
00283    fLogger = pi->eDest->logger();
00284    fROOT.clear();
00285 
00286    // Configuration directives
00287    RegisterDirectives();
00288 }
00289 
00290 //__________________________________________________________________________
00291 void XrdROOTMgr::SetLogDir(const char *dir)
00292 {
00293    // Set the log dir
00294    XPDLOC(SMGR, "ROOTMgr::SetLogDir")
00295 
00296    if (fMgr && dir && strlen(dir)) {
00297       // MAke sure that the directory to store logs from validation exists
00298       XPDFORM(fLogDir, "%s/rootsysvalidation", dir);
00299       XrdProofUI ui;
00300       XrdProofdAux::GetUserInfo(fMgr->EffectiveUser(), ui);
00301       if (XrdProofdAux::AssertDir(fLogDir.c_str(), ui, fMgr->ChangeOwn()) != 0) {
00302          XPDERR("unable to assert the rootsys log validation path: "<<fLogDir);
00303          fLogDir = "";
00304       } else {
00305          TRACE(ALL,"rootsys log validation path: "<<fLogDir);
00306       }
00307    }
00308 }
00309 
00310 //__________________________________________________________________________
00311 int XrdROOTMgr::Config(bool rcf)
00312 {
00313    // Run configuration and parse the entered config directives.
00314    // Return 0 on success, -1 on error
00315    XPDLOC(SMGR, "ROOTMgr::Config")
00316 
00317    // Run first the configurator
00318    if (XrdProofdConfig::Config(rcf) != 0) {
00319       TRACE(XERR, "problems parsing file ");
00320       return -1;
00321    }
00322 
00323    XrdOucString msg;
00324    msg = (rcf) ? "re-configuring" : "configuring";
00325    TRACE(ALL, msg);
00326 
00327    // ROOT dirs
00328    if (rcf) {
00329       // Remove parked ROOT sys entries
00330       std::list<XrdROOT *>::iterator tri;
00331       if (fROOT.size() > 0) {
00332          for (tri = fROOT.begin(); tri != fROOT.end();) {
00333             if ((*tri)->IsParked()) {
00334                delete (*tri);
00335                tri = fROOT.erase(tri);
00336             } else {
00337                tri++;
00338             }
00339          }
00340       }
00341    } else {
00342       // Check the ROOT dirs
00343       if (fROOT.size() <= 0) {
00344 #ifdef R__HAVE_CONFIG
00345          XrdOucString dir(ROOTPREFIX), bd(ROOTBINDIR), ld(ROOTLIBDIR),
00346                       id(ROOTINCDIR), dd(ROOTDATADIR);
00347 #else
00348          XrdOucString dir(getenv("ROOTSYS")), bd, ld, id, dd;
00349 #endif
00350          // None defined: use ROOTSYS as default, if any; otherwise we fail
00351          if (dir.length() > 0) {
00352             XrdROOT *rootc = new XrdROOT(dir.c_str(), "",
00353                                          bd.c_str(), id.c_str(), ld.c_str(), dd.c_str());
00354             if (Validate(rootc, fMgr->Sched()) == 0) {
00355                XPDFORM(msg, "ROOT dist: '%s' validated", rootc->Export());
00356                fROOT.push_back(rootc);
00357                TRACE(ALL, msg);
00358                XrdOucString mnp;
00359                XPDFORM(mnp, "ROOT version details: svn: %d, code: %d, {mnp} = {%d,%d,%d}",
00360                             rootc->SvnRevision(), rootc->VersionCode(), rootc->VrsMajor(),
00361                             rootc->VrsMinor(), rootc->VrsPatch());
00362                TRACE(ALL, mnp);
00363             } else {
00364                XPDFORM(msg, "ROOT dist: '%s' could not be validated", rootc->Export());
00365                TRACE(XERR, msg);
00366             }
00367          }
00368          if (fROOT.size() <= 0) {
00369             TRACE(XERR, "no ROOT dir defined; ROOTSYS location missing - unloading");
00370             return -1;
00371          }
00372       }
00373    }
00374 
00375    // Done
00376    return 0;
00377 }
00378 
00379 //__________________________________________________________________________
00380 void XrdROOTMgr::RegisterDirectives()
00381 {
00382    // Register directives for configuration
00383 
00384    Register("rootsys", new XrdProofdDirective("rootsys", this, &DoDirectiveClass));
00385 }
00386 
00387 //______________________________________________________________________________
00388 int XrdROOTMgr::DoDirective(XrdProofdDirective *d,
00389                             char *val, XrdOucStream *cfg, bool rcf)
00390 {
00391    // Update the priorities of the active sessions.
00392    XPDLOC(SMGR, "ROOTMgr::DoDirective")
00393 
00394    if (!d)
00395       // undefined inputs
00396       return -1;
00397 
00398    if (d->fName == "rootsys") {
00399       return DoDirectiveRootSys(val, cfg, rcf);
00400    }
00401    TRACE(XERR, "unknown directive: "<<d->fName);
00402    return -1;
00403 }
00404 
00405 //______________________________________________________________________________
00406 int XrdROOTMgr::DoDirectiveRootSys(char *val, XrdOucStream *cfg, bool)
00407 {
00408    // Process 'rootsys' directive
00409    XPDLOC(SMGR, "ROOTMgr::DoDirectiveRootSys")
00410 
00411    if (!val || !cfg)
00412       // undefined inputs
00413       return -1;
00414 
00415    // Two tokens may be meaningful
00416    XrdOucString dir = val;
00417    val = cfg->GetWord();
00418    XrdOucString tag = val;
00419    bool ok = 1;
00420    if (tag == "if") {
00421       tag = "";
00422       // Conditional
00423       cfg->RetToken();
00424       ok = (XrdProofdAux::CheckIf(cfg, fMgr->Host()) > 0) ? 1 : 0;
00425    }
00426    if (ok) {
00427       // Check for additional info in the form: bindir incdir libdir datadir
00428       XrdOucString a[4];
00429       int i = 0;
00430       if (tag.length() > 0) {
00431          while ((val = cfg->GetWord())) { a[i++] = val; }
00432       }
00433       XrdROOT *rootc = new XrdROOT(dir.c_str(), tag.c_str(), a[0].c_str(),
00434                                    a[1].c_str(), a[2].c_str(), a[3].c_str());
00435       // Check if already validated
00436       std::list<XrdROOT *>::iterator ori;
00437       for (ori = fROOT.begin(); ori != fROOT.end(); ori++) {
00438          if ((*ori)->Match(rootc->Dir(), rootc->Tag())) {
00439             if ((*ori)->IsParked()) {
00440                (*ori)->SetValid();
00441                SafeDelete(rootc);
00442                break;
00443             }
00444          }
00445       }
00446       // If not, try validation
00447       if (rootc) {
00448          if (Validate(rootc, fMgr->Sched()) == 0) {
00449             TRACE(REQ, "validation OK for: "<<rootc->Export());
00450             XrdOucString mnp;
00451             XPDFORM(mnp, "version details: svn: %d, code: %d, {mnp} = {%d,%d,%d}",
00452                          rootc->SvnRevision(), rootc->VersionCode(), rootc->VrsMajor(),
00453                          rootc->VrsMinor(), rootc->VrsPatch());
00454             TRACE(REQ, mnp);
00455             // Add to the list
00456             fROOT.push_back(rootc);
00457          } else {
00458             TRACE(XERR, "could not validate "<<rootc->Export());
00459             SafeDelete(rootc);
00460          }
00461       }
00462    }
00463    return 0;
00464 }
00465 
00466 //__________________________________________________________________________
00467 int XrdROOTMgr::Validate(XrdROOT *r, XrdScheduler *sched)
00468 {
00469    // Start a trial server application to test forking and get the version
00470    // of the protocol run by the PROOF server.
00471    // Return 0 if everything goes well, -1 in case of any error.
00472    XPDLOC(SMGR, "ROOTMgr::Validate")
00473 
00474    TRACE(REQ, "forking test and protocol retrieval");
00475 
00476    if (r->IsInvalid()) {
00477       // Cannot be validated
00478       TRACE(XERR, "invalid instance - cannot be validated");
00479       return -1;
00480    }
00481 
00482    // Make sure the application path has been defined
00483    if (!r->PrgmSrv() || strlen(r->PrgmSrv()) <= 0) {
00484       TRACE(XERR, "path to PROOF server application undefined - exit");
00485       return -1;
00486    }
00487 
00488    // Make sure the scheduler is defined
00489    if (!sched) {
00490       TRACE(XERR, "scheduler undefined - exit");
00491       return -1;
00492    }
00493 
00494    // Pipe to communicate the protocol number
00495    int fp[2];
00496    if (pipe(fp) != 0) {
00497       TRACE(XERR, "PROOT protocol number communication");
00498       return -1;
00499    }
00500 
00501    // Debug flag
00502    bool debug = 0;
00503    if (TRACING(DBG)) debug = 1;
00504 
00505    // Log the attemp into this file
00506    XrdOucString logfile, rootrc;
00507    if (fLogDir.length() > 0) {
00508       XrdOucString tag(r->Tag());
00509       tag.replace("/","-");
00510       XPDFORM(logfile, "%s/root.%s.log", fLogDir.c_str(), tag.c_str());
00511       if (debug) {
00512          XPDFORM(rootrc, "%s/root.%s.rootrc", fLogDir.c_str(), tag.c_str());
00513       }
00514    }
00515 
00516    // Fork a test agent process to handle this session
00517    TRACE(FORK,"XrdROOTMgr::Validate: forking external proofsrv");
00518    int pid = -1;
00519    if (!(pid = sched->Fork("proofsrv"))) {
00520 
00521       if (logfile.length() > 0 && fLogger) {
00522          // Log to the session log file from now on
00523          fLogger->Bind(logfile.c_str());
00524          // Transfer the info to proofserv
00525          char *ev = new char[strlen("ROOTPROOFLOGFILE=") + logfile.length() + 2];
00526          sprintf(ev, "ROOTPROOFLOGFILE=%s", logfile.c_str());
00527          putenv(ev);
00528          if (debug && rootrc.length() > 0) {
00529             // Create .rootrc
00530             FILE *frc = fopen(rootrc.c_str(),"w");
00531             if (frc) {
00532                fprintf(frc, "Proof.DebugLevel: 1\n");
00533                fclose(frc);
00534             }
00535             // Transfer the info to proofserv
00536             ev = new char[strlen("ROOTRCFILE=") + rootrc.length() + 2];
00537             sprintf(ev, "ROOTRCFILE=%s", rootrc.c_str());
00538             putenv(ev);
00539          }
00540       }
00541 
00542       char *argvv[6] = {0};
00543 
00544       // start server
00545       argvv[0] = (char *)r->PrgmSrv();
00546       argvv[1] = (char *)"proofserv";
00547       argvv[2] = (char *)"xpd";
00548       argvv[3] = (char *)"test";
00549       if (debug) {
00550          argvv[4] = (char *)"1";
00551          argvv[5] = 0;
00552       } else {
00553          argvv[4] = 0;
00554          argvv[5] = 0;
00555       }
00556 
00557       // Set basic environment for proofserv
00558       if (XrdProofdProofServMgr::SetProofServEnv(fMgr, r) != 0) {
00559          TRACE(XERR, " SetProofServEnv did not return OK - EXIT");
00560          exit(1);
00561       }
00562 
00563       // Set Open socket
00564       char *ev = new char[25];
00565       sprintf(ev, "ROOTOPENSOCK=%d", fp[1]);
00566       putenv(ev);
00567 
00568       // Prepare for execution: we need to acquire the identity of
00569       // a normal user
00570       if (!getuid()) {
00571          XrdProofUI ui;
00572          if (XrdProofdAux::GetUserInfo(geteuid(), ui) != 0) {
00573             TRACE(XERR, "could not get info for user-id: "<<geteuid());
00574             exit(1);
00575          }
00576 
00577          // acquire permanently target user privileges
00578          if (XrdSysPriv::ChangePerm((uid_t)ui.fUid, (gid_t)ui.fGid) != 0) {
00579             TRACE(XERR, "can't acquire "<<ui.fUser <<" identity");
00580             exit(1);
00581          }
00582 
00583       }
00584 
00585       // Run the program
00586       execv(r->PrgmSrv(), argvv);
00587 
00588       // We should not be here!!!
00589       TRACE(XERR, "returned from execv: bad, bad sign !!!");
00590       exit(1);
00591    }
00592 
00593    // parent process
00594    if (pid < 0) {
00595       TRACE(XERR, "forking failed - exit");
00596       close(fp[0]);
00597       close(fp[1]);
00598       return -1;
00599    }
00600 
00601    // now we wait for the callback to be (successfully) established
00602    TRACE(FORK, "test server launched: wait for protocol ");
00603 
00604    // Read protocol
00605    int proto = -1;
00606    struct pollfd fds_r;
00607    fds_r.fd = fp[0];
00608    fds_r.events = POLLIN;
00609    int pollRet = 0;
00610    // We wait for 60 secs max (30 x 2000 millisecs): this is enough to
00611    // cover possible delays due to heavy load
00612    int ntry = 30;
00613    while (pollRet == 0 && ntry--) {
00614       while ((pollRet = poll(&fds_r, 1, 2000)) < 0 &&
00615              (errno == EINTR)) { }
00616       if (pollRet == 0)
00617          TRACE(DBG, "receiving PROOF server protocol number: waiting 2 s ...");
00618    }
00619    if (pollRet > 0) {
00620       if (read(fp[0], &proto, sizeof(proto)) != sizeof(proto)) {
00621          TRACE(XERR, "problems receiving PROOF server protocol number");
00622          return -1;
00623       }
00624    } else {
00625       if (pollRet == 0) {
00626          TRACE(XERR, "timed-out receiving PROOF server protocol number");
00627       } else {
00628          TRACE(XERR, "failed to receive PROOF server protocol number");
00629       }
00630       return -1;
00631    }
00632 
00633    // Set valid, record protocol and update export string
00634    r->SetValid((kXR_int16) ntohl(proto));
00635 
00636    // Cleanup files
00637    if (logfile.length() > 0 && !debug) {
00638       if (unlink(logfile.c_str()) != 0) {
00639          TRACE(XERR, "problems unlinking "<<logfile<<"; errno: "<<errno);
00640       }
00641    }
00642    if (debug && rootrc.length() > 0 && unlink(rootrc.c_str()) != 0) {
00643       TRACE(XERR, "problems unlinking "<<rootrc<<"; errno: "<<errno);
00644    }
00645 
00646    // Cleanup
00647    close(fp[0]);
00648    close(fp[1]);
00649 
00650    // We are done
00651    return 0;
00652 }
00653 
00654 //______________________________________________________________________________
00655 XrdOucString XrdROOTMgr::ExportVersions(XrdROOT *def)
00656 {
00657    // Return a string describing the available versions, with the default
00658    // version 'def' markde with a '*'
00659 
00660    XrdOucString out;
00661 
00662    // Generic info about all known sessions
00663    std::list<XrdROOT *>::iterator ip;
00664    for (ip = fROOT.begin(); ip != fROOT.end(); ++ip) {
00665       // Flag the default one
00666       if (def == *ip)
00667          out += "  * ";
00668       else
00669          out += "    ";
00670       out += (*ip)->Export();
00671       out += "\n";
00672    }
00673 
00674    // Over
00675    return out;
00676 }
00677 
00678 //______________________________________________________________________________
00679 XrdROOT *XrdROOTMgr::GetVersion(const char *tag)
00680 {
00681    // Return pointer to the ROOT version corresponding to 'tag'
00682    // or 0 if not found.
00683 
00684    XrdROOT *r = 0;
00685 
00686    std::list<XrdROOT *>::iterator ip;
00687    for (ip = fROOT.begin(); ip != fROOT.end(); ++ip) {
00688       if ((*ip)->MatchTag(tag)) {
00689          r = (*ip);
00690          break;
00691       }
00692    }
00693 
00694    // Over
00695    return r;
00696 }

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