//------------------------------------------------------------------------------ //! @file FsckCmd.cc //! @author Elvin Sindrilaru - CERN //------------------------------------------------------------------------------ /************************************************************************ * EOS - the CERN Disk Storage System * * Copyright (C) 2019 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 "FsckCmd.hh" #include "mgm/XrdMgmOfs.hh" #include "mgm/FsView.hh" #include "mgm/fsck/Fsck.hh" EOSMGMNAMESPACE_BEGIN //------------------------------------------------------------------------------ // Method implementing the specific behavior of the command executed //------------------------------------------------------------------------------ eos::console::ReplyProto FsckCmd::ProcessRequest() noexcept { eos::console::ReplyProto reply; eos::console::FsckProto fsck = mReqProto.fsck(); eos::console::FsckProto::SubcmdCase subcmd = fsck.subcmd_case(); if ((subcmd != eos::console::FsckProto::kReport) && (mVid.uid != 0)) { reply.set_retc(EPERM); reply.set_std_err("error: only admin can execute this command"); return reply; } if (subcmd == eos::console::FsckProto::kStat) { const bool monitor_fmt = (mReqProto.format() == eos::console::RequestProto_FormatType_FUSE); std::string output; gOFS->mFsckEngine->PrintOut(output, monitor_fmt); reply.set_std_out(std::move(output)); } else if (subcmd == eos::console::FsckProto::kConfig) { const eos::console::FsckProto::ConfigProto& config = fsck.config(); std::string msg; if (!gOFS->mFsckEngine->Config(config.key(), config.value(), msg)) { reply.set_retc(EINVAL); if (msg.empty()) { reply.set_std_err(SSTR("error: failed to set " << config.key() << "=" << config.value()).c_str()); } else { reply.set_std_err(msg); } } } else if (subcmd == eos::console::FsckProto::kReport) { const eos::console::FsckProto::ReportProto& report = fsck.report(); std::set tags; // Collect all the tags for (const auto& elem : report.tags()) { tags.insert(elem); } std::string out; if (gOFS->mFsckEngine->Report(out, tags, report.display_per_fs(), report.display_fxid(), report.display_lfn(), report.display_json())) { reply.set_std_out(out); } else { reply.set_retc(EINVAL); reply.set_std_err(out); } } else if (subcmd == eos::console::FsckProto::kRepair) { std::string out; const eos::console::FsckProto::RepairProto& repair = fsck.repair(); const eos::common::FileSystem::fsid_t fsid_err = repair.fsid_err(); if (gOFS->mFsckEngine->RepairEntry(repair.fid(), {fsid_err}, repair.error(), repair.async(), out)) { reply.set_std_out(out); } else { reply.set_std_err(out); reply.set_retc(EINVAL); } } else if (subcmd == eos::console::FsckProto::kCleanOrphans) { const eos::console::FsckProto::CleanOrphansProto& clean = fsck.clean_orphans(); eos::common::FileSystem::fsid_t fsid = clean.fsid(); std::string query = "/?fst.pcmd=clean_orphans&fst.fsid=" + std::to_string(fsid); std::set endpoints; if (fsid == 0ul) { // Send command to all FSTs (nodes) eos::common::RWMutexReadLock fs_rd_lock(FsView::gFsView.ViewMutex); for (const auto& elem : FsView::gFsView.mNodeView) { if (elem.second->GetActiveStatus() == eos::common::ActiveStatus::kOnline) { eos_static_debug("msg=\"fsck clean_orphans\" hostport=\"%s\"", elem.second->GetMember("hostport").c_str()); endpoints.insert(elem.second->GetMember("hostport")); } } } else { // Send command only to the corresponding FST (node) eos::common::RWMutexReadLock fs_rd_lock(FsView::gFsView.ViewMutex); auto* fs = FsView::gFsView.mIdView.lookupByID(fsid); if (!fs) { reply.set_retc(EINVAL); reply.set_std_err("error: given file system does not exist"); return reply; } std::ostringstream endpoint; endpoint << fs->GetHost() << ":" << fs->getCoreParams().getLocator().getPort(); endpoints.insert(endpoint.str()); } // Map of responses from each individual endpoint std::map> responses; if (gOFS->BroadcastQuery(query, endpoints, responses)) { std::ostringstream err_msg; err_msg << "error: failed orphans clean for the following endpoints\n"; for (const auto& elem : responses) { if (elem.second.first) { err_msg << "node: " << elem.first << " errc: " << elem.second.first << " msg: " << elem.second.second; } } reply.set_std_err(err_msg.str()); reply.set_retc(EINVAL); } else { reply.set_std_out("info: orphans successfully cleaned"); } } else { reply.set_retc(EINVAL); reply.set_std_err("error: not supported"); } return reply; } EOSMGMNAMESPACE_END