XRootD
XrdOssArcConfig.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d O s s A r c C o n f i g . c c */
4 /* */
5 /* (c) 2023 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 /******************************************************************************/
31 /* i n c l u d e s */
32 /******************************************************************************/
33 
34 #include <set>
35 #include <string>
36 #include <vector>
37 
38 #include <string.h>
39 #include <unistd.h>
40 #include <sys/param.h>
41 #include <sys/stat.h>
42 #include <sys/types.h>
43 
44 #include "Xrd/XrdScheduler.hh"
45 
46 #include "XrdOss/XrdOss.hh"
47 
48 #include "XrdOssArc/XrdOssArc.hh"
54 
55 #include "XrdOuc/XrdOuca2x.hh"
56 #include "XrdOuc/XrdOucECMsg.hh"
57 #include "XrdOuc/XrdOucEnv.hh"
59 #include "XrdOuc/XrdOucProg.hh"
60 #include "XrdOuc/XrdOucStream.hh"
61 #include "XrdOuc/XrdOucUtils.hh"
62 
63 #include "XrdSys/XrdSysError.hh"
64 #include "XrdSys/XrdSysPlatform.hh"
65 
66 /******************************************************************************/
67 /* G l o b a l O b j e c t s */
68 /******************************************************************************/
69 
70 namespace XrdOssArcGlobals
71 {
72 extern XrdOss* ossP;
73 
74 extern XrdScheduler* schedP;
75 
76 extern XrdSysError Elog;
77 
78 extern XrdSysTrace ArcTrace;
79 
81 
82  thread_local XrdOucECMsg ecMsg("[ossArc]");
83 }
84 using namespace XrdOssArcGlobals;
85 
86 /******************************************************************************/
87 /* L o c a l O b j e c t s */
88 /******************************************************************************/
89 
90 namespace
91 {
92 std::set<std::string> bkpScopes;
93 }
94 
95 /******************************************************************************/
96 /* C o n s t r u c t o r */
97 /******************************************************************************/
98 
100 {
101 // Establish the defaults
102 //
103  BkpUtilPath = strdup("XrdOssArc_BkpUtils");
104  BkpUtilName = BkpUtilPath;
105 
106  PrepArcPath = 0;
107  PrepArcName = 0;
108 
109  PostArcPath = 0;
110  PostArcName = 0;
111 
112  ArchiverPath= strdup("XrdOssArc_Archiver");
113  ArchiverName= ArchiverPath;
114  ArchiverSave= 0;
115 
116  MssComPath = strdup("XrdOssArc_MssCom");
117  MssComName = MssComPath;
118  MssComCmd = 0;
119  MssComRoot = 0;
120 
121  arcvPathLFN = strdup("/archive/");
122  arcvPathLEN = strlen(arcvPathLFN);
123  bkupPathLFN = strdup("/backup/");
124  bkupPathLEN = strlen(bkupPathLFN);
125  dsetPathLFN = strdup("/dataset/");
126  dsetRepoPFN = 0;
127 
128  const char*atmp;
129  if ((atmp = getenv("XRDADMINPATH")))
130  {std::string as = atmp;
131  if (as.back() != '/') as.append("/");
132  as.append("OssArc/");
133  admnPath = strdup(as.c_str());
134  }
135  stopPath = 0;
136 
137  srcData = strdup("");
138  stagePath = strdup("/tmp/stage");
139  tapePath = strdup("/TapeBuffer");
140  tapePathLEN = strlen(tapePath);
141  utilsPath = strdup("/usr/local/etc");
142 
143  stopMon = 0;
144 
145  metaBKP = "arcBackup";
146  metaIDX = "arcIndex";
147  doneBKP = 0;
148  needBKP = 0;
149  dstRSE = 0;
150  srcRSE = 0;
151  manCKS = strdup("adler32");
152 
153  bkpMinF = -20;
154  bkpMax = 2;
155  bkpPoll = 15*60;
156  bkpFSt = -1; // Eventual default is bkpPoll/3
157  maxStage = 30;
158  wtpStage = 30;
159  r_maxItems = 1000;
160  arFName = strdup("Archive.zip");
161  arfSfx = strdup(".zip");
162  arfSfxLen = 4;
163  stopChk = 10;
164  bkpLocal = true;
165 
166  arcSZ_Skip = false;
167  arcSZ_Want = 0; // The XrdOssArc_BkpUtils defines the default
168  arcSZ_MinV = 0;
169  arcSZ_MaxV = 0;
170 
171  if (getenv("XRDOSSARC_DEBUG") || getenv("XRDDEBUG"))
173 }
174 
175 /******************************************************************************/
176 /* Private: B u i l d P a t h */
177 /******************************************************************************/
178 
179 bool XrdOssArcConfig::BuildPath(const char* what, const char* baseP,
180  const char* addP, char*& destP, int mode)
181 {
182  char lclPath[MAXPATHLEN];
183  int rc;
184 
185 // Get the local path to the base directory
186 //
187  if ((rc = GenLocalPath(baseP, lclPath, sizeof(lclPath))))
188  {Elog.Emsg("Config", rc, "configure", what);
189  return false;
190  }
191 
192 // Copy the path for further modification
193 //
194  std::string tmpStr(lclPath);
195 
196 // Trimp off trailing slashes
197 //
198  while(tmpStr.back() == '/') tmpStr.pop_back();
199 
200 // Add any additional element
201 //
202  if (addP) tmpStr.append(addP);
203 
204 // Create modifiable copy
205 //
206  char* modStr = strdup(tmpStr.c_str());
207 
208 // Check if we need to create the full path
209 //
210  if (mode)
211  {int rc = XrdOucUtils::makePath(modStr, mode);
212  if (rc)
213  {std::string msgT("create ");
214  msgT.append(what);
215  Elog.Emsg("Config", rc, msgT.c_str(), tmpStr.c_str());
216  free(modStr);
217  return false;
218  }
219  }
220 
221 // Set destination and return success
222 //
223  destP = modStr;
224  return true;
225 }
226 
227 /******************************************************************************/
228 /* C o n f i g u r e */
229 /******************************************************************************/
230 
231 bool XrdOssArcConfig::Configure(const char* cfn, const char* parms,
232  XrdOucEnv* envP)
233 {
234  TraceInfo("Configure", 0);
235  bool NoGo = false;
236 
237 // Read and process the config file
238 //
239  if (!ConfigXeq(cfn, parms, envP)) return false;
240 
241 // Set the external debug flag as needed
242 //
244  XrdOucEnv::Export("XRDOSSARC_DEBUG",ArcTrace.What & TRACE_Save ? "2":"1");
245 
246 // Make sure that the rse declarations have been specified
247 //
248  if (dstRSE && srcRSE)
249  {std::string tmp;
250  XrdOucEnv::Export("XRDOSSARC_DSTRSE", dstRSE);
251  DEBUG("exporting XRDOSSARC_DSTRSE="<<dstRSE);
252  XrdOucEnv::Export("XRDOSSARC_SRCRSE", srcRSE);
253  DEBUG("exporting XRDOSSARC_SRCRSE="<<srcRSE);
254 
255  tmp = dstRSE;
256  tmp += ":need";
257  needBKP = strdup(tmp.c_str());
258  tmp = dstRSE;
259  tmp += ":done";
260  doneBKP = strdup(tmp.c_str());
261  } else {
262  Elog.Say("Config mistake: required 'rsedcl' directive not specified!");
263  NoGo = true;
264  }
265 
266 // Export values needed by the metadata script
267 //
268  XrdOucEnv::Export("XRDOSSARC_MAXITEMS", r_maxItems);
269 
270 // Export manifest checksum, unless none wanted
271 //
272  if (strcmp(manCKS, "none")) XrdOucEnv::Export("XRDOSSARC_CKSUM", manCKS);
273 
274 // Export archive size parameters if specified
275 //
276  if (arcSZ_Want)
277  {char buff[1024];
278  snprintf(buff, sizeof(buff), "%lld %lld %lld %d", arcSZ_Want,
279  arcSZ_MinV, arcSZ_MaxV, (int)arcSZ_Skip);
280  XrdOucEnv::Export("XRDOSSARC_SIZE", buff);
281  }
282 
283 // Handle the admin path
284 //
285  if (admnPath)
286  {int rc = XrdOucUtils::makePath(admnPath, S_IRWXU | S_IRGRP);
287  if (rc) {Elog.Emsg("Config", rc, "create admin path", admnPath);
288  NoGo = true;
289  }
290  else if (!Usable(admnPath, "admin path", false)) NoGo = true;
291  }
292 
293 // Handle the stop file path
294 //
295  if (!stopPath) stopPath = admnPath;
296  else {std::string ss = stopPath;
297  if (ss.back() != '/')
298  {ss.append("/");
299  free(stopPath);
300  stopPath = strdup(ss.c_str());
301  }
302  }
303 
304 // Create the stop monitor
305 //
306  if (!stopPath)
307  {Elog.Emsg("Config", "Unable to determine the stopfile path!");
308  NoGo = true;
309  } else {
310  if (!Usable(stopPath, "stopfile path", false)) NoGo = true;
311  else if (!NoGo)
312  {bool uOK;
313  stopMon = new XrdOssArcStopMon(stopPath, stopChk, uOK);
314  if (!uOK)
315  {NoGo = true;
316  delete stopMon;
317  stopMon = 0;
318  }
319  }
320  }
321 
322 // Verify that the tape buffer is usable
323 //
324  if (!Usable(tapePath, "tape buffer path", false)) NoGo = true;
325  tapePathLEN = strlen(tapePath);
326 
327 // Initialize the tape buffer resourse monitor
328 //
329  if (bkpFSt < 0)
330  {bkpFSt = bkpPoll/3;
331  if (bkpFSt < 30) bkpFSt = 30;
332  }
333  if (!fsMon.Init(tapePath, bkpMinF, bkpFSt)) NoGo = true;
334 
335 // Verify that the data source mount point is usable
336 //
337  if (*srcData)
338  {struct stat Stat;
339  if (stat(srcData, &Stat))
340  {Elog.Emsg("Config", errno, "use srcdata path", srcData);
341  NoGo = true;
342  }
343  }
344 
345 // Create the backup staging path
346 //
347  if (!BuildPath("dataset backup arena", dsetPathLFN, "/4bkp/",
348  dsetRepoPFN, S_IRWXU|S_IRGRP|S_IXGRP))
349  NoGo = true;
350 
351 // Create the program that returns the datasets that need to be backed up.
352 // It also is the one that manipulates the backup status of a dataset.
353 //
354  BkpUtilProg = new XrdOucProg(&Elog);
355  ConfigPath(&BkpUtilPath, utilsPath);
356  if (BkpUtilProg->Setup(BkpUtilPath)) NoGo = true;
357  else {const char* rslash = rindex(BkpUtilPath, '/');
358  BkpUtilName = (rslash ? rslash+1 : BkpUtilPath);
359  }
360 
361 // Create program to communicate with the MSS
362 //
363  MssComProg = new XrdOucProg(&Elog);
364  ConfigPath(&MssComPath, utilsPath);
365  if (MssComProg->Setup(MssComPath)) NoGo = true;
366  else {const char* rslash = rindex(MssComPath, '/');
367  MssComName = (rslash ? rslash+1 : MssComPath);
368  }
369 
370 // Export envars that the programs needs
371 //
372  if (MssComCmd)
373  {XrdOucEnv::Export("XRDOSSARC_MSSCMD", MssComCmd);
374  DEBUG("Exporting XRDOSSARC_MSSCMD="<<MssComCmd);
375  }
376  if (MssComRoot)
377  {XrdOucEnv::Export("XRDOSSARC_MSSROOT", MssComRoot);
378  DEBUG("exporting XRDOSSARC_MSSROOT="<<MssComRoot);
379  } else MssComRoot = strdup("");
380 
381 // Create the pre archiver program if it has been specified
382 //
383  if (PrepArcPath)
384  {PrepArcProg = new XrdOucProg(&Elog);
385  ConfigPath(&PrepArcPath, utilsPath);
386  if (PrepArcProg->Setup(PrepArcPath)) NoGo = true;
387  else {const char* rslash = rindex(PrepArcPath, '/');
388  PrepArcName = (rslash ? rslash+1 : PrepArcPath);
389  }
390  } else PrepArcProg = 0;
391 
392 // Create the post archiver program if it has been specified
393 //
394  if (PostArcPath)
395  {PostArcProg = new XrdOucProg(&Elog);
396  ConfigPath(&PostArcPath, utilsPath);
397  if (PostArcProg->Setup(PostArcPath)) NoGo = true;
398  else {const char* rslash = rindex(PostArcPath, '/');
399  PostArcName = (rslash ? rslash+1 : PostArcPath);
400  }
401  } else {
402  PostArcProg = 0;
403  PostArcName = PostArcPath = strdup("");
404  }
405 
406 // Create the program to be used to create the archive
407 //
408  ArchiverProg = new XrdOucProg(&Elog);
409  ConfigPath(&ArchiverPath, utilsPath);
410  if (ArchiverProg->Setup(ArchiverPath)) NoGo = true;
411  else {const char* rslash = rindex(ArchiverPath, '/');
412  ArchiverName = (rslash ? rslash+1 : ArchiverPath);
413  }
414 
415 // Setup the remote copy command the archiver should use for backups
416 //
417  if (bkpLocal)
418  {if (ArchiverSave) free(ArchiverSave);
419  ArchiverSave = strdup("");
420  } else {
421  if (!ArchiverSave) ArchiverSave = MssComPath;
422  else ConfigPath(&ArchiverSave, utilsPath);
423  DEBUG("Archiver remote copycmd="<<ArchiverSave);
424  }
425 
426 // Make sure all the required metadata keys have been defined
427 //
428  DEBUG("Running "<<BkpUtilName<<" addkey "<<metaBKP<<' '<<metaIDX);
429  if (BkpUtilProg->Run("addkey", metaBKP, metaIDX))
430  Elog.Emsg("Config","Unable to create/verify metadata keys; continuing...");
431 
432 // Start the backup process.
433 //
434  std::vector<XrdOssArcBackup*> bkpVec;
435  XrdOssArcBackup* bkpP;
436  if (bkpScopes.empty())
437  {Elog.Emsg("Config", "No backup scopes specified!"); NoGo = true;
438  } else {
439  bool isOK;
440  for (auto it = bkpScopes.begin(); it != bkpScopes.end(); ++it)
441  {bkpP = new XrdOssArcBackup(it->c_str(), isOK);
442  if (!isOK)
443  {NoGo = true;
444  Elog.Emsg("Config", "Unable to start backing up scope",
445  it->c_str());
446  delete bkpP;
447  } else bkpVec.push_back(bkpP);
448  }
449  }
450 
451 // Start the configured number of backup workers The workers will wait for
452 // backup tasks which will come shortly as we will start them once we have
453 // dispatched workers. However, if we failed in any way, nothing is started.
454 //
455  if (!NoGo)
457  for (auto it = bkpVec.begin(); it != bkpVec.end(); it++)
458  {Elog.Say("Config process: scheduling backup for scope ",
459  (*it)->theScope());
460  schedP->Schedule(*it, time(0)+3);
461  }
462  }
463 
464 // All done
465 //
466  return !NoGo;
467 }
468 
469 /******************************************************************************/
470 /* Private: C o n f i g P a t h */
471 /******************************************************************************/
472 
473 void XrdOssArcConfig::ConfigPath(char** pDest, const char* pRoot)
474 {
475 // If pDest starts with a slash then we use it as is; otherwise qualify it
476 //
477  if ((*pDest)[0] != '/')
478  {std::string tmp(pRoot);
479  if (tmp.back() != '/') tmp += '/';
480  tmp += *pDest;
481  free(*pDest);
482  *pDest = strdup(tmp.c_str());
483  }
484 }
485 
486 /******************************************************************************/
487 /* Private: C o n f i g P r o c */
488 /******************************************************************************/
489 
490 bool XrdOssArcConfig::ConfigProc(const char* drctv)
491 {
492 
493 // Process each directive
494 //
495  if (!strcmp(drctv, "arcsize")) return xqArcsz();
496  else if (!strcmp(drctv, "backup")) return xqBkup();
497  else if (!strcmp(drctv, "manifest"))return xqManf();
498  else if (!strcmp(drctv, "msscmd"))
499  return xqGrab("msscmd", MssComCmd, Conf->LastLine());
500  else if (!strcmp(drctv, "paths")) return xqPaths();
501  else if (!strcmp(drctv, "rsedcl")) return xqRse();
502  else if (!strcmp(drctv, "rucio")) return xqRucio();
503  else if (!strcmp(drctv, "stage")) return xqStage();
504  else if (!strcmp(drctv, "trace")) return xqTrace();
505  else if (!strcmp(drctv, "utils")) return xqUtils();
506  else Conf->MsgfW("ignoring unknown directive '%s'", drctv);
507 
508  return true;
509 }
510 
511 /******************************************************************************/
512 /* Private: C o n f i g X e q */
513 /******************************************************************************/
514 
515 
516 bool XrdOssArcConfig::ConfigXeq(const char* cfName, const char* parms,
517  XrdOucEnv* envP)
518 {
519  XrdOucGatherConf Cfile("ossarc.", &Elog);
520  char *token;
521  int rc;
522  bool NoGo = false;
523 
524 // Get all relevant config options. Ignore the parms.
525 //
526  if ((rc = Cfile.Gather(cfName, XrdOucGatherConf::full_lines)) <= 0)
527  return (rc < 0 ? false : true);
528 
529  Cfile.Tabs(0);
530 
531 // We point to the tokenizer to avod passing it around everywhere
532 //
533  Conf = &Cfile;
534 
535 // Process each directive
536 //
537  while(Cfile.GetLine())
538  {if ((token = Cfile.GetToken()))
539  {if (!strncmp(token, "ossarc.", 7)) token += 7;
540  NoGo |= !ConfigProc(token);
541  }
542  }
543 
544 // All done
545 //
546  return !NoGo;
547 }
548 
549 /******************************************************************************/
550 /* Private: G e n L o c a l P a t h */
551 /******************************************************************************/
552 
553 int XrdOssArcConfig::GenLocalPath(const char* dsn, char* buff, int bSZ)
554 {
555  int rc;
556 
557 // Generate the pfn treating the dsn as the lfn
558 //
559  if ((rc = ossP->Lfn2Pfn(dsn, buff, bSZ)))
560  {Elog.Emsg("Archive", rc, "generate local path for", dsn);
561  return rc;
562  }
563  return 0;
564 }
565 
566 /******************************************************************************/
567 /* Private: M i s s A r g */
568 /******************************************************************************/
569 
570 bool XrdOssArcConfig::MissArg(const char* what)
571 {
572  Conf->MsgfE("%s not specified.", what);
573  return false;
574 }
575 
576 /******************************************************************************/
577 /* U s a b l e */
578 /******************************************************************************/
579 
580 bool XrdOssArcConfig::Usable(const char* path, const char* what, bool useOss)
581 {
582  struct stat Stat;
583  int rc;
584 
585  if (useOss) rc = ossP->Stat(path, &Stat);
586  else if ((rc = stat(path, &Stat))) rc = errno;
587 
588  if (rc)
589  {char buff[256];
590  snprintf(buff, sizeof(buff), "use %s", what);
591  Elog.Emsg("Config", rc, buff, path);
592  return false;
593  }
594 
595 // Verify that it is a directory
596 //
597  if (!S_ISDIR(Stat.st_mode))
598  {Elog.Emsg("Config", what, path, "is not a directory!");
599  return false;
600  }
601 
602 // Verify that it is writable
603 //
604  if ( ((Stat.st_mode & S_IWOTH) == 0)
605  && ((Stat.st_mode & S_IWUSR) != 0 && (Stat.st_uid != geteuid()))
606  && ((Stat.st_mode & S_IWGRP) != 0 && (Stat.st_uid != getegid())))
607  {Elog.Emsg("Config", what, path, "is not writable!");
608  rc = 1;
609  }
610 
611 // Verify that it is searchable
612 //
613  if ( ( (Stat.st_mode & S_IXOTH) == 0)
614  && ( (Stat.st_mode & S_IXUSR) != 0 && (Stat.st_uid != geteuid()))
615  && ( (Stat.st_mode & S_IXGRP) != 0 && (Stat.st_uid != getegid())))
616  {Elog.Emsg("Config", what, path, "is not searchable!");
617  rc = 1;
618  }
619 
620 // All done
621 //
622  return rc == 0;
623 }
624 
625 /******************************************************************************/
626 /* Private: x q A r c s z */
627 /******************************************************************************/
628 /*
629  arcsize <target> [range <min> <max>] [skip]
630 */
631 
632 namespace
633 {
634 bool getVal(XrdOucGatherConf* Conf, const char* what, long long& theval,
635  long long minV, long long maxV)
636 {
637  char* token;
638 
639 // Get next token
640 //
641  if (!(token = Conf->GetToken()))
642  {Conf->MsgE(what, "value not specified!"); return false;}
643 
644 // Convert it
645 //
646  if (XrdOuca2x::a2sz(Elog,what, token, &theval, minV, maxV))
647  {Conf-> EchoLine();
648  return false;
649  }
650 
651 // All done, success
652 //
653  return true;
654 }
655 }
656 
657 bool XrdOssArcConfig::xqArcsz()
658 {
659  static const long long MinV = 104857600LL; // minimum value 100 MB
660  static const long long MaxV = 500*1073741824LL; // maximum value 500 GB
661 
662  char* token;
663  long long tVal, minVal = 0, maxVal = 0;
664 
665 // Get first value which is the target size
666 //
667  if (!getVal(Conf, "arcsize target", tVal, MinV, MaxV)) return false;
668 
669 // Get optional arguments
670 //
671  while((token = Conf->GetToken()))
672  {if (!strcmp(token, "range"))
673  {if (!getVal(Conf, "arcsize range minimum", minVal, MinV, MaxV))
674  return false;
675  if (!getVal(Conf, "arcsize range maximum", maxVal, MinV, MaxV))
676  return false;
677  if (minVal > maxVal)
678  {Conf->MsgE("arcsize range minimum is greater than maximum!");
679  return false;
680  }
681  if (tVal < minVal || tVal > maxVal)
682  {Conf->MsgE("arcsize target value out of specified range!");
683  return false;
684  }
685  } else if (!strcmp(token, "skip"))
686  {arcSZ_Skip = true;
687  } else {
688  Conf->MsgE("Invalid arcsize option -", token);
689  return false;
690  }
691  }
692 
693 // If no range has been specified, provide one
694 //
695  if (!minVal)
696  {minVal = tVal/2;
697  maxVal = tVal*2;
698  }
699 
700 // Set the values in common area
701 //
702  arcSZ_Want = tVal;
703  arcSZ_MinV = minVal;
704  arcSZ_MaxV = maxVal;
705 
706 // Return success
707 //
708  return true;
709 }
710 
711 /******************************************************************************/
712 /* Private: x q B k u p */
713 /******************************************************************************/
714 /*
715  backup [fscan <sec>] [max <num>] [mode {local|remote}] [poll <sec>]
716  [stopchk <sec>] [minfree <n>[%|k|m|g]] [scope <name> [<name [...]]]
717 */
718 
719 bool XrdOssArcConfig::xqBkup()
720 {
721  static const int isN = 0; // Argument is int
722  static const int isT = 1; // Argument is time
723  static const int isPS = 2; // Atgument is size value or percentage
724  static const int isM = 3; // Atgument is mode
725 
726  struct bkpopts {const char *opname; int* oploc; int minv; int isX;}
727  bkpopt[] =
728  {
729  {"check", &stopChk, 5, isT},
730  {"fscan", &bkpFSt, 30, isT},
731  {"max", &bkpMax, 1, isN},
732  {"minfree", 0, 1, isPS},
733  {"mode", 0, 0, isM},
734  {"poll", &bkpPoll, 60, isT},
735  {"scope", 0, -1, isN}
736  };
737  int numopts = sizeof(bkpopt)/sizeof(struct bkpopts);
738  int i;
739  char* token, *tval;
740 
741 // Get the first token, there must be one
742 //
743  if (!(token = Conf->GetToken()))
744  {Conf->MsgfE("no backup arguments specified!"); return false;}
745 
746 // Process all options
747 //
748 do{for (i = 0; i < numopts; i++)
749  {if (!strcmp(token, bkpopt[i].opname))
750  {if (bkpopt[i].minv == -1) return xqBkupScope();
751  int* val = bkpopt[i].oploc;
752  int minv = bkpopt[i].minv;
753 
754  if (!(tval = Conf->GetToken()) || !(*tval))
755  {Conf->MsgE("backup", token, "value not specified!");
756  return false;
757  }
758 
759  if (bkpopt[i].isX == isM)
760  { if (!strcmp("remote", tval)) bkpLocal = false;
761  else if (!strcmp("local", tval)) bkpLocal = true;
762  else {Conf->MsgfE("Invalid backup mode '%s'.", token);
763  return false;
764  }
765  break;
766  }
767 
768  if (bkpopt[i].isX == isPS)
769  {if (!xqBkupPS(tval)) return false;
770  break;
771  }
772 
773  if (bkpopt[i].isX == isT)
774  {if (XrdOuca2x::a2tm(Elog,bkpopt[i].opname,tval,val,minv))
775  {Conf-> EchoLine();
776  return false;
777  }
778  break;
779  }
780 
781  if (XrdOuca2x::a2i(Elog,bkpopt[i].opname,tval,val,minv))
782  {Conf-> EchoLine();
783  return false;
784  }
785  break;
786  }
787  }
788  if (i >= numopts)
789  {Conf->MsgfE("Unknown backup option '%s'.", token); return false;}
790 
791  } while((token = Conf->GetToken()));
792 
793 // All done
794 //
795  return true;
796 }
797 
798 /******************************************************************************/
799 /* Private: x q B k u p P S */
800 /******************************************************************************/
801 
802 bool XrdOssArcConfig::xqBkupPS(char* tval)
803 {
804  int n = strlen(tval);
805 
806 // Check for percentage or actual size
807 //
808  if (tval[n-1] == '%')
809  {if (XrdOuca2x::a2sp(Elog,"backup minfree",tval,&bkpMinF,1,99))
810  {Conf-> EchoLine();
811  return false;
812  }
813  bkpMinF = -bkpMinF;
814  } else {
815  if (XrdOuca2x::a2sz(Elog,"backup minfree",tval,&bkpMinF,1))
816  {Conf-> EchoLine();
817  return false;
818  }
819  }
820 
821 // All done
822 //
823  return true;
824 }
825 
826 /******************************************************************************/
827 /* Private: x q B k u p S c o p e */
828 /******************************************************************************/
829 
830 bool XrdOssArcConfig::xqBkupScope()
831 {
832  char* scope = Conf->GetToken();
833 
834  if (!scope || !(*scope))
835  {Conf->MsgfE("backup scope not specified!"); return false;}
836 
837 do{auto rslt = bkpScopes.insert(std::string(scope));
838  if (!rslt.second)
839  Conf->MsgW("backup scope", scope, "previously specified.");
840  scope = Conf->GetToken();
841  } while(scope && *scope);
842 
843  return true;
844 }
845 
846 /******************************************************************************/
847 /* Private: x q G r a b */
848 /******************************************************************************/
849 
850 bool XrdOssArcConfig::xqGrab(const char* what, char*& theDest,
851  const char* theLine)
852 {
853  const char* tP;
854 
855 // Get all text after the direcive keyword in the last line
856 //
857  if ((tP = index(theLine, ' '))) while(*tP == ' ') tP++;
858  if (!tP || !(*tP))
859  {Conf->MsgfE("%s argument not specified!", what);
860  return false;
861  }
862 
863 // Replace the new argument with the old one
864 //
865  if (theDest) free(theDest);
866  theDest = strdup(tP);
867  return true;
868 }
869 
870 /******************************************************************************/
871 /* Private: x q M a n f */
872 /******************************************************************************/
873 /*
874  manifest cksum <ckalg>
875 */
876 
877 bool XrdOssArcConfig::xqManf()
878 {
879  char** tDest = 0;
880  char *token, *targ;
881 
882  if (!(token = Conf->GetToken()))
883  {Conf->MsgfE("No manifest parameters specified!");
884  return false;
885  }
886 
887 // Process all options
888 //
889  do { if (!strcmp("cksum", token)) tDest = &manCKS;
890  else {Conf->MsgfE("Unknown manifest parameter '%s'; ignored.", token);
891  return false;
892  }
893  if (!(targ = Conf->GetToken()))
894  {Conf->MsgfE("%s argument not specified!", token);
895  return false;
896  }
897  if (*tDest) free(*tDest);
898  *tDest = strdup(targ);
899  } while((token = Conf->GetToken()));
900 
901 // All done
902 //
903  return true;
904 }
905 
906 /******************************************************************************/
907 /* Private: x q P a t h s */
908 /******************************************************************************/
909 /*
910  paths [backing <path>] [{mssfs|mssroot} <path>] [srcdata <path>]
911  [staging <path>] [utils <path>]
912 */
913 
914 bool XrdOssArcConfig::xqPaths()
915 {
916  char** pDest = 0;
917  char *token, *ploc;
918 
919 // Process all options
920 //
921  while((token = Conf->GetToken()))
922  { if (!strcmp("backing", token)) pDest = &tapePath;
923  else if (!strcmp("mssfs", token)) pDest = &MssComRoot;
924  else if (!strcmp("mssroot", token)) pDest = &MssComRoot;
925  else if (!strcmp("srcdata", token)) pDest = &srcData;
926  else if (!strcmp("staging", token)) pDest = &stagePath;
927  else if (!strcmp("stopfile", token)) pDest = &stopPath;
928  else if (!strcmp("utils", token)) pDest = &utilsPath;
929  else {Conf->MsgfE("Unknown path type '%s'; ignored.", token);
930  if (!Conf->GetToken()) break;
931  continue;
932  }
933  if (!(ploc = Conf->GetToken()))
934  {Conf->MsgfE("%s path not specified!", token);
935  return false;
936  }
937 
938  // Make sure path starts with a slash
939  //
940  if (*ploc != '/')
941  {Conf->MsgfE("%s path is not absolute!", token);
942  return false;
943  }
944 
945  if (*pDest) free(*pDest);
946  *pDest = strdup(ploc);
947  }
948 
949 // Make sure we have at least one argument
950 //
951  if (!pDest) {Conf->MsgfE("no 'path' arguments specified!"); return false;}
952 
953 // All done
954 //
955  return true;
956 }
957 
958 /******************************************************************************/
959 /* Private: x q R s e */
960 /******************************************************************************/
961 /*
962  rsedcl <srcrse_name> <dstrse_name>
963 */
964 bool XrdOssArcConfig::xqRse()
965 {
966  char* token;
967 
968 // Get the first token, there must be one
969 //
970  if (!(token = Conf->GetToken()))
971  {Conf->MsgfE("source rse name not specified!"); return false;}
972 
973 // Copy it over
974 //
975  if (srcRSE) free(srcRSE);
976  srcRSE = strdup(token);
977 
978 // Get the next token, there must be one
979 //
980  if (!(token = Conf->GetToken()))
981  {Conf->MsgfE("destination rse name not specified!"); return false;}
982 
983 // Copy it over
984 //
985  if (dstRSE) free(dstRSE);
986  dstRSE = strdup(token);
987  return true;
988 }
989 
990 /******************************************************************************/
991 /* Private: x q R u c i o */
992 /******************************************************************************/
993 /*
994 Note: the maxitems value should match what is specified in the schema.py file
995  that is used to describe the Rucio schema.
996 
997  maxitems <items>
998 */
999 bool XrdOssArcConfig::xqRucio()
1000 {
1001  char* token, *val;
1002  int num;
1003 
1004 // Get the first token, there must be one
1005 //
1006  if (!(token = Conf->GetToken()))
1007  {Conf->MsgfE("rucio parameter not specified!"); return false;}
1008 
1009 // Process the attribute
1010 //
1011 do{if (!strcmp(token, "maxitems"))
1012  {if (!(val = Conf->GetToken())
1013  || XrdOuca2x::a2i(Elog, "rucio maxitems value", val, &num, 1)) break;
1014  r_maxItems = num;
1015  } else {
1016  Conf->MsgfE("Invalid rucio parameter, '%s'!", token);
1017  return false;
1018  }
1019  } while((token = Conf->GetToken()));
1020 
1021 // Check ending
1022 //
1023  if (token)
1024  {if (val) Conf->EchoLine();
1025  else Conf->MsgfE("rucio %s parameter value not specified.", token);
1026  return false;
1027  }
1028 
1029 // All done
1030 //
1031  return true;
1032 }
1033 
1034 /******************************************************************************/
1035 /* Private: x q S t a g e */
1036 /******************************************************************************/
1037 /*
1038  stage [max <num>] [poll <sec>]
1039 */
1040 
1041 bool XrdOssArcConfig::xqStage()
1042 {
1043  static const int minStg = 1, maxStg = 100, minPoll = 5, maxPoll = 100;
1044  char* val;
1045  int num, rc;
1046 
1047 // Get the first token (there must be at least one)
1048 //
1049  if (!(val = Conf->GetToken()))
1050  {Conf->MsgfE("No stage parameters specified");
1051  return false;
1052  }
1053 
1054 // Now process all of them
1055 //
1056  while(val)
1057  { if (!strcmp(val, "max"))
1058  {if (!(val = Conf->GetToken())) return MissArg("'max' value");
1059  rc = XrdOuca2x::a2i(Elog, "stage max value", val, &num,
1060  minStg, maxStg);
1061  if (rc) {Conf->EchoLine(); return false;}
1062  maxStage = num;
1063  }
1064  else if (!strcmp(val, "poll"))
1065  {if (!(val = Conf->GetToken())) return MissArg("'poll' value");
1066  rc = XrdOuca2x::a2tm(Elog, "stage poll value", val, &num,
1067  minPoll, maxPoll);
1068  if (rc) {Conf->EchoLine(); return false;}
1069  wtpStage = num;
1070  }
1071  else {Conf->MsgE("unknown option -", val);
1072  return false;
1073  }
1074  } while((val = Conf->GetToken()));
1075 
1076 // All done
1077 //
1078  return true;
1079 }
1080 
1081 /******************************************************************************/
1082 /* Private: x q T r a c e */
1083 /******************************************************************************/
1084 
1085 bool XrdOssArcConfig::xqTrace()
1086 {
1087  char *val;
1088  struct traceopts {const char *opname; unsigned int opval;} tropts[] =
1089  {
1090  {"all", TRACE_All},
1091  {"off", TRACE_None},
1092  {"none", TRACE_None},
1093  {"save", TRACE_Save},
1094  {"debug", TRACE_Debug}
1095  };
1096  int i, neg, trval = 0, numopts = sizeof(tropts)/sizeof(struct traceopts);
1097 
1098  if (!(val = Conf->GetToken()))
1099  {Conf->MsgE("no trace options specified");
1100  return false;
1101  }
1102  while (val)
1103  {if (!strcmp(val, "off")) trval = 0;
1104  else {if ((neg = (val[0] == '-' && val[1]))) val++;
1105  for (i = 0; i < numopts; i++)
1106  {if (!strcmp(val, tropts[i].opname))
1107  {if (neg)
1108  if (tropts[i].opval) trval &= ~tropts[i].opval;
1109  else trval = TRACE_All;
1110  else if (tropts[i].opval) trval |= tropts[i].opval;
1111  else trval = TRACE_None;
1112  break;
1113  }
1114  }
1115  if (i >= numopts)
1116  Conf->MsgfW("ignoring invalid trace option '%s'", val);
1117  }
1118  val = Conf->GetToken();
1119  }
1120  ArcTrace.What = trval;
1121  return true;
1122 }
1123 
1124 /******************************************************************************/
1125 /* Private: x q U t i l s */
1126 /******************************************************************************/
1127 /*
1128  utils [archiver <path>] [bkputils <path>] [disparc <path>] [msscom <path>]
1129  [preparc <path>]
1130 */
1131 
1132 bool XrdOssArcConfig::xqUtils()
1133 {
1134  char** uDest = 0;
1135  char *token, *uloc;
1136 
1137 // Process all options
1138 //
1139  while((token = Conf->GetToken()))
1140  { if (!strcmp("archiver", token)) uDest = &ArchiverPath;
1141  else if (!strcmp("bkputils", token)) uDest = &BkpUtilPath;
1142  else if (!strcmp("msscom", token)) uDest = &MssComPath;
1143  else if (!strcmp("postarc", token)) uDest = &PostArcPath;
1144  else if (!strcmp("preparc", token)) uDest = &PrepArcPath;
1145  else if (!strcmp("saver", token)) uDest = &ArchiverSave;
1146  else {Conf->MsgfW("Unknown util '%s'; ignored.", token);
1147  if (!Conf->GetToken()) break;
1148  continue;
1149  }
1150  if (!(uloc = Conf->GetToken()))
1151  {Conf->MsgfE("utils %s value not specified!", token);
1152  return false;
1153  }
1154  if (*uDest) free(*uDest);
1155  *uDest = strdup(uloc);
1156  }
1157 
1158 // Make sure we have at least one argument
1159 //
1160  if (!uDest) {Conf->MsgE("no 'utils' arguments specified!"); return false;}
1161 
1162 // All done
1163 //
1164  return true;
1165 }
#define DEBUG(x)
Definition: XrdBwmTrace.hh:54
struct stat Stat
Definition: XrdCks.cc:49
XRootDStatus BuildPath(std::string &newPath, Env *env, const std::string &path)
Definition: XrdClFS.cc:56
#define TRACE_Debug
Definition: XrdCmsTrace.hh:37
#define TRACE_All
#define TraceInfo(x, y)
#define TRACE_Save
#define TRACE_None
#define stat(a, b)
Definition: XrdPosix.hh:105
static void StartWorkers(int maxw)
bool BuildPath(const char *what, const char *baseP, const char *addP, char *&destP, int mode=0)
bool Configure(const char *cfn, const char *parms, XrdOucEnv *envP)
bool Init(const char *path, long long fVal, int fsupdt)
virtual int Lfn2Pfn(const char *Path, char *buff, int blen)
Definition: XrdOss.hh:954
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
char * GetToken(char **rest=0, int lowcase=0)
void MsgfW(const char *fmt,...)
void MsgW(const char *txt1, const char *txt2=0, const char *txt3=0, const char *txt4=0, const char *txt5=0, const char *txt6=0)
void MsgfE(const char *fmt,...)
void MsgE(const char *txt1, const char *txt2=0, const char *txt3=0, const char *txt4=0, const char *txt5=0, const char *txt6=0)
@ full_lines
Complete lines.
static int makePath(char *path, mode_t mode, bool reset=false)
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 a2sz(XrdSysError &, const char *emsg, const char *item, long long *val, long long minv=-1, long long maxv=-1)
Definition: XrdOuca2x.cc:257
static int a2tm(XrdSysError &, const char *emsg, const char *item, int *val, int minv=-1, int maxv=-1)
Definition: XrdOuca2x.cc:288
void Schedule(XrdJob *jp)
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
Definition: XrdSysError.cc:116
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:162
thread_local XrdOucECMsg ecMsg
XrdOss * ossP
Definition: XrdOssArc.cc:64
XrdSysTrace ArcTrace("OssArc")
XrdScheduler * schedP
Definition: XrdOssArc.cc:66
XrdOssArcFSMon fsMon
XrdSysError Elog(0, "OssArc_")
XrdOucEnv * envP
Definition: XrdPss.cc:110