/******************************************************************************/ /* */ /* 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]