XRootD
XrdFrmConfig.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d F r m C o n f i g . c c */
4 /* */
5 /* (c) 2009 by the Board of Trustees of the Leland Stanford, Jr., University */
6 /* Produced by Andrew Hanushevsky for Stanford University under contract */
7 /* DE-AC02-76-SFO0515 with the Deprtment of Energy */
8 /* */
9 /* This file is part of the XRootD software suite. */
10 /* */
11 /* XRootD is free software: you can redistribute it and/or modify it under */
12 /* the terms of the GNU Lesser General Public License as published by the */
13 /* Free Software Foundation, either version 3 of the License, or (at your */
14 /* option) any later version. */
15 /* */
16 /* XRootD is distributed in the hope that it will be useful, but WITHOUT */
17 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
18 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
19 /* License for more details. */
20 /* */
21 /* You should have received a copy of the GNU Lesser General Public License */
22 /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
23 /* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
24 /* */
25 /* The copyright holder's institutional names and contributor's names may not */
26 /* be used to endorse or promote products derived from this software without */
27 /* specific prior written permission of the institution or contributor. */
28 /******************************************************************************/
29 
30 #include <unistd.h>
31 #include <cctype>
32 #include <dirent.h>
33 #include <cstring>
34 #include <cstdio>
35 #include <fcntl.h>
36 #include <sys/param.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 
40 #include "XrdVersion.hh"
41 
42 #include "Xrd/XrdInfo.hh"
43 #include "XrdFrc/XrdFrcTrace.hh"
44 #include "XrdFrc/XrdFrcUtils.hh"
45 #include "XrdFrm/XrdFrmCns.hh"
46 #include "XrdFrm/XrdFrmConfig.hh"
47 #include "XrdFrm/XrdFrmMonitor.hh"
48 #include "XrdNet/XrdNetAddr.hh"
50 #include "XrdOfs/XrdOfsConfigPI.hh"
51 #include "XrdOss/XrdOss.hh"
52 #include "XrdOss/XrdOssSpace.hh"
53 #include "XrdOuc/XrdOuca2x.hh"
54 #include "XrdOuc/XrdOucEnv.hh"
55 #include "XrdOuc/XrdOucExport.hh"
56 #include "XrdOuc/XrdOucMsubs.hh"
58 #include "XrdOuc/XrdOucProg.hh"
59 #include "XrdOuc/XrdOucSiteName.hh"
60 #include "XrdOuc/XrdOucStream.hh"
61 #include "XrdOuc/XrdOucPList.hh"
62 #include "XrdOuc/XrdOucTList.hh"
64 #include "XrdOuc/XrdOucUtils.hh"
65 #include "XrdSys/XrdSysError.hh"
66 #include "XrdSys/XrdSysHeaders.hh"
67 #include "XrdSys/XrdSysLogger.hh"
68 #include "XrdSys/XrdSysTimer.hh"
69 #include "XrdSys/XrdSysPlatform.hh"
70 #include "XrdSys/XrdSysPthread.hh"
71 #include "XrdSys/XrdSysUtils.hh"
72 
73 using namespace XrdFrc;
74 using namespace XrdFrm;
75 
76 /******************************************************************************/
77 /* L o c a l C l a s s e s */
78 /******************************************************************************/
79 
81 {
82 public:
83 
85 int myFD;
86 int seFD;
87 int BLen;
88 char Buff[32000];
89 
90  XrdFrmConfigSE() : mySem(0), myFD(-1), seFD(-1), BLen(0) {}
92 };
93 
94 /******************************************************************************/
95 /* T h r e a d I n t e r f a c e s */
96 /******************************************************************************/
97 
98 void *XrdFrmConfigMum(void *parg)
99 {
100  XrdFrmConfigSE *theSE = (XrdFrmConfigSE *)parg;
101  char *bp = theSE->Buff;
102  int n, bleft = sizeof(theSE->Buff)-2;
103 
104 // Let the calling thread continue at this point
105 //
106  theSE->mySem.Post();
107 
108 // Read everything we can
109 //
110  do {if ((n = read(theSE->myFD, bp, bleft)) <= 0)
111  {if (!n || (n < 0 && errno != EINTR)) break;}
112  bp += n;
113  } while ((bleft -= n));
114 
115 // Refalgomize everything
116 //
117  dup2(theSE->seFD, STDERR_FILENO);
118  close(theSE->seFD);
119 
120 // Check if we should add a newline character
121 //
122  if (theSE->Buff[bp-(theSE->Buff)-1L] != '\n') *bp++ = '\n';
123  theSE->BLen = bp-(theSE->Buff);
124 
125 // All done
126 //
127  theSE->mySem.Post();
128  return (void *)0;
129 }
130 
131 /******************************************************************************/
132 /* C o n s t r u c t o r */
133 /******************************************************************************/
134 
135 
136 XrdFrmConfig::XrdFrmConfig(SubSys ss, const char *vopts, const char *uinfo)
137  : dfltPolicy("*", -2, -3, 72000, 0)
138 {
139  static XrdVERSIONINFODEF(myVer, XrdFrm, XrdVNUMBER, XrdVERSION);
140  char *sP, buff[128];
141 
142 // Preset all variables with common defaults
143 //
144  myVersion= &myVer;
145  mySite = 0;
146  vOpts = vopts;
147  uInfo = uinfo;
148  ssID = ss;
149  AdminPath= 0;
150  QPath = 0;
151  AdminMode= 0740;
152  xfrMax = 2;
153  xfrMaxIn = 0;
154  xfrMaxOt = 0;
155  FailHold = 3*60*60;
156  IdleHold = 10*60;
157  WaitMigr = 60*60;
158  WaitPurge= 600;
159  WaitQChk = 300;
160  MSSCmd = 0;
161  memset(&xfrCmd, 0, sizeof(xfrCmd));
162  xfrCmd[0].Desc = "copycmd in"; xfrCmd[1].Desc = "copycmd out";
163  xfrCmd[2].Desc = "copycmd in url"; xfrCmd[3].Desc = "copycmd out url";
164  xfrIN = xfrOUT = 0;
165  isAgent = (getenv("XRDADMINPATH") ? 1 : 0);
166  OfsCfg = 0;
167  cmsPath = 0;
168  haveCMS = 0;
169  isOTO = 0;
170  Test = 0;
171  Verbose = 0;
172  pathList = 0;
173  spacList = 0;
174  lockFN = "DIR_LOCK"; // May be ".DIR_LOCK" if hidden
175  cmdHold = -1;
176  cmdFree = 0;
177  pVecNum = 0;
178  pProg = 0;
179  Fix = 0;
180  dirHold = 40*60*60;
181  runOld = 0;
182  runNew = 1;
183  nonXA = 0;
184  doStatPF = 0;
185 
186  myUid = geteuid();
187  myGid = getegid();
188 
189  LocalRoot= RemoteRoot = 0;
190  lcl_N2N = rmt_N2N = the_N2N = 0;
191  N2N_Lib = N2N_Parms = 0;
192  CksMan = 0;
193 
194  xfrFdir = 0;
195  xfrFdln = 0;
196 
197 // Establish our instance name
198 //
200 
201 // Establish default config file
202 //
203  if (!(sP = getenv("XRDCONFIGFN")) || !*sP)
204  ConfigFN = 0;
205  else {ConfigFN = strdup(sP); isAgent = 1;}
206 
207 // Establish directive prefix
208 //
209  if (ss == ssAdmin) {myFrmid = "admin"; myFrmID = "ADMIN";}
210  else if (ss == ssPurg) {myFrmid = "purge"; myFrmID = "PURG";}
211  else if (ss == ssXfr) {myFrmid = "xfr"; myFrmID = "XFR"; }
212  else {myFrmid = "frm"; myFrmID = "FRM";}
213 
214 // Set correct error prefix
215 //
216  strcpy(buff, myFrmid);
217  strcat(buff, "_");
218  Say.SetPrefix(strdup(buff));
219 
220 // Set correct option prefix
221 //
222  strcpy(buff, "frm.");
223  strcat(buff, myFrmid);
224  strcat(buff, ".");
225  pfxDTS = strdup(buff); plnDTS = strlen(buff);
226 }
227 
228 /******************************************************************************/
229 /* Public: C o n f i g u r e */
230 /******************************************************************************/
231 
232 int XrdFrmConfig::Configure(int argc, char **argv, int (*ppf)())
233 {
234  extern XrdOss *XrdOssGetSS(XrdSysLogger *, const char *, const char *,
235  const char *, XrdOucEnv *, XrdVersionInfo &);
236  static XrdNetAddr myAddr(0);
237  XrdFrmConfigSE theSE;
238  int retc, isMum = 0, myXfrMax = -1, NoGo = 0, optBG = 0;
239  const char *temp;
240  char c, buff[1024], *logfn = 0;
241  extern char *optarg;
242  extern int opterr, optopt;
243  int pipeFD[2] = {-1, -1}, bindArg = -1, pureLFN = 0;
244  const char *pidFN = 0;
245 
246 // Obtain the program name (used for logging)
247 //
248  retc = strlen(argv[0]);
249  while(retc--) if (argv[0][retc] == '/') break;
250  myProg = &argv[0][retc+1];
251  vectArg = argv; numcArg = argc;
252 
253 // Process the options
254 //
255  opterr = 0; nextArg = 1;
256  while(nextArg < argc && '-' == *argv[nextArg]
257  && (c=getopt(argc,argv,vOpts)) && (c != (char)-1))
258  { switch(c)
259  {
260  case 'b': optBG = 1;
261  break;
262  case 'c': if (ConfigFN) free(ConfigFN);
263  ConfigFN = strdup(optarg);
264  break;
265  case 'd': Trace.What |= TRACE_ALL;
266  XrdOucEnv::Export("XRDDEBUG","1");
267  break;
268  case 'f': Fix = 1;
269  break;
270  case 'h': Usage(0);
271  break;
272  case 'k': if (!(bindArg = Say.logger()->ParseKeep(optarg)))
273  {Say.Emsg("Config","Invalid -k argument -",optarg);
274  Usage(1);
275  }
276  break;
277  case 'l': if ((pureLFN = *optarg == '=')) optarg++;
278  if (!*optarg)
279  {Say.Emsg("Config", "Logfile name not specified.");
280  Usage(1);
281  }
282  if (logfn) free(logfn);
283  logfn = strdup(optarg);
284  break;
285  case 'm': if (XrdOuca2x::a2i(Say,"max number",optarg,&myXfrMax))
286  Usage(1);
287  break;
288  case 'n': myInst = (!strcmp(optarg,"anon")||!strcmp(optarg,"default")
289  ? 0 : optarg);
290  break;
291  case 'O': isOTO = 1;
292  if (!ConfigOTO(optarg)) Usage(1);
293  break;
294  case 'T': Test = 1;
295  break;
296  case 'v': Verbose = 1;
297  break;
298  case 'w': if (XrdOuca2x::a2tm(Say,"wait time",optarg,&WaitPurge))
299  Usage(1);
300  break;
301  case 's': pidFN = optarg;
302  break;
303  case 'S': mySite= optarg;
304  break;
305  case 'z': Say.logger()->setHiRes();
306  break;
307  default: sprintf(buff,"'%c'", optopt);
308  if (c == ':') Say.Emsg("Config", buff, "value not specified.");
309  else Say.Emsg("Config", buff, "option is invalid");
310  Usage(1);
311  }
312  nextArg = optind;
313  }
314 
315 // Set the site name if we have it at this point
316 //
318 
319 // If we are an agent without a logfile and one is actually defined for the
320 // underlying system, use the directory of the underlying system.
321 //
322  if (ssID != ssAdmin)
323  {if (!logfn)
324  {if (isAgent && (logfn = getenv("XRDLOGDIR")))
325  {snprintf(buff, sizeof(buff), "%s%s%clog", logfn, myFrmid,
326  (isAgent ? 'a' : 'd'));
327  logfn = strdup(buff);
328  }
329  } else if (!pureLFN
330  && !(logfn=XrdOucUtils::subLogfn(Say,myInst,logfn))) _exit(16);
331 
332  // If undercover desired and we are not an agent, do so
333  //
334  if (optBG && !isAgent)
335  {
336 #ifdef WIN32
337  XrdOucUtils::Undercover( Say, !logfn );
338 #else
339  if (pipe( pipeFD ) == -1)
340  {Say.Emsg("Config", errno, "create a pipe"); exit(17);}
341  XrdOucUtils::Undercover( Say, !logfn, pipeFD );
342 #endif
343  }
344 
345  // Bind the log file if we have one
346  //
347  if (logfn)
348  {Say.logger()->AddMsg(XrdBANNER);
349  if (Say.logger()->Bind(logfn, bindArg)) _exit(19);
350  }
351  }
352 
353 // Get the full host name. In theory, we should always get some kind of name.
354 //
355  if (!(myName = myAddr.Name()))
356  {Say.Emsg("Config","Unable to determine host name; execution terminated.");
357  _exit(16);
358  }
359 
360 // Set the Environmental variables to hold some config information
361 // XRDINSTANCE=<pgm> <instance name>@<host name>
362 //
363  snprintf(buff,sizeof(buff), "XRDINSTANCE=%s %s@%s",myProg,
365  putenv(strdup(buff)); // XRDINSTANCE
366  myInstance = strdup(index(buff,'=')+1);
367  XrdOucEnv::Export("XRDHOST", myName);
368  XrdOucEnv::Export("XRDPROG", myProg);
370 
371 // We need to divert the output if we are in admin mode with no logfile
372 //
373  if (!logfn && (ssID == ssAdmin || isOTO) && !Trace.What)
374  isMum = ConfigMum(theSE);
375 
376 // Add final message to the logger
377 //
378  if (logfn)
379  {char msgBuff[2048];
380  strcpy(msgBuff, myInstance); strcat(msgBuff, " running.");
381  Say.logger()->AddMsg(msgBuff);
382  }
383 
384 // Put out the herald
385 //
386  sprintf(buff, "File Residency Manager %s is starting. . .", myProg);
387  Say.Say(0, buff);
388  Say.Say(XrdBANNER);
389 
390 // Process the configuration file.
391 //
392  Say.Say("++++++ ", myInstance, " initialization started.");
393  if (!ConfigFN || !*ConfigFN) ConfigFN = strdup("/opt/xrootd/etc/xrootd.cf");
394  Say.Say("Config using configuration file ", ConfigFN);
395  NoGo = ConfigProc();
396 
397 // Create the correct admin path
398 //
399  if (!NoGo) NoGo = ConfigPaths();
400 
401 // Obtain and configure the oss (lightweight option only)
402 //
403  if (!isAgent)
404  {XrdOucEnv::Export("XRDREDIRECT", "Q");
405  XrdOucEnv::Export("XRDOSSTYPE", myFrmID);
406  if (ssID == ssPurg) XrdOucEnv::Export("XRDOSSCSCAN", "off");
407  if (!NoGo)
409  if (ssID == ssAdmin) loadPI |= XrdOfsConfigPI::theCksLib;
410  if (!OfsCfg->Load(loadPI)) NoGo = 1;
411  else {struct stat Stat;
412  OfsCfg->Plugin(ossFS);
413  OfsCfg->Plugin(CksMan);
414  doStatPF = ossFS->StatPF("/", &Stat) != -ENOTSUP;
415  }
416  }
417  }
418 
419 // Now we can create a home directory for core files and do a cwd to it
420 //
422 
423 // Configure each specific component
424 //
425  if (!NoGo) switch(ssID)
426  {case ssAdmin: NoGo = (ConfigN2N() || ConfigMss());
427  break;
428  case ssPurg: if (!(NoGo = (ConfigMon(0) || ConfigMP("purgeable"))))
429  ConfigPF("frm_purged");
430  break;
431  case ssXfr: if (!isAgent && !(NoGo = (ConfigMon(1) || ConfigXfr())))
432  ConfigPF("frm_xfrd");
433  break;
434  default: break;
435  }
436 
437 // If we have a post-processing routine, invoke it
438 //
439  if (!NoGo && ppf) NoGo = ppf();
440 
441  // if we call this it means that the daemon has forked and we are
442  // in the child process
443 #ifndef WIN32
444  if (optBG && !isAgent)
445  {
446  if (pidFN && !XrdOucUtils::PidFile( Say, pidFN ) )
447  NoGo = 1;
448 
449  int status = NoGo ? 1 : 0;
450  if(write( pipeFD[1], &status, sizeof( status ) )) {};
451  close( pipeFD[1]);
452  }
453 #endif
454 
455 // Print ending message
456 //
457  temp = (NoGo ? " initialization failed." : " initialization completed.");
458  Say.Say("------ ", myInstance, temp);
459 
460 // Finish up mum processing
461 //
462  if (isMum)
463  {close(STDERR_FILENO);
464  theSE.mySem.Wait();
465  if (NoGo && write(STDERR_FILENO, theSE.Buff, theSE.BLen)) {}
466  }
467 
468 // All done
469 //
470  if (OfsCfg) delete OfsCfg;
471  return !NoGo;
472 }
473 
474 /******************************************************************************/
475 /* Public: L o c a l P a t h */
476 /******************************************************************************/
477 
478 int XrdFrmConfig::LocalPath(const char *oldp, char *newp, int newpsz)
479 {
480  int rc = 0;
481 
482  if (lcl_N2N) rc = lcl_N2N->lfn2pfn(oldp, newp, newpsz);
483  else if (((int)strlen(oldp)) >= newpsz) rc = ENAMETOOLONG;
484  else strcpy(newp, oldp);
485  if (rc) {Say.Emsg("Config", rc, "generate local path from", oldp);
486  return 0;
487  }
488  return 1;
489 }
490 
491 /******************************************************************************/
492 /* Public: L o g i c a l P a t h */
493 /******************************************************************************/
494 
495 int XrdFrmConfig::LogicalPath(const char *oldp, char *newp, int newpsz)
496 {
497  int rc = 0;
498 
499  if (lcl_N2N) rc = lcl_N2N->pfn2lfn(oldp, newp, newpsz);
500  else if (((int)strlen(oldp)) >= newpsz) rc = ENAMETOOLONG;
501  else strcpy(newp, oldp);
502  if (rc) {Say.Emsg("Config", rc, "generate logical path from", oldp);
503  return 0;
504  }
505  return 1;
506 }
507 
508 /******************************************************************************/
509 /* Public: N e e d s C T A */
510 /******************************************************************************/
511 
512 int XrdFrmConfig::NeedsCTA(const char *Lfn)
513 {
515 
516  return (XrdOssRPList->Find(Lfn) & XRDEXP_MIGPRG) != 0;
517 }
518 
519 /******************************************************************************/
520 /* Public: P a t h O p t s */
521 /******************************************************************************/
522 
523 unsigned long long XrdFrmConfig::PathOpts(const char *Lfn)
524 {
526 
527  return XrdOssRPList->Find(Lfn);
528 }
529 
530 /******************************************************************************/
531 /* Public: R e m o t e P a t h */
532 /******************************************************************************/
533 
534 int XrdFrmConfig::RemotePath(const char *oldp, char *newp, int newpsz)
535 {
536  int rc = 0;
537 
538  if (rmt_N2N) rc = rmt_N2N->lfn2rfn(oldp, newp, newpsz);
539  else if (((int)strlen(oldp)) >= newpsz) rc = ENAMETOOLONG;
540  else strcpy(newp, oldp);
541  if (rc) {Say.Emsg("Config", rc, "generate rmote path from", oldp);
542  return 0;
543  }
544  return 1;
545 }
546 
547 /******************************************************************************/
548 /* S p a c e */
549 /******************************************************************************/
550 
551 XrdOucTList *XrdFrmConfig::Space(const char *Name, const char *Path)
552 {
553  static XrdOucTList nullEnt;
554  struct VPInfo *vP = VPList;
555  XrdOucTList *tP;
556  char buff[1032];
557  int n;
558 
559 // First find the space entry
560 //
561  while(vP && strcmp(vP->Name, Name)) vP = vP->Next;
562  if (!vP) return 0;
563 
564 // Check if we should find a particular path
565 //
566  if (!Path) return vP->Dir;
567 
568 // Make sure it nds with a slash (it usually does not)
569 //
570  n = strlen(Path)-1;
571  if (Path[n] != '/')
572  {if (n >= (int)sizeof(buff)-2) return &nullEnt;
573  strcpy(buff, Path); buff[n+1] = '/'; buff[n+2] = '\0';
574  Path = buff;
575  }
576 
577 // Find the path
578 //
579  tP = vP->Dir;
580  while(tP && strcmp(Path, tP->text)) tP = tP->next;
581  return (tP ? tP : &nullEnt);
582 }
583 
584 /******************************************************************************/
585 /* S t a t */
586 /******************************************************************************/
587 
588 int XrdFrmConfig::Stat(const char *xLfn, const char *xPfn, struct stat *buff)
589 {
590  return (doStatPF ? ossFS->StatPF(xPfn, buff)
591  : ossFS->Stat (xLfn, buff, XRDOSS_resonly));
592 }
593 
594 /******************************************************************************/
595 /* P r i v a t e F u n c t i o n s */
596 /******************************************************************************/
597 /******************************************************************************/
598 /* Private: C o n f i g C m d */
599 /******************************************************************************/
600 
601 XrdOucMsubs *XrdFrmConfig::ConfigCmd(const char *cname, char *cdata)
602 {
603  XrdOucMsubs *msubs;
604  char *cP;
605 
606  if (!cdata) {Say.Emsg("Config", cname, "not specified."); return 0;}
607 
608  if ((cP = index(cdata, ' '))) *cP = '\0';
609 
610  if (access(cdata, X_OK))
611  {Say.Emsg("Config", errno, "set up", cdata);
612  return 0;
613  }
614  if (cP) *cP = ' ';
615 
616  msubs = new XrdOucMsubs(&Say);
617  if (msubs->Parse(cname, cdata)) return msubs;
618 
619  return 0; // We will exit no need to delete msubs
620 }
621 
622 /******************************************************************************/
623 /* Private: C o n f i g M o n */
624 /******************************************************************************/
625 
626 int XrdFrmConfig::ConfigMon(int isXfr)
627 {
628 // We configure the name2name here
629 //
630  if (ConfigN2N()) return 1;
631 
632 // If we need to configure monitoring, do so here
633 //
635  || (!isXfr && XrdFrmMonitor::monPURGE))
636  {if (!XrdFrmMonitor::Init(myName, myProg, myInst)) return 1;
637  else {if (!XrdFrmMonitor::monSTAGE)
638  {xfrCmd[0].Opts &= ~cmdXPD; xfrCmd[2].Opts &= ~cmdXPD;}
640  {xfrCmd[1].Opts &= ~cmdXPD; xfrCmd[3].Opts &= ~cmdXPD;}
641  }
642  }
643 
644 // All done
645 //
646  return 0;
647 }
648 
649 /******************************************************************************/
650 /* Private: C o n f i g M P */
651 /******************************************************************************/
652 
653 int XrdFrmConfig::ConfigMP(const char *pType)
654 {
655  EPNAME("ConfigMP");
657  XrdOucTList *nP, *tP, *mypList = 0, *expList = 0;
658  char pDir[MAXPATHLEN+1];
659  long long pOpts, xOpt = (*pType == 'm' ? XRDEXP_MIG : XRDEXP_PURGE);
660  int i, NoGo = 0;
661 
662 // Verify that we have an RPList
663 //
664  if (!XrdOssRPList)
665  {Say.Emsg("Config", "Cannot determine", pType, "paths."); return 1;}
666 
667 // Parse the arguments which consist of space names and paths
668 //
669  for (i = nextArg; i < numcArg; i++)
670  {char *psVal = vectArg[i];
671  int psLen = strlen(psVal);
672  if (*psVal == '/')
673  {pOpts = XrdOssRPList->Find(psVal);
674  if (pOpts & xOpt) mypList = InsertPL(mypList, psVal, psLen,
675  (pOpts & XRDEXP_MIGPRG ? 1:0));
676  else {Say.Say("Config", psVal, "not marked", pType); NoGo = 1;}
677  } else {
678  VPInfo *vP = VPList;
679  while(vP && strcmp(psVal, vP->Name)) vP = vP->Next;
680  if (vP) spacList = new XrdOucTList(psVal, psLen, spacList);
681  else {Say.Emsg("Config", "Space", psVal, "not defined.");
682  NoGo = 1;
683  }
684  }
685  }
686 
687 // Check if we should continue
688 //
689  if (NoGo) return 1;
690 
691 // Get correct path list
692 //
693  if (!mypList)
694  {XrdOucPList *fP = XrdOssRPList->First();
695  short sval[4]; // Last two elements are unused
696  while(fP)
697  {sval[0] = (fP->Flag() & XRDEXP_MIGPRG ? 1 : 0);
698  sval[1] = fP->Plen();
699  if (fP->Flag() & xOpt)
700  mypList = new XrdOucTList(fP->Path(), sval, mypList);
701  else
702  expList = new XrdOucTList(fP->Path(), sval, expList);
703  fP = fP->Next();
704  }
705 // if (!mypList)
706  // {Say.Emsg("Config", "No", pType, "paths found."); return 1;}
707  }
708 
709 // Now we need to construct a search list which may include excludes which
710 // hapen when we get nested subtrees with different options
711 //
712  while((tP = mypList))
713  {if (!LocalPath(tP->text, pDir, sizeof(pDir))) NoGo = 1;
714  else {pathList = new VPInfo(pDir, int(tP->sval[0]), pathList);
715  DEBUG("Will scan " <<(tP->sval[0]?"r/w: ":"r/o: ") <<pDir);
716  nP = expList;
717  while(nP)
718  {if (!strncmp(tP->text, nP->text, tP->sval[1]))
719  InsertXD(nP->text);
720  nP = nP->next;
721  }
722  mypList = tP->next; delete tP;
723  }
724  }
725 
726 // Delete the explist
727 //
728  while((tP = expList)) {expList = tP->next; delete tP;}
729 
730 // For purging, make sure we have at least one path to purge
731 //
732  if (xOpt == XRDEXP_PURGE && !pathList)
733  {Say.Emsg("Config","No purgeable paths specified!");
734  NoGo = 1;
735  }
736 
737 // The oss would have already set NORCREATE and NOCHECK for all stageable paths.
738 // But now, we must also off the R/O flag on every purgeable and stageable path
739 // to prevent oss complaints. This needs to be deferred to here because we need
740 // to know which paths are actually r/o and r/w.
741 //
742  if (!NoGo)
743  {XrdOucPList *fp = XrdOssRPList->First();
744  while(fp)
745  {if (fp->Flag() & (XRDEXP_STAGE | XRDEXP_PURGE))
746  fp->Set(fp->Flag() & ~XRDEXP_NOTRW);
747  fp = fp->Next();
748  }
749  }
750 
751 // All done now
752 //
753  return NoGo;
754 }
755 
756 /******************************************************************************/
757 /* Private: C o n f i g M s s */
758 /******************************************************************************/
759 
760 int XrdFrmConfig::ConfigMss()
761 {
762  if (MSSCmd)
763  {MSSProg = new XrdOucProg(&Say);
764  if (MSSProg->Setup(MSSCmd)) return 1;
765  }
766  return 0;
767 }
768 
769 /******************************************************************************/
770 /* Private: C o n f i g M u m */
771 /******************************************************************************/
772 
773 int XrdFrmConfig::ConfigMum(XrdFrmConfigSE &theSE)
774 {
775  class Recover
776  {public:
777  int fdvec[2];
778  int stdErr;
779  Recover() : stdErr(-1) {fdvec[0] = -1; fdvec[1] = -1;}
780  ~Recover() {if (fdvec[0] >= 0) close(fdvec[0]);
781  if (fdvec[1] >= 0) close(fdvec[1]);
782  if (stdErr >= 0) {dup2(stdErr, STDERR_FILENO);
783  close(stdErr);
784  }
785  }
786  };
787  Recover FD;
788  pthread_t tid;
789  int rc;
790 
791 // Create a pipe
792 //
793  if (pipe(FD.fdvec) < 0) return 0;
794  fcntl(FD.fdvec[0], F_SETFD, FD_CLOEXEC);
795 
796 // Save the current standard error FD
797 //
798  if ((FD.stdErr = dup(STDERR_FILENO)) < 0) return 0;
799 
800 // Now hook-up the pipe to standard error
801 //
802  if (dup2(FD.fdvec[1], STDERR_FILENO) < 0) return 0;
803  close(FD.fdvec[1]); FD.fdvec[1] = -1;
804 
805 // Prepare arguments to the thread that will suck up the output
806 //
807  theSE.myFD = FD.fdvec[0];
808  theSE.seFD = FD.stdErr;
809 
810 // Start a thread to read all of the output
811 //
812  if ((rc = XrdSysThread::Run(&tid, XrdFrmConfigMum, (void *)&theSE,
813  XRDSYSTHREAD_BIND, "Mumify"))) return 0;
814 
815 // Now fixup to return correctly
816 //
817  theSE.mySem.Wait();
818  FD.fdvec[0] = -1;
819  FD.stdErr = -1;
820  return 1;
821 }
822 
823 /******************************************************************************/
824 /* Private: C o n f i g N 2 N */
825 /******************************************************************************/
826 
827 int XrdFrmConfig::ConfigN2N()
828 {
829  XrdOucN2NLoader n2nLoader(&Say,ConfigFN,N2N_Parms,LocalRoot,RemoteRoot);
830 
831 // Check if we really need to configure this
832 //
833  if (!N2N_Lib && !LocalRoot && !RemoteRoot) return 0;
834 
835 // Get the plugin
836 //
837  if (!(the_N2N = n2nLoader.Load(N2N_Lib, *myVersion))) return 1;
838 
839 // Optimize the local case
840 //
841  if (N2N_Lib) rmt_N2N = lcl_N2N = the_N2N;
842  else {if (LocalRoot) lcl_N2N = the_N2N;
843  if (RemoteRoot) rmt_N2N = the_N2N;
844  }
845 
846 // All done
847 //
848  return 0;
849 }
850 
851 /******************************************************************************/
852 /* C o n f i g O T O */
853 /******************************************************************************/
854 
855 int XrdFrmConfig::ConfigOTO(char *Parms)
856 {
857  char *Comma;
858 
859 // Pick up free argument
860 //
861  if ((Comma = index(Parms, ','))) *Comma = '\0';
862  if (XrdOuca2x::a2sp(Say, "free value", Parms, &cmdFree, 1)) return 0;
863 
864 // Pick up hold argument
865 //
866  if (!Comma || !(*(Comma+1))) return 1;
867  if (*(Comma+1) == ',') Comma++;
868  else {Parms = Comma+1;
869  if ((Comma = index(Parms, ','))) *Comma = '\0';
870  if (XrdOuca2x::a2i(Say,"hold value",Parms,&cmdHold,0)) return 0;
871  }
872 
873 // All done
874 //
875  return 1;
876 }
877 
878 /******************************************************************************/
879 /* C o n f i g P a t h s */
880 /******************************************************************************/
881 
882 int XrdFrmConfig::ConfigPaths()
883 {
884  char *xPath, buff[MAXPATHLEN];
885  const char *insName;
886 
887 // Get the directory for the meta information. If we don't get it from the
888 // config, then use XRDADMINPATH which already contains the instance name.
889 //
890 // Set the directory where the meta information is to go
891 // XRDADMINPATH already contains the instance name
892 
893  if ((xPath = AdminPath)) insName = myInst;
894  else if ((xPath = getenv("XRDADMINPATH"))) insName = 0;
895  else {xPath = (char *)"/tmp/"; insName = myInst;}
896 
897 // Do post initialization for the cnsd
898 //
899  if (XrdFrmCns::Init(myFrmid, xPath, insName)) return 1;
900 
901 // Establish the cmsd notification object. We need to do this using an
902 // unqualified admin path that we determined above.
903 //
904  if (haveCMS)
905  cmsPath = new XrdNetCmsNotify(&Say,xPath,insName,XrdNetCmsNotify::isServ);
906 
907 // Create the admin directory if it does not exists and set QPath
908 //
909  if (!(xPath = XrdFrcUtils::makePath(insName, xPath, AdminMode))) return 1;
910  if (AdminPath) free(AdminPath);
911  AdminPath = xPath;
912  if (!QPath) QPath = AdminPath;
913 
914 // Create the purge stop file name
915 //
916  strcpy(buff, Config.AdminPath); strcat(buff, "STOPPURGE");
917  StopPurge = strdup(buff);
918 
919 // All done
920 //
921  return 0;
922 }
923 
924 /******************************************************************************/
925 /* C o n f i g P F */
926 /******************************************************************************/
927 
928 void XrdFrmConfig::ConfigPF(const char *pFN)
929 {
930  static const int Mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH;
931  const char *ppP = (PidPath ? PidPath : "/tmp");
932  char buff[1032], data[24];
933  int pfFD, n;
934 
935 // Construct pidfile name
936 //
937  if (myInst) snprintf(buff, sizeof(buff), "%s/%s/%s.pid", ppP, myInst, pFN);
938  else sprintf(buff, "%s/%s.pid", ppP, pFN);
939 
940 // Open the pidfile creating it if necessary
941 //
942  if ((pfFD = open(buff, O_WRONLY|O_CREAT|O_TRUNC, Mode)) < 0)
943  {Say.Emsg("Config",errno,"open",buff); return;}
944 
945 // Write out our pid
946 //
947  n = sprintf(data, "%lld", static_cast<long long>(getpid()));
948  if (write(pfFD, data, n) < 0) Say.Emsg("Config",errno,"writing",buff);
949  close(pfFD);
950 }
951 
952 /******************************************************************************/
953 /* Private: C o n f i g P r o c */
954 /******************************************************************************/
955 
956 int XrdFrmConfig::ConfigProc()
957 {
958  char *var;
959  int cfgFD, retc, mbok, NoGo = 0;
960  XrdOucEnv myEnv;
961  XrdOucStream cfgFile(&Say, myInstance, &myEnv, "=====> ");
962 
963 // Allocate a plugin library configurator
964 //
965  OfsCfg = XrdOfsConfigPI::New(ConfigFN, &cfgFile, &Say, myVersion);
966  if (!OfsCfg) return 1;
967 
968 // Try to open the configuration file.
969 //
970  if ( (cfgFD = open(ConfigFN, O_RDONLY, 0)) < 0)
971  {Say.Emsg("Config", errno, "open config file", ConfigFN);
972  return 1;
973  }
974  cfgFile.Attach(cfgFD); cFile = &cfgFile;
975  static const char *cvec[] = { "*** frm server config:", 0 };
976  cfgFile.Capture(cvec);
977 
978 // Now start reading records until eof.
979 //
980  while((var = cFile->GetMyFirstWord()))
981  {mbok = 0;
982  if (!strncmp(var, pfxDTS, plnDTS)) {var += plnDTS; mbok = 1;}
983  if(ConfigXeq(var, mbok)) {cfgFile.Echo(); NoGo = 1;}
984  }
985 
986 // Now check if any errors occurred during file i/o
987 //
988  if ((retc = cfgFile.LastError()))
989  NoGo = Say.Emsg("Config", retc, "read config file", ConfigFN);
990  cfgFile.Close(); cFile = 0;
991 
992 // Return final return code
993 //
994  return NoGo;
995 }
996 
997 /******************************************************************************/
998 /* Prvate: C o n f i g X e q */
999 /******************************************************************************/
1000 
1001 #define PARSEPI(x) return !OfsCfg->Parse(XrdOfsConfigPI:: x);
1002 
1003 int XrdFrmConfig::ConfigXeq(char *var, int mbok)
1004 {
1005 
1006 // Process common items to all subsystems
1007 //
1008  if (!strcmp(var, "all.adminpath" )) return xapath();
1009  if (!strcmp(var, "all.pidpath" )) return Grab(var, &PidPath, 0);
1010  if (!strcmp(var, "all.manager" )) {haveCMS = 1; return 0;}
1011  if (!strcmp(var, "frm.all.cnsd" )) return xcnsd();
1012 
1013 // Process directives specific to each subsystem
1014 //
1015  if (ssID == ssAdmin)
1016  {
1017  if (!strcmp(var, "frm.xfr.qcheck")) return xqchk();
1018  if (!strcmp(var, "ofs.ckslib" )) PARSEPI(theCksLib);
1019  if (!strcmp(var, "ofs.osslib" )) PARSEPI(theOssLib);
1020  if (!strcmp(var, "ofs.xattrlib" )) PARSEPI(theAtrLib);
1021 // if (!strcmp(var, "oss.cache" )){hasCache = 1; // runOld
1022 // return xspace(0,0);
1023 // }
1024  if (!strcmp(var, "oss.localroot" )) return Grab(var, &LocalRoot, 0);
1025  if (!strcmp(var, "oss.namelib" )) return xnml();
1026  if (!strcmp(var, "oss.remoteroot")) return Grab(var, &RemoteRoot, 0);
1027  if (!strcmp(var, "oss.space" )) return xspace();
1028  if (!strcmp(var, "xrootd.chksum" )) return xcks();
1029 // if (!strcmp(var, "oss.mssgwcmd" )) return Grab(var, &MSSCmd, 0);
1030 // if (!strcmp(var, "oss.msscmd" )) return Grab(var, &MSSCmd, 0);
1031  if (!strcmp(var, "oss.xfr" )) return xxfr();
1032  }
1033 
1034  if (ssID == ssXfr)
1035  {
1036  if (!strcmp(var, "qcheck" )) return xqchk();
1037  if (isAgent) return 0; // Server-oriented directives
1038 
1039  if (!strcmp(var, "all.sitename" )) return xsit();
1040  if (!strcmp(var, "ofs.osslib" )) PARSEPI(theOssLib);
1041  if (!strcmp(var, "ofs.xattrlib" )) PARSEPI(theAtrLib);
1042  if (!strcmp(var, "oss.cache" )) return xspace(0,0);
1043  if (!strcmp(var, "oss.localroot" )) return Grab(var, &LocalRoot, 0);
1044  if (!strcmp(var, "oss.namelib" )) return xnml();
1045  if (!strcmp(var, "oss.remoteroot")) return Grab(var, &RemoteRoot, 0);
1046  if (!strcmp(var, "oss.xfr" )) return xxfr();
1047  if (!strcmp(var, "frm.all.monitor"))return xmon();
1048 
1049  if (!strcmp(var, "copycmd" )) return xcopy();
1050  if (!strcmp(var, "copymax" )) return xcmax();
1051  if (!strcmp(var, "oss.space" )) return xspace();
1052 
1053  if (!strncmp(var, "migr.", 5)) // xfr.migr
1054  {char *vas = var+5;
1055  if (!strcmp(vas, "idlehold" )) return xitm("idle time", IdleHold);
1056  if (!strcmp(vas, "waittime" )) return xitm("migr wait", WaitMigr);
1057  }
1058  }
1059 
1060  if (ssID == ssPurg)
1061  {
1062  if (!strcmp(var, "all.sitename" )) return xsit();
1063  if (!strcmp(var, "dirhold" )) return xdpol();
1064  if (!strcmp(var, "oss.cache" )) return xspace(1,0);
1065  if (!strcmp(var, "oss.localroot" )) return Grab(var, &LocalRoot, 0);
1066  if (!strcmp(var, "ofs.osslib" )) PARSEPI(theOssLib);
1067  if (!strcmp(var, "ofs.xattrlib" )) PARSEPI(theAtrLib);
1068  if (!strcmp(var, "policy" )) return xpol();
1069  if (!strcmp(var, "polprog" )) return xpolprog();
1070  if (!strcmp(var, "oss.space" )) return xspace(1);
1071  if (!strcmp(var, "waittime" )) return xitm("purge wait",WaitPurge);
1072  if (!strcmp(var, "frm.all.monitor"))return xmon();
1073  }
1074 
1075  // No match found, complain.
1076  //
1077  if (!mbok) cFile->noEcho();
1078  else {Say.Say("Config warning: ignoring unknown frm directive '",var,"'.");
1079  cFile->Echo();
1080  }
1081  return 0;
1082 }
1083 
1084 /******************************************************************************/
1085 /* Private: C o n f i g X f r */
1086 /******************************************************************************/
1087 
1088 int XrdFrmConfig::ConfigXfr()
1089 {
1090  int i, isBad, ioOK[2] = {0};
1091 
1092 // Configure the name2name library and migratable paths and mass storage
1093 //
1094  isBad = ConfigMP("migratable") || ConfigMss();
1095 
1096 // Make sure
1097 
1098 // Configure all of the transfer commands
1099 //
1100  for (i = 0; i < 4; i++)
1101  {if (xfrCmd[i].theCmd)
1102  {if ((xfrCmd[i].theVec=ConfigCmd(xfrCmd[i].Desc, xfrCmd[i].theCmd)))
1103  ioOK[i%2] = 1;
1104  else isBad = 1;
1105  }
1106  }
1107 
1108 // Verify that we can actually do something
1109 //
1110  if (!(ioOK[0] | ioOK[1]))
1111  {Say.Emsg("Config",
1112  "No copy commands specified; execution is meaningless!");
1113  return 1;
1114  }
1115 
1116 // Verify that input copies are OK
1117 //
1118  if (!(xfrIN = ioOK[0]))
1119  Say.Emsg("Config", "Input copy command not specified; "
1120  "incoming transfers prohibited!");
1121 
1122 // Verify that input copies are OK
1123 //
1124  if (!(xfrOUT = ioOK[1]))
1125  Say.Emsg("Config", "Output copy command not specified; "
1126  "outgoing transfers prohibited!");
1127 
1128 // All done
1129 //
1130  return isBad;
1131 }
1132 
1133 /******************************************************************************/
1134 /* Private: g e t T i m e */
1135 /******************************************************************************/
1136 
1137 int XrdFrmConfig::getTime(const char *emsg, const char *item, int *val,
1138  int minv, int maxv)
1139 {
1140  if (strcmp(item, "forever"))
1141  return XrdOuca2x::a2tm(Say, emsg, item, val, minv, maxv);
1142  *val = -1;
1143  return 0;
1144 }
1145 
1146 /******************************************************************************/
1147 /* Private: G r a b */
1148 /******************************************************************************/
1149 
1150 int XrdFrmConfig::Grab(const char *var, char **Dest, int nosubs)
1151 {
1152  char myVar[1024], buff[2048], *val;
1153  XrdOucEnv *myEnv = 0;
1154 
1155 // Copy the variable name as this may change because it points to an
1156 // internal buffer in Config. The vagaries of effeciency.
1157 //
1158  strlcpy(myVar, var, sizeof(myVar));
1159  var = myVar;
1160 
1161 // If substitutions allowed then we need to grab a single token else grab
1162 // the remainder of the line but suppress substitutions.
1163 //
1164  if (!nosubs) val = cFile->GetWord();
1165  else {myEnv = cFile->SetEnv(0);
1166  if (!cFile->GetRest(buff, sizeof(buff)))
1167  {Say.Emsg("Config", "arguments too long for", var);
1168  cFile->SetEnv(myEnv);
1169  return 1;
1170  }
1171  val = buff;
1172  cFile->SetEnv(myEnv);
1173  }
1174 
1175 // At this point, make sure we have a value
1176 //
1177  if (!val || !(*val))
1178  {if (nosubs < 0) Say.Emsg("Config", "no arguments for", var);
1179  else Say.Emsg("Config", "no value for directive", var);
1180  return 1;
1181  }
1182 
1183 // Set the value. Either this is a simple string or a compund string
1184 //
1185  if (*Dest) {free(*Dest); Dest = 0;}
1186  if (nosubs < 0)
1187  {char fBuff[2048];
1188  int n = strlen(myVar);
1189  if (n + strlen(val) > sizeof(fBuff)-1)
1190  {Say.Emsg("Config", "arguments too long for", var); return 1;}
1191  strcpy(fBuff, myVar); *(fBuff+n) = ' '; strcpy(fBuff+n+1, val);
1192  *Dest = strdup(fBuff);
1193  } else *Dest = strdup(val);
1194 
1195 // All done
1196 //
1197  return 0;
1198 }
1199 
1200 /******************************************************************************/
1201 /* Private: I n s e r t P L */
1202 /******************************************************************************/
1203 
1204 XrdOucTList *XrdFrmConfig::InsertPL(XrdOucTList *pL, const char *Path,
1205  int Plen, int isRW)
1206 {
1207  short sval[4] = {static_cast<short>(isRW), static_cast<short>(Plen)};
1208  XrdOucTList *pP = 0, *tP = pL;
1209 
1210 // Find insertion point
1211 //
1212  while(tP && tP->sval[1] < Plen) {pP = tP; tP = tP->next;}
1213 
1214 // Insert new element
1215 //
1216  if (pP) pP->next = new XrdOucTList(Path, sval, tP);
1217  else pL = new XrdOucTList(Path, sval, tP);
1218 
1219 // Return the new list
1220 //
1221  return pL;
1222 }
1223 
1224 /******************************************************************************/
1225 /* Private: I n s e r t X D */
1226 /******************************************************************************/
1227 
1228 void XrdFrmConfig::InsertXD(const char *Path)
1229 {
1230  EPNAME("InsertXD");
1231  char pBuff[MAXPATHLEN], *pP;
1232  int n = strlen(Path);
1233 
1234 // Make sure this does not end with a slash
1235 //
1236  strcpy(pBuff, Path);
1237  pP = pBuff + n - 1;
1238  while(*pP == '/' && pP != pBuff) {*pP-- = '\0'; n--;}
1239 
1240 // Insert this directory into the exclude list for the current path
1241 //
1242  pathList->Dir = new XrdOucTList(pBuff, n, pathList->Dir);
1243  DEBUG("Excluding '" <<pBuff <<"'");
1244 }
1245 
1246 /******************************************************************************/
1247 /* Private: U s a g e */
1248 /******************************************************************************/
1249 
1250 void XrdFrmConfig::Usage(int rc)
1251 {
1252  std::cerr <<"\nUsage: " <<myProg <<" " <<uInfo <<std::endl;
1253  _exit(rc);
1254 }
1255 
1256 /******************************************************************************/
1257 /* Private: x a p a t h */
1258 /******************************************************************************/
1259 
1260 /* Function: xapath
1261 
1262  Purpose: To parse the directive: adminpath <path> [group]
1263 
1264  <path> the path of the FIFO to use for admin requests.
1265 
1266  group allows group access to the admin path
1267 
1268  Output: 0 upon success or !0 upon failure.
1269 */
1270 
1271 int XrdFrmConfig::xapath()
1272 {
1273  char *pval, *val;
1274  mode_t mode = S_IRWXU;
1275 
1276 // Get the path
1277 //
1278  pval = cFile->GetWord();
1279  if (!pval || !pval[0])
1280  {Say.Emsg("Config", "adminpath not specified"); return 1;}
1281 
1282 // Make sure it's an absolute path
1283 //
1284  if (*pval != '/')
1285  {Say.Emsg("Config", "adminpath not absolute"); return 1;}
1286 
1287 // Record the path
1288 //
1289  if (AdminPath) free(AdminPath);
1290  AdminPath = strdup(pval);
1291 
1292 // Get the optional access rights
1293 //
1294  if ((val = cFile->GetWord()) && val[0])
1295  {if (!strcmp("group", val)) mode |= S_IRWXG;
1296  else {Say.Emsg("Config", "invalid admin path modifier -", val);
1297  return 1;
1298  }
1299  }
1300  AdminMode = mode;
1301  return 0;
1302 }
1303 
1304 /******************************************************************************/
1305 /* Private: x c k s */
1306 /******************************************************************************/
1307 
1308 /* Function: xcks
1309 
1310  Purpose: To parse the directive: chksum [max <n>] <type> <path>
1311 
1312  max maximum number of simultaneous jobs
1313  <type> algorithm of checksum (e.g., md5)
1314  <path> the path of the program performing the checksum
1315 
1316  Output: 0 upon success or !0 upon failure.
1317 */
1318 
1319 int XrdFrmConfig::xcks()
1320 {
1321  char *palg;
1322 
1323 // Get the algorithm name and the program implementing it
1324 //
1325  while ((palg = cFile->GetWord()) && *palg != '/')
1326  {if (strcmp(palg, "max")) break;
1327  if (!(palg = cFile->GetWord()))
1328  {Say.Emsg("Config", "chksum max not specified"); return 1;}
1329  }
1330 
1331 // Verify we have an algoritm
1332 //
1333  if (!palg || *palg == '/')
1334  {Say.Emsg("Config", "chksum algorithm not specified"); return 1;}
1335 
1336 // Set default checksum
1337 //
1338  OfsCfg->DefaultCS(palg);
1339  return 0;
1340 }
1341 
1342 /******************************************************************************/
1343 /* Private: x c n s d */
1344 /******************************************************************************/
1345 
1346 /* Function: cnsd
1347 
1348  Purpose: To parse the directive: cnsd {auto | ignore | require} [Options]
1349 
1350  Options: [apath <path>]
1351 
1352  auto use the cnsd if present, ignore otherwise.
1353  ignore never use the cnsd, even if present.
1354  require always use the cnsd. If not present, wait for it.
1355  apath The path specified on the -a option of the cnsd.
1356 
1357  Output: 0 upon success or !0 upon failure.
1358 */
1359 int XrdFrmConfig::xcnsd()
1360 {
1361  int cnsMode = 0;
1362  char *val, *cnsPath = 0;
1363  struct cnsdopts {const char *opname; int opval;} cnsopt[] =
1364  {
1365  {"auto", XrdFrmCns::cnsAuto},
1366  {"ignore", XrdFrmCns::cnsIgnore},
1367  {"require", XrdFrmCns::cnsRequire}
1368  };
1369  int i, numopts = sizeof(cnsopt)/sizeof(struct cnsdopts);
1370 
1371 // Pick up required parameter
1372 //
1373  if (!(val = cFile->GetWord()))
1374  {Say.Emsg("Config", "cnsd mode not specified"); return 1;}
1375 
1376 // Now match that option
1377 //
1378  for (i = 0; i < numopts; i++)
1379  if (!strcmp(val,cnsopt[i].opname)) {cnsMode = cnsopt[i].opval; break;}
1380  if (i >= numopts)
1381  {Say.Emsg("Config", "invalid cnsd mode '",val,"'."); return 1;}
1382 
1383 // Check if we have an apath now
1384 //
1385  if ((val = cFile->GetWord()))
1386  {if (strcmp("apath", val))
1387  {Say.Emsg("Config", "invalid cnsd option '",val,"'."); return 1;}
1388  if (!(cnsPath = cFile->GetWord()))
1389  {Say.Emsg("Config", "cnsd apath not specified"); return 1;}
1390  }
1391 
1392 // Preset the cnsd options and return
1393 //
1394  return XrdFrmCns::Init(cnsPath, cnsMode);
1395 }
1396 
1397 /******************************************************************************/
1398 /* Private: x c o p y */
1399 /******************************************************************************/
1400 
1401 /* Function: copycmd
1402 
1403  Purpose: To parse the directive: copycmd [Options] cmd [args]
1404 
1405  Options: [in] [noalloc] [out] [rmerr] [stats] [timeout <sec>] [url] [xpd]
1406 
1407  in use command for incoming copies.
1408  noalloc do not pre-allocate space for incoming copies.
1409  out use command for outgoing copies.
1410  rmerr remove incoming file when copy ends with an error.
1411  Default unless noalloc is specified.
1412  stats print transfer statistics in the log.
1413  timeout how long the cmd can run before it is killed.
1414  url use command for url-based transfers.
1415  xpd extend monitoring with program data.
1416 
1417  Output: 0 upon success or !0 upon failure.
1418 */
1419 int XrdFrmConfig::xcopy()
1420 { int cmdIO[2] = {0,0}, TLim=0, Stats=0, hasMDP=0, cmdUrl=0, noAlo=0, rmErr=0;
1421  int monPD = 0;
1422  char *val, *theCmd = 0;
1423  struct copyopts {const char *opname; int *oploc;} cpopts[] =
1424  {
1425  {"in", &cmdIO[0]},
1426  {"out", &cmdIO[1]},
1427  {"noalloc",&noAlo},
1428  {"rmerr", &rmErr},
1429  {"stats", &Stats},
1430  {"timeout",&TLim},
1431  {"url", &cmdUrl},
1432  {"xpd", &monPD}
1433  };
1434  int i, n, numopts = sizeof(cpopts)/sizeof(struct copyopts);
1435 
1436 // Pick up options
1437 //
1438  val = cFile->GetWord();
1439  while(val && *val != '/')
1440  {for (i = 0; i < numopts; i++)
1441  {if (!strcmp(val,cpopts[i].opname))
1442  {if (strcmp("timeout", val)) {*cpopts[i].oploc = 1; break;}
1443  else if (!xcopy(TLim)) return 1;
1444  }
1445  }
1446  if (i >= numopts)
1447  Say.Say("Config warning: ignoring invalid copycmd option '",val,"'.");
1448  val = cFile->GetWord();
1449  }
1450 
1451 // Pick up the program
1452 //
1453  if (!val || !*val)
1454  {Say.Emsg("Config", "copy command not specified"); return 1;}
1455  if (Grab(val, &theCmd, -1)) return 1;
1456 
1457 // Find if $MDP is present here
1458 //
1459  if (!cmdIO[0] && !cmdIO[1]) cmdIO[0] = cmdIO[1] = 1;
1460  if (cmdIO[1]) hasMDP = (strstr(theCmd, "$MDP") != 0);
1461 
1462 // Initialzie the appropriate command structures
1463 //
1464  n = (cmdUrl ? 3 : 1);
1465  i = 1;
1466  do {if (cmdIO[i])
1467  {if (xfrCmd[n].theCmd) free(xfrCmd[n].theCmd);
1468  xfrCmd[n].theCmd = strdup(theCmd);
1469  if (Stats) xfrCmd[n].Opts |= cmdStats;
1470  if (monPD) xfrCmd[n].Opts |= cmdXPD;
1471  if (hasMDP) xfrCmd[n].Opts |= cmdMDP;
1472  if (rmErr) xfrCmd[n].Opts |= cmdRME;
1473  if (noAlo) xfrCmd[n].Opts &=~cmdAlloc;
1474  else xfrCmd[n].Opts |= cmdAlloc;
1475  xfrCmd[n].TLimit = TLim;
1476  }
1477  n--;
1478  } while(i--);
1479 
1480 // All done
1481 //
1482  free(theCmd);
1483  return 0;
1484 }
1485 
1486 /******************************************************************************/
1487 
1488 int XrdFrmConfig::xcopy(int &TLim)
1489 {
1490  char *val;
1491 
1492  if (!(val = cFile->GetWord()) || !*val)
1493  {Say.Emsg("Config", "copy command timeout not specified"); return 0;}
1494  if (XrdOuca2x::a2tm(Say,"copy command timeout", val, &TLim, 0)) return 0;
1495  return 1;
1496 }
1497 
1498 /******************************************************************************/
1499 /* Private: x c m a x */
1500 /******************************************************************************/
1501 
1502 /* Function: copymax
1503 
1504  Purpose: To parse the directive: copymax <num> | split <inmax> <outmax>
1505 
1506  <num> maximum number of simultaneous transfers
1507  <inmax> maximum number of simultaneous transfers in (get|stage)
1508  <outmax> maximum number of simultaneous transfers out (put|migr)
1509 
1510  Output: 0 upon success or !0 upon failure.
1511 */
1512 int XrdFrmConfig::xcmax()
1513 { char *val;
1514 
1515  if (!(val = cFile->GetWord()))
1516  {Say.Emsg("Config", "copymax value not specified"); return 1;}
1517 
1518  if (!strcmp(val, "split"))
1519  {if (!(val = cFile->GetWord()))
1520  {Say.Emsg("Config", "copymax in value not specified"); return 1;}
1521  if (XrdOuca2x::a2i(Say,"copymax in", val, &xfrMaxIn, 1)) return 1;
1522  if (!(val = cFile->GetWord()))
1523  {Say.Emsg("Config", "copymax out value not specified"); return 1;}
1524  if (XrdOuca2x::a2i(Say,"copymax out", val, &xfrMaxOt, 1)) return 1;
1525  xfrMax = xfrMaxIn + xfrMaxOt;
1526  } else {
1527  if (XrdOuca2x::a2i(Say, "copymax", val, &xfrMax, 1)) return 1;
1528  xfrMaxIn = xfrMaxOt = 0;
1529  }
1530  return 0;
1531 }
1532 
1533 
1534 /******************************************************************************/
1535 /* Private: x d p o l */
1536 /******************************************************************************/
1537 
1538 
1539 /* Function: xdpol
1540 
1541  Purpose: To parse the directive: dirpolicy <sec>
1542 
1543  <sec> number of seconds to hold an empty directory or the
1544  word 'forever'.
1545 
1546  Output: 0 upon success or !0 upon failure.
1547 */
1548 int XrdFrmConfig::xdpol()
1549 { int htm;
1550  char *val;
1551 
1552  if (!(val = cFile->GetWord()))
1553  {Say.Emsg("Config", "dirpolicy hold time not specified"); return 1;}
1554  if (XrdOuca2x::a2tm(Say,"dirpolicy hold time", val, &htm, 0)) return 1;
1555  dirHold = htm;
1556  return 0;
1557 }
1558 
1559 /******************************************************************************/
1560 /* Private: x i t m */
1561 /******************************************************************************/
1562 
1563 /* Function: xitm
1564 
1565  Purpose: To parse the directive: xxxxtime <sec>
1566 
1567  <sec> number of seconds applicable to the directive.
1568 
1569  Output: 0 upon success or !0 upon failure.
1570 */
1571 int XrdFrmConfig::xitm(const char *What, int &tDest)
1572 { int itime;
1573  char *val;
1574 
1575  if (!(val = cFile->GetWord()))
1576  {Say.Emsg("Config", What, "not specified"); return 1;}
1577  if (XrdOuca2x::a2tm(Say, What, val, &itime)) return 1;
1578  tDest = itime;
1579  return 0;
1580 }
1581 
1582 /******************************************************************************/
1583 /* x m o n */
1584 /******************************************************************************/
1585 
1586 /* Function: xmon
1587 
1588  Purpose: Parse directive: monitor [ident <sec>] dest [Events] <host:port>
1589 
1590  Events: [migr] [purge] [stage]
1591 
1592  ident <sec> time (seconds, M, H) between ident records.
1593  dest specified routing information. Up to two dests
1594  may be specified.
1595  migr monitors file migr operations
1596  purge monitors file purge operations
1597  stage monitors file stage operations
1598  <host:port> where monitor records are to be sentvia UDP.
1599 
1600  Output: 0 upon success or !0 upon failure. Ignored by master.
1601 */
1602 int XrdFrmConfig::xmon()
1603 { char *val, *cp, *monDest[2] = {0, 0};
1604  int i, monIdent=3600, monMode[2] = {0, 0};
1605 
1606  while((val = cFile->GetWord()))
1607 
1608  { if (!strcmp("ident", val))
1609  {if (!(val = cFile->GetWord()))
1610  {Say.Emsg("Config", "monitor ident value not specified");
1611  return 1;
1612  }
1613  if (XrdOuca2x::a2tm(Say,"monitor ident",val,
1614  &monIdent,0)) return 1;
1615  }
1616  else break;
1617  }
1618 
1619  if (!val) {Say.Emsg("Config", "monitor dest not specified"); return 1;}
1620 
1621  for (i = 0; i < 2; i++)
1622  {if (strcmp("dest", val)) break;
1623  while((val = cFile->GetWord()))
1624  if (!strcmp("stage",val)) monMode[i] |= XROOTD_MON_STAGE;
1625  else if (!strcmp("migr", val)) monMode[i] |= XROOTD_MON_MIGR;
1626  else if (!strcmp("purge",val)) monMode[i] |= XROOTD_MON_PURGE;
1627  else break;
1628  if (!val) {Say.Emsg("Config","monitor dest value not specified");
1629  return 1;
1630  }
1631  if (!(cp = index(val, (int)':')) || !atoi(cp+1))
1632  {Say.Emsg("Config","monitor dest port missing or invalid in",val);
1633  return 1;
1634  }
1635  monDest[i] = strdup(val);
1636  if (!(val = cFile->GetWord())) break;
1637  }
1638 
1639  if (val)
1640  {if (!strcmp("dest", val))
1641  Say.Emsg("Config", "Warning, a maximum of two dest values allowed.");
1642  else Say.Emsg("Config", "Warning, invalid monitor option", val);
1643  }
1644 
1645 // Make sure dests differ
1646 //
1647  if (monDest[0] && monDest[1] && !strcmp(monDest[0], monDest[1]))
1648  {Say.Emsg("Config", "Warning, monitor dests are identical.");
1649  monMode[0] |= monMode[1]; monMode[1] = 0;
1650  free(monDest[1]); monDest[1] = 0;
1651  }
1652 
1653 // Don't bother doing any more if monitoring is not enabled
1654 //
1655  if (!monMode[0] && !monMode[1]) return 0;
1656 
1657 // Set the monitor defaults
1658 //
1659  XrdFrmMonitor::Defaults(monDest[0],monMode[0],monDest[1],monMode[1],monIdent);
1660  return 0;
1661 }
1662 
1663 /******************************************************************************/
1664 /* Private: x n m l */
1665 /******************************************************************************/
1666 
1667 /* Function: xnml
1668 
1669  Purpose: To parse the directive: namelib <path> [<parms>]
1670 
1671  <path> the path of the filesystem library to be used.
1672  <parms> optional parms to be passed
1673 
1674  Output: 0 upon success or !0 upon failure.
1675 */
1676 
1677 int XrdFrmConfig::xnml()
1678 {
1679  char *val, parms[1024];
1680 
1681 // Get the path
1682 //
1683  if (!(val = cFile->GetWord()) || !val[0])
1684  {Say.Emsg("Config", "namelib not specified"); return 1;}
1685 
1686 // Record the path
1687 //
1688  if (N2N_Lib) free(N2N_Lib);
1689  N2N_Lib = strdup(val);
1690 
1691 // Record any parms
1692 //
1693  if (!cFile->GetRest(parms, sizeof(parms)))
1694  {Say.Emsg("Config", "namelib parameters too long"); return 1;}
1695  if (N2N_Parms) free(N2N_Parms);
1696  N2N_Parms = (*parms ? strdup(parms) : 0);
1697  return 0;
1698 }
1699 
1700 /******************************************************************************/
1701 /* Private: x p o l */
1702 /******************************************************************************/
1703 
1704 /* Function: xpol
1705 
1706  Purpose: To parse the directive: policy {*|sname} {nopurge|min} max]] [opts]
1707 
1708  * The default policy for all spaces.
1709 
1710  sname The policy to apply for this space. Defaults apply for
1711  unspecified values. To make sure the specified default
1712  is used, the '*' entry must appear first.
1713 
1714  nopurge Turns off purging.
1715 
1716  min% Minimum free space; purge starts when less available.
1717  Can be specified as a percentage (i.e., n%) or an
1718  absolute size value (with k, m, g, t suffix).
1719  Default: 5%
1720 
1721  max% Maximum free space; purge stops when more available.
1722  Must be specified in the same units as min and must be
1723  greater than min.
1724  Default: min% + 2 or min * 1.2
1725 
1726  opts: hold <tm> Time to hold a file before it can be purged. The <tm>
1727  can be a suffixed number or 'forever'.
1728  Default: 20h (20*3600)s
1729 
1730  polprog Invoke the policy program to do final determination.
1731 
1732 
1733  Output: 0 upon success or !0 upon failure.
1734 */
1735 int XrdFrmConfig::xpol()
1736 {
1737  Policy *pP = &dfltPolicy;
1738  char *val, sname[XrdOssSpace::minSNbsz];
1739  long long minP = dfltPolicy.minFree, maxP = dfltPolicy.maxFree;
1740  int Hold = dfltPolicy.Hold, Ext = 0;
1741  struct purgeopts {const char *opname; int isTime; int *oploc;} pgopts[] =
1742  {
1743  {"polprog", -1, &Ext},
1744  {"hold", 1, &Hold}
1745  };
1746  int i, rc, numopts = sizeof(pgopts)/sizeof(struct purgeopts);
1747 
1748 // Get the space name
1749 //
1750  if (!(val = cFile->GetWord()))
1751  {Say.Emsg("Config", "space name not specified"); return 1;}
1752  if (strlen(val) >= sizeof(sname))
1753  {Say.Emsg("Config", "space name '", val, "' too long"); return 1;}
1754 
1755 // If we have an equal sign then an external policy is being defined
1756 //
1757  if (!strcmp("=", val)) return xpolprog();
1758  strcpy(sname, val);
1759 
1760 // The next item may be minimum percentage followed by a maximum percentage
1761 // Otherwise, it may be 'nopurge'.
1762 //
1763  if ( (val = cFile->GetWord()) && isdigit(*val))
1764  {if ( XrdOuca2x::a2sp(Say, "min free", val, &minP, 1)) return 1;
1765  if ((val = cFile->GetWord()) && isdigit(*val))
1766  {if (XrdOuca2x::a2sp(Say, "max free", val, &maxP, 1)) return 1;
1767  if ((minP < 0 && maxP >= 0) || (minP >= 0 && maxP < 0))
1768  {Say.Emsg("Config", "purge min/max may not differ in type.");
1769  return 1;
1770  }
1771  if (XRDABS(minP) >= XRDABS(maxP))
1772  {Say.Emsg("Config", "purge min must be < max value."); return 1;}
1773  val = cFile->GetWord();
1774  } else {
1775  if (minP < 0) maxP = (minP < -99 ? -100 : minP - 1);
1776  else maxP = (minP * 120LL)/100LL;
1777  }
1778  } else if (val && !strcmp(val, "nopurge"))
1779  {minP = maxP = 0;
1780  if ((val = cFile->GetWord()))
1781  {Say.Say("Config warning: ignoring extraneous policy option '",val,"'.");
1782  val = 0;
1783  }
1784  }
1785 
1786 // Pick up the remining options
1787 //
1788  while(val)
1789  {for (i = 0; i < numopts; i++) if (!strcmp(val,pgopts[i].opname)) break;
1790  if (i >= numopts)
1791  {Say.Say("Config warning: ignoring invalid policy option '",val,"'.");
1792  val = cFile->GetWord();
1793  continue;
1794  }
1795  if (pgopts[i].isTime < 0) *(pgopts[i].oploc) = 1;
1796  else {if (!(val = cFile->GetWord()))
1797  {Say.Emsg("Config", "policy", pgopts[i].opname,
1798  "argument not specified.");
1799  return 1;
1800  }
1801  rc = (pgopts[i].isTime
1802  ? getTime( "purge value",val,pgopts[i].oploc,0)
1803  : XrdOuca2x::a2i (Say,"purge value",val,pgopts[i].oploc,0));
1804  if (rc) return 1;
1805  }
1806  val = cFile->GetWord();
1807  }
1808 
1809 // If an external policy applies, it must be present
1810 //
1811  if (Ext && !pProg)
1812  {Say.Emsg("Config", "External policy has not been pre-defined.");
1813  return 1;
1814  }
1815 
1816 // Add this policy definition
1817 //
1818  while(pP && strcmp(pP->Sname, sname)) pP = pP->Next;
1819  if (pP) {pP->minFree=minP; pP->maxFree=maxP; pP->Hold=Hold; pP->Ext=Ext;}
1820  else {pP = new Policy(sname, minP, maxP, Hold, Ext);
1821  pP->Next = dfltPolicy.Next; dfltPolicy.Next = pP;
1822  }
1823  return 0;
1824 }
1825 
1826 /******************************************************************************/
1827 /* Private: x p o l p r o g */
1828 /******************************************************************************/
1829 
1830 /* Function: xpolprog
1831 
1832  Purpose: To parse the directive: policy = [vars] |<prog> [args]
1833 
1834  Where:
1835  = Defines an external policy via a program, as follows:
1836 
1837  vars The information to ship to the program via stdin:
1838  atime - access time
1839  ctime - create time
1840  fname - the filename itself
1841  fsize - file size
1842  fspace - free space
1843  mtime - modify time
1844  pfn - physical file name
1845  sname - space name
1846  tspace - total space
1847 
1848  |<prog> The name of the policy program to receive the info.
1849 
1850  args Optional program arguments (substituted), up to 8.
1851 
1852  Output: 0 upon success or !0 upon failure.
1853 */
1854 int XrdFrmConfig::xpolprog()
1855 {
1856  char *val, pBuff[4096], *pbP = pBuff;
1857  struct polopts {const char *opname; int opval;} plopts[] =
1858  {
1859  {"atime", PP_atime },
1860  {"ctime", PP_ctime },
1861  {"fname", PP_fname },
1862  {"fsize", PP_fsize },
1863  {"fspace", PP_fspace},
1864  {"mtime", PP_mtime },
1865  {"pfn", PP_pfn },
1866  {"sname", PP_sname },
1867  {"tspace", PP_tspace},
1868  {"usage", PP_usage}
1869  };
1870  int i, n, numopts = sizeof(plopts)/sizeof(struct polopts);
1871 
1872 // Get the first token
1873 //
1874  if (!(val = cFile->GetWord()))
1875  {Say.Emsg("Config", "policy program not specified"); return 1;}
1876  pVecNum = 0;
1877 
1878 // Pick up the remining options
1879 //
1880  while(val && *val != '|')
1881  {for (i = 0; i < numopts; i++) if (!strcmp(val,plopts[i].opname)) break;
1882  if (i >= numopts)
1883  {Say.Say("Config warning: ignoring invalid policy option '",val,"'.");
1884  val = cFile->GetWord();
1885  continue;
1886  }
1887  if (pVecNum >= pVecMax)
1888  {Say.Emsg("Config", "To many policy program variables specified.");
1889  return 1;
1890  }
1891  pVec[pVecNum++] = static_cast<char>(plopts[i].opval);
1892  val = cFile->GetWord();
1893  }
1894 
1895 // Pick up the program
1896 //
1897  if (val) val++;
1898  if (val && !(*val)) val = cFile->GetWord();
1899  if (!val)
1900  {Say.Emsg("Config", "policy program not specified."); return 1;}
1901  i = strlen(val);
1902  if (i >= (int)sizeof(pBuff)-8)
1903  {Say.Emsg("Config", "policy program name is too long."); return 1;}
1904  strcpy(pBuff, val); pbP = pBuff+i; *(pbP+1) = '\0';
1905 
1906 // Now get any optional arguments
1907 //
1908  n = sizeof(pBuff) - i - 1;
1909  if (!cFile->GetRest(pbP+1, n))
1910  {Say.Emsg("Config", "policy program args are too long."); return 1;}
1911  if (*(pbP+1)) *pbP = ' ';
1912 
1913 // Record the program
1914 //
1915  if (pProg) free(pProg);
1916  pProg = strdup(pBuff);
1917  return 0;
1918 }
1919 
1920 /******************************************************************************/
1921 /* Private: x q c h k */
1922 /******************************************************************************/
1923 
1924 /* Function: xqchk
1925 
1926  Purpose: To parse the directive: qcheck <sec> <path>
1927 
1928  <sec> number of seconds between forced queue checks. This is
1929  optional is <path> is specified.
1930  <path> the absolute location of the queue directory.
1931 
1932  Output: 0 upon success or !0 upon failure.
1933 */
1934 int XrdFrmConfig::xqchk()
1935 { int itime;
1936  char *val;
1937 
1938 // Get the next token, we must have one here
1939 //
1940  if (!(val = cFile->GetWord()))
1941  {Say.Emsg("Config", "qcheck time not specified"); return 1;}
1942 
1943 // If not a path, then it must be a time
1944 //
1945  if (*val != '/')
1946  {if (XrdOuca2x::a2tm(Say, "qcheck time", val, &itime)) return 1;
1947  WaitQChk = itime;
1948  if (!(val = cFile->GetWord())) return 0;
1949  }
1950 
1951 // The next token has to be an absolute path if it is present at all
1952 //
1953  if (*val != '/')
1954  {Say.Emsg("Config", "qcheck path not absolute"); return 1;}
1955  if (QPath) free(QPath);
1956  QPath = strdup(val);
1957  return 0;
1958 }
1959 
1960 /******************************************************************************/
1961 /* x s i t */
1962 /******************************************************************************/
1963 
1964 /* Function: xsit
1965 
1966  Purpose: To parse directive: sitename <name>
1967 
1968  <name> is the 1- to 15-character site name to be included in
1969  monitoring information. This can also come from the
1970  command line -N option. The first such name is used.
1971 
1972  Output: 0 upon success or 1 upon failure.
1973 */
1974 
1975 int XrdFrmConfig::xsit()
1976 {
1977  char *val;
1978 
1979  if (!(val = cFile->GetWord()))
1980  {Say.Emsg("Config", "sitename value not specified"); return 1;}
1981 
1982  if (mySite) Say.Emsg("Config", "sitename already specified, using '",
1983  mySite, "'.");
1984  else mySite = XrdOucSiteName::Set(val);
1985  return 0;
1986 }
1987 
1988 /******************************************************************************/
1989 /* x s p a c e */
1990 /******************************************************************************/
1991 
1992 /* Function: xspace
1993 
1994  Purpose: To parse the directive: space <group> <path>
1995 
1996  <group> logical group name for the filesystem.
1997  <path> path to the filesystem.
1998 
1999  Output: 0 upon success or !0 upon failure.
2000 */
2001 
2002 int XrdFrmConfig::xspace(int isPrg, int isXA)
2003 {
2004  char *val, *pfxdir, *sfxdir;
2005  char grp[XrdOssSpace::minSNbsz], fn[MAXPATHLEN], dn[MAXNAMLEN];
2006  int i, k, rc, pfxln, cnum = 0;
2007  struct dirent *dp;
2008  struct stat buff;
2009  DIR *DFD;
2010 
2011  if (!(val = cFile->GetWord()))
2012  {Say.Emsg("Config", "space name not specified"); return 1;}
2013  if (strlen(val) >= (int)sizeof(grp))
2014  {Say.Emsg("Config","excessively long space name - ",val); return 1;}
2015  strcpy(grp, val);
2016 
2017  if (!(val = cFile->GetWord()))
2018  {Say.Emsg("Config", "path to space not specified"); return 1;}
2019 
2020 // Ignore the space assignment version of the directive (new in 4.8).
2021 //
2022  if (!strcmp(val, "assign") || !strcmp(val, "default")) return 0;
2023 
2024  k = strlen(val);
2025  if (k >= (int)(sizeof(fn)-1) || val[0] != '/' || k < 2)
2026  {Say.Emsg("Config", "invalid space path - ", val); return 1;}
2027  strcpy(fn, val);
2028 
2029  if (!isXA && (val = cFile->GetWord()))
2030  {if (strcmp("xa", val))
2031  {Say.Emsg("Config","invalid cache option - ",val); return 1;}
2032  else isXA = 1;
2033  }
2034 
2035 // We only support xa caches now
2036 //
2037  if (!isXA)
2038  {Say.Emsg("Config","old-style spaces using oss.cache are no longer "
2039  "supported!");
2040  return 1;
2041  }
2042 
2043  if (fn[k-1] != '*')
2044  {for (i = k-1; i; i--) if (fn[i] != '/') break;
2045  fn[i+1] = '/'; fn[i+2] = '\0';
2046  xspaceBuild(grp, fn, isXA);
2047  return 0;
2048  }
2049 
2050  for (i = k-1; i; i--) if (fn[i] == '/') break;
2051  i++; strcpy(dn, &fn[i]); fn[i] = '\0';
2052  sfxdir = &fn[i]; pfxdir = dn; pfxln = strlen(dn)-1;
2053  if (!(DFD = opendir(fn)))
2054  {Say.Emsg("Config", errno, "open space directory", fn); return 1;}
2055 
2056  errno = 0;
2057  while((dp = readdir(DFD)))
2058  {if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")
2059  || (pfxln && strncmp(dp->d_name, pfxdir, pfxln)))
2060  continue;
2061  strcpy(sfxdir, dp->d_name);
2062  if (stat(fn, &buff)) break;
2063  if ((buff.st_mode & S_IFMT) == S_IFDIR)
2064  {val = sfxdir + strlen(sfxdir) - 1;
2065  if (*val++ != '/') {*val++ = '/'; *val = '\0';}
2066  xspaceBuild(grp, fn, isXA);
2067  cnum++;
2068  }
2069  errno = 0;
2070  }
2071 
2072  if ((rc = errno))
2073  Say.Emsg("Config", errno, "process space directory", fn);
2074  else if (!cnum) Say.Say("Config warning: no space directories found in ",val);
2075 
2076  closedir(DFD);
2077  return rc != 0;
2078 }
2079 
2080 void XrdFrmConfig::xspaceBuild(char *grp, char *fn, int isxa)
2081 {
2082  struct VPInfo *nP = VPList;
2083  XrdOucTList *tP;
2084 
2085  while(nP && strcmp(nP->Name, grp)) nP = nP->Next;
2086 
2087  if (!nP) VPList = nP = new VPInfo(grp, 0, VPList);
2088 
2089  tP = nP->Dir;
2090  while(tP && strcmp(tP->text, fn)) tP = tP->next;
2091  if (!tP) nP->Dir = new XrdOucTList(fn, isxa, nP->Dir);
2092 
2093  if (!isxa) nonXA = 1;
2094 }
2095 
2096 /******************************************************************************/
2097 /* x x f r */
2098 /******************************************************************************/
2099 
2100 /* Function: xxfr
2101 
2102  Purpose: To parse the directive: xfr [deny <sec>] [fdir <path>] [keep <sec>]
2103 
2104  deny number of seconds that a fail file rejects a request
2105  fdir base directory where fail files are kept
2106  keep number of seconds to keep queued requests (ignored)
2107 
2108  Output: 0 upon success or !0 upon failure.
2109 */
2110 
2111 int XrdFrmConfig::xxfr()
2112 {
2113  static const int maxfdln = 256;
2114  const char *wantParm = 0;
2115  char *val;
2116  int htime = 3*60*60;
2117 
2118  while((val = cFile->GetWord())) // deny | keep
2119  { if (!strcmp("deny", val))
2120  {wantParm = "xfr deny";
2121  if ((val = cFile->GetWord())) // keep time
2122  {if (XrdOuca2x::a2tm(Say,wantParm,val,&htime,0)) return 1;
2123  FailHold = htime, wantParm=0;
2124  }
2125  }
2126  else if (!strcmp("fdir", val))
2127  {wantParm = "xfr fdir";
2128  if ((val = cFile->GetWord())) // fdir path
2129  {if (xfrFdir) free(xfrFdir);
2130  xfrFdln = strlen(val);
2131  if (xfrFdln > maxfdln)
2132  {Say.Emsg("Config","xfr fdir path too long");
2133  xfrFdir = 0; xfrFdln = 0; return 1;
2134  }
2135  xfrFdir = strdup(val);
2136  wantParm = 0;
2137  }
2138  }
2139  else if (!strcmp("keep", val))
2140  {wantParm = "xfr keep";
2141  if ((val = cFile->GetWord())) // keep time
2142  {if (XrdOuca2x::a2tm(Say,wantParm,val,&htime,0)) return 1;
2143  wantParm=0;
2144  }
2145  }
2146  else break;
2147  };
2148 
2149  if (!val && wantParm)
2150  {Say.Emsg("Config", wantParm, "value not specified"); return 1;}
2151 
2152  return 0;
2153 }
#define DEBUG(x)
Definition: XrdBwmTrace.hh:54
#define EPNAME(x)
Definition: XrdBwmTrace.hh:56
#define PARSEPI(x)
void * XrdFrmConfigMum(void *parg)
Definition: XrdFrmConfig.cc:98
#define XROOTD_MON_PURGE
#define XROOTD_MON_MIGR
#define XROOTD_MON_STAGE
#define XrdBANNER
Definition: XrdInfo.hh:38
int optopt
int optind
XrdOss * XrdOssGetSS(XrdSysLogger *Logger, const char *config_fn, const char *OssLib, const char *OssParms, XrdOucEnv *envP, XrdVersionInfo &urVer)
Definition: XrdOssApi.cc:98
XrdOucPListAnchor * XrdOssRPList
Definition: XrdOssConfig.cc:80
#define XRDOSS_resonly
Definition: XrdOss.hh:486
#define XRDEXP_NOTRW
Definition: XrdOucExport.hh:45
#define XRDEXP_PURGE
Definition: XrdOucExport.hh:62
#define XRDEXP_MIGPRG
Definition: XrdOucExport.hh:86
#define XRDEXP_STAGE
Definition: XrdOucExport.hh:52
#define XRDEXP_MIG
Definition: XrdOucExport.hh:54
int stat(const char *path, struct stat *buf)
struct dirent * readdir(DIR *dirp)
int open(const char *path, int oflag,...)
int fcntl(int fd, int cmd,...)
ssize_t write(int fildes, const void *buf, size_t nbyte)
int access(const char *path, int amode)
int closedir(DIR *dirp)
ssize_t read(int fildes, void *buf, size_t nbyte)
DIR * opendir(const char *path)
#define close(a)
Definition: XrdPosix.hh:43
int Mode
XrdOucString Path
int emsg(int rc, char *msg)
size_t strlcpy(char *dst, const char *src, size_t sz)
#define XRDABS(x)
#define XRDSYSTHREAD_BIND
#define TRACE_ALL
Definition: XrdTrace.hh:35
static char * makePath(const char *iName, const char *Path, int Mode)
Definition: XrdFrcUtils.cc:102
static const int cnsAuto
Definition: XrdFrmCns.hh:43
static const int cnsIgnore
Definition: XrdFrmCns.hh:45
static const int cnsRequire
Definition: XrdFrmCns.hh:47
static int Init(const char *aPath, int Opts)
Definition: XrdFrmCns.cc:167
char Buff[32000]
Definition: XrdFrmConfig.cc:88
XrdSysSemaphore mySem
Definition: XrdFrmConfig.cc:84
struct XrdFrmConfig::Cmd xfrCmd[4]
XrdOucTList * Space(const char *Name, const char *Path=0)
int LogicalPath(const char *oldp, char *newp, int newpsz)
int NeedsCTA(const char *Lfn)
XrdOfsConfigPI * OfsCfg
Definition: XrdFrmConfig.hh:88
XrdNetCmsNotify * cmsPath
Definition: XrdFrmConfig.hh:92
static const int cmdStats
Definition: XrdFrmConfig.hh:81
static const int cmdAlloc
Definition: XrdFrmConfig.hh:79
struct XrdFrmConfig::VPInfo * VPList
const char * myInst
Definition: XrdFrmConfig.hh:59
XrdOucProg * MSSProg
Definition: XrdFrmConfig.hh:70
XrdCks * CksMan
Definition: XrdFrmConfig.hh:89
char * StopPurge
Definition: XrdFrmConfig.hh:68
static const int cmdRME
Definition: XrdFrmConfig.hh:83
int RemotePath(const char *oldp, char *newp, int newpsz)
char * myInstance
Definition: XrdFrmConfig.hh:67
XrdOss * ossFS
Definition: XrdFrmConfig.hh:91
const char * mySite
Definition: XrdFrmConfig.hh:60
VPInfo * pathList
static const int cmdXPD
Definition: XrdFrmConfig.hh:82
unsigned long long PathOpts(const char *Lfn)
XrdFrmConfig(SubSys ss, const char *vopts, const char *uinfo)
const char * myFrmID
Definition: XrdFrmConfig.hh:62
const char * Desc
Definition: XrdFrmConfig.hh:73
XrdOucTList * spacList
const char * myFrmid
Definition: XrdFrmConfig.hh:61
int Stat(const char *xLfn, const char *xPfn, struct stat *buff)
char ** vectArg
char pVec[pVecMax]
long long cmdFree
Definition: XrdFrmConfig.hh:95
static const int cmdMDP
Definition: XrdFrmConfig.hh:80
static const int pVecMax
XrdOucName2Name * the_N2N
Definition: XrdFrmConfig.hh:90
int LocalPath(const char *oldp, char *newp, int newpsz)
Policy dfltPolicy
char * PidPath
Definition: XrdFrmConfig.hh:66
const char * myProg
Definition: XrdFrmConfig.hh:57
char * AdminPath
Definition: XrdFrmConfig.hh:64
int Configure(int argc, char **argv, int(*ppf)())
const char * lockFN
Definition: XrdFrmConfig.hh:63
const char * myName
Definition: XrdFrmConfig.hh:58
static char monPURGE
static int Init(const char *iHost, const char *iProg, const char *iName)
static char monMIGR
static void Defaults(char *dest1, int m1, char *dest2, int m2, int iTime)
static char monSTAGE
const char * Name(const char *eName=0, const char **eText=0)
static const int isServ
bool Plugin(XrdAccAuthorize *&piP)
Get Authorization plugin.
static XrdOfsConfigPI * New(const char *cfn, XrdOucStream *cfgP, XrdSysError *errP, XrdVersionInfo *verP=0, XrdSfsFileSystem *sfsP=0)
void DefaultCS(const char *alg)
bool Load(int what, XrdOucEnv *envP=0)
@ theOssLib
Oss plugin.
@ theCksLib
Checksum manager plugin.
@ theAtrLib
Extended attribute plugin.
static const int minSNbsz
Definition: XrdOssSpace.hh:45
virtual int StatPF(const char *path, struct stat *buff, int opts)
Definition: XrdOss.cc:107
virtual int Stat(const char *path, struct stat *buff, int opts=0, XrdOucEnv *envP=0)=0
static int Export(const char *Var, const char *Val)
Definition: XrdOucEnv.cc:188
int Parse(const char *oname, char *msg)
Definition: XrdOucMsubs.cc:100
virtual int lfn2pfn(const char *lfn, char *buff, int blen)=0
virtual int pfn2lfn(const char *pfn, char *buff, int blen)=0
virtual int lfn2rfn(const char *lfn, char *buff, int blen)=0
XrdOucPList * First()
Definition: XrdOucPList.hh:132
unsigned long long Find(const char *pathname)
Definition: XrdOucPList.hh:112
XrdOucPList * Next()
Definition: XrdOucPList.hh:44
void Set(int aval)
Definition: XrdOucPList.hh:51
char * Path()
Definition: XrdOucPList.hh:45
unsigned long long Flag()
Definition: XrdOucPList.hh:42
int Setup(const char *prog, XrdSysError *errP=0, int(*Proc)(XrdOucStream *, char **, int)=0)
Definition: XrdOucProg.cc:296
static const char * Set(const char *name, int maxlen=15)
char * GetMyFirstWord(int lowcase=0)
char * GetWord(int lowcase=0)
XrdOucEnv * SetEnv(XrdOucEnv *newEnv)
int GetRest(char *theBuf, int Blen, int lowcase=0)
static void Capture(const char **cVec=0, bool linefeed=true)
XrdOucTList * next
Definition: XrdOucTList.hh:45
char * text
Definition: XrdOucTList.hh:46
static const char * InstName(int TranOpt=0)
Definition: XrdOucUtils.cc:732
static bool PidFile(XrdSysError &eDest, const char *path)
static void makeHome(XrdSysError &eDest, const char *inst)
Definition: XrdOucUtils.cc:850
static void Undercover(XrdSysError &eDest, int noLog, int *pipeFD=0)
static char * subLogfn(XrdSysError &eDest, const char *inst, char *logfn)
static int a2sp(XrdSysError &, const char *emsg, const char *item, long long *val, long long minv=-1, long long maxv=-1)
Definition: XrdOuca2x.cc:213
static int a2i(XrdSysError &, const char *emsg, const char *item, int *val, int minv=-1, int maxv=-1)
Definition: XrdOuca2x.cc:45
static int a2tm(XrdSysError &, const char *emsg, const char *item, int *val, int minv=-1, int maxv=-1)
Definition: XrdOuca2x.cc:288
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
Definition: XrdSysError.cc:95
void Say(const char *text1, const char *text2=0, const char *txt3=0, const char *text4=0, const char *text5=0, const char *txt6=0)
Definition: XrdSysError.cc:141
XrdSysLogger * logger(XrdSysLogger *lp=0)
Definition: XrdSysError.hh:141
const char * SetPrefix(const char *prefix)
Definition: XrdSysError.hh:160
void setHiRes()
Set log file timstamp to high resolution (hh:mm:ss.uuuu).
void AddMsg(const char *msg)
int Bind(const char *path, int lfh=0)
int ParseKeep(const char *arg)
static int Run(pthread_t *, void *(*proc)(void *), void *arg, int opts=0, const char *desc=0)
XrdVERSIONINFODEF(myVersion, cmsclient, XrdVNUMBER, XrdVERSION)
XrdSysError Say
XrdSysTrace Trace("cms")
XrdCmsConfig Config
XrdPosixStats Stats
Definition: XrdPosixFile.cc:64