XRootD
Loading...
Searching...
No Matches
XrdCpConfig.cc
Go to the documentation of this file.
1/******************************************************************************/
2/* */
3/* X r d C p C o n f i g . c c */
4/* */
5/* (c) 2011 by the Board of Trustees of the Leland Stanford, Jr., University */
6/* All Rights Reserved */
7/* Produced by Andrew Hanushevsky for Stanford University under contract */
8/* DE-AC02-76-SFO0515 with the Department of Energy */
9/* */
10/* This file is part of the XRootD software suite. */
11/* */
12/* XRootD is free software: you can redistribute it and/or modify it under */
13/* the terms of the GNU Lesser General Public License as published by the */
14/* Free Software Foundation, either version 3 of the License, or (at your */
15/* option) any later version. */
16/* */
17/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
18/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
19/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
20/* License for more details. */
21/* */
22/* You should have received a copy of the GNU Lesser General Public License */
23/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
24/* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
25/* */
26/* The copyright holder's institutional names and contributor's names may not */
27/* be used to endorse or promote products derived from this software without */
28/* specific prior written permission of the institution or contributor. */
29/******************************************************************************/
30
31#include <fcntl.h>
32#include <getopt.h>
33#include <cstdio>
34#include <cstdlib>
35#include <cstring>
36#include <sys/stat.h>
37#include <sys/types.h>
38
39#include "XrdVersion.hh"
41#include "XrdApps/XrdCpFile.hh"
42#include "XrdCks/XrdCksCalc.hh"
45#include "XrdSys/XrdSysE2T.hh"
46#include "XrdSys/XrdSysError.hh"
49
50
51/******************************************************************************/
52/* D e f i n e M a c r o s */
53/******************************************************************************/
54
55#define EMSG(x) std::cerr <<PName <<": " <<x <<std::endl
56
57#define FMSG(x,y) {EMSG(x);exit(y);}
58
59#define UMSG(x) {EMSG(x);Usage(22);}
60
61#define ZMSG(x) {EMSG(x);return 0;}
62
63// Bypass stupid issue with stupid solaris for missdefining 'struct opt'.
64//
65#ifdef __solaris__
66#define OPT_TYPE (char *)
67#else
68#define OPT_TYPE
69#endif
70
71/******************************************************************************/
72/* S t a t i c M e m b e r s */
73/******************************************************************************/
74
76{
78static XrdSysError eDest(&Logger, "");
79
80// Returns true if the protocol is one that carries HTTP requests.
81//
82static bool isHttpProt(XrdCpFile::PType pType)
83 {return pType == XrdCpFile::isHttp
84 || pType == XrdCpFile::isHttps
85 || pType == XrdCpFile::isS3;
86 }
87};
88
90
91XrdSysError *XrdCpConfig::Log = &XrdCpConfiguration::eDest;
92
93const char *XrdCpConfig::opLetters = ":C:d:D:EfFhH:I:NpPrRsS:t:T:vVX:y:z:ZA";
94
95struct option XrdCpConfig::opVec[] = // For getopt_long()
96 {
97 {OPT_TYPE "cksum", 1, 0, XrdCpConfig::OpCksum},
98 {OPT_TYPE "coerce", 0, 0, XrdCpConfig::OpCoerce},
99 {OPT_TYPE "continue", 0, 0, XrdCpConfig::OpContinue},
100 {OPT_TYPE "debug", 1, 0, XrdCpConfig::OpDebug},
101 {OPT_TYPE "dynamic-src", 0, 0, XrdCpConfig::OpDynaSrc},
102 {OPT_TYPE "force", 0, 0, XrdCpConfig::OpForce},
103 {OPT_TYPE "header", 1, 0, XrdCpConfig::OpHttpHeader},
104 {OPT_TYPE "help", 0, 0, XrdCpConfig::OpHelp},
105 {OPT_TYPE "infiles", 1, 0, XrdCpConfig::OpIfile},
106 {OPT_TYPE "license", 0, 0, XrdCpConfig::OpLicense},
107 {OPT_TYPE "nopbar", 0, 0, XrdCpConfig::OpNoPbar},
108 {OPT_TYPE "notlsok", 0, 0, XrdCpConfig::OpNoTlsOK},
109 {OPT_TYPE "parallel", 1, 0, XrdCpConfig::OpParallel},
110 {OPT_TYPE "path", 0, 0, XrdCpConfig::OpPath},
111 {OPT_TYPE "posc", 0, 0, XrdCpConfig::OpPosc},
112 {OPT_TYPE "proxy", 1, 0, XrdCpConfig::OpProxy},
113 {OPT_TYPE "recursive", 0, 0, XrdCpConfig::OpRecurse},
114 {OPT_TYPE "retry", 1, 0, XrdCpConfig::OpRetry},
115 {OPT_TYPE "retry-policy", 1, 0, XrdCpConfig::OpRetryPolicy},
116 {OPT_TYPE "rm-bad-cksum", 0, 0, XrdCpConfig::OpRmOnBadCksum},
117 {OPT_TYPE "server", 0, 0, XrdCpConfig::OpServer},
118 {OPT_TYPE "silent", 0, 0, XrdCpConfig::OpSilent},
119 {OPT_TYPE "sources", 1, 0, XrdCpConfig::OpSources},
120 {OPT_TYPE "streams", 1, 0, XrdCpConfig::OpStreams},
121 {OPT_TYPE "tlsmetalink", 0, 0, XrdCpConfig::OpTlsMLF},
122 {OPT_TYPE "tlsnodata", 0, 0, XrdCpConfig::OpTlsNoData},
123 {OPT_TYPE "tpc", 1, 0, XrdCpConfig::OpTpc},
124 {OPT_TYPE "tpc-token-file", 1, 0, XrdCpConfig::OpTpcTokenFile},
125 {OPT_TYPE "verbose", 0, 0, XrdCpConfig::OpVerbose},
126 {OPT_TYPE "version", 0, 0, XrdCpConfig::OpVersion},
127 {OPT_TYPE "xattr", 0, 0, XrdCpConfig::OpXAttr},
128 {OPT_TYPE "xrate", 1, 0, XrdCpConfig::OpXrate},
129 {OPT_TYPE "xrate-threshold",1, 0, XrdCpConfig::OpXrateThreshold},
130 {OPT_TYPE "zip", 1, 0, XrdCpConfig::OpZip},
131 {OPT_TYPE "zip-append", 0, 0, XrdCpConfig::OpZipAppend},
132 {OPT_TYPE "zip-mtln-cksum", 0, 0, XrdCpConfig::OpZipMtlnCksum},
133 {0, 0, 0, 0}
134 };
135
136/******************************************************************************/
137/* C o n s t r u c t o r */
138/******************************************************************************/
139
141{
142 if ((PName = rindex(pgm, '/'))) PName++;
143 else PName = pgm;
145 intDefs = 0;
146 intDend = 0;
147 strDefs = 0;
148 strDend = 0;
149 dstOpq = 0;
150 srcOpq = 0;
151 pHost = 0;
152 pPort = 0;
153 xRate = 0;
154 xRateThreshold = 0;
155 Parallel = 1;
156 OpSpec = 0;
157 Dlvl = 0;
158 nSrcs = 1;
159 nStrm = 0;
160 Retry =-1;
161 RetryPolicy = "force";
162 Verbose = 0;
163 numFiles = 0;
164 totBytes = 0;
165 CksLen = 0;
166 CksMan = 0;
167 CksObj = 0;
168 CksVal = 0;
169 srcFile = 0;
170 dstFile = 0;
171 inFile = 0;
172 parmVal = 0;
173 parmCnt = 0;
174 zipFile = 0;
175
176 tcpTokenFile = 0;
177 if (const auto value = getenv("BEARER_TOKEN_FILE"); value != nullptr)
178 tcpTokenFile = strdup(value);
179}
180
181/******************************************************************************/
182/* D e s t r u c t o r */
183/******************************************************************************/
184
186{
187 XrdCpFile *pNow;
188 defVar *dP;
189
190 if (inFile) free(inFile);
191 if (pHost) free(pHost);
192 if (parmVal) free(parmVal);
193 if (CksObj) delete CksObj;
194 if (CksMan) delete CksMan;
195 if (zipFile) free(zipFile);
196 if (tcpTokenFile) free(tcpTokenFile);
197 if (dstFile) delete dstFile;
198
199 while((pNow = pFile)) {pFile = pFile->Next; delete pNow;}
200
201 while((dP = intDefs)) {intDefs = dP->Next; delete dP;}
202 while((dP = strDefs)) {strDefs = dP->Next; delete dP;}
203
204}
205
206/******************************************************************************/
207/* C o n f i g */
208/******************************************************************************/
209
210void XrdCpConfig::Config(int aCnt, char **aVec, int opts)
211{
212 extern char *optarg;
213 extern int optind, opterr;
214 static int pgmSet = 0;
215 char Buff[128], *Path, opC;
216 XrdCpFile pBase;
217 int i, rc;
218
219// Allocate a parameter vector
220//
221 if (parmVal) free(parmVal);
222 parmVal = (char **)malloc(aCnt*sizeof(char *));
223
224// Preset handling options
225//
226 Argv = aVec;
227 Argc = aCnt;
228 Opts = opts;
229 opterr = 0;
230 optind = 1;
231 opC = 0;
232
233// Set name of executable for error messages
234//
235 if (!pgmSet)
236 {char *Slash = rindex(aVec[0], '/');
237 pgmSet = 1;
238 Pgm = (Slash ? Slash+1 : aVec[0]);
239 Log->SetPrefix(Pgm);
240 }
241
242// Process legacy options first before atempting normal options
243//
244do{while(optind < Argc && Legacy(optind)) {}
245 if ((opC = getopt_long(Argc, Argv, opLetters, opVec, &i)) != (char)-1)
246 switch(opC)
247 {case OpCksum: defCks(optarg);
248 break;
249 case OpCoerce: OpSpec |= DoCoerce;
250 break;
251 case OpDebug: OpSpec |= DoDebug;
252 if (!a2i(optarg, &Dlvl, 0, 3)) Usage(22);
253 break;
254 case OpDynaSrc: OpSpec |= DoDynaSrc;
255 break;
256 case OpForce: OpSpec |= DoForce;
257 break;
258 case OpZip: OpSpec |= DoZip;
259 if (zipFile) free(zipFile);
260 zipFile = strdup(optarg);
261 break;
263 HttpHeaders.push_back(optarg);
264 break;
265 case OpHelp: Usage(0);
266 break;
267 case OpIfile: if (inFile) free(inFile);
268 inFile = strdup(optarg);
269 OpSpec |= DoIfile;
270 break;
271 case OpLicense: License();
272 break;
273 case OpNoPbar: OpSpec |= DoNoPbar;
274 break;
275 case OpNoTlsOK: OpSpec |= DoNoTlsOK;
276 break;
277 case OpPath: OpSpec |= DoPath;
278 break;
279 case OpPosc: OpSpec |= DoPosc;
280 break;
281 case OpProxy: OpSpec |= DoProxy;
282 defPxy(optarg);
283 break;
284 case OpRecurse: OpSpec |= DoRecurse;
285 break;
286 case OpRecursv: OpSpec |= DoRecurse;
287 break;
288 case OpRetry: OpSpec |= DoRetry;
289 if (!a2i(optarg, &Retry, 0, -1)) Usage(22);
290 break;
292 RetryPolicy = optarg;
293 if( RetryPolicy != "force" && RetryPolicy != "continue" ) Usage(22);
294 break;
296 break;
298 break;
300 break;
301 case OpSources: OpSpec |= DoSources;
302 if (!a2i(optarg, &nSrcs, 1, 32)) Usage(22);
303 break;
304 case OpStreams: OpSpec |= DoStreams;
305 if (!a2i(optarg, &nStrm, 1, 15)) Usage(22);
306 break;
308 break;
309 case OpTlsMLF: OpSpec |= DoTlsMLF;
310 break;
311 case OpTpc: OpSpec |= DoTpc;
312 if (!strcmp("delegate", optarg))
313 {OpSpec|= DoTpcDlgt;
314 if (optind >= Argc)
315 {UMSG("Missing tpc qualifier after "
316 "'delegate'");
317 }
318 optarg = Argv[optind++];
319 }
320 if (!strcmp("push", optarg))
322 if (optind >= Argc)
323 {UMSG("Missing tpc qualifier after "
324 "'push'");
325 }
326 optarg = Argv[optind++];
327 }
328 if (!strcmp("only", optarg)) OpSpec|= DoTpcOnly;
329 else if (strcmp("first", optarg))
330 {optind--;
331 UMSG("Invalid option, '" <<OpName()
332 <<' ' <<optarg <<"' ");
333 }
334 break;
336 if (tcpTokenFile) free(tcpTokenFile);
337 tcpTokenFile = strdup(optarg);
338 break;
339 case OpVerbose: OpSpec |= DoVerbose;
340 Verbose = 1;
341 break;
342 case OpVersion: std::cerr <<XrdVERSION <<std::endl; exit(0);
343 break;
344 case OpXrate: OpSpec |= DoXrate;
345 if (!a2z(optarg, &xRate, 10*1024LL, -1)) Usage(22);
346 break;
348 if (!a2z(optarg, &xRateThreshold, 10*1024LL, -1)) Usage(22);
349 break;
351 if (!a2i(optarg, &Parallel, 1, 128)) Usage(22);
352 break;
353 case OpXAttr : OpSpec |= DoXAttr;
354 break;
356 break;
358 break;
359 case OpContinue : OpSpec |= DoContinue;
360 break;
361 case ':': UMSG("'" <<OpName() <<"' argument missing.");
362 break;
363 case '?': if (!Legacy(optind-1))
364 UMSG("Invalid option, '" <<OpName() <<"'.");
365 break;
366 default: UMSG("Internal error processing '" <<OpName() <<"'.");
367 break;
368 }
369 } while(opC != (char)-1 && optind < Argc);
370
371// Make sure we have the right number of files
372//
373 if (inFile) {if (!parmCnt ) UMSG("Destination not specified.");}
374 else { if (!parmCnt ) UMSG("No files specified.");
375 if ( parmCnt == 1 ) UMSG("Destination not specified.");
376 }
377
378// Check for conflicts wit third party copy
379//
380 if (OpSpec & DoTpc && nSrcs > 1)
381 UMSG("Third party copy requires a single source.");
382
383// Check for conflicts with ZIP archive
384//
385 if( OpSpec & DoZip & DoCksrc )
386 UMSG("Cannot calculate source checksum for a file in ZIP archive.");
387
388 if( ( OpSpec & DoZip & DoCksum ) && !CksData.HasValue() )
389 UMSG("Cannot calculate source checksum for a file in ZIP archive.");
390
391// Turn off verbose if we are in server mode
392//
393 if (OpSpec & DoServer)
394 {OpSpec &= ~DoVerbose;
395 Verbose = 0;
396 }
397
398// Turn on auto-path creation if requested via envar
399//
400 if (getenv("XRD_MAKEPATH")) OpSpec |= DoPath;
401
402// Process the destination first as it is special
403//
404 dstFile = new XrdCpFile(parmVal[--parmCnt], rc);
405 if (rc) FMSG("Invalid url, '" <<dstFile->Path <<"'.", 22);
406
407// Do a protocol check
408//
417 {FMSG(dstFile->ProtName <<"file protocol is not supported.", 22)}
418
419// Resolve this file if it is a local file
420//
423 if (isLcl && (rc = dstFile->Resolve()))
424 {if (rc != ENOENT || (Argc - optind - 1) > 1 || OpSpec & DoRecurse)
425 FMSG(XrdSysE2T(rc) <<" processing " <<dstFile->Path, 2);
426 }
427
428// Now pick up all the source files from the command line
429//
430 pLast = &pBase;
431 for (i = 0; i < parmCnt; i++) ProcFile(parmVal[i]);
432
433// If an input file list was specified, process it as well
434//
435 if (inFile)
437 char *fname;
438 int inFD = open(inFile, O_RDONLY);
439 if (inFD < 0) FMSG(XrdSysE2T(errno) <<" opening infiles " <<inFile, 2);
440 inList.Attach(inFD);
441 while((fname = inList.GetLine())) if (*fname) ProcFile(fname);
442 }
443
444// Check if we have any sources or too many sources
445//
446 srcFile = pBase.Next;
447
448 if (!numFiles || !srcFile)
449 UMSG("Source not specified.");
450
451 if (Opts & opt1Src && numFiles > 1)
452 FMSG("Only a single source is allowed.", 2);
453
454// Check if we have an appropriate destination
455//
458 FMSG("Destination is neither remote nor a directory.", 2);
459
460// Do the dumb check
461//
462 if (isLcl && Opts & optNoLclCp)
463 FMSG("All files are local; use 'cp' instead!", 1);
464
465// Injected headers only apply to http and https endpoints
466//
467 if (OpSpec & DoHttpHeader)
468 {if (!isHttpProt(srcFile->Protocol) && !isHttpProt(dstFile->Protocol))
469 UMSG("'--header' requires an http or https source or destination.");
470 }
471
472// Check for checksum spec conflicts
473//
474 if (OpSpec & DoCksum)
475 {if (CksData.Length && numFiles > 1)
476 FMSG("Checksum with fixed value requires a single input file.", 2);
478 FMSG("Checksum with fixed value conflicts with '--recursive'.", 2);
479 }
480
481// Now extend all local sources if recursive is in effect
482//
483 if (OpSpec & DoRecurse && !(Opts & optNoXtnd))
484 {pPrev = &pBase; pBase.Next = srcFile;
485 while((pFile = pPrev->Next))
486 {if (pFile->Protocol != XrdCpFile::isDir) pPrev = pFile;
487 else {Path = pFile->Path;
488 pPrev->Next = pFile->Next;
489 if (Verbose) EMSG("Indexing files in " <<Path);
490 numFiles--;
491 if ((rc = pFile->Extend(&pLast, numFiles, totBytes)))
492 FMSG(XrdSysE2T(rc) <<" indexing " <<Path, 2);
493 if (pFile->Next)
494 {pLast->Next = pPrev->Next;
495 pPrev->Next = pFile->Next;
496 }
497 delete pFile;
498 }
499 }
500 if (!(srcFile = pBase.Next))
501 FMSG("No regular files found to copy!", 2);
502 if (Verbose) EMSG("Copying " <<Human(totBytes, Buff, sizeof(Buff))
503 <<" from " <<numFiles
504 <<(numFiles != 1 ? " files." : " file."));
505 }
506}
507
508/******************************************************************************/
509/* P r i v a t e M e t h o d s */
510/******************************************************************************/
511/******************************************************************************/
512/* Private: a 2 i */
513/******************************************************************************/
514
515int XrdCpConfig::a2i(const char *item, int *val, int minv, int maxv)
516{
517 char *eP;
518
519// Convert the numeric argument
520//
521 errno = 0;
522 *val = strtol(item, &eP, 10);
523 if (errno || *eP) ZMSG("'" <<OpName() <<"' argument is not a number.");
524
525// Impose min/max limits
526//
527 if (*val < minv)
528 ZMSG("'" <<OpName() <<"' argument must be >= " <<minv <<'.');
529 if (maxv >= 0 && *val > maxv)
530 ZMSG("'" <<OpName() <<"' argument must be <= " <<maxv <<'.');
531 return 1;
532}
533/******************************************************************************/
534/* Private: a 2 l */
535/******************************************************************************/
536
537int XrdCpConfig::a2l(const char *item, long long *val,
538 long long minv, long long maxv)
539{
540 char *eP;
541
542// Convert the numeric argument
543//
544 errno = 0;
545 *val = strtoll(item, &eP, 10);
546 if (errno || *eP) ZMSG("'" <<OpName() <<"' argument is not a number.");
547
548// Impose min/max limits
549//
550 if (*val < minv)
551 ZMSG("'" <<OpName() <<"' argument must be >= " <<minv <<'.');
552 if (maxv >= 0 && *val > maxv)
553 ZMSG("'" <<OpName() <<"' argument must be <= " <<maxv <<'.');
554 return 1;
555}
556
557/******************************************************************************/
558/* Private: a 2 t */
559/******************************************************************************/
560
561int XrdCpConfig::a2t(const char *item, int *val, int minv, int maxv)
562{ int qmult;
563 char *eP, *fP = (char *)item + strlen(item) - 1;
564
565// Get scaling
566//
567 if (*fP == 's' || *fP == 'S') qmult = 1;
568 else if (*fP == 'm' || *fP == 'M') qmult = 60;
569 else if (*fP == 'h' || *fP == 'H') qmult = 60*60;
570 else if (*fP == 'd' || *fP == 'D') qmult = 60*60*24;
571 else {qmult = 1; fP++;}
572
573// Convert the value
574//
575 errno = 0;
576 *val = strtoll(item, &eP, 10) * qmult;
577 if (errno || eP != fP)
578 ZMSG("'" <<OpName() <<"' argument is not a valid time.");
579
580// Impose min/max limits
581//
582 if (*val < minv)
583 ZMSG("'" <<OpName() <<"' argument must be >= " <<minv <<'.');
584 if (maxv >= 0 && *val > maxv)
585 ZMSG("'" <<OpName() <<"' argument must be <= " <<maxv <<'.');
586 return 1;
587}
588
589/******************************************************************************/
590/* Private: a 2 x */
591/******************************************************************************/
592
593int XrdCpConfig::a2x(const char *Val, char *Buff, int Vlen)
594{
595 int n, i = 0, Odd = 0;
596 if (Vlen & 0x01) return 0;
597 while(Vlen--)
598 { if (*Val >= '0' && *Val <= '9') n = *Val-48;
599 else if (*Val >= 'a' && *Val <= 'f') n = *Val-87;
600 else if (*Val >= 'A' && *Val <= 'F') n = *Val-55;
601 else return 0;
602 if (Odd) Buff[i++] |= n;
603 else Buff[i ] = n << 4;
604 Val++; Odd = ~Odd;
605 }
606 return 1;
607}
608
609/******************************************************************************/
610/* Private: a 2 z */
611/******************************************************************************/
612
613int XrdCpConfig::a2z(const char *item, long long *val,
614 long long minv, long long maxv)
615{ long long qmult;
616 char *eP, *fP = (char *)item + strlen(item) - 1;
617
618// Get scaling
619//
620 if (*fP == 'k' || *fP == 'K') qmult = 1024LL;
621 else if (*fP == 'm' || *fP == 'M') qmult = 1024LL*1024LL;
622 else if (*fP == 'g' || *fP == 'G') qmult = 1024LL*1024LL*1024LL;
623 else if (*fP == 't' || *fP == 'T') qmult = 1024LL*1024LL*1024LL*1024LL;
624 else {qmult = 1; fP++;}
625
626// Convert the value
627//
628 errno = 0;
629 *val = strtoll(item, &eP, 10) * qmult;
630 if (errno || eP != fP)
631 ZMSG("'" <<OpName() <<"' argument is not a valid time.");
632
633// Impose min/max limits
634//
635 if (*val < minv)
636 ZMSG("'" <<OpName() <<"' argument must be >= " <<minv <<'.');
637 if (maxv >= 0 && *val > maxv)
638 ZMSG("'" <<OpName() <<"' argument must be <= " <<maxv <<'.');
639 return 1;
640}
641
642/******************************************************************************/
643/* Private: d e f C k s */
644/******************************************************************************/
645
646int XrdCpConfig::defCks(const char *opval)
647{
648 if( CksVal )
649 {
650 std::string cksum( opval );
651 size_t pos = cksum.find( ':' );
652 std::string mode = cksum.substr( pos + 1 );
653 if( mode != "source" )
654 FMSG("Additional checksum must be of mode 'source'.", 13);
655 AddCksVal.push_back( cksum.substr( 0, pos ) );
656 return 1;
657 }
658
659 static XrdVERSIONINFODEF(myVer, xrdcp, XrdVNUMBER, XrdVERSION);
660 const char *Colon = index(opval, ':');
661 char csName[XrdCksData::NameSize];
662 int n;
663
664// Initialize the checksum manager if we have not done so already
665//
666 if (!CksMan)
667 {CksMan = new XrdCksManager(Log, 0, myVer, true);
668 if (!(CksMan->Init("")))
669 {delete CksMan; CksMan = 0;
670 FMSG("Unable to initialize checksum processing.", 13);
671 }
672 }
673
674// Copy out the checksum name
675//
676 n = (Colon ? Colon - opval : strlen(opval));
677 if (n >= XrdCksData::NameSize)
678 UMSG("Invalid checksum type, '" <<opval <<"'.");
679 strncpy(csName, opval, n); csName[n] = 0;
680 toLower( csName );
681
682// Get a checksum object for this checksum
683//
684 if( strcmp( csName, "auto" ) )
685 {
686 if (CksObj) {delete CksObj; CksObj = 0;}
687 if (!CksData.Set(csName) || !(CksObj = CksMan->Object(CksData.Name)))
688 UMSG("Invalid checksum type, '" <<csName <<"'.");
690 }
691
692// Reset checksum information
693//
694 CksData.Length = 0;
695 OpSpec &= ~(DoCkprt | DoCksrc | DoCksum);
696
697// Check for any additional arguments
698//
699 if (Colon)
700 {Colon++;
701 if (!(*Colon)) UMSG(CksData.Name <<" argument missing after ':'.");
702 if (!strcmp(Colon, "print")) OpSpec |= (DoCkprt | DoCksum);
703 else if (!strcmp(Colon, "source")) OpSpec |= (DoCkprt | DoCksrc);
704 else {n = strlen(Colon);
705 if (n != CksLen*2 || !CksData.Set(Colon, n))
706 UMSG("Invalid " <<CksData.Name <<" value '" <<Colon <<"'.");
707 OpSpec |= DoCksum;
708 }
709 } else OpSpec |= DoCksum;
710
711// All done
712//
713 CksVal = opval;
714 return 1;
715}
716
717/******************************************************************************/
718/* Private: d e f O p q */
719/******************************************************************************/
720
721int XrdCpConfig::defOpq(const char *theOp)
722{
723 const char *oVal = theOp+3;
724
725// Make sure opaque information was specified
726//
727 if (!(*oVal)) UMSG("'" <<theOp <<"' opaque data not specified.");
728
729// Set proper opaque data
730//
731 if (*(theOp+2) == 'S') srcOpq = oVal;
732 else dstOpq = oVal;
733
734// All done
735//
736 return 1;
737}
738
739/******************************************************************************/
740/* Private: d e f O p t */
741/******************************************************************************/
742
743int XrdCpConfig::defOpt(const char *theOp, const char *theArg)
744{
745 defVar *dP;
746 int opval, isInt = (*(theOp+2) == 'I');
747 const char *vName = theOp+3;
748 char *eP;
749
750// Make sure define variable name specified
751//
752 if (!(*vName)) UMSG("'" <<theOp <<"' variable not specified.");
753
754// Make sure we have a value
755//
756 if (!theArg) UMSG("'" <<theOp <<"' argument not specified.");
757
758// For integer arguments convert the value
759//
760 if (isInt)
761 {errno = 0;
762 opval = strtol(theArg, &eP, 10);
763 if (errno || *eP) UMSG("'" <<theOp <<"' argument is not a number.");
764 dP = new defVar(vName, opval);
765 if (!intDend) intDefs = intDend = dP;
766 else {intDend->Next = dP; intDend = dP;}
767 } else {
768 dP = new defVar(vName, theArg);
769 if (!strDend) strDefs = strDend = dP;
770 else {strDend->Next = dP; strDend = dP;}
771 }
772
773// Convert the argument
774//
775 return 2;
776}
777
778/******************************************************************************/
779/* Private: d e f P x y */
780/******************************************************************************/
781
782void XrdCpConfig::defPxy(const char *opval)
783{
784 const char *Colon = index(opval, ':');
785 char *eP;
786 int n;
787
788// Make sure the host was specified
789//
790 if (Colon == opval) UMSG("Proxy host not specified.");
791
792// Make sure the port was specified
793//
794 if (!Colon || !(*(Colon+1))) UMSG("Proxy port not specified.");
795
796// Make sure the port is a valid number that is not too big
797//
798 errno = 0;
799 pPort = strtol(Colon+1, &eP, 10);
800 if (errno || *eP || pPort < 1 || pPort > 65535)
801 UMSG("Invalid proxy port, '" <<opval <<"'.");
802
803// Copy out the proxy host
804//
805 if (pHost) free(pHost);
806 n = Colon - opval + 1;
807 pHost = (char *)malloc(n);
808 strncpy(pHost, opval, n-1);
809 pHost[n-1] = 0;
810}
811
812
813/******************************************************************************/
814/* H u m a n */
815/******************************************************************************/
816
817const char *XrdCpConfig::Human(long long inval, char *Buff, int Blen)
818{
819 static const char *sfx[] = {" bytes", "KB", "MB", "GB", "TB", "PB"};
820 unsigned int i;
821
822 for (i = 0; i < sizeof(sfx)/sizeof(sfx[0]) - 1 && inval >= 1024; i++)
823 inval = inval/1024;
824
825 snprintf(Buff, Blen, "%lld%s", inval, sfx[i]);
826 return Buff;
827}
828
829/******************************************************************************/
830/* Private: L e g a c y */
831/******************************************************************************/
832
833int XrdCpConfig::Legacy(int oIndex)
834{
835 extern int optind;
836 char *oArg;
837 int rc;
838
839// if (!Argv[oIndex]) return 0;
840
841 while(oIndex < Argc && (*Argv[oIndex] != '-' || *(Argv[oIndex]+1) == '\0'))
842 parmVal[parmCnt++] = Argv[oIndex++];
843 if (oIndex >= Argc) return 0;
844
845 if (oIndex+1 >= Argc || *Argv[oIndex+1] == '-') oArg = 0;
846 else oArg = Argv[oIndex+1];
847 if (!(rc = Legacy(Argv[oIndex], oArg))) return 0;
848 optind = oIndex + rc;
849
850 return 1;
851}
852
853/******************************************************************************/
854
855int XrdCpConfig::Legacy(const char *theOp, const char *theArg)
856{
857 if (!strcmp(theOp, "-adler")) return defCks("adler32:source");
858
859 if (!strncmp(theOp, "-DI", 3) || !strncmp(theOp, "-DS", 3))
860 return defOpt(theOp, theArg);
861
862 if (!strcmp(theOp, "-extreme") || !strcmp(theOp, "-x"))
863 {if (nSrcs <= 1) {nSrcs = dfltSrcs; OpSpec |= DoSources;}
864 return 1;
865 }
866
867 if (!strcmp(theOp, "-np")) {OpSpec |= DoNoPbar; return 1;}
868
869 if (!strcmp(theOp, "-md5")) return defCks("md5:source");
870
871 if (!strncmp(theOp,"-OD",3) || !strncmp(theOp,"-OS",3)) return defOpq(theOp);
872
873 if (!strcmp(theOp, "-version")) {std::cerr <<XrdVERSION <<std::endl; exit(0);}
874
875 if (!strcmp(theOp, "-force"))
876 FMSG("-force is no longer supported; use --retry instead!",22);
877
878 return 0;
879}
880
881/******************************************************************************/
882/* Private: L i c e n s e */
883/******************************************************************************/
884
885void XrdCpConfig::License()
886{
887 const char *theLicense =
888#include "../../LICENSE"
889;
890
891 std::cerr <<theLicense;
892 exit(0);
893}
894
895/******************************************************************************/
896/* Private: O p N a m e */
897/******************************************************************************/
898
899const char *XrdCpConfig::OpName()
900{
901 extern int optind, optopt;
902 static char oName[4] = {'-', 0, 0, 0};
903
904 if (!optopt || optopt == '-' || *(Argv[optind-1]+1) == '-')
905 return Argv[optind-1];
906 oName[1] = optopt;
907 return oName;
908}
909
910/******************************************************************************/
911/* p r o c F i l e */
912/******************************************************************************/
913
914void XrdCpConfig::ProcFile(const char *fname)
915{
916 int rc;
917
918// Chain in this file in the input list
919//
920 pLast->Next = pFile = new XrdCpFile(fname, rc);
921 if (rc) FMSG("Invalid url, '" <<fname <<"'.", 22);
922
923// For local files, make sure it exists and get its size
924//
925 if (pFile->Protocol == XrdCpFile::isFile && (rc = pFile->Resolve()))
926 FMSG(XrdSysE2T(rc) <<" processing " <<pFile->Path, 2);
927
928// Process file based on type (local or remote)
929//
930 if (pFile->Protocol == XrdCpFile::isFile) totBytes += pFile->fSize;
931 else if (pFile->Protocol == XrdCpFile::isDir)
932 {if (!(OpSpec & DoRecurse))
933 FMSG(pFile->Path <<" is a directory.", 2);
934 }
935 else if (pFile->Protocol == XrdCpFile::isStdIO)
936 {if (Opts & optNoStdIn)
937 FMSG("Using stdin as a source is disallowed.", 22);
938 if (numFiles)
939 FMSG("Multiple sources disallowed with stdin.", 22);
940 }
941 else if (!((pFile->Protocol == XrdCpFile::isXroot) ||
942 (pFile->Protocol == XrdCpFile::isXroots) ||
943 (pFile->Protocol == XrdCpFile::isHttp) ||
944 (pFile->Protocol == XrdCpFile::isHttps) ||
945 (pFile->Protocol == XrdCpFile::isPelican) ||
946 (pFile->Protocol == XrdCpFile::isS3)))
947 {FMSG(pFile->ProtName <<" file protocol is not supported.", 22)}
948 else if (OpSpec & DoRecurse && !(Opts & optRmtRec))
949 {FMSG("Recursive copy from a remote host is not supported.",22)}
950 else isLcl = 0;
951
952// Update last pointer and we are done if this is stdin
953//
954 numFiles++;
955 pLast = pFile;
956}
957
958/******************************************************************************/
959/* U s a g e */
960/******************************************************************************/
961
962void XrdCpConfig::Usage(int rc)
963{
964 static const char *Syntax = "\n"
965 "Usage: xrdcp [<options>] <src> [<src> [. . .]] <dest>\n";
966
967 static const char *Syntax1= "\n"
968 "Usage: xrdcp [<options>] <src> <dest>\n";
969
970 static const char *Options= "\n"
971 "Options: [--cksum <args>] [--coerce] [--continue]\n"
972 " [--debug <lvl>] [--dynamic-src] [--force] [--header <name: value>]\n"
973 " [--help] [--infiles <fn>] [--license] [--nopbar] [--notlsok]\n"
974 " [--parallel <n>] [--posc] [--proxy <host>:<port>]\n"
975 " [--recursive] [--retry <n>] [--retry-policy <force|continue>]\n"
976 " [--rm-bad-cksum] [--server] [--silent] [--sources <n>]\n"
977 " [--streams <n>] [--tlsmetalink] [--tlsnodata]\n"
978 " [--tpc [delegate] [push] {first|only}] [--verbose] [--version]\n"
979 " [--tpc-token-file <file>]\n"
980 " [--xattr] [--xrate <rate>] [--xrate-threshold <rate>]\n"
981 " [--zip <file>] [--zip-append] [--zip-mtln-cksum]\n";
982
983 static const char *Syntax2= "\n"
984 "<src>: [[x]root[s]://<host>[:<port>]/]<path> | -";
985
986 static const char *Syntay2= "\n"
987 "<src>: [[x]root[s]://<host>[:<port>]/]<path>";
988
989 static const char *Syntax3= "\n"
990 "<dest>: [[x]root[s]://<host>[:<port>]/]<path> | -";
991
992 static const char *Detail = "\n"
993 "Note: using a dash (-) for <src> uses stdin and for <dest> stdout\n\n"
994 "-C | --cksum <args> verifies the checksum at the destination as provided\n"
995 " by the source server or locally computed. The args are\n"
996 " <ckstype>[:{<value>|print|source}]\n"
997 " where <ckstype> is one of adler32, crc32, crc32c, md5,\n"
998 " zcrc32 or auto. If 'auto' is chosen, xrdcp will try to\n"
999 " automatically infer the right checksum type based on the\n"
1000 " source/destination configuration, source file type\n"
1001 " (e.g. metalink, ZIP), and available checksum plug-ins.\n"
1002 " If the hex value of the checksum is given, it is used.\n"
1003 " Otherwise, the server's checksum is used for remote files\n"
1004 " and computed for local files. Specifying print merely\n"
1005 " prints the checksum but does not verify it.\n"
1006 "-F | --coerce coerces the copy by ignoring file locking semantics\n"
1007 " --continue continue copying a file from the point where the previous\n"
1008 " copy was interrupted\n"
1009 "-d | --debug <lvl> sets the debug level: 0 off, 1 low, 2 medium, 3 high\n"
1010 "-Z | --dynamic-src file size may change during the copy\n"
1011 "-f | --force replaces any existing output file\n"
1012 "-H | --header <name: value> adds the given header to the requests sent to an\n"
1013 " http or https endpoint. May be repeated to add more\n"
1014 " than one header. Requires an http or https source or\n"
1015 " destination. The hop-by-hop and message framing\n"
1016 " headers are reserved and cannot be overridden.\n"
1017 " With --tpc, the headers go to the server the client\n"
1018 " connects to: the destination server in 'pull' mode,\n"
1019 " or the source server in 'push' mode. To send a header\n"
1020 " to the other server, prepend 'TransferHeader' to the\n"
1021 " header name. Example, in 'pull' mode:\n"
1022 " -H \"X-Request-Id: <destination-id>\"\n"
1023 " -H \"TransferHeaderX-Request-Id: <source-id>\"\n"
1024 " The destination server gets the X-Request-Id header,\n"
1025 " and sends the value of TransferHeaderX-Request-Id as\n"
1026 " the X-Request-Id header of its request to the source.\n"
1027 " If the option is not specified, the XRD_HTTPHEADERS\n"
1028 " environment variable is used instead. It holds the\n"
1029 " headers as a newline separated list of\n"
1030 " '<name>: <value>' entries.\n"
1031 "-h | --help prints this information\n"
1032 "-I | --infiles <fname> specifies the file that contains a list of input files\n"
1033 " --license prints license terms and conditions\n"
1034 "-N | --nopbar does not print the progress bar\n"
1035 " --notlsok if server is too old to support TLS encryption fallback\n"
1036 " to unencrypted communication\n"
1037 " --parallel <n> number of files to copy at the same time\n"
1038 "-P | --posc enables persist on successful close semantics\n"
1039 "-D | --proxy <host>:<port> uses the specified SOCKS4 proxy connection\n"
1040 "-r | --recursive recursively copies all source files\n"
1041 "-t | --retry <n> maximum number of times to retry failed copy-jobs\n"
1042 " --retry-policy <policy> retry policy: force or continue\n"
1043 " --rm-bad-cksum remove the target file if checksum verification failed\n"
1044 " (enables also POSC semantics)\n"
1045 " --server runs in a server environment with added operations\n"
1046 "-s | --silent produces no output other than error messages\n"
1047 "-y | --sources <n> uses up to the number of sources specified in parallel\n"
1048 "-S | --streams <n> copies using the specified number of TCP connections\n"
1049 " --tlsmetalink convert [x]root to [x]roots protocol in metalinks\n"
1050 "-E | --tlsnodata in case of [x]roots protocol, encrypt only the control\n"
1051 " stream and leave the data streams unencrypted\n"
1052 "-T | --tpc <args> uses third party copy mode between the src and dest.\n"
1053 " Both the src and dest must allow tpc mode. Argument\n"
1054 " 'first' tries tpc and if it fails, does a normal copy;\n"
1055 " while 'only' fails the copy unless tpc succeeds.\n"
1056 " Argument 'push' drives the copy from the source server,\n"
1057 " which pushes the data to the destination; by default the\n"
1058 " destination server pulls the data from the source. A push\n"
1059 " copy only applies to tpc over HTTP(S).\n"
1060 " --tpc-token-file <file> Specify a token file containing in the first line the\n"
1061 " <src> token and in the second line the <dst> token. In\n"
1062 " case the file is a JSON object, the <src> and <dst>\n"
1063 " tokens are taken from its 'src' and 'dst' properties.\n"
1064 " Either token may be left out, by an empty line or by an\n"
1065 " omitted property, but not both.\n"
1066 " In case no file is specified the BEARER_TOKEN_FILE env\n"
1067 " variable will be used.\n"
1068 "-v | --verbose produces more information about the copy\n"
1069 "-V | --version prints the version number\n"
1070 " --xattr preserve extended attributes\n"
1071 "-X | --xrate <rate> limits the transfer to the specified rate. You can\n"
1072 " suffix the value with 'k', 'm', or 'g'\n"
1073 " --xrate-threshold <rate> If the transfer rate drops below given threshold force\n"
1074 " the client to use different source or if no more sources\n"
1075 " are available fail the transfer. You can suffix the value\n"
1076 " with 'k', 'm', or 'g'\n"
1077 "-z | --zip <file> treat the source as a ZIP archive containing given file\n"
1078 " --zip-append append file to existing zip archive\n"
1079 " --zip-mtln-cksum use the checksum available in a metalink file even if\n"
1080 " a file is being extracted from a ZIP archive\n"
1081 "\n"
1082 "Legacy options: [-adler] [-DI<var> <val>] [-DS<var> <val>] [-np]\n"
1083 " [-md5] [-OD<cgi>] [-OS<cgi>] [-version] [-x]";
1084
1085 std::cerr <<(Opts & opt1Src ? Syntax1 : Syntax) <<Options;
1086 std::cerr <<(Opts & optNoStdIn ? Syntay2 : Syntax2) <<Syntax3 <<std::endl;
1087 if (!rc) std::cerr <<Detail <<std::endl;
1088 exit(rc);
1089}
int inList(const char *var, const char **Vec)
#define OPT_TYPE
#define ZMSG(x)
#define FMSG(x, y)
#define EMSG(x)
#define UMSG(x)
XrdSysError eDest(0, "HttpMon")
int optopt
int optind
#define open
Definition XrdPosix.hh:78
XrdOucString Path
struct myOpts opts
const char * XrdSysE2T(int errcode)
Definition XrdSysE2T.cc:104
virtual const char * Type(int &csSize)=0
int Set(const char *csName)
Definition XrdCksData.hh:81
bool HasValue()
static const int NameSize
Definition XrdCksData.hh:41
char Name[NameSize]
Definition XrdCksData.hh:44
XrdCksManager(XrdSysError *erP, int iosz, XrdVersionInfo &vInfo, bool autoload=false)
virtual int Init(const char *ConfigFN, const char *DfltCalc=0)=0
virtual XrdCksCalc * Object(const char *name)
Definition XrdCks.hh:214
static const uint64_t OpVerbose
static const uint64_t OpXAttr
static const uint64_t DoProxy
defVar * intDefs
void Config(int argc, char **argv, int Opts=0)
static const uint64_t OpRecurse
char * tcpTokenFile
XrdCksCalc * CksObj
static const uint64_t OpContinue
static const uint64_t DoRetry
static const uint64_t DoStreams
std::vector< std::string > AddCksVal
static const uint64_t OpParallel
static const uint64_t OpZipAppend
const char * dstOpq
static const uint64_t DoZipMtlnCksum
XrdCksData CksData
static const uint64_t OpSilent
static const uint64_t OpTlsMLF
static const uint64_t OpNoTlsOK
XrdCks * CksMan
XrdCpFile * srcFile
const char * Pgm
XrdCpFile * dstFile
static const uint64_t OpRetryPolicy
static const uint64_t OpDebug
char * zipFile
XrdCpConfig(const char *pgname)
static const uint64_t OpRetry
static const uint64_t DoNoPbar
static const uint64_t OpXrateThreshold
static const uint64_t DoCoerce
static const uint64_t OpServer
static const uint64_t DoForce
static const uint64_t OpVersion
static const uint64_t OpTpc
static const uint64_t DoParallel
static const uint64_t DoRmOnBadCksum
static const uint64_t DoNoTlsOK
static const uint64_t OpPath
long long OpSpec
static const uint64_t OpRecursv
static const uint64_t OpProxy
static const uint64_t DoTpc
static const uint64_t DoDebug
static const uint64_t OpSources
std::vector< std::string > HttpHeaders
static const uint64_t DoCksum
defVar * strDefs
static const uint64_t OpPosc
static const uint64_t DoXrate
static const uint64_t DoCksrc
static const uint64_t DoTpcModePush
static const uint64_t OpZipMtlnCksum
static const uint64_t DoHttpHeader
static const int opt1Src
static const uint64_t OpXrate
static const uint64_t DoTpcDlgt
static const uint64_t DoZip
static const uint64_t DoVerbose
static const uint64_t DoContinue
static const uint64_t OpCksum
const char * CksVal
static const uint64_t DoRecurse
static const uint64_t OpTlsNoData
static const int optNoLclCp
static const uint64_t DoXrateThreshold
const char * srcOpq
static const uint64_t DoTpcTokenFile
static const uint64_t DoZipAppend
static const uint64_t OpIfile
static const uint64_t DoDynaSrc
static const uint64_t OpHttpHeader
long long xRate
static const int optNoStdIn
static const uint64_t OpNoPbar
static const uint64_t DoSources
static const uint64_t DoSilent
static const uint64_t OpForce
static const uint64_t OpRmOnBadCksum
static const uint64_t OpDynaSrc
static const uint64_t DoXAttr
static const int optNoXtnd
static const uint64_t DoTlsMLF
static const uint64_t OpZip
static const uint64_t OpLicense
static const uint64_t DoIfile
static const uint64_t OpHelp
static XrdSysError * Log
static const int optRmtRec
static const uint64_t DoRetryPolicy
std::string RetryPolicy
static const uint64_t DoPath
static const uint64_t DoPosc
static const uint64_t OpStreams
long long xRateThreshold
static const uint64_t OpCoerce
long long totBytes
static const uint64_t DoTpcOnly
static const uint64_t DoTlsNoData
static const uint64_t OpTpcTokenFile
static const uint64_t DoServer
static const uint64_t DoCkprt
static void SetMsgPfx(const char *pfx)
Definition XrdCpFile.hh:57
PType Protocol
Definition XrdCpFile.hh:49
int Resolve()
Definition XrdCpFile.cc:158
char * Path
Definition XrdCpFile.hh:45
char ProtName[8]
Definition XrdCpFile.hh:50
XrdCpFile * Next
Definition XrdCpFile.hh:44
const char * SetPrefix(const char *prefix)
XrdVERSIONINFODEF(myVersion, cmsclient, XrdVNUMBER, XrdVERSION)
static XrdSysLogger Logger
static bool isHttpProt(XrdCpFile::PType pType)
defVar(const char *vn, const char *vl)