// ----------------------------------------------------------------------
// File: com_fusex.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 "console/ConsoleMain.hh"
#include "common/StringTokenizer.hh"
#include "common/StringConversion.hh"
#include "common/SymKeys.hh"
/*----------------------------------------------------------------------------*/
/* fusex Clients - Interface */
int
com_fusex(char* arg1)
{
eos::common::StringTokenizer subtokenizer(arg1);
subtokenizer.GetLine();
XrdOucString option = "";
XrdOucString options = "";
XrdOucString in = "";
XrdOucString subcmd = subtokenizer.GetToken();
XrdOucString filter;
if (wants_help(arg1)) {
goto com_fusex_usage;
}
in = "mgm.cmd=fusex";
if (subcmd == "ls") {
in += "&mgm.subcmd=ls";
} else if (subcmd == "evict") {
XrdOucString uuid = subtokenizer.GetToken();
XrdOucString reason = subtokenizer.GetToken();
if (!uuid.length()) {
goto com_fusex_usage;
}
in += "&mgm.subcmd=evict";
in += "&mgm.fusex.uuid=";
in += uuid;
if (reason.length()) {
XrdOucString b64;
eos::common::SymKey::Base64(reason, b64);
in += "&mgm.fusex.reason=";
in += b64;
}
} else if (subcmd == "caps") {
option = subtokenizer.GetToken();
filter = subtokenizer.GetToken();
while (option.replace("-", "")) {
};
in += "&mgm.subcmd=caps";
in += "&mgm.option=";
in += option;
while (auto val = subtokenizer.GetToken()) {
filter += " ";
filter += val;
}
if (filter.length()) {
in += "&mgm.filter=";
in += eos::common::StringConversion::curl_escaped(filter.c_str()).c_str();
}
} else if (subcmd == "dropcaps") {
XrdOucString uuid = subtokenizer.GetToken();
if (!uuid.length()) {
goto com_fusex_usage;
}
in += "&mgm.subcmd=dropcaps";
in += "&mgm.fusex.uuid=";
in += uuid;
} else if (subcmd == "droplocks") {
XrdOucString inode = subtokenizer.GetToken();
XrdOucString pid = subtokenizer.GetToken();
if (!inode.length() || !pid.length()) {
goto com_fusex_usage;
}
in += "&mgm.subcmd=droplocks";
in += "&mgm.inode=";
in += inode;
in += "&mgm.fusex.pid=";
in += pid;
} else if (subcmd == "conf") {
XrdOucString interval = subtokenizer.GetToken();
XrdOucString quota_interval = subtokenizer.GetToken();
XrdOucString bc_audience = subtokenizer.GetToken();
XrdOucString bc_audience_match = subtokenizer.GetToken();
int i_interval = interval.length() ? atoi(interval.c_str()) : 0;
int q_interval = quota_interval.length() ? atoi(quota_interval.c_str()) : 0;
if ((i_interval < 0) ||
(i_interval > 60)) {
goto com_fusex_usage;
}
if ((q_interval < 0) ||
(q_interval > 120)) {
goto com_fusex_usage;
}
in += "&mgm.subcmd=conf";
in += "&mgm.fusex.hb=";
in += interval;
if (quota_interval.length()) {
in += "&mgm.fusex.qc=";
in += quota_interval;
}
if (bc_audience.length()) {
in += "&mgm.fusex.bc.max=";
in += bc_audience;
}
if (bc_audience_match.length()) {
in += "&mgm.fusex.bc.match=";
in += bc_audience_match;
}
} else {
goto com_fusex_usage;
}
do {
option = subtokenizer.GetToken();
if (!option.length()) {
break;
}
if (option == "-a") {
options += "a";
} else {
if (option == "-m") {
options += "m";
} else {
if (option == "-s") {
options += "s";
} else {
if (option == "-f") {
options += "f";
} else {
if (option == "-l") {
options += "l";
} else {
if (option == "-k") {
options += "k";
} else {
goto com_fusex_usage;
}
}
}
}
}
}
} while (true);
if (options.length()) {
in += "&mgm.option=";
in += options;
}
global_retc = output_result(client_command(in, true));
return (0);
com_fusex_usage:
fprintf(stdout,
"usage: fusex ls [-l] [-f] [-m] : print statistics about eosxd fuse clients\n");
fprintf(stdout,
" [no option] - break down by client host [default]\n");
fprintf(stdout,
" -l - break down by client host and show statistics \n");
fprintf(stdout,
" -f - show ongoing flush locks\n");
fprintf(stdout,
" -k - show R/W locks\n");
fprintf(stdout,
" -m - show monitoring output format\n");
fprintf(stdout, "\n");
fprintf(stdout,
" fuxex evict [] : evict a fuse client\n");
fprintf(stdout,
" - uuid of the client to evict\n");
fprintf(stdout,
" - optional text shown to the client why he has been evicted or an instruction for an action to the client\n");
fprintf(stdout,
" - if the reason contains the keywoard 'abort' the abort handler will be called on client side (might create a stack trace/core)\n");
fprintf(stdout,
" - if reason contains the keyword 'log2big' the client will effectily not be evicted, but will truncate his logfile to 0\n");
fprintf(stdout,
" - if reason contains the keyword 'setlog' and 'debug','notice', 'error', 'crit', 'info', 'warning' the log level of the targeted mount is changed accordingly .e.g evict \"setlog error\"\n");
fprintf(stdout,
" - if reason contains the keyword 'stacktrace' the client will send a self-stacktrace with the next heartbeat message and it will be stored in /var/log/eos/mgm/eosxd-stacktraces.log e.g. evict stacktrace\n");
fprintf(stdout,
" - if reason contains the keyword 'sendlog' the client will send max. the last 512 lines of each log level and the log will be stored in /var/log/eos/mgm/eosxd-logtraces.log e.g. evict sendlog\n");
fprintf(stdout,
" - if reason contains the keyword 'resetbuffer' the client will reset the read-ahead and write-buffers in flight and possibly unlock a locked mount point");
fprintf(stdout, "\n");
fprintf(stdout,
" fusex evict static|autofs mem:|idle: : evict all autofs or static mounts which have a resident memory footprint larger than or are idle longer than \n");
fprintf(stdout, "\n");
fprintf(stdout,
" fusex dropcaps : advice a client to drop all caps\n");
fprintf(stdout, "\n");
fprintf(stdout,
" fusex droplocks : advice a client to drop for a given (hexadecimal) inode and process id\n");
fprintf(stdout, "\n");
fprintf(stdout,
" fusex caps [-t | -i | -p [] ] : print caps\n");
fprintf(stdout,
" -t - sort by expiration time\n");
fprintf(stdout,
" -i - sort by inode\n");
fprintf(stdout,
" -p - display by path\n");
fprintf(stdout,
" -t|i|p > - display entries matching for the used filter type");
fprintf(stdout, "\n");
fprintf(stdout, "examples:\n");
fprintf(stdout,
" fusex caps -i ^0000abcd$ : show caps for inode 0000abcd\n");
fprintf(stdout,
" fusex caps -p ^/eos/$ : show caps for path /eos\n");
fprintf(stdout,
" fusex caps -p ^/eos/caps/ : show all caps in subtree /eos/caps\n");
fprintf(stdout,
" fusex conf [] [quota-check-in-seconds] [max broadcast audience] [broadcast audience match]\n");
fprintf(stdout, " : show heartbeat and quota interval\n");
fprintf(stdout,
" : [ optional change heartbeat interval from [1-15] seconds ]\n");
fprintf(stdout,
" : [ optional set quota check interval from [1-16] seconds ]\n");
fprintf(stdout, "examples:\n");
fprintf(stdout,
" fusex conf : show heartbeat and quota interval\n");
fprintf(stdout,
" fusex conf 10 : define heartbeat interval as 10 seconds\n");
fprintf(stdout,
" fusex conf 10 30 : define heartbeat as 10 seconds and quota interval as 30 seconds\n");
fprintf(stdout,
" fusex conf 0 0 256 @b[67] : suppress broadcasts when more than 256 clients are conected and the target matches @b[67]\n");
return (0);
}