mirror of
https://github.com/akuker/RASCSI.git
synced 2024-06-02 11:41:34 +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 \
|
filepath.cpp \
|
||||||
fileio.cpp \
|
fileio.cpp \
|
||||||
rascsi_version.cpp \
|
rascsi_version.cpp \
|
||||||
rascsi_image.cpp \
|
|
||||||
rascsi_response.cpp \
|
|
||||||
rascsi_executor.cpp \
|
|
||||||
rasutil.cpp \
|
rasutil.cpp \
|
||||||
command_util.cpp \
|
command_util.cpp \
|
||||||
protobuf_serializer.cpp \
|
protobuf_serializer.cpp
|
||||||
localizer.cpp
|
SRC_RASCSI_CORE += $(shell find ./rascsi -name '*.cpp')
|
||||||
SRC_RASCSI_CORE += $(shell find ./controllers -name '*.cpp')
|
SRC_RASCSI_CORE += $(shell find ./controllers -name '*.cpp')
|
||||||
SRC_RASCSI_CORE += $(shell find ./devices -name '*.cpp')
|
SRC_RASCSI_CORE += $(shell find ./devices -name '*.cpp')
|
||||||
SRC_RASCSI_CORE += $(shell find ./hal -name '*.cpp')
|
SRC_RASCSI_CORE += $(shell find ./hal -name '*.cpp')
|
||||||
SRC_RASCSI_CORE += $(SRC_PROTOBUF)
|
|
||||||
|
|
||||||
SRC_RASCSI = rascsi.cpp \
|
SRC_RASCSI = rascsi.cpp
|
||||||
rascsi_service.cpp
|
|
||||||
|
|
||||||
SRC_SCSIMON = \
|
SRC_SCSIMON = \
|
||||||
scsimon.cpp \
|
scsimon.cpp \
|
||||||
|
@ -114,14 +109,11 @@ SRC_SCSIMON += $(shell find ./hal -name '*.cpp')
|
||||||
|
|
||||||
SRC_RASCTL = \
|
SRC_RASCTL = \
|
||||||
rasctl.cpp\
|
rasctl.cpp\
|
||||||
rasctl_commands.cpp \
|
|
||||||
rasctl_display.cpp \
|
|
||||||
rascsi_version.cpp \
|
rascsi_version.cpp \
|
||||||
rasutil.cpp \
|
rasutil.cpp \
|
||||||
command_util.cpp \
|
command_util.cpp \
|
||||||
protobuf_serializer.cpp \
|
protobuf_serializer.cpp
|
||||||
localizer.cpp
|
SRC_RASCTL += $(shell find ./rasctl -name '*.cpp')
|
||||||
SRC_RASCTL += $(SRC_PROTOBUF)
|
|
||||||
|
|
||||||
SRC_RASDUMP = \
|
SRC_RASDUMP = \
|
||||||
rasdump.cpp \
|
rasdump.cpp \
|
||||||
|
@ -134,8 +126,8 @@ SRC_RASDUMP += $(shell find ./hal -name '*.cpp')
|
||||||
SRC_RASCSI_TEST = $(shell find ./test -name '*.cpp')
|
SRC_RASCSI_TEST = $(shell find ./test -name '*.cpp')
|
||||||
|
|
||||||
|
|
||||||
vpath %.h ./ ./controllers ./devices ./monitor ./hal
|
vpath %.h ./ ./controllers ./devices ./monitor ./hal ./rascsi ./rasctl
|
||||||
vpath %.cpp ./ ./controllers ./devices ./monitor ./test ./hal
|
vpath %.cpp ./ ./controllers ./devices ./monitor ./test ./hal ./rascsi ./rasctl
|
||||||
vpath %.o ./$(OBJDIR)
|
vpath %.o ./$(OBJDIR)
|
||||||
vpath ./$(BINDIR)
|
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_RASDUMP := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASDUMP:%.cpp=%.o)))
|
||||||
OBJ_SCSIMON := $(addprefix $(OBJDIR)/,$(notdir $(SRC_SCSIMON:%.cpp=%.o)))
|
OBJ_SCSIMON := $(addprefix $(OBJDIR)/,$(notdir $(SRC_SCSIMON:%.cpp=%.o)))
|
||||||
OBJ_RASCSI_TEST := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASCSI_TEST:%.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
|
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
|
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)
|
$(SRC_RASCSI_CORE): $(SRC_PROTOBUF)
|
||||||
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCSI_CORE) $(OBJ_RASCSI) -lpthread -lpcap -lprotobuf -lstdc++fs
|
|
||||||
|
|
||||||
$(BINDIR)/$(RASCTL): $(SRC_PROTOBUF) $(OBJ_RASCTL) | $(BINDIR)
|
$(BINDIR)/$(RASCSI): $(SRC_PROTOBUF) $(OBJ_RASCSI_CORE) $(OBJ_RASCSI) $(OBJ_PROTOBUF) | $(BINDIR)
|
||||||
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCTL) -lpthread -lprotobuf
|
$(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)
|
$(BINDIR)/$(RASDUMP): $(OBJ_RASDUMP) | $(BINDIR)
|
||||||
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASDUMP)
|
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASDUMP)
|
||||||
|
@ -205,8 +200,8 @@ $(BINDIR)/$(RASDUMP): $(OBJ_RASDUMP) | $(BINDIR)
|
||||||
$(BINDIR)/$(SCSIMON): $(OBJ_SCSIMON) | $(BINDIR)
|
$(BINDIR)/$(SCSIMON): $(OBJ_SCSIMON) | $(BINDIR)
|
||||||
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_SCSIMON) -lpthread
|
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_SCSIMON) -lpthread
|
||||||
|
|
||||||
$(BINDIR)/$(RASCSI_TEST): $(SRC_PROTOBUF) $(OBJ_RASCSI_CORE) $(OBJ_RASCSI_TEST) | $(BINDIR)
|
$(BINDIR)/$(RASCSI_TEST): $(SRC_PROTOBUF) $(OBJ_RASCSI_CORE) $(OBJ_RASCSI_TEST) $(OBJ_PROTOBUF) | $(BINDIR)
|
||||||
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCSI_CORE) $(OBJ_RASCSI_TEST) -lpthread -lpcap -lprotobuf -lstdc++fs -lgmock -lgtest
|
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCSI_CORE) $(OBJ_RASCSI_TEST) $(OBJ_PROTOBUF) -lpthread -lpcap -lprotobuf -lstdc++fs -lgmock -lgtest
|
||||||
|
|
||||||
|
|
||||||
# Phony rules for building individual utilities
|
# 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 "log.h"
|
||||||
#include "rascsi_interface.pb.h"
|
#include "rascsi_interface.pb.h"
|
||||||
#include "localizer.h"
|
|
||||||
#include "protobuf_serializer.h"
|
#include "protobuf_serializer.h"
|
||||||
#include "command_util.h"
|
#include "command_util.h"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
@ -86,51 +85,3 @@ void command_util::AddParam(PbDeviceDefinition& device, const string& key, strin
|
||||||
map[key] = value;
|
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 "google/protobuf/message.h"
|
||||||
#include "rascsi_interface.pb.h"
|
#include "rascsi_interface.pb.h"
|
||||||
#include "command_context.h"
|
|
||||||
#include "localizer.h"
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
using namespace rascsi_interface;
|
using namespace rascsi_interface;
|
||||||
|
|
||||||
namespace command_util
|
namespace command_util
|
||||||
|
@ -27,10 +26,4 @@ namespace command_util
|
||||||
void AddParam(PbCommand&, const string&, string_view);
|
void AddParam(PbCommand&, const string&, string_view);
|
||||||
void AddParam(PbDevice&, const string&, string_view);
|
void AddParam(PbDevice&, const string&, string_view);
|
||||||
void AddParam(PbDeviceDefinition&, 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 {
|
else {
|
||||||
string address = inet;
|
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) {
|
if (size_t separatorPos = inet.find('/'); separatorPos != string::npos) {
|
||||||
address = inet.substr(0, separatorPos);
|
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
|
// 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;
|
uint32_t crc = 0xffffffff;
|
||||||
for (int i = 0; i < length; i++) {
|
for (int i = 0; i < length; i++) {
|
||||||
crc ^= buf[i];
|
crc ^= buf[i];
|
||||||
for (int j = 0; j < 8; j++) {
|
for (int j = 0; j < 8; j++) {
|
||||||
uint32_t mask = -(crc & 1);
|
uint32_t mask = -((int)crc & 1);
|
||||||
crc = (crc >> 1) ^ (0xEDB88320 & mask);
|
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.
|
// 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
|
// The Linux network subsystem removes it, since most software apps shouldn't ever
|
||||||
// need it.
|
// need it.
|
||||||
int crc = crc32(buf, dwReceived);
|
int crc = Crc32(buf, dwReceived);
|
||||||
|
|
||||||
buf[dwReceived + 0] = (BYTE)((crc >> 0) & 0xFF);
|
buf[dwReceived + 0] = (BYTE)((crc >> 0) & 0xFF);
|
||||||
buf[dwReceived + 1] = (BYTE)((crc >> 8) & 0xFF);
|
buf[dwReceived + 1] = (BYTE)((crc >> 8) & 0xFF);
|
||||||
|
|
|
@ -46,6 +46,8 @@ public:
|
||||||
bool Disable() const; // Disable the ras0 interface
|
bool Disable() const; // Disable the ras0 interface
|
||||||
void Flush(); // Purge all of the packets that are waiting to be processed
|
void Flush(); // Purge all of the packets that are waiting to be processed
|
||||||
|
|
||||||
|
static uint32_t Crc32(const BYTE *, int);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
array<byte, 6> m_MacAddr; // MAC Address
|
array<byte, 6> m_MacAddr; // MAC Address
|
||||||
|
|
||||||
|
|
|
@ -41,9 +41,9 @@ DeviceFactory::DeviceFactory()
|
||||||
}
|
}
|
||||||
|
|
||||||
default_params[SCBR]["interface"] = network_interfaces;
|
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]["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]["cmd"] = "lp -oraw %f";
|
||||||
default_params[SCLP]["timeout"] = "30";
|
default_params[SCLP]["timeout"] = "30";
|
||||||
|
|
||||||
|
|
|
@ -11,11 +11,10 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <vector>
|
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <string>
|
|
||||||
#include "rascsi_interface.pb.h"
|
#include "rascsi_interface.pb.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
@ -26,6 +25,8 @@ class PrimaryDevice;
|
||||||
|
|
||||||
class DeviceFactory
|
class DeviceFactory
|
||||||
{
|
{
|
||||||
|
const string DEFAULT_IP = "10.10.20.1/24"; //NOSONAR This hardcoded IP address is safe
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
DeviceFactory();
|
DeviceFactory();
|
||||||
|
@ -41,14 +42,14 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
string GetExtension(const string&) const;
|
||||||
|
|
||||||
unordered_map<PbDeviceType, unordered_set<uint32_t>> sector_sizes;
|
unordered_map<PbDeviceType, unordered_set<uint32_t>> sector_sizes;
|
||||||
|
|
||||||
unordered_map<PbDeviceType, unordered_map<string, string>> default_params;
|
unordered_map<PbDeviceType, unordered_map<string, string>> default_params;
|
||||||
|
|
||||||
unordered_map<string, PbDeviceType> extension_mapping;
|
unordered_map<string, PbDeviceType> extension_mapping;
|
||||||
|
|
||||||
string GetExtension(const string&) const;
|
|
||||||
|
|
||||||
unordered_set<uint32_t> empty_set;
|
unordered_set<uint32_t> empty_set;
|
||||||
unordered_map<string, string> empty_map;
|
unordered_map<string, string> empty_map;
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,10 +23,8 @@
|
||||||
using namespace scsi_command_util;
|
using namespace scsi_command_util;
|
||||||
|
|
||||||
SCSIHD::SCSIHD(int lun, const unordered_set<uint32_t>& sector_sizes, bool removable, scsi_defs::scsi_level level)
|
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);
|
SetSectorSizes(sector_sizes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,11 +14,6 @@
|
||||||
#include "fileio.h"
|
#include "fileio.h"
|
||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
|
|
||||||
Filepath::Filepath()
|
|
||||||
{
|
|
||||||
Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
Filepath& Filepath::operator=(const Filepath& path)
|
Filepath& Filepath::operator=(const Filepath& path)
|
||||||
{
|
{
|
||||||
// Set path (split internally)
|
// Set path (split internally)
|
||||||
|
@ -27,15 +22,6 @@ Filepath& Filepath::operator=(const Filepath& path)
|
||||||
return *this;
|
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
|
// File settings (user) for MBCS
|
||||||
|
|
|
@ -14,8 +14,6 @@
|
||||||
|
|
||||||
using TCHAR = char;
|
using TCHAR = char;
|
||||||
|
|
||||||
class Fileio;
|
|
||||||
|
|
||||||
static const int _MAX_EXT = 256;
|
static const int _MAX_EXT = 256;
|
||||||
static const int _MAX_DIR = 256;
|
static const int _MAX_DIR = 256;
|
||||||
static const int _MAX_PATH = 260;
|
static const int _MAX_PATH = 260;
|
||||||
|
@ -30,15 +28,13 @@ static const int FILEPATH_MAX = _MAX_PATH;
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
class Filepath
|
class Filepath
|
||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Filepath();
|
Filepath() = default;
|
||||||
virtual ~Filepath() = default;
|
~Filepath() = default;
|
||||||
Filepath(Filepath&) = default;
|
Filepath(Filepath&) = default;
|
||||||
Filepath& operator=(const Filepath&);
|
Filepath& operator=(const Filepath&);
|
||||||
|
|
||||||
void Clear();
|
|
||||||
void SetPath(const char *); // File settings (user) for MBCS
|
void SetPath(const char *); // File settings (user) for MBCS
|
||||||
const char *GetPath() const { return m_szPath; } // Get path name
|
const char *GetPath() const { return m_szPath; } // Get path name
|
||||||
const char *GetFileExt() const; // Get short name (LPCTSTR)
|
const char *GetFileExt() const; // Get short name (LPCTSTR)
|
||||||
|
@ -46,10 +42,10 @@ public:
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Split(); // Split the path
|
void Split(); // Split the path
|
||||||
TCHAR m_szPath[_MAX_PATH]; // File path
|
TCHAR m_szPath[_MAX_PATH] = {}; // File path
|
||||||
TCHAR m_szDir[_MAX_DIR]; // Directory
|
TCHAR m_szDir[_MAX_DIR] = {}; // Directory
|
||||||
TCHAR m_szFile[_MAX_FNAME]; // File
|
TCHAR m_szFile[_MAX_FNAME] = {}; // File
|
||||||
TCHAR m_szExt[_MAX_EXT]; // Extension
|
TCHAR m_szExt[_MAX_EXT] = {}; // Extension
|
||||||
|
|
||||||
static TCHAR FileExt[_MAX_FNAME + _MAX_DIR]; // Short name (TCHAR)
|
static TCHAR FileExt[_MAX_FNAME + _MAX_DIR]; // Short name (TCHAR)
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
#include "rascsi_interface.pb.h"
|
#include "rascsi_interface.pb.h"
|
||||||
#include "rascsi_exceptions.h"
|
|
||||||
#include "protobuf_serializer.h"
|
#include "protobuf_serializer.h"
|
||||||
|
#include "rascsi_exceptions.h"
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
#include "google/protobuf/message.h"
|
#include "google/protobuf/message.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
class ProtobufSerializer
|
class ProtobufSerializer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -11,11 +11,10 @@
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "log.h"
|
||||||
#include "controllers/controller_manager.h"
|
#include "controllers/controller_manager.h"
|
||||||
#include "controllers/scsi_controller.h"
|
#include "controllers/scsi_controller.h"
|
||||||
#include "devices/device_factory.h"
|
#include "devices/device_factory.h"
|
||||||
#include "devices/device.h"
|
|
||||||
#include "devices/disk.h"
|
|
||||||
#include "devices/file_support.h"
|
#include "devices/file_support.h"
|
||||||
#include "hal/gpiobus.h"
|
#include "hal/gpiobus.h"
|
||||||
#include "hal/systimer.h"
|
#include "hal/systimer.h"
|
||||||
|
@ -23,11 +22,11 @@
|
||||||
#include "protobuf_serializer.h"
|
#include "protobuf_serializer.h"
|
||||||
#include "command_util.h"
|
#include "command_util.h"
|
||||||
#include "rascsi_version.h"
|
#include "rascsi_version.h"
|
||||||
#include "rascsi_executor.h"
|
|
||||||
#include "rascsi_response.h"
|
|
||||||
#include "rascsi_image.h"
|
|
||||||
#include "rascsi_interface.pb.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 "rasutil.h"
|
||||||
#include "spdlog/spdlog.h"
|
#include "spdlog/spdlog.h"
|
||||||
#include "spdlog/sinks/stdout_color_sinks.h"
|
#include "spdlog/sinks/stdout_color_sinks.h"
|
||||||
|
@ -51,7 +50,6 @@ using namespace command_util;
|
||||||
// Constant declarations
|
// Constant declarations
|
||||||
//
|
//
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
#define FPRT(fp, ...) fprintf(fp, __VA_ARGS__ )
|
|
||||||
static const int DEFAULT_PORT = 6868;
|
static const int DEFAULT_PORT = 6868;
|
||||||
static const char COMPONENT_SEPARATOR = ':';
|
static const char COMPONENT_SEPARATOR = ':';
|
||||||
|
|
||||||
|
@ -74,32 +72,28 @@ const ProtobufSerializer serializer;
|
||||||
|
|
||||||
void Banner(int argc, char* argv[])
|
void Banner(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
FPRT(stdout,"SCSI Target Emulator RaSCSI Reloaded ");
|
cout << "SCSI Target Emulator RaSCSI Reloaded version " << rascsi_get_version_string()
|
||||||
FPRT(stdout,"version %s (%s, %s)\n",
|
<< " (" << __DATE__ << ' ' << __TIME__ << ')' << endl;
|
||||||
rascsi_get_version_string().c_str(),
|
cout << "Powered by XM6 TypeG Technology / ";
|
||||||
__DATE__,
|
cout << "Copyright (C) 2016-2020 GIMONS" << endl;
|
||||||
__TIME__);
|
cout << "Copyright (C) 2020-2022 Contributors to the RaSCSI Reloaded project" << endl;
|
||||||
FPRT(stdout,"Powered by XM6 TypeG Technology / ");
|
cout << "Connect type: " << CONNECT_DESC << endl;
|
||||||
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());
|
|
||||||
|
|
||||||
if ((argc > 1 && strcmp(argv[1], "-h") == 0) ||
|
if ((argc > 1 && strcmp(argv[1], "-h") == 0) || (argc > 1 && strcmp(argv[1], "--help") == 0)){
|
||||||
(argc > 1 && strcmp(argv[1], "--help") == 0)){
|
cout << endl;
|
||||||
FPRT(stdout,"\n");
|
cout << "Usage: " << argv[0] << " [-idn[:m] FILE] ..." << endl << endl;
|
||||||
FPRT(stdout,"Usage: %s [-idn[:m] FILE] ...\n\n", argv[0]);
|
cout << " n is SCSI device ID (0-7)." << endl;
|
||||||
FPRT(stdout," n is SCSI device ID (0-7).\n");
|
cout << " m is the optional logical unit (LUN) (0-31)." << endl;
|
||||||
FPRT(stdout," m is the optional logical unit (LUN) (0-31).\n");
|
cout << " FILE is a disk image file, \"daynaport\", \"bridge\", \"printer\" or \"services\"." << endl << endl;
|
||||||
FPRT(stdout," FILE is a disk image file, \"daynaport\", \"bridge\", \"printer\" or \"services\".\n\n");
|
cout << " Image type is detected based on file extension if no explicit type is specified." << endl;
|
||||||
FPRT(stdout," Image type is detected based on file extension if no explicit type is specified.\n");
|
cout << " hd1 : SCSI-1 HD image (Non-removable generic SCSI-1 HD image)" << endl;
|
||||||
FPRT(stdout," hd1 : SCSI-1 HD image (Non-removable generic SCSI-1 HD image)\n");
|
cout << " hds : SCSI HD image (Non-removable generic SCSI HD image)" << endl;
|
||||||
FPRT(stdout," hds : SCSI HD image (Non-removable generic SCSI HD image)\n");
|
cout << " hdr : SCSI HD image (Removable generic HD image)" << endl;
|
||||||
FPRT(stdout," hdr : SCSI HD image (Removable generic HD image)\n");
|
cout << " hdn : SCSI HD image (NEC GENUINE)" << endl;
|
||||||
FPRT(stdout," hdn : SCSI HD image (NEC GENUINE)\n");
|
cout << " hdi : SCSI HD image (Anex86 HD image)" << endl;
|
||||||
FPRT(stdout," hdi : SCSI HD image (Anex86 HD image)\n");
|
cout << " nhd : SCSI HD image (T98Next HD image)" << endl;
|
||||||
FPRT(stdout," nhd : SCSI HD image (T98Next HD image)\n");
|
cout << " mos : SCSI MO image (MO image)" << endl;
|
||||||
FPRT(stdout," mos : SCSI MO image (MO image)\n");
|
cout << " iso : SCSI CD image (ISO 9660 image)" << endl;
|
||||||
FPRT(stdout," iso : SCSI CD image (ISO 9660 image)\n");
|
|
||||||
|
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
@ -122,6 +116,8 @@ void Cleanup()
|
||||||
{
|
{
|
||||||
executor.DetachAll();
|
executor.DetachAll();
|
||||||
|
|
||||||
|
service.Cleanup();
|
||||||
|
|
||||||
// Clean up and discard the bus
|
// Clean up and discard the bus
|
||||||
bus.Cleanup();
|
bus.Cleanup();
|
||||||
}
|
}
|
||||||
|
@ -359,9 +355,7 @@ bool ParseArgument(int argc, char* argv[], int& port)
|
||||||
// Attach all specified devices
|
// Attach all specified devices
|
||||||
command.set_operation(ATTACH);
|
command.set_operation(ATTACH);
|
||||||
|
|
||||||
Localizer localizer;
|
if (CommandContext context(locale); !executor.ProcessCmd(context, command)) {
|
||||||
CommandContext context(serializer, localizer, -1, locale);
|
|
||||||
if (!executor.ProcessCmd(context, command)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,21 +370,16 @@ bool ParseArgument(int argc, char* argv[], int& port)
|
||||||
return true;
|
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")) {
|
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())) {
|
if (!PbOperation_IsValid(command.operation())) {
|
||||||
LOGERROR("Received unknown command with operation opcode %d", 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())
|
LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str())
|
||||||
|
@ -401,35 +390,35 @@ static bool ExecuteCommand(PbCommand& command, CommandContext& context)
|
||||||
case LOG_LEVEL: {
|
case LOG_LEVEL: {
|
||||||
string log_level = GetParam(command, "level");
|
string log_level = GetParam(command, "level");
|
||||||
if (bool status = executor.SetLogLevel(log_level); !status) {
|
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 {
|
else {
|
||||||
current_log_level = log_level;
|
current_log_level = log_level;
|
||||||
|
|
||||||
ReturnStatus(context);
|
context.ReturnStatus();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case DEFAULT_FOLDER: {
|
case DEFAULT_FOLDER: {
|
||||||
if (string status = rascsi_image.SetDefaultFolder(GetParam(command, "folder")); !status.empty()) {
|
if (string status = rascsi_image.SetDefaultFolder(GetParam(command, "folder")); !status.empty()) {
|
||||||
ReturnStatus(context, false, status);
|
context.ReturnStatus(false, status);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ReturnStatus(context);
|
context.ReturnStatus();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case DEVICES_INFO: {
|
case DEVICES_INFO: {
|
||||||
rascsi_response.GetDevicesInfo(result, command, rascsi_image.GetDefaultFolder());
|
rascsi_response.GetDevicesInfo(result, command, rascsi_image.GetDefaultFolder());
|
||||||
serializer.SerializeMessage(context.fd, result);
|
serializer.SerializeMessage(context.GetFd(), result);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case DEVICE_TYPES_INFO: {
|
case DEVICE_TYPES_INFO: {
|
||||||
result.set_allocated_device_types_info(rascsi_response.GetDeviceTypesInfo(result).release());
|
result.set_allocated_device_types_info(rascsi_response.GetDeviceTypesInfo(result).release());
|
||||||
serializer.SerializeMessage(context.fd, result);
|
serializer.SerializeMessage(context.GetFd(), result);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -438,19 +427,19 @@ static bool ExecuteCommand(PbCommand& command, CommandContext& context)
|
||||||
result, executor.GetReservedIds(), current_log_level, rascsi_image.GetDefaultFolder(),
|
result, executor.GetReservedIds(), current_log_level, rascsi_image.GetDefaultFolder(),
|
||||||
GetParam(command, "folder_pattern"), GetParam(command, "file_pattern"),
|
GetParam(command, "folder_pattern"), GetParam(command, "file_pattern"),
|
||||||
rascsi_image.GetDepth()).release());
|
rascsi_image.GetDepth()).release());
|
||||||
serializer.SerializeMessage(context.fd, result);
|
serializer.SerializeMessage(context.GetFd(), result);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case VERSION_INFO: {
|
case VERSION_INFO: {
|
||||||
result.set_allocated_version_info(rascsi_response.GetVersionInfo(result).release());
|
result.set_allocated_version_info(rascsi_response.GetVersionInfo(result).release());
|
||||||
serializer.SerializeMessage(context.fd, result);
|
serializer.SerializeMessage(context.GetFd(), result);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case LOG_LEVEL_INFO: {
|
case LOG_LEVEL_INFO: {
|
||||||
result.set_allocated_log_level_info(rascsi_response.GetLogLevelInfo(result, current_log_level).release());
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -458,13 +447,13 @@ static bool ExecuteCommand(PbCommand& command, CommandContext& context)
|
||||||
result.set_allocated_image_files_info(rascsi_response.GetAvailableImages(result,
|
result.set_allocated_image_files_info(rascsi_response.GetAvailableImages(result,
|
||||||
rascsi_image.GetDefaultFolder(), GetParam(command, "folder_pattern"),
|
rascsi_image.GetDefaultFolder(), GetParam(command, "folder_pattern"),
|
||||||
GetParam(command, "file_pattern"), rascsi_image.GetDepth()).release());
|
GetParam(command, "file_pattern"), rascsi_image.GetDepth()).release());
|
||||||
serializer.SerializeMessage(context.fd, result);
|
serializer.SerializeMessage(context.GetFd(), result);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case IMAGE_FILE_INFO: {
|
case IMAGE_FILE_INFO: {
|
||||||
if (string filename = GetParam(command, "file"); filename.empty()) {
|
if (string filename = GetParam(command, "file"); filename.empty()) {
|
||||||
ReturnLocalizedError(context, LocalizationKey::ERROR_MISSING_FILENAME);
|
context.ReturnLocalizedError( LocalizationKey::ERROR_MISSING_FILENAME);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
auto image_file = make_unique<PbImageFile>();
|
auto image_file = make_unique<PbImageFile>();
|
||||||
|
@ -472,10 +461,10 @@ static bool ExecuteCommand(PbCommand& command, CommandContext& context)
|
||||||
if (status) {
|
if (status) {
|
||||||
result.set_status(true);
|
result.set_status(true);
|
||||||
result.set_allocated_image_file_info(image_file.get());
|
result.set_allocated_image_file_info(image_file.get());
|
||||||
serializer.SerializeMessage(context.fd, result);
|
serializer.SerializeMessage(context.GetFd(), result);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ReturnLocalizedError(context, LocalizationKey::ERROR_IMAGE_FILE_INFO);
|
context.ReturnLocalizedError(LocalizationKey::ERROR_IMAGE_FILE_INFO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -483,27 +472,27 @@ static bool ExecuteCommand(PbCommand& command, CommandContext& context)
|
||||||
|
|
||||||
case NETWORK_INTERFACES_INFO: {
|
case NETWORK_INTERFACES_INFO: {
|
||||||
result.set_allocated_network_interfaces_info(rascsi_response.GetNetworkInterfacesInfo(result).release());
|
result.set_allocated_network_interfaces_info(rascsi_response.GetNetworkInterfacesInfo(result).release());
|
||||||
serializer.SerializeMessage(context.fd, result);
|
serializer.SerializeMessage(context.GetFd(), result);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case MAPPING_INFO: {
|
case MAPPING_INFO: {
|
||||||
result.set_allocated_mapping_info(rascsi_response.GetMappingInfo(result).release());
|
result.set_allocated_mapping_info(rascsi_response.GetMappingInfo(result).release());
|
||||||
serializer.SerializeMessage(context.fd, result);
|
serializer.SerializeMessage(context.GetFd(), result);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OPERATION_INFO: {
|
case OPERATION_INFO: {
|
||||||
result.set_allocated_operation_info(rascsi_response.GetOperationInfo(result,
|
result.set_allocated_operation_info(rascsi_response.GetOperationInfo(result,
|
||||||
rascsi_image.GetDepth()).release());
|
rascsi_image.GetDepth()).release());
|
||||||
serializer.SerializeMessage(context.fd, result);
|
serializer.SerializeMessage(context.GetFd(), result);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case RESERVED_IDS_INFO: {
|
case RESERVED_IDS_INFO: {
|
||||||
result.set_allocated_reserved_ids_info(rascsi_response.GetReservedIds(result,
|
result.set_allocated_reserved_ids_info(rascsi_response.GetReservedIds(result,
|
||||||
executor.GetReservedIds()).release());
|
executor.GetReservedIds()).release());
|
||||||
serializer.SerializeMessage(context.fd, result);
|
serializer.SerializeMessage(context.GetFd(), result);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -516,8 +505,9 @@ static bool ExecuteCommand(PbCommand& command, CommandContext& context)
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
// Wait until we become idle
|
// Wait until we become idle
|
||||||
|
timespec ts = { .tv_sec = 0, .tv_nsec = 500 * 1000 * 1000};
|
||||||
while (active) {
|
while (active) {
|
||||||
usleep(500 * 1000);
|
nanosleep(&ts, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
executor.ProcessCmd(context, command);
|
executor.ProcessCmd(context, command);
|
||||||
|
@ -609,7 +599,8 @@ int main(int argc, char* argv[])
|
||||||
#else
|
#else
|
||||||
bus.Acquire();
|
bus.Acquire();
|
||||||
if (!bus.GetSEL()) {
|
if (!bus.GetSEL()) {
|
||||||
usleep(0);
|
timespec ts = { .tv_sec = 0, .tv_nsec = 0};
|
||||||
|
nanosleep(&ts, nullptr);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#endif
|
#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 "rascsi_exceptions.h"
|
||||||
#include "localizer.h"
|
#include "localizer.h"
|
||||||
#include "command_util.h"
|
#include "command_util.h"
|
||||||
|
#include "command_context.h"
|
||||||
#include "rasutil.h"
|
#include "rasutil.h"
|
||||||
#include "spdlog/spdlog.h"
|
#include "spdlog/spdlog.h"
|
||||||
#include "rascsi_executor.h"
|
#include "rascsi_executor.h"
|
||||||
|
@ -87,7 +88,7 @@ bool RascsiExecutor::ProcessCmd(const CommandContext& context, const PbDeviceDef
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_OPERATION);
|
return context.ReturnLocalizedError(LocalizationKey::ERROR_OPERATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -98,15 +99,15 @@ bool RascsiExecutor::ProcessCmd(const CommandContext& context, const PbCommand&
|
||||||
switch (command.operation()) {
|
switch (command.operation()) {
|
||||||
case DETACH_ALL:
|
case DETACH_ALL:
|
||||||
DetachAll();
|
DetachAll();
|
||||||
return ReturnStatus(context);
|
return context.ReturnStatus();
|
||||||
|
|
||||||
case RESERVE_IDS: {
|
case RESERVE_IDS: {
|
||||||
const string ids = GetParam(command, "ids");
|
const string ids = GetParam(command, "ids");
|
||||||
if (string error = SetReservedIds(ids); !error.empty()) {
|
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:
|
case CREATE_IMAGE:
|
||||||
|
@ -144,7 +145,7 @@ bool RascsiExecutor::ProcessCmd(const CommandContext& context, const PbCommand&
|
||||||
FileSupport::SetReservedFiles(reserved_files);
|
FileSupport::SetReservedFiles(reserved_files);
|
||||||
|
|
||||||
if (string result = ValidateLunSetup(command); !result.empty()) {
|
if (string result = ValidateLunSetup(command); !result.empty()) {
|
||||||
return ReturnStatus(context, false, result);
|
return context.ReturnStatus(false, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& device : command.devices()) {
|
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
|
// 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
|
// A new command with an empty device list is required here in order to return data for all devices
|
||||||
PbCommand cmd;
|
PbCommand cmd;
|
||||||
PbResult result;
|
PbResult result;
|
||||||
rascsi_response.GetDevicesInfo(result, cmd, rascsi_image.GetDefaultFolder());
|
rascsi_response.GetDevicesInfo(result, cmd, rascsi_image.GetDefaultFolder());
|
||||||
serializer.SerializeMessage(context.fd, result);
|
serializer.SerializeMessage(context.GetFd(), result);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ReturnStatus(context);
|
return context.ReturnStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RascsiExecutor::SetLogLevel(const string& log_level) const
|
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();
|
const PbDeviceType type = pb_device.type();
|
||||||
|
|
||||||
if (lun >= ScsiController::LUN_MAX) {
|
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) {
|
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()) {
|
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");
|
string filename = GetParam(pb_device, "file");
|
||||||
|
@ -305,7 +306,7 @@ bool RascsiExecutor::Attach(const CommandContext& context, const PbDeviceDefinit
|
||||||
if (file_support != nullptr) {
|
if (file_support != nullptr) {
|
||||||
// File check (type is HD, for removable media drives, CD and MO the medium (=file) may be inserted later
|
// File check (type is HD, for removable media drives, CD and MO the medium (=file) may be inserted later
|
||||||
if (!device->IsRemovable() && filename.empty()) {
|
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)) {
|
if (!ValidateImageFile(context, device, filename, full_path)) {
|
||||||
|
@ -330,12 +331,12 @@ bool RascsiExecutor::Attach(const CommandContext& context, const PbDeviceDefinit
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!device->Init(params)) {
|
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));
|
to_string(id), to_string(lun));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!controller_manager.AttachToScsiController(id, device)) {
|
if (!controller_manager.AttachToScsiController(id, device)) {
|
||||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_SCSI_CONTROLLER);
|
return context.ReturnLocalizedError(LocalizationKey::ERROR_SCSI_CONTROLLER);
|
||||||
}
|
}
|
||||||
|
|
||||||
Filepath filepath;
|
Filepath filepath;
|
||||||
|
@ -359,16 +360,16 @@ bool RascsiExecutor::Insert(const CommandContext& context, const PbDeviceDefinit
|
||||||
shared_ptr<PrimaryDevice> device, bool dryRun) const
|
shared_ptr<PrimaryDevice> device, bool dryRun) const
|
||||||
{
|
{
|
||||||
if (!device->IsRemoved()) {
|
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()) {
|
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");
|
string filename = GetParam(pb_device, "file");
|
||||||
if (filename.empty()) {
|
if (filename.empty()) {
|
||||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_MISSING_FILENAME);
|
return context.ReturnLocalizedError(LocalizationKey::ERROR_MISSING_FILENAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dryRun) {
|
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
|
// LUN 0 can only be detached if there is no other LUN anymore
|
||||||
if (!device->GetLun() && controller_manager.FindController(device->GetId())->GetLunCount() > 1) {
|
if (!device->GetLun() && controller_manager.FindController(device->GetId())->GetLunCount() > 1) {
|
||||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_LUN0);
|
return context.ReturnLocalizedError(LocalizationKey::ERROR_LUN0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dryRun) {
|
if (!dryRun) {
|
||||||
|
@ -422,7 +423,7 @@ bool RascsiExecutor::Detach(const CommandContext& context, shared_ptr<PrimaryDev
|
||||||
|
|
||||||
auto controller = controller_manager.FindController(device->GetId());
|
auto controller = controller_manager.FindController(device->GetId());
|
||||||
if (controller == nullptr || !controller->DeleteDevice(device)) {
|
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
|
// 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) {
|
bool RascsiExecutor::ShutDown(const CommandContext& context, const string& mode) {
|
||||||
if (mode.empty()) {
|
if (mode.empty()) {
|
||||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_SHUTDOWN_MODE_MISSING);
|
return context.ReturnLocalizedError(LocalizationKey::ERROR_SHUTDOWN_MODE_MISSING);
|
||||||
}
|
}
|
||||||
|
|
||||||
PbResult result;
|
PbResult result;
|
||||||
|
@ -455,24 +456,24 @@ bool RascsiExecutor::ShutDown(const CommandContext& context, const string& mode)
|
||||||
if (mode == "rascsi") {
|
if (mode == "rascsi") {
|
||||||
LOGINFO("RaSCSI shutdown requested")
|
LOGINFO("RaSCSI shutdown requested")
|
||||||
|
|
||||||
serializer.SerializeMessage(context.fd, result);
|
serializer.SerializeMessage(context.GetFd(), result);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode != "system" && mode != "reboot") {
|
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
|
// The root user has UID 0
|
||||||
if (getuid()) {
|
if (getuid()) {
|
||||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_SHUTDOWN_PERMISSION);
|
return context.ReturnLocalizedError(LocalizationKey::ERROR_SHUTDOWN_PERMISSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode == "system") {
|
if (mode == "system") {
|
||||||
LOGINFO("System shutdown requested")
|
LOGINFO("System shutdown requested")
|
||||||
|
|
||||||
serializer.SerializeMessage(context.fd, result);
|
serializer.SerializeMessage(context.GetFd(), result);
|
||||||
|
|
||||||
DetachAll();
|
DetachAll();
|
||||||
|
|
||||||
|
@ -483,7 +484,7 @@ bool RascsiExecutor::ShutDown(const CommandContext& context, const string& mode)
|
||||||
else if (mode == "reboot") {
|
else if (mode == "reboot") {
|
||||||
LOGINFO("System reboot requested")
|
LOGINFO("System reboot requested")
|
||||||
|
|
||||||
serializer.SerializeMessage(context.fd, result);
|
serializer.SerializeMessage(context.GetFd(), result);
|
||||||
|
|
||||||
DetachAll();
|
DetachAll();
|
||||||
|
|
||||||
|
@ -559,7 +560,7 @@ bool RascsiExecutor::ValidateImageFile(const CommandContext& context, shared_ptr
|
||||||
filepath.SetPath(filename.c_str());
|
filepath.SetPath(filename.c_str());
|
||||||
|
|
||||||
if (FileSupport::GetIdsForReservedFile(filepath, id, lun)) {
|
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));
|
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());
|
filepath.SetPath((rascsi_image.GetDefaultFolder() + "/" + filename).c_str());
|
||||||
|
|
||||||
if (FileSupport::GetIdsForReservedFile(filepath, id, lun)) {
|
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));
|
to_string(id), to_string(lun));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -579,7 +580,7 @@ bool RascsiExecutor::ValidateImageFile(const CommandContext& context, shared_ptr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(const io_exception& e) {
|
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();
|
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
|
bool RascsiExecutor::VerifyExistingIdAndLun(const CommandContext& context, int id, int lun) const
|
||||||
{
|
{
|
||||||
if (controller_manager.FindController(id) == nullptr) {
|
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) {
|
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;
|
return true;
|
||||||
|
@ -672,10 +673,10 @@ shared_ptr<PrimaryDevice> RascsiExecutor::CreateDevice(const CommandContext& con
|
||||||
auto device = device_factory.CreateDevice(controller_manager, type, lun, filename);
|
auto device = device_factory.CreateDevice(controller_manager, type, lun, filename);
|
||||||
if (device == nullptr) {
|
if (device == nullptr) {
|
||||||
if (type == UNDEFINED) {
|
if (type == UNDEFINED) {
|
||||||
ReturnLocalizedError(context, LocalizationKey::ERROR_MISSING_DEVICE_TYPE, filename);
|
context.ReturnLocalizedError(LocalizationKey::ERROR_MISSING_DEVICE_TYPE, filename);
|
||||||
}
|
}
|
||||||
else {
|
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);
|
auto disk = dynamic_pointer_cast<Disk>(device);
|
||||||
if (disk != nullptr && disk->IsSectorSizeConfigurable()) {
|
if (disk != nullptr && disk->IsSectorSizeConfigurable()) {
|
||||||
if (!disk->SetConfiguredSectorSize(device_factory, block_size)) {
|
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 {
|
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();
|
const string& type = device->GetType();
|
||||||
|
|
||||||
if ((operation == START || operation == STOP) && !device->IsStoppable()) {
|
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()) {
|
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()) {
|
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()) {
|
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;
|
return true;
|
||||||
|
@ -728,13 +729,13 @@ bool RascsiExecutor::ValidateIdAndLun(const CommandContext& context, int id, int
|
||||||
{
|
{
|
||||||
// Validate the device ID and LUN
|
// Validate the device ID and LUN
|
||||||
if (id < 0) {
|
if (id < 0) {
|
||||||
return ReturnLocalizedError(context, LocalizationKey::ERROR_MISSING_DEVICE_ID);
|
return context.ReturnLocalizedError(LocalizationKey::ERROR_MISSING_DEVICE_ID);
|
||||||
}
|
}
|
||||||
if (id >= ControllerManager::DEVICE_MAX) {
|
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) {
|
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;
|
return true;
|
||||||
|
@ -755,7 +756,7 @@ bool RascsiExecutor::SetProductData(const CommandContext& context, const PbDevic
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(const invalid_argument& e) {
|
catch(const invalid_argument& e) {
|
||||||
return ReturnStatus(context, false, e.what());
|
return context.ReturnStatus(false, e.what());
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
|
@ -14,6 +14,7 @@
|
||||||
#include "spdlog/spdlog.h"
|
#include "spdlog/spdlog.h"
|
||||||
#include "devices/file_support.h"
|
#include "devices/file_support.h"
|
||||||
#include "command_util.h"
|
#include "command_util.h"
|
||||||
|
#include "command_context.h"
|
||||||
#include "rascsi_image.h"
|
#include "rascsi_image.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
@ -48,7 +49,7 @@ bool RascsiImage::CreateImageFolder(const CommandContext& context, const string&
|
||||||
std::error_code error;
|
std::error_code error;
|
||||||
filesystem::create_directories(folder, error);
|
filesystem::create_directories(folder, error);
|
||||||
if (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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,21 +107,21 @@ bool RascsiImage::CreateImage(const CommandContext& context, const PbCommand& co
|
||||||
{
|
{
|
||||||
string filename = GetParam(command, "file");
|
string filename = GetParam(command, "file");
|
||||||
if (filename.empty()) {
|
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)) {
|
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);
|
string full_filename = GetFullName(filename);
|
||||||
if (!IsValidDstFilename(full_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");
|
const string size = GetParam(command, "size");
|
||||||
if (size.empty()) {
|
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;
|
off_t len;
|
||||||
|
@ -128,13 +129,13 @@ bool RascsiImage::CreateImage(const CommandContext& context, const PbCommand& co
|
||||||
len = stoull(size);
|
len = stoull(size);
|
||||||
}
|
}
|
||||||
catch(const invalid_argument&) {
|
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&) {
|
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)) {
|
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)) {
|
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);
|
int image_fd = open(full_filename.c_str(), O_CREAT|O_WRONLY, permissions);
|
||||||
if (image_fd == -1) {
|
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__
|
#ifndef __linux__
|
||||||
|
@ -163,7 +164,7 @@ bool RascsiImage::CreateImage(const CommandContext& context, const PbCommand& co
|
||||||
|
|
||||||
unlink(full_filename.c_str());
|
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);
|
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 +
|
LOGINFO("%s", string("Created " + string(permissions & S_IWUSR ? "": "read-only ") + "image file '" + full_filename +
|
||||||
"' with a size of " + to_string(len) + " bytes").c_str())
|
"' with a size of " + to_string(len) + " bytes").c_str())
|
||||||
|
|
||||||
return ReturnStatus(context);
|
return context.ReturnStatus();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,11 +180,11 @@ bool RascsiImage::DeleteImage(const CommandContext& context, const PbCommand& co
|
||||||
{
|
{
|
||||||
string filename = GetParam(command, "file");
|
string filename = GetParam(command, "file");
|
||||||
if (filename.empty()) {
|
if (filename.empty()) {
|
||||||
return ReturnStatus(context, false, "Missing image filename");
|
return context.ReturnStatus(false, "Missing image filename");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CheckDepth(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);
|
string full_filename = GetFullName(filename);
|
||||||
|
@ -193,12 +194,12 @@ bool RascsiImage::DeleteImage(const CommandContext& context, const PbCommand& co
|
||||||
Filepath filepath;
|
Filepath filepath;
|
||||||
filepath.SetPath(full_filename.c_str());
|
filepath.SetPath(full_filename.c_str());
|
||||||
if (FileSupport::GetIdsForReservedFile(filepath, id, unit)) {
|
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));
|
"', it is currently being used by device ID " + to_string(id) + ", unit " + to_string(unit));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (remove(full_filename.c_str())) {
|
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
|
// Delete empty subfolders
|
||||||
|
@ -212,7 +213,7 @@ bool RascsiImage::DeleteImage(const CommandContext& context, const PbCommand& co
|
||||||
}
|
}
|
||||||
|
|
||||||
if (remove(full_folder.c_str())) {
|
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('/');
|
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())
|
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
|
bool RascsiImage::RenameImage(const CommandContext& context, const PbCommand& command) const
|
||||||
{
|
{
|
||||||
string from = GetParam(command, "from");
|
string from;
|
||||||
if (from.empty()) {
|
string to;
|
||||||
return ReturnStatus(context, false, "Can't rename/move image file: Missing source filename");
|
if (!ValidateParams(context, command, "rename/move", from, to)) {
|
||||||
}
|
return false;
|
||||||
|
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CreateImageFolder(context, to)) {
|
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())) {
|
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())
|
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
|
bool RascsiImage::CopyImage(const CommandContext& context, const PbCommand& command) const
|
||||||
{
|
{
|
||||||
string from = GetParam(command, "from");
|
string from;
|
||||||
if (from.empty()) {
|
string to;
|
||||||
return ReturnStatus(context, false, "Can't copy image file: Missing source filename");
|
if (!ValidateParams(context, command, "copy", from, to)) {
|
||||||
}
|
return false;
|
||||||
|
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (lstat(from.c_str(), &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)) {
|
if (!CreateImageFolder(context, to)) {
|
||||||
|
@ -308,17 +265,17 @@ bool RascsiImage::CopyImage(const CommandContext& context, const PbCommand& comm
|
||||||
// Symbolic links need a special handling
|
// Symbolic links need a special handling
|
||||||
if ((st.st_mode & S_IFMT) == S_IFLNK) {
|
if ((st.st_mode & S_IFMT) == S_IFLNK) {
|
||||||
if (symlink(filesystem::read_symlink(from).c_str(), to.c_str())) {
|
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())
|
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);
|
int fd_src = open(from.c_str(), O_RDONLY, 0);
|
||||||
if (fd_src == -1) {
|
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");
|
string permission = GetParam(command, "read_only");
|
||||||
|
@ -330,7 +287,7 @@ bool RascsiImage::CopyImage(const CommandContext& context, const PbCommand& comm
|
||||||
if (fd_dst == -1) {
|
if (fd_dst == -1) {
|
||||||
close(fd_src);
|
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__
|
#ifndef __linux__
|
||||||
|
@ -339,6 +296,8 @@ bool RascsiImage::CopyImage(const CommandContext& context, const PbCommand& comm
|
||||||
|
|
||||||
unlink(to.c_str());
|
unlink(to.c_str());
|
||||||
|
|
||||||
|
LOGWARN("Copying image files is only supported under Linux")
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
#else
|
#else
|
||||||
if (sendfile(fd_dst, fd_src, nullptr, st.st_size) == -1) {
|
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());
|
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);
|
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())
|
LOGINFO("Copied image file '%s' to '%s'", from.c_str(), to.c_str())
|
||||||
|
|
||||||
return ReturnStatus(context);
|
return context.ReturnStatus();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,23 +322,23 @@ bool RascsiImage::SetImagePermissions(const CommandContext& context, const PbCom
|
||||||
{
|
{
|
||||||
string filename = GetParam(command, "file");
|
string filename = GetParam(command, "file");
|
||||||
if (filename.empty()) {
|
if (filename.empty()) {
|
||||||
return ReturnStatus(context, false, "Missing image filename");
|
return context.ReturnStatus(false, "Missing image filename");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CheckDepth(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);
|
filename = GetFullName(filename);
|
||||||
if (!IsValidSrcFilename(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;
|
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;
|
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) {
|
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));
|
strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -390,10 +349,44 @@ bool RascsiImage::SetImagePermissions(const CommandContext& context, const PbCom
|
||||||
LOGINFO("Unprotected image file '%s'", filename.c_str())
|
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();
|
int uid = getuid();
|
||||||
if (const char *sudo_user = getenv("SUDO_UID"); sudo_user != nullptr) {
|
if (const char *sudo_user = getenv("SUDO_UID"); sudo_user != nullptr) {
|
|
@ -13,6 +13,7 @@
|
||||||
#include "command_context.h"
|
#include "command_context.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
using namespace rascsi_interface;
|
using namespace rascsi_interface;
|
||||||
|
|
||||||
class RascsiImage
|
class RascsiImage
|
||||||
|
@ -24,22 +25,24 @@ public:
|
||||||
|
|
||||||
void SetDepth(int d) { depth = d; }
|
void SetDepth(int d) { depth = d; }
|
||||||
int GetDepth() const { return depth; }
|
int GetDepth() const { return depth; }
|
||||||
bool CheckDepth(string_view) const;
|
|
||||||
bool CreateImageFolder(const CommandContext&, const string&) const;
|
|
||||||
string GetDefaultFolder() const { return default_folder; }
|
string GetDefaultFolder() const { return default_folder; }
|
||||||
string SetDefaultFolder(const string&);
|
string SetDefaultFolder(const string&);
|
||||||
bool IsValidSrcFilename(const string&) const;
|
|
||||||
bool IsValidDstFilename(const string&) const;
|
|
||||||
bool CreateImage(const CommandContext&, const PbCommand&) const;
|
bool CreateImage(const CommandContext&, const PbCommand&) const;
|
||||||
bool DeleteImage(const CommandContext&, const PbCommand&) const;
|
bool DeleteImage(const CommandContext&, const PbCommand&) const;
|
||||||
bool RenameImage(const CommandContext&, const PbCommand&) const;
|
bool RenameImage(const CommandContext&, const PbCommand&) const;
|
||||||
bool CopyImage(const CommandContext&, const PbCommand&) const;
|
bool CopyImage(const CommandContext&, const PbCommand&) const;
|
||||||
bool SetImagePermissions(const CommandContext&, const PbCommand&) const;
|
bool SetImagePermissions(const CommandContext&, const PbCommand&) const;
|
||||||
string GetFullName(const string& filename) const { return default_folder + "/" + filename; }
|
|
||||||
|
|
||||||
private:
|
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;
|
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());
|
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);
|
pb_device.set_allocated_status(status);
|
||||||
status->set_protected_(device.IsProtected());
|
status->set_protected_(device.IsProtected());
|
||||||
status->set_stopped(device.IsStopped());
|
status->set_stopped(device.IsStopped());
|
|
@ -21,25 +21,25 @@ using namespace rascsi_interface;
|
||||||
|
|
||||||
volatile bool RascsiService::running = false;
|
volatile bool RascsiService::running = false;
|
||||||
|
|
||||||
RascsiService::~RascsiService()
|
void RascsiService::Cleanup() const
|
||||||
{
|
{
|
||||||
if (service_socket != -1) {
|
if (service_socket != -1) {
|
||||||
close(service_socket);
|
close(service_socket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RascsiService::Init(bool (e)(PbCommand&, CommandContext&), int port)
|
bool RascsiService::Init(const callback& cb, int port)
|
||||||
{
|
{
|
||||||
// Create socket for monitor
|
// Create socket for monitor
|
||||||
sockaddr_in server = {};
|
sockaddr_in server = {};
|
||||||
service_socket = socket(PF_INET, SOCK_STREAM, 0);
|
service_socket = socket(PF_INET, SOCK_STREAM, 0);
|
||||||
if (service_socket == -1) {
|
if (service_socket == -1) {
|
||||||
LOGERROR("Unable to create socket");
|
LOGERROR("Unable to create socket")
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
server.sin_family = PF_INET;
|
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);
|
server.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
|
|
||||||
// Allow address reuse
|
// Allow address reuse
|
||||||
|
@ -54,7 +54,7 @@ bool RascsiService::Init(bool (e)(PbCommand&, CommandContext&), int port)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
execute = e;
|
execute = cb;
|
||||||
|
|
||||||
monthread = thread(&RascsiService::Execute, this);
|
monthread = thread(&RascsiService::Execute, this);
|
||||||
monthread.detach();
|
monthread.detach();
|
||||||
|
@ -64,7 +64,7 @@ bool RascsiService::Init(bool (e)(PbCommand&, CommandContext&), int port)
|
||||||
&& signal(SIGTERM, KillHandler) != SIG_ERR;
|
&& signal(SIGTERM, KillHandler) != SIG_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RascsiService::Execute()
|
void RascsiService::Execute() const
|
||||||
{
|
{
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
// Scheduler Settings
|
// Scheduler Settings
|
||||||
|
@ -77,62 +77,57 @@ void RascsiService::Execute()
|
||||||
ras_util::FixCpu(2);
|
ras_util::FixCpu(2);
|
||||||
|
|
||||||
// Wait for the execution to start
|
// Wait for the execution to start
|
||||||
|
timespec ts = { .tv_sec = 0, .tv_nsec = 1000};
|
||||||
while (!running) {
|
while (!running) {
|
||||||
usleep(1);
|
nanosleep(&ts, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up the monitor socket to receive commands
|
// Set up the monitor socket to receive commands
|
||||||
listen(service_socket, 1);
|
listen(service_socket, 1);
|
||||||
|
|
||||||
ProtobufSerializer serializer;
|
|
||||||
Localizer localizer;
|
|
||||||
while (true) {
|
while (true) {
|
||||||
CommandContext context(serializer, localizer, -1, "");
|
CommandContext context;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
PbCommand command;
|
PbCommand command = ReadCommand(context);
|
||||||
context.fd = ReadCommand(serializer, command);
|
if (context.IsValid()) {
|
||||||
if (context.fd == -1) {
|
execute(context, command);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
execute(command, context);
|
|
||||||
}
|
}
|
||||||
catch(const io_exception& e) {
|
catch(const io_exception& e) {
|
||||||
LOGWARN("%s", e.get_msg().c_str())
|
LOGWARN("%s", e.get_msg().c_str())
|
||||||
|
|
||||||
// Fall through
|
// Fall through
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context.fd != -1) {
|
context.Cleanup();
|
||||||
close(context.fd);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int RascsiService::ReadCommand(ProtobufSerializer& serializer, PbCommand& command)
|
PbCommand RascsiService::ReadCommand(CommandContext& context) const
|
||||||
{
|
{
|
||||||
// Wait for connection
|
// Wait for connection
|
||||||
sockaddr client = {};
|
sockaddr client = {};
|
||||||
socklen_t socklen = sizeof(client);
|
socklen_t socklen = sizeof(client);
|
||||||
int fd = accept(service_socket, &client, &socklen);
|
int fd = accept(service_socket, &client, &socklen);
|
||||||
if (fd < 0) {
|
if (fd == -1) {
|
||||||
throw io_exception("accept() failed");
|
throw io_exception("accept() failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PbCommand command;
|
||||||
|
|
||||||
// Read magic string
|
// Read magic string
|
||||||
vector<byte> magic(6);
|
vector<byte> magic(6);
|
||||||
size_t bytes_read = serializer.ReadBytes(fd, magic);
|
if (size_t bytes_read = context.GetSerializer().ReadBytes(fd, magic);
|
||||||
if (!bytes_read) {
|
bytes_read != magic.size() || memcmp(magic.data(), "RASCSI", magic.size())) {
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (bytes_read != magic.size() || memcmp(magic.data(), "RASCSI", magic.size())) {
|
|
||||||
throw io_exception("Invalid magic");
|
throw io_exception("Invalid magic");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch the command
|
// 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
|
#pragma once
|
||||||
|
|
||||||
#include "rascsi_interface.pb.h"
|
#include "rascsi_interface.pb.h"
|
||||||
|
#include <functional>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
class CommandContext;
|
class CommandContext;
|
||||||
class ProtobufSerializer;
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
class RascsiService
|
class RascsiService
|
||||||
{
|
{
|
||||||
bool (*execute)(rascsi_interface::PbCommand&, CommandContext&) = nullptr;
|
using callback = function<bool(const CommandContext&, rascsi_interface::PbCommand&)>;
|
||||||
|
|
||||||
|
callback execute;
|
||||||
|
|
||||||
int service_socket = -1;
|
int service_socket = -1;
|
||||||
|
|
||||||
|
@ -28,16 +32,17 @@ class RascsiService
|
||||||
public:
|
public:
|
||||||
|
|
||||||
RascsiService() = default;
|
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; }
|
bool IsRunning() const { return running; }
|
||||||
void SetRunning(bool b) const { running = b; }
|
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; }
|
static void KillHandler(int) { running = false; }
|
||||||
};
|
};
|
|
@ -14,8 +14,8 @@
|
||||||
#include "rascsi_version.h"
|
#include "rascsi_version.h"
|
||||||
#include "command_util.h"
|
#include "command_util.h"
|
||||||
#include "rasutil.h"
|
#include "rasutil.h"
|
||||||
#include "rasctl_commands.h"
|
|
||||||
#include "rascsi_interface.pb.h"
|
#include "rascsi_interface.pb.h"
|
||||||
|
#include "rasctl/rasctl_commands.h"
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <clocale>
|
#include <clocale>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "hal/gpiobus.h"
|
#include "hal/gpiobus.h"
|
||||||
#include "hal/systimer.h"
|
#include "hal/systimer.h"
|
||||||
#include "rascsi_version.h"
|
#include "rascsi_version.h"
|
||||||
|
#include <cstring>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
|
@ -258,7 +259,9 @@ bool Selection(int id)
|
||||||
// wait for busy
|
// wait for busy
|
||||||
count = 10000;
|
count = 10000;
|
||||||
do {
|
do {
|
||||||
usleep(20);
|
// Wait 20 microseconds
|
||||||
|
timespec ts = { .tv_sec = 0, .tv_nsec = 20 * 1000};
|
||||||
|
nanosleep(&ts, nullptr);
|
||||||
bus.Acquire();
|
bus.Acquire();
|
||||||
if (bus.GetBSY()) {
|
if (bus.GetBSY()) {
|
||||||
break;
|
break;
|
||||||
|
@ -289,7 +292,7 @@ bool Command(BYTE *buf, int length)
|
||||||
// Send Command
|
// Send Command
|
||||||
count = bus.SendHandShake(buf, length, BUS::SEND_NO_DELAY);
|
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
|
// of requests
|
||||||
if (count == length) {
|
if (count == length) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -851,7 +854,9 @@ int main(int argc, char* argv[])
|
||||||
|
|
||||||
// Assert reset signal
|
// Assert reset signal
|
||||||
bus.SetRST(true);
|
bus.SetRST(true);
|
||||||
usleep(1000);
|
// Wait 1 ms
|
||||||
|
timespec ts = { .tv_sec = 0, .tv_nsec = 1000 * 1000};
|
||||||
|
nanosleep(&ts, nullptr);
|
||||||
bus.SetRST(false);
|
bus.SetRST(false);
|
||||||
|
|
||||||
// Start dump
|
// 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("printer");
|
||||||
TestSpecialDevice("services");
|
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/scsicd.h"
|
||||||
#include "devices/scsimo.h"
|
#include "devices/scsimo.h"
|
||||||
#include "devices/host_services.h"
|
#include "devices/host_services.h"
|
||||||
#include "protobuf_serializer.h"
|
#include "rascsi/command_context.h"
|
||||||
#include "command_context.h"
|
|
||||||
#include "localizer.h"
|
|
||||||
|
|
||||||
class MockBus final : public BUS //NOSONAR Having many fields/methods cannot be avoided
|
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
|
class MockCommandContext : public CommandContext
|
||||||
{
|
{
|
||||||
ProtobufSerializer s;
|
|
||||||
Localizer l;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
MockCommandContext() : CommandContext(s, l, STDOUT_FILENO, "") {}
|
MockCommandContext() {
|
||||||
|
SetFd(open("/dev/null", O_WRONLY));
|
||||||
|
}
|
||||||
~MockCommandContext() = default;
|
~MockCommandContext() = default;
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,6 +19,9 @@ TEST(ProtobufSerializerTest, SerializeMessage)
|
||||||
PbResult message;
|
PbResult message;
|
||||||
ProtobufSerializer serializer;
|
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);
|
EXPECT_THROW(serializer.SerializeMessage(-1, message), io_exception);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,12 +8,13 @@
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
#include "mocks.h"
|
#include "mocks.h"
|
||||||
|
#include "command_util.h"
|
||||||
#include "controllers/controller_manager.h"
|
#include "controllers/controller_manager.h"
|
||||||
#include "devices/device_factory.h"
|
#include "devices/device_factory.h"
|
||||||
#include "command_util.h"
|
#include "rascsi/command_context.h"
|
||||||
#include "rascsi_response.h"
|
#include "rascsi/rascsi_response.h"
|
||||||
#include "rascsi_image.h"
|
#include "rascsi/rascsi_image.h"
|
||||||
#include "rascsi_executor.h"
|
#include "rascsi/rascsi_executor.h"
|
||||||
|
|
||||||
using namespace rascsi_interface;
|
using namespace rascsi_interface;
|
||||||
using namespace command_util;
|
using namespace command_util;
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
#include "controllers/controller_manager.h"
|
#include "controllers/controller_manager.h"
|
||||||
#include "devices/device_factory.h"
|
#include "devices/device_factory.h"
|
||||||
#include "rascsi_interface.pb.h"
|
#include "rascsi_interface.pb.h"
|
||||||
#include "rascsi_response.h"
|
#include "rascsi/rascsi_response.h"
|
||||||
|
|
||||||
using namespace rascsi_interface;
|
using namespace rascsi_interface;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user