1
0
mirror of https://github.com/akuker/RASCSI.git synced 2025-01-10 01:30:45 +00:00

Feature server information ()

* Extended protobuf interface with rascsi server information

* Added default_image_folder (to be used in a different feature)

* Remember log level because not all versions of spdlog support get_log_level()

* Display enum names instead of values

* Added support for default image folder

* Added method that returns the available image files

* Added list of image files to protobuf interface

* Error handling update

* Filter image files

* Update setting up image file list

* Message update

* Replaced if/else cascade by switch

* Updated log level handling

* Renaming, sort rasctl list output

* Added -lstdc++fs (required by gcc 8.3.0)

* Changed option shortcut

* Sorted log levels by severity

* Fixed sorting of log levels

* Use map for storing available log levels

* Replaced explicit typ

* Revert "Replaced explicit typ"

This reverts commit 4106c15d6f391b840d109d4284a5c8854c42af21.

* Revert "Use map for storing available log levels"

This reverts commit 505751e64a34f49055bd54812c03d20056bd3872.

* Added comments

* Removed needless CR/LF when logging

Co-authored-by: akuker <akuker@gmail.com>
This commit is contained in:
Uwe Seimet 2021-08-06 03:56:07 +02:00 committed by GitHub
parent dd7ce23adc
commit 735aff6cd1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 198 additions and 44 deletions

@ -161,10 +161,10 @@ ALL: all
docs: $(DOC_DIR)/rascsi_man_page.txt $(DOC_DIR)/rasctl_man_page.txt $(DOC_DIR)/scsimon_man_page.txt
$(BINDIR)/$(RASCSI): $(SRC_PROTOBUF) $(OBJ_RASCSI) | $(BINDIR)
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCSI) -lpthread -lz -lpcap -lprotobuf
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCSI) -lpthread -lz -lpcap -lprotobuf -lstdc++fs
$(BINDIR)/$(RASCTL): $(SRC_PROTOBUF) $(OBJ_RASCTL) | $(BINDIR)
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCTL) -lprotobuf
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCTL) -lprotobuf -lstdc++fs
$(BINDIR)/$(RASDUMP): $(OBJ_RASDUMP) | $(BINDIR)
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASDUMP)

@ -35,6 +35,8 @@
#include <string>
#include <sstream>
#include <iostream>
#include <list>
#include <filesystem>
using namespace std;
using namespace spdlog;
@ -63,6 +65,9 @@ int monsocket; // Monitor Socket
pthread_t monthread; // Monitor Thread
pthread_mutex_t ctrl_mutex; // Semaphore for the ctrl array
static void *MonThread(void *param);
list<string> available_log_levels;
string current_log_level; // Some versions of spdlog do not support get_log_level()
string default_image_folder = "/home/pi/images";
set<string> files_in_use;
//---------------------------------------------------------------------------
@ -123,16 +128,14 @@ void Banner(int argc, char* argv[])
BOOL InitService(int port)
{
struct sockaddr_in server;
int yes, result;
result = pthread_mutex_init(&ctrl_mutex,NULL);
int result = pthread_mutex_init(&ctrl_mutex,NULL);
if(result != EXIT_SUCCESS){
LOGERROR("Unable to create a mutex. Err code: %d", result);
return FALSE;
}
// Create socket for monitor
struct sockaddr_in server;
monsocket = socket(PF_INET, SOCK_STREAM, 0);
memset(&server, 0, sizeof(server));
server.sin_family = PF_INET;
@ -140,7 +143,7 @@ BOOL InitService(int port)
server.sin_addr.s_addr = htonl(INADDR_ANY);
// allow address reuse
yes = 1;
int yes = 1;
if (setsockopt(
monsocket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0){
return FALSE;
@ -431,7 +434,7 @@ bool ReturnStatus(int fd, bool status = true, const string msg = "") {
return status;
}
void SetLogLevel(const string& log_level) {
bool SetLogLevel(const string& log_level) {
if (log_level == "trace") {
set_level(level::trace);
}
@ -454,9 +457,12 @@ void SetLogLevel(const string& log_level) {
set_level(level::off);
}
else {
LOGWARN("Invalid log level '%s', falling back to 'trace'", log_level.c_str());
set_level(level::trace);
return false;
}
current_log_level = log_level;
return true;
}
void LogDeviceList(const string& device_list)
@ -469,6 +475,24 @@ void LogDeviceList(const string& device_list)
}
}
void GetAvailableLogLevels(PbServerInfo& serverInfo)
{
for (auto it = available_log_levels.begin(); it != available_log_levels.end(); ++it) {
serverInfo.add_available_log_levels(*it);
}
}
void GetAvailableImages(PbServerInfo& serverInfo)
{
if (access(default_image_folder.c_str(), F_OK) != -1) {
for (const auto& entry : filesystem::directory_iterator(default_image_folder)) {
if (entry.is_regular_file()) {
serverInfo.add_available_image_files(entry.path().filename());
}
}
}
}
//---------------------------------------------------------------------------
//
// Command Processing
@ -488,7 +512,7 @@ bool ProcessCmd(int fd, const PbCommand &command)
string params = command.params().c_str();
ostringstream s;
s << "Processing: cmd=" << cmd << ", id=" << id << ", un=" << un << ", type=" << type << ", params=" << params << endl;
s << "Processing: cmd=" << PbOperation_Name(cmd) << ", id=" << id << ", un=" << un << ", type=" << PbDeviceType_Name(type) << ", params=" << params;
LOGINFO("%s", s.str().c_str());
// Copy the Unit List
@ -555,7 +579,7 @@ bool ProcessCmd(int fd, const PbCommand &command)
break;
default:
ostringstream error;
error << "rasctl sent a command for an invalid drive type: " << type;
error << "rasctl sent a command for an invalid drive type: " << PbDeviceType_Name(type);
return ReturnStatus(fd, false, error.str());
}
@ -576,13 +600,18 @@ bool ProcessCmd(int fd, const PbCommand &command)
// Open the file path
if (!pUnit->Open(filepath)) {
delete pUnit;
// If the file does not exist search for it in the default image folder
string default_file = default_image_folder + "/" + file;
filepath.SetPath(default_file.c_str());
if (!pUnit->Open(filepath)) {
delete pUnit;
LOGWARN("rasctl tried to open an invalid file %s", file.c_str());
LOGWARN("rasctl tried to open an invalid file %s", file.c_str());
ostringstream error;
error << "File open error [" << file << "]";
return ReturnStatus(fd, false, error.str());
ostringstream error;
error << "File open error [" << file << "]";
return ReturnStatus(fd, false, error.str());
}
}
}
@ -674,7 +703,7 @@ bool ProcessCmd(int fd, const PbCommand &command)
default:
ostringstream error;
error << "Received unknown command from rasctl: " << cmd;
error << "Received unknown command from rasctl: " << PbOperation_Name(cmd);
LOGWARN("%s", error.str().c_str());
return ReturnStatus(fd, false, error.str());
}
@ -699,7 +728,7 @@ bool ParseArgument(int argc, char* argv[], int& port)
string log_level = "trace";
int opt;
while ((opt = getopt(argc, argv, "-IiHhG:g:D:d:p:")) != -1) {
while ((opt = getopt(argc, argv, "-IiHhG:g:D:d:p:f:")) != -1) {
switch (tolower(opt)) {
case 'i':
is_sasi = false;
@ -735,6 +764,17 @@ bool ParseArgument(int argc, char* argv[], int& port)
}
continue;
case 'f':
struct stat folder_stat;
stat(optarg, &folder_stat);
if (!S_ISDIR(folder_stat.st_mode) || access(optarg, F_OK) == -1) {
cerr << "Default image folder '" << optarg << "' is not accessible" << endl;
return false;
}
default_image_folder = optarg;
continue;
default:
return false;
@ -787,7 +827,9 @@ bool ParseArgument(int argc, char* argv[], int& port)
id = -1;
}
SetLogLevel(log_level);
if (!SetLogLevel(log_level)) {
LOGWARN("Invalid log level '%s'", log_level.c_str());
}
// Display and log the device list
const PbDevices devices = GetDevices();
@ -859,22 +901,47 @@ static void *MonThread(void *param)
PbCommand command;
DeserializeMessage(fd, command);
// List and log all of the devices
if (command.cmd() == LIST) {
const PbDevices devices = GetDevices();
SerializeMessage(fd, devices);
LogDeviceList(ListDevices(devices));
}
else if (command.cmd() == LOG_LEVEL) {
SetLogLevel(command.params());
}
else {
// Wait until we become idle
while (active) {
usleep(500 * 1000);
switch(command.cmd()) {
case LIST: {
const PbDevices devices = GetDevices();
SerializeMessage(fd, devices);
LogDeviceList(ListDevices(devices));
break;
}
ProcessCmd(fd, command);
case LOG_LEVEL: {
bool status = SetLogLevel(command.params());
if (!status) {
ostringstream error;
error << "Invalid log level: " << command.params();
ReturnStatus(fd, false, error.str());
}
else {
ReturnStatus(fd);
}
break;
}
case SERVER_INFO: {
PbServerInfo serverInfo;
serverInfo.set_rascsi_version(rascsi_get_version_string());
GetAvailableLogLevels(serverInfo);
serverInfo.set_current_log_level(current_log_level);
serverInfo.set_default_image_folder(default_image_folder);
GetAvailableImages(serverInfo);
SerializeMessage(fd, serverInfo);
break;
}
default: {
// Wait until we become idle
while (active) {
usleep(500 * 1000);
}
ProcessCmd(fd, command);
break;
}
}
close(fd);
@ -912,7 +979,15 @@ int main(int argc, char* argv[])
setvbuf(stdout, NULL, _IONBF, 0);
struct sched_param schparam;
set_level(level::trace);
available_log_levels.push_back("trace");
available_log_levels.push_back("debug");
available_log_levels.push_back("info");
available_log_levels.push_back("warn");
available_log_levels.push_back("err");
available_log_levels.push_back("critical");
available_log_levels.push_back("off");
SetLogLevel("trace");
// Create a thread-safe stdout logger to process the log messages
auto logger = stdout_color_mt("rascsi stdout logger");

@ -17,13 +17,14 @@ enum PbDeviceType {
// rascsi remote operations
enum PbOperation {
NONE = 0;
LIST = 1;
ATTACH = 2;
DETACH = 3;
INSERT = 4;
EJECT = 5;
PROTECT = 6;
LOG_LEVEL = 7;
SERVER_INFO = 1;
LIST = 2;
ATTACH = 3;
DETACH = 4;
INSERT = 5;
EJECT = 6;
PROTECT = 7;
LOG_LEVEL = 8;
}
// Commands rascsi can execute
@ -52,4 +53,15 @@ message PbDevice {
message PbDevices {
repeated PbDevice devices = 1;
}
// The rascsi server information
message PbServerInfo {
string rascsi_version = 1;
// Sorted by severity
repeated string available_log_levels = 2;
string current_log_level = 3;
string default_image_folder = 4;
// Files in the default folder
repeated string available_image_files = 5;
}

@ -18,6 +18,7 @@
#include "rascsi_interface.pb.h"
#include <sstream>
#include <iostream>
#include <list>
using namespace std;
using namespace rascsi_interface;
@ -152,6 +153,63 @@ void CommandLogLevel(const string& hostname, int port, const string& log_level)
close(fd);
}
void CommandServerInfo(const string& hostname, int port)
{
PbCommand command;
command.set_cmd(SERVER_INFO);
int fd = SendCommand(hostname.c_str(), port, command);
if (fd < 0) {
exit(ENOTCONN);
}
PbServerInfo serverInfo;
try {
DeserializeMessage(fd, serverInfo);
}
catch(const ioexception& e) {
cerr << "Error: " << e.getmsg() << endl;
close(fd);
exit(-1);
}
close(fd);
cout << "rascsi version: " << serverInfo.rascsi_version() << endl;
if (!serverInfo.available_log_levels_size()) {
cout << " No log level settings available" << endl;
}
else {
cout << "Available log levels, sorted by severity:" << endl;
for (int i = 0; i < serverInfo.available_log_levels_size(); i++) {
cout << " " << serverInfo.available_log_levels(i) << endl;
}
cout << "Current log level: " << serverInfo.current_log_level() << endl;
}
cout << "Default image file folder: " << serverInfo.default_image_folder() << endl;
if (!serverInfo.available_image_files_size()) {
cout << " No image files available in the default folder" << endl;
}
else {
list<string> sorted_image_files;
for (int i = 0; i < serverInfo.available_image_files_size(); i++) {
sorted_image_files.push_back(serverInfo.available_image_files(i));
}
sorted_image_files.sort();
cout << "Image files available in the default folder:" << endl;
for (auto it = sorted_image_files.begin(); it != sorted_image_files.end(); ++it) {
cout << " " << *it << endl;
}
}
}
//---------------------------------------------------------------------------
//
// Main processing
@ -165,7 +223,7 @@ int main(int argc, char* argv[])
if (argc < 2) {
cerr << "SCSI Target Emulator RaSCSI Controller" << endl;
cerr << "version " << rascsi_get_version_string() << " (" << __DATE__ << ", " << __TIME__ << ")" << endl;
cerr << "Usage: " << argv[0] << " -i ID [-u UNIT] [-c CMD] [-t TYPE] [-f FILE] [-h HOSTNAME] [-p PORT] [-g LOG_LEVEL]" << endl;
cerr << "Usage: " << argv[0] << " -i ID [-u UNIT] [-c CMD] [-t TYPE] [-f FILE] [-h HOSTNAME] [-p PORT] [-g LOG_LEVEL] [-s]" << endl;
cerr << " where ID := {0|1|2|3|4|5|6|7}" << endl;
cerr << " UNIT := {0|1} default setting is 0." << endl;
cerr << " CMD := {attach|detach|insert|eject|protect}" << endl;
@ -191,7 +249,7 @@ int main(int argc, char* argv[])
int port = 6868;
string params;
opterr = 0;
while ((opt = getopt(argc, argv, "i:u:c:t:f:h:p:g:l")) != -1) {
while ((opt = getopt(argc, argv, "i:u:c:t:f:h:p:g:ls")) != -1) {
switch (opt) {
case 'i':
id = optarg[0] - '0';
@ -281,6 +339,10 @@ int main(int argc, char* argv[])
cmd = LOG_LEVEL;
params = optarg;
break;
case 's':
cmd = SERVER_INFO;
break;
}
}
@ -291,6 +353,11 @@ int main(int argc, char* argv[])
exit(0);
}
if (cmd == SERVER_INFO) {
CommandServerInfo(hostname, port);
exit(0);
}
// List display only
if (cmd == LIST || (id < 0 && type == UNDEFINED && params.empty())) {
CommandList(hostname, port);