From 8629dea87f66e3941ae335a1a0b28499c10649a9 Mon Sep 17 00:00:00 2001 From: Uwe Seimet Date: Thu, 16 Sep 2021 12:16:53 +0200 Subject: [PATCH] Replaced parameter lists by map with named parameters --- src/raspberrypi/devices/device.cpp | 5 + src/raspberrypi/devices/device.h | 19 +- src/raspberrypi/devices/device_factory.cpp | 4 +- src/raspberrypi/devices/device_factory.h | 4 +- src/raspberrypi/devices/scsi_daynaport.cpp | 4 +- src/raspberrypi/devices/scsi_daynaport.h | 2 +- src/raspberrypi/devices/scsi_host_bridge.cpp | 4 +- src/raspberrypi/devices/scsi_host_bridge.h | 2 +- src/raspberrypi/protobuf_util.cpp | 38 +++- src/raspberrypi/protobuf_util.h | 7 + src/raspberrypi/rascsi.cpp | 195 ++++++++++--------- src/raspberrypi/rascsi_interface.proto | 106 ++++++---- src/raspberrypi/rasctl.cpp | 48 ++--- 13 files changed, 262 insertions(+), 176 deletions(-) diff --git a/src/raspberrypi/devices/device.cpp b/src/raspberrypi/devices/device.cpp index 481b8b74..2c9f3275 100644 --- a/src/raspberrypi/devices/device.cpp +++ b/src/raspberrypi/devices/device.cpp @@ -108,6 +108,11 @@ const string Device::GetPaddedName() const return name; } +const string Device::GetParam(const string& key) +{ + return params.find(key) != params.end() ? params[key] : ""; +} + void Device::SetStatusCode(int status_code) { if (status_code) { diff --git a/src/raspberrypi/devices/device.h b/src/raspberrypi/devices/device.h index 9f022104..f08372a9 100644 --- a/src/raspberrypi/devices/device.h +++ b/src/raspberrypi/devices/device.h @@ -9,7 +9,7 @@ #pragma once -#include +#include #include using namespace std; @@ -96,10 +96,10 @@ private: string revision; // The parameters the device was created with - list params; + map params; // The default parameters - list default_params; + map default_params; // Sense Key, ASC and ASCQ int status_code; @@ -110,7 +110,7 @@ public: virtual ~Device() {}; // Override for device specific initializations, to be called after all device properties have been set - virtual bool Init(const list&) { return true; }; + virtual bool Init(const map&) { return true; }; virtual bool Dispatch(SCSIDEV *) = 0; @@ -163,13 +163,14 @@ public: bool SupportsParams() const { return supports_params; } void SupportsParams(bool supports_paams) { this->supports_params = supports_paams; } - const list GetParams() const { return params; } - void SetParams(const list& params) { this->params = params; } - const list GetDefaultParams() const { return default_params; } - void SetDefaultParams(const list& default_params) { this->default_params = default_params; } + const map GetParams() const { return params; } + const string GetParam(const string&); + void SetParams(const map& params) { this->params = params; } + const map GetDefaultParams() const { return default_params; } + void SetDefaultParams(const map& default_params) { this->default_params = default_params; } int GetStatusCode() const { return status_code; } - void SetStatusCode(int status_code); + void SetStatusCode(int); bool Start(); void Stop(); diff --git a/src/raspberrypi/devices/device_factory.cpp b/src/raspberrypi/devices/device_factory.cpp index 4b611360..bf55d330 100644 --- a/src/raspberrypi/devices/device_factory.cpp +++ b/src/raspberrypi/devices/device_factory.cpp @@ -53,8 +53,8 @@ DeviceFactory::DeviceFactory() default_params[SCRM] = {}; default_params[SCMO] = {}; default_params[SCCD] = {}; - default_params[SCBR] = { "eth0,wlan0" }; - default_params[SCDP] = { "eth0,wlan0" }; + default_params[SCBR]["interfaces"] = "eth0,wlan0"; + default_params[SCDP]["interfaces"] = "eth0,wlan0"; } DeviceFactory& DeviceFactory::instance() diff --git a/src/raspberrypi/devices/device_factory.h b/src/raspberrypi/devices/device_factory.h index addb888d..c35b9cb0 100644 --- a/src/raspberrypi/devices/device_factory.h +++ b/src/raspberrypi/devices/device_factory.h @@ -36,7 +36,7 @@ public: const set& GetSectorSizes(PbDeviceType type) { return sector_sizes[type]; } const set& GetSectorSizes(const string&); const set GetCapacities(PbDeviceType); - const list& GetDefaultParams(PbDeviceType type) { return default_params[type]; } + const map& GetDefaultParams(PbDeviceType type) { return default_params[type]; } Device *CreateDevice(PbDeviceType type, const string& filename, const string& ext); @@ -46,5 +46,5 @@ private: map> geometries; - map> default_params; + map> default_params; }; diff --git a/src/raspberrypi/devices/scsi_daynaport.cpp b/src/raspberrypi/devices/scsi_daynaport.cpp index feb8b258..04aca7f1 100644 --- a/src/raspberrypi/devices/scsi_daynaport.cpp +++ b/src/raspberrypi/devices/scsi_daynaport.cpp @@ -85,13 +85,13 @@ bool SCSIDaynaPort::Dispatch(SCSIDEV *controller) return Disk::Dispatch(controller); } -bool SCSIDaynaPort::Init(const list& params) +bool SCSIDaynaPort::Init(const map& params) { SetParams(params.empty() ? GetDefaultParams() : params); #ifdef __linux__ // TAP Driver Generation - m_tap = new CTapDriver(GetParams().front()); + m_tap = new CTapDriver(GetParam("interfaces")); m_bTapEnable = m_tap->Init(); if(!m_bTapEnable){ LOGERROR("Unable to open the TAP interface"); diff --git a/src/raspberrypi/devices/scsi_daynaport.h b/src/raspberrypi/devices/scsi_daynaport.h index e7cdcdb2..2c7edaf8 100644 --- a/src/raspberrypi/devices/scsi_daynaport.h +++ b/src/raspberrypi/devices/scsi_daynaport.h @@ -60,7 +60,7 @@ public: SCSIDaynaPort(); ~SCSIDaynaPort(); - bool Init(const list&) override; + bool Init(const map&) override; void Open(const Filepath& path) override; // Commands diff --git a/src/raspberrypi/devices/scsi_host_bridge.cpp b/src/raspberrypi/devices/scsi_host_bridge.cpp index 4c0ae59b..1bb8b62f 100644 --- a/src/raspberrypi/devices/scsi_host_bridge.cpp +++ b/src/raspberrypi/devices/scsi_host_bridge.cpp @@ -63,14 +63,14 @@ SCSIBR::~SCSIBR() } } -bool SCSIBR::Init(const list& params) +bool SCSIBR::Init(const map& params) { // Use default parameters if no parameters were provided SetParams(params.empty() ? GetDefaultParams() : params); #ifdef __linux__ // TAP Driver Generation - tap = new CTapDriver(GetParams().front()); + tap = new CTapDriver(GetParam("interfaces")); m_bTapEnable = tap->Init(); // Generate MAC Address diff --git a/src/raspberrypi/devices/scsi_host_bridge.h b/src/raspberrypi/devices/scsi_host_bridge.h index 7afb650e..873b0cf5 100644 --- a/src/raspberrypi/devices/scsi_host_bridge.h +++ b/src/raspberrypi/devices/scsi_host_bridge.h @@ -50,7 +50,7 @@ public: SCSIBR(); ~SCSIBR(); - bool Init(const list&) override; + bool Init(const map&) override; bool Dispatch(SCSIDEV *) override; // Commands diff --git a/src/raspberrypi/protobuf_util.cpp b/src/raspberrypi/protobuf_util.cpp index cdc53070..4791c5f5 100644 --- a/src/raspberrypi/protobuf_util.cpp +++ b/src/raspberrypi/protobuf_util.cpp @@ -8,7 +8,6 @@ //--------------------------------------------------------------------------- #include -#include #include "rascsi_interface.pb.h" #include "exceptions.h" #include "protobuf_util.h" @@ -16,6 +15,43 @@ using namespace std; using namespace rascsi_interface; + +const string GetParam(const PbCommand& command, const string& key) +{ + auto map = command.params(); + return map[key]; +} + +const string GetParam(const PbDeviceDefinition& device, const string& key) +{ + auto map = device.params(); + return map[key]; +} + +void AddParam(PbCommand& command, const string& key, const string& value) +{ + if (!key.empty() && !value.empty()) { + auto& map = *command.mutable_params(); + map[key] = value; + } +} + +void AddParam(PbDevice& device, const string& key, const string& value) +{ + if (!key.empty() && !value.empty()) { + auto& map = *device.mutable_params(); + map[key] = value; + } +} + +void AddParam(PbDeviceDefinition& device, const string& key, const string& value) +{ + if (!key.empty() && !value.empty()) { + auto& map = *device.mutable_params(); + map[key] = value; + } +} + //--------------------------------------------------------------------------- // // Serialize/Deserialize protobuf message: Length followed by the actual data. diff --git a/src/raspberrypi/protobuf_util.h b/src/raspberrypi/protobuf_util.h index a98a4e68..18d07dd2 100644 --- a/src/raspberrypi/protobuf_util.h +++ b/src/raspberrypi/protobuf_util.h @@ -14,6 +14,13 @@ #include "google/protobuf/message.h" #include "rascsi_interface.pb.h" +using namespace rascsi_interface; + +const string GetParam(const PbCommand&, const string&); +const string GetParam(const PbDeviceDefinition&, const string&); +void AddParam(PbCommand&, const string&, const string&); +void AddParam(PbDevice&, const string&, const string&); +void AddParam(PbDeviceDefinition&, const string&, const string&); void SerializeMessage(int, const google::protobuf::Message&); void DeserializeMessage(int, google::protobuf::Message&); int ReadNBytes(int, uint8_t *, int); diff --git a/src/raspberrypi/rascsi.cpp b/src/raspberrypi/rascsi.cpp index f7a41189..cf4838b5 100644 --- a/src/raspberrypi/rascsi.cpp +++ b/src/raspberrypi/rascsi.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include using namespace std; @@ -133,7 +134,7 @@ bool InitService(int port) { int result = pthread_mutex_init(&ctrl_mutex,NULL); if (result != EXIT_SUCCESS){ - LOGERROR("Unable to create a mutex. Err code: %d", result); + LOGERROR("Unable to create a mutex. Error code: %d", result); return false; } @@ -156,7 +157,7 @@ bool InitService(int port) // Bind if (bind(monsocket, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0) { - FPRT(stderr, "Error : Already running?\n"); + FPRT(stderr, "Error: Already running?\n"); return false; } @@ -489,7 +490,8 @@ PbDeviceProperties *GetDeviceProperties(const Device *device) if (device->SupportsParams()) { for (const auto& param : device_factory.GetDefaultParams(t)) { - properties->add_default_params(param); + auto& map = *properties->mutable_default_params(); + map[param.first] = param.second; } } @@ -557,8 +559,8 @@ void GetDevice(const Device *device, PbDevice *pb_device) status->set_locked(device->IsLocked()); if (device->SupportsParams()) { - for (const string& param : device->GetParams()) { - pb_device->add_params(param); + for (const auto& param : device->GetParams()) { + AddParam(*pb_device, param.first, param.second); } } @@ -670,9 +672,16 @@ bool SetDefaultImageFolder(const string& f) return true; } -string SetReservedIds(const list& ids_to_reserve) +string SetReservedIds(const string& ids) { - set reserved; + list ids_to_reserve; + stringstream ss(ids); + string id; + while (getline(ss, id, ',')) { + ids_to_reserve.push_back(id); + } + + set reserved; for (string id_to_reserve : ids_to_reserve) { int id; if (!GetAsInt(id_to_reserve, id)) { @@ -693,8 +702,8 @@ string SetReservedIds(const list& ids_to_reserve) if (!isFirst) { s << ", "; } - s << id; isFirst = false; + s << id; } LOGINFO("Reserved IDs set to: %s", s.str().c_str()); @@ -708,22 +717,28 @@ string SetReservedIds(const list& ids_to_reserve) bool CreateImage(int fd, const PbCommand& command) { - if (command.params().size() < 3 || command.params().Get(0).empty() || command.params().Get(1).empty() - || command.params().Get(2).empty()) { - return ReturnStatus(fd, false, "Can't create image file: Missing filename, file size or permission"); + string filename = GetParam(command, "file"); + if (filename.empty()) { + return ReturnStatus(fd, false, "Missing image filename"); } - int permissions = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; - const char *permission = command.params().Get(2).c_str(); - if (strcasecmp(permission, "true") && strcasecmp(permission, "false")) { - return ReturnStatus(fd, false, "Invalid read-only setting '" + command.params().Get(2) + "'"); + string size = GetParam(command, "size"); + if (size.empty()) { + return ReturnStatus(fd, false, "Missing image size"); } - if (!strcasecmp(permission, "true")) { - permissions = S_IRUSR | S_IRGRP | S_IROTH; + string permission = GetParam(command, "read_only"); + if (permission.empty()) { + return ReturnStatus(fd, false, "Missing read-only flag"); } - string filename = command.params().Get(0); + if (strcasecmp(permission.c_str(), "true") && strcasecmp(permission.c_str(), "false")) { + return ReturnStatus(fd, false, "Invalid read-only flag '" + permission + "'"); + } + + int permissions = !strcasecmp(permission.c_str(), "true") ? + S_IRUSR | S_IRGRP | S_IROTH : S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; + if (filename.find('/') != string::npos) { return ReturnStatus(fd, false, "The image filename '" + filename + "' must not contain a path"); } @@ -732,13 +747,13 @@ bool CreateImage(int fd, const PbCommand& command) off_t len; try { - len = stoul(command.params().Get(1)); + len = stoul(size); } catch(const invalid_argument& e) { - return ReturnStatus(fd, false, "Invalid image file size " + command.params().Get(1)); + return ReturnStatus(fd, false, "Invalid image file size " + size); } catch(const out_of_range& e) { - return ReturnStatus(fd, false, "Invalid image file size " + command.params().Get(1)); + return ReturnStatus(fd, false, "Invalid image file size " + size); } if (len < 512 || (len & 0x1ff)) { ostringstream error; @@ -774,11 +789,11 @@ bool CreateImage(int fd, const PbCommand& command) bool DeleteImage(int fd, const PbCommand& command) { - if (command.params().size() < 1 || command.params().Get(0).empty()) { - return ReturnStatus(fd, false, "Can't delete image file: Missing filename"); + string filename = GetParam(command, "file"); + if (filename.empty()) { + return ReturnStatus(fd, false, "Missing image filename"); } - string filename = command.params().Get(0); if (filename.find('/') != string::npos) { return ReturnStatus(fd, false, "The image filename '" + filename + "' must not contain a path"); } @@ -806,87 +821,95 @@ bool DeleteImage(int fd, const PbCommand& command) bool RenameImage(int fd, const PbCommand& command) { - if (command.params().size() < 2 || command.params().Get(0).empty() || command.params().Get(1).empty()) { - return ReturnStatus(fd, false, "Can't rename image file: Missing filename"); + string from = GetParam(command, "from"); + if (from.empty()) { + return ReturnStatus(fd, false, "Missing source filename"); } - string src = command.params().Get(0); - if (src.find('/') != string::npos) { - return ReturnStatus(fd, false, "The current filename '" + src + "' must not contain a path"); - } - string dst = command.params().Get(1); - if (dst.find('/') != string::npos) { - return ReturnStatus(fd, false, "The new filename '" + dst + "' must not contain a path"); + string to = GetParam(command, "to"); + if (to.empty()) { + return ReturnStatus(fd, false, "Missing destination filename"); } - src = default_image_folder + "/" + src; - dst = default_image_folder + "/" + dst; + if (from.find('/') != string::npos) { + return ReturnStatus(fd, false, "The current filename '" + from + "' must not contain a path"); + } + if (to.find('/') != string::npos) { + return ReturnStatus(fd, false, "The new filename '" + to + "' must not contain a path"); + } + + from = default_image_folder + "/" + from; + to = default_image_folder + "/" + to; struct stat st; - if (!stat(dst.c_str(), &st)) { - return ReturnStatus(fd, false, "Image file '" + dst + "' already exists"); + if (!stat(to.c_str(), &st)) { + return ReturnStatus(fd, false, "Image file '" + to + "' already exists"); } - if (rename(src.c_str(), dst.c_str())) { - return ReturnStatus(fd, false, "Can't rename image file '" + src + "' to '" + dst + "': " + string(strerror(errno))); + if (rename(from.c_str(), to.c_str())) { + return ReturnStatus(fd, false, "Can't rename image file '" + from + "' to '" + to + "': " + string(strerror(errno))); } - LOGINFO("%s", string("Renamed image file '" + src + "' to '" + dst + "'").c_str()); + LOGINFO("%s", string("Renamed image file '" + from + "' to '" + to + "'").c_str()); return ReturnStatus(fd); } bool CopyImage(int fd, const PbCommand& command) { - if (command.params().size() < 2 || command.params().Get(0).empty() || command.params().Get(1).empty()) { - return ReturnStatus(fd, false, "Can't copy image file: Missing filename"); + string from = GetParam(command, "from"); + if (from.empty()) { + return ReturnStatus(fd, false, "Missing source filename"); } - string src = command.params().Get(0); - if (src.find('/') != string::npos) { - return ReturnStatus(fd, false, "The current filename '" + src + "' must not contain a path"); - } - string dst = command.params().Get(1); - if (dst.find('/') != string::npos) { - return ReturnStatus(fd, false, "The new filename '" + dst + "' must not contain a path"); + string to = GetParam(command, "to"); + if (to.empty()) { + return ReturnStatus(fd, false, "Missing destination filename"); } - src = default_image_folder + "/" + src; - dst = default_image_folder + "/" + dst; + if (from.find('/') != string::npos) { + return ReturnStatus(fd, false, "The current filename '" + from + "' must not contain a path"); + } + if (to.find('/') != string::npos) { + return ReturnStatus(fd, false, "The new filename '" + to + "' must not contain a path"); + } + + from = default_image_folder + "/" + from; + to = default_image_folder + "/" + to; struct stat st; - if (!stat(dst.c_str(), &st)) { - return ReturnStatus(fd, false, "Image file '" + dst + "' already exists"); + if (!stat(to.c_str(), &st)) { + return ReturnStatus(fd, false, "Image file '" + to + "' already exists"); } - int fd_src = open(src.c_str(), O_RDONLY, 0); + int fd_src = open(from.c_str(), O_RDONLY, 0); if (fd_src == -1) { - return ReturnStatus(fd, false, "Can't open source image file '" + src + "': " + string(strerror(errno))); + return ReturnStatus(fd, false, "Can't open source image file '" + from + "': " + string(strerror(errno))); } struct stat st_src; if (fstat(fd_src, &st_src) == -1) { - return ReturnStatus(fd, false, "Can't read source image file '" + src + "': " + string(strerror(errno))); + return ReturnStatus(fd, false, "Can't read source image file '" + from + "': " + string(strerror(errno))); } - int fd_dst = open(dst.c_str(), O_WRONLY | O_CREAT, st_src.st_mode); + int fd_dst = open(to.c_str(), O_WRONLY | O_CREAT, st_src.st_mode); if (fd_dst == -1) { close (fd_dst); - return ReturnStatus(fd, false, "Can't open destination image file '" + dst + "': " + string(strerror(errno))); + return ReturnStatus(fd, false, "Can't open destination image file '" + to + "': " + string(strerror(errno))); } if (sendfile(fd_dst, fd_src, 0, st_src.st_size) == -1) { close(fd_dst); close(fd_src); - return ReturnStatus(fd, false, "Can't copy image file '" + src + "' to '" + dst + "': " + string(strerror(errno))); + return ReturnStatus(fd, false, "Can't copy image file '" + from + "' to '" + to + "': " + string(strerror(errno))); } close(fd_dst); close(fd_src); - LOGINFO("%s", string("Copied image file '" + src + "' to '" + dst + "'").c_str()); + LOGINFO("%s", string("Copied image file '" + from + "' to '" + to + "'").c_str()); return ReturnStatus(fd); } @@ -917,7 +940,7 @@ bool Attach(int fd, const PbDeviceDefinition& pb_device, Device *map[], bool dry return ReturnStatus(fd, false, error); } - string filename = pb_device.params_size() > 0 ? pb_device.params().Get(0) : ""; + string filename = GetParam(pb_device, "file"); string ext; size_t separator = filename.rfind('.'); if (separator != string::npos) { @@ -1027,7 +1050,7 @@ bool Attach(int fd, const PbDeviceDefinition& pb_device, Device *map[], bool dry return true; } - const list params = { pb_device.params().begin(), pb_device.params().end() }; + std::map params = { pb_device.params().begin(), pb_device.params().end() }; if (!device->Init(params)) { error << "Initialization of " << device->GetType() << " device, ID " << id << ", unit " << unit << " failed"; @@ -1097,7 +1120,7 @@ bool Insert(int fd, const PbDeviceDefinition& pb_device, Device *device, bool dr return ReturnStatus(fd, false, "Once set the device name cannot be changed anymore"); } - string filename = pb_device.params_size() > 0 ? pb_device.params().Get(0): ""; + string filename = GetParam(pb_device, "file"); if (filename.empty()) { return ReturnStatus(fd, false, "Missing filename for " + PbOperation_Name(INSERT)); } @@ -1161,13 +1184,15 @@ bool Insert(int fd, const PbDeviceDefinition& pb_device, Device *device, bool dr // //--------------------------------------------------------------------------- -bool ProcessCmd(int fd, const PbDeviceDefinition& pb_device, const PbOperation operation, const vector& params, bool dryRun) +bool ProcessCmd(int fd, const PbDeviceDefinition& pb_device, const PbCommand& command, bool dryRun) { ostringstream error; const int id = pb_device.id(); const int unit = pb_device.unit(); const PbDeviceType type = pb_device.type(); + const PbOperation operation = command.operation(); + const map params = { command.params().begin(), command.params().end() }; ostringstream s; s << (dryRun ? "Validating: " : "Executing: "); @@ -1175,11 +1200,13 @@ bool ProcessCmd(int fd, const PbDeviceDefinition& pb_device, const PbOperation o if (!params.empty()) { s << ", command params="; - for (size_t i = 0; i < params.size(); i++) { - if (i) { + bool isFirst = true; + for (const auto& param: params) { + if (!isFirst) { s << ", "; } - s << "'" << params[i] << "'"; + isFirst = false; + s << param.first << "=" << param.second; } } @@ -1187,11 +1214,13 @@ bool ProcessCmd(int fd, const PbDeviceDefinition& pb_device, const PbOperation o if (pb_device.params_size()) { s << ", device params="; - for (int i = 0; i < pb_device.params_size(); i++) { - if (i) { + bool isFirst = true; + for (const auto& param: pb_device.params()) { + if (!isFirst) { s << ", "; } - s << "'" << pb_device.params().Get(i) << "'"; + isFirst = false; + s << param.first << "=" << param.second; } } @@ -1331,7 +1360,7 @@ bool ProcessCmd(const int fd, const PbCommand& command) return ReturnStatus(fd); case RESERVE: { - const list ids = { command.params().begin(), command.params().end() }; + const string ids = GetParam(command, "ids"); string invalid_id = SetReservedIds(ids); if (!invalid_id.empty()) { return ReturnStatus(fd, false, "Invalid ID " + invalid_id + " for " + PbOperation_Name(RESERVE)); @@ -1357,12 +1386,10 @@ bool ProcessCmd(const int fd, const PbCommand& command) break; } - const vector params = { command.params().begin(), command.params().end() }; - // Remember the list of reserved files, than run the dry run const auto reserved_files = FileSupport::GetReservedFiles(); for (const auto& device : command.devices()) { - if (!ProcessCmd(fd, device, command.operation(), params, true)) { + if (!ProcessCmd(fd, device, command, true)) { // Dry run failed, restore the file list FileSupport::SetReservedFiles(reserved_files); return false; @@ -1372,7 +1399,7 @@ bool ProcessCmd(const int fd, const PbCommand& command) // Restore list of reserved files, then execute the command FileSupport::SetReservedFiles(reserved_files); for (const auto& device : command.devices()) { - if (!ProcessCmd(fd, device, command.operation(), params, false)) { + if (!ProcessCmd(fd, device, command, false)) { return false; } } @@ -1453,15 +1480,7 @@ bool ParseArgument(int argc, char* argv[], int& port) continue; case 'r': { - stringstream ss(optarg); - string id; - - list ids; - while (getline(ss, id, ',')) { - ids.push_back(id); - } - - string invalid_id = SetReservedIds(ids); + string invalid_id = SetReservedIds(optarg); if (!invalid_id.empty()) { cerr << "Invalid ID " << invalid_id << " for " << PbOperation_Name(RESERVE); return false; @@ -1503,9 +1522,7 @@ bool ParseArgument(int argc, char* argv[], int& port) device->set_unit(unit); device->set_type(type); device->set_block_size(block_size); - if (strlen(optarg)) { - device->add_params(optarg); - } + AddParam(*device, "file", optarg); size_t separatorPos = name.find(':'); if (separatorPos != string::npos) { @@ -1617,7 +1634,7 @@ static void *MonThread(void *param) case LOG_LEVEL: { LOGTRACE(string("Received " + PbOperation_Name(LOG_LEVEL) + " command").c_str()); - string log_level = command.params_size() > 0 ? command.params().Get(0) : ""; + string log_level = GetParam(command, "level"); bool status = SetLogLevel(log_level); if (!status) { ReturnStatus(fd, false, "Invalid log level: " + log_level); @@ -1631,7 +1648,7 @@ static void *MonThread(void *param) case DEFAULT_FOLDER: { LOGTRACE(string("Received " + PbOperation_Name(DEFAULT_FOLDER) + " command").c_str()); - string folder = command.params_size() > 0 ? command.params().Get(0) : ""; + string folder = GetParam(command, "folder"); if (folder.empty()) { ReturnStatus(fd, false, "Can't set default image folder: Missing folder name"); } diff --git a/src/raspberrypi/rascsi_interface.proto b/src/raspberrypi/rascsi_interface.proto index 4b16e92b..18c345c7 100644 --- a/src/raspberrypi/rascsi_interface.proto +++ b/src/raspberrypi/rascsi_interface.proto @@ -27,52 +27,82 @@ enum PbDeviceType { SCDP = 7; } -// rascsi remote operations, returns PbResult +// rascsi remote operations, returning PbResult enum PbOperation { NONE = 0; - // Gets the server information - SERVER_INFO = 1; - // Gets information for a list of attached devices. Returns data for all attached devices if empty. - DEVICE_INFO = 2; - // Set the default folder for image files. PbCommand.params contains the folder name. - DEFAULT_FOLDER = 3; - // Set server log level. PbCommand.params contains the log level. - LOG_LEVEL = 4; + // Attach devices - ATTACH = 5; + ATTACH = 1; + // Detach devices - DETACH = 6; + DETACH = 2; + // Detach all devices, does not require a device list - DETACH_ALL = 7; + DETACH_ALL = 3; + // Start device - START = 8; + START = 4; + // Stop device, e.g. park drive - STOP = 9; + STOP = 5; + // Insert medium - INSERT = 10; + INSERT = 6; + // Eject medium - EJECT = 11; + EJECT = 7; + // Write-protect medium (not possible for read-only media) - PROTECT = 12; + PROTECT = 8; + // Make medium writable (not possible for read-only media) - UNPROTECT = 13; - // IDs blocked from being used, usually the IDs of the initiators (computers) in the SCSI chain. - // PbCommand.params contains the list of IDs to reserve, or is empty in order not to reserve any ID. + UNPROTECT = 9; + + // Gets the server information + SERVER_INFO = 10; + + // Gets information for a list of attached devices. Returns data for all attached devices if empty. + DEVICE_INFO = 11; + + // Set the default folder for image files. + // Parameters: + // "folder": The default folder name. + DEFAULT_FOLDER = 12; + + // Set server log level. + // Parameters: + // "level": The new log level + LOG_LEVEL = 13; + + // Block IDs from being used, usually the IDs of the initiators (computers) in the SCSI chain. + // Parameters: + // "ids": A comma-separated list of IDs to reserve, or an empty string in order not to reserve any ID. RESERVE = 14; + // Create an image file. The image file must not yet exist. - // PbCommand.params(0) contains the filename, PbCommand.params(1) contains the file size in bytes. - // PbCommand.params(2) controls the file permissions. If "true" (case-insensitive) a read-only file is created. - // The filename is relative to the default image folder and must not contain a slash. - // The file size must be a multiple of 512. + // Parameters: + // "file": The filename, relative to the default image folder. It must not contain a slash. + // "size": The file size in bytes, must be a multiple of 512 + // "read_only": "true" (case-insensitive) in order to create a read-only file, otherwise "false" CREATE_IMAGE = 15; - // Delete an image file. PbCommand.params(0) contains the filename. - // The filename is relative to the default image folder and must not contain a slash. + + // Delete an image file. + // Parameters: + // "file": The filename, relative to the default image folder. It must not contain a slash. DELETE_IMAGE = 16; - // Rename an image file. PbCommand.params(0) contains the current filename, PbCommand.params(1) the new name. - // The filenames are relative to the default image folder and must not contain a slash. + + // Rename an image file. + // Parameters: + // "from": The old filename, relative to the default image folder. It must not contain a slash. + // "to": The new filename, relative to the default image folder. It must not contain a slash. + // The new filename must not yet exist. RENAME_IMAGE = 17; - // Copy an image file. PbCommand.params(0) contains the source filename, PbCommand.params(1) the destination name. - // The filenames are relative to the default image folder and must not contain a slash. + + // Copy an image file. + // Parameters: + // "from": The source filename, relative to the default image folder. It must not contain a slash. + // "to": The destination filename, relative to the default image folder. It must not contain a slash. + // The destination filename must not yet exist. COPY_IMAGE = 18; } @@ -92,8 +122,8 @@ message PbDeviceProperties { bool supports_file = 6; // Device supports parameters other than a filename bool supports_params = 7; - // Ordered list of default parameters, if any (requires supports_params to be true) - repeated string default_params = 8; + // List of default parameters, if any (requires supports_params to be true) + map default_params = 8; // Number of supported LUNs, at least 1 (for LUN 0) uint32 luns = 9; // Unordered list of permitted block sizes in bytes, empty if the block size is not configurable @@ -132,8 +162,8 @@ message PbDeviceDefinition { int32 id = 1; int32 unit = 2; PbDeviceType type = 3; - // Optional device specific parameters, e.g. the name of an image file - repeated string params = 4; + // Device specific named parameters, e.g. the name of an image file + map params = 4; // The optional block size in bytes per sector, must be one of the supported block sizes for SASI/SCSI int32 block_size = 5; // The device name components @@ -153,8 +183,8 @@ message PbDevice { PbDeviceStatus status = 5; // Image file information, if the device supports image files PbImageFile file = 6; - // Ordered list of effective parameters the device was created with - repeated string params = 7; + // Effective parameters the device was created with + map params = 7; string vendor = 8; string product = 9; string revision = 10; @@ -173,8 +203,8 @@ message PbCommand { PbOperation operation = 1; // The non-empty list of devices for this command repeated PbDeviceDefinition devices = 2; - // The optional parameters depending on the operation, e.g. a filename, or a network interface list - repeated string params = 3; + // The named parameters for the operation, e.g. a filename, or a network interface list + map params = 3; } // The result of a command diff --git a/src/raspberrypi/rasctl.cpp b/src/raspberrypi/rasctl.cpp index 28a8dd3e..70c77bc4 100644 --- a/src/raspberrypi/rasctl.cpp +++ b/src/raspberrypi/rasctl.cpp @@ -142,10 +142,8 @@ void DisplayDeviceInfo(const PbDevice& pb_device) cout << " "; } - if (pb_device.params_size()) { - for (const string param : pb_device.params()) { - cout << param << " "; - } + for (const auto& param : pb_device.params()) { + cout << param.first << "=" << param.second; } cout << endl; @@ -184,7 +182,7 @@ void CommandLogLevel(const string& hostname, int port, const string& log_level) { PbCommand command; command.set_operation(LOG_LEVEL); - command.add_params(log_level); + AddParam(command, "level", log_level); PbResult result; SendCommand(hostname.c_str(), port, command, result); @@ -194,13 +192,7 @@ void CommandReserve(const string&hostname, int port, const string& reserved_ids) { PbCommand command; command.set_operation(RESERVE); - - stringstream ss(reserved_ids); - string reserved_id; - - while (getline(ss, reserved_id, ',')) { - command.add_params(reserved_id); - } + AddParam(command, "ids", reserved_ids); PbResult result; SendCommand(hostname.c_str(), port, command, result); @@ -213,15 +205,15 @@ void CommandCreateImage(const string&hostname, int port, const string& image_par size_t separatorPos = image_params.find(COMPONENT_SEPARATOR); if (separatorPos != string::npos) { - command.add_params(image_params.substr(0, separatorPos)); - command.add_params(image_params.substr(separatorPos + 1)); + AddParam(command, "file", image_params.substr(0, separatorPos)); + AddParam(command, "size", image_params.substr(separatorPos + 1)); } else { - cerr << "Error: Invalid file description '" << image_params << "', format is NAME:SIZE" << endl; + cerr << "Error: Invalid file descriptor '" << image_params << "', format is NAME:SIZE" << endl; exit(EXIT_FAILURE); } - command.add_params("false"); + AddParam(command, "read_only", "false"); PbResult result; SendCommand(hostname.c_str(), port, command, result); @@ -231,8 +223,7 @@ void CommandDeleteImage(const string&hostname, int port, const string& filename) { PbCommand command; command.set_operation(DELETE_IMAGE); - - command.add_params(filename); + AddParam(command, "file", filename); PbResult result; SendCommand(hostname.c_str(), port, command, result); @@ -245,11 +236,11 @@ void CommandRenameImage(const string&hostname, int port, const string& image_par size_t separatorPos = image_params.find(COMPONENT_SEPARATOR); if (separatorPos != string::npos) { - command.add_params(image_params.substr(0, separatorPos)); - command.add_params(image_params.substr(separatorPos + 1)); + AddParam(command, "from", image_params.substr(0, separatorPos)); + AddParam(command, "to", image_params.substr(separatorPos + 1)); } else { - cerr << "Error: Invalid file description '" << image_params << "', format is CURRENT_NAME:NEW_NAME" << endl; + cerr << "Error: Invalid file descriptor '" << image_params << "', format is CURRENT_NAME:NEW_NAME" << endl; exit(EXIT_FAILURE); } @@ -264,11 +255,11 @@ void CommandCopyImage(const string&hostname, int port, const string& image_param size_t separatorPos = image_params.find(COMPONENT_SEPARATOR); if (separatorPos != string::npos) { - command.add_params(image_params.substr(0, separatorPos)); - command.add_params(image_params.substr(separatorPos + 1)); + AddParam(command, "from", image_params.substr(0, separatorPos)); + AddParam(command, "to", image_params.substr(separatorPos + 1)); } else { - cerr << "Error: Invalid file description '" << image_params << "', format is CURRENT_NAME:NEW_NAME" << endl; + cerr << "Error: Invalid file descriptor '" << image_params << "', format is CURRENT_NAME:NEW_NAME" << endl; exit(EXIT_FAILURE); } @@ -280,7 +271,7 @@ void CommandDefaultImageFolder(const string& hostname, int port, const string& f { PbCommand command; command.set_operation(DEFAULT_FOLDER); - command.add_params(folder); + AddParam(command, "folder", folder); PbResult result; SendCommand(hostname.c_str(), port, command, result); @@ -387,8 +378,7 @@ void CommandServerInfo(const string& hostname, int port) } if (properties.supports_params() && properties.default_params_size()) { - list params = { properties.default_params().begin(), properties.default_params().end() }; - params.sort([](const auto& a, const auto& b) { return a < b; }); + map params = { properties.default_params().begin(), properties.default_params().end() }; cout << " Default parameters: "; @@ -397,7 +387,7 @@ void CommandServerInfo(const string& hostname, int port) if (!isFirst) { cout << ", "; } - cout << param; + cout << param.first << "=" << param.second; isFirst = false; } @@ -615,7 +605,7 @@ int main(int argc, char* argv[]) break; case 'f': - device->add_params(optarg); + AddParam(*device, "folder", optarg); break; case 't':