XrdCmsConfig.cc

Go to the documentation of this file.
00001 /******************************************************************************/
00002 /*                                                                            */
00003 /*                       X r d C m s C o n f i g . c c                        */
00004 /*                                                                            */
00005 /* (c) 2007 by the Board of Trustees of the Leland Stanford, Jr., University  */
00006 /*                            All Rights Reserved                             */
00007 /*   Produced by Andrew Hanushevsky for Stanford University under contract    */
00008 /*              DE-AC02-76-SFO0515 with the Department of Energy              */
00009 /******************************************************************************/
00010 
00011 //         $Id: XrdCmsConfig.cc 35287 2010-09-14 21:19:35Z ganis $
00012 
00013 // Original Version: 1.54 2007/08/30 00:42:37 abh
00014 
00015 const char *XrdCmsConfigCVSID = "$Id: XrdCmsConfig.cc 35287 2010-09-14 21:19:35Z ganis $";
00016 
00017 /*
00018    The routines in this file handle cmsd() initialization. They get the
00019    configuration values either from configuration file or XrdCmsconfig.h (in that
00020    order of precedence).
00021 
00022    These routines are thread-safe if compiled with:
00023    AIX: -D_THREAD_SAFE
00024    SUN: -D_REENTRANT
00025 */
00026   
00027 #include <unistd.h>
00028 #include <ctype.h>
00029 #include <fcntl.h>
00030 #include <strings.h>
00031 #include <stdio.h>
00032 #include <sys/param.h>
00033 #include <sys/resource.h>
00034 #include <sys/stat.h>
00035 #include <sys/types.h>
00036 #include <sys/un.h>
00037 #include <dirent.h>
00038 
00039 #include "../XrdVersion.hh"
00040 #include "Xrd/XrdScheduler.hh"
00041 
00042 #include "XrdCms/XrdCmsAdmin.hh"
00043 #include "XrdCms/XrdCmsCache.hh"
00044 #include "XrdCms/XrdCmsCluster.hh"
00045 #include "XrdCms/XrdCmsConfig.hh"
00046 #include "XrdCms/XrdCmsManager.hh"
00047 #include "XrdCms/XrdCmsManTree.hh"
00048 #include "XrdCms/XrdCmsMeter.hh"
00049 #include "XrdCms/XrdCmsNode.hh"
00050 #include "XrdCms/XrdCmsPrepare.hh"
00051 #include "XrdCms/XrdCmsPrepArgs.hh"
00052 #include "XrdCms/XrdCmsProtocol.hh"
00053 #include "XrdCms/XrdCmsRRQ.hh"
00054 #include "XrdCms/XrdCmsSecurity.hh"
00055 #include "XrdCms/XrdCmsState.hh"
00056 #include "XrdCms/XrdCmsSupervisor.hh"
00057 #include "XrdCms/XrdCmsTrace.hh"
00058 #include "XrdCms/XrdCmsXmi.hh"
00059 #include "XrdCms/XrdCmsXmiReq.hh"
00060 
00061 #include "XrdNet/XrdNetDNS.hh"
00062 #include "XrdNet/XrdNetOpts.hh"
00063 #include "XrdNet/XrdNetSecurity.hh"
00064 #include "XrdNet/XrdNetSocket.hh"
00065 
00066 #include "XrdOss/XrdOss.hh"
00067 
00068 #include "XrdOuc/XrdOuca2x.hh"
00069 #include "XrdOuc/XrdOucEnv.hh"
00070 #include "XrdSys/XrdSysError.hh"
00071 #include "XrdOuc/XrdOucExport.hh"
00072 #include "XrdOuc/XrdOucName2Name.hh"
00073 #include "XrdOuc/XrdOucProg.hh"
00074 #include "XrdOuc/XrdOucUtils.hh"
00075 
00076 #include "XrdSys/XrdSysHeaders.hh"
00077 #include "XrdSys/XrdSysPlatform.hh"
00078 #include "XrdSys/XrdSysPlugin.hh"
00079 #include "XrdSys/XrdSysPthread.hh"
00080 #include "XrdOuc/XrdOucStream.hh"
00081 #include "XrdSys/XrdSysTimer.hh"
00082 
00083 using namespace XrdCms;
00084 
00085 /******************************************************************************/
00086 /*                  C o m m a n d   L i n e   O p t i o n s                   */
00087 /******************************************************************************/
00088 /*
00089    cmsd [options] [configfn]
00090 
00091    options: [xopt] [-i] [-m] [-s] [-w]
00092 
00093 Where:
00094     xopt  Are Xrd processed options (some of which we use).
00095 
00096    -i     Immediate start-up (do not wait for a server connection).
00097 
00098    -m     function in manager mode.
00099 
00100    -s     Executes in server  mode.
00101 */
00102 
00103 /******************************************************************************/
00104 /*                        G l o b a l   O b j e c t s                         */
00105 /******************************************************************************/
00106 
00107        XrdCmsAdmin      XrdCms::Admin;
00108 
00109        XrdCmsConfig     XrdCms::Config;
00110 
00111        XrdSysError      XrdCms::Say(0, "");
00112 
00113        XrdOucTrace      XrdCms::Trace(&Say);
00114 
00115        XrdScheduler    *XrdCms::Sched = 0;
00116 
00117        XrdCmsXmi       *XrdCms::Xmi_Chmod  = 0;
00118        XrdCmsXmi       *XrdCms::Xmi_Load   = 0;
00119        XrdCmsXmi       *XrdCms::Xmi_Mkdir  = 0;
00120        XrdCmsXmi       *XrdCms::Xmi_Mkpath = 0;
00121        XrdCmsXmi       *XrdCms::Xmi_Prep   = 0;
00122        XrdCmsXmi       *XrdCms::Xmi_Rename = 0;
00123        XrdCmsXmi       *XrdCms::Xmi_Remdir = 0;
00124        XrdCmsXmi       *XrdCms::Xmi_Remove = 0;
00125        XrdCmsXmi       *XrdCms::Xmi_Select = 0;
00126        XrdCmsXmi       *XrdCms::Xmi_Space  = 0;
00127        XrdCmsXmi       *XrdCms::Xmi_Stat   = 0;
00128 
00129 /******************************************************************************/
00130 /*                S e c u r i t y   S y m b o l   T i e - I n                 */
00131 /******************************************************************************/
00132   
00133 // The following is a bit of a kludge. The client side will use the xrootd
00134 // security infrastructure if it exists. This is tipped off by the presence
00135 // of the following symbol being non-zero. On the server side, we have no
00136 // such symbol and need to provide one initialized to zero.
00137 //
00138        XrdSecProtocol *(*XrdXrootdSecGetProtocol)
00139                                           (const char             *hostname,
00140                                            const struct sockaddr  &netaddr,
00141                                            const XrdSecParameters &parms,
00142                                                  XrdOucErrInfo    *einfo)=0;
00143   
00144 /******************************************************************************/
00145 /*            E x t e r n a l   T h r e a d   I n t e r f a c e s             */
00146 /******************************************************************************/
00147 
00148 void *XrdCmsStartMonPerf(void *carg) { return Cluster.MonPerf(); }
00149 
00150 void *XrdCmsStartMonRefs(void *carg) { return Cluster.MonRefs(); }
00151 
00152 void *XrdCmsStartMonStat(void *carg) { return CmsState.Monitor(); }
00153 
00154 void *XrdCmsStartAdmin(void *carg)
00155       {return XrdCms::Admin.Start((XrdNetSocket *)carg);
00156       }
00157 
00158 void *XrdCmsStartAnote(void *carg)
00159       {XrdCmsAdmin Anote;
00160        return Anote.Notes((XrdNetSocket *)carg);
00161       }
00162 
00163 void *XrdCmsStartPreparing(void *carg)
00164       {XrdCmsPrepArgs::Process();
00165        return (void *)0;
00166       }
00167 
00168 void *XrdCmsStartSupervising(void *carg)
00169       {XrdCmsSupervisor::Start();
00170        return (void *)0;
00171       }
00172 
00173 /******************************************************************************/
00174 /*                               d e f i n e s                                */
00175 /******************************************************************************/
00176 
00177 #define TS_String(x,m) if (!strcmp(x,var)) {free(m); m = strdup(val); return 0;}
00178 
00179 #define TS_Xeq(x,m)    if (!strcmp(x,var)) return m(eDest, CFile);
00180 
00181 #define TS_Set(x,v)    if (!strcmp(x,var)) {v=1; CFile.Echo(); return 0;}
00182 
00183 #define TS_unSet(x,v)  if (!strcmp(x,var)) {v=0; CFile.Echo(); return 0;}
00184 
00185 /******************************************************************************/
00186 /*                            C o n f i g u r e 1                             */
00187 /******************************************************************************/
00188   
00189 int XrdCmsConfig::Configure1(int argc, char **argv, char *cfn)
00190 {
00191 /*
00192   Function: Establish phase 1 configuration at start up time.
00193 
00194   Input:    argc - argument count
00195             argv - argument vector
00196             cfn  - optional configuration file name
00197 
00198   Output:   0 upon success or !0 otherwise.
00199 */
00200    int NoGo = 0, immed = 0;
00201    char c, buff[512];
00202    extern int opterr, optopt;
00203 
00204 // Prohibit this program from executing as superuser
00205 //
00206    if (geteuid() == 0)
00207       {Say.Emsg("Config", "Security reasons prohibit cmsd running as "
00208                   "superuser; cmsd is terminating.");
00209        _exit(8);
00210       }
00211 
00212 // Process the options
00213 //
00214    opterr = 0; optind = 1;
00215    if (argc > 1 && '-' == *argv[1]) 
00216       while ((c=getopt(argc,argv,"imsw")) && ((unsigned char)c != 0xff))
00217      { switch(c)
00218        {
00219        case 'i': immed = 1;
00220                  break;
00221        case 'm': isManager = 1;
00222                  break;
00223        case 's': isServer = 1;
00224                  break;
00225        case 'w': immed = -1;   // Backward compatability only
00226                  break;
00227        default:  buff[0] = '-'; buff[1] = optopt; buff[2] = '\0';
00228                  Say.Say("Config warning: unrecognized option,",buff,", ignored.");
00229        }
00230      }
00231 
00232 // Bail if no configuration file specified
00233 //
00234    inArgv = argv; inArgc = argc;
00235    if ((!(ConfigFN = cfn) && !(ConfigFN = getenv("XrdCmsCONFIGFN")))
00236    ||  !*ConfigFN)
00237       {Say.Emsg("Config", "Required config file not specified.");
00238        Usage(1);
00239       }
00240 
00241 // Establish my instance name
00242 //
00243    sprintf(buff, "%s@%s", XrdOucUtils::InstName(myInsName), myName);
00244    myInstance = strdup(buff);
00245 
00246 // Print herald
00247 //
00248    Say.Say("++++++ ", myInstance, " phase 1 initialization started.");
00249 
00250 // If we don't know our role yet then we must find out before processing the
00251 // config file. This means a double scan, sigh.
00252 //
00253    if (!(isManager || isServer)) 
00254       if (!(NoGo |= ConfigProc(1)) && !(isManager || isServer))
00255          {Say.Say("Config warning: role not specified; manager role assumed.");
00256           isManager = -1;
00257          }
00258 
00259 // Process the configuration file
00260 //
00261    if (!NoGo) NoGo |= ConfigProc();
00262 
00263 // Override the wait/nowait from the command line
00264 //
00265    if (immed) doWait = (immed > 0 ? 0 : 1);
00266 
00267 // Determine the role
00268 //
00269    if (isManager < 0) isManager = 1;
00270    if (isPeer    < 0) isPeer    = 1;
00271    if (isProxy   < 0) isProxy   = 1;
00272    if (isServer  < 0) isServer  = 1;
00273 
00274 // Create a text description of our role for use in messages
00275 //
00276    if (!myRole)
00277       {      if (isPeer)                myRole = strdup("peer");
00278         else if (isProxy)               myRole = strdup("proxy");
00279         else if (isManager && isServer) myRole = strdup("Supervisor");
00280         else if (isManager)             myRole = strdup("manager");
00281         else                            myRole = strdup("server");
00282       }
00283 
00284 // For managers, make sure that we have a well designated port.
00285 // For servers or supervisors, force an ephemeral port to be used.
00286 //
00287    if (!NoGo)
00288       {if ((isManager && !isServer) || isPeer)
00289           {if (PortTCP <= 0)
00290               {Say.Emsg("Config","port for this", myRole, "not specified.");
00291                NoGo = 1;
00292               }
00293           }
00294           else PortTCP = 0;
00295       }
00296 
00297 // Determine how we ended and return status
00298 //
00299    sprintf(buff, " phase 1 %s initialization %s.", myRole,
00300                 (NoGo ? "failed" : "completed"));
00301    Say.Say("------ ", myInstance, buff);
00302    return NoGo;
00303 }
00304 
00305 /******************************************************************************/
00306 /*                            C o n f i g u r e 2                             */
00307 /******************************************************************************/
00308   
00309 int XrdCmsConfig::Configure2()
00310 {
00311 /*
00312   Function: Establish phase 2 configuration at start up time.
00313 
00314   Input:    None.
00315 
00316   Output:   0 upon success or !0 otherwise.
00317 */
00318    EPNAME("Configure2");
00319    int Who, NoGo = 0;
00320    char *p, buff[512];
00321 
00322 // Print herald
00323 //
00324    sprintf(buff, " phase 2 %s initialization started.", myRole);
00325    Say.Say("++++++ ", myInstance, buff);
00326 
00327 // Determine who we are. If we are a manager or supervisor start the file
00328 // location cache scrubber.
00329 //
00330    if (isManager) NoGo = !Cache.Init(cachelife, LUPDelay);
00331 
00332 // Issue warning if the adminpath resides in /tmp
00333 //
00334    if (!strncmp(AdminPath, "/tmp/", 5))
00335       Say.Say("Config warning: adminpath resides in /tmp and may be unstable!");
00336 
00337 
00338 // Establish the path to be used for admin functions
00339 //
00340    p = XrdOucUtils::genPath(AdminPath,XrdOucUtils::InstName(myInsName,0),".olb");
00341    free(AdminPath);
00342    AdminPath = p;
00343 
00344 // Setup the admin path (used in all roles)
00345 //
00346    if (!NoGo) NoGo = !(AdminSock = XrdNetSocket::Create(&Say, AdminPath,
00347                      (isManager|isPeer ? "olbd.nimda":"olbd.admin"),AdminMode));
00348 
00349 // Develop a stable unique identifier for this cmsd independent of the port
00350 //
00351    if (!NoGo && !(mySID = setupSid()))
00352       {Say.Emsg("cmsd", "Unable to generate system ID; too many managers.");
00353        NoGo = 1;
00354       } else {DEBUG("Global System Identification: " <<mySID);}
00355 
00356 // If we need a name library, load it now
00357 //
00358    if ((LocalRoot || RemotRoot) && ConfigN2N()) NoGo = 1;
00359 
00360 // Configure the OSS
00361 //
00362    if (!NoGo) NoGo = ConfigOSS();
00363 
00364 // Setup manager or server, as needed
00365 //
00366   if (!NoGo && isManager)              NoGo = setupManager();
00367   if (!NoGo && (isServer || ManList))  NoGo = setupServer();
00368 
00369 // If we are a solo peer then we have no servers and a lot of space and
00370 // connections don't matter. Only one connection matters for a meta-manager.
00371 // Servers, supervisors, and managers who have a meta manager must wait for
00372 // for the local data server to connect so port mapping occurs. Otherwise,
00373 // we indicate that it doesn't matter as the local server won't connect.
00374 //
00375    if (isPeer && isSolo) 
00376       {SUPCount = SUPLevel = 0; Meter.setVirtual(XrdCmsMeter::peerFS);}
00377       else if (isManager)
00378               {Meter.setVirtual(XrdCmsMeter::manFS);
00379                if (isMeta) {SUPCount = 1; SUPLevel = 0;}
00380                if (!ManList) CmsState.Update(XrdCmsState::FrontEnd, 1);
00381               }
00382     if (isManager) Who = (isServer ? -1 : 1);
00383        else        Who = 0;
00384     CmsState.Set(SUPCount, Who, AdminPath);
00385 
00386 // Create the pid file
00387 //
00388    if (!NoGo) NoGo |= PidFile();
00389 
00390 // Load the XMI plugin
00391 //
00392    if (!NoGo && XmiPath) NoGo = setupXmi();
00393 
00394 // Set the default scheduling options if they have not already been set
00395 //
00396    Sched->setParms(8, 200, 40, -1, 1);
00397 
00398 // All done, check for success or failure
00399 //
00400    sprintf(buff, " phase 2 %s initialization %s.", myRole,
00401                  (NoGo ? "failed" : "completed"));
00402    Say.Say("------ ", myInstance, buff);
00403 
00404 // The remainder of the configuration needs to be run in a separate thread
00405 //
00406    if (!NoGo) Sched->Schedule((XrdJob *)this);
00407 
00408 // All done
00409 //
00410    return NoGo;
00411 }
00412 
00413 /******************************************************************************/
00414 /*                             C o n f i g X e q                              */
00415 /******************************************************************************/
00416 
00417 int XrdCmsConfig::ConfigXeq(char *var, XrdOucStream &CFile, XrdSysError *eDest)
00418 {
00419    int dynamic;
00420 
00421    // Determine whether is is dynamic or not
00422    //
00423    if (eDest) dynamic = 1;
00424       else   {dynamic = 0; eDest = &Say;}
00425 
00426    // Process items
00427    //
00428    TS_Xeq("delay",         xdelay);  // Manager,     dynamic
00429    TS_Xeq("fxhold",        xfxhld);  // Manager,     dynamic
00430    TS_Xeq("ping",          xping);   // Manager,     dynamic
00431    TS_Xeq("sched",         xsched);  // Any,         dynamic
00432    TS_Xeq("space",         xspace);  // Any,         dynamic
00433    TS_Xeq("trace",         xtrace);  // Any,         dynamic
00434 
00435    if (!dynamic)
00436    {
00437    TS_Xeq("adminpath",     xapath);  // Any,     non-dynamic
00438    TS_Xeq("allow",         xallow);  // Manager, non-dynamic
00439    TS_Xeq("defaults",      xdefs);   // Server,  non-dynamic
00440    TS_Xeq("export",        xexpo);   // Any,     non-dynamic
00441    TS_Xeq("fsxeq",         xfsxq);   // Server,  non-dynamic
00442    TS_Xeq("localroot",     xlclrt);  // Any,     non-dynamic
00443    TS_Xeq("manager",       xmang);   // Server,  non-dynamic
00444    TS_Xeq("namelib",       xnml);    // Server,  non-dynamic
00445    TS_Xeq("osslib",        xolib);   // Any,     non-dynamic
00446    TS_Xeq("perf",          xperf);   // Server,  non-dynamic
00447    TS_Xeq("pidpath",       xpidf);   // Any,     non-dynamic
00448    TS_Xeq("prep",          xprep);   // Any,     non-dynamic
00449    TS_Xeq("prepmsg",       xprepm);  // Any,     non-dynamic
00450    TS_Xeq("remoteroot",    xrmtrt);  // Any,     non-dynamic
00451    TS_Xeq("role",          xrole);   // Server,  non-dynamic
00452    TS_Xeq("seclib",        xsecl);   // Server,  non-dynamic
00453    TS_Set("wait",          doWait);  // Server,  non-dynamic (backward compat)
00454    TS_unSet("nowait",      doWait);  // Server,  non-dynamic
00455    TS_Xeq("xmilib",        xxmi);    // Any,     non-dynamic
00456    }
00457 
00458    // The following are client directives that we will ignore
00459    //
00460    if (!strcmp(var, "conwait")
00461    ||  !strcmp(var, "request")) return 0;
00462 
00463    // No match found, complain.
00464    //
00465    eDest->Say("Config warning: ignoring unknown directive '", var, "'.");
00466    CFile.Echo();
00467    return 0;
00468 }
00469 
00470 /******************************************************************************/
00471 /*                                  D o I t                                   */
00472 /******************************************************************************/
00473   
00474 void XrdCmsConfig::DoIt()
00475 {
00476    XrdSysSemaphore SyncUp(0);
00477    XrdCmsProtocol *pP;
00478    XrdOucTList    *tp;
00479    pthread_t       tid;
00480    time_t          eTime = time(0);
00481    int             wTime;
00482 
00483 // Set doWait correctly. We only wait if we have to provide a data path. This
00484 // include server, supervisors, and managers who have a meta-manager, only.
00485 // Why? Because we never get a primary login if we are a mere manager.
00486 //
00487    if (isManager && !isServer && !ManList) doWait = 0;
00488 
00489 // Start the notification thread if we need to
00490 //
00491    if (AnoteSock)
00492       if (XrdSysThread::Run(&tid, XrdCmsStartAnote, (void *)AnoteSock,
00493                             0, "Notification handler"))
00494          Say.Emsg("cmsd", errno, "start notification handler");
00495 
00496 // Start the prepare handler
00497 //
00498    if (XrdSysThread::Run(&tid,XrdCmsStartPreparing,
00499                              (void *)0, 0, "Prep handler"))
00500       Say.Emsg("cmsd", errno, "start prep handler");
00501 
00502 // Start the supervisor subsystem
00503 //
00504    if (XrdCmsSupervisor::superOK)
00505       {if (XrdSysThread::Run(&tid,XrdCmsStartSupervising, 
00506                              (void *)0, 0, "supervisor"))
00507           {Say.Emsg("cmsd", errno, "start", myRole);
00508           return;
00509           }
00510       }
00511 
00512 // Start the admin thread if we need to, we will not continue until told
00513 // to do so by the admin interface.
00514 //
00515    if (AdminSock)
00516       {XrdCmsAdmin::setSync(&SyncUp);
00517        if (XrdSysThread::Run(&tid, XrdCmsStartAdmin, (void *)AdminSock,
00518                              0, "Admin traffic"))
00519           Say.Emsg("cmsd", errno, "start admin handler");
00520        SyncUp.Wait();
00521       }
00522 
00523 // Start the server subsystem. We check here to make sure we will not be
00524 // tying to connect to ourselves. This is possible if the manager and meta-
00525 // manager were defined to be the same and we are a manager. We would have
00526 // liked to screen this out earlier but port discovery prevents it.
00527 //
00528    if (isManager || isServer || isPeer)
00529       {tp = ManList;
00530        while(tp)
00531             {if (strcmp(tp->text, myName) || tp->val != PortTCP)
00532                 {pP = XrdCmsProtocol::Alloc(myRole, tp->text, tp->val);
00533                  Sched->Schedule((XrdJob *)pP);
00534                 } else {
00535                  char buff[512];
00536                  sprintf(buff, "%s:%d", tp->text, tp->val);
00537                  Say.Emsg("Config", "Circular connection to", buff, "ignored.");
00538                 }
00539              tp = tp->next;
00540             }
00541       }
00542 
00543 // Start state monitoring thread
00544 //
00545    if (XrdSysThread::Run(&tid, XrdCmsStartMonStat, (void *)0,
00546                                0, "State monitor"))
00547       {Say.Emsg("Config", errno, "create state monitor thread");
00548        return;
00549       }
00550 
00551 // If we are a manager then we must do a service enable after a service delay
00552 //
00553    if ((isManager || isPeer) && SRVDelay)
00554       {wTime = SRVDelay - static_cast<int>((time(0) - eTime));
00555        if (wTime > 0) XrdSysTimer::Wait(wTime*1000);
00556       }
00557 
00558 // All done
00559 //
00560    if (!SUPCount) CmsState.Update(XrdCmsState::Counts, 0, 0);
00561    CmsState.Enable();
00562    Say.Emsg("Config", myRole, "service enabled.");
00563 }
00564 
00565 /******************************************************************************/
00566 /*                          G e n L o c a l P a t h                           */
00567 /******************************************************************************/
00568   
00569 /* GenLocalPath() generates the path that a file will have in the local file
00570    system. The decision is made based on the user-given path (typically what 
00571    the user thinks is the local file system path). The output buffer where the 
00572    new path is placed must be at least XrdCmsMAX_PATH_LEN bytes long.
00573 */
00574 int XrdCmsConfig::GenLocalPath(const char *oldp, char *newp)
00575 {
00576     if (lcl_N2N) return -(lcl_N2N->lfn2pfn(oldp, newp, XrdCmsMAX_PATH_LEN));
00577     if (strlen(oldp) >= XrdCmsMAX_PATH_LEN) return -ENAMETOOLONG;
00578     strcpy(newp, oldp);
00579     return 0;
00580 }
00581   
00582 /******************************************************************************/
00583 /*                     P r i v a t e   F u n c t i o n s                      */
00584 /******************************************************************************/
00585 /******************************************************************************/
00586 /*                        C o n f i g D e f a u l t s                         */
00587 /******************************************************************************/
00588 
00589 void XrdCmsConfig::ConfigDefaults(void)
00590 {
00591 
00592 // Preset all variables with common defaults
00593 //
00594    myName   = (char *)"localhost"; // Correctly set in Configure()
00595    myDomain = 0;
00596    LUPDelay = 5;
00597    LUPHold  = 178;
00598    DRPDelay = 10*60;
00599    PSDelay  = 0;
00600    RWDelay  = 2;
00601    SRVDelay = 90;
00602    SUPCount = 1;
00603    SUPLevel = 80;
00604    SUPDelay = 15;
00605    SUSDelay = 30;
00606    MaxLoad  = 0x7fffffff;
00607    MsgTTL   = 7;
00608    PortTCP  = 0;
00609    P_cpu    = 0;
00610    P_fuzz   = 20;
00611    P_io     = 0;
00612    P_load   = 0;
00613    P_mem    = 0;
00614    P_pag    = 0;
00615    AskPerf  = 10;         // Every 10 pings
00616    AskPing  = 60;         // Every  1 minute
00617    MaxDelay = -1;
00618    LogPerf  = 10;         // Every 10 usage requests
00619    DiskMin  = 10240;      // 10GB*1024 (Min partition space) in MB
00620    DiskHWM  = 11264;      // 11GB*1024 (High Water Mark SUO) in MB
00621    DiskMinP = 2;
00622    DiskHWMP = 5;
00623    DiskAsk  = 12;         // 15 Seconds between space calibrations.
00624    DiskWT   = 0;          // Do not defer when out of space
00625    DiskSS   = 0;          // Not a staging server
00626    DiskOK   = 0;          // Does not have any disk
00627    myPaths  = (char *)""; // Default is 'r /'
00628    ConfigFN = 0;
00629    sched_RR = 0;
00630    isManager= 0;
00631    isMeta   = 0;
00632    isPeer   = 0;
00633    isSolo   = 0;
00634    isProxy  = 0;
00635    isServer = 0;
00636    N2N_Lib  = 0;
00637    N2N_Parms= 0;
00638    lcl_N2N  = 0;
00639    xeq_N2N  = 0;
00640    LocalRoot= 0;
00641    RemotRoot= 0;
00642    myInsName= 0;
00643    myRole    =0;
00644    ManList   =0;
00645    NanList   =0;
00646    mySID    = 0;
00647    perfint  = 3*60;
00648    perfpgm  = 0;
00649    AdminPath= strdup("/tmp/");
00650    AdminMode= 0700;
00651    AdminSock= 0;
00652    AnoteSock= 0;
00653    RedirSock= 0;
00654    pidPath  = strdup("/tmp");
00655    Police   = 0;
00656    cachelife= 8*60*60;
00657    pendplife=   60*60*24*7;
00658    DiskLinger=0;
00659    ProgCH   = 0;
00660    ProgMD   = 0;
00661    ProgMV   = 0;
00662    ProgRD   = 0;
00663    ProgRM   = 0;
00664    doWait   = 1;
00665    RefReset = 60*60;
00666    RefTurn  = 3*STMax*(DiskLinger+1);
00667    XmiPath     = 0;
00668    XmiParms    = 0;
00669    DirFlags    = 0;
00670    SecLib      = 0;
00671    ossLib      = 0;
00672    ossFS       = 0;
00673 }
00674   
00675 /******************************************************************************/
00676 /*                             C o n f i g N 2 N                              */
00677 /******************************************************************************/
00678 
00679 int XrdCmsConfig::ConfigN2N()
00680 {
00681    XrdSysPlugin    *myLib;
00682    XrdOucName2Name *(*ep)(XrdOucgetName2NameArgs);
00683 
00684 // If we have no library path then use the default method (this will always
00685 // succeed).
00686 //
00687    if (!N2N_Lib)
00688       {if (LocalRoot || (RemotRoot && XmiPath))
00689           {xeq_N2N = XrdOucgetName2Name(&Say,ConfigFN,"",LocalRoot,RemotRoot);
00690            if (LocalRoot) lcl_N2N = xeq_N2N;
00691           }
00692        PrepQ.setParms(xeq_N2N);
00693        return 0;
00694       }
00695 
00696 // Create a pluin object (we will throw this away without deletion because
00697 // the library must stay open but we never want to reference it again).
00698 //
00699    if (!(myLib = new XrdSysPlugin(&Say, N2N_Lib))) return 1;
00700 
00701 // Now get the entry point of the object creator
00702 //
00703    ep = (XrdOucName2Name *(*)(XrdOucgetName2NameArgs))(myLib->getPlugin("XrdOucgetName2Name"));
00704    if (!ep) return 1;
00705 
00706 // Get the Object now
00707 //
00708    lcl_N2N = ep(&Say,ConfigFN,(N2N_Parms ? N2N_Parms : ""),LocalRoot,RemotRoot);
00709    PrepQ.setParms(lcl_N2N);
00710    return lcl_N2N == 0;
00711 }
00712   
00713 /******************************************************************************/
00714 /*                             C o n f i g O S S                              */
00715 /******************************************************************************/
00716 
00717 int XrdCmsConfig::ConfigOSS()
00718 {
00719    extern XrdOss *XrdOssGetSS(XrdSysLogger *, const char *, const char *);
00720 
00721 // Set up environment for the OSS to keep it relevant for cmsd
00722 //
00723    XrdOucEnv::Export("XRDREDIRECT", "Q");
00724    XrdOucEnv::Export("XRDOSSTYPE",  "cms");
00725    XrdOucEnv::Export("XRDOSSCSCAN", "off");
00726 
00727 // Load and return result
00728 //
00729    return !(ossFS=XrdOssGetSS(Say.logger(),ConfigFN,ossLib));
00730 }
00731 
00732 /******************************************************************************/
00733 /*                            C o n f i g P r o c                             */
00734 /******************************************************************************/
00735   
00736 int XrdCmsConfig::ConfigProc(int getrole)
00737 {
00738   char *var;
00739   int  cfgFD, retc, NoGo = 0;
00740   XrdOucEnv myEnv;
00741   XrdOucStream CFile(&Say, getenv("XRDINSTANCE"), &myEnv, "=====> ");
00742 
00743 // Try to open the configuration file.
00744 //
00745    if ( (cfgFD = open(ConfigFN, O_RDONLY, 0)) < 0)
00746       {Say.Emsg("Config", errno, "open config file", ConfigFN);
00747        return 1;
00748       }
00749    CFile.Attach(cfgFD);
00750 
00751 // Turn off echoing if we are doing a pre-scan
00752 //
00753    if (getrole) CFile.SetEroute(0);
00754 
00755 // Now start reading records until eof.
00756 //
00757    while((var = CFile.GetMyFirstWord()))
00758         if (getrole)
00759            {if (!strcmp("all.role", var) || !strcmp("olb.role", var))
00760                if (xrole(&Say, CFile))
00761                   {CFile.SetEroute(&Say); CFile.Echo(); NoGo = 1;
00762                    CFile.SetEroute(0);
00763                   }
00764            }
00765            else if (!strncmp(var, "cms.", 4)
00766                 ||  !strncmp(var, "olb.", 4)      // Backward compatability
00767                 ||  !strcmp(var, "ofs.osslib")
00768                 ||  !strcmp(var, "oss.defaults")
00769                 ||  !strcmp(var, "oss.localroot")
00770                 ||  !strcmp(var, "oss.remoteroot")
00771                 ||  !strcmp(var, "oss.namelib")
00772                 ||  !strcmp(var, "all.adminpath")
00773                 ||  !strcmp(var, "all.export")
00774                 ||  !strcmp(var, "all.manager")
00775                 ||  !strcmp(var, "all.pidpath")
00776                 ||  !strcmp(var, "all.role")
00777                 ||  !strcmp(var, "all.seclib"))
00778                    {if (ConfigXeq(var+4, CFile, 0)) {CFile.Echo(); NoGo = 1;}}
00779                    else if (!strcmp(var, "oss.stagecmd")) DiskSS = 1;
00780 
00781 // Now check if any errors occured during file i/o
00782 //
00783    if ((retc = CFile.LastError()))
00784       NoGo = Say.Emsg("Config", retc, "read config file", ConfigFN);
00785    CFile.Close();
00786 
00787 // Merge Paths as needed
00788 //
00789    if (!getrole && ManList) NoGo |= MergeP();
00790 
00791 // Return final return code
00792 //
00793    return NoGo;
00794 }
00795  
00796 /******************************************************************************/
00797 /*                                i s E x e c                                 */
00798 /******************************************************************************/
00799   
00800 int XrdCmsConfig::isExec(XrdSysError *eDest, const char *ptype, char *prog)
00801 {
00802   char buff[512], pp, *mp = prog;
00803 
00804 // Isolate the program name
00805 //
00806    while(*mp && *mp != ' ') mp++;
00807    pp = *mp; *mp ='\0';
00808 
00809 // Make sure the program is executable by us
00810 //
00811    if (access(prog, X_OK))
00812       {sprintf(buff, "find %s execuatble", ptype);
00813        eDest->Emsg("Config", errno, buff, prog);
00814        *mp = pp;
00815        return 0;
00816       }
00817 
00818 // All is well
00819 //
00820    *mp = pp;
00821    return 1;
00822 }
00823 
00824 /******************************************************************************/
00825 /*                                M e r g e P                                 */
00826 /******************************************************************************/
00827   
00828 int XrdCmsConfig::MergeP()
00829 {
00830    XrdOucPList *plp = PexpList.First();
00831    XrdCmsPList *pp;
00832    XrdCmsPInfo opinfo, npinfo;
00833    const char *ptype;
00834    char *pbP;
00835    unsigned long long Opts;
00836    int pbLen = 0, NoGo = 0;
00837    npinfo.rovec = 1;
00838 
00839 // For each path in the export list merge it into the path list
00840 //
00841    while(plp)
00842         {Opts = plp->Flag();
00843          if (!(Opts & XRDEXP_LOCAL))
00844             {npinfo.rwvec = (Opts & (XRDEXP_GLBLRO | XRDEXP_NOTRW) ? 0 : 1);
00845              npinfo.ssvec = (Opts & XRDEXP_STAGE ? 1 : 0);
00846              if (!PathList.Add(plp->Path(), &npinfo))
00847                 Say.Emsg("Config","Ignoring duplicate export path",plp->Path());
00848                 else if (npinfo.ssvec) DiskSS = 1;
00849             }
00850           plp = plp->Next();
00851          }
00852 
00853 // Document what we will be declaring as available
00854 //
00855    if (!NoGo)
00856       {const char *Who = (isManager ? (isServer ? "manager:" : "meta-manager:")
00857                                     : "redirector:");
00858        Say.Say("The following paths are available to the ", Who);
00859        if (!(pp = PathList.First())) Say.Say("r  /");
00860         else while(pp)
00861              {ptype = pp->PType();
00862               Say.Say(ptype, (strlen(ptype) > 1 ? " " : "  "), pp->Path());
00863               pbLen += strlen(pp->Path())+8; pp = pp->Next();
00864              }
00865        Say.Say(" ");
00866       }
00867 
00868 // Now allocate a buffer and place all of the paths into that buffer to be
00869 // sent during the login phase.
00870 //
00871    if (pbLen != 0 && (pp = PathList.First()))
00872       {pbP = myPaths = (char *)malloc(pbLen);
00873        while(pp)
00874             {pbP += sprintf(pbP, "\n%s %s", pp->PType(), pp->Path());
00875              pp = pp->Next();
00876             }
00877        myPaths++;
00878       }
00879 
00880 // All done update the staging status (it's nostage by default)
00881 //
00882    if (DiskSS) CmsState.Update(XrdCmsState::Counts, 0, 1);
00883    return NoGo;
00884 }
00885 
00886 /******************************************************************************/
00887 /*                               P i d F i l e                                */
00888 /******************************************************************************/
00889   
00890 int XrdCmsConfig::PidFile()
00891 {
00892     int rc, xfd;
00893     const char *clID;
00894     char buff[1024];
00895     char pidFN[1200], *ppath=XrdOucUtils::genPath(pidPath,
00896                              XrdOucUtils::InstName(myInsName,0));
00897     const char *xop = 0;
00898 
00899     if ((rc = XrdOucUtils::makePath(ppath, XrdOucUtils::pathMode)))
00900        {Say.Emsg("Config", rc, "create pid file path", ppath);
00901         free(ppath);
00902         return 1;
00903        }
00904 
00905     if ((clID = index(mySID, ' '))) clID++;
00906        else clID = mySID;
00907 
00908          if (isManager && isServer)
00909             snprintf(pidFN, sizeof(pidFN), "%s/cmsd.super.pid", ppath);
00910     else if (isServer)
00911             snprintf(pidFN, sizeof(pidFN), "%s/cmsd.pid", ppath);
00912     else    snprintf(pidFN, sizeof(pidFN), "%s/cmsd.mangr.pid", ppath);
00913 
00914     if ((xfd = open(pidFN, O_WRONLY|O_CREAT|O_TRUNC,0644)) < 0) xop = "open";
00915        else {if ((write(xfd,buff,snprintf(buff,sizeof(buff),"%d",
00916                             static_cast<int>(getpid()))) < 0)
00917              || (LocalRoot && 
00918                            (write(xfd,(void *)"\n&pfx=",6)  < 0 ||
00919                             write(xfd,(void *)LocalRoot,strlen(LocalRoot)) < 0
00920                 )          )
00921              || (AdminPath && 
00922                            (write(xfd,(void *)"\n&ap=", 5)  < 0 ||
00923                             write(xfd,(void *)AdminPath,strlen(AdminPath)) < 0
00924                 )          )
00925              ||             write(xfd,(void *)"\n&cn=", 5)  < 0
00926              ||             write(xfd,(void *)clID,     strlen(clID))      < 0
00927                 ) xop = "write";
00928              close(xfd);
00929             }
00930 
00931      if (xop) Say.Emsg("Config", errno, xop, pidFN);
00932         else XrdOucEnv::Export("XRDCMSPIDFN", pidFN);
00933 
00934      free(ppath);
00935      return xop != 0;
00936 }
00937 
00938 /******************************************************************************/
00939 /*                          s e t u p M a n a g e r                           */
00940 /******************************************************************************/
00941   
00942 int XrdCmsConfig::setupManager()
00943 {
00944    pthread_t tid;
00945    int rc;
00946 
00947 // Setup supervisor mode if we are also a server
00948 //
00949    if (isServer && !XrdCmsSupervisor::Init(AdminPath, AdminMode)) return 1;
00950 
00951 // Compute the scheduling policy
00952 //
00953    sched_RR = (100 == P_fuzz) || !AskPerf
00954               || !(P_cpu || P_io || P_load || P_mem || P_pag);
00955    if (sched_RR)
00956       Say.Say("Config round robin scheduling in effect.");
00957 
00958 // Create statistical monitoring thread
00959 //
00960    if ((rc = XrdSysThread::Run(&tid, XrdCmsStartMonPerf, (void *)0,
00961                                0, "Performance monitor")))
00962       {Say.Emsg("Config", rc, "create perf monitor thread");
00963        return 1;
00964       }
00965 
00966 // Create reference monitoring thread
00967 //
00968    RefTurn  = 3*STMax*(DiskLinger+1);
00969    if (RefReset)
00970       {if ((rc = XrdSysThread::Run(&tid, XrdCmsStartMonRefs, (void *)0,
00971                                    0, "Refcount monitor")))
00972           {Say.Emsg("Config", rc, "create refcount monitor thread");
00973            return 1;
00974           }
00975       }
00976 
00977 // Initialize the fast redirect queue
00978 //
00979    RRQ.Init(LUPHold, LUPDelay);
00980 
00981 // Initialize the security interface
00982 //
00983    if (SecLib && !XrdCmsSecurity::Configure(SecLib, ConfigFN)) return 1;
00984 
00985 // All done
00986 //
00987    return 0;
00988 }
00989 
00990 /******************************************************************************/
00991 /*                           s e t u p S e r v e r                            */
00992 /******************************************************************************/
00993   
00994 int XrdCmsConfig::setupServer()
00995 {
00996    XrdOucTList *tp;
00997    int n = 0;
00998 
00999 // Make sure we have enough info to be a server
01000 //
01001    if (!ManList)
01002       {Say.Emsg("Config", "Manager node not specified for", myRole, "role");
01003        return 1;
01004       }
01005 
01006 // Count the number of managers we have and tell ManTree about it
01007 //
01008    tp = ManList;
01009    while(tp) {n++; tp = tp->next;}
01010    if (n > XrdCmsManager::MTMax)
01011       {Say.Emsg("Config", "Too many managers have been specified"); return 1;}
01012    ManTree.setMaxCon(n);
01013 
01014 // Calculate overload delay time
01015 //
01016    if (MaxDelay < 0) MaxDelay = AskPerf*AskPing+30;
01017    if (DiskWT   < 0) DiskWT   = AskPerf*AskPing+30;
01018 
01019 // Setup notification path
01020 //
01021    if (!(AnoteSock = XrdNetSocket::Create(&Say, AdminPath,
01022                              (isManager|isPeer ? "olbd.seton":"olbd.notes"),
01023                              AdminMode, XRDNET_UDPSOCKET))) return 1;
01024 
01025 // We have data only if we are a pure data server (the default is noData)
01026 // If we have no data, then we are done (the rest is for pure servers)
01027 //
01028    if (isManager || isPeer || isProxy) return 0;
01029    DiskOK = 1; SUPCount = 0; SUPLevel = 0;
01030 
01031 // If this is a staging server then set up the Prepq object
01032 //
01033    if (DiskSS) PrepQ.Reset(myInsName, AdminPath, AdminMode);
01034 
01035 // Setup file system metering (skip it for peers)
01036 //
01037    Meter.Init();
01038    if (perfpgm && Meter.Monitor(perfpgm, perfint))
01039       Say.Say("Config warning: load based scheduling disabled.");
01040 
01041 // All done
01042 //
01043    return 0;
01044 }
01045 
01046 /******************************************************************************/
01047 /*                              s e t u p S i d                               */
01048 /******************************************************************************/
01049   
01050 char *XrdCmsConfig::setupSid()
01051 {
01052    XrdOucTList *tp = (NanList ? NanList : ManList);
01053    char sfx;
01054 
01055 // Determine what type of role we are playing
01056 //
01057    if (isManager && isServer) sfx = 'u';
01058       else sfx = (isManager ? 'm' : 's');
01059 
01060 // Generate the system ID and set the cluster ID
01061 //
01062    return XrdCmsSecurity::setSystemID(tp, myInsName, myName, sfx);
01063 }
01064 
01065 /******************************************************************************/
01066 /*                              s e t u p X m i                               */
01067 /******************************************************************************/
01068   
01069 int XrdCmsConfig::setupXmi()
01070 {
01071    EPNAME("setupXmi");
01072    static XrdCmsXmiEnv XmiEnv;
01073    XrdSysPlugin       *xmiLib;
01074    XrdCmsXmi          *(*ep)(int, char **, XrdCmsXmiEnv *);
01075    unsigned int isNormal, isDirect;
01076    XrdCmsXmi          *XMI, *myXMI;
01077    const char         *theMode;
01078    int i;
01079 
01080    struct {unsigned int   theMask;
01081            XrdCmsXmi    **theAddr;
01082            const char    *theName;} XmiTab[] =
01083           {{XMI_CHMOD,  &Xmi_Chmod,  "chmod"},
01084            {XMI_LOAD,   &Xmi_Load,   "load"},
01085            {XMI_MKDIR,  &Xmi_Mkdir,  "mkdir"},
01086            {XMI_MKPATH, &Xmi_Mkpath, "mkpath"},
01087            {XMI_PREP,   &Xmi_Prep,   "prep"},
01088            {XMI_RENAME, &Xmi_Rename, "rename"},
01089            {XMI_REMDIR, &Xmi_Remdir, "remdir"},
01090            {XMI_REMOVE, &Xmi_Remove, "remove"},
01091            {XMI_SELECT, &Xmi_Select, "select"},
01092            {XMI_SPACE,  &Xmi_Space,  "space"},
01093            {XMI_STAT,   &Xmi_Stat,   "stat"}};
01094    int numintab = sizeof(XmiTab)/sizeof(XmiTab[0]);
01095 
01096 // Fill out the rest of the XmiEnv structure
01097 //
01098    XmiEnv.Role     = myRole;
01099    XmiEnv.ConfigFN = ConfigFN;
01100    XmiEnv.Parms    = XmiParms;
01101    XmiEnv.eDest    = &Say;
01102    XmiEnv.iNet     = NetTCP;
01103    XmiEnv.Sched    = Sched;
01104    XmiEnv.Trace    = &Trace;
01105    XmiEnv.Name2Name= xeq_N2N;
01106 
01107 // Create a pluin object (we will throw this away without deletion because
01108 // the library must stay open but we never want to reference it again).
01109 //
01110    if (!(xmiLib = new XrdSysPlugin(&Say, XmiPath))) return 1;
01111 
01112 // Now get the entry point of the object creator
01113 //
01114    ep = (XrdCmsXmi *(*)(int, char **, XrdCmsXmiEnv *))(xmiLib->getPlugin("XrdCmsgetXmi"));
01115    if (!ep) return 1;
01116 
01117 // Get the Object now
01118 //
01119    if (!(XMI = ep(inArgc, inArgv, &XmiEnv))) return 1;
01120    DEBUG("xmi library loaded; path=" <<XmiPath);
01121 
01122 // Obtain the execution mode
01123 //
01124    XMI->XeqMode(isNormal, isDirect);
01125 
01126 // Check if we need to create an indirect XMI interface
01127 //
01128    if ((isDirect & XMI_ALL) == XMI_ALL) myXMI = 0;
01129       else myXMI = (XrdCmsXmi *)new XrdCmsXmiReq(XMI);
01130 
01131 // Now run throw all of the possibilities setting the execution mode as needed
01132 //
01133    for (i = 0; i < numintab; i++)
01134        {if (!(isNormal & XmiTab[i].theMask))
01135            if (isDirect & XmiTab[i].theMask)
01136                    {*XmiTab[i].theAddr =   XMI; theMode = "direct";}
01137               else {*XmiTab[i].theAddr = myXMI; theMode = "queued";}
01138            else theMode = "normal";
01139         DEBUG(XmiTab[i].theName <<" is " <<theMode);
01140        }
01141    return 0;
01142 }
01143 
01144 /******************************************************************************/
01145 /*                                 U s a g e                                  */
01146 /******************************************************************************/
01147   
01148 void XrdCmsConfig::Usage(int rc)
01149 {
01150 cerr <<"\nUsage: cmsd [xrdopts] [-i] [-m] [-s] -c <cfile>" <<endl;
01151 exit(rc);
01152 }
01153   
01154 /******************************************************************************/
01155 /*                                x a l l o w                                 */
01156 /******************************************************************************/
01157 
01158 /* Function: xallow
01159 
01160    Purpose:  To parse the directive: allow {host | netgroup} <name>
01161 
01162              <name> The dns name of the host that is allowed to connect or the
01163                     netgroup name the host must be a member of. For DNS names,
01164                     a single asterisk may be specified anywhere in the name.
01165 
01166    Type: Manager only, non-dynamic.
01167 
01168    Output: 0 upon success or !0 upon failure.
01169 */
01170 
01171 int XrdCmsConfig::xallow(XrdSysError *eDest, XrdOucStream &CFile)
01172 {
01173     char *val;
01174     int ishost;
01175 
01176     if (!isManager) return CFile.noEcho();
01177 
01178     if (!(val = CFile.GetWord()))
01179        {eDest->Emsg("Config", "allow type not specified"); return 1;}
01180 
01181     if (!strcmp(val, "host")) ishost = 1;
01182        else if (!strcmp(val, "netgroup")) ishost = 0;
01183                else {eDest->Emsg("Config", "invalid allow type -", val);
01184                      return 1;
01185                     }
01186 
01187     if (!(val = CFile.GetWord()))
01188        {eDest->Emsg("Config", "allow target name not specified"); return 1;}
01189 
01190     if (!Police) Police = new XrdNetSecurity();
01191     if (ishost)  Police->AddHost(val);
01192        else      Police->AddNetGroup(val);
01193 
01194     return 0;
01195 }
01196 
01197 /******************************************************************************/
01198 /*                                x a p a t h                                 */
01199 /******************************************************************************/
01200 
01201 /* Function: xapath
01202 
01203    Purpose:  To parse the directive: adminpath <path>
01204 
01205              <path>    the path of the named socket to use for admin requests.
01206 
01207    Type: Manager and Server, non-dynamic.
01208 
01209    Output: 0 upon success or !0 upon failure.
01210 */
01211 
01212 int XrdCmsConfig::xapath(XrdSysError *eDest, XrdOucStream &CFile)
01213 {
01214     char *pval, *val;
01215     mode_t mode = S_IRWXU;
01216     struct sockaddr_un USock;
01217 
01218 // Get the path
01219 //
01220    pval = CFile.GetWord();
01221    if (!pval || !pval[0])
01222       {eDest->Emsg("Config", "adminpath not specified"); return 1;}
01223 
01224 // Make sure it's an absolute path
01225 //
01226    if (*pval != '/')
01227       {eDest->Emsg("Config", "adminpath not absolute"); return 1;}
01228 
01229 // Make sure path is not too long (account for "/olbd.admin")
01230 //                                              12345678901
01231    if (strlen(pval) > sizeof(USock.sun_path) - 11)
01232       {eDest->Emsg("Config", "admin path", pval, "is too long");
01233        return 1;
01234       }
01235    pval = strdup(pval);
01236 
01237 // Get the optional access rights
01238 //
01239    if ((val = CFile.GetWord()) && val[0])
01240       {if (!strcmp("group", val)) mode |= S_IRWXG;
01241           else {eDest->Emsg("Config", "invalid admin path modifier -", val);
01242                 free(pval); return 1;
01243                }
01244       }
01245 
01246 // Record the path
01247 //
01248    if (AdminPath) free(AdminPath);
01249    AdminPath = pval;
01250    AdminMode = mode;
01251    return 0;
01252 }
01253 
01254 /******************************************************************************/
01255 /*                                x d e l a y                                 */
01256 /******************************************************************************/
01257 
01258 /* Function: xdelay
01259 
01260    Purpose:  To parse the directive: delay [lookup <sec>] [overload <sec>]
01261                                            [startup <sec>] [servers <cnt>[%]]
01262                                            [full <sec>] [discard <cnt>]
01263                                            [suspend <sec>] [drop <sec>]
01264                                            [service <sec>] [hold <msec>]
01265                                            [peer <sec>] [rw <lvl>]
01266 
01267    discard   <cnt>     maximum number a message may be forwarded.
01268    drop      <sec>     seconds to delay a drop of an offline server.
01269    full      <sec>     seconds to delay client when no servers have space.
01270    hold      <msec>    millseconds to optimistically hold requests.
01271    lookup    <sec>     seconds to delay client when finding a file.
01272    overload  <sec>     seconds to delay client when all servers overloaded.
01273    peer      <sec>     maximum seconds client may be delayed before peer
01274                        selection is triggered.
01275    rw        <lvl>     how to delay r/w lookups (one of three levels):
01276                        0 - always use fast redirect when possible
01277                        1 - delay update requests only
01278                        2 - delay all rw requests (the default)
01279    servers   <cnt>     minimum number of servers we need.
01280    service   <sec>     seconds to delay client when waiting for servers.
01281    startup   <sec>     seconds to delay enabling our service
01282    suspend   <sec>     seconds to delay client when all servers suspended.
01283 
01284    Type: Manager only, dynamic.
01285 
01286    Output: 0 upon success or !0 upon failure.
01287 */
01288 int XrdCmsConfig::xdelay(XrdSysError *eDest, XrdOucStream &CFile)
01289 {   char *val;
01290     const char *etxt = "invalid delay option";
01291     int  i, ppp, minV = 1, ispercent = 0;
01292     static struct delayopts {const char *opname; int *oploc; int istime;}
01293            dyopts[] =
01294        {
01295         {"discard",  &MsgTTL,   0},
01296         {"drop",     &DRPDelay, 1},
01297         {"full",     &DiskWT,  -1},
01298         {"hold",     &LUPHold,  0},
01299         {"lookup",   &LUPDelay, 1},
01300         {"overload", &MaxDelay,-1},
01301         {"peer",     &PSDelay,  1},
01302         {"rw",       &RWDelay,  0},
01303         {"servers",  &SUPCount, 0},
01304         {"service",  &SUPDelay, 1},
01305         {"startup",  &SRVDelay, 1},
01306         {"suspend",  &SUSDelay, 1}
01307        };
01308     int numopts = sizeof(dyopts)/sizeof(struct delayopts);
01309 
01310     if (!isManager && !isPeer) return CFile.noEcho();
01311 
01312     if (!(val = CFile.GetWord()))
01313        {eDest->Emsg("Config", "delay arguments not specified"); return 1;}
01314 
01315     while (val)
01316           {for (i = 0; i < numopts; i++)
01317                if (!strcmp(val, dyopts[i].opname))
01318                   {if (!(val = CFile.GetWord()))
01319                       {eDest->Emsg("Config", "delay ", dyopts[i].opname,
01320                                    " argument not specified.");
01321                        return 1;
01322                       }
01323                    if (dyopts[i].istime < 0 && !strcmp(val, "*")) ppp = -1;
01324                       else if (dyopts[i].istime)
01325                               {if (XrdOuca2x::a2tm(*eDest,etxt,val,&ppp,1))
01326                                   return 1;
01327                               } else
01328                                if (*dyopts[i].opname == 'r')
01329                               {if (XrdOuca2x::a2i( *eDest,etxt,val,&ppp,0,2))
01330                                   return 1;
01331                               } else {
01332                                if (*dyopts[i].opname == 's')
01333                                   {ppp = strlen(val); SUPLevel = 0; minV = 0;
01334                                    if (val[ppp-1] == '%')
01335                                       {ispercent = 1; val[ppp-1] = '\0';}
01336                                   } else minV = 1;
01337                                if (XrdOuca2x::a2i( *eDest,etxt,val,&ppp,minV))
01338                                   return 1;
01339                               }
01340                    if (!ispercent) *dyopts[i].oploc = ppp;
01341                       else {ispercent = 0; SUPCount = 1; SUPLevel = ppp;}
01342                    break;
01343                   }
01344            if (i >= numopts) 
01345               eDest->Say("Config warning: ignoring invalid delay option '",val,"'.");
01346            val = CFile.GetWord();
01347           }
01348      return 0;
01349 }
01350 
01351 /******************************************************************************/
01352 /*                                 x d e f s                                  */
01353 /******************************************************************************/
01354 
01355 /* Function: xdefs
01356 
01357    Purpose:  Parse: oss.defaults <default options>
01358                               
01359    Notes: See the oss configuration manual for the meaning of each option.
01360           The actual implementation is defined in XrdOucExport.
01361 
01362    Output: 0 upon success or !0 upon failure.
01363 */
01364 
01365 int XrdCmsConfig::xdefs(XrdSysError *eDest, XrdOucStream &CFile)
01366 {
01367    if (!isServer) return CFile.noEcho();
01368    DirFlags = XrdOucExport::ParseDefs(CFile, *eDest, DirFlags);
01369    return 0;
01370 }
01371   
01372 /******************************************************************************/
01373 /*                                 x e x p o                                  */
01374 /******************************************************************************/
01375 
01376 /* Function: xexpo
01377 
01378    Purpose:  To parse the directive: all.export <path> [<options>]
01379 
01380              <path>    the full path that resides in a remote system.
01381              <options> a blank separated list of options (see XrdOucExport)
01382 
01383    Output: 0 upon success or !0 upon failure.
01384 */
01385 
01386 int XrdCmsConfig::xexpo(XrdSysError *eDest, XrdOucStream &CFile)
01387 {
01388    XrdOucPList *plp, *olp;
01389    unsigned long long Opts = DirFlags & XRDEXP_SETTINGS;
01390 
01391 // Parse the arguments
01392 //
01393    if (!(plp = XrdOucExport::ParsePath(CFile, *eDest, Opts))) return 1;
01394 
01395 // Check if this path is being modified or added. For modifications, turn off
01396 // all bitsin the old path specified in the new path and then set the new bits.
01397 //
01398    if (!(olp = PexpList.Match(plp->Path()))) PexpList.Insert(plp);
01399       else {Opts = plp->Flag() >> XRDEXP_MASKSHIFT;
01400             Opts = olp->Flag() & ~Opts;
01401             olp->Set(Opts | plp->Flag());
01402             delete plp;
01403            }
01404    return 0;
01405 }
01406   
01407 /******************************************************************************/
01408 /*                                 x f s x q                                  */
01409 /******************************************************************************/
01410   
01411 /* Function: xfsxq
01412 
01413    Purpose:  To parse the directive: fsxeq <types> <prog>
01414 
01415              <types>   what operations the program performs (one or more of):
01416                        chmod mkdir mkpath mv rm rmdir
01417              <prog>    the program to execute when doing a forwarded fs op.
01418 
01419    Type: Server only, non-dynamic.
01420 
01421    Output: 0 upon success or !0 upon failure.
01422 */
01423 
01424 int XrdCmsConfig::xfsxq(XrdSysError *eDest, XrdOucStream &CFile)
01425 {
01426     struct xeqopts {const char *opname; int doset; XrdOucProg **pgm;} xqopts[] =
01427        {
01428         {"chmod",    0, &ProgCH},
01429         {"mkdir",    0, &ProgMD},
01430         {"mkpath",   0, &ProgMP},
01431         {"mv",       0, &ProgMV},
01432         {"rm",       0, &ProgRM},
01433         {"rmdir",    0, &ProgRD},
01434         {"trunc",    0, &ProgTR}
01435        };
01436     int i, xtval = 0, numopts = sizeof(xqopts)/sizeof(struct xeqopts);
01437     char *val;
01438 
01439 // If we are a manager, ignore this option
01440 //
01441    if (!isServer) return CFile.noEcho();
01442 
01443 // Get the operation types
01444 //
01445     val = CFile.GetWord();
01446     while (val && *val != '/')
01447           {for (i = 0; i < numopts; i++)
01448                if (!strcmp(val, xqopts[i].opname))
01449                   {xqopts[i].doset = 1;
01450                    xtval = 1;
01451                    break;
01452                   }
01453            if (i >= numopts)
01454               eDest->Say("Config warning: ignoring invalid fsxeq type option '",val,"'.");
01455            val = CFile.GetWord();
01456           }
01457 
01458 // Make sure some type was specified
01459 //
01460    if (!xtval)
01461       {eDest->Emsg("Config", "fsxeq type option not specified"); return 1;}
01462 
01463 // Make sure a program was specified
01464 //
01465    if (!val)
01466       {eDest->Emsg("Config", "fsxeq program not specified"); return 1;}
01467 
01468 // Get the program
01469 //
01470    CFile.RetToken();
01471 
01472 // Set the program for each type
01473 //
01474    for (i = 0; i < numopts; i++)
01475        if (xqopts[i].doset)
01476           {if (!*xqopts[i].pgm) *(xqopts[i].pgm) = new XrdOucProg(0);
01477            if ((*(xqopts[i].pgm))->Setup(val, eDest)) return 1;
01478           }
01479 
01480 // All done
01481 //
01482    return 0;
01483 }
01484 
01485 /******************************************************************************/
01486 /*                                x f x h l d                                 */
01487 /******************************************************************************/
01488 
01489 /* Function: xfxhld
01490 
01491    Purpose:  To parse the directive: fxhold <sec>
01492 
01493              <sec>  number of seconds (or M, H, etc) to cache file existence
01494 
01495    Type: Manager only, dynamic.
01496 
01497    Output: 0 upon success or !0 upon failure.
01498 */
01499 
01500 int XrdCmsConfig::xfxhld(XrdSysError *eDest, XrdOucStream &CFile)
01501 {
01502     char *val;
01503     int ct;
01504 
01505     if (!isManager) return CFile.noEcho();
01506 
01507     if (!(val = CFile.GetWord()))
01508        {eDest->Emsg("Config", "fxhold value not specified."); return 1;}
01509 
01510     if (XrdOuca2x::a2tm(*eDest, "fxhold value", val, &ct, 60)) return 1;
01511 
01512     cachelife = ct;
01513     return 0;
01514 }
01515 
01516 /******************************************************************************/
01517 /*                                x l c l r t                                 */
01518 /******************************************************************************/
01519 
01520 /* Function: xlclrt
01521 
01522    Purpose:  To parse the directive: localroot <path>
01523 
01524              <path>    the path that the server will prefix to all local paths.
01525 
01526    Type: Server only, non-dynamic.
01527 
01528    Output: 0 upon success or !0 upon failure.
01529 */
01530 
01531 int XrdCmsConfig::xlclrt(XrdSysError *eDest, XrdOucStream &CFile)
01532 {
01533     char *val;
01534     int i;
01535 
01536 // If we are a manager, ignore this option
01537 //
01538    if (!isServer) return CFile.noEcho();
01539 
01540 // Get path type
01541 //
01542    val = CFile.GetWord();
01543    if (!val || !val[0])
01544       {eDest->Emsg("Config", "localroot path not specified"); return 1;}
01545    if (*val != '/')
01546       {eDest->Emsg("Config", "localroot path not absolute"); return 1;}
01547 
01548 // Cleanup the path
01549 //
01550    i = strlen(val)-1;
01551    while (i && val[i] == '/') val[i--] = '\0';
01552 
01553 // Assign new path prefix
01554 //
01555    if (i)
01556       {if (LocalRoot) free(LocalRoot);
01557        LocalRoot = strdup(val);
01558       }
01559    return 0;
01560 }
01561 
01562 /******************************************************************************/
01563 /*                                 x m a n g                                  */
01564 /******************************************************************************/
01565 
01566 /* Function: xmang
01567 
01568    Purpose:  Parse: manager [meta | peer | proxy] [all|any]
01569                             <host>[+][:<port>|<port>] [if ...]
01570 
01571              meta   For cmsd:   Specified the manager when running as a manager
01572                     For xrootd: The directive is ignored.
01573              peer   For cmsd:   Specified the manager when running as a peer
01574                     For xrootd: The directive is ignored.
01575              proxy  For cmsd:   This directive is ignored.
01576                     For xrootd: Specifies the cmsd-proxy service manager
01577              all    Ignored (useful only to the cmsd client)
01578              any    Ignored (useful only to the cmsd client)
01579              <host> The dns name of the host that is the cache manager.
01580                     If the host name ends with a plus, all addresses that are
01581                     associated with the host are treated as managers.
01582              <port> The port number to use for this host.
01583              if     Apply the manager directive if "if" is true. See
01584                     XrdOucUtils:doIf() for "if" syntax.
01585 
01586    Notes:   Any number of manager directives can be given. 
01587 
01588    Type: Remote server only, non-dynamic.
01589 
01590    Output: 0 upon success or !0 upon failure.
01591 */
01592 
01593 int XrdCmsConfig::xmang(XrdSysError *eDest, XrdOucStream &CFile)
01594 {
01595     class StorageHelper
01596     {public:
01597           StorageHelper(char **v1, char **v2) : val1(v1), val2(v2) {}
01598          ~StorageHelper() {if (*val1) free(*val1);
01599                            if (*val2) free(*val2);
01600                           }
01601     char **val1, **val2;
01602     };
01603 
01604     static const int sockALen = sizeof(struct sockaddr);
01605     struct sockaddr InetAddr[8];
01606     XrdOucTList *tp = 0, *tpp = 0, *tpnew;
01607     char *val, *bval = 0, *mval = 0;
01608     StorageHelper SHelp(&bval, &mval);
01609     int j, i, multi = 0, port = 0, xMeta = 0, xPeer = 0, xProxy = 0, Prt = 1;
01610 
01611 //  Process the optional "peer" or "proxy"
01612 //
01613     if ((val = CFile.GetWord()))
01614        {if ((xMeta  = !strcmp("meta", val))
01615         ||  (xPeer  = !strcmp("peer", val))
01616         ||  (xProxy = !strcmp("proxy", val)))
01617            {if (xMeta && (isServer || isPeer || isProxy)) return CFile.noEcho();
01618             if (xProxy || (xPeer && !isPeer)) return CFile.noEcho();
01619             val = CFile.GetWord();
01620            } else if (isPeer) return CFile.noEcho();
01621        }
01622 
01623 //  We can accept this manager. Skip the optional "all" or "any"
01624 //
01625     if (val)
01626        if (!strcmp("any", val) || !strcmp("all", val)) val = CFile.GetWord();
01627 
01628 //  Get the actual host name
01629 //
01630     if (!val)
01631        {eDest->Emsg("Config","manager host name not specified"); return 1;}
01632     mval = strdup(val);
01633 
01634 //  Grab the port number
01635 //
01636     if ((val = index(mval, ':'))) {*val = '\0'; val++;}
01637        else val = CFile.GetWord();
01638 
01639     if (val)
01640        {if (isdigit(*val))
01641            {if (XrdOuca2x::a2i(*eDest,"manager port",val,&port,1,65535))
01642                port = 0;
01643            }
01644            else if (!(port = XrdNetDNS::getPort(val, "tcp")))
01645                    {eDest->Emsg("Config", "Unable to find tcp service '",val,"'.");
01646                     port = 0;
01647                    }
01648        }
01649        else if (!(port = PortTCP))
01650                eDest->Emsg("Config","manager port not specified for",mval);
01651 
01652     if (!port) return 1;
01653 
01654     if ((val = CFile.GetWord()))
01655        {if (strcmp(val, "if"))
01656            {eDest->Emsg("Config","expecting manager 'if' but",val,"found");
01657             return 1;
01658            }
01659         if ((i=XrdOucUtils::doIf(eDest,CFile,"manager directive",
01660                             myName,myInsName,myProg))<=0) return i < 0;
01661        }
01662 
01663     i = strlen(mval);
01664     if (mval[i-1] != '+') 
01665        {i = 1;
01666         if (!XrdNetDNS::getHostAddr(mval, InetAddr))
01667            {eDest->Emsg("CFile","Manager host", mval, "not found");
01668             return 1;
01669            }
01670         free(mval); mval = XrdNetDNS::getHostName(InetAddr[0]);
01671        }
01672         else {bval = strdup(mval); mval[i-1] = '\0'; multi = 1;
01673               if (!(i = XrdNetDNS::getHostAddr(mval, InetAddr, 8)))
01674                  {eDest->Emsg("CFile","Manager host", mval, "not found");
01675                   return 1;
01676                  }
01677              }
01678 
01679 // Now try to determine our port number if we are a [meta] manager
01680 //
01681     if (isManager && !isServer)
01682        {if ((xMeta && isMeta) || (!xMeta && !isMeta))
01683            for (j = 0; j < i; j++)
01684                 if (!memcmp(&InetAddr[j], &myAddr, sockALen))
01685                    {PortTCP = port; break;}
01686         if (isMeta) return (xMeta ? 0: CFile.noEcho());
01687         if (!xMeta) Prt = 0;
01688        }
01689 
01690 // Now construct the list of [meta] managers
01691 //
01692     do {if (multi)
01693            {free(mval);
01694             char mvBuff[1024];
01695             if (Prt) sprintf(mvBuff, "%s -> all.manager ", bval);
01696             mval = XrdNetDNS::getHostName(InetAddr[i-1]);
01697             if (Prt) eDest->Say("Config ", mvBuff, mval);
01698            }
01699         tp = (Prt ? ManList : NanList); tpp = 0; j = 1;
01700         while(tp) 
01701              if ((j = strcmp(tp->text, mval)) < 0 || tp->val != port)
01702                 {tpp = tp; tp = tp->next;}
01703                 else {if (Prt && !j)
01704                          eDest->Say("Config warning: duplicate manager ",mval);
01705                       break;
01706                      }
01707         if (j) {tpnew = new XrdOucTList(mval, port, tp);
01708                 if (tpp) tpp->next = tpnew;
01709                    else if (Prt) ManList = tpnew;
01710                            else  NanList = tpnew;
01711                }
01712        } while(--i);
01713 
01714     return 0;
01715 }
01716   
01717 /******************************************************************************/
01718 /*                                  x n m l                                   */
01719 /******************************************************************************/
01720 
01721 /* Function: xnml
01722 
01723    Purpose:  To parse the directive: namelib <path> [<parms>]
01724 
01725              <path>    the path of the filesystem library to be used.
01726              <parms>   optional parms to be passed
01727 
01728   Output: 0 upon success or !0 upon failure.
01729 */
01730 
01731 int XrdCmsConfig::xnml(XrdSysError *eDest, XrdOucStream &CFile)
01732 {
01733     char *val, parms[1024];
01734 
01735 // Get the path
01736 //
01737    if (!(val = CFile.GetWord()) || !val[0])
01738       {eDest->Emsg("Config", "namelib not specified"); return 1;}
01739 
01740 // Record the path
01741 //
01742    if (N2N_Lib) free(N2N_Lib);
01743    N2N_Lib = strdup(val);
01744 
01745 // Record any parms
01746 //
01747    if (!CFile.GetRest(parms, sizeof(parms)))
01748       {eDest->Emsg("Config", "namelib parameters too long"); return 1;}
01749    if (N2N_Parms) free(N2N_Parms);
01750    N2N_Parms = (*parms ? strdup(parms) : 0);
01751    return 0;
01752 }
01753   
01754 /******************************************************************************/
01755 /*                                 x o l i b                                  */
01756 /******************************************************************************/
01757 
01758 /* Function: xolib
01759 
01760    Purpose:  To parse the directive: osslib <path>
01761 
01762              <path>    the path of the filesystem library to be used.
01763 
01764   Output: 0 upon success or !0 upon failure.
01765 */
01766 
01767 int XrdCmsConfig::xolib(XrdSysError *eDest, XrdOucStream &CFile)
01768 {
01769     char *val, parms[1024];
01770 
01771 // Get the path
01772 //
01773    if (!(val = CFile.GetWord()) || !val[0])
01774       {eDest->Emsg("Config", "osslib not specified"); return 1;}
01775    if (ossLib) free(ossLib);
01776    ossLib = strdup(val);
01777 
01778 // Record any parms
01779 //
01780    if (!CFile.GetRest(parms, sizeof(parms)))
01781       {eDest->Emsg("Config", "namelib parameters too long"); return 1;}
01782    if (ossParms) free(ossParms);
01783    ossParms = (*parms ? strdup(parms) : 0);
01784    return 0;
01785 }
01786 
01787 /******************************************************************************/
01788 /*                                 x p e r f                                  */
01789 /******************************************************************************/
01790 
01791 /* Function: xperf
01792 
01793    Purpose:  To parse the directive: perf [key <num>] [int <sec>] [pgm <pgm>]
01794 
01795          int <time>    estimated time (seconds, M, H) between reports by <pgm>
01796          key <num>     This is no longer documented but kept for compatability.
01797          pgm <pgm>     program to start that will write perf values to standard
01798                        out. It must be the last option.
01799 
01800    Type: Server only, non-dynamic.
01801 
01802    Output: 0 upon success or !0 upon failure. Ignored by manager.
01803 */
01804 int XrdCmsConfig::xperf(XrdSysError *eDest, XrdOucStream &CFile)
01805 {   int   ival = 3*60;
01806     char *pgm=0, *val, rest[2048];
01807 
01808     if (!isServer) return CFile.noEcho();
01809 
01810     if (!(val = CFile.GetWord()))
01811        {eDest->Emsg("Config", "perf options not specified"); return 1;}
01812 
01813     do {     if (!strcmp("int", val))
01814                 {if (!(val = CFile.GetWord()))
01815                     {eDest->Emsg("Config", "perf int value not specified");
01816                      return 1;
01817                     }
01818                  if (XrdOuca2x::a2tm(*eDest,"perf int",val,&ival,0)) return 1;
01819                 }
01820         else if (!strcmp("pgm",  val))
01821                 {if (!CFile.GetRest(rest, sizeof(rest)))
01822                     {eDest->Emsg("Config", "perf pgm parameters too long"); return 1;}
01823                  if (!*rest)
01824                     {eDest->Emsg("Config", "perf prog value not specified");
01825                      return 1;
01826                     }
01827                  pgm = rest;
01828                  break;
01829                 }
01830         else eDest->Say("Config warning: ignoring invalid perf option '",val,"'.");
01831        } while((val = CFile.GetWord()));
01832 
01833 // Make sure that the perf program is here
01834 //
01835    if (perfpgm) {free(perfpgm); perfpgm = 0;}
01836    if (pgm) {if (!isExec(eDest, "perf", pgm)) return 1;
01837                 else perfpgm = strdup(pgm);
01838             }
01839 
01840 // Set remaining values
01841 //
01842     perfint = ival;
01843     return 0;
01844 }
01845 
01846   
01847 /******************************************************************************/
01848 /*                                 x p i d f                                  */
01849 /******************************************************************************/
01850 
01851 /* Function: xpidf
01852 
01853    Purpose:  To parse the directive: pidpath <path>
01854 
01855              <path>    the path where the pid file is to be created.
01856 
01857   Output: 0 upon success or !0 upon failure.
01858 */
01859 
01860 int XrdCmsConfig::xpidf(XrdSysError *eDest, XrdOucStream &CFile)
01861 {
01862     char *val;
01863 
01864 // Get the path
01865 //
01866    val = CFile.GetWord();
01867    if (!val || !val[0])
01868       {eDest->Emsg("Config", "pidpath not specified"); return 1;}
01869 
01870 // Record the path
01871 //
01872    if (pidPath) free(pidPath);
01873    pidPath = strdup(val);
01874    return 0;
01875 }
01876   
01877 /******************************************************************************/
01878 /*                                 x p i n g                                  */
01879 /******************************************************************************/
01880 
01881 /* Function: xping
01882 
01883    Purpose:  To parse the directive: ping <ptm> [log <num>] [usage <cnt>]
01884 
01885              <ptm>     Time (seconds, M, H. etc) between keepalive pings.
01886                        The default is 60 seconds.
01887              log       values are logged to the log every <num> usage
01888                        requests (default 10). Zero, suppresses logging.
01889              usage     The number of pings between resource usage requests.
01890                        The default is 10. Zero suppresses usage requests.
01891 
01892    Note: The defaults will log usage 100 minutes (little less than 2 hours).
01893 
01894    Type: Server for ping value and Manager for all values, dynamic.
01895 
01896    Output: 0 upon success or !0 upon failure.
01897 */
01898 int XrdCmsConfig::xping(XrdSysError *eDest, XrdOucStream &CFile)
01899 {   int pnum = AskPerf, lnum = LogPerf, ping;
01900     char *val;
01901 
01902     if (!(val = CFile.GetWord()))
01903        {eDest->Emsg("Config", "ping value not specified"); return 1;}
01904     if (XrdOuca2x::a2tm(*eDest, "ping interval",val,&ping,0)) return 1;
01905 
01906 
01907     while((val = CFile.GetWord()))
01908         {     if (!strcmp("log", val))
01909                  {if (!(val = CFile.GetWord()))
01910                      {eDest->Emsg("Config", "ping log value not specified");
01911                       return 1;
01912                      }
01913                   if (XrdOuca2x::a2i(*eDest,"ping log",val,&lnum,0)) return 1;
01914                  }
01915          else if (!strcmp("usage", val))
01916                  {if (!(val = CFile.GetWord()))
01917                     {eDest->Emsg("Config", "ping usage value not specified");
01918                      return 1;
01919                     }
01920                   if (XrdOuca2x::a2i(*eDest,"ping usage",val,&pnum,1)) return 1;
01921                  }
01922         }
01923     AskPerf = pnum;
01924     AskPing = ping;
01925     LogPerf = lnum;
01926     return 0;
01927 }
01928   
01929 /******************************************************************************/
01930 /*                                 x p r e p                                  */
01931 /******************************************************************************/
01932 
01933 /* Function: xprep
01934 
01935    Purpose:  To parse the directive: prep  [echo]
01936                                            [reset <cnt>] [scrub <sec>] 
01937                                            [ifpgm <pgm>]
01938 
01939          echo          display list of pending prepares during resets.
01940          reset <cnt>   number of scrubs after which a full reset is done.
01941          scrub <sec>   time (seconds, M, H) between pendq scrubs.
01942          ifpgm <pgm>   program that adds, deletes, and lists prepare queue
01943                        entries. If specified, t must be specified as the last
01944                        option on the line. If not specified, then the built-in
01945                        frm_xfragent program is used.
01946 
01947    Type: Any, non-dynamic. Note that the Manager only need the "batch" option
01948          while slacves need the remaining options.
01949 
01950    Output: 0 upon success or !0 upon failure. Ignored by manager.
01951 */
01952 int XrdCmsConfig::xprep(XrdSysError *eDest, XrdOucStream &CFile)
01953 {   int   reset=0, scrub=0, echo = 0, doset = 0;
01954     char  *prepif=0, *val, rest[2048];
01955 
01956     if (!isServer) return CFile.noEcho();
01957 
01958     if (!(val = CFile.GetWord())) {PrepQ.setParms(""); return 0;}
01959 
01960     do {     if (!strcmp("echo", val)) doset = echo = 1;
01961         else if (!strcmp("reset", val))
01962                 {if (!(val = CFile.GetWord()))
01963                     {eDest->Emsg("Config", "prep reset value not specified");
01964                      return 1;
01965                     }
01966                  if (XrdOuca2x::a2i(*eDest,"prep reset int",val,&reset,1)) return 1;
01967                  doset = 1;
01968                 }
01969         else if (!strcmp("scrub", val))
01970                 {if (!(val = CFile.GetWord()))
01971                     {eDest->Emsg("Config", "prep scrub value not specified");
01972                      return 1;
01973                     }
01974                  if (XrdOuca2x::a2tm(*eDest,"prep scrub",val,&scrub,0)) return 1;
01975                  doset = 1;
01976                 }
01977         else if (!strcmp("ifpgm",  val))
01978                 {if (!CFile.GetRest(rest, sizeof(rest)))
01979                     {eDest->Emsg("Config", "prep ifpgm parameters too long"); return 1;}
01980                  if (!*rest)
01981                     {eDest->Emsg("Config", "prep ifpgm value not specified");
01982                      return 1;
01983                     }
01984                  prepif = rest;
01985                  break;
01986                 }
01987         else eDest->Say("Config warning: ignoring invalid prep option '",val,"'.");
01988        } while((val = CFile.GetWord()));
01989 
01990 
01991 
01992 // Set the values
01993 //
01994    if (scrub) pendplife = scrub;
01995    if (doset) PrepQ.setParms(reset, scrub, echo);
01996    if (prepif) {if (!isExec(eDest, "prep", prepif)) return 1;
01997                    else return PrepQ.setParms(prepif);
01998                } else PrepQ.setParms("");
01999    return 0;
02000 }
02001 
02002 /******************************************************************************/
02003 /*                                x p r e p m                                 */
02004 /******************************************************************************/
02005 
02006 /* Function: xprepm
02007 
02008    Purpose:  To parse the directive: prepmsg <msg>
02009 
02010              <msg>     the message to be sent to the prep ifpgm (see prep).
02011 
02012    Type: Manager only, non-dynamic.
02013 
02014    Output: 0 upon success or !0 upon failure.
02015 */
02016 
02017 int XrdCmsConfig::xprepm(XrdSysError *eDest, XrdOucStream &CFile)
02018 {
02019     char *val, buff[2048];
02020     XrdOucEnv *myEnv = CFile.SetEnv(0);
02021 
02022    // At this point, make sure we have a value
02023    //
02024    if (!(val = CFile.GetWord()))
02025       {eDest->Emsg("Config", "no value for prepmsg directive");
02026        CFile.SetEnv(myEnv);
02027        return 1;
02028       }
02029 
02030    // We need to suck all the tokens to the end of the line for remaining
02031    // options. Do so, until we run out of space in the buffer.
02032    //
02033    CFile.RetToken();
02034    if (!CFile.GetRest(buff, sizeof(buff)))
02035       {eDest->Emsg("Config", "prepmsg arguments too long");
02036        CFile.SetEnv(myEnv);
02037        return 1;
02038       }
02039 
02040    // Restore substitutions and parse the message
02041    //
02042    CFile.SetEnv(myEnv);
02043    return PrepQ.setParms(0, buff);
02044 }
02045   
02046 /******************************************************************************/
02047 /*                                x r m t r t                                 */
02048 /******************************************************************************/
02049 
02050 /* Function: xrmtrt
02051 
02052    Purpose:  To parse the directive: remoteroot <path>
02053 
02054              <path>    the path that the server will prefix to all remote paths.
02055 
02056    Type: Manager only, non-dynamic.
02057 
02058    Output: 0 upon success or !0 upon failure.
02059 */
02060 
02061 int XrdCmsConfig::xrmtrt(XrdSysError *eDest, XrdOucStream &CFile)
02062 {
02063     char *val, *colon, *slash;
02064     int i;
02065 
02066 // If we are a manager, ignore this option
02067 //
02068    if (isManager) return CFile.noEcho();
02069 
02070 // Get path type
02071 //
02072    val = CFile.GetWord();
02073    if (!val || !val[0])
02074       {eDest->Emsg("Config", "remoteroot path not specified"); return 1;}
02075 
02076 // For remote roots we allow a url-type specification o/w path must be absolute
02077 //
02078    if (*val != '/')
02079       {colon = index(val, ':'); slash = index(val, '/');
02080        if ((colon+1) != slash)
02081           {eDest->Emsg("Config", "remoteroot path not absolute"); return 1;}
02082       }
02083 
02084 // Cleanup the path
02085 //
02086    i = strlen(val)-1;
02087    while (i && val[i] == '/') val[i--] = '\0';
02088 
02089 // Assign new path prefix
02090 //
02091    if (i)
02092       {if (RemotRoot) free(RemotRoot);
02093        RemotRoot = strdup(val);
02094       }
02095    return 0;
02096 }
02097 
02098 /******************************************************************************/
02099 /*                                 x r o l e                                  */
02100 /******************************************************************************/
02101 
02102 /* Function: xrole
02103    Purpose:  Parse: role { {[meta] | [peer] [proxy]} manager
02104                            | peer | proxy | [proxy]  server
02105                            |                [proxy]  supervisor
02106                          } [if ...]
02107 
02108              manager    xrootd: act as a manager (redirecting server). Prefixes:
02109                                 meta  - connect only to manager meta's
02110                                 peer  - ignored
02111                                 proxy - ignored
02112                         cmsd:   accept server subscribes and redirectors. Prefix
02113                                 modifiers do the following:
02114                                 meta  - No other managers apply
02115                                 peer  - subscribe to other managers as a peer
02116                                 proxy - manage a cluster of proxy servers
02117 
02118              peer       xrootd: same as "peer manager"
02119                         cmsd:   same as "peer manager" but no server subscribers
02120                                 are required to function (i.e., run stand-alone).
02121 
02122              proxy      xrootd: act as a server but supply data from another 
02123                                 server. No local cmsd is present or required.
02124                         cmsd:   Generates an error as this makes no sense.
02125 
02126              server     xrootd: act as a server (supply local data). Prefix
02127                                 modifications do the following:
02128                                 proxy - server is part of a cluster. A local
02129                                         cmsd is required.
02130                         cmsd:   subscribe to a manager, possibly as a proxy.
02131 
02132              supervisor xrootd: equivalent to manager.
02133                         cmsd:   equivalent to manager but also subscribe to a
02134                                 manager. When proxy is specified, subscribe as
02135                                 a proxy and only accept proxy servers.
02136 
02137 
02138              if         Apply the manager directive if "if" is true. See
02139                         XrdOucUtils:doIf() for "if" syntax.
02140 
02141 
02142    Type: Server only, non-dynamic.
02143 
02144    Output: 0 upon success or !0 upon failure.
02145 */
02146 
02147 int XrdCmsConfig::xrole(XrdSysError *eDest, XrdOucStream &CFile)
02148 {
02149     char *val, role[64];
02150     int rc, xMeta=0, xPeer=0, xProxy=0, xServ=0, xMan=0, xSolo=0, xSup=0;
02151 
02152     *role = '\0';
02153     if (!(val = CFile.GetWord()))
02154        {eDest->Emsg("Config", "role not specified"); return 1;}
02155 
02156 // Scan for "meta" o/w "peer" or "proxy"
02157 //
02158    if (!strcmp("meta", val))
02159       {xMeta = -1; strcpy(role, val); val = CFile.GetWord();}
02160       else {if (!strcmp("peer", val))
02161                {xPeer = -1; strcpy(role, val); 
02162                 val = CFile.GetWord();
02163                }
02164             if (val && !strcmp("proxy", val))
02165                {xProxy = -1; if (xPeer) strcat(role, " "); strcat(role, val);
02166                 val = CFile.GetWord();
02167                }
02168            }
02169 
02170 // Scan for other possible alternatives
02171 //
02172    if (val && strcmp("if", val))
02173       {     if (!strcmp("manager",    val)) {xMan = -1;}
02174        else if (!strcmp("server",     val)) {           xServ = -1;}
02175        else if (!strcmp("supervisor", val)) {xMan = -1; xServ = -1; xSup = -1;}
02176        else    {eDest->Emsg("Config", "invalid role -", val); return 1;}
02177 
02178        if (xMeta || xPeer || xProxy) strcat(role, " ");
02179        strcat(role, val);
02180        val = CFile.GetWord();
02181       }
02182 
02183 // Scan for invalid roles
02184 //
02185    if (((xPeer && xProxy) && !(xMan || xServ)) // peer proxy
02186    ||  (xPeer && xServ)                        // peer server
02187    ||  (xPeer && xSup)                         // peer supervisor
02188    ||  (xMeta &&!xMan))                        // meta, meta server, meta super
02189       {eDest->Emsg("Config", "invalid role -", role); return 1;}
02190    if (!(xMan || xServ) && xProxy)
02191       {eDest->Emsg("Config", "pure proxy role is not supported"); return 1;}
02192 
02193 // Make sure a role was specified
02194 //
02195     if (!(xPeer || xProxy || xServ || xMan))
02196        {eDest->Emsg("Config", "role not specified"); return 1;}
02197 
02198 // Check if this is a solo peer
02199 //
02200     if (xPeer) if (!xMan) {xSolo = 1; xServ = -1;}
02201 
02202 // Handle optional "if"
02203 //
02204     if (val && !strcmp("if", val))
02205        if ((rc = XrdOucUtils::doIf(eDest,CFile,"role directive",
02206                               myName,myInsName,myProg)) <= 0) return (rc < 0);
02207 
02208     if (isServer > 0 || isManager > 0 || isProxy > 0 || isPeer > 0)
02209        eDest->Say("Config warning: role directive over-ridden by command line options.");
02210        else {isServer = xServ; isManager = xMan;  isProxy = xProxy;
02211              isPeer   = xPeer; isSolo    = xSolo; isMeta  = xMeta;
02212              if (myRole) free(myRole); myRole = strdup(role);
02213             }
02214     return 0;
02215 }
02216 
02217 /******************************************************************************/
02218 /*                                x s c h e d                                 */
02219 /******************************************************************************/
02220 
02221 /* Function: xsched
02222 
02223    Purpose:  To parse directive: sched [cpu <p>] [io <p>] [runq <p>]
02224                                        [mem <p>] [pag <p>] [space <p>]
02225                                        [fuzz <p>] [maxload <p>] [refreset <sec>]
02226 
02227              <p>      is the percentage to include in the load as a value
02228                       between 0 and 100. For fuzz this is the largest
02229                       difference two load values may have to be treated equal.
02230                       maxload is the largest load allowed before server is
02231                       not selected. refreset is the minimum number of seconds
02232                       between reference counter resets.
02233 
02234    Type: Any, dynamic.
02235 
02236    Output: retc upon success or -EINVAL upon failure.
02237 */
02238 
02239 int XrdCmsConfig::xsched(XrdSysError *eDest, XrdOucStream &CFile)
02240 {
02241     char *val;
02242     int  i, ppp;
02243     static struct schedopts {const char *opname; int maxv; int *oploc;}
02244            scopts[] =
02245        {
02246         {"cpu",      100, &P_cpu},
02247         {"fuzz",     100, &P_fuzz},
02248         {"io",       100, &P_io},
02249         {"runq",     100, &P_load}, // Actually load, runq to avoid confusion
02250         {"mem",      100, &P_mem},
02251         {"pag",      100, &P_pag},
02252         {"space",    100, &P_dsk},
02253         {"maxload",  100, &MaxLoad},
02254         {"refreset", -1,  &RefReset}
02255        };
02256     int numopts = sizeof(scopts)/sizeof(struct schedopts);
02257 
02258     if (!(val = CFile.GetWord()))
02259        {eDest->Emsg("Config", "sched option not specified"); return 1;}
02260 
02261     while (val)
02262           {for (i = 0; i < numopts; i++)
02263                if (!strcmp(val, scopts[i].opname))
02264                   {if (!(val = CFile.GetWord()))
02265                       {eDest->Emsg("Config", "sched ", scopts[i].opname,
02266                                    "argument not specified.");
02267                        return 1;
02268                       }
02269                    if (scopts[i].maxv < 0)
02270                       {if (XrdOuca2x::a2tm(*eDest,"sched value", val, &ppp, 0)) 
02271                           return 1;
02272                       }
02273                       else if (XrdOuca2x::a2i(*eDest,"sched value", val, &ppp,
02274                                               0, scopts[i].maxv)) return 1;
02275                    *scopts[i].oploc = ppp;
02276                    break;
02277                   }
02278            if (i >= numopts)
02279               eDest->Say("Config warning: ignoring invalid sched option '",val,"'.");
02280            val = CFile.GetWord();
02281           }
02282 
02283     return 0;
02284 }
02285 
02286 /******************************************************************************/
02287 /*                                 x s e c l                                  */
02288 /******************************************************************************/
02289 
02290 /* Function: xsecl
02291 
02292    Purpose:  To parse the directive: seclib <path>
02293 
02294              <path>    the location of the security library.
02295 
02296    Type: Server only, non-dynamic.
02297 
02298    Output: 0 upon success or !0 upon failure.
02299 */
02300 
02301 int XrdCmsConfig::xsecl(XrdSysError *eDest, XrdOucStream &CFile)
02302 {
02303     char *val;
02304 
02305 // If we are a server, ignore this option
02306 //
02307    if (!isManager) return CFile.noEcho();
02308 
02309 // Get path
02310 //
02311    val = CFile.GetWord();
02312    if (!val || !val[0])
02313       {eDest->Emsg("Config", "seclib path not specified"); return 1;}
02314 
02315 // Assign new path
02316 //
02317    if (SecLib) free(SecLib);
02318    SecLib = strdup(val);
02319    return 0;
02320 }
02321   
02322 /******************************************************************************/
02323 /*                                x s p a c e                                 */
02324 /******************************************************************************/
02325 
02326 /* Function: xspace
02327 
02328    Purpose:  To parse the directive: space [linger <num>] [recalc <sec>]
02329 
02330                           [[min] {<mnp> [<min>] | <min>}  [[<hwp>] <hwm>]]
02331 
02332              <num> Maximum number of times a server may be reselected without
02333                    a break. The default is 0.
02334 
02335              <mnp> Min free space needed as percentage of the largest partition.
02336 
02337              <min> Min free space needed in bytes (or K, M, G) in a partition.
02338                    The default is 10G.
02339 
02340              <hwp> Percentage of free space needed to requalify.
02341 
02342              <hwm> Bytes (or K, M,G) of free space needed when bytes falls below
02343                    <min> to requalify a server for selection.
02344                    The default is 11G.
02345 
02346              <sec> Number of seconds that must elapse before a disk free space
02347                    calculation will occur.
02348 
02349    Notes:   This is used by the manager and the server.
02350 
02351    Type: All, dynamic.
02352 
02353    Output: 0 upon success or !0 upon failure.
02354 */
02355 
02356 int XrdCmsConfig::xspace(XrdSysError *eDest, XrdOucStream &CFile)
02357 {
02358     char *val;
02359     int i, alinger = -1, arecalc = -1, minfP = 0, hwmP = 0;
02360     long long minf = -1, hwm = -1;
02361 
02362     while((val = CFile.GetWord()))
02363       {    if (!strcmp("linger", val))
02364               {if (!(val = CFile.GetWord()))
02365                   {eDest->Emsg("Config", "linger value not specified"); return 1;}
02366                if (XrdOuca2x::a2i(*eDest,"linger",val,&alinger,0)) return 1;
02367               }
02368       else if (!strcmp("recalc", val))
02369               {if (!(val = CFile.GetWord()))
02370                   {eDest->Emsg("Config", "recalc value not specified"); return 1;}
02371                if (XrdOuca2x::a2i(*eDest,"recalc",val,&arecalc,1)) return 1;
02372               }
02373       else if (!strcmp("min", val))
02374               {if (!(val = CFile.GetWord()) || !isdigit(*val))
02375                   {eDest->Emsg("Config", "space min value not specified"); return 1;}
02376                break;
02377               }
02378       else if (isdigit(*val)) break;
02379       else {eDest->Emsg("Config", "invalid space parameters"); return 1;}
02380       }
02381 
02382     if (val && isdigit(*val))
02383        {i = strlen(val);
02384         if (val[i-1] == '%')
02385            {val[i-1] = '\0';
02386             if (XrdOuca2x::a2i(*eDest,"space % minfree",val,&minfP,1,99)) return 1;
02387             val = CFile.GetWord(); minf  = 10240LL<<20LL; hwm  = 11264LL<<20LL;
02388            }
02389        }
02390 
02391     if (val && isdigit(*val))
02392        {i = strlen(val);
02393         if (val[i-1] != '%')
02394            {if (XrdOuca2x::a2sz(*eDest,"space minfree",val,&minf,0)) return 1;
02395             val = CFile.GetWord();
02396            }
02397        }
02398 
02399     if (val && isdigit(*val))
02400        {i = strlen(val);
02401         if (val[i-1] == '%')
02402            {val[i-1] = '\0';
02403             if (XrdOuca2x::a2i(*eDest,"space % high watermark",val,&hwmP,1,99)) return 1;
02404             val = CFile.GetWord();
02405            }
02406        }
02407 
02408     if (val && isdigit(*val))
02409        {i = strlen(val);
02410         if (val[i-1] != '%')
02411            {if (XrdOuca2x::a2sz(*eDest,"space high watermark",val,&hwm,0)) return 1;
02412             val = CFile.GetWord();
02413            }
02414        }
02415 
02416     if (val) {eDest->Emsg("Config", "invalid space parameter -", val); return 1;}
02417     
02418     if (alinger < 0 && arecalc < 0 && minf < 0 && minfP)
02419        {eDest->Emsg("Config", "no space values specified"); return 1;}
02420 
02421     if (alinger >= 0) DiskLinger = alinger;
02422     if (arecalc >= 0) DiskAsk    = arecalc;
02423 
02424     if (minfP)
02425        {if (hwmP < minfP) hwmP = minfP + 1;
02426         DiskMinP = minfP; DiskHWMP = hwmP;
02427        }
02428 
02429     if (minf >= 0)
02430        {if (hwm < minf) hwm = minf+1073741824;     // Minimum + 1GB
02431         minf = minf >> 20LL; hwm = hwm >> 20LL;    // Now Megabytes
02432         if (minf >> 31LL) {minf = 0x7fefffff; hwm = 0x7fffffff;}
02433            else if (hwm >> 31LL) minf = 0x7fffffff;
02434         DiskMin = static_cast<int>(minf);
02435         DiskHWM = static_cast<int>(hwm);
02436        }
02437     return 0;
02438 }
02439   
02440 /******************************************************************************/
02441 /*                                x t r a c e                                 */
02442 /******************************************************************************/
02443 
02444 /* Function: xtrace
02445 
02446    Purpose:  To parse the directive: trace <options>
02447 
02448    Type: Manager or Server, dynamic.
02449 
02450    Output: 0 upon success or !0 upon failure.
02451 */
02452 
02453 int XrdCmsConfig::xtrace(XrdSysError *eDest, XrdOucStream &CFile)
02454 {
02455     char  *val;
02456     static struct traceopts {const char *opname; int opval;} tropts[] =
02457        {
02458         {"all",      TRACE_ALL},
02459         {"debug",    TRACE_Debug},
02460         {"defer",    TRACE_Defer},
02461         {"files",    TRACE_Files},
02462         {"forward",  TRACE_Forward},
02463         {"redirect", TRACE_Redirect},
02464         {"stage",    TRACE_Stage}
02465        };
02466     int i, neg, trval = 0, numopts = sizeof(tropts)/sizeof(struct traceopts);
02467 
02468     if (!(val = CFile.GetWord()))
02469        {eDest->Emsg("config", "trace option not specified"); return 1;}
02470     while (val)
02471          {if (!strcmp(val, "off")) trval = 0;
02472              else {if ((neg = (val[0] == '-' && val[1]))) val++;
02473                    for (i = 0; i < numopts; i++)
02474                        {if (!strcmp(val, tropts[i].opname))
02475                            {if (neg) trval &= ~tropts[i].opval;
02476                                else  trval |=  tropts[i].opval;
02477                             break;
02478                            }
02479                        }
02480                    if (i >= numopts)
02481                       eDest->Say("Config warning: ignoring invalid trace option '",val,"'.");
02482                   }
02483           val = CFile.GetWord();
02484          }
02485 
02486     Trace.What = trval;
02487     return 0;
02488 }
02489   
02490 /******************************************************************************/
02491 /*                                  x x m i                                   */
02492 /******************************************************************************/
02493 
02494 /* Function: xxmi
02495 
02496    Purpose:  To parse the directive: xmilib <path> [<parms>]
02497 
02498              <path>    the SO path for the XrdCmsXmi plugin.
02499              <parms>   optional parms to be passed to the Xmi object
02500 
02501   Output: 0 upon success or !0 upon failure.
02502 */
02503 
02504 int XrdCmsConfig::xxmi(XrdSysError *eDest, XrdOucStream &CFile)
02505 {
02506     char *val, parms[1024];
02507 
02508 // Get the path
02509 //
02510    if (!(val = CFile.GetWord()) || !val[0])
02511       {eDest->Emsg("Config", "xmilib path not specified"); return 1;}
02512 
02513 // Record the path
02514 //
02515    if (XmiPath) free(XmiPath);
02516    XmiPath = strdup(val);
02517 
02518 // Record any parms
02519 //
02520    if (!CFile.GetRest(parms, sizeof(parms)))
02521       {eDest->Emsg("Config", "xmilib parameters too long"); return 1;}
02522    if (XmiParms) free(XmiParms);
02523    XmiParms = (*parms ? strdup(parms) : 0);
02524 
02525    return 0;
02526 }

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