//------------------------------------------------------------------------------
//! @file RecycleHelper.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 "console/commands/helpers/RecycleHelper.hh"
#include "common/StringTokenizer.hh"
#include "common/StringConversion.hh"
//------------------------------------------------------------------------------
// Check if given date format respects the specifications
//------------------------------------------------------------------------------
bool
RecycleHelper::CheckDateFormat(const std::string& sdate) const
{
using eos::common::StringConversion;
if (sdate.find('/') != std::string::npos) {
std::vector tokens;
StringConversion::Tokenize(sdate, tokens, "/");
if (tokens.size() > 4) {
return false;
}
// All tokens must be numeric
for (const auto& token : tokens) {
try {
(void) std::stoi(token);
} catch (...) {
return false;
}
}
} else {
try {
(void) std::stoi(sdate);
} catch (...) {
return false;
}
}
return true;
}
//------------------------------------------------------------------------------
// Parse command line input
//------------------------------------------------------------------------------
bool
RecycleHelper::ParseCommand(const char* arg)
{
const char* option {nullptr};
std::string soption;
eos::console::RecycleProto* recycle = mReq.mutable_recycle();
eos::common::StringTokenizer tokenizer(arg);
tokenizer.GetLine();
option = tokenizer.GetToken();
std::string cmd = (option ? option : "");
if ((cmd == "ls") || cmd.empty() || (cmd == "-m")) {
eos::console::RecycleProto_LsProto* ls = recycle->mutable_ls();
if (cmd.empty()) {
ls->set_all(true);
} else if (cmd == "-m") {
ls->set_monitorfmt(true);
} else {
ls->set_fulldetails(true);
while ((option = tokenizer.GetToken())) {
soption = option;
if (soption == "-g") {
ls->set_all(true);
} else if (soption == "-m") {
ls->set_monitorfmt(true);
} else if (soption == "-n") {
ls->set_numericids(true);
} else {
// This must be a date format
if (!CheckDateFormat(soption)) {
std::cerr << "error: \"" << soption << "\" does not respect the "
<< "date format" << std::endl;
return false;
}
ls->set_date(soption);
}
}
if (ls->all() && (!ls->date().empty())) {
std::cerr << "error: -g and can not be used together"
<< std::endl;
return false;
}
}
} else if (cmd == "purge") {
eos::console::RecycleProto_PurgeProto* purge = recycle->mutable_purge();
while ((option = tokenizer.GetToken())) {
soption = option;
if (soption == "-g") {
purge->set_all(true);
} else if (soption == "-k") {
option = tokenizer.GetToken();
if (option) {
purge->set_key(option);
} else {
std::cerr << "error: you have to provide a key when using the -k option" <<
std::endl;
return false;
}
} else {
if (!CheckDateFormat(soption)) {
std::cerr << "error: \"" << soption << "\" does not respect the "
<< "date format" << std::endl;
return false;
}
purge->set_date(soption);
}
}
if (purge->all() && (!purge->date().empty())) {
std::cerr << "error: -g and can not be used together"
<< std::endl;
return false;
}
} else if (cmd == "restore") {
eos::console::RecycleProto_RestoreProto* restore = recycle->mutable_restore();
while ((option = tokenizer.GetToken())) {
soption = option;
if ((soption == "-f") || (soption == "--force-original-name")) {
restore->set_forceorigname(true);
} else if ((soption == "-r") || (soption == "--restore-versions")) {
restore->set_restoreversions(true);
} else if (soption == "-p") {
restore->set_makepath(true);
} else {
// This must be the recycle-key
restore->set_key(soption);
break;
}
}
if (restore->key().empty()) {
return false;
}
} else if (cmd == "config") {
eos::console::RecycleProto_ConfigProto* config = recycle->mutable_config();
if (!(option = tokenizer.GetToken())) {
return false;
}
soption = option;
if ((soption == "--add-bin") || (soption == "--remove-bin")) {
if (soption == "--add-bin") {
config->set_op(eos::console::RecycleProto_ConfigProto::ADD_BIN);
} else {
config->set_op(eos::console::RecycleProto_ConfigProto::RM_BIN);
}
if (!(option = tokenizer.GetToken())) {
return false;
}
config->set_subtree(option);
} else if (soption == "--lifetime") {
config->set_op(eos::console::RecycleProto_ConfigProto::LIFETIME);
if (!(option = tokenizer.GetToken())) {
return false;
}
soption = option;
int lifetime = 0;
try {
lifetime = std::stoi(soption);
} catch (...) {
return false;
}
config->set_lifetimesec(lifetime);
} else if (soption == "--ratio") {
config->set_op(eos::console::RecycleProto_ConfigProto::RATIO);
if (!(option = tokenizer.GetToken())) {
return false;
}
soption = option;
float ratio = 0.0;
try {
ratio = std::stof(soption);
} catch (...) {
return false;
}
config->set_ratio(ratio);
} else if (soption == "--size") {
config->set_op(eos::console::RecycleProto::ConfigProto::SIZE);
if (!(option = tokenizer.GetToken())) {
return false;
}
soption = option;
std::set units {'K', 'M', 'G'};
uint64_t size = eos::common::StringConversion::GetSizeFromString(soption);
if (errno) {
std::cerr << "error: specified size could not be converted" << std::endl;
return false;
}
config->set_size(size);
} else if (soption == "--inodes") {
config->set_op(eos::console::RecycleProto::ConfigProto::INODES);
if (!(option = tokenizer.GetToken())) {
return false;
}
soption = option;
std::set units {'K', 'M', 'G'};
uint64_t size = eos::common::StringConversion::GetSizeFromString(soption);
if (errno) {
std::cerr << "error: specified number of inodes could not be converted"
<< std::endl;
return false;
}
config->set_size(size);
} else {
return false;
}
} else {
return false;
}
return true;
}