XRootD
Loading...
Searching...
No Matches
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"
48#include "XrdNet/XrdNetAddr.hh"
51#include "XrdOss/XrdOss.hh"
52#include "XrdOss/XrdOssSpace.hh"
53#include "XrdOuc/XrdOuca2x.hh"
54#include "XrdOuc/XrdOucEnv.hh"
56#include "XrdOuc/XrdOucMsubs.hh"
58#include "XrdOuc/XrdOucProg.hh"
61#include "XrdOuc/XrdOucPList.hh"
62#include "XrdOuc/XrdOucTList.hh"
64#include "XrdOuc/XrdOucUtils.hh"
65#include "XrdSys/XrdSysError.hh"
68#include "XrdSys/XrdSysTimer.hh"
71#include "XrdSys/XrdSysUtils.hh"
72
73using namespace XrdFrc;
74using namespace XrdFrm;
75
76/******************************************************************************/
77/* L o c a l C l a s s e s */
78/******************************************************************************/
79
81{
82public:
83
85int myFD;
86int seFD;
87int BLen;
88char 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
98void *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
136XrdFrmConfig::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
232int 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;
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
478int 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
495int 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
512int 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
523unsigned 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
534int 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
551XrdOucTList *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
588int 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
601XrdOucMsubs *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
626int 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
653int 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)
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)
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
760int 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
773int 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
827int 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
855int 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
882int 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)
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
928void 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
956int 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
1003int 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
1088int 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
1137int 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
1150int 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
1204XrdOucTList *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
1228void 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
1250void 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
1271int 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
1319int 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*/
1359int 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*/
1419int 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
1488int 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*/
1512int 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;
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*/
1548int 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*/
1571int 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*/
1602int 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
1677int 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*/
1735int 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*/
1854int 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*/
1934int 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
1975int 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
2002int 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
2080void 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
2111int 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)
#define EPNAME(x)
struct stat Stat
Definition XrdCks.cc:49
XrdOucPup XrdCmsParser::Pup & Say
void * XrdFrmConfigMum(void *parg)
#define PARSEPI(x)
#define XROOTD_MON_PURGE
#define XROOTD_MON_MIGR
#define XROOTD_MON_STAGE
static XrdVERSIONINFODEF(compiledVer, XrdHttpProtocolTest, XrdVNUMBER, XrdVERSION)
#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
#define XRDOSS_resonly
Definition XrdOss.hh:486
#define XRDEXP_NOTRW
#define XRDEXP_PURGE
#define XRDEXP_MIGPRG
#define XRDEXP_STAGE
#define XRDEXP_MIG
#define access(a, b)
Definition XrdPosix.hh:44
#define close(a)
Definition XrdPosix.hh:48
#define write(a, b, c)
Definition XrdPosix.hh:115
#define opendir(a)
Definition XrdPosix.hh:78
#define open
Definition XrdPosix.hh:76
#define closedir(a)
Definition XrdPosix.hh:50
#define stat(a, b)
Definition XrdPosix.hh:101
#define readdir(a)
Definition XrdPosix.hh:86
#define read(a, b, c)
Definition XrdPosix.hh:82
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)
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]
XrdSysSemaphore mySem
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
XrdNetCmsNotify * cmsPath
static const int cmdStats
static const int cmdAlloc
struct XrdFrmConfig::VPInfo * VPList
const char * myInst
XrdOucProg * MSSProg
XrdCks * CksMan
static const int cmdRME
int RemotePath(const char *oldp, char *newp, int newpsz)
char * myInstance
XrdOss * ossFS
const char * mySite
VPInfo * pathList
static const int cmdXPD
unsigned long long PathOpts(const char *Lfn)
XrdFrmConfig(SubSys ss, const char *vopts, const char *uinfo)
const char * myFrmID
const char * Desc
XrdOucTList * spacList
const char * myFrmid
int Stat(const char *xLfn, const char *xPfn, struct stat *buff)
char pVec[pVecMax]
long long cmdFree
static const int cmdMDP
static const int pVecMax
XrdOucName2Name * the_N2N
int LocalPath(const char *oldp, char *newp, int newpsz)
const char * myProg
int Configure(int argc, char **argv, int(*ppf)())
const char * lockFN
const char * myName
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
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:170
int Parse(const char *oname, char *msg)
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()
unsigned long long Find(const char *pathname)
char * Path()
void Set(int aval)
XrdOucPList * Next()
unsigned long long Flag()
int Setup(const char *prog, XrdSysError *errP=0, int(*Proc)(XrdOucStream *, char **, int)=0)
static const char * Set(const char *name, int maxlen=15)
XrdOucEnv * SetEnv(XrdOucEnv *newEnv)
char * GetMyFirstWord(int lowcase=0)
char * GetWord(int lowcase=0)
int GetRest(char *theBuf, int Blen, int lowcase=0)
static void Capture(const char **cVec=0, bool linefeed=true)
XrdOucTList * next
static const char * InstName(int TranOpt=0)
static bool PidFile(XrdSysError &eDest, const char *path)
static void makeHome(XrdSysError &eDest, const char *inst)
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
static int Run(pthread_t *, void *(*proc)(void *), void *arg, int opts=0, const char *desc=0)
XrdOucTrace Trace
XrdFrmConfig Config
XrdPosixStats Stats