Replaced parameter lists by map with named parameters

This commit is contained in:
Uwe Seimet 2021-09-16 12:16:53 +02:00
parent 00a08e8d18
commit 8629dea87f
13 changed files with 262 additions and 176 deletions

View File

@ -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) {

View File

@ -9,7 +9,7 @@
#pragma once
#include <list>
#include <map>
#include <string>
using namespace std;
@ -96,10 +96,10 @@ private:
string revision;
// The parameters the device was created with
list<string> params;
map<string, string> params;
// The default parameters
list<string> default_params;
map<string, string> 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<string>&) { return true; };
virtual bool Init(const map<string, string>&) { 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<string> GetParams() const { return params; }
void SetParams(const list<string>& params) { this->params = params; }
const list<string> GetDefaultParams() const { return default_params; }
void SetDefaultParams(const list<string>& default_params) { this->default_params = default_params; }
const map<string, string> GetParams() const { return params; }
const string GetParam(const string&);
void SetParams(const map<string, string>& params) { this->params = params; }
const map<string, string> GetDefaultParams() const { return default_params; }
void SetDefaultParams(const map<string, string>& 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();

View File

@ -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()

View File

@ -36,7 +36,7 @@ public:
const set<uint32_t>& GetSectorSizes(PbDeviceType type) { return sector_sizes[type]; }
const set<uint32_t>& GetSectorSizes(const string&);
const set<uint64_t> GetCapacities(PbDeviceType);
const list<string>& GetDefaultParams(PbDeviceType type) { return default_params[type]; }
const map<string, string>& GetDefaultParams(PbDeviceType type) { return default_params[type]; }
Device *CreateDevice(PbDeviceType type, const string& filename, const string& ext);
@ -46,5 +46,5 @@ private:
map<PbDeviceType, map<uint64_t, Geometry>> geometries;
map<PbDeviceType, list<string>> default_params;
map<PbDeviceType, map<string, string>> default_params;
};

View File

@ -85,13 +85,13 @@ bool SCSIDaynaPort::Dispatch(SCSIDEV *controller)
return Disk::Dispatch(controller);
}
bool SCSIDaynaPort::Init(const list<string>& params)
bool SCSIDaynaPort::Init(const map<string, string>& 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");

View File

@ -60,7 +60,7 @@ public:
SCSIDaynaPort();
~SCSIDaynaPort();
bool Init(const list<string>&) override;
bool Init(const map<string, string>&) override;
void Open(const Filepath& path) override;
// Commands

View File

@ -63,14 +63,14 @@ SCSIBR::~SCSIBR()
}
}
bool SCSIBR::Init(const list<string>& params)
bool SCSIBR::Init(const map<string, string>& 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

View File

@ -50,7 +50,7 @@ public:
SCSIBR();
~SCSIBR();
bool Init(const list<string>&) override;
bool Init(const map<string, string>&) override;
bool Dispatch(SCSIDEV *) override;
// Commands

View File

@ -8,7 +8,6 @@
//---------------------------------------------------------------------------
#include <unistd.h>
#include <sstream>
#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.

View File

@ -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);

View File

@ -37,6 +37,7 @@
#include <iostream>
#include <list>
#include <vector>
#include <map>
#include <filesystem>
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<string>& ids_to_reserve)
string SetReservedIds(const string& ids)
{
set<int> reserved;
list<string> ids_to_reserve;
stringstream ss(ids);
string id;
while (getline(ss, id, ',')) {
ids_to_reserve.push_back(id);
}
set<int> 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<string>& 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<string>& 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<string> params = { pb_device.params().begin(), pb_device.params().end() };
std::map<string, string> 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<string>& 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<string, string> 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<string> 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<string> 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<string> 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");
}

View File

@ -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<string, string> 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<string, string> 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<string, string> 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<string, string> params = 3;
}
// The result of a command

View File

@ -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<string> params = { properties.default_params().begin(), properties.default_params().end() };
params.sort([](const auto& a, const auto& b) { return a < b; });
map<string, string> 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':