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