// ---------------------------------------------------------------------- // File: proc/user/File.cc // Author: Andreas-Joachim Peters - CERN // ---------------------------------------------------------------------- /************************************************************************ * EOS - the CERN Disk Storage System * * Copyright (C) 2011 CERN/Switzerland * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program 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 General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* ************************************************************************/ #include "mgm/proc/ProcInterface.hh" #include "mgm/XrdMgmOfs.hh" #include "mgm/Access.hh" #include "mgm/Macros.hh" #include "mgm/Quota.hh" #include "mgm/Stat.hh" #include "common/table_formatter/TableFormatterBase.hh" #include "common/table_formatter/TableCell.hh" #include "common/LayoutId.hh" #include "common/Timing.hh" #include "common/Path.hh" #include "namespace/interface/IView.hh" #include "namespace/interface/ContainerIterators.hh" #include "namespace/Prefetcher.hh" #include "namespace/Resolver.hh" #include "namespace/utils/Etag.hh" #include "namespace/utils/Checksum.hh" #include EOSMGMNAMESPACE_BEGIN //------------------------------------------------------------------------------ // Fileinfo method //------------------------------------------------------------------------------ std::string ProcCommand::FileMDToStatus(std::shared_ptr fmd) { int tape_copy = 0; if (fmd->hasLocation(EOS_TAPE_FSID)) { tape_copy++; } if (fmd->getNumLocation() == 0) { return "locations::uncommitted"; } if (fmd->getNumLocation() < (eos::common::LayoutId::GetStripeNumber( fmd->getLayoutId()) + 1 + tape_copy)) { return "locations::incomplete"; } if (fmd->getNumLocation() > (eos::common::LayoutId::GetStripeNumber( fmd->getLayoutId()) + 1 + tape_copy)) { return "locations::overreplicated"; } eos::IFileMD::XAttrMap xattrs = fmd->getAttributes(); // check sys.fusex.state std::string fs = xattrs["sys.fusex.state"]; if (fs.length()) { if (fs.length() > 1) { std::string b2 = fs.substr(fs.length() - 2); if (b2 == "±") { return "fuse::needsflush"; } } if (fs.back() == 'Z') { return "fuse::repairing"; } // scan from the back if (fs.back() == '|') { size_t spos = fs.rfind("±", fs.length() - 1); size_t ncommits = 0; if (spos != std::string::npos) { spos++; // multichar ! for (size_t i = spos; i < fs.length(); ++i) { if (fs.at(i) == '+') { ncommits++; } } } if (eos::common::LayoutId::GetLayoutType(fmd->getLayoutId()) == eos::common::LayoutId::kReplica) { if (ncommits < fmd->getNumLocation()) { return "fuse::missingcommmits"; } } } } return "healthy"; } int ProcCommand::Fileinfo() { gOFS->MgmStats.Add("FileInfo", pVid->uid, pVid->gid, 1); XrdOucString spath = pOpaque->Get("mgm.path"); const char* inpath = spath.c_str(); NAMESPACEMAP; PROC_BOUNCE_ILLEGAL_NAMES; PROC_BOUNCE_NOT_ALLOWED; struct stat buf; unsigned long long fid = 0; if ((!spath.beginswith("fid:")) && (!spath.beginswith("fxid:")) && (!spath.beginswith("pid:")) && (!spath.beginswith("pxid:")) && (!spath.beginswith("inode:"))) { if (gOFS->_stat(path, &buf, *mError, *pVid, (char*) 0, (std::string*)0, false)) { stdErr = "error: cannot stat '"; stdErr += path; stdErr += "'\n"; retc = ENOENT; return SFS_OK; } if (S_ISDIR(buf.st_mode)) { fid = buf.st_ino; } else { fid = eos::common::FileId::InodeToFid(buf.st_ino); } } else { XrdOucString sfid = spath; if ((sfid.replace("inode:", ""))) { size_t pos = 0; try { fid = std::stoull(sfid.c_str(), &pos, 10); } catch (...) { stdErr = "error: inode option takes a fuse inode decimal value"; retc = EINVAL; return SFS_OK; } if (pos != (size_t)sfid.length()) { stdErr = "error: inode option takes a fuse inode decimal value - some " "characters were not converted"; retc = EINVAL; return SFS_OK; } if (eos::common::FileId::IsFileInode(fid)) { buf.st_mode = S_IFREG; fid = eos::common::FileId::InodeToFid(fid); spath = "fid:"; spath += eos::common::StringConversion::GetSizeString(sfid, fid); path = spath.c_str(); } else { buf.st_mode = S_IFDIR; spath.replace("inode:", "pid:"); path = spath.c_str(); } } else { // one of fid, fxid, pid, pxid buf.st_mode = (sfid.beginswith("f")) ? S_IFREG : S_IFDIR; sfid.replace('p', 'f', 0, 1); fid = Resolver::retrieveFileIdentifier(sfid).getUnderlyingUInt64(); } } if (mJsonFormat) { if (S_ISDIR(buf.st_mode)) { return DirJSON(fid, 0); } else { return FileJSON(fid, 0); } } else { if (S_ISDIR(buf.st_mode)) { return DirInfo(path); } else { return FileInfo(path); } } } //------------------------------------------------------------------------------ // Fileinfo given path //------------------------------------------------------------------------------ int ProcCommand::FileInfo(const char* path) { XrdOucString option = pOpaque->Get("mgm.file.info.option"); XrdOucString spath = path; bool detached = false; uint64_t clock = 0; { eos::common::RWMutexReadLock viewReadLock; std::shared_ptr fmd; if ((spath.beginswith("fid:") || (spath.beginswith("fxid:")))) { unsigned long long fid = Resolver::retrieveFileIdentifier( spath).getUnderlyingUInt64(); // Reference by fid+fxid eos::Prefetcher::prefetchFileMDAndWait(gOFS->eosView, fid); viewReadLock.Grab(gOFS->eosViewRWMutex); std::string nspath; try { fmd = gOFS->eosFileService->getFileMD(fid, &clock); nspath = gOFS->eosView->getUri(fmd.get()); if (fmd->isLink()) { try { spath = gOFS->eosView->getRealPath(nspath).c_str(); } catch (const eos::MDException& e) { // The link points to a location outside the EOS namespace therefore // we return info about the symlink object spath = nspath.c_str(); } } else { spath = nspath.c_str(); } } catch (eos::MDException& e) { errno = e.getErrno(); stdErr = "error: cannot retrieve file meta data - "; stdErr += e.getMessage().str().c_str(); eos_debug("msg=\"exception retrieving file metadata\" ec=%d " "emsg=\"%s\"\n", e.getErrno(), e.getMessage().str().c_str()); } // Detect detached state for fid/fxid reference detached = nspath.empty(); } else { // Reference by path eos::Prefetcher::prefetchFileMDAndWait(gOFS->eosView, spath.c_str()); viewReadLock.Grab(gOFS->eosViewRWMutex); try { fmd = gOFS->eosView->getFile(spath.c_str()); } catch (eos::MDException& e) { try { // Maybe this is a symlink pointing outside the EOS namespace fmd = gOFS->eosView->getFile(spath.c_str(), false); } catch (eos::MDException& ee) { errno = ee.getErrno(); stdErr = "error: cannot retrieve file meta data - "; stdErr += ee.getMessage().str().c_str(); eos_debug("msg=\"exception retrieving file metadata\" ec=%d " "emsg=\"%s\"\n", ee.getErrno(), ee.getMessage().str().c_str()); } } if (fmd) { try { std::string nspath = gOFS->eosView->getUri(fmd.get()); if (fmd->isLink()) { spath = gOFS->eosView->getRealPath(nspath).c_str(); } else { spath = nspath.c_str(); } } catch (eos::MDException& ee) { fmd.reset(); errno = ee.getErrno(); stdErr = "error: cannot retrieve file meta data - "; stdErr += ee.getMessage().str().c_str(); eos_debug("msg=\"exception retrieving file metadata\" ec=%d " "emsg=\"%s\"\n", ee.getErrno(), ee.getMessage().str().c_str()); } } } if (!fmd) { retc = errno; viewReadLock.Release(); //------------------------------------------- } else { using eos::common::Timing; using eos::common::FileId; using eos::common::LayoutId; using eos::common::StringConversion; // Make a copy of the file metadata object std::shared_ptr fmd_copy(fmd->clone()); fmd.reset(); // TODO (esindril): All this copying should be reviewed viewReadLock.Release(); //------------------------------------------- XrdOucString sizestring; bool Monitoring = false; bool Envformat = false; bool outputFilter = false; std::ostringstream out; const std::string hex_fid = FileId::Fid2Hex(fmd_copy->getId()); const std::string hex_pid = FileId::Fid2Hex(fmd_copy->getContainerId()); if ((option.find("-m")) != STR_NPOS) { Monitoring = true; } if ((option.find("-env")) != STR_NPOS) { Envformat = true; Monitoring = false; } if (Envformat) { std::string env; fmd_copy->getEnv(env); eos::common::Path cPath(spath.c_str()); out << env << "&container=" << cPath.GetParentPath() << std::endl; } else { // Filter output according to requested filters // Note: filters affect only non-monitoring output if (!Monitoring) { if ((option.find("-path")) != STR_NPOS) { out << "path: " << spath << std::endl; } if ((option.find("-fxid")) != STR_NPOS) { out << "fxid: " << hex_fid << std::endl; } if ((option.find("-fid")) != STR_NPOS) { out << "fid: " << fmd_copy->getId() << std::endl; } if ((option.find("-size")) != STR_NPOS) { out << "size: " << fmd_copy->getSize() << std::endl; } if ((option.find("-checksum")) != STR_NPOS) { std::string xs; eos::appendChecksumOnStringAsHex(fmd_copy.get(), xs); out << "xstype: " << LayoutId::GetChecksumString(fmd_copy->getLayoutId()) << std::endl << "xs: " << xs << std::endl; } // Mark filter flag if out is not empty outputFilter = (out.tellp() != std::streampos(0)); } if (Monitoring || !outputFilter) { eos::IFileMD::XAttrMap xattrs = fmd_copy->getAttributes(); bool showFullpath = (option.find("-fullpath") != STR_NPOS); bool showProxygroup = (option.find("-proxy") != STR_NPOS); eos::IFileMD::ctime_t mtime; eos::IFileMD::ctime_t ctime; eos::IFileMD::ctime_t btime {0, 0}; eos::IFileMD::ctime_t atime {0, 0}; fmd_copy->getCTime(ctime); fmd_copy->getMTime(mtime); fmd_copy->getATime(atime); if (xattrs.count("sys.eos.btime")) { Timing::Timespec_from_TimespecStr(xattrs["sys.eos.btime"], btime); } time_t filectime = (time_t) ctime.tv_sec; time_t filemtime = (time_t) mtime.tv_sec; time_t filebtime = (time_t) btime.tv_sec; time_t fileatime = (time_t) atime.tv_sec; std::string etag, xs_spaces; eos::calculateEtag(fmd_copy.get(), etag); eos::appendChecksumOnStringAsHex(fmd_copy.get(), xs_spaces, ' '); std::string redundancy = eos::common::LayoutId::GetRedundancySymbol( fmd_copy->hasLocation(EOS_TAPE_FSID), eos::common::LayoutId::GetRedundancy(fmd_copy->getLayoutId(), fmd_copy->getNumLocation())); if (!Monitoring) { out << " File: '" << spath << "'" << " Flags: " << StringConversion::IntToOctal((int) fmd_copy->getFlags(), 4); if (clock) { out << " Clock: " << FileId::Fid2Hex(clock); } out << std::endl; out << " Size: " << fmd_copy->getSize() << std::endl << "Status: " << FileMDToStatus(fmd_copy) << std::endl << "Modify: " << eos::common::Timing::ltime(filemtime) << " Timestamp: " << eos::common::Timing::TimespecToString(mtime) << std::endl << "Change: " << eos::common::Timing::ltime(filectime) << " Timestamp: " << eos::common::Timing::TimespecToString(ctime) << std::endl << "Access: " << eos::common::Timing::ltime(fileatime) << " Timestamp: " << eos::common::Timing::TimespecToString(atime) << std::endl << " Birth: " << eos::common::Timing::ltime(filebtime) << " Timestamp: " << eos::common::Timing::TimespecToString(btime) << std::endl << " CUid: " << fmd_copy->getCUid() << " CGid: " << fmd_copy->getCGid() << " Fxid: " << hex_fid << " Fid: " << fmd_copy->getId() << " Pid: " << fmd_copy->getContainerId() << " Pxid: " << hex_pid << std::endl; out << "XStype: " << LayoutId::GetChecksumString(fmd_copy->getLayoutId()) << " XS: " << xs_spaces << " ETAGs: " << etag << std::endl; out << "Layout: " << LayoutId::GetLayoutTypeString(fmd_copy->getLayoutId()) << " Stripes: " << (LayoutId::GetStripeNumber(fmd_copy->getLayoutId()) + 1) << " Blocksize: " << LayoutId::GetBlockSizeString(fmd_copy->getLayoutId()) << " LayoutId: " << FileId::Fid2Hex(fmd_copy->getLayoutId()) << " Redundancy: " << redundancy << std::endl; out << " #Rep: " << fmd_copy->getNumLocation() << std::endl; if (fmd_copy->hasLocation(EOS_TAPE_FSID)) { std::string storage_class = xattrs["sys.archive.storage_class"]; std::string archive_id = xattrs["sys.archive.file_id"]; out << "TapeID: " << (archive_id.length() ? archive_id : "undef") << " StorageClass: " << (storage_class.length() ? storage_class : "none") << std::endl; } if (xattrs.count("user.obfuscate.key")) { if (xattrs.count("user.encrypted")) { out << " Crypt: encrypted" << std::endl; } else { out << " Crypt: obfuscated" << std::endl; } } } else { std::string xs; if (LayoutId::GetChecksumLen(fmd_copy->getLayoutId())) { eos::appendChecksumOnStringAsHex(fmd_copy.get(), xs); } else { xs = "0"; } out << "keylength.file=" << spath.length() << " file=" << spath << " size=" << fmd_copy->getSize() << " status=" << FileMDToStatus(fmd_copy) << " mtime=" << mtime.tv_sec << "." << mtime.tv_nsec << " ctime=" << ctime.tv_sec << "." << ctime.tv_nsec << " btime=" << btime.tv_sec << "." << btime.tv_nsec << " atime=" << atime.tv_sec << "." << atime.tv_nsec << " clock=" << clock << " mode=" << StringConversion::IntToOctal((int) fmd_copy->getFlags(), 4) << " uid=" << fmd_copy->getCUid() << " gid=" << fmd_copy->getCGid() << " fxid=" << hex_fid << " fid=" << fmd_copy->getId() << " ino=" << FileId::FidToInode(fmd_copy->getId()) << " pid=" << fmd_copy->getContainerId() << " pxid=" << hex_pid << " xstype=" << LayoutId::GetChecksumString(fmd_copy->getLayoutId()) << " xs=" << xs << " etag=" << etag << " detached=" << detached << " layout=" << LayoutId::GetLayoutTypeString(fmd_copy->getLayoutId()) << " nstripes=" << (LayoutId::GetStripeNumber(fmd_copy->getLayoutId()) + 1) << " lid=" << FileId::Fid2Hex(fmd_copy->getLayoutId()) << " nrep=" << fmd_copy->getNumLocation() << " "; for (const auto& elem : xattrs) { out << "xattrn=" << elem.first << " xattrv=" << elem.second << " "; } } eos::IFileMD::LocationVector::const_iterator lociter; eos::IFileMD::LocationVector loc_vect = fmd_copy->getLocations(); std::vector selectedfs; std::vector proxys; std::vector firewalleps; std::vector unavailfs; std::vector replacedfs; size_t fsIndex; Scheduler::AccessArguments acsargs; int i = 0; int schedretc = -1; TableHeader table_mq_header; TableData table_mq_data; TableFormatterBase table_mq; bool table_mq_header_exist = false; for (lociter = loc_vect.begin(); lociter != loc_vect.end(); ++lociter) { // Ignore filesystem id 0 if (!(*lociter)) { eos_err("msg=\"found file on fsid=0\" fxid=%08llx", fmd_copy->getId()); continue; } XrdOucString location = ""; location += (int) * lociter; eos::common::RWMutexReadLock lock(FsView::gFsView.ViewMutex); eos::common::FileSystem* filesystem = FsView::gFsView.mIdView.lookupByID( *lociter); if (filesystem) { // For the fullpath option we output the physical location of the // replicas std::string fullpath; if (showFullpath) { fullpath = FileId::FidPrefix2FullPath(hex_fid.c_str(), filesystem->GetPath().c_str()); } if (!Monitoring) { std::string format = "header=1|key=host:width=24:format=s|key=schedgroup:width=16:format=s|key=path:width=16:format=s|key=stat.boot:width=10:format=s|key=configstatus:width=14:format=s|key=local.drain:width=12:format=s|key=stat.active:width=8:format=s|key=stat.geotag:width=24:format=s"; if (showProxygroup) { format += "|key=proxygroup:width=24:format=s"; } filesystem->Print(table_mq_header, table_mq_data, format); // Build header if (!table_mq_header.empty()) { TableHeader table_mq_header_temp; table_mq_header_temp.push_back(std::make_tuple("no.", 3, "-l")); table_mq_header_temp.push_back(std::make_tuple("fs-id", 6, "l")); std::copy(table_mq_header.begin(), table_mq_header.end(), std::back_inserter(table_mq_header_temp)); if (showFullpath) { table_mq_header_temp.push_back(std::make_tuple("physical location", 18, "s")); } table_mq.SetHeader(table_mq_header_temp); table_mq_header_exist = true; } // Build body if (table_mq_header_exist) { TableData table_mq_data_temp; for (auto& row : table_mq_data) { if (!row.empty()) { table_mq_data_temp.emplace_back(); table_mq_data_temp.back().push_back(TableCell(i, "l")); table_mq_data_temp.back().push_back(TableCell(*lociter, "l")); for (auto& cell : row) { table_mq_data_temp.back().push_back(cell); } if (showFullpath) { table_mq_data_temp.back().push_back(TableCell(fullpath.c_str(), "s")); } } } table_mq.AddRows(table_mq_data_temp); table_mq_data.clear(); table_mq_data_temp.clear(); } if ((filesystem->GetString("proxygroup").size()) && (filesystem->GetString("proxygroup") != "") && filesystem->GetString("filestickyproxydepth").size() && filesystem->GetLongLong("filestickyproxydepth") >= 0) { // we do the scheduling only once when we meet a filesystem that requires it if (schedretc == -1) { acsargs.bookingsize = fmd_copy->getSize(); acsargs.dataproxys = &proxys; acsargs.firewallentpts = NULL; acsargs.forcedfsid = 0; std::string space = filesystem->GetString("schedgroup"); space.resize(space.rfind(".")); acsargs.forcedspace = space.c_str(); acsargs.fsindex = &fsIndex; acsargs.isRW = false; acsargs.lid = fmd_copy->getLayoutId(); acsargs.inode = (ino64_t) fmd_copy->getId(); acsargs.locationsfs = &selectedfs; for (auto it = loc_vect.begin(); it != loc_vect.end(); it++) { selectedfs.push_back(*it); } std::string stried_cgi = ""; acsargs.tried_cgi = &stried_cgi; acsargs.unavailfs = &unavailfs; acsargs.vid = &vid; if (!acsargs.isValid()) { // there is something wrong in the arguments of file access eos_static_err("msg=\"open - invalid access argument\""); } schedretc = Scheduler::FileAccess(&acsargs); if (schedretc) { eos_static_warning("msg=\"cannot schedule the proxy\""); } } if (schedretc) { out << " sticky to undefined"; } else { size_t k; for (k = 0; k < loc_vect.size() && selectedfs[k] != loc_vect[i]; k++); out << "sticky to " << proxys[k]; } } } else { out << "fsid=" << location << " "; if (showFullpath) { out << "fullpath=" << fullpath << " "; } } } else { if (!Monitoring) { if (location != EOS_TAPE_FSID) { out << std::setw(3) << i << std::setw(8) << location << " NA" << std::endl; } } else { out << "fsid=" << location << " "; } } i++; } out << table_mq.GenerateTable(HEADER); eos::IFileMD::LocationVector unlink_vect = fmd_copy->getUnlinkedLocations(); for (lociter = unlink_vect.begin(); lociter != unlink_vect.end(); ++lociter) { if (!Monitoring) { out << "(undeleted) $ " << *lociter << std::endl; } else { out << "fsdel=" << *lociter << " "; } } if (!Monitoring) { out << "*******"; } } } stdOut += out.str().c_str(); } } return SFS_OK; } //------------------------------------------------------------------------------ // DirInfo by path //------------------------------------------------------------------------------ int ProcCommand::DirInfo(const char* path) { XrdOucString option = pOpaque->Get("mgm.file.info.option"); XrdOucString spath = path; bool detached = false; uint64_t clock = 0; { eos::common::RWMutexReadLock viewReadLock; std::shared_ptr dmd; if ((spath.beginswith("pid:") || (spath.beginswith("pxid:")))) { unsigned long long fid = 0; if (spath.beginswith("pid:")) { spath.replace("pid:", ""); fid = strtoull(spath.c_str(), 0, 10); } if (spath.beginswith("pxid:")) { spath.replace("pxid:", ""); fid = strtoull(spath.c_str(), 0, 16); } // reference by pid+pxid //------------------------------------------- eos::Prefetcher::prefetchContainerMDAndWait(gOFS->eosView, fid); viewReadLock.Grab(gOFS->eosViewRWMutex); std::string nspath; try { dmd = gOFS->eosDirectoryService->getContainerMD(fid, &clock); nspath = gOFS->eosView->getUri(dmd.get()); spath = nspath.c_str(); } catch (eos::MDException& e) { errno = e.getErrno(); stdErr = "error: cannot retrieve directory meta data - "; stdErr += e.getMessage().str().c_str(); eos_debug("msg=\"exception retrieving container metadata\" ec=%d " "emsg=\"%s\"\n", e.getErrno(), e.getMessage().str().c_str()); } // Detect detached state for pid/pxid reference detached = nspath.empty(); } else { eos::Prefetcher::prefetchContainerMDAndWait(gOFS->eosView, spath.c_str()); // reference by path //------------------------------------------- viewReadLock.Grab(gOFS->eosViewRWMutex); try { dmd = gOFS->eosView->getContainer(spath.c_str()); } catch (eos::MDException& e) { errno = e.getErrno(); stdErr = "error: cannot retrieve directory meta data - "; stdErr += e.getMessage().str().c_str(); eos_debug("msg=\"exception retrieving container metadata\" ec=%d " "emsg=\"%s\"\n", e.getErrno(), e.getMessage().str().c_str()); } } if (!dmd) { retc = errno; viewReadLock.Release(); //------------------------------------------- } else { using eos::common::Timing; using eos::common::FileId; using eos::common::LayoutId; using eos::common::StringConversion; size_t num_containers = dmd->getNumContainers(); size_t num_files = dmd->getNumFiles(); size_t tree_size = dmd->getTreeSize(); std::shared_ptr dmd_copy(dmd->clone()); dmd.reset(); viewReadLock.Release(); //------------------------------------------- XrdOucString sizestring; bool Monitoring = false; bool outputFilter = false; std::ostringstream out; const std::string hex_fid = FileId::Fid2Hex(dmd_copy->getId()); const std::string hex_pid = FileId::Fid2Hex(dmd_copy->getParentId()); if ((option.find("-m")) != STR_NPOS) { Monitoring = true; } // Filter output according to requested filters // Note: filters affect only non-monitoring output if (!Monitoring) { if ((option.find("-path")) != STR_NPOS) { out << "path: " << spath << std::endl; } if ((option.find("-fxid")) != STR_NPOS) { out << "fxid: " << hex_fid << std::endl; } if ((option.find("-fid")) != STR_NPOS) { out << "fid: " << dmd_copy->getId() << std::endl; } if ((option.find("-size")) != STR_NPOS) { out << "size: " << (num_containers + num_files) << std::endl; } outputFilter = ((out.tellp() != std::streampos(0)) || (option.find("-checksum") != STR_NPOS)); } if (Monitoring || !outputFilter) { eos::IFileMD::XAttrMap xattrs = dmd_copy->getAttributes(); eos::IContainerMD::ctime_t ctime; eos::IContainerMD::mtime_t mtime; eos::IContainerMD::tmtime_t tmtime; eos::IContainerMD::ctime_t btime {0, 0}; dmd_copy->getCTime(ctime); dmd_copy->getMTime(mtime); dmd_copy->getTMTime(tmtime); if (xattrs.count("sys.eos.btime")) { Timing::Timespec_from_TimespecStr(xattrs["sys.eos.btime"], btime); } time_t filectime = (time_t) ctime.tv_sec; time_t filemtime = (time_t) mtime.tv_sec; time_t filetmtime = (time_t) tmtime.tv_sec; time_t filebtime = (time_t) btime.tv_sec; char fid[32]; snprintf(fid, 32, "%llu", (unsigned long long) dmd_copy->getId()); std::string etag; eos::calculateEtag(dmd_copy.get(), etag); if (!Monitoring) { out << " Directory: '" << spath << "'" << " Treesize: " << tree_size << std::endl; out << " Container: " << num_containers << " Files: " << num_files << " Flags: " << StringConversion::IntToOctal(dmd_copy->getMode(), 4); if (clock) { out << " Clock: " << FileId::Fid2Hex(clock); } out << std::endl; out << "Modify: " << eos::common::Timing::ltime(filemtime) << " Timestamp: " << eos::common::Timing::TimespecToString(mtime) << std::endl << "Change: " << eos::common::Timing::ltime(filectime) << " Timestamp: " << eos::common::Timing::TimespecToString(ctime) << std::endl << "Sync : " << eos::common::Timing::ltime(filetmtime) << " Timestamp: " << eos::common::Timing::TimespecToString(tmtime) << std::endl << "Birth : " << eos::common::Timing::ltime(filebtime) << " Timestamp: " << eos::common::Timing::TimespecToString(btime) << std::endl << " CUid: " << dmd_copy->getCUid() << " CGid: " << dmd_copy->getCGid() << " Fxid: " << hex_fid << " Fid: " << dmd_copy->getId() << " Pid: " << dmd_copy->getParentId() << " Pxid: " << hex_pid << std::endl << " ETAG: " << etag << std::endl; } else { out << "keylength.file=" << spath.length() << " file=" << spath << " treesize=" << tree_size << " container=" << num_containers << " files=" << num_files << " mtime=" << mtime.tv_sec << "." << mtime.tv_nsec << " ctime=" << ctime.tv_sec << "." << ctime.tv_nsec << " btime=" << btime.tv_sec << "." << btime.tv_nsec << " stime=" << tmtime.tv_sec << "." << tmtime.tv_nsec << " clock=" << clock << " mode=" << StringConversion::IntToOctal((int) dmd_copy->getMode(), 4) << " uid=" << dmd_copy->getCUid() << " gid=" << dmd_copy->getCGid() << " fxid=" << hex_fid << " fid=" << dmd_copy->getId() << " ino=" << dmd_copy->getId() << " pid=" << dmd_copy->getParentId() << " pxid=" << hex_pid << " etag=" << etag << " detached=" << detached << " "; for (const auto& elem : xattrs) { out << "xattrn=" << elem.first << " xattrv=" << elem.second << " "; } } } stdOut += out.str().c_str(); } } return SFS_OK; } //------------------------------------------------------------------------------ // File info in JSON format //------------------------------------------------------------------------------ int ProcCommand::FileJSON(uint64_t fid, Json::Value* ret_json, bool dolock) { eos::IFileMD::ctime_t ctime; eos::IFileMD::ctime_t mtime; eos::IFileMD::ctime_t atime {0, 0}; eos::IFileMD::ctime_t btime {0, 0}; eos_static_debug("msg=\"JSON fileinfo\" fxid=%08llx", fid); Json::Value json; json["id"] = (Json::Value::UInt64) fid; const std::string hex_fid = eos::common::FileId::Fid2Hex(fid); try { eos::Prefetcher::prefetchFileMDWithParentsAndWait(gOFS->eosView, fid); eos::common::RWMutexReadLock viewReadLock; std::shared_ptr fmd; std::string path; bool detached; if (dolock) { viewReadLock.Grab(gOFS->eosViewRWMutex); } try { fmd = gOFS->eosFileService->getFileMD(fid); path = gOFS->eosView->getUri(fmd.get()); } catch (eos::MDException& e) { eos_static_debug("msg=\"exception retrieving file metadata\" ec=%d " "emsg=\"%s\"\n", e.getErrno(), e.getMessage().str().c_str()); if (!fmd) { if (dolock) { viewReadLock.Release(); } std::rethrow_exception(std::current_exception()); } } std::shared_ptr fmd_copy(fmd->clone()); fmd.reset(); if (dolock) { viewReadLock.Release(); } // TODO (esindril): All this copying should be reviewed //-------------------------------------------------------------------------- fmd_copy->getCTime(ctime); fmd_copy->getMTime(mtime); fmd_copy->getATime(atime); unsigned long long nlink = (fmd_copy->isLink()) ? 1 : fmd_copy->getNumLocation(); eos::IFileMD::XAttrMap xattrs = fmd_copy->getAttributes(); if (xattrs.count("sys.eos.btime")) { eos::common::Timing::Timespec_from_TimespecStr(xattrs["sys.eos.btime"], btime); } if ((detached = path.empty())) { path = SSTR("fid:" << fid); } json["fxid"] = hex_fid.c_str(); json["inode"] = (Json::Value::UInt64) eos::common::FileId::FidToInode(fid); json["ctime"] = (Json::Value::UInt64) ctime.tv_sec; json["ctime_ns"] = (Json::Value::UInt64) ctime.tv_nsec; json["atime"] = (Json::Value::UInt64) atime.tv_sec; json["atime_ns"] = (Json::Value::UInt64) atime.tv_nsec; json["mtime"] = (Json::Value::UInt64) mtime.tv_sec; json["mtime_ns"] = (Json::Value::UInt64) mtime.tv_nsec; json["btime"] = (Json::Value::UInt64) btime.tv_sec; json["btime_ns"] = (Json::Value::UInt64) btime.tv_nsec; json["size"] = (Json::Value::UInt64) fmd_copy->getSize(); json["uid"] = fmd_copy->getCUid(); json["gid"] = fmd_copy->getCGid(); json["mode"] = fmd_copy->getFlags(); json["nlink"] = (Json::Value::UInt64) nlink; json["name"] = fmd_copy->getName(); json["path"] = path; json["detached"] = detached; json["pid"] = (Json::Value::UInt64) fmd_copy->getContainerId(); json["layout"] = eos::common::LayoutId::GetLayoutTypeString( fmd_copy->getLayoutId()); json["nstripes"] = (int)(eos::common::LayoutId::GetStripeNumber( fmd_copy->getLayoutId()) + 1); if (fmd_copy->isLink()) { json["target"] = fmd_copy->getLink(); } Json::Value jsonxattr; for (const auto& elem : xattrs) { jsonxattr[elem.first] = elem.second; } if (fmd_copy->numAttributes()) { json["xattr"] = jsonxattr; } Json::Value jsonfsids; eos::IFileMD::LocationVector loc_vect = fmd_copy->getLocations(); // Get host name for the fs ids for (auto loc_it = loc_vect.begin(); loc_it != loc_vect.end(); ++loc_it) { eos::common::RWMutexReadLock lock(FsView::gFsView.ViewMutex); Json::Value jsonfsinfo; eos::common::FileSystem* filesystem = FsView::gFsView.mIdView.lookupByID( *loc_it); if (filesystem) { eos::common::FileSystem::fs_snapshot_t fs; if (filesystem->SnapShotFileSystem(fs, true)) { std::string fstpath = eos::common::FileId::FidPrefix2FullPath(hex_fid.c_str(), fs.mPath.c_str()); jsonfsinfo["fsid"] = fs.mId; jsonfsinfo["geotag"] = filesystem->GetString("stat.geotag"); jsonfsinfo["host"] = fs.mHost; jsonfsinfo["mountpoint"] = fs.mPath; jsonfsinfo["fstpath"] = fstpath.c_str(); jsonfsinfo["schedgroup"] = fs.mGroup; jsonfsinfo["status"] = eos::common::FileSystem::GetStatusAsString(fs.mStatus); if (!fs.mForceGeoTag.empty()) { jsonfsinfo["forcegeotag"] = fs.mForceGeoTag; } } } else { jsonfsinfo["fsid"] = *loc_it; } jsonfsids.append(jsonfsinfo); } json["locations"] = jsonfsids; json["checksumtype"] = eos::common::LayoutId::GetChecksumString( fmd_copy->getLayoutId()); std::string cks; eos::appendChecksumOnStringAsHex(fmd_copy.get(), cks); json["checksumvalue"] = cks; std::string etag; eos::calculateEtag(fmd_copy.get(), etag); json["etag"] = etag; json["status"] = FileMDToStatus(fmd_copy); } catch (eos::MDException& e) { errno = e.getErrno(); eos_static_debug("msg=\"exception during JSON fileinfo\" ec=%d " "emsg=\"%s\"\n", e.getErrno(), e.getMessage().str().c_str()); json["errc"] = errno; json["errmsg"] = e.getMessage().str().c_str(); } if (!ret_json) { std::stringstream r; r << json; stdJson += r.str().c_str(); } else { *ret_json = json; } retc = 0; return SFS_OK; } //------------------------------------------------------------------------------ // Get directory info in JSON format //------------------------------------------------------------------------------ int ProcCommand::DirJSON(uint64_t fid, Json::Value* ret_json, bool dolock) { eos::IFileMD::ctime_t ctime; eos::IFileMD::ctime_t mtime; eos::IFileMD::ctime_t tmtime; eos::IFileMD::ctime_t btime {0, 0}; eos_static_debug("msg=\"JSON dirinfo\" fxid=%08llx", fid); Json::Value json; json["id"] = (Json::Value::UInt64) fid; try { eos::common::RWMutexReadLock viewReadLock; std::shared_ptr cmd; std::string path; bool detached; eos::Prefetcher::prefetchContainerMDWithParentsAndWait(gOFS->eosView, fid); if (dolock) { viewReadLock.Grab(gOFS->eosViewRWMutex); } try { cmd = gOFS->eosDirectoryService->getContainerMD(fid); path = gOFS->eosView->getUri(cmd.get()); } catch (eos::MDException& e) { eos_static_debug("msg=\"exception retrieving container metadata\" " "ec=%d emsg=\"%s\"\n", e.getErrno(), e.getMessage().str().c_str()); if (!cmd) { viewReadLock.Release(); std::rethrow_exception(std::current_exception()); } } eos::IFileMD::XAttrMap xattrs = cmd->getAttributes(); cmd->getCTime(ctime); cmd->getMTime(mtime); cmd->getTMTime(tmtime); if (xattrs.count("sys.eos.btime")) { eos::common::Timing::Timespec_from_TimespecStr(xattrs["sys.eos.btime"], btime); } if ((detached = path.empty())) { path = SSTR("pid:" << fid); } json["inode"] = (Json::Value::UInt64) fid; json["ctime"] = (Json::Value::UInt64) ctime.tv_sec; json["ctime_ns"] = (Json::Value::UInt64) ctime.tv_nsec; json["atime"] = (Json::Value::UInt64) ctime.tv_sec; json["atime_ns"] = (Json::Value::UInt64) ctime.tv_nsec; json["mtime"] = (Json::Value::UInt64) mtime.tv_sec; json["mtime_ns"] = (Json::Value::UInt64) mtime.tv_nsec; json["tmtime"] = (Json::Value::UInt64) tmtime.tv_sec; json["tmtime_ns"] = (Json::Value::UInt64) tmtime.tv_nsec; json["btime"] = (Json::Value::UInt64) btime.tv_sec; json["btime_ns"] = (Json::Value::UInt64) btime.tv_nsec; json["treesize"] = (Json::Value::UInt64) cmd->getTreeSize(); json["uid"] = cmd->getCUid(); json["gid"] = cmd->getCGid(); json["flags"] = cmd->getFlags(); json["mode"] = cmd->getMode(); json["nlink"] = 1; json["name"] = cmd->getName(); json["path"] = path; json["detached"] = detached; json["pid"] = (Json::Value::UInt64) cmd->getParentId(); json["nndirectories"] = (int)cmd->getNumContainers(); json["nfiles"] = (int)cmd->getNumFiles(); Json::Value chld; std::shared_ptr cmd_copy(cmd->clone()); cmd_copy->InheritChildren(*(cmd.get())); cmd.reset(); viewReadLock.Release(); if (!ret_json) { for (auto it = FileMapIterator(cmd_copy); it.valid(); it.next()) { Json::Value fjson; FileJSON(it.value(), &fjson, true); chld.append(fjson); } // Loop through all subcontainers for (auto dit = ContainerMapIterator(cmd_copy); dit.valid(); dit.next()) { Json::Value djson; DirJSON(dit.value(), &djson, true); chld.append(djson); } } if ((cmd_copy->getNumFiles() + cmd_copy->getNumContainers()) != 0) { json["children"] = chld; } Json::Value jsonxattr; for (const auto& elem : xattrs) { jsonxattr[elem.first] = elem.second; } if (cmd_copy->numAttributes()) { json["xattr"] = jsonxattr; } std::string etag; eos::calculateEtag(cmd_copy.get(), etag); json["etag"] = etag; } catch (eos::MDException& e) { errno = e.getErrno(); eos_static_debug("msg=\"exception during JSON dirinfo\" ec=%d " "emsg=\"%s\"\n", e.getErrno(), e.getMessage().str().c_str()); json["errc"] = errno; json["errmsg"] = e.getMessage().str().c_str(); } if (!ret_json) { std::stringstream r; r << json; stdJson += r.str().c_str(); retc = 0; } else { *ret_json = json; } return SFS_OK; } EOSMGMNAMESPACE_END