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