65#define EMSG(x) std::cerr <<"xrdmapc: " <<x <<std::endl
70#define OPT_TYPE (char *)
89 clMap(
const char *addr) : nextMan(0), nextSrv(0), nextLvl(0),
90 state(
""), hasfile(
' '), verfile(
' '),
94 epAddr.
Set(addr); epAddr.
Name();
95 epAddr.
Format(name,
sizeof(name));
114bool listMan =
true, listSrv =
true, doVerify =
false, doHush =
false, doJson =
false;
131const char *MakeURL(
const char *name,
char *buff,
int blen)
133 snprintf(buff, blen,
"xroot://%s//", name);
151 {
switch(Status.
errNo)
152 {
case kXR_FSError: node->state =
" [fs error]";
break;
153 case kXR_IOError: node->state =
" [io error]";
break;
157 node->state =
" [no subscribers]";
158 else {node->state =
"";
162 case kXR_NotFile: node->state =
" [not a file]";
break;
163 default: sprintf(buff,
" [xrootd error %d]", Status.
errNo);
164 node->state = strdup(buff);
193 default:
if (!(*Status.
ToStr().c_str()))
194 sprintf(buff,
" [client error %d]", Status.
code);
195 else snprintf(buff,
sizeof(buff),
" [%s]",
196 Status.
ToStr().c_str());
197 node->state = strdup(buff);
209void MapCluster(clMap *node, clMap *origin)
213 XrdCl::URL theURL((
const std::string)MakeURL(node->name,buff,
sizeof(buff)));
219 clMap *clmP, *branch;
223 Status = xrdFS.Locate((
const std::string)
"*", flags, info, theTO);
229 EMSG(
"Unable to get " <<node->name <<
" subscribers; "
230 <<Status.
ToStr().c_str());
231 MapCode(Status, origin,
true);
238 for( it = info->
Begin(); it != info->
End(); ++it )
239 {clmP =
new clMap(it->GetAddress().c_str());
240 locType = it->GetType();
243 {clmP->nextSrv = node->nextSrv;
244 node->nextSrv = clmP;
246 clmP->nextMan = node->nextMan;
247 node->nextMan = clmP;
250 clHash.Add(clmP->key, clmP, 0,
Hash_keep);
255 clmP = node->nextMan;
257 {branch =
new clMap(clmP->name);
258 MapCluster(branch, clmP);
260 clmP->nextLvl = branch;
262 clmP = clmP->nextMan;
277void MapPath(clMap *node,
const char *
Path,
bool doRefresh=
false)
281 XrdCl::URL theURL((
const std::string)MakeURL(node->name,buff,
sizeof(buff)));
294 Status = xrdFS.Locate((
const std::string)
Path, flags, info, theTO);
300 EMSG(
"Unable to query " <<node->name <<
" about path; "
301 <<Status.
ToStr().c_str());
302 MapCode(Status, node);
308 for( it = info->
Begin(); it != info->
End(); ++it )
309 {
const char *clAddr = it->GetAddress().c_str();
310 if ((clmP = clHash.Find(clAddr)))
311 {clmP->hasfile =
'>';
312 if (clmP->isMan) MapPath(clmP,
Path);
314 clmP =
new clMap(clAddr);
315 clmP->nextSrv = clLost;
332const char *OpName(
char *Argv[])
334 static char oName[4] = {
'-', 0, 0, 0};
349void PathChk(clMap *node)
352 XrdCl::URL theURL((
const std::string)MakeURL(node->name,buff,
sizeof(buff)));
359 Status = xrdFS.Stat((
const std::string)
Path, info);
363 if (!Status.
IsOK()) MapCode(Status, node);
364 else node->verfile =
'+';
378void PrintMap(clMap *clmP,
int lvl)
381 const char *pfx =
"";
388 {pfxbuff = (
char *)malloc(n+1);
389 memset(pfxbuff,
' ', n); pfxbuff[n] = 0;
396 {clnow = clmP->nextSrv;
398 {
if (doVerify) PathChk(clnow);
400 {pfxbuff[1] = clnow->hasfile;
401 pfxbuff[2] = clnow->verfile;
403 std::cout <<
' ' <<pfx <<
"Srv " <<clnow->name <<clnow->state <<std::endl;
404 clnow = clnow->nextSrv;
411 {clnow = clmP->nextMan;
412 if (lvl) pfxbuff[2] =
' ';
414 {
if (lvl) pfxbuff[1] = clnow->hasfile;
415 std::cout <<lvl <<pfx <<
"Man " <<clnow->name <<clnow->state <<std::endl;
416 if (clnow->valid && clnow->nextLvl) PrintMap(clnow->nextLvl,lvl+1);
417 clnow = clnow->nextMan;
423 if (lvl) free(pfxbuff);
433void PrintJsonSrv(clMap *clnow)
437 printf(
"{\"name\":\"%s\"", clnow->name);
439 {st = clnow->state;
while (*st ==
' ') st++;
440 printf(
",\"state\":\"%s\"", st);
442 if (clnow->hasfile !=
' ')
443 printf(
",\"hasFile\":%s", clnow->hasfile ==
'>' ?
"true" :
"false");
444 if (clnow->verfile !=
' ' && clnow->verfile !=
'?')
445 printf(
",\"verified\":%s", clnow->verfile ==
'+' ?
"true" :
"false");
449void PrintJson(clMap *clmP)
453 std::vector<clMap*> nodes;
456 printf(
"{\"name\":\"%s\",\"type\":\"manager\"", clmP->name);
459 {st = clmP->state;
while (*st ==
' ') st++;
460 printf(
",\"state\":\"%s\"", st);
462 if (clmP->hasfile !=
' ')
463 printf(
",\"hasFile\":%s", clmP->hasfile ==
'>' ?
"true" :
"false");
464 if (clmP->verfile !=
' ' && clmP->verfile !=
'?')
465 printf(
",\"verified\":%s", clmP->verfile ==
'+' ?
"true" :
"false");
470 if (clmP->nextSrv && listSrv)
472 for (clnow = clmP->nextSrv; clnow; clnow = clnow->nextSrv)
473 nodes.push_back(clnow);
474 std::sort(nodes.begin(), nodes.end(),
475 [](
const clMap *a,
const clMap *b)
476 { return strcmp(a->name, b->name) < 0; });
477 printf(
",\"servers\":[");
478 for (i = 0; i < nodes.size(); ++i)
479 {
if (i) putchar(
',');
480 PrintJsonSrv(nodes[i]);
485 if (clmP->nextMan && listMan)
487 for (clnow = clmP->nextMan; clnow; clnow = clnow->nextMan)
488 nodes.push_back(clnow);
489 std::sort(nodes.begin(), nodes.end(),
490 [](
const clMap *a,
const clMap *b)
491 { return strcmp(a->name, b->name) < 0; });
492 printf(
",\"managers\":[");
493 for (i = 0; i < nodes.size(); ++i)
494 {
if (i) putchar(
',');
497 {
if (*clnow->state) clnow->nextLvl->state = clnow->state;
498 PrintJson(clnow->nextLvl);
501 {printf(
"{\"name\":\"%s\",\"type\":\"manager\"", clnow->name);
503 {st = clnow->state;
while (*st ==
' ') st++;
504 printf(
",\"state\":\"%s\"", st);
530 env->
PutInt(
"ConnectionWindow", cwValue);
531 env->
PutInt(
"ConnectionRetry", crValue);
532 env->
PutInt(
"TimeoutResolution",trValue);
545 std::cerr <<
"Usage: xrdmapc [<opt>] <host>:<port> [<path>]\n"
546 <<
"<opt>: [--help] [--format {text|json}] [--list {all|m|s}] [--quiet] [--refresh] [--verify]" <<std::endl;
549"--format | -f 'text' prints human-readable output (default), 'json' prints\n"
550" a JSON representation of the cluster topology (managers and\n"
551" servers arrays are sorted by name).\n"
552"--list | -l 'all' lists managers and servers (default), 'm' lists only\n"
553" managers and 's' lists only servers.\n"
554"--quiet | -q does not print error messages to std::cerr; errors appear inline.\n"
555"--refresh | -r does not use cached information but will refresh the cache.\n"
556"--verify | -v verifies <path> existence status at each server.\n"
557"<path> when specified, uses <host>:<port> to determine the locations\n"
558" of path and does optional verification."
561 exit((
emsg ? 1 : 0));
569int main(
int argc,
char *argv[])
571 const char *opLetters =
":f:hl:rv";
572 struct option opVec[] =
574 {
OPT_TYPE "format", 1, 0, (int)
'f'},
578 {
OPT_TYPE "refresh", 0, 0, (int)
'r'},
579 {
OPT_TYPE "verify", 0, 0, (int)
'v'},
582 extern int optind, opterr;
585 clMap *baseNode, *clNow;
589 bool doRefresh =
false;
595 while((opC = getopt_long(argc, argv, opLetters, opVec, &i)) != (
char)-1)
599 {
case 'f':
if (!strcmp(
"json",optarg))
600 {doJson =
true; doHush =
true;}
601 else if (!strcmp(
"text",optarg))
603 else Usage(
"Invalid format argument.");
607 case 'l':
if (!strcmp(
"all",optarg))
608 {listMan =
true; listSrv =
true;}
609 else if (!strcmp(
"m", optarg))
610 {listMan =
true; listSrv =
false;}
611 else if (!strcmp(
"s", optarg))
612 {listMan =
false; listSrv =
true;}
613 else Usage(
"Invalid list argument.");
615 case 'q': doHush =
true;
617 case 'r': doRefresh =
true;
619 case 'v': doVerify =
true;
621 case ':':
EMSG(
"'" <<OpName(argv) <<
"' argument missing.");
623 case '?':
EMSG(
"Invalid option, '" <<OpName(argv) <<
"'.");
625 default:
EMSG(
"Internal error processing '" <<OpName(argv) <<
"'.");
631 if (
optind >= argc)
Usage(
"Initial node not specified.");
636 {
EMSG(
"Unable to validate initial node; " <<
eMsg);
649 baseNode =
new clMap(argv[
optind]);
654 else doVerify =
false;
662 MapCluster(baseNode, baseNode);
667 {MapPath(baseNode,
Path, doRefresh);
668 eMsg = (doVerify ?
"0*rv* " :
"0*r** ");
669 }
else eMsg =
"0**** ";
674 {PrintJson(baseNode);
678 {std::cout <<
eMsg <<baseNode->name <<baseNode->state <<std::endl;
679 PrintMap(baseNode, 1);
685 {std::cerr <<
"Warning! " <<baseNode->name
686 <<
" referred to the following unconnected node:" <<std::endl;
689 {std::cerr <<
"????? " <<clNow->name <<std::endl;
690 clNow = clNow->nextSrv;
void Usage(const char *msg)
int main(int argc, char *argv[])
int emsg(int rc, char *msg)
static Env * GetEnv()
Get default client environment.
bool PutInt(const std::string &key, int value)
Send file/filesystem queries to an XRootD cluster.
Iterator Begin()
Get the location begin iterator.
LocationType
Describes the node type and file status for a given location.
@ ServerPending
server node where the file is pending to be online
@ ServerOnline
server node where the file is online
LocationList::iterator Iterator
Iterator over locations.
Iterator End()
Get the location end iterator.
std::string ToStr() const
Convert to string.
int Format(char *bAddr, int bLen, fmtUse fmtType=fmtAuto, int fmtOpts=0)
const char * Name(const char *eName=0, const char **eText=0)
const char * Set(const char *hSpec, int pNum=PortInSpec)
const uint16_t errInvalidAddr
const uint16_t errStreamDisconnect
const uint16_t errRedirectLimit
const uint16_t errErrorResponse
const uint16_t errOperationExpired
const uint16_t errLoginFailed
const uint16_t errSocketTimeout
const uint16_t errHandShakeFailed
const uint16_t errConnectionError
const uint16_t errSocketError
const uint16_t errSocketDisconnected
const uint16_t errAuthFailed
Flags
Open flags, may be or'd when appropriate.
uint16_t code
Error type, or additional hints on what to do.
bool IsOK() const
We're fine.
uint32_t errNo
Errno, if any.