39#include "XrdVersion.hh"
55#define EMSG(x) std::cerr <<PName <<": " <<x <<std::endl
57#define FMSG(x,y) {EMSG(x);exit(y);}
59#define UMSG(x) {EMSG(x);Usage(22);}
61#define ZMSG(x) {EMSG(x);return 0;}
66#define OPT_TYPE (char *)
83const char *XrdCpConfig::opLetters =
":C:d:D:EfFhHI:NpPrRsS:t:T:vVX:y:z:ZA";
130 if ((PName = rindex(pgm,
'/'))) PName++;
174 if (inFile) free(inFile);
176 if (parmVal) free(parmVal);
182 while((pNow = pFile)) {pFile = pFile->Next;
delete pNow;}
196 extern int optind, opterr;
197 static int pgmSet = 0;
198 char Buff[128], *
Path, opC;
204 if (parmVal) free(parmVal);
205 parmVal = (
char **)malloc(aCnt*
sizeof(
char *));
219 {
char *Slash = rindex(aVec[0],
'/');
221 Pgm = (Slash ? Slash+1 : aVec[0]);
228 if ((opC = getopt_long(Argc, Argv, opLetters, opVec, &i)) != (
char)-1)
235 if (!a2i(optarg, &
Dlvl, 0, 3)) Usage(22);
247 case OpIfile:
if (inFile) free(inFile);
248 inFile = strdup(optarg);
269 if (!a2i(optarg, &
Retry, 0, -1)) Usage(22);
282 if (!a2i(optarg, &
nSrcs, 1, 32)) Usage(22);
285 if (!a2i(optarg, &
nStrm, 1, 15)) Usage(22);
292 if (!strcmp(
"delegate", optarg))
295 {
UMSG(
"Missing tpc qualifier after "
301 else if (strcmp(
"first", optarg))
303 UMSG(
"Invalid option, '" <<OpName()
304 <<
' ' <<optarg <<
"' ");
310 case OpVersion: std::cerr <<XrdVERSION <<std::endl; exit(0);
313 if (!a2z(optarg, &
xRate, 10*1024LL, -1)) Usage(22);
319 if (!a2i(optarg, &
Parallel, 1, 128)) Usage(22);
329 case ':':
UMSG(
"'" <<OpName() <<
"' argument missing.");
331 case '?':
if (!Legacy(
optind-1))
332 UMSG(
"Invalid option, '" <<OpName() <<
"'.");
334 default:
UMSG(
"Internal error processing '" <<OpName() <<
"'.");
337 }
while(opC != (
char)-1 &&
optind < Argc);
341 if (inFile) {
if (!parmCnt )
UMSG(
"Destination not specified.");}
342 else {
if (!parmCnt )
UMSG(
"No files specified.");
343 if ( parmCnt == 1 )
UMSG(
"Destination not specified.");
349 UMSG(
"Third party copy requires a single source.");
354 UMSG(
"Cannot calculate source checksum for a file in ZIP archive.");
357 UMSG(
"Cannot calculate source checksum for a file in ZIP archive.");
373 if (rc)
FMSG(
"Invalid url, '" <<
dstFile->Path <<
"'.", 22);
385 {
FMSG(
dstFile->ProtName <<
"file protocol is not supported.", 22)}
391 if (isLcl && (rc =
dstFile->Resolve()))
399 for (i = 0; i < parmCnt; i++) ProcFile(parmVal[i]);
406 int inFD =
open(inFile, O_RDONLY);
407 if (inFD < 0)
FMSG(
XrdSysE2T(errno) <<
" opening infiles " <<inFile, 2);
409 while((fname =
inList.GetLine()))
if (*fname) ProcFile(fname);
416 FMSG(
"Only a single source is allowed.", 2);
423 FMSG(
"Destination is neither remote nor a directory.", 2);
428 FMSG(
"All files are local; use 'cp' instead!", 1);
434 FMSG(
"Checksum with fixed value requires a single input file.", 2);
436 FMSG(
"Checksum with fixed value conflicts with '--recursive'.", 2);
443 while((pFile = pPrev->Next))
445 else {
Path = pFile->Path;
446 pPrev->Next = pFile->Next;
452 {pLast->Next = pPrev->Next;
453 pPrev->Next = pFile->Next;
459 FMSG(
"No regular files found to copy!", 2);
462 <<(
numFiles != 1 ?
" files." :
" file."));
473int XrdCpConfig::a2i(
const char *item,
int *val,
int minv,
int maxv)
480 *val = strtol(item, &eP, 10);
481 if (errno || *eP)
ZMSG(
"'" <<OpName() <<
"' argument is not a number.");
486 ZMSG(
"'" <<OpName() <<
"' argument must be >= " <<minv <<
'.');
487 if (maxv >= 0 && *val > maxv)
488 ZMSG(
"'" <<OpName() <<
"' argument must be <= " <<maxv <<
'.');
495int XrdCpConfig::a2l(
const char *item,
long long *val,
496 long long minv,
long long maxv)
503 *val = strtoll(item, &eP, 10);
504 if (errno || *eP)
ZMSG(
"'" <<OpName() <<
"' argument is not a number.");
509 ZMSG(
"'" <<OpName() <<
"' argument must be >= " <<minv <<
'.');
510 if (maxv >= 0 && *val > maxv)
511 ZMSG(
"'" <<OpName() <<
"' argument must be <= " <<maxv <<
'.');
519int XrdCpConfig::a2t(
const char *item,
int *val,
int minv,
int maxv)
521 char *eP, *fP = (
char *)item + strlen(item) - 1;
525 if (*fP ==
's' || *fP ==
'S') qmult = 1;
526 else if (*fP ==
'm' || *fP ==
'M') qmult = 60;
527 else if (*fP ==
'h' || *fP ==
'H') qmult = 60*60;
528 else if (*fP ==
'd' || *fP ==
'D') qmult = 60*60*24;
529 else {qmult = 1; fP++;}
534 *val = strtoll(item, &eP, 10) * qmult;
535 if (errno || eP != fP)
536 ZMSG(
"'" <<OpName() <<
"' argument is not a valid time.");
541 ZMSG(
"'" <<OpName() <<
"' argument must be >= " <<minv <<
'.');
542 if (maxv >= 0 && *val > maxv)
543 ZMSG(
"'" <<OpName() <<
"' argument must be <= " <<maxv <<
'.');
551int XrdCpConfig::a2x(
const char *Val,
char *Buff,
int Vlen)
553 int n, i = 0, Odd = 0;
554 if (Vlen & 0x01)
return 0;
556 {
if (*Val >=
'0' && *Val <=
'9') n = *Val-48;
557 else if (*Val >=
'a' && *Val <=
'f') n = *Val-87;
558 else if (*Val >=
'A' && *Val <=
'F') n = *Val-55;
560 if (Odd) Buff[i++] |= n;
561 else Buff[i ] = n << 4;
571int XrdCpConfig::a2z(
const char *item,
long long *val,
572 long long minv,
long long maxv)
574 char *eP, *fP = (
char *)item + strlen(item) - 1;
578 if (*fP ==
'k' || *fP ==
'K') qmult = 1024LL;
579 else if (*fP ==
'm' || *fP ==
'M') qmult = 1024LL*1024LL;
580 else if (*fP ==
'g' || *fP ==
'G') qmult = 1024LL*1024LL*1024LL;
581 else if (*fP ==
't' || *fP ==
'T') qmult = 1024LL*1024LL*1024LL*1024LL;
582 else {qmult = 1; fP++;}
587 *val = strtoll(item, &eP, 10) * qmult;
588 if (errno || eP != fP)
589 ZMSG(
"'" <<OpName() <<
"' argument is not a valid time.");
594 ZMSG(
"'" <<OpName() <<
"' argument must be >= " <<minv <<
'.');
595 if (maxv >= 0 && *val > maxv)
596 ZMSG(
"'" <<OpName() <<
"' argument must be <= " <<maxv <<
'.');
604int XrdCpConfig::defCks(
const char *opval)
608 std::string cksum( opval );
609 size_t pos = cksum.find(
':' );
610 std::string mode = cksum.substr( pos + 1 );
611 if( mode !=
"source" )
612 FMSG(
"Additional checksum must be of mode 'source'.", 13);
613 AddCksVal.push_back( cksum.substr( 0, pos ) );
618 const char *Colon = index(opval,
':');
625 {
CksMan =
new XrdCksManager(
Log, 0, myVer,
true);
628 FMSG(
"Unable to initialize checksum processing.", 13);
634 n = (Colon ? Colon - opval : strlen(opval));
636 UMSG(
"Invalid checksum type, '" <<opval <<
"'.");
637 strncpy(csName, opval, n); csName[n] = 0;
642 if( strcmp( csName,
"auto" ) )
646 UMSG(
"Invalid checksum type, '" <<csName <<
"'.");
659 if (!(*Colon))
UMSG(
CksData.Name <<
" argument missing after ':'.");
662 else {n = strlen(Colon);
664 UMSG(
"Invalid " <<
CksData.Name <<
" value '" <<Colon <<
"'.");
679int XrdCpConfig::defOpq(
const char *theOp)
681 const char *oVal = theOp+3;
685 if (!(*oVal))
UMSG(
"'" <<theOp <<
"' opaque data not specified.");
689 if (*(theOp+2) ==
'S')
srcOpq = oVal;
701int XrdCpConfig::defOpt(
const char *theOp,
const char *theArg)
704 int opval, isInt = (*(theOp+2) ==
'I');
705 const char *vName = theOp+3;
710 if (!(*vName))
UMSG(
"'" <<theOp <<
"' variable not specified.");
714 if (!theArg)
UMSG(
"'" <<theOp <<
"' argument not specified.");
720 opval = strtol(theArg, &eP, 10);
721 if (errno || *eP)
UMSG(
"'" <<theOp <<
"' argument is not a number.");
722 dP =
new defVar(vName, opval);
723 if (!intDend)
intDefs = intDend = dP;
724 else {intDend->Next = dP; intDend = dP;}
726 dP =
new defVar(vName, theArg);
727 if (!strDend)
strDefs = strDend = dP;
728 else {strDend->Next = dP; strDend = dP;}
740void XrdCpConfig::defPxy(
const char *opval)
742 const char *Colon = index(opval,
':');
748 if (Colon == opval)
UMSG(
"Proxy host not specified.");
752 if (!Colon || !(*(Colon+1)))
UMSG(
"Proxy port not specified.");
757 pPort = strtol(Colon+1, &eP, 10);
759 UMSG(
"Invalid proxy port, '" <<opval <<
"'.");
764 n = Colon - opval + 1;
765 pHost = (
char *)malloc(n);
766 strncpy(
pHost, opval, n-1);
775const char *XrdCpConfig::Human(
long long inval,
char *Buff,
int Blen)
777 static const char *sfx[] = {
" bytes",
"KB",
"MB",
"GB",
"TB",
"PB"};
780 for (i = 0; i <
sizeof(sfx)/
sizeof(sfx[0]) - 1 && inval >= 1024; i++)
783 snprintf(Buff, Blen,
"%lld%s", inval, sfx[i]);
791int XrdCpConfig::Legacy(
int oIndex)
799 while(oIndex < Argc && (*Argv[oIndex] !=
'-' || *(Argv[oIndex]+1) ==
'\0'))
800 parmVal[parmCnt++] = Argv[oIndex++];
801 if (oIndex >= Argc)
return 0;
803 if (oIndex+1 >= Argc || *Argv[oIndex+1] ==
'-') oArg = 0;
804 else oArg = Argv[oIndex+1];
805 if (!(rc = Legacy(Argv[oIndex], oArg)))
return 0;
813int XrdCpConfig::Legacy(
const char *theOp,
const char *theArg)
815 if (!strcmp(theOp,
"-adler"))
return defCks(
"adler32:source");
817 if (!strncmp(theOp,
"-DI", 3) || !strncmp(theOp,
"-DS", 3))
818 return defOpt(theOp, theArg);
820 if (!strcmp(theOp,
"-extreme") || !strcmp(theOp,
"-x"))
827 if (!strcmp(theOp,
"-md5"))
return defCks(
"md5:source");
829 if (!strncmp(theOp,
"-OD",3) || !strncmp(theOp,
"-OS",3))
return defOpq(theOp);
831 if (!strcmp(theOp,
"-version")) {std::cerr <<XrdVERSION <<std::endl; exit(0);}
833 if (!strcmp(theOp,
"-force"))
834 FMSG(
"-force is no longer supported; use --retry instead!",22);
843void XrdCpConfig::License()
845 const char *theLicense =
846#include "../../LICENSE"
849 std::cerr <<theLicense;
857const char *XrdCpConfig::OpName()
860 static char oName[4] = {
'-', 0, 0, 0};
872void XrdCpConfig::ProcFile(
const char *fname)
878 pLast->Next = pFile =
new XrdCpFile(fname, rc);
879 if (rc)
FMSG(
"Invalid url, '" <<fname <<
"'.", 22);
891 FMSG(pFile->Path <<
" is a directory.", 2);
895 FMSG(
"Using stdin as a source is disallowed.", 22);
897 FMSG(
"Multiple sources disallowed with stdin.", 22);
905 {
FMSG(pFile->ProtName <<
" file protocol is not supported.", 22)}
907 {
FMSG(
"Recursive copy from a remote host is not supported.",22)}
920void XrdCpConfig::Usage(
int rc)
922 static const char *Syntax =
"\n"
923 "Usage: xrdcp [<options>] <src> [<src> [. . .]] <dest>\n";
925 static const char *Syntax1=
"\n"
926 "Usage: xrdcp [<options>] <src> <dest>\n";
928 static const char *Options=
"\n"
929 "Options: [--cksum <args>] [--coerce] [--continue]\n"
930 " [--debug <lvl>] [--dynamic-src] [--force] [--help]\n"
931 " [--infiles <fn>] [--license] [--nopbar] [--notlsok]\n"
932 " [--parallel <n>] [--posc] [--proxy <host>:<port>]\n"
933 " [--recursive] [--retry <n>] [--retry-policy <force|continue>]\n"
934 " [--rm-bad-cksum] [--server] [--silent] [--sources <n>]\n"
935 " [--streams <n>] [--tlsmetalink] [--tlsnodata]\n"
936 " [--tpc [delegate] {first|only}] [--verbose] [--version]\n"
937 " [--xattr] [--xrate <rate>] [--xrate-threshold <rate>]\n"
938 " [--zip <file>] [--zip-append] [--zip-mtln-cksum]\n";
940 static const char *Syntax2=
"\n"
941 "<src>: [[x]root[s]://<host>[:<port>]/]<path> | -";
943 static const char *Syntay2=
"\n"
944 "<src>: [[x]root[s]://<host>[:<port>]/]<path>";
946 static const char *Syntax3=
"\n"
947 "<dest>: [[x]root[s]://<host>[:<port>]/]<path> | -";
949 static const char *Detail =
"\n"
950 "Note: using a dash (-) for <src> uses stdin and for <dest> stdout\n\n"
951 "-C | --cksum <args> verifies the checksum at the destination as provided\n"
952 " by the source server or locally computed. The args are\n"
953 " <ckstype>[:{<value>|print|source}]\n"
954 " where <ckstype> is one of adler32, crc32, crc32c, md5,\n"
955 " zcrc32 or auto. If 'auto' is chosen, xrdcp will try to\n"
956 " automatically infer the right checksum type based on the\n"
957 " source/destination configuration, source file type\n"
958 " (e.g. metalink, ZIP), and available checksum plug-ins.\n"
959 " If the hex value of the checksum is given, it is used.\n"
960 " Otherwise, the server's checksum is used for remote files\n"
961 " and computed for local files. Specifying print merely\n"
962 " prints the checksum but does not verify it.\n"
963 "-F | --coerce coerces the copy by ignoring file locking semantics\n"
964 " --continue continue copying a file from the point where the previous\n"
965 " copy was interrupted\n"
966 "-d | --debug <lvl> sets the debug level: 0 off, 1 low, 2 medium, 3 high\n"
967 "-Z | --dynamic-src file size may change during the copy\n"
968 "-f | --force replaces any existing output file\n"
969 "-h | --help prints this information\n"
970 "-I | --infiles <fname> specifies the file that contains a list of input files\n"
971 "-H | --license prints license terms and conditions\n"
972 "-N | --nopbar does not print the progress bar\n"
973 " --notlsok if server is too old to support TLS encryption fallback\n"
974 " to unencrypted communication\n"
975 " --parallel <n> number of files to copy at the same time\n"
976 "-P | --posc enables persist on successful close semantics\n"
977 "-D | --proxy <host>:<port> uses the specified SOCKS4 proxy connection\n"
978 "-r | --recursive recursively copies all source files\n"
979 "-t | --retry <n> maximum number of times to retry failed copy-jobs\n"
980 " --retry-policy <policy> retry policy: force or continue\n"
981 " --rm-bad-cksum remove the target file if checksum verification failed\n"
982 " (enables also POSC semantics)\n"
983 " --server runs in a server environment with added operations\n"
984 "-s | --silent produces no output other than error messages\n"
985 "-y | --sources <n> uses up to the number of sources specified in parallel\n"
986 "-S | --streams <n> copies using the specified number of TCP connections\n"
987 " --tlsmetalink convert [x]root to [x]roots protocol in metalinks\n"
988 "-E | --tlsnodata in case of [x]roots protocol, encrypt only the control\n"
989 " stream and leave the data streams unencrypted\n"
990 "-T | --tpc <args> uses third party copy mode between the src and dest.\n"
991 " Both the src and dest must allow tpc mode. Argument\n"
992 " 'first' tries tpc and if it fails, does a normal copy;\n"
993 " while 'only' fails the copy unless tpc succeeds.\n"
994 "-v | --verbose produces more information about the copy\n"
995 "-V | --version prints the version number\n"
996 " --xattr preserve extended attributes\n"
997 "-X | --xrate <rate> limits the transfer to the specified rate. You can\n"
998 " suffix the value with 'k', 'm', or 'g'\n"
999 " --xrate-threshold <rate> If the transfer rate drops below given threshold force\n"
1000 " the client to use different source or if no more sources\n"
1001 " are available fail the transfer. You can suffix the value\n"
1002 " with 'k', 'm', or 'g'\n"
1003 "-z | --zip <file> treat the source as a ZIP archive containing given file\n"
1004 " --zip-append append file to existing zip archive\n"
1005 " --zip-mtln-cksum use the checksum available in a metalink file even if\n"
1006 " a file is being extracted from a ZIP archive\n"
1008 "Legacy options: [-adler] [-DI<var> <val>] [-DS<var> <val>] [-np]\n"
1009 " [-md5] [-OD<cgi>] [-OS<cgi>] [-version] [-x]";
1011 std::cerr <<(Opts &
opt1Src ? Syntax1 : Syntax) <<Options;
1012 std::cerr <<(Opts &
optNoStdIn ? Syntay2 : Syntax2) <<Syntax3 <<std::endl;
1013 if (!rc) std::cerr <<Detail <<std::endl;
int inList(const char *var, const char **Vec)
static XrdSysError eDest(0,"crypto_")
static XrdVERSIONINFODEF(compiledVer, XrdHttpProtocolTest, XrdVNUMBER, XrdVERSION)
const char * XrdSysE2T(int errcode)
static const int NameSize
static const uint64_t OpVerbose
static const uint64_t OpXAttr
static const uint64_t DoProxy
void Config(int argc, char **argv, int Opts=0)
static const uint64_t OpRecurse
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
static const uint64_t DoZipMtlnCksum
static const uint64_t OpSilent
static const uint64_t OpTlsMLF
static const uint64_t OpNoTlsOK
static const uint64_t OpRetryPolicy
static const uint64_t OpDebug
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
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
static const uint64_t OpPosc
static const uint64_t DoXrate
static const uint64_t DoCksrc
static const uint64_t OpZipMtlnCksum
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
static const uint64_t DoRecurse
static const uint64_t OpTlsNoData
static const int optNoLclCp
static const uint64_t DoXrateThreshold
static const uint64_t DoZipAppend
static const uint64_t OpIfile
static const uint64_t DoDynaSrc
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 const int optRmtRec
static const uint64_t DoRetryPolicy
static const uint64_t DoPath
static const uint64_t DoPosc
static const uint64_t OpStreams
static const uint64_t OpCoerce
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)
static XrdSysLogger Logger