mirror of
https://github.com/akuker/RASCSI.git
synced 2025-01-10 01:30:45 +00:00
Feature server information (#163)
* 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:
parent
dd7ce23adc
commit
735aff6cd1
src/raspberrypi
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user