/******************************************************************************/
/* */
/* X r d F r m A d m i n . c c */
/* */
/* (c) 2009 by the Board of Trustees of the Leland Stanford, Jr., University */
/* All Rights Reserved */
/* Produced by Andrew Hanushevsky for Stanford University under contract */
/* DE-AC02-76-SFO0515 with the Department of Energy */
/* */
/* This file is part of the XRootD software suite. */
/* */
/* XRootD is free software: you can redistribute it and/or modify it under */
/* the terms of the GNU Lesser General Public License as published by the */
/* Free Software Foundation, either version 3 of the License, or (at your */
/* option) any later version. */
/* */
/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
/* License for more details. */
/* */
/* You should have received a copy of the GNU Lesser General Public License */
/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
/* COPYING (GPL license). If not, see . */
/* */
/* The copyright holder's institutional names and contributor's names may not */
/* be used to endorse or promote products derived from this software without */
/* specific prior written permission of the institution or contributor. */
/******************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "XrdCks/XrdCksManager.hh"
#include "XrdFrc/XrdFrcProxy.hh"
#include "XrdFrc/XrdFrcTrace.hh"
#include "XrdFrc/XrdFrcUtils.hh"
#include "XrdFrm/XrdFrmAdmin.hh"
#include "XrdFrm/XrdFrmConfig.hh"
#include "XrdOss/XrdOss.hh"
#include "XrdOuc/XrdOuca2x.hh"
#include "XrdOuc/XrdOucArgs.hh"
#include "XrdOuc/XrdOucExport.hh"
#include "XrdOuc/XrdOucTList.hh"
#include "XrdOuc/XrdOucTokenizer.hh"
#include "XrdSys/XrdSysTimer.hh"
using namespace XrdFrc;
using namespace XrdFrm;
/******************************************************************************/
/* A u d i t */
/******************************************************************************/
const char *XrdFrmAdmin::AuditHelp =
"audit [opts] {names ldir | space name[:pdir] | usage [name]}\n\n"
"opts: -fix -f[orce] -m[igratable] -p[urgeable] -r[ecursive]";
int XrdFrmAdmin::Audit()
{
static XrdOucArgs Spec(&Say, "frm_admin: ", "",
"fix", 3, "f",
"force", 1, "F",
"migratable", 1, "m",
"purgeable", 1, "p",
"recursive", 1, "r",
(const char *)0);
static const char *Reqs[] = {"type", 0};
// Parse the request
//
if (!Parse("audit ", Spec, Reqs)) return 1;
Opt.Args[1] = Spec.getarg();
// Fan out based on the function
//
if (!strcmp(Opt.Args[0], "usage")) return AuditUsage();
if (!Opt.Args[1]) Emsg("audit target not specified.");
else if (!strcmp(Opt.Args[0], "names")) return AuditNames();
else if (!strcmp(Opt.Args[0], "space")) return AuditSpace();
else Emsg("Unknown audit type - ", Opt.Args[0]);
// Nothing we understand
//
return 4;
}
/******************************************************************************/
/* C h k s u m */
/******************************************************************************/
const char *XrdFrmAdmin::ChksumHelp =
"chksum [opts] {calc | ls | set | unset | ver[ify] } fn\n\n"
"opts: -f[orce] -pfn -t[ype] -v[erbose]";
int XrdFrmAdmin::Chksum()
{
static XrdOucArgs Spec(&Say, "frm_admin: ", "",
"force", 1, "f",
"pfn", 3, "p",
"type", 1, "t:",
"verbose", 1, "v", (const char *)0);
static const char *Reqs[] = {"function", "target", 0};
const char *csName;
char pfnbuf[MAXPATHLEN], *Pfn, *Lfn, *csFunc;
int rc = 0;
// Check if this is even supported
//
CksData.Reset();
if (!Config.CksMan || !(CksData.Length = Config.CksMan->Size()))
{Emsg("Checksum support has not been configured!"); return 8;}
// Parse the request
//
if (!Parse("chksum ", Spec, Reqs)) return 1;
csFunc = Opt.Args[0];
csName = CksData.Name;
if (!*CksData.Name) {Opt.All = 1; CksData.Set(Config.CksMan->Name());}
// Check first for set or verify
//
if (!strcmp (csFunc, "set") || Abbrev(csFunc, "verify", 3))
{int n = strlen(Opt.Args[1]);
if (n != CksData.Length*2 || !CksData.Set(Opt.Args[1], n))
{Emsg("Invalid ", csName, " checksum value - ", Opt.Args[1]);
return 4;
}
if (!(Opt.Args[1] = Spec.getarg()))
{Emsg("chksum target not specified."); return 4;}
}
// Convert the lfn to a pfn if it has not been converted already
//
Pfn = Lfn = Opt.Args[1];
if (Opt.MPType != 'p')
{if (!Config.LocalPath(Opt.Args[1], pfnbuf, sizeof(pfnbuf))) return 4;
Pfn = pfnbuf;
}
// Process the request
//
if (!strcmp(csFunc, "calc"))
{if (Opt.Force || Config.CksMan->Get(Pfn, CksData) <= 0)
rc = Config.CksMan->Calc(Pfn, CksData, 1);
if (rc >= 0) {ChksumPrint(Lfn, rc); return 0;}
}
else if (!strcmp("ls", csFunc))
{if (!(rc = ChksumList(Lfn, Pfn))) return 0;}
else if (!strcmp(csFunc, "set"))
{if (!(rc = Config.CksMan->Set(Pfn, CksData))) return 0;}
else if (!strcmp(csFunc, "unset"))
{if (!(rc = Config.CksMan->Del(Pfn, CksData))) return 0;}
else if (Abbrev(csFunc, "verify", 3))
{if ((rc = Config.CksMan->Ver(Pfn, CksData)) > 0)
{Say.Say(CksData.Name, " checksums match for ", Lfn); return 0;}
if (!rc)
{Say.Say(CksData.Name, " checksums differ for ",Lfn); return 1;}
}
else {Emsg("Unknown chksum function - ", csFunc); return 4;}
// Determine name of the problem
//
if (rc == -EDOM) Emsg("Invalid ", csName, " checksum length.");
else if (rc == -ENOTSUP) Emsg(csName, " checksums are not supported.");
else if (rc == -ESRCH) Emsg(csName, " checksum not set for ", Lfn);
else if (rc == -ESTALE) Emsg(csName, " checksum no longer valid for ", Lfn);
else Emsg(-rc, csFunc, " ", csName, " checksum");
// Return failure
//
return 4;
}
/******************************************************************************/
/* C h k s u m L i s t */
/******************************************************************************/
int XrdFrmAdmin::ChksumList(const char *Lfn, const char *Pfn)
{
char Buff[256], *csBP;
XrdOucTokenizer csList(Buff);
int rc = 0;
// If all checksums wanted, then check if we have any
//
if (Opt.All)
{if (!(csBP = Config.CksMan->List(Pfn, Buff, sizeof(Buff))))
{Say.Say("No checksums exist for ", Lfn); return 0;}
csList.GetLine();
}
// Print one or all checksums, as needed
//
do {if (Opt.All)
{if ((csBP = csList.GetToken())) CksData.Set(csBP);
else break;
}
if ((rc = Config.CksMan->Get(Pfn, CksData)) <= 0
&& rc != -ESTALE && rc != -ENOTSUP) return rc;
ChksumPrint(Lfn, rc);
} while(Opt.All);
// All done
//
return 0;
}
/******************************************************************************/
/* C h k s u m P r i n t */
/******************************************************************************/
void XrdFrmAdmin::ChksumPrint(const char *Lfn, int rc)
{
char csBuff[XrdCksData::ValuSize*2+8], Buff[64];
static const int bSize = sizeof(Buff)-XrdCksData::NameSize;
// Insert the checksum and name in the buffer
//
*Buff = ' ';
strcpy(Buff+1, CksData.Name);
// Format long display, if so wanted
//
if (Opt.Verbose)
{time_t csTime = CksData.fmTime + CksData.csTime;
strftime(Buff+strlen(Buff), bSize, " %D %T ", localtime(&csTime));
}
// Grab the checksum value
//
if (rc == -ENOTSUP) strcpy(csBuff, "Unsupported!");
else if (rc < 0 ) strcpy(csBuff, "Invalid!");
else CksData.Get(csBuff, sizeof(csBuff));
// Print result
//
Say.Say(csBuff, Buff, (Opt.Verbose ? Lfn : 0));
}
/******************************************************************************/
/* F i n d */
/******************************************************************************/
const char *XrdFrmAdmin::FindHelp = "find [-r[ecursive]] what ldir [ldir [...]]\n\n"
"what: fail[files] | mmap[ped] | nochksum | nolk[files] | pin[ned] | unmig[rated]";
int XrdFrmAdmin::Find()
{
static XrdOucArgs Spec(&Say, "frm_admin: ", "",
"recursive", 1, "r", (const char *)0);
static const char *Reqs[] = {"type", "target", 0};
// Parse the request
//
if (!Parse("find ", Spec, Reqs)) return 1;
// Process the correct find
//
if (Abbrev(Opt.Args[0], "failfiles", 4)) return FindFail(Spec);
else if (Abbrev(Opt.Args[0], "mmapped", 4)) return FindMmap(Spec);
else if (Abbrev(Opt.Args[0], "nocs", 4)) return FindNocs(Spec);
else if (Abbrev(Opt.Args[0], "nochksum", 8)) return FindNocs(Spec);
else if (Abbrev(Opt.Args[0], "nolkfiles", 4)) return FindNolk(Spec);
else if (Abbrev(Opt.Args[0], "pinned", 3)) return FindPins(Spec);
else if (Abbrev(Opt.Args[0], "unmigrated",4)) return FindUnmi(Spec);
// Nothing we understand
//
Emsg("Unknown find type - ", Opt.Args[0]);
return 4;
}
/******************************************************************************/
/* H e l p */
/******************************************************************************/
const char *XrdFrmAdmin::HelpHelp =
"[help] {audit | chksum | exit | f[ind] | makelf | mark | mmap | mv | pin "
"| q[uery] | quit | reloc | rm} ...";
int XrdFrmAdmin::Help()
{
static struct CmdInfo {const char *Name;
int minL;
int maxL;
const char *Help;
}
CmdTab[] = {{"audit", 5, 5, AuditHelp },
{"chksum", 6, 6, ChksumHelp },
{"find", 1, 4, FindHelp },
{"makelf", 6, 6, MakeLFHelp},
{"mark", 4, 4, MarkHelp },
{"mmap", 4, 4, MmapHelp },
{"mv", 2, 2, MvHelp },
{"pin", 3, 3, PinHelp },
{"query", 1, 5, QueryHelp },
{"reloc", 5, 5, RelocHelp },
{"rm", 2, 2, RemoveHelp}
};
static int CmdNum = sizeof(CmdTab)/sizeof(struct CmdInfo);
const char *theHelp = HelpHelp;
char *Cmd;
int i, n;
// Get the next argument (array or string)
//
if (!ArgS) Cmd = ArgV[0];
else {XrdOucTokenizer Tokens(ArgS);
if ((Cmd = Tokens.GetLine())) Cmd = Tokens.GetToken();
}
// Try to give the correct help
//
if (Cmd)
{n = strlen(Cmd);
for (i = 0; i < CmdNum; i++)
if (n <= CmdTab[i].maxL && n >= CmdTab[i].minL
&& !strncmp(CmdTab[i].Name, Cmd, n)) break;
if (i < CmdNum) {Msg("Usage: ", CmdTab[i].Help); return 0;}
}
Emsg(0, "Usage: ", theHelp);
return 0;
}
/******************************************************************************/
/* M a k e L F */
/******************************************************************************/
const char *XrdFrmAdmin::MakeLFHelp = "makelf [opts] lspec [lspec [...]]\n\n"
"opts: -m[igratable] -o[wner] [usr][:[grp]] -p[urgeable] "
"-r[ecursive]\n\n"
"lspec: lfn | ldir[*]";
int XrdFrmAdmin::MakeLF()
{
static XrdOucArgs Spec(&Say, "frm_admin: ", "",
"migratable", 1, "m",
"owner", 1, "o:",
"purgeable", 1, "p",
"recursive", 1, "r",
(const char *)0);
static const char *Reqs[] = {"lfn", 0};
char *lfn, buff[80], Resp;
int ok = 1;
// Parse the request
//
if (!Parse("makelf ", Spec, Reqs)) return 1;
// Process all of the files
//
numFiles = 0;
lfn = Opt.Args[0];
if (!Opt.MPType) Opt.MPType = 'm';
do {Opt.All = VerifyAll(lfn);
if ((Resp = VerifyMP("makelf", lfn)) == 'y') ok = mkLock(lfn);
} while(Resp != 'a' && ok && (lfn = Spec.getarg()));
// All done
//
if (Resp == 'a' || !ok) Msg("makelf aborted!");
sprintf(buff, "%d lock file%s made.", numFiles, (numFiles == 1 ? "" : "s"));
Msg(buff);
return 0;
}
/******************************************************************************/
/* M a r k */
/******************************************************************************/
const char *XrdFrmAdmin::MarkHelp = "mark [opts] lspec [lspec [...]]\n\n"
"opts: -f[orce] -m[igratable] -p[urgeable] -r[ecursive]\n\n"
"lspec: lfn | ldir[/*]";
int XrdFrmAdmin::Mark()
{
static XrdOucArgs Spec(&Say, "frm_admin: ", "",
"force", 1, "F",
"migratable", 1, "m",
"purgeable", 1, "p",
"recursive", 1, "r",
(const char *)0);
static const char *Reqs[] = {"lfn", 0};
char *lfn, buff[80], Resp;
int ok = 1;
// Parse the request
//
if (!Parse("mark ", Spec, Reqs)) return 1;
// Process all of the files
//
numFiles = 0;
lfn = Opt.Args[0];
if (!Opt.MPType) Opt.MPType = 'm';
do {Opt.All = VerifyAll(lfn);
if ((Resp = VerifyMP("mark", lfn)) == 'y') ok = mkMark(lfn);
} while(Resp != 'a' && ok && (lfn = Spec.getarg()));
// All done
//
if (Resp == 'a' || !ok) Msg("mark aborted!");
sprintf(buff, "%d file%s marked %s.", numFiles, (numFiles == 1 ? "" : "s"),
(Opt.MPType == 'm' ? "migratable" : "purgeable"));
Msg(buff);
return 0;
}
/******************************************************************************/
/* M m a p */
/******************************************************************************/
const char *XrdFrmAdmin::MmapHelp = "mmap [opts] lspec [lspec [...]]\n\n"
"opts: -k[eep] -l[ock] -o[ff] -r[ecursive]\n\n"
"lspec: lfn | ldir[/*]";
int XrdFrmAdmin::Mmap()
{
static XrdOucArgs Spec(&Say, "frm_admin: ", "",
"keep", 1, "K",
"lock", 1, "f",
"off", 1, "l",
"recursive", 1, "r",
(const char *)0);
static const char *Reqs[] = {"lfn", 0};
char *lfn, itbuff[80], Resp;
int ok = 1;
// Parse the request
//
if (!Parse("pin ", Spec, Reqs)) return 1;
// Process all of the files
//
numFiles = 0;
lfn = Opt.Args[0];
Opt.MPType = 'p';
do {Opt.All = VerifyAll(lfn);
if ((Resp = VerifyMP("mmap", lfn)) == 'y') ok = mkMmap(lfn);
} while(Resp != 'a' && ok && (lfn = Spec.getarg()));
// All done
//
if (Resp == 'a' || !ok) Msg("mmap aborted!");
sprintf(itbuff,"%d mmap%s processed.",numFiles,(numFiles==1?"":"s"));
Msg(itbuff);
return 0;
}
/******************************************************************************/
/* M v */
/******************************************************************************/
const char *XrdFrmAdmin::MvHelp = "mv oldlfn newlfn";
int XrdFrmAdmin::Mv()
{
static XrdOucArgs Spec(&Say, "frm_admin: ", "", (const char *)0);
static const char *Reqs[] = {"oldlfn", "newlfn", 0};
int rc;
// Parse the request and do it
//
if (!Parse("mv ", Spec, Reqs)) return 1;
// Simply invoke the reloc function in the underlying FS
//
if ((rc = Config.ossFS->Rename(Opt.Args[0], Opt.Args[1])))
Emsg(-rc, "rename ", Opt.Args[0]);
else Msg(Opt.Args[0], " renamed to ", Opt.Args[1]);
return rc != 0;
}
/******************************************************************************/
/* P i n */
/******************************************************************************/
const char *XrdFrmAdmin::PinHelp = "pin [opts] lspec [lspec [...]]\n\n"
"opts: -k[eep]