//------------------------------------------------------------------------------
//! @file ProcCommand.hh
//! @param Elvin Sindrilaru - CERN
//------------------------------------------------------------------------------
/************************************************************************
* EOS - the CERN Disk Storage System *
* Copyright (C) 2017 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 .*
************************************************************************/
#pragma once
#include "mgm/Namespace.hh"
#include "IProcCommand.hh"
#include "XrdOuc/XrdOucEnv.hh"
#include "namespace/interface/IView.hh"
#include
//! Forward declaration
namespace Json
{
class Value;
}
EOSMGMNAMESPACE_BEGIN
//------------------------------------------------------------------------------
//! @todo (esindril): This needs to be moved to the archive command
//! Class IFilter used as interface to implement various types of filters
//! for the archive and backup operations.
//------------------------------------------------------------------------------
class IFilter
{
public:
//----------------------------------------------------------------------------
//! Destructor
//----------------------------------------------------------------------------
virtual ~IFilter() {};
//----------------------------------------------------------------------------
//! Filter the file entry
//!
//! @param entry_info entry information on which the filter is applied
//!
//! @return true if entry should be filtered out, otherwise false
//----------------------------------------------------------------------------
virtual bool FilterOutFile(const std::map& entry_info) = 0 ;
//----------------------------------------------------------------------------
//! Filter the directory entry
//!
//! @param path current directory path
//!
//! @return true if entry should be filtered out, otherwise false
//----------------------------------------------------------------------------
virtual bool FilterOutDir(const std::string& path) = 0;
};
//------------------------------------------------------------------------------
//! Class handling proc command execution
//------------------------------------------------------------------------------
class ProcCommand: public IProcCommand
{
public:
//----------------------------------------------------------------------------
//! Constructor
//----------------------------------------------------------------------------
ProcCommand();
//----------------------------------------------------------------------------
//! Constructor
//!
//! @param vid identity of the user executing the current command
//----------------------------------------------------------------------------
ProcCommand(eos::common::VirtualIdentity& vid);
//----------------------------------------------------------------------------
//! Destructor
//----------------------------------------------------------------------------
virtual ~ProcCommand();
//----------------------------------------------------------------------------
//! Open a proc command e.g. call the appropriate user or admin command and
//! store the output in a resultstream of in case of find in temporary output
//! files.
//!
//! @param inpath path indicating user or admin command
//! @param info CGI describing the proc command
//! @param vid_in virtual identity of the user requesting a command
//! @param error object to store errors
//!
//! @return SFS_OK or client stall interval in seconds
//----------------------------------------------------------------------------
virtual int open(const char* path, const char* info,
eos::common::VirtualIdentity& vid,
XrdOucErrInfo* error) override;
//----------------------------------------------------------------------------
//! Read a part of the result stream created during open
//!
//! @param boff offset where to start
//! @param buff buffer to store stream
//! @param blen len to return
//!
//! @return number of bytes read
//----------------------------------------------------------------------------
virtual size_t read(XrdSfsFileOffset offset, char* buff,
XrdSfsXferSize blen) override;
//----------------------------------------------------------------------------
//! Get the size of the result stream
//!
//! @param buf stat structure to fill
//!
//! @return SFS_OK in any case
//----------------------------------------------------------------------------
virtual int stat(struct stat* buf) override;
//----------------------------------------------------------------------------
//! Close the proc stream and store the client's command comment
//! in the comments logbook
//!
//! @return 0 if comment has been successfully stored otherwise != 0
//----------------------------------------------------------------------------
virtual int close() override;
//----------------------------------------------------------------------------
//! Method implementing the specific behavior of the command executed by the
//! asynchronous thread - used only for protobuf commands
//----------------------------------------------------------------------------
virtual eos::console::ReplyProto ProcessRequest() noexcept override
{
// Default behavior for old (raw) style commands
return eos::console::ReplyProto();
}
//----------------------------------------------------------------------------
//! Add stdout, stderr to an external stdout, stderr variable
//----------------------------------------------------------------------------
void
AddOutput(XrdOucString& lStdOut, XrdOucString& lStdErr)
{
lStdOut += stdOut;
lStdErr += stdErr;
}
//----------------------------------------------------------------------------
//! Add stdout, stderr to an external stdout, stderr variable
//----------------------------------------------------------------------------
void
AddOutput(std::string& lStdOut, std::string& lStdErr)
{
lStdOut += stdOut.c_str();
lStdErr += stdErr.c_str();
}
//----------------------------------------------------------------------------
//! Open temporary output files for find commands
//!
//! @return true if successful otherwise false
//----------------------------------------------------------------------------
bool OpenTemporaryOutputFiles() override;
//----------------------------------------------------------------------------
//! Get the return code of a proc command
//----------------------------------------------------------------------------
inline int GetRetc() const
{
return retc;
}
//----------------------------------------------------------------------------
//! Get stdErr of a proc command
//----------------------------------------------------------------------------
inline const char* GetStdErr() const
{
return stdErr.c_str();
}
//----------------------------------------------------------------------------
//! Get stdJson of a proc command
//----------------------------------------------------------------------------
inline const char* GetStdJson() const
{
return stdJson.c_str();
}
//----------------------------------------------------------------------------
//! Get the result stream of a proc command
//----------------------------------------------------------------------------
inline const char* GetResult(size_t& size) const override
{
if (mClosed) {
size = 0;
return 0;
}
size = mResultStream.size();
return mResultStream.c_str();
}
//----------------------------------------------------------------------------
//! Get result file name
//----------------------------------------------------------------------------
inline const char* GetResultFn() const
{
return fresultStreamfilename.c_str();
}
//----------------------------------------------------------------------------
//! List of user proc commands
//----------------------------------------------------------------------------
int Accounting();
int Attr();
int Archive();
int Backup();
int Cd();
int Chmod();
int DirInfo(const char* path);
int DirJSON(uint64_t id, Json::Value* json, bool dolock = true);
int Find();
int File();
int Fileinfo();
int FileInfo(const char* path);
int FileJSON(uint64_t id, Json::Value* json, bool dolock = true);
int Fuse();
int FuseX();
int Ls();
int Map();
int Member();
int Mkdir();
int Motd();
int Recycle();
int Rm();
int Rmdir();
int Version();
int Who();
int Whoami();
int UserQuota();
//----------------------------------------------------------------------------
//! List of admin proc commands
//----------------------------------------------------------------------------
int Chown();
int Drain();
int Fusex();
int GeoSched();
int Ns();
int Rtlog();
int Vid();
int Access(); // @todo (faluchet) drop when move to 5.0.0
int Config(); // @todo (faluchet) drop when move to 5.0.0
int Group(); // @todo (faluchet) drop when move to 5.0.0
int AdminQuota(); // @todo (faluchet) drop when move to 5.0.0
//----------------------------------------------------------------------------
//! Send command to archive daemon and collect the response
//!
//! @param cmd archive command in JSON format
//!
//! @return 0 is successful, otherwise errno. The output of the command or
//! any possible error messages are saved in stdOut and stdErr.
//----------------------------------------------------------------------------
int ArchiveExecuteCmd(const::string& cmd);
//----------------------------------------------------------------------------
//! Response structure holding information about the status of an archived dir
//----------------------------------------------------------------------------
struct ArchDirStatus {
std::string mTime;
std::string mUuid;
std::string mPath;
std::string mOp;
std::string mStatus;
//--------------------------------------------------------------------------
//! Constructor
//--------------------------------------------------------------------------
ArchDirStatus(const std::string& xtime, const std::string& uuid,
const std::string& path, const std::string& op,
const std::string& st):
mTime(xtime), mUuid(uuid), mPath(path), mOp(op), mStatus(st)
{};
//--------------------------------------------------------------------------
//! Destructor
//--------------------------------------------------------------------------
~ArchDirStatus() {};
};
//----------------------------------------------------------------------------
//! Create a result stream from stdOut, stdErr & retc
//----------------------------------------------------------------------------
void MakeResult();
//----------------------------------------------------------------------------
//! Helper function able to detect key value pair output and convert to http
//! table format
//----------------------------------------------------------------------------
bool KeyValToHttpTable(XrdOucString& stdOut);
//----------------------------------------------------------------------------
//! Helper function to classify the current file state
//----------------------------------------------------------------------------
std::string FileMDToStatus(std::shared_ptr fmd);
//----------------------------------------------------------------------------
//! Return the name of the command
//----------------------------------------------------------------------------
std::string GetCmd(const char* cgi) override
{
if (cgi) {
XrdOucEnv env(cgi);
return env.Get("mgm.cmd") ? env.Get("mgm.cmd") : "none";
}
return "none";
}
void SetError(XrdOucErrInfo* error) override
{
mError = error;
}
//----------------------------------------------------------------------------
//! Convert output to json format for EOS-wnc
//----------------------------------------------------------------------------
static Json::Value CallJsonFormatter(const std::string& output);
protected:
eos::common::VirtualIdentity* pVid; ///< Pointer to virtual identity
private:
XrdOucString mPath; ///< path argument for the proc command
XrdOucString mCmd; ///< proc command name
XrdOucString mSubCmd; ///< proc sub command name
XrdOucString mArgs; ///< full args from opaque input
std::string mResultStream; ///< string containing the assembled stream
XrdOucEnv* pOpaque; ///< pointer to the opaque information object
const char* ininfo; ///< original opaque info string
bool mDoSort; ///< sort flag (true = sorting)
const char* mSelection; ///< selection argument from the opaque request
XrdOucString mOutFormat; ///< output format type e.g. fuse or json
unsigned mOutDepth; ///< depth of aggregation along the topology tree
//----------------------------------------------------------------------------
//! The 'find' command does not keep results in memory but writes to
//! a temporary output file which is streamed to the client
//----------------------------------------------------------------------------
FILE* fstdout;
FILE* fstderr;
FILE* fresultStream;
XrdOucString fstdoutfilename;
XrdOucString fstderrfilename;
XrdOucString fresultStreamfilename;
XrdOucErrInfo* mError;
ssize_t mLen; ///< len of the result stream
bool mAdminCmd; ///< indicates an admin command
bool mUserCmd; ///< indicates a user command
bool mFuseFormat; ///< indicates FUSE format
bool mJsonFormat; ///< indicates JSON format
bool mHttpFormat; ///< indicates HTTP format
bool mClosed; ///< indicates the proc command has been closed already
bool mSendRetc; ///< indicates to return the return code to the open call
XrdOucString mJsonCallback; ///< sets the JSONP callback name in a response
//----------------------------------------------------------------------------
//! Create archive file. If successful then the archive file is copied to the
//! arch_dir location. If not it sets the retc and stdErr string accordingly.
//!
//! @param arch_dir directory for which the archive file is created
//! @param dst_url archive destination URL (i.e. CASTOR location)
//! @param fid inode number of the archive root directory used for fast find
//! functionality of archived directories through .../proc/archive/
//!
//! @return void, it sets the global retc in case of error
//----------------------------------------------------------------------------
void ArchiveCreate(const std::string& arch_dir,
const std::string& dst_url, uint64_t fid);
//----------------------------------------------------------------------------
//! Get list of archived files from the proc/archive directory
//!
//! @param root root of subtree for which we collect archived entries
//!
//! @return vector containing the full path of the directories currently
//! archived
//----------------------------------------------------------------------------
std::vector ArchiveGetDirs(const std::string& root) const;
//----------------------------------------------------------------------------
//! Update the status of the archived directories depending on the information
//! that we got from the archiver daemon. All ongoing transfers will be in
//! status "transferring" while the rest will display the status of the
//! archive.
//!
//! @param dirs vector of archived directories
//! @param tx_dirs vector of ongoing transfers
//! @param max_path_len max path length of the entries in the dirs vector
//----------------------------------------------------------------------------
void ArchiveUpdateStatus(std::vector& dirs,
std::vector& tx_dirs,
size_t& max_path_len);
//----------------------------------------------------------------------------
//! Get fileinfo for all files/dirs in the subtree and add it to the
//! archive i.e. do
//! "find -d --fileinfo /dir/" for directories or
//! "find -f --fileinfo /dir/ for files.
//!
//! @param arch_dir EOS directory being archived
//! @param arch_ofs local archive file stream object
//! @param num number of entries added
//! @param is_file if true add file entries to the archive, otherwise
//! directories
//! @param filter filter to be applied to the entries
//!
//! @return 0 if successful, otherwise errno
//----------------------------------------------------------------------------
int ArchiveAddEntries(const std::string& arch_dir, std::fstream& arch_ofs,
int& num, bool is_file, IFilter* filter = NULL);
//----------------------------------------------------------------------------
//! Make EOS sub-tree immutable by adding the sys.acl=z:i rule to all of the
//! directories in the sub-tree.
//!
//! @param arch_dir EOS directory
//! @param vect_files vector of special archive filenames
//!
//! @return 0 is successful, otherwise errno. It sets the global retc in case
//! of error.
//----------------------------------------------------------------------------
int MakeSubTreeImmutable(const std::string& arch_dir,
const std::vector& vect_files);
//----------------------------------------------------------------------------
//! Make EOS sub-tree mutable by removing the sys.acl=z:i rule from all of the
//! directories in the sub-tree.
//!
//! @param arch_dir EOS directory
//!
//! @return 0 is successful, otherwise errno. It sets the global retc in case
//! of error.
//----------------------------------------------------------------------------
int MakeSubTreeMutable(const std::string& arch_dir);
//----------------------------------------------------------------------------
//! Check that the user has the necessary permissions to do an archiving
//! operation.
//!
//! @param arch_dir archive directory
//!
//! @return true if user is allowed, otherwise False
//----------------------------------------------------------------------------
bool ArchiveCheckAcl(const std::string& arch_dir) const;
//----------------------------------------------------------------------------
//! Format listing output. Includes combining the information that we get
//! from the archiver daemon with the list of pending transfers at the MGM.
//!
//! @param cmd_json command to be sent to the archive daemon
//----------------------------------------------------------------------------
void ArchiveFormatListing(const std::string& cmd_json);
//----------------------------------------------------------------------------
//! Create backup file. If successful then the backup file is copied to the
//! backup_dir location. If not it sets the retc and stdErr string accordingly.
//!
//! @param backup_dir directory for which the backup file is created
//! @param dst_url backup destination URL ending with '/'
//! @param twindow_type time window type which can refer either to the
//! mtime or the ctime
//! @param twindow_val time window timestamp
//! @param excl_xattr set of extended attributes which are not enforced and
//! also not checked during the verification step
//!
//! @return 0 if successful, otherwise errno. It sets the global retc in case
//! of error
//----------------------------------------------------------------------------
int BackupCreate(const std::string& backup_dir,
const std::string& dst_url,
const std::string& twindow_type,
const std::string& twindow_val,
const std::set& excl_xattr);
};
EOSMGMNAMESPACE_END