mirror of
https://github.com/akuker/RASCSI.git
synced 2025-02-16 19:31:09 +00:00
Moved rascsi/rasctl specific classes to sub-folders, cleaned up code, fixed SonarCloud issues (#889)
* Moved rasctl/rascsi core code to folders * Improved granularity in order to add more unit tests * Pointer handling update * Updated ID and controller handling * Updated memory management * Added unit tests * Fixed SonarCloud issues
This commit is contained in:
parent
52259c374f
commit
a30438279e
@ -90,20 +90,15 @@ SRC_RASCSI_CORE = \
|
||||
filepath.cpp \
|
||||
fileio.cpp \
|
||||
rascsi_version.cpp \
|
||||
rascsi_image.cpp \
|
||||
rascsi_response.cpp \
|
||||
rascsi_executor.cpp \
|
||||
rasutil.cpp \
|
||||
command_util.cpp \
|
||||
protobuf_serializer.cpp \
|
||||
localizer.cpp
|
||||
protobuf_serializer.cpp
|
||||
SRC_RASCSI_CORE += $(shell find ./rascsi -name '*.cpp')
|
||||
SRC_RASCSI_CORE += $(shell find ./controllers -name '*.cpp')
|
||||
SRC_RASCSI_CORE += $(shell find ./devices -name '*.cpp')
|
||||
SRC_RASCSI_CORE += $(shell find ./hal -name '*.cpp')
|
||||
SRC_RASCSI_CORE += $(SRC_PROTOBUF)
|
||||
|
||||
SRC_RASCSI = rascsi.cpp \
|
||||
rascsi_service.cpp
|
||||
SRC_RASCSI = rascsi.cpp
|
||||
|
||||
SRC_SCSIMON = \
|
||||
scsimon.cpp \
|
||||
@ -114,14 +109,11 @@ SRC_SCSIMON += $(shell find ./hal -name '*.cpp')
|
||||
|
||||
SRC_RASCTL = \
|
||||
rasctl.cpp\
|
||||
rasctl_commands.cpp \
|
||||
rasctl_display.cpp \
|
||||
rascsi_version.cpp \
|
||||
rasutil.cpp \
|
||||
command_util.cpp \
|
||||
protobuf_serializer.cpp \
|
||||
localizer.cpp
|
||||
SRC_RASCTL += $(SRC_PROTOBUF)
|
||||
protobuf_serializer.cpp
|
||||
SRC_RASCTL += $(shell find ./rasctl -name '*.cpp')
|
||||
|
||||
SRC_RASDUMP = \
|
||||
rasdump.cpp \
|
||||
@ -134,8 +126,8 @@ SRC_RASDUMP += $(shell find ./hal -name '*.cpp')
|
||||
SRC_RASCSI_TEST = $(shell find ./test -name '*.cpp')
|
||||
|
||||
|
||||
vpath %.h ./ ./controllers ./devices ./monitor ./hal
|
||||
vpath %.cpp ./ ./controllers ./devices ./monitor ./test ./hal
|
||||
vpath %.h ./ ./controllers ./devices ./monitor ./hal ./rascsi ./rasctl
|
||||
vpath %.cpp ./ ./controllers ./devices ./monitor ./test ./hal ./rascsi ./rasctl
|
||||
vpath %.o ./$(OBJDIR)
|
||||
vpath ./$(BINDIR)
|
||||
|
||||
@ -146,6 +138,7 @@ OBJ_RASCTL := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASCTL:%.cpp=%.o)))
|
||||
OBJ_RASDUMP := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASDUMP:%.cpp=%.o)))
|
||||
OBJ_SCSIMON := $(addprefix $(OBJDIR)/,$(notdir $(SRC_SCSIMON:%.cpp=%.o)))
|
||||
OBJ_RASCSI_TEST := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASCSI_TEST:%.cpp=%.o)))
|
||||
OBJ_PROTOBUF := $(addprefix $(OBJDIR)/,$(notdir $(SRC_PROTOBUF:%.cpp=%.o)))
|
||||
|
||||
GEN_PROTOBUF := $(SRC_PROTOBUF) rascsi_interface.pb.h
|
||||
|
||||
@ -193,11 +186,13 @@ lcov: test
|
||||
|
||||
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_CORE) $(OBJ_RASCSI) | $(BINDIR)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCSI_CORE) $(OBJ_RASCSI) -lpthread -lpcap -lprotobuf -lstdc++fs
|
||||
$(SRC_RASCSI_CORE): $(SRC_PROTOBUF)
|
||||
|
||||
$(BINDIR)/$(RASCTL): $(SRC_PROTOBUF) $(OBJ_RASCTL) | $(BINDIR)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCTL) -lpthread -lprotobuf
|
||||
$(BINDIR)/$(RASCSI): $(SRC_PROTOBUF) $(OBJ_RASCSI_CORE) $(OBJ_RASCSI) $(OBJ_PROTOBUF) | $(BINDIR)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCSI_CORE) $(OBJ_RASCSI) $(OBJ_PROTOBUF) -lpthread -lpcap -lprotobuf -lstdc++fs
|
||||
|
||||
$(BINDIR)/$(RASCTL): $(SRC_PROTOBUF) $(OBJ_RASCTL) $(OBJ_PROTOBUF) | $(BINDIR)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCTL) $(OBJ_PROTOBUF) -lpthread -lprotobuf
|
||||
|
||||
$(BINDIR)/$(RASDUMP): $(OBJ_RASDUMP) | $(BINDIR)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASDUMP)
|
||||
@ -205,8 +200,8 @@ $(BINDIR)/$(RASDUMP): $(OBJ_RASDUMP) | $(BINDIR)
|
||||
$(BINDIR)/$(SCSIMON): $(OBJ_SCSIMON) | $(BINDIR)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_SCSIMON) -lpthread
|
||||
|
||||
$(BINDIR)/$(RASCSI_TEST): $(SRC_PROTOBUF) $(OBJ_RASCSI_CORE) $(OBJ_RASCSI_TEST) | $(BINDIR)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCSI_CORE) $(OBJ_RASCSI_TEST) -lpthread -lpcap -lprotobuf -lstdc++fs -lgmock -lgtest
|
||||
$(BINDIR)/$(RASCSI_TEST): $(SRC_PROTOBUF) $(OBJ_RASCSI_CORE) $(OBJ_RASCSI_TEST) $(OBJ_PROTOBUF) | $(BINDIR)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCSI_CORE) $(OBJ_RASCSI_TEST) $(OBJ_PROTOBUF) -lpthread -lpcap -lprotobuf -lstdc++fs -lgmock -lgtest
|
||||
|
||||
|
||||
# Phony rules for building individual utilities
|
||||
|
@ -1,29 +0,0 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2021-2022 Uwe Seimet
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
class ProtobufSerializer;
|
||||
class Localizer;
|
||||
|
||||
class CommandContext
|
||||
{
|
||||
public:
|
||||
|
||||
CommandContext(const ProtobufSerializer& c, const Localizer& l, int f, const std::string& s)
|
||||
: serializer(c), localizer(l), fd(f), locale(s) {}
|
||||
~CommandContext() = default;
|
||||
|
||||
const ProtobufSerializer& serializer;
|
||||
const Localizer& localizer;
|
||||
int fd;
|
||||
std::string locale;
|
||||
};
|
@ -9,7 +9,6 @@
|
||||
|
||||
#include "log.h"
|
||||
#include "rascsi_interface.pb.h"
|
||||
#include "localizer.h"
|
||||
#include "protobuf_serializer.h"
|
||||
#include "command_util.h"
|
||||
#include <sstream>
|
||||
@ -86,51 +85,3 @@ void command_util::AddParam(PbDeviceDefinition& device, const string& key, strin
|
||||
map[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
bool command_util::ReturnLocalizedError(const CommandContext& context, LocalizationKey key,
|
||||
const string& arg1, const string& arg2, const string& arg3)
|
||||
{
|
||||
return ReturnLocalizedError(context, key, NO_ERROR_CODE, arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
bool command_util::ReturnLocalizedError(const CommandContext& context, LocalizationKey key,
|
||||
PbErrorCode error_code, const string& arg1, const string& arg2, const string& arg3)
|
||||
{
|
||||
// For the logfile always use English
|
||||
LOGERROR("%s", context.localizer.Localize(key, "en", arg1, arg2, arg3).c_str())
|
||||
|
||||
return ReturnStatus(context, false, context.localizer.Localize(key, context.locale, arg1, arg2, arg3), error_code,
|
||||
false);
|
||||
}
|
||||
|
||||
bool command_util::ReturnStatus(const CommandContext& context, bool status, const string& msg,
|
||||
PbErrorCode error_code, bool log)
|
||||
{
|
||||
// Do not log twice if logging has already been done in the localized error handling above
|
||||
if (log && !status && !msg.empty()) {
|
||||
LOGERROR("%s", msg.c_str())
|
||||
}
|
||||
|
||||
if (context.fd == -1) {
|
||||
if (!msg.empty()) {
|
||||
if (status) {
|
||||
FPRT(stderr, "Error: ");
|
||||
FPRT(stderr, "%s", msg.c_str());
|
||||
FPRT(stderr, "\n");
|
||||
}
|
||||
else {
|
||||
FPRT(stdout, "%s", msg.c_str());
|
||||
FPRT(stderr, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
PbResult result;
|
||||
result.set_status(status);
|
||||
result.set_error_code(error_code);
|
||||
result.set_msg(msg);
|
||||
context.serializer.SerializeMessage(context.fd, result);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
@ -13,10 +13,9 @@
|
||||
|
||||
#include "google/protobuf/message.h"
|
||||
#include "rascsi_interface.pb.h"
|
||||
#include "command_context.h"
|
||||
#include "localizer.h"
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
using namespace rascsi_interface;
|
||||
|
||||
namespace command_util
|
||||
@ -27,10 +26,4 @@ namespace command_util
|
||||
void AddParam(PbCommand&, const string&, string_view);
|
||||
void AddParam(PbDevice&, const string&, string_view);
|
||||
void AddParam(PbDeviceDefinition&, const string&, string_view);
|
||||
bool ReturnLocalizedError(const CommandContext&, LocalizationKey, const string& = "", const string& = "",
|
||||
const string& = "");
|
||||
bool ReturnLocalizedError(const CommandContext&, LocalizationKey, PbErrorCode, const string& = "",
|
||||
const string& = "", const string& = "");
|
||||
bool ReturnStatus(const CommandContext&, bool = true, const string& = "",
|
||||
PbErrorCode = PbErrorCode::NO_ERROR_CODE, bool = true);
|
||||
}
|
||||
|
@ -245,7 +245,7 @@ bool CTapDriver::Init(const unordered_map<string, string>& const_params)
|
||||
}
|
||||
else {
|
||||
string address = inet;
|
||||
string netmask = "255.255.255.0";
|
||||
string netmask = "255.255.255.0"; //NOSONAR This hardcoded IP address is safe
|
||||
if (size_t separatorPos = inet.find('/'); separatorPos != string::npos) {
|
||||
address = inet.substr(0, separatorPos);
|
||||
|
||||
@ -447,12 +447,12 @@ bool CTapDriver::PendingPackets() const
|
||||
}
|
||||
|
||||
// See https://stackoverflow.com/questions/21001659/crc32-algorithm-implementation-in-c-without-a-look-up-table-and-with-a-public-li
|
||||
uint32_t crc32(const BYTE *buf, int length) {
|
||||
uint32_t CTapDriver::Crc32(const BYTE *buf, int length) {
|
||||
uint32_t crc = 0xffffffff;
|
||||
for (int i = 0; i < length; i++) {
|
||||
crc ^= buf[i];
|
||||
for (int j = 0; j < 8; j++) {
|
||||
uint32_t mask = -(crc & 1);
|
||||
uint32_t mask = -((int)crc & 1);
|
||||
crc = (crc >> 1) ^ (0xEDB88320 & mask);
|
||||
}
|
||||
}
|
||||
@ -480,7 +480,7 @@ int CTapDriver::Receive(BYTE *buf)
|
||||
// We need to add the Frame Check Status (FCS) CRC back onto the end of the packet.
|
||||
// The Linux network subsystem removes it, since most software apps shouldn't ever
|
||||
// need it.
|
||||
int crc = crc32(buf, dwReceived);
|
||||
int crc = Crc32(buf, dwReceived);
|
||||
|
||||
buf[dwReceived + 0] = (BYTE)((crc >> 0) & 0xFF);
|
||||
buf[dwReceived + 1] = (BYTE)((crc >> 8) & 0xFF);
|
||||
|
@ -46,6 +46,8 @@ public:
|
||||
bool Disable() const; // Disable the ras0 interface
|
||||
void Flush(); // Purge all of the packets that are waiting to be processed
|
||||
|
||||
static uint32_t Crc32(const BYTE *, int);
|
||||
|
||||
private:
|
||||
array<byte, 6> m_MacAddr; // MAC Address
|
||||
|
||||
|
@ -41,9 +41,9 @@ DeviceFactory::DeviceFactory()
|
||||
}
|
||||
|
||||
default_params[SCBR]["interface"] = network_interfaces;
|
||||
default_params[SCBR]["inet"] = "10.10.20.1/24";
|
||||
default_params[SCBR]["inet"] = DEFAULT_IP;
|
||||
default_params[SCDP]["interface"] = network_interfaces;
|
||||
default_params[SCDP]["inet"] = "10.10.20.1/24";
|
||||
default_params[SCDP]["inet"] = DEFAULT_IP;
|
||||
default_params[SCLP]["cmd"] = "lp -oraw %f";
|
||||
default_params[SCLP]["timeout"] = "30";
|
||||
|
||||
|
@ -11,11 +11,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include "rascsi_interface.pb.h"
|
||||
|
||||
using namespace std;
|
||||
@ -26,6 +25,8 @@ class PrimaryDevice;
|
||||
|
||||
class DeviceFactory
|
||||
{
|
||||
const string DEFAULT_IP = "10.10.20.1/24"; //NOSONAR This hardcoded IP address is safe
|
||||
|
||||
public:
|
||||
|
||||
DeviceFactory();
|
||||
@ -41,14 +42,14 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
string GetExtension(const string&) const;
|
||||
|
||||
unordered_map<PbDeviceType, unordered_set<uint32_t>> sector_sizes;
|
||||
|
||||
unordered_map<PbDeviceType, unordered_map<string, string>> default_params;
|
||||
|
||||
unordered_map<string, PbDeviceType> extension_mapping;
|
||||
|
||||
string GetExtension(const string&) const;
|
||||
|
||||
unordered_set<uint32_t> empty_set;
|
||||
unordered_map<string, string> empty_map;
|
||||
};
|
||||
|
@ -23,10 +23,8 @@
|
||||
using namespace scsi_command_util;
|
||||
|
||||
SCSIHD::SCSIHD(int lun, const unordered_set<uint32_t>& sector_sizes, bool removable, scsi_defs::scsi_level level)
|
||||
: Disk(removable ? "SCRM" : "SCHD", lun)
|
||||
: Disk(removable ? "SCRM" : "SCHD", lun), scsi_level(level)
|
||||
{
|
||||
scsi_level = level;
|
||||
|
||||
SetSectorSizes(sector_sizes);
|
||||
}
|
||||
|
||||
|
@ -14,11 +14,6 @@
|
||||
#include "fileio.h"
|
||||
#include <libgen.h>
|
||||
|
||||
Filepath::Filepath()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
Filepath& Filepath::operator=(const Filepath& path)
|
||||
{
|
||||
// Set path (split internally)
|
||||
@ -27,15 +22,6 @@ Filepath& Filepath::operator=(const Filepath& path)
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Filepath::Clear()
|
||||
{
|
||||
// Clear the path and each part
|
||||
m_szPath[0] = '\0';
|
||||
m_szDir[0] = '\0';
|
||||
m_szFile[0] = '\0';
|
||||
m_szExt[0] = '\0';
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// File settings (user) for MBCS
|
||||
|
@ -14,8 +14,6 @@
|
||||
|
||||
using TCHAR = char;
|
||||
|
||||
class Fileio;
|
||||
|
||||
static const int _MAX_EXT = 256;
|
||||
static const int _MAX_DIR = 256;
|
||||
static const int _MAX_PATH = 260;
|
||||
@ -30,15 +28,13 @@ static const int FILEPATH_MAX = _MAX_PATH;
|
||||
//===========================================================================
|
||||
class Filepath
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
Filepath();
|
||||
virtual ~Filepath() = default;
|
||||
Filepath() = default;
|
||||
~Filepath() = default;
|
||||
Filepath(Filepath&) = default;
|
||||
Filepath& operator=(const Filepath&);
|
||||
|
||||
void Clear();
|
||||
void SetPath(const char *); // File settings (user) for MBCS
|
||||
const char *GetPath() const { return m_szPath; } // Get path name
|
||||
const char *GetFileExt() const; // Get short name (LPCTSTR)
|
||||
@ -46,10 +42,10 @@ public:
|
||||
private:
|
||||
|
||||
void Split(); // Split the path
|
||||
TCHAR m_szPath[_MAX_PATH]; // File path
|
||||
TCHAR m_szDir[_MAX_DIR]; // Directory
|
||||
TCHAR m_szFile[_MAX_FNAME]; // File
|
||||
TCHAR m_szExt[_MAX_EXT]; // Extension
|
||||
TCHAR m_szPath[_MAX_PATH] = {}; // File path
|
||||
TCHAR m_szDir[_MAX_DIR] = {}; // Directory
|
||||
TCHAR m_szFile[_MAX_FNAME] = {}; // File
|
||||
TCHAR m_szExt[_MAX_EXT] = {}; // Extension
|
||||
|
||||
static TCHAR FileExt[_MAX_FNAME + _MAX_DIR]; // Short name (TCHAR)
|
||||
};
|
||||
|
@ -8,8 +8,8 @@
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "rascsi_interface.pb.h"
|
||||
#include "rascsi_exceptions.h"
|
||||
#include "protobuf_serializer.h"
|
||||
#include "rascsi_exceptions.h"
|
||||
#include <unistd.h>
|
||||
#include <sstream>
|
||||
|
||||
|
@ -14,6 +14,8 @@
|
||||
#include "google/protobuf/message.h"
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class ProtobufSerializer
|
||||
{
|
||||
public:
|
||||
|
@ -11,11 +11,10 @@
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "config.h"
|
||||
#include "log.h"
|
||||
#include "controllers/controller_manager.h"
|
||||
#include "controllers/scsi_controller.h"
|
||||
#include "devices/device_factory.h"
|
||||
#include "devices/device.h"
|
||||
#include "devices/disk.h"
|
||||
#include "devices/file_support.h"
|
||||
#include "hal/gpiobus.h"
|
||||
#include "hal/systimer.h"
|
||||
@ -23,11 +22,11 @@
|
||||
#include "protobuf_serializer.h"
|
||||
#include "command_util.h"
|
||||
#include "rascsi_version.h"
|
||||
#include "rascsi_executor.h"
|
||||
#include "rascsi_response.h"
|
||||
#include "rascsi_image.h"
|
||||
#include "rascsi_interface.pb.h"
|
||||
#include "rascsi_service.h"
|
||||
#include "rascsi/rascsi_executor.h"
|
||||
#include "rascsi/rascsi_response.h"
|
||||
#include "rascsi/rascsi_image.h"
|
||||
#include "rascsi/rascsi_service.h"
|
||||
#include "rasutil.h"
|
||||
#include "spdlog/spdlog.h"
|
||||
#include "spdlog/sinks/stdout_color_sinks.h"
|
||||
@ -51,7 +50,6 @@ using namespace command_util;
|
||||
// Constant declarations
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
#define FPRT(fp, ...) fprintf(fp, __VA_ARGS__ )
|
||||
static const int DEFAULT_PORT = 6868;
|
||||
static const char COMPONENT_SEPARATOR = ':';
|
||||
|
||||
@ -74,32 +72,28 @@ const ProtobufSerializer serializer;
|
||||
|
||||
void Banner(int argc, char* argv[])
|
||||
{
|
||||
FPRT(stdout,"SCSI Target Emulator RaSCSI Reloaded ");
|
||||
FPRT(stdout,"version %s (%s, %s)\n",
|
||||
rascsi_get_version_string().c_str(),
|
||||
__DATE__,
|
||||
__TIME__);
|
||||
FPRT(stdout,"Powered by XM6 TypeG Technology / ");
|
||||
FPRT(stdout,"Copyright (C) 2016-2020 GIMONS\n");
|
||||
FPRT(stdout,"Copyright (C) 2020-2022 Contributors to the RaSCSI Reloaded project\n");
|
||||
FPRT(stdout,"Connect type: %s\n", CONNECT_DESC.c_str());
|
||||
cout << "SCSI Target Emulator RaSCSI Reloaded version " << rascsi_get_version_string()
|
||||
<< " (" << __DATE__ << ' ' << __TIME__ << ')' << endl;
|
||||
cout << "Powered by XM6 TypeG Technology / ";
|
||||
cout << "Copyright (C) 2016-2020 GIMONS" << endl;
|
||||
cout << "Copyright (C) 2020-2022 Contributors to the RaSCSI Reloaded project" << endl;
|
||||
cout << "Connect type: " << CONNECT_DESC << endl;
|
||||
|
||||
if ((argc > 1 && strcmp(argv[1], "-h") == 0) ||
|
||||
(argc > 1 && strcmp(argv[1], "--help") == 0)){
|
||||
FPRT(stdout,"\n");
|
||||
FPRT(stdout,"Usage: %s [-idn[:m] FILE] ...\n\n", argv[0]);
|
||||
FPRT(stdout," n is SCSI device ID (0-7).\n");
|
||||
FPRT(stdout," m is the optional logical unit (LUN) (0-31).\n");
|
||||
FPRT(stdout," FILE is a disk image file, \"daynaport\", \"bridge\", \"printer\" or \"services\".\n\n");
|
||||
FPRT(stdout," Image type is detected based on file extension if no explicit type is specified.\n");
|
||||
FPRT(stdout," hd1 : SCSI-1 HD image (Non-removable generic SCSI-1 HD image)\n");
|
||||
FPRT(stdout," hds : SCSI HD image (Non-removable generic SCSI HD image)\n");
|
||||
FPRT(stdout," hdr : SCSI HD image (Removable generic HD image)\n");
|
||||
FPRT(stdout," hdn : SCSI HD image (NEC GENUINE)\n");
|
||||
FPRT(stdout," hdi : SCSI HD image (Anex86 HD image)\n");
|
||||
FPRT(stdout," nhd : SCSI HD image (T98Next HD image)\n");
|
||||
FPRT(stdout," mos : SCSI MO image (MO image)\n");
|
||||
FPRT(stdout," iso : SCSI CD image (ISO 9660 image)\n");
|
||||
if ((argc > 1 && strcmp(argv[1], "-h") == 0) || (argc > 1 && strcmp(argv[1], "--help") == 0)){
|
||||
cout << endl;
|
||||
cout << "Usage: " << argv[0] << " [-idn[:m] FILE] ..." << endl << endl;
|
||||
cout << " n is SCSI device ID (0-7)." << endl;
|
||||
cout << " m is the optional logical unit (LUN) (0-31)." << endl;
|
||||
cout << " FILE is a disk image file, \"daynaport\", \"bridge\", \"printer\" or \"services\"." << endl << endl;
|
||||
cout << " Image type is detected based on file extension if no explicit type is specified." << endl;
|
||||
cout << " hd1 : SCSI-1 HD image (Non-removable generic SCSI-1 HD image)" << endl;
|
||||
cout << " hds : SCSI HD image (Non-removable generic SCSI HD image)" << endl;
|
||||
cout << " hdr : SCSI HD image (Removable generic HD image)" << endl;
|
||||
cout << " hdn : SCSI HD image (NEC GENUINE)" << endl;
|
||||
cout << " hdi : SCSI HD image (Anex86 HD image)" << endl;
|
||||
cout << " nhd : SCSI HD image (T98Next HD image)" << endl;
|
||||
cout << " mos : SCSI MO image (MO image)" << endl;
|
||||
cout << " iso : SCSI CD image (ISO 9660 image)" << endl;
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
@ -122,6 +116,8 @@ void Cleanup()
|
||||
{
|
||||
executor.DetachAll();
|
||||
|
||||
service.Cleanup();
|
||||
|
||||
// Clean up and discard the bus
|
||||
bus.Cleanup();
|
||||
}
|
||||
@ -359,9 +355,7 @@ bool ParseArgument(int argc, char* argv[], int& port)
|
||||
// Attach all specified devices
|
||||
command.set_operation(ATTACH);
|
||||
|
||||
Localizer localizer;
|
||||
CommandContext context(serializer, localizer, -1, locale);
|
||||
if (!executor.ProcessCmd(context, command)) {
|
||||
if (CommandContext context(locale); !executor.ProcessCmd(context, command)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -376,21 +370,16 @@ bool ParseArgument(int argc, char* argv[], int& port)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ExecuteCommand(PbCommand& command, CommandContext& context)
|
||||
static bool ExecuteCommand(const CommandContext& context, PbCommand& command)
|
||||
{
|
||||
context.locale = GetParam(command, "locale");
|
||||
if (context.locale.empty()) {
|
||||
context.locale = "en";
|
||||
}
|
||||
|
||||
if (!access_token.empty() && access_token != GetParam(command, "token")) {
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_AUTHENTICATION, UNAUTHORIZED);
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_AUTHENTICATION, UNAUTHORIZED);
|
||||
}
|
||||
|
||||
if (!PbOperation_IsValid(command.operation())) {
|
||||
LOGERROR("Received unknown command with operation opcode %d", command.operation())
|
||||
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_OPERATION, UNKNOWN_OPERATION);
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_OPERATION, UNKNOWN_OPERATION);
|
||||
}
|
||||
|
||||
LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str())
|
||||
@ -401,35 +390,35 @@ static bool ExecuteCommand(PbCommand& command, CommandContext& context)
|
||||
case LOG_LEVEL: {
|
||||
string log_level = GetParam(command, "level");
|
||||
if (bool status = executor.SetLogLevel(log_level); !status) {
|
||||
ReturnLocalizedError(context, LocalizationKey::ERROR_LOG_LEVEL, log_level);
|
||||
context.ReturnLocalizedError(LocalizationKey::ERROR_LOG_LEVEL, log_level);
|
||||
}
|
||||
else {
|
||||
current_log_level = log_level;
|
||||
|
||||
ReturnStatus(context);
|
||||
context.ReturnStatus();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DEFAULT_FOLDER: {
|
||||
if (string status = rascsi_image.SetDefaultFolder(GetParam(command, "folder")); !status.empty()) {
|
||||
ReturnStatus(context, false, status);
|
||||
context.ReturnStatus(false, status);
|
||||
}
|
||||
else {
|
||||
ReturnStatus(context);
|
||||
context.ReturnStatus();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DEVICES_INFO: {
|
||||
rascsi_response.GetDevicesInfo(result, command, rascsi_image.GetDefaultFolder());
|
||||
serializer.SerializeMessage(context.fd, result);
|
||||
serializer.SerializeMessage(context.GetFd(), result);
|
||||
break;
|
||||
}
|
||||
|
||||
case DEVICE_TYPES_INFO: {
|
||||
result.set_allocated_device_types_info(rascsi_response.GetDeviceTypesInfo(result).release());
|
||||
serializer.SerializeMessage(context.fd, result);
|
||||
serializer.SerializeMessage(context.GetFd(), result);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -438,19 +427,19 @@ static bool ExecuteCommand(PbCommand& command, CommandContext& context)
|
||||
result, executor.GetReservedIds(), current_log_level, rascsi_image.GetDefaultFolder(),
|
||||
GetParam(command, "folder_pattern"), GetParam(command, "file_pattern"),
|
||||
rascsi_image.GetDepth()).release());
|
||||
serializer.SerializeMessage(context.fd, result);
|
||||
serializer.SerializeMessage(context.GetFd(), result);
|
||||
break;
|
||||
}
|
||||
|
||||
case VERSION_INFO: {
|
||||
result.set_allocated_version_info(rascsi_response.GetVersionInfo(result).release());
|
||||
serializer.SerializeMessage(context.fd, result);
|
||||
serializer.SerializeMessage(context.GetFd(), result);
|
||||
break;
|
||||
}
|
||||
|
||||
case LOG_LEVEL_INFO: {
|
||||
result.set_allocated_log_level_info(rascsi_response.GetLogLevelInfo(result, current_log_level).release());
|
||||
serializer.SerializeMessage(context.fd, result);
|
||||
serializer.SerializeMessage(context.GetFd(), result);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -458,13 +447,13 @@ static bool ExecuteCommand(PbCommand& command, CommandContext& context)
|
||||
result.set_allocated_image_files_info(rascsi_response.GetAvailableImages(result,
|
||||
rascsi_image.GetDefaultFolder(), GetParam(command, "folder_pattern"),
|
||||
GetParam(command, "file_pattern"), rascsi_image.GetDepth()).release());
|
||||
serializer.SerializeMessage(context.fd, result);
|
||||
serializer.SerializeMessage(context.GetFd(), result);
|
||||
break;
|
||||
}
|
||||
|
||||
case IMAGE_FILE_INFO: {
|
||||
if (string filename = GetParam(command, "file"); filename.empty()) {
|
||||
ReturnLocalizedError(context, LocalizationKey::ERROR_MISSING_FILENAME);
|
||||
context.ReturnLocalizedError( LocalizationKey::ERROR_MISSING_FILENAME);
|
||||
}
|
||||
else {
|
||||
auto image_file = make_unique<PbImageFile>();
|
||||
@ -472,10 +461,10 @@ static bool ExecuteCommand(PbCommand& command, CommandContext& context)
|
||||
if (status) {
|
||||
result.set_status(true);
|
||||
result.set_allocated_image_file_info(image_file.get());
|
||||
serializer.SerializeMessage(context.fd, result);
|
||||
serializer.SerializeMessage(context.GetFd(), result);
|
||||
}
|
||||
else {
|
||||
ReturnLocalizedError(context, LocalizationKey::ERROR_IMAGE_FILE_INFO);
|
||||
context.ReturnLocalizedError(LocalizationKey::ERROR_IMAGE_FILE_INFO);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -483,27 +472,27 @@ static bool ExecuteCommand(PbCommand& command, CommandContext& context)
|
||||
|
||||
case NETWORK_INTERFACES_INFO: {
|
||||
result.set_allocated_network_interfaces_info(rascsi_response.GetNetworkInterfacesInfo(result).release());
|
||||
serializer.SerializeMessage(context.fd, result);
|
||||
serializer.SerializeMessage(context.GetFd(), result);
|
||||
break;
|
||||
}
|
||||
|
||||
case MAPPING_INFO: {
|
||||
result.set_allocated_mapping_info(rascsi_response.GetMappingInfo(result).release());
|
||||
serializer.SerializeMessage(context.fd, result);
|
||||
serializer.SerializeMessage(context.GetFd(), result);
|
||||
break;
|
||||
}
|
||||
|
||||
case OPERATION_INFO: {
|
||||
result.set_allocated_operation_info(rascsi_response.GetOperationInfo(result,
|
||||
rascsi_image.GetDepth()).release());
|
||||
serializer.SerializeMessage(context.fd, result);
|
||||
serializer.SerializeMessage(context.GetFd(), result);
|
||||
break;
|
||||
}
|
||||
|
||||
case RESERVED_IDS_INFO: {
|
||||
result.set_allocated_reserved_ids_info(rascsi_response.GetReservedIds(result,
|
||||
executor.GetReservedIds()).release());
|
||||
serializer.SerializeMessage(context.fd, result);
|
||||
serializer.SerializeMessage(context.GetFd(), result);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -516,8 +505,9 @@ static bool ExecuteCommand(PbCommand& command, CommandContext& context)
|
||||
|
||||
default: {
|
||||
// Wait until we become idle
|
||||
timespec ts = { .tv_sec = 0, .tv_nsec = 500 * 1000 * 1000};
|
||||
while (active) {
|
||||
usleep(500 * 1000);
|
||||
nanosleep(&ts, nullptr);
|
||||
}
|
||||
|
||||
executor.ProcessCmd(context, command);
|
||||
@ -609,7 +599,8 @@ int main(int argc, char* argv[])
|
||||
#else
|
||||
bus.Acquire();
|
||||
if (!bus.GetSEL()) {
|
||||
usleep(0);
|
||||
timespec ts = { .tv_sec = 0, .tv_nsec = 0};
|
||||
nanosleep(&ts, nullptr);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
66
src/raspberrypi/rascsi/command_context.cpp
Normal file
66
src/raspberrypi/rascsi/command_context.cpp
Normal file
@ -0,0 +1,66 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2021-2022 Uwe Seimet
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "log.h"
|
||||
#include "rascsi_interface.pb.h"
|
||||
#include "command_context.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace rascsi_interface;
|
||||
|
||||
void CommandContext::Cleanup() const
|
||||
{
|
||||
if (fd != -1) {
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
bool CommandContext::ReturnLocalizedError(LocalizationKey key, const string& arg1, const string& arg2,
|
||||
const string& arg3) const
|
||||
{
|
||||
return ReturnLocalizedError(key, NO_ERROR_CODE, arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
bool CommandContext::ReturnLocalizedError(LocalizationKey key, PbErrorCode error_code, const string& arg1,
|
||||
const string& arg2, const string& arg3) const
|
||||
{
|
||||
// For the logfile always use English
|
||||
LOGERROR("%s", localizer.Localize(key, "en", arg1, arg2, arg3).c_str())
|
||||
|
||||
return ReturnStatus(false, localizer.Localize(key, locale, arg1, arg2, arg3), error_code, false);
|
||||
}
|
||||
|
||||
bool CommandContext::ReturnStatus(bool status, const string& msg, PbErrorCode error_code, bool log) const
|
||||
{
|
||||
// Do not log twice if logging has already been done in the localized error handling above
|
||||
if (log && !status && !msg.empty()) {
|
||||
LOGERROR("%s", msg.c_str())
|
||||
}
|
||||
|
||||
if (fd == -1) {
|
||||
if (!msg.empty()) {
|
||||
if (status) {
|
||||
cerr << "Error: " << msg << endl;
|
||||
}
|
||||
else {
|
||||
cout << msg << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
PbResult result;
|
||||
result.set_status(status);
|
||||
result.set_error_code(error_code);
|
||||
result.set_msg(msg);
|
||||
serializer.SerializeMessage(fd, result);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
45
src/raspberrypi/rascsi/command_context.h
Normal file
45
src/raspberrypi/rascsi/command_context.h
Normal file
@ -0,0 +1,45 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2021-2022 Uwe Seimet
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "rascsi_interface.pb.h"
|
||||
#include "localizer.h"
|
||||
#include "protobuf_serializer.h"
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
using namespace rascsi_interface;
|
||||
|
||||
class CommandContext
|
||||
{
|
||||
const ProtobufSerializer serializer;
|
||||
|
||||
const Localizer localizer;
|
||||
|
||||
string locale;
|
||||
|
||||
int fd;
|
||||
|
||||
public:
|
||||
|
||||
CommandContext(const std::string& s = "", int f = -1) : locale(s), fd(f) {}
|
||||
~CommandContext() = default;
|
||||
|
||||
void Cleanup() const;
|
||||
|
||||
const ProtobufSerializer& GetSerializer() const { return serializer; }
|
||||
int GetFd() const { return fd; }
|
||||
void SetFd(int f) { fd = f; }
|
||||
bool IsValid() const { return fd != -1; }
|
||||
|
||||
bool ReturnLocalizedError(LocalizationKey, const string& = "", const string& = "", const string& = "") const;
|
||||
bool ReturnLocalizedError(LocalizationKey, PbErrorCode, const string& = "", const string& = "", const string& = "") const;
|
||||
bool ReturnStatus(bool = true, const string& = "", PbErrorCode = PbErrorCode::NO_ERROR_CODE, bool = true) const;
|
||||
};
|
@ -20,6 +20,7 @@
|
||||
#include "rascsi_exceptions.h"
|
||||
#include "localizer.h"
|
||||
#include "command_util.h"
|
||||
#include "command_context.h"
|
||||
#include "rasutil.h"
|
||||
#include "spdlog/spdlog.h"
|
||||
#include "rascsi_executor.h"
|
||||
@ -87,7 +88,7 @@ bool RascsiExecutor::ProcessCmd(const CommandContext& context, const PbDeviceDef
|
||||
break;
|
||||
|
||||
default:
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_OPERATION);
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_OPERATION);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -98,15 +99,15 @@ bool RascsiExecutor::ProcessCmd(const CommandContext& context, const PbCommand&
|
||||
switch (command.operation()) {
|
||||
case DETACH_ALL:
|
||||
DetachAll();
|
||||
return ReturnStatus(context);
|
||||
return context.ReturnStatus();
|
||||
|
||||
case RESERVE_IDS: {
|
||||
const string ids = GetParam(command, "ids");
|
||||
if (string error = SetReservedIds(ids); !error.empty()) {
|
||||
return ReturnStatus(context, false, error);
|
||||
return context.ReturnStatus(false, error);
|
||||
}
|
||||
|
||||
return ReturnStatus(context);
|
||||
return context.ReturnStatus();
|
||||
}
|
||||
|
||||
case CREATE_IMAGE:
|
||||
@ -144,7 +145,7 @@ bool RascsiExecutor::ProcessCmd(const CommandContext& context, const PbCommand&
|
||||
FileSupport::SetReservedFiles(reserved_files);
|
||||
|
||||
if (string result = ValidateLunSetup(command); !result.empty()) {
|
||||
return ReturnStatus(context, false, result);
|
||||
return context.ReturnStatus(false, result);
|
||||
}
|
||||
|
||||
for (const auto& device : command.devices()) {
|
||||
@ -154,16 +155,16 @@ bool RascsiExecutor::ProcessCmd(const CommandContext& context, const PbCommand&
|
||||
}
|
||||
|
||||
// ATTACH and DETACH return the device list
|
||||
if (context.fd != -1 && (command.operation() == ATTACH || command.operation() == DETACH)) {
|
||||
if (context.IsValid() && (command.operation() == ATTACH || command.operation() == DETACH)) {
|
||||
// A new command with an empty device list is required here in order to return data for all devices
|
||||
PbCommand cmd;
|
||||
PbResult result;
|
||||
rascsi_response.GetDevicesInfo(result, cmd, rascsi_image.GetDefaultFolder());
|
||||
serializer.SerializeMessage(context.fd, result);
|
||||
serializer.SerializeMessage(context.GetFd(), result);
|
||||
return true;
|
||||
}
|
||||
|
||||
return ReturnStatus(context);
|
||||
return context.ReturnStatus();
|
||||
}
|
||||
|
||||
bool RascsiExecutor::SetLogLevel(const string& log_level) const
|
||||
@ -271,15 +272,15 @@ bool RascsiExecutor::Attach(const CommandContext& context, const PbDeviceDefinit
|
||||
const PbDeviceType type = pb_device.type();
|
||||
|
||||
if (lun >= ScsiController::LUN_MAX) {
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_INVALID_LUN, to_string(lun), to_string(ScsiController::LUN_MAX));
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_INVALID_LUN, to_string(lun), to_string(ScsiController::LUN_MAX));
|
||||
}
|
||||
|
||||
if (controller_manager.GetDeviceByIdAndLun(id, lun) != nullptr) {
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_DUPLICATE_ID, to_string(id), to_string(lun));
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_DUPLICATE_ID, to_string(id), to_string(lun));
|
||||
}
|
||||
|
||||
if (reserved_ids.find(id) != reserved_ids.end()) {
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_RESERVED_ID, to_string(id));
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_RESERVED_ID, to_string(id));
|
||||
}
|
||||
|
||||
string filename = GetParam(pb_device, "file");
|
||||
@ -305,7 +306,7 @@ bool RascsiExecutor::Attach(const CommandContext& context, const PbDeviceDefinit
|
||||
if (file_support != nullptr) {
|
||||
// File check (type is HD, for removable media drives, CD and MO the medium (=file) may be inserted later
|
||||
if (!device->IsRemovable() && filename.empty()) {
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_MISSING_FILENAME, PbDeviceType_Name(type));
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_MISSING_FILENAME, PbDeviceType_Name(type));
|
||||
}
|
||||
|
||||
if (!ValidateImageFile(context, device, filename, full_path)) {
|
||||
@ -330,12 +331,12 @@ bool RascsiExecutor::Attach(const CommandContext& context, const PbDeviceDefinit
|
||||
}
|
||||
|
||||
if (!device->Init(params)) {
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_INITIALIZATION, PbDeviceType_Name(type),
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_INITIALIZATION, PbDeviceType_Name(type),
|
||||
to_string(id), to_string(lun));
|
||||
}
|
||||
|
||||
if (!controller_manager.AttachToScsiController(id, device)) {
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_SCSI_CONTROLLER);
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_SCSI_CONTROLLER);
|
||||
}
|
||||
|
||||
Filepath filepath;
|
||||
@ -359,16 +360,16 @@ bool RascsiExecutor::Insert(const CommandContext& context, const PbDeviceDefinit
|
||||
shared_ptr<PrimaryDevice> device, bool dryRun) const
|
||||
{
|
||||
if (!device->IsRemoved()) {
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_EJECT_REQUIRED);
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_EJECT_REQUIRED);
|
||||
}
|
||||
|
||||
if (!pb_device.vendor().empty() || !pb_device.product().empty() || !pb_device.revision().empty()) {
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_DEVICE_NAME_UPDATE);
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_DEVICE_NAME_UPDATE);
|
||||
}
|
||||
|
||||
string filename = GetParam(pb_device, "file");
|
||||
if (filename.empty()) {
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_MISSING_FILENAME);
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_MISSING_FILENAME);
|
||||
}
|
||||
|
||||
if (dryRun) {
|
||||
@ -408,7 +409,7 @@ bool RascsiExecutor::Detach(const CommandContext& context, shared_ptr<PrimaryDev
|
||||
{
|
||||
// LUN 0 can only be detached if there is no other LUN anymore
|
||||
if (!device->GetLun() && controller_manager.FindController(device->GetId())->GetLunCount() > 1) {
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_LUN0);
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_LUN0);
|
||||
}
|
||||
|
||||
if (!dryRun) {
|
||||
@ -422,7 +423,7 @@ bool RascsiExecutor::Detach(const CommandContext& context, shared_ptr<PrimaryDev
|
||||
|
||||
auto controller = controller_manager.FindController(device->GetId());
|
||||
if (controller == nullptr || !controller->DeleteDevice(device)) {
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_DETACH);
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_DETACH);
|
||||
}
|
||||
|
||||
// If no LUN is left also delete the controller
|
||||
@ -446,7 +447,7 @@ void RascsiExecutor::DetachAll()
|
||||
|
||||
bool RascsiExecutor::ShutDown(const CommandContext& context, const string& mode) {
|
||||
if (mode.empty()) {
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_SHUTDOWN_MODE_MISSING);
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_SHUTDOWN_MODE_MISSING);
|
||||
}
|
||||
|
||||
PbResult result;
|
||||
@ -455,24 +456,24 @@ bool RascsiExecutor::ShutDown(const CommandContext& context, const string& mode)
|
||||
if (mode == "rascsi") {
|
||||
LOGINFO("RaSCSI shutdown requested")
|
||||
|
||||
serializer.SerializeMessage(context.fd, result);
|
||||
serializer.SerializeMessage(context.GetFd(), result);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mode != "system" && mode != "reboot") {
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_SHUTDOWN_MODE_INVALID, mode);
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_SHUTDOWN_MODE_INVALID, mode);
|
||||
}
|
||||
|
||||
// The root user has UID 0
|
||||
if (getuid()) {
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_SHUTDOWN_PERMISSION);
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_SHUTDOWN_PERMISSION);
|
||||
}
|
||||
|
||||
if (mode == "system") {
|
||||
LOGINFO("System shutdown requested")
|
||||
|
||||
serializer.SerializeMessage(context.fd, result);
|
||||
serializer.SerializeMessage(context.GetFd(), result);
|
||||
|
||||
DetachAll();
|
||||
|
||||
@ -483,7 +484,7 @@ bool RascsiExecutor::ShutDown(const CommandContext& context, const string& mode)
|
||||
else if (mode == "reboot") {
|
||||
LOGINFO("System reboot requested")
|
||||
|
||||
serializer.SerializeMessage(context.fd, result);
|
||||
serializer.SerializeMessage(context.GetFd(), result);
|
||||
|
||||
DetachAll();
|
||||
|
||||
@ -559,7 +560,7 @@ bool RascsiExecutor::ValidateImageFile(const CommandContext& context, shared_ptr
|
||||
filepath.SetPath(filename.c_str());
|
||||
|
||||
if (FileSupport::GetIdsForReservedFile(filepath, id, lun)) {
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_IMAGE_IN_USE, filename,
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_IMAGE_IN_USE, filename,
|
||||
to_string(id), to_string(lun));
|
||||
}
|
||||
|
||||
@ -571,7 +572,7 @@ bool RascsiExecutor::ValidateImageFile(const CommandContext& context, shared_ptr
|
||||
filepath.SetPath((rascsi_image.GetDefaultFolder() + "/" + filename).c_str());
|
||||
|
||||
if (FileSupport::GetIdsForReservedFile(filepath, id, lun)) {
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_IMAGE_IN_USE, filename,
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_IMAGE_IN_USE, filename,
|
||||
to_string(id), to_string(lun));
|
||||
}
|
||||
|
||||
@ -579,7 +580,7 @@ bool RascsiExecutor::ValidateImageFile(const CommandContext& context, shared_ptr
|
||||
}
|
||||
}
|
||||
catch(const io_exception& e) {
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_FILE_OPEN, initial_filename, e.get_msg());
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_FILE_OPEN, initial_filename, e.get_msg());
|
||||
}
|
||||
|
||||
full_path = filepath.GetPath();
|
||||
@ -656,11 +657,11 @@ string RascsiExecutor::ValidateLunSetup(const PbCommand& command) const
|
||||
bool RascsiExecutor::VerifyExistingIdAndLun(const CommandContext& context, int id, int lun) const
|
||||
{
|
||||
if (controller_manager.FindController(id) == nullptr) {
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_NON_EXISTING_DEVICE, to_string(id));
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_NON_EXISTING_DEVICE, to_string(id));
|
||||
}
|
||||
|
||||
if (controller_manager.GetDeviceByIdAndLun(id, lun) == nullptr) {
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_NON_EXISTING_UNIT, to_string(id), to_string(lun));
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_NON_EXISTING_UNIT, to_string(id), to_string(lun));
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -672,10 +673,10 @@ shared_ptr<PrimaryDevice> RascsiExecutor::CreateDevice(const CommandContext& con
|
||||
auto device = device_factory.CreateDevice(controller_manager, type, lun, filename);
|
||||
if (device == nullptr) {
|
||||
if (type == UNDEFINED) {
|
||||
ReturnLocalizedError(context, LocalizationKey::ERROR_MISSING_DEVICE_TYPE, filename);
|
||||
context.ReturnLocalizedError(LocalizationKey::ERROR_MISSING_DEVICE_TYPE, filename);
|
||||
}
|
||||
else {
|
||||
ReturnLocalizedError(context, LocalizationKey::ERROR_UNKNOWN_DEVICE_TYPE, PbDeviceType_Name(type));
|
||||
context.ReturnLocalizedError(LocalizationKey::ERROR_UNKNOWN_DEVICE_TYPE, PbDeviceType_Name(type));
|
||||
}
|
||||
}
|
||||
|
||||
@ -689,11 +690,11 @@ bool RascsiExecutor::SetSectorSize(const CommandContext& context, const string&
|
||||
auto disk = dynamic_pointer_cast<Disk>(device);
|
||||
if (disk != nullptr && disk->IsSectorSizeConfigurable()) {
|
||||
if (!disk->SetConfiguredSectorSize(device_factory, block_size)) {
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_BLOCK_SIZE, to_string(block_size));
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_BLOCK_SIZE, to_string(block_size));
|
||||
}
|
||||
}
|
||||
else {
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, type);
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_BLOCK_SIZE_NOT_CONFIGURABLE, type);
|
||||
}
|
||||
}
|
||||
|
||||
@ -706,19 +707,19 @@ bool RascsiExecutor::ValidationOperationAgainstDevice(const CommandContext& cont
|
||||
const string& type = device->GetType();
|
||||
|
||||
if ((operation == START || operation == STOP) && !device->IsStoppable()) {
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_OPERATION_DENIED_STOPPABLE, type);
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_OPERATION_DENIED_STOPPABLE, type);
|
||||
}
|
||||
|
||||
if ((operation == INSERT || operation == EJECT) && !device->IsRemovable()) {
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_OPERATION_DENIED_REMOVABLE, type);
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_OPERATION_DENIED_REMOVABLE, type);
|
||||
}
|
||||
|
||||
if ((operation == PROTECT || operation == UNPROTECT) && !device->IsProtectable()) {
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_OPERATION_DENIED_PROTECTABLE, type);
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_OPERATION_DENIED_PROTECTABLE, type);
|
||||
}
|
||||
|
||||
if ((operation == PROTECT || operation == UNPROTECT) && !device->IsReady()) {
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_OPERATION_DENIED_READY, type);
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_OPERATION_DENIED_READY, type);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -728,13 +729,13 @@ bool RascsiExecutor::ValidateIdAndLun(const CommandContext& context, int id, int
|
||||
{
|
||||
// Validate the device ID and LUN
|
||||
if (id < 0) {
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_MISSING_DEVICE_ID);
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_MISSING_DEVICE_ID);
|
||||
}
|
||||
if (id >= ControllerManager::DEVICE_MAX) {
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_INVALID_ID, to_string(id), to_string(ControllerManager::DEVICE_MAX - 1));
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_INVALID_ID, to_string(id), to_string(ControllerManager::DEVICE_MAX - 1));
|
||||
}
|
||||
if (lun < 0 || lun >= ScsiController::LUN_MAX) {
|
||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_INVALID_LUN, to_string(lun), to_string(ScsiController::LUN_MAX - 1));
|
||||
return context.ReturnLocalizedError(LocalizationKey::ERROR_INVALID_LUN, to_string(lun), to_string(ScsiController::LUN_MAX - 1));
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -755,7 +756,7 @@ bool RascsiExecutor::SetProductData(const CommandContext& context, const PbDevic
|
||||
}
|
||||
}
|
||||
catch(const invalid_argument& e) {
|
||||
return ReturnStatus(context, false, e.what());
|
||||
return context.ReturnStatus(false, e.what());
|
||||
}
|
||||
|
||||
return true;
|
@ -14,6 +14,7 @@
|
||||
#include "spdlog/spdlog.h"
|
||||
#include "devices/file_support.h"
|
||||
#include "command_util.h"
|
||||
#include "command_context.h"
|
||||
#include "rascsi_image.h"
|
||||
#include <string>
|
||||
#include <array>
|
||||
@ -48,7 +49,7 @@ bool RascsiImage::CreateImageFolder(const CommandContext& context, const string&
|
||||
std::error_code error;
|
||||
filesystem::create_directories(folder, error);
|
||||
if (error) {
|
||||
ReturnStatus(context, false, "Can't create image folder '" + folder + "': " + strerror(errno));
|
||||
context.ReturnStatus(false, "Can't create image folder '" + folder + "': " + strerror(errno));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -106,21 +107,21 @@ bool RascsiImage::CreateImage(const CommandContext& context, const PbCommand& co
|
||||
{
|
||||
string filename = GetParam(command, "file");
|
||||
if (filename.empty()) {
|
||||
return ReturnStatus(context, false, "Can't create image file: Missing image filename");
|
||||
return context.ReturnStatus(false, "Can't create image file: Missing image filename");
|
||||
}
|
||||
|
||||
if (!CheckDepth(filename)) {
|
||||
return ReturnStatus(context, false, ("Invalid folder hierarchy depth '" + filename + "'").c_str());
|
||||
return context.ReturnStatus(false, ("Invalid folder hierarchy depth '" + filename + "'").c_str());
|
||||
}
|
||||
|
||||
string full_filename = GetFullName(filename);
|
||||
if (!IsValidDstFilename(full_filename)) {
|
||||
return ReturnStatus(context, false, "Can't create image file: '" + full_filename + "': File already exists");
|
||||
return context.ReturnStatus(false, "Can't create image file: '" + full_filename + "': File already exists");
|
||||
}
|
||||
|
||||
const string size = GetParam(command, "size");
|
||||
if (size.empty()) {
|
||||
return ReturnStatus(context, false, "Can't create image file '" + full_filename + "': Missing image size");
|
||||
return context.ReturnStatus(false, "Can't create image file '" + full_filename + "': Missing image size");
|
||||
}
|
||||
|
||||
off_t len;
|
||||
@ -128,13 +129,13 @@ bool RascsiImage::CreateImage(const CommandContext& context, const PbCommand& co
|
||||
len = stoull(size);
|
||||
}
|
||||
catch(const invalid_argument&) {
|
||||
return ReturnStatus(context, false, "Can't create image file '" + full_filename + "': Invalid file size " + size);
|
||||
return context.ReturnStatus(false, "Can't create image file '" + full_filename + "': Invalid file size " + size);
|
||||
}
|
||||
catch(const out_of_range&) {
|
||||
return ReturnStatus(context, false, "Can't create image file '" + full_filename + "': Invalid file size " + size);
|
||||
return context.ReturnStatus(false, "Can't create image file '" + full_filename + "': Invalid file size " + size);
|
||||
}
|
||||
if (len < 512 || (len & 0x1ff)) {
|
||||
return ReturnStatus(context, false, "Invalid image file size " + to_string(len) + " (not a multiple of 512)");
|
||||
return context.ReturnStatus(false, "Invalid image file size " + to_string(len) + " (not a multiple of 512)");
|
||||
}
|
||||
|
||||
if (!CreateImageFolder(context, full_filename)) {
|
||||
@ -148,7 +149,7 @@ bool RascsiImage::CreateImage(const CommandContext& context, const PbCommand& co
|
||||
|
||||
int image_fd = open(full_filename.c_str(), O_CREAT|O_WRONLY, permissions);
|
||||
if (image_fd == -1) {
|
||||
return ReturnStatus(context, false, "Can't create image file '" + full_filename + "': " + string(strerror(errno)));
|
||||
return context.ReturnStatus(false, "Can't create image file '" + full_filename + "': " + string(strerror(errno)));
|
||||
}
|
||||
|
||||
#ifndef __linux__
|
||||
@ -163,7 +164,7 @@ bool RascsiImage::CreateImage(const CommandContext& context, const PbCommand& co
|
||||
|
||||
unlink(full_filename.c_str());
|
||||
|
||||
return ReturnStatus(context, false, "Can't allocate space for image file '" + full_filename + "': " + string(strerror(errno)));
|
||||
return context.ReturnStatus(false, "Can't allocate space for image file '" + full_filename + "': " + string(strerror(errno)));
|
||||
}
|
||||
|
||||
close(image_fd);
|
||||
@ -171,7 +172,7 @@ bool RascsiImage::CreateImage(const CommandContext& context, const PbCommand& co
|
||||
LOGINFO("%s", string("Created " + string(permissions & S_IWUSR ? "": "read-only ") + "image file '" + full_filename +
|
||||
"' with a size of " + to_string(len) + " bytes").c_str())
|
||||
|
||||
return ReturnStatus(context);
|
||||
return context.ReturnStatus();
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -179,11 +180,11 @@ bool RascsiImage::DeleteImage(const CommandContext& context, const PbCommand& co
|
||||
{
|
||||
string filename = GetParam(command, "file");
|
||||
if (filename.empty()) {
|
||||
return ReturnStatus(context, false, "Missing image filename");
|
||||
return context.ReturnStatus(false, "Missing image filename");
|
||||
}
|
||||
|
||||
if (!CheckDepth(filename)) {
|
||||
return ReturnStatus(context, false, ("Invalid folder hierarchy depth '" + filename + "'").c_str());
|
||||
return context.ReturnStatus(false, ("Invalid folder hierarchy depth '" + filename + "'").c_str());
|
||||
}
|
||||
|
||||
string full_filename = GetFullName(filename);
|
||||
@ -193,12 +194,12 @@ bool RascsiImage::DeleteImage(const CommandContext& context, const PbCommand& co
|
||||
Filepath filepath;
|
||||
filepath.SetPath(full_filename.c_str());
|
||||
if (FileSupport::GetIdsForReservedFile(filepath, id, unit)) {
|
||||
return ReturnStatus(context, false, "Can't delete image file '" + full_filename +
|
||||
return context.ReturnStatus(false, "Can't delete image file '" + full_filename +
|
||||
"', it is currently being used by device ID " + to_string(id) + ", unit " + to_string(unit));
|
||||
}
|
||||
|
||||
if (remove(full_filename.c_str())) {
|
||||
return ReturnStatus(context, false, "Can't delete image file '" + full_filename + "': " + string(strerror(errno)));
|
||||
return context.ReturnStatus(false, "Can't delete image file '" + full_filename + "': " + string(strerror(errno)));
|
||||
}
|
||||
|
||||
// Delete empty subfolders
|
||||
@ -212,7 +213,7 @@ bool RascsiImage::DeleteImage(const CommandContext& context, const PbCommand& co
|
||||
}
|
||||
|
||||
if (remove(full_folder.c_str())) {
|
||||
return ReturnStatus(context, false, "Can't delete empty image folder '" + full_folder + "'");
|
||||
return context.ReturnStatus(false, "Can't delete empty image folder '" + full_folder + "'");
|
||||
}
|
||||
|
||||
last_slash = folder.rfind('/');
|
||||
@ -220,37 +221,15 @@ bool RascsiImage::DeleteImage(const CommandContext& context, const PbCommand& co
|
||||
|
||||
LOGINFO("Deleted image file '%s'", full_filename.c_str())
|
||||
|
||||
return ReturnStatus(context);
|
||||
return context.ReturnStatus();
|
||||
}
|
||||
|
||||
bool RascsiImage::RenameImage(const CommandContext& context, const PbCommand& command) const
|
||||
{
|
||||
string from = GetParam(command, "from");
|
||||
if (from.empty()) {
|
||||
return ReturnStatus(context, false, "Can't rename/move image file: Missing source filename");
|
||||
}
|
||||
|
||||
if (!CheckDepth(from)) {
|
||||
return ReturnStatus(context, false, ("Invalid folder hierarchy depth '" + from + "'").c_str());
|
||||
}
|
||||
|
||||
from = GetFullName(from);
|
||||
if (!IsValidSrcFilename(from)) {
|
||||
return ReturnStatus(context, false, "Can't rename/move image file: '" + from + "': Invalid name or type");
|
||||
}
|
||||
|
||||
string to = GetParam(command, "to");
|
||||
if (to.empty()) {
|
||||
return ReturnStatus(context, false, "Can't rename/move image file '" + from + "': Missing destination filename");
|
||||
}
|
||||
|
||||
if (!CheckDepth(to)) {
|
||||
return ReturnStatus(context, false, ("Invalid folder hierarchy depth '" + to + "'").c_str());
|
||||
}
|
||||
|
||||
to = GetFullName(to);
|
||||
if (!IsValidDstFilename(to)) {
|
||||
return ReturnStatus(context, false, "Can't rename/move image file '" + from + "' to '" + to + "': File already exists");
|
||||
string from;
|
||||
string to;
|
||||
if (!ValidateParams(context, command, "rename/move", from, to)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CreateImageFolder(context, to)) {
|
||||
@ -258,47 +237,25 @@ bool RascsiImage::RenameImage(const CommandContext& context, const PbCommand& co
|
||||
}
|
||||
|
||||
if (rename(from.c_str(), to.c_str())) {
|
||||
return ReturnStatus(context, false, "Can't rename/move image file '" + from + "' to '" + to + "': " + string(strerror(errno)));
|
||||
return context.ReturnStatus(false, "Can't rename/move image file '" + from + "' to '" + to + "': " + string(strerror(errno)));
|
||||
}
|
||||
|
||||
LOGINFO("Renamed/Moved image file '%s' to '%s'", from.c_str(), to.c_str())
|
||||
|
||||
return ReturnStatus(context);
|
||||
return context.ReturnStatus();
|
||||
}
|
||||
|
||||
bool RascsiImage::CopyImage(const CommandContext& context, const PbCommand& command) const
|
||||
{
|
||||
string from = GetParam(command, "from");
|
||||
if (from.empty()) {
|
||||
return ReturnStatus(context, false, "Can't copy image file: Missing source filename");
|
||||
}
|
||||
|
||||
if (!CheckDepth(from)) {
|
||||
return ReturnStatus(context, false, ("Invalid folder hierarchy depth '" + from + "'").c_str());
|
||||
}
|
||||
|
||||
from = GetFullName(from);
|
||||
if (!IsValidSrcFilename(from)) {
|
||||
return ReturnStatus(context, false, "Can't copy image file: '" + from + "': Invalid name or type");
|
||||
}
|
||||
|
||||
string to = GetParam(command, "to");
|
||||
if (to.empty()) {
|
||||
return ReturnStatus(context, false, "Can't copy image file '" + from + "': Missing destination filename");
|
||||
}
|
||||
|
||||
if (!CheckDepth(to)) {
|
||||
return ReturnStatus(context, false, ("Invalid folder hierarchy depth '" + to + "'").c_str());
|
||||
}
|
||||
|
||||
to = GetFullName(to);
|
||||
if (!IsValidDstFilename(to)) {
|
||||
return ReturnStatus(context, false, "Can't copy image file '" + from + "' to '" + to + "': File already exists");
|
||||
string from;
|
||||
string to;
|
||||
if (!ValidateParams(context, command, "copy", from, to)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct stat st;
|
||||
if (lstat(from.c_str(), &st)) {
|
||||
return ReturnStatus(context, false, "Can't access source image file '" + from + "': " + string(strerror(errno)));
|
||||
return context.ReturnStatus(false, "Can't access source image file '" + from + "': " + string(strerror(errno)));
|
||||
}
|
||||
|
||||
if (!CreateImageFolder(context, to)) {
|
||||
@ -308,17 +265,17 @@ bool RascsiImage::CopyImage(const CommandContext& context, const PbCommand& comm
|
||||
// Symbolic links need a special handling
|
||||
if ((st.st_mode & S_IFMT) == S_IFLNK) {
|
||||
if (symlink(filesystem::read_symlink(from).c_str(), to.c_str())) {
|
||||
return ReturnStatus(context, false, "Can't copy symlink '" + from + "': " + string(strerror(errno)));
|
||||
return context.ReturnStatus(false, "Can't copy symlink '" + from + "': " + string(strerror(errno)));
|
||||
}
|
||||
|
||||
LOGINFO("Copied symlink '%s' to '%s'", from.c_str(), to.c_str())
|
||||
|
||||
return ReturnStatus(context);
|
||||
return context.ReturnStatus();
|
||||
}
|
||||
|
||||
int fd_src = open(from.c_str(), O_RDONLY, 0);
|
||||
if (fd_src == -1) {
|
||||
return ReturnStatus(context, false, "Can't open source image file '" + from + "': " + string(strerror(errno)));
|
||||
return context.ReturnStatus(false, "Can't open source image file '" + from + "': " + string(strerror(errno)));
|
||||
}
|
||||
|
||||
string permission = GetParam(command, "read_only");
|
||||
@ -330,7 +287,7 @@ bool RascsiImage::CopyImage(const CommandContext& context, const PbCommand& comm
|
||||
if (fd_dst == -1) {
|
||||
close(fd_src);
|
||||
|
||||
return ReturnStatus(context, false, "Can't open destination image file '" + to + "': " + string(strerror(errno)));
|
||||
return context.ReturnStatus(false, "Can't open destination image file '" + to + "': " + string(strerror(errno)));
|
||||
}
|
||||
|
||||
#ifndef __linux__
|
||||
@ -339,6 +296,8 @@ bool RascsiImage::CopyImage(const CommandContext& context, const PbCommand& comm
|
||||
|
||||
unlink(to.c_str());
|
||||
|
||||
LOGWARN("Copying image files is only supported under Linux")
|
||||
|
||||
return false;
|
||||
#else
|
||||
if (sendfile(fd_dst, fd_src, nullptr, st.st_size) == -1) {
|
||||
@ -347,7 +306,7 @@ bool RascsiImage::CopyImage(const CommandContext& context, const PbCommand& comm
|
||||
|
||||
unlink(to.c_str());
|
||||
|
||||
return ReturnStatus(context, false, "Can't copy image file '" + from + "' to '" + to + "': " + string(strerror(errno)));
|
||||
return context.ReturnStatus(false, "Can't copy image file '" + from + "' to '" + to + "': " + string(strerror(errno)));
|
||||
}
|
||||
|
||||
close(fd_dst);
|
||||
@ -355,7 +314,7 @@ bool RascsiImage::CopyImage(const CommandContext& context, const PbCommand& comm
|
||||
|
||||
LOGINFO("Copied image file '%s' to '%s'", from.c_str(), to.c_str())
|
||||
|
||||
return ReturnStatus(context);
|
||||
return context.ReturnStatus();
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -363,23 +322,23 @@ bool RascsiImage::SetImagePermissions(const CommandContext& context, const PbCom
|
||||
{
|
||||
string filename = GetParam(command, "file");
|
||||
if (filename.empty()) {
|
||||
return ReturnStatus(context, false, "Missing image filename");
|
||||
return context.ReturnStatus(false, "Missing image filename");
|
||||
}
|
||||
|
||||
if (!CheckDepth(filename)) {
|
||||
return ReturnStatus(context, false, ("Invalid folder hierarchy depth '" + filename + "'").c_str());
|
||||
return context.ReturnStatus(false, ("Invalid folder hierarchy depth '" + filename + "'").c_str());
|
||||
}
|
||||
|
||||
filename = GetFullName(filename);
|
||||
if (!IsValidSrcFilename(filename)) {
|
||||
return ReturnStatus(context, false, "Can't modify image file '" + filename + "': Invalid name or type");
|
||||
return context.ReturnStatus(false, "Can't modify image file '" + filename + "': Invalid name or type");
|
||||
}
|
||||
|
||||
bool protect = command.operation() == PROTECT_IMAGE;
|
||||
|
||||
if (int permissions = protect ? S_IRUSR | S_IRGRP | S_IROTH : S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
|
||||
chmod(filename.c_str(), permissions) == -1) {
|
||||
return ReturnStatus(context, false, "Can't " + string(protect ? "protect" : "unprotect") + " image file '" + filename + "': " +
|
||||
return context.ReturnStatus(false, "Can't " + string(protect ? "protect" : "unprotect") + " image file '" + filename + "': " +
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
@ -390,10 +349,44 @@ bool RascsiImage::SetImagePermissions(const CommandContext& context, const PbCom
|
||||
LOGINFO("Unprotected image file '%s'", filename.c_str())
|
||||
}
|
||||
|
||||
return ReturnStatus(context);
|
||||
return context.ReturnStatus();
|
||||
}
|
||||
|
||||
string RascsiImage::GetHomeDir() const
|
||||
bool RascsiImage::ValidateParams(const CommandContext& context, const PbCommand& command, const string& operation,
|
||||
string& from, string& to) const
|
||||
{
|
||||
from = GetParam(command, "from");
|
||||
if (from.empty()) {
|
||||
return context.ReturnStatus(false, "Can't " + operation + " image file: Missing source filename");
|
||||
}
|
||||
|
||||
if (!CheckDepth(from)) {
|
||||
return context.ReturnStatus(false, ("Invalid folder hierarchy depth '" + from + "'").c_str());
|
||||
}
|
||||
|
||||
from = GetFullName(from);
|
||||
if (!IsValidSrcFilename(from)) {
|
||||
return context.ReturnStatus(false, "Can't " + operation + " image file: '" + from + "': Invalid name or type");
|
||||
}
|
||||
|
||||
to = GetParam(command, "to");
|
||||
if (to.empty()) {
|
||||
return context.ReturnStatus(false, "Can't " + operation + " image file '" + from + "': Missing destination filename");
|
||||
}
|
||||
|
||||
if (!CheckDepth(to)) {
|
||||
return context.ReturnStatus(false, ("Invalid folder hierarchy depth '" + to + "'").c_str());
|
||||
}
|
||||
|
||||
to = GetFullName(to);
|
||||
if (!IsValidDstFilename(to)) {
|
||||
return context.ReturnStatus(false, "Can't " + operation + " image file '" + from + "' to '" + to + "': File already exists");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
string RascsiImage::GetHomeDir()
|
||||
{
|
||||
int uid = getuid();
|
||||
if (const char *sudo_user = getenv("SUDO_UID"); sudo_user != nullptr) {
|
@ -13,6 +13,7 @@
|
||||
#include "command_context.h"
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
using namespace rascsi_interface;
|
||||
|
||||
class RascsiImage
|
||||
@ -24,22 +25,24 @@ public:
|
||||
|
||||
void SetDepth(int d) { depth = d; }
|
||||
int GetDepth() const { return depth; }
|
||||
bool CheckDepth(string_view) const;
|
||||
bool CreateImageFolder(const CommandContext&, const string&) const;
|
||||
string GetDefaultFolder() const { return default_folder; }
|
||||
string SetDefaultFolder(const string&);
|
||||
bool IsValidSrcFilename(const string&) const;
|
||||
bool IsValidDstFilename(const string&) const;
|
||||
bool CreateImage(const CommandContext&, const PbCommand&) const;
|
||||
bool DeleteImage(const CommandContext&, const PbCommand&) const;
|
||||
bool RenameImage(const CommandContext&, const PbCommand&) const;
|
||||
bool CopyImage(const CommandContext&, const PbCommand&) const;
|
||||
bool SetImagePermissions(const CommandContext&, const PbCommand&) const;
|
||||
string GetFullName(const string& filename) const { return default_folder + "/" + filename; }
|
||||
|
||||
private:
|
||||
|
||||
string GetHomeDir() const;
|
||||
bool CheckDepth(string_view) const;
|
||||
string GetFullName(const string& filename) const { return default_folder + "/" + filename; }
|
||||
bool CreateImageFolder(const CommandContext&, const string&) const;
|
||||
bool IsValidSrcFilename(const string&) const;
|
||||
bool IsValidDstFilename(const string&) const;
|
||||
bool ValidateParams(const CommandContext&, const PbCommand&, const string&, string&, string&) const;
|
||||
|
||||
static string GetHomeDir();
|
||||
|
||||
string default_folder;
|
||||
|
@ -83,7 +83,7 @@ void RascsiResponse::GetDevice(const Device& device, PbDevice& pb_device, const
|
||||
|
||||
pb_device.set_allocated_properties(GetDeviceProperties(device).release());
|
||||
|
||||
auto status = make_unique<PbDeviceStatus>().release();
|
||||
auto status = make_unique<PbDeviceStatus>().release(); //NOSONAR The allocated memory is managed by protobuf
|
||||
pb_device.set_allocated_status(status);
|
||||
status->set_protected_(device.IsProtected());
|
||||
status->set_stopped(device.IsStopped());
|
@ -21,25 +21,25 @@ using namespace rascsi_interface;
|
||||
|
||||
volatile bool RascsiService::running = false;
|
||||
|
||||
RascsiService::~RascsiService()
|
||||
void RascsiService::Cleanup() const
|
||||
{
|
||||
if (service_socket != -1) {
|
||||
close(service_socket);
|
||||
}
|
||||
}
|
||||
|
||||
bool RascsiService::Init(bool (e)(PbCommand&, CommandContext&), int port)
|
||||
bool RascsiService::Init(const callback& cb, int port)
|
||||
{
|
||||
// Create socket for monitor
|
||||
sockaddr_in server = {};
|
||||
service_socket = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if (service_socket == -1) {
|
||||
LOGERROR("Unable to create socket");
|
||||
LOGERROR("Unable to create socket")
|
||||
return false;
|
||||
}
|
||||
|
||||
server.sin_family = PF_INET;
|
||||
server.sin_port = htons(port);
|
||||
server.sin_port = htons((uint16_t)port);
|
||||
server.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
// Allow address reuse
|
||||
@ -54,7 +54,7 @@ bool RascsiService::Init(bool (e)(PbCommand&, CommandContext&), int port)
|
||||
return false;
|
||||
}
|
||||
|
||||
execute = e;
|
||||
execute = cb;
|
||||
|
||||
monthread = thread(&RascsiService::Execute, this);
|
||||
monthread.detach();
|
||||
@ -64,7 +64,7 @@ bool RascsiService::Init(bool (e)(PbCommand&, CommandContext&), int port)
|
||||
&& signal(SIGTERM, KillHandler) != SIG_ERR;
|
||||
}
|
||||
|
||||
void RascsiService::Execute()
|
||||
void RascsiService::Execute() const
|
||||
{
|
||||
#ifdef __linux__
|
||||
// Scheduler Settings
|
||||
@ -77,62 +77,57 @@ void RascsiService::Execute()
|
||||
ras_util::FixCpu(2);
|
||||
|
||||
// Wait for the execution to start
|
||||
timespec ts = { .tv_sec = 0, .tv_nsec = 1000};
|
||||
while (!running) {
|
||||
usleep(1);
|
||||
nanosleep(&ts, nullptr);
|
||||
}
|
||||
|
||||
// Set up the monitor socket to receive commands
|
||||
listen(service_socket, 1);
|
||||
|
||||
ProtobufSerializer serializer;
|
||||
Localizer localizer;
|
||||
while (true) {
|
||||
CommandContext context(serializer, localizer, -1, "");
|
||||
CommandContext context;
|
||||
|
||||
try {
|
||||
PbCommand command;
|
||||
context.fd = ReadCommand(serializer, command);
|
||||
if (context.fd == -1) {
|
||||
continue;
|
||||
PbCommand command = ReadCommand(context);
|
||||
if (context.IsValid()) {
|
||||
execute(context, command);
|
||||
}
|
||||
|
||||
execute(command, context);
|
||||
}
|
||||
catch(const io_exception& e) {
|
||||
LOGWARN("%s", e.get_msg().c_str())
|
||||
|
||||
// Fall through
|
||||
// Fall through
|
||||
}
|
||||
|
||||
if (context.fd != -1) {
|
||||
close(context.fd);
|
||||
}
|
||||
context.Cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
int RascsiService::ReadCommand(ProtobufSerializer& serializer, PbCommand& command)
|
||||
PbCommand RascsiService::ReadCommand(CommandContext& context) const
|
||||
{
|
||||
// Wait for connection
|
||||
sockaddr client = {};
|
||||
socklen_t socklen = sizeof(client);
|
||||
int fd = accept(service_socket, &client, &socklen);
|
||||
if (fd < 0) {
|
||||
if (fd == -1) {
|
||||
throw io_exception("accept() failed");
|
||||
}
|
||||
|
||||
PbCommand command;
|
||||
|
||||
// Read magic string
|
||||
vector<byte> magic(6);
|
||||
size_t bytes_read = serializer.ReadBytes(fd, magic);
|
||||
if (!bytes_read) {
|
||||
return -1;
|
||||
}
|
||||
if (bytes_read != magic.size() || memcmp(magic.data(), "RASCSI", magic.size())) {
|
||||
if (size_t bytes_read = context.GetSerializer().ReadBytes(fd, magic);
|
||||
bytes_read != magic.size() || memcmp(magic.data(), "RASCSI", magic.size())) {
|
||||
throw io_exception("Invalid magic");
|
||||
}
|
||||
|
||||
// Fetch the command
|
||||
serializer.DeserializeMessage(fd, command);
|
||||
context.GetSerializer().DeserializeMessage(fd, command);
|
||||
|
||||
return fd;
|
||||
context.SetFd(fd);
|
||||
|
||||
return command;
|
||||
}
|
||||
|
@ -10,14 +10,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "rascsi_interface.pb.h"
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
|
||||
class CommandContext;
|
||||
class ProtobufSerializer;
|
||||
|
||||
using namespace std;
|
||||
|
||||
class RascsiService
|
||||
{
|
||||
bool (*execute)(rascsi_interface::PbCommand&, CommandContext&) = nullptr;
|
||||
using callback = function<bool(const CommandContext&, rascsi_interface::PbCommand&)>;
|
||||
|
||||
callback execute;
|
||||
|
||||
int service_socket = -1;
|
||||
|
||||
@ -28,16 +32,17 @@ class RascsiService
|
||||
public:
|
||||
|
||||
RascsiService() = default;
|
||||
~RascsiService();
|
||||
~RascsiService() = default;
|
||||
|
||||
bool Init(bool (ExecuteCommand)(rascsi_interface::PbCommand&, CommandContext&), int);
|
||||
bool Init(const callback&, int);
|
||||
void Cleanup() const;
|
||||
|
||||
bool IsRunning() const { return running; }
|
||||
void SetRunning(bool b) const { running = b; }
|
||||
|
||||
void Execute();
|
||||
void Execute() const;
|
||||
|
||||
int ReadCommand(ProtobufSerializer&, rascsi_interface::PbCommand&);
|
||||
PbCommand ReadCommand(CommandContext&) const;
|
||||
|
||||
static void KillHandler(int) { running = false; }
|
||||
};
|
@ -14,8 +14,8 @@
|
||||
#include "rascsi_version.h"
|
||||
#include "command_util.h"
|
||||
#include "rasutil.h"
|
||||
#include "rasctl_commands.h"
|
||||
#include "rascsi_interface.pb.h"
|
||||
#include "rasctl/rasctl_commands.h"
|
||||
#include <unistd.h>
|
||||
#include <clocale>
|
||||
#include <iostream>
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "hal/gpiobus.h"
|
||||
#include "hal/systimer.h"
|
||||
#include "rascsi_version.h"
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <array>
|
||||
|
||||
@ -258,7 +259,9 @@ bool Selection(int id)
|
||||
// wait for busy
|
||||
count = 10000;
|
||||
do {
|
||||
usleep(20);
|
||||
// Wait 20 microseconds
|
||||
timespec ts = { .tv_sec = 0, .tv_nsec = 20 * 1000};
|
||||
nanosleep(&ts, nullptr);
|
||||
bus.Acquire();
|
||||
if (bus.GetBSY()) {
|
||||
break;
|
||||
@ -289,7 +292,7 @@ bool Command(BYTE *buf, int length)
|
||||
// Send Command
|
||||
count = bus.SendHandShake(buf, length, BUS::SEND_NO_DELAY);
|
||||
|
||||
// Success if the transmission result is the same as the number
|
||||
// Success if the transmission result is the same as the number
|
||||
// of requests
|
||||
if (count == length) {
|
||||
return true;
|
||||
@ -851,7 +854,9 @@ int main(int argc, char* argv[])
|
||||
|
||||
// Assert reset signal
|
||||
bus.SetRST(true);
|
||||
usleep(1000);
|
||||
// Wait 1 ms
|
||||
timespec ts = { .tv_sec = 0, .tv_nsec = 1000 * 1000};
|
||||
nanosleep(&ts, nullptr);
|
||||
bus.SetRST(false);
|
||||
|
||||
// Start dump
|
||||
|
20
src/raspberrypi/test/command_context_test.cpp
Normal file
20
src/raspberrypi/test/command_context_test.cpp
Normal file
@ -0,0 +1,20 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2022 Uwe Seimet
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "mocks.h"
|
||||
#include "rascsi/command_context.h"
|
||||
|
||||
using namespace rascsi_interface;
|
||||
|
||||
TEST(CommandContext, ReturnLocalizedError)
|
||||
{
|
||||
MockCommandContext context;
|
||||
|
||||
EXPECT_FALSE(context.ReturnLocalizedError(LocalizationKey::ERROR_LOG_LEVEL));
|
||||
}
|
@ -59,10 +59,3 @@ TEST(CommandUtil, ParseParameters)
|
||||
TestSpecialDevice("printer");
|
||||
TestSpecialDevice("services");
|
||||
}
|
||||
|
||||
TEST(CommandUtil, ReturnLocalizedError)
|
||||
{
|
||||
MockCommandContext context;
|
||||
|
||||
EXPECT_FALSE(ReturnLocalizedError(context, LocalizationKey::ERROR_LOG_LEVEL));
|
||||
}
|
||||
|
41
src/raspberrypi/test/ctapdriver_test.cpp
Normal file
41
src/raspberrypi/test/ctapdriver_test.cpp
Normal file
@ -0,0 +1,41 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// SCSI Target Emulator RaSCSI Reloaded
|
||||
// for Raspberry Pi
|
||||
//
|
||||
// Copyright (C) 2022 Uwe Seimet
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "mocks.h"
|
||||
#include "devices/ctapdriver.h"
|
||||
|
||||
TEST(CTapDriverTest, Crc32)
|
||||
{
|
||||
array<BYTE, ETH_FRAME_LEN> buf;
|
||||
|
||||
buf.fill(0x00);
|
||||
EXPECT_EQ(0xe3d887bb, CTapDriver::Crc32(buf.data(), ETH_FRAME_LEN));
|
||||
|
||||
buf.fill(0xff);
|
||||
EXPECT_EQ(0x814765f4, CTapDriver::Crc32(buf.data(), ETH_FRAME_LEN));
|
||||
|
||||
buf.fill(0x10);
|
||||
EXPECT_EQ(0xb7288Cd3, CTapDriver::Crc32(buf.data(), ETH_FRAME_LEN));
|
||||
|
||||
buf.fill(0x7f);
|
||||
EXPECT_EQ(0x4b543477, CTapDriver::Crc32(buf.data(), ETH_FRAME_LEN));
|
||||
|
||||
buf.fill(0x80);
|
||||
EXPECT_EQ(0x29cbd638, CTapDriver::Crc32(buf.data(), ETH_FRAME_LEN));
|
||||
|
||||
for (size_t i = 0; i < buf.size(); i++) {
|
||||
buf[i] = (BYTE)i;
|
||||
}
|
||||
EXPECT_EQ(0xe7870705, CTapDriver::Crc32(buf.data(), ETH_FRAME_LEN));
|
||||
|
||||
for (size_t i = buf.size() - 1; i > 0; i--) {
|
||||
buf[i] = (BYTE)i;
|
||||
}
|
||||
EXPECT_EQ(0xe7870705, CTapDriver::Crc32(buf.data(), ETH_FRAME_LEN));
|
||||
}
|
@ -18,9 +18,7 @@
|
||||
#include "devices/scsicd.h"
|
||||
#include "devices/scsimo.h"
|
||||
#include "devices/host_services.h"
|
||||
#include "protobuf_serializer.h"
|
||||
#include "command_context.h"
|
||||
#include "localizer.h"
|
||||
#include "rascsi/command_context.h"
|
||||
|
||||
class MockBus final : public BUS //NOSONAR Having many fields/methods cannot be avoided
|
||||
{
|
||||
@ -273,11 +271,10 @@ class MockHostServices final : public HostServices
|
||||
|
||||
class MockCommandContext : public CommandContext
|
||||
{
|
||||
ProtobufSerializer s;
|
||||
Localizer l;
|
||||
|
||||
public:
|
||||
|
||||
MockCommandContext() : CommandContext(s, l, STDOUT_FILENO, "") {}
|
||||
MockCommandContext() {
|
||||
SetFd(open("/dev/null", O_WRONLY));
|
||||
}
|
||||
~MockCommandContext() = default;
|
||||
};
|
||||
|
@ -19,6 +19,9 @@ TEST(ProtobufSerializerTest, SerializeMessage)
|
||||
PbResult message;
|
||||
ProtobufSerializer serializer;
|
||||
|
||||
serializer.SerializeMessage(STDOUT_FILENO, message);
|
||||
int fd = open("/dev/null", O_WRONLY);
|
||||
ASSERT_NE(-1, fd);
|
||||
serializer.SerializeMessage(fd, message);
|
||||
close(fd);
|
||||
EXPECT_THROW(serializer.SerializeMessage(-1, message), io_exception);
|
||||
}
|
||||
|
@ -8,12 +8,13 @@
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#include "mocks.h"
|
||||
#include "command_util.h"
|
||||
#include "controllers/controller_manager.h"
|
||||
#include "devices/device_factory.h"
|
||||
#include "command_util.h"
|
||||
#include "rascsi_response.h"
|
||||
#include "rascsi_image.h"
|
||||
#include "rascsi_executor.h"
|
||||
#include "rascsi/command_context.h"
|
||||
#include "rascsi/rascsi_response.h"
|
||||
#include "rascsi/rascsi_image.h"
|
||||
#include "rascsi/rascsi_executor.h"
|
||||
|
||||
using namespace rascsi_interface;
|
||||
using namespace command_util;
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "controllers/controller_manager.h"
|
||||
#include "devices/device_factory.h"
|
||||
#include "rascsi_interface.pb.h"
|
||||
#include "rascsi_response.h"
|
||||
#include "rascsi/rascsi_response.h"
|
||||
|
||||
using namespace rascsi_interface;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user