Feature interface granularity (#304)

* Added VERSION_INFO

* Added LOG_LEVEL_INFO

* Added RESERVED_IDS_INFO

* Renaming

* Renaming

* Split rasctl

* Code cleanup

* Removed unused method

* Include cleanup

* More cleanup

* More cleanup

* Simplified sending commands

* Fully set up command

* Further simplified sending commands

* Moved code

* Include cleanup

* Reject reserving an ID that is in use

* Update rascsi-web for the changes in protobuf interface

Co-authored-by: Daniel Markstedt <markstedt@gmail.com>
This commit is contained in:
Uwe Seimet 2021-10-06 23:25:43 +02:00 committed by GitHub
parent 95607cd603
commit a638fec8a8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 983 additions and 711 deletions

View File

@ -3,12 +3,16 @@
rasctl \- Sends management commands to the rascsi process rasctl \- Sends management commands to the rascsi process
.SH SYNOPSIS .SH SYNOPSIS
.B rasctl .B rasctl
\fB\-L\fR |
\fB\-e\fR | \fB\-e\fR |
\fB\-l\fR | \fB\-l\fR |
\fB\-m\fR | \fB\-m\fR |
\fB\-s\fR | \fB\-s\fR |
\fB\-v\fR |
\fB\-I\fR |
\fB\-L\fR |
\fB\-O\fR |
\fB\-T\fR | \fB\-T\fR |
\fB\-V\fR |
[\fB\-E\fR \fIFILENAME\fR] [\fB\-E\fR \fIFILENAME\fR]
[\fB\-F\fR \fIIMAGE_FOLDER\fR] [\fB\-F\fR \fIIMAGE_FOLDER\fR]
[\fB\-C\fR \fIFILENAME:FILESIZE\fR] [\fB\-C\fR \fIFILENAME:FILESIZE\fR]
@ -18,8 +22,7 @@ rasctl \- Sends management commands to the rascsi process
[\fB\-h\fR \fIHOST\fR] [\fB\-h\fR \fIHOST\fR]
[\fB\-p\fR \fIPORT\fR] [\fB\-p\fR \fIPORT\fR]
[\fB\-r\fR \fIRESERVED_IDS\fR] [\fB\-r\fR \fIRESERVED_IDS\fR]
[\fB\-v\fR] [\fB\-i\fR \fIID\fR
\fB\-i\fR \fIID\fR
[\fB\-c\fR \fICMD\fR] [\fB\-c\fR \fICMD\fR]
[\fB\-f\fR \fIFILE|PARAM\fR] [\fB\-f\fR \fIFILE|PARAM\fR]
[\fB\-n\fR \fINAME\fR] [\fB\-n\fR \fINAME\fR]
@ -46,6 +49,9 @@ Display information on an image file.
.BR \-F\fI " "\fIIMAGE_FOLDER .BR \-F\fI " "\fIIMAGE_FOLDER
Set the default image folder. Set the default image folder.
.TP .TP
.BR \-I\fI
Gets the list of reserved device IDs.
.TP
.BR \-L\fI " "\fILOG_LEVEL .BR \-L\fI " "\fILOG_LEVEL
Set the rascsi log level (trace, debug, info, warn, err, critical, off). Set the rascsi log level (trace, debug, info, warn, err, critical, off).
.TP .TP
@ -58,6 +64,9 @@ List all images files in the default image folder.
.BR \-N\fI .BR \-N\fI
Lists all available network interfaces provided that they are up. Lists all available network interfaces provided that they are up.
.TP .TP
.BR \-O\fI
Display the available rascsi server log levels and the current log level.
.TP
.BR \-l\fI .BR \-l\fI
List all of the devices that are currently being emulated by RaSCSI, as well as their current status. List all of the devices that are currently being emulated by RaSCSI, as well as their current status.
.TP .TP
@ -80,7 +89,10 @@ Display server-side settings like available images or supported device types.
Display all device types and their properties. Display all device types and their properties.
.TP .TP
.BR \-v\fI " " \fI .BR \-v\fI " " \fI
Display the rascsi version. Display the rascsi server version.
.TP
.BR \-V\fI " " \fI
Display the rasctl version.
.TP .TP
.BR \-D\fI " "\fIFILENAME .BR \-D\fI " "\fIFILENAME
Delete an image file in the default image folder. Delete an image file in the default image folder.

View File

@ -6,10 +6,10 @@ NAME
rasctl - Sends management commands to the rascsi process rasctl - Sends management commands to the rascsi process
SYNOPSIS SYNOPSIS
rasctl -L | -e | -l | -m | -s | -T | [-E FILENAME] [-F IMAGE_FOLDER] rasctl -e | -l | -m | -s | -v | -I | -L | -O | -T | -V | [-E FILENAME]
[-C FILENAME:FILESIZE] [-x CURRENT_NAME:NEW_NAME] [-R CUR [-F IMAGE_FOLDER] [-C FILENAME:FILESIZE] [-x CURRENT_NAME:NEW_NAME] [-R
RENT_NAME:NEW_NAME] [-g LOG_LEVEL] [-h HOST] [-p PORT] [-r RE CURRENT_NAME:NEW_NAME] [-g LOG_LEVEL] [-h HOST] [-p PORT] [-r RE
SERVED_IDS] [-v] -i ID [-c CMD] [-f FILE|PARAM] [-n NAME] [-t TYPE] [-u SERVED_IDS] [-i ID [-c CMD] [-f FILE|PARAM] [-n NAME] [-t TYPE] [-u
UNIT] UNIT]
DESCRIPTION DESCRIPTION
@ -34,6 +34,8 @@ OPTIONS
-F IMAGE_FOLDER -F IMAGE_FOLDER
Set the default image folder. Set the default image folder.
-I Gets the list of reserved device IDs.
-L LOG_LEVEL -L LOG_LEVEL
Set the rascsi log level (trace, debug, info, warn, err, criti Set the rascsi log level (trace, debug, info, warn, err, criti
cal, off). cal, off).
@ -46,10 +48,13 @@ OPTIONS
-N Lists all available network interfaces provided that they are -N Lists all available network interfaces provided that they are
up. up.
-l List all of the devices that are currently being emulated by -O Display the available rascsi server log levels and the current
log level.
-l List all of the devices that are currently being emulated by
RaSCSI, as well as their current status. RaSCSI, as well as their current status.
-m List all file extensions recognized by RaSCSI and the device -m List all file extensions recognized by RaSCSI and the device
types they map to. types they map to.
-R CURRENT_NAME:NEW_NAME -R CURRENT_NAME:NEW_NAME
@ -61,12 +66,14 @@ OPTIONS
-r RESERVED_IDS -r RESERVED_IDS
Comma-separated list of IDs to reserve. Comma-separated list of IDs to reserve.
-s Display server-side settings like available images or supported -s Display server-side settings like available images or supported
device types. device types.
-T Display all device types and their properties. -T Display all device types and their properties.
-v Display the rascsi version. -v Display the rascsi server version.
-V Display the rasctl version.
-D FILENAME -D FILENAME
Delete an image file in the default image folder. Delete an image file in the default image folder.
@ -81,7 +88,7 @@ OPTIONS
d(etach): Detach disk d(etach): Detach disk
i(nsert): Insert media (removable media devices only) i(nsert): Insert media (removable media devices only)
e(ject): Eject media (removable media devices only) e(ject): Eject media (removable media devices only)
p(rotect): Write protect the medium (not for CD-ROMs, which p(rotect): Write protect the medium (not for CD-ROMs, which
are always read-only) are always read-only)
u(nprotect): Remove write protection from the medium (not for u(nprotect): Remove write protection from the medium (not for
CD-ROMs, which are always read-only) CD-ROMs, which are always read-only)
@ -91,18 +98,18 @@ OPTIONS
-b BLOCK_SIZE -b BLOCK_SIZE
The optional block size. For SCSI drives 512, 1024, 2048 or 4096 The optional block size. For SCSI drives 512, 1024, 2048 or 4096
bytes, default size is 512 bytes. For SASI drives 256 or 1024 bytes, default size is 512 bytes. For SASI drives 256 or 1024
bytes, default is 256 bytes. bytes, default is 256 bytes.
-f FILE|PARAM -f FILE|PARAM
Device-specific: Either a path to a disk image file, or a param Device-specific: Either a path to a disk image file, or a param
eter for a non-disk device. See the rascsi(1) man page for per eter for a non-disk device. See the rascsi(1) man page for per
mitted file types. mitted file types.
-t TYPE -t TYPE
Specifies the device type. This type overrides the type derived Specifies the device type. This type overrides the type derived
from the file extension of the specified image. See the from the file extension of the specified image. See the
rascsi(1) man page for the available device types. For some rascsi(1) man page for the available device types. For some
types there are shortcuts (only the first letter is required): types there are shortcuts (only the first letter is required):
hd: SCSI hard disk drive hd: SCSI hard disk drive
rm: SCSI removable media drive rm: SCSI removable media drive
@ -112,16 +119,16 @@ OPTIONS
daynaport: DaynaPORT network adapter daynaport: DaynaPORT network adapter
-n VENDOR:PRODUCT:REVISION -n VENDOR:PRODUCT:REVISION
The vendor, product and revision for the device, to be returned The vendor, product and revision for the device, to be returned
with the INQUIRY data. A complete set of name components must be with the INQUIRY data. A complete set of name components must be
provided. VENDOR may have up to 8, PRODUCT up to 16, REVISION up provided. VENDOR may have up to 8, PRODUCT up to 16, REVISION up
to 4 characters. Padding with blanks to the maxium length is au to 4 characters. Padding with blanks to the maxium length is au
tomatically applied. Once set the name of a device cannot be tomatically applied. Once set the name of a device cannot be
changed. changed.
-u UNIT -u UNIT
Unit number (0 or 1). This will default to 0. This option is Unit number (0 or 1). This will default to 0. This option is
only used when there are multiple SCSI devices on a shared SCSI only used when there are multiple SCSI devices on a shared SCSI
controller. (This is not common) controller. (This is not common)
EXAMPLES EXAMPLES
@ -140,7 +147,7 @@ EXAMPLES
rasctl -i 0 -f HDIIMAGE0.HDS rasctl -i 0 -f HDIIMAGE0.HDS
SEE ALSO SEE ALSO
rascsi(1) scsimon(1) rascsi(1), scsimon(1), rasdump(1), sasidump(1)
Full documentation is available at: Full documentation is available at:
<https://www.github.com/akuker/RASCSI/wiki/> <https://www.github.com/akuker/RASCSI/wiki/>

View File

@ -101,6 +101,8 @@ SRC_SCSIMON = \
SRC_RASCTL = \ SRC_RASCTL = \
rasctl.cpp\ rasctl.cpp\
rasctl_commands.cpp \
rasctl_display.cpp \
rascsi_version.cpp \ rascsi_version.cpp \
rasutil.cpp \ rasutil.cpp \
protobuf_util.cpp protobuf_util.cpp

View File

@ -206,12 +206,24 @@ void ProtobufResponseHandler::GetAvailableImages(PbResult& result, PbServerInfo&
result.set_status(true); result.set_status(true);
} }
void ProtobufResponseHandler::GetDevices(PbServerInfo& serverInfo, const vector<Device *>& devices, const string& image_folder) PbReservedIdsInfo *ProtobufResponseHandler::GetReservedIds(PbResult& result, const set<int>& ids)
{
PbReservedIdsInfo *reserved_ids_info = new PbReservedIdsInfo();
for (int id : ids) {
reserved_ids_info->add_ids(id);
}
result.set_status(true);
return reserved_ids_info;
}
void ProtobufResponseHandler::GetDevices(PbServerInfo& server_info, const vector<Device *>& devices, const string& image_folder)
{ {
for (const Device *device : devices) { for (const Device *device : devices) {
// Skip if unit does not exist or is not assigned // Skip if unit does not exist or is not assigned
if (device) { if (device) {
PbDevice *pb_device = serverInfo.mutable_devices()->add_devices(); PbDevice *pb_device = server_info.mutable_devices_info()->add_devices();
GetDevice(device, pb_device, image_folder); GetDevice(device, pb_device, image_folder);
} }
} }
@ -243,12 +255,12 @@ void ProtobufResponseHandler::GetDevicesInfo(PbResult& result, const PbCommand&
} }
} }
PbDevices *pb_devices = new PbDevices(); PbDevicesInfo *devices_info = new PbDevicesInfo();
result.set_allocated_device_info(pb_devices); result.set_allocated_devices_info(devices_info);
for (const auto& id_set : id_sets) { for (const auto& id_set : id_sets) {
const Device *device = devices[id_set.first * unit_count + id_set.second]; const Device *device = devices[id_set.first * unit_count + id_set.second];
GetDevice(device, pb_devices->add_devices(), image_folder); GetDevice(device, devices_info->add_devices(), image_folder);
} }
result.set_status(true); result.set_status(true);
@ -266,34 +278,50 @@ PbDeviceTypesInfo *ProtobufResponseHandler::GetDeviceTypesInfo(PbResult& result,
} }
PbServerInfo *ProtobufResponseHandler::GetServerInfo(PbResult& result, const vector<Device *>& devices, const set<int>& reserved_ids, PbServerInfo *ProtobufResponseHandler::GetServerInfo(PbResult& result, const vector<Device *>& devices, const set<int>& reserved_ids,
const string& image_folder, const string& log_level) const string& image_folder, const string& current_log_level)
{ {
PbServerInfo *server_info = new PbServerInfo(); PbServerInfo *server_info = new PbServerInfo();
server_info->set_major_version(rascsi_major_version); server_info->set_allocated_version_info(GetVersionInfo(result));
server_info->set_minor_version(rascsi_minor_version); server_info->set_allocated_log_level_info(GetLogLevelInfo(result, current_log_level));
server_info->set_patch_version(rascsi_patch_version);
GetLogLevels(*server_info);
server_info->set_current_log_level(log_level);
GetAllDeviceTypeProperties(*server_info->mutable_device_types_info()); GetAllDeviceTypeProperties(*server_info->mutable_device_types_info());
GetAvailableImages(result, *server_info, image_folder); GetAvailableImages(result, *server_info, image_folder);
server_info->set_allocated_network_interfaces_info(GetNetworkInterfacesInfo(result)); server_info->set_allocated_network_interfaces_info(GetNetworkInterfacesInfo(result));
server_info->set_allocated_mapping_info(GetMappingInfo(result)); server_info->set_allocated_mapping_info(GetMappingInfo(result));
GetDevices(*server_info, devices, image_folder); GetDevices(*server_info, devices, image_folder);
for (int id : reserved_ids) { server_info->set_allocated_reserved_ids_info(GetReservedIds(result, reserved_ids));
server_info->add_reserved_ids(id);
}
result.set_status(true); result.set_status(true);
return server_info; return server_info;
} }
void ProtobufResponseHandler::GetLogLevels(PbServerInfo& server_info) PbVersionInfo *ProtobufResponseHandler::GetVersionInfo(PbResult& result)
{ {
PbVersionInfo *version_info = new PbVersionInfo();
version_info->set_major_version(rascsi_major_version);
version_info->set_minor_version(rascsi_minor_version);
version_info->set_patch_version(rascsi_patch_version);
result.set_status(true);
return version_info;
}
PbLogLevelInfo *ProtobufResponseHandler::GetLogLevelInfo(PbResult& result, const string& current_log_level)
{
PbLogLevelInfo *log_level_info = new PbLogLevelInfo();
for (const auto& log_level : log_levels) { for (const auto& log_level : log_levels) {
server_info.add_log_levels(log_level); log_level_info->add_log_levels(log_level);
} }
log_level_info->set_current_log_level(current_log_level);
result.set_status(true);
return log_level_info;
} }
PbNetworkInterfacesInfo *ProtobufResponseHandler::GetNetworkInterfacesInfo(PbResult& result) PbNetworkInterfacesInfo *ProtobufResponseHandler::GetNetworkInterfacesInfo(PbResult& result)

View File

@ -32,12 +32,15 @@ public:
bool GetImageFile(PbImageFile *, const string&, const string&); bool GetImageFile(PbImageFile *, const string&, const string&);
PbImageFilesInfo *GetAvailableImages(PbResult&, const string&); PbImageFilesInfo *GetAvailableImages(PbResult&, const string&);
PbReservedIdsInfo *GetReservedIds(PbResult&, const set<int>&);
void GetDevices(PbServerInfo&, const vector<Device *>&, const string&); void GetDevices(PbServerInfo&, const vector<Device *>&, const string&);
void GetDevicesInfo(PbResult&, const PbCommand&, const vector<Device *>&, const string&, int); void GetDevicesInfo(PbResult&, const PbCommand&, const vector<Device *>&, const string&, int);
PbDeviceTypesInfo *GetDeviceTypesInfo(PbResult&, const PbCommand&); PbDeviceTypesInfo *GetDeviceTypesInfo(PbResult&, const PbCommand&);
PbVersionInfo *GetVersionInfo(PbResult&);
PbServerInfo *GetServerInfo(PbResult&, const vector<Device *>&, const set<int>&, const string&, const string&); PbServerInfo *GetServerInfo(PbResult&, const vector<Device *>&, const set<int>&, const string&, const string&);
PbNetworkInterfacesInfo *GetNetworkInterfacesInfo(PbResult&); PbNetworkInterfacesInfo *GetNetworkInterfacesInfo(PbResult&);
PbMappingInfo *GetMappingInfo(PbResult&); PbMappingInfo *GetMappingInfo(PbResult&);
PbLogLevelInfo *GetLogLevelInfo(PbResult&, const string&);
private: private:
@ -50,5 +53,4 @@ private:
void GetAllDeviceTypeProperties(PbDeviceTypesInfo&); void GetAllDeviceTypeProperties(PbDeviceTypesInfo&);
void GetDeviceTypeProperties(PbDeviceTypesInfo&, PbDeviceType); void GetDeviceTypeProperties(PbDeviceTypesInfo&, PbDeviceType);
void GetAvailableImages(PbResult& result, PbServerInfo&, const string&); void GetAvailableImages(PbResult& result, PbServerInfo&, const string&);
void GetLogLevels(PbServerInfo&);
}; };

View File

@ -13,7 +13,9 @@
#include "google/protobuf/message.h" #include "google/protobuf/message.h"
#include "rascsi_interface.pb.h" #include "rascsi_interface.pb.h"
#include <string>
using namespace std;
using namespace rascsi_interface; using namespace rascsi_interface;
const string GetParam(const PbCommand&, const string&); const string GetParam(const PbCommand&, const string&);

View File

@ -498,8 +498,12 @@ string SetReservedIds(const string& ids)
set<int> reserved; set<int> reserved;
for (string id_to_reserve : ids_to_reserve) { for (string id_to_reserve : ids_to_reserve) {
int id; int id;
if (!GetAsInt(id_to_reserve, id)) { if (!GetAsInt(id_to_reserve, id) || id > 7) {
return id_to_reserve; return "Invalid ID " + id_to_reserve;
}
if (devices[id * UnitNum]) {
return "ID " + id_to_reserve + " is currently in use";
} }
reserved.insert(id); reserved.insert(id);
@ -508,16 +512,14 @@ string SetReservedIds(const string& ids)
reserved_ids = reserved; reserved_ids = reserved;
if (!reserved_ids.empty()) { if (!reserved_ids.empty()) {
list<int> ids = { reserved_ids.begin(), reserved_ids.end() };
ids.sort([](const auto& a, const auto& b) { return a < b; });
ostringstream s; ostringstream s;
bool isFirst = true; bool isFirst = true;
for (auto const& id : ids) { for (auto const& reserved_id : reserved_ids) {
if (!isFirst) { if (!isFirst) {
s << ", "; s << ", ";
} }
isFirst = false; isFirst = false;
s << id; s << reserved_id;
} }
LOGINFO("Reserved ID(s) set to %s", s.str().c_str()); LOGINFO("Reserved ID(s) set to %s", s.str().c_str());
@ -1236,11 +1238,11 @@ bool ProcessCmd(const int fd, const PbCommand& command)
DetachAll(); DetachAll();
return ReturnStatus(fd); return ReturnStatus(fd);
case RESERVE: { case RESERVE_IDS: {
const string ids = GetParam(command, "ids"); const string ids = GetParam(command, "ids");
string invalid_id = SetReservedIds(ids); string error = SetReservedIds(ids);
if (!invalid_id.empty()) { if (!error.empty()) {
return ReturnStatus(fd, false, "Invalid ID " + invalid_id + " for " + PbOperation_Name(RESERVE)); return ReturnStatus(fd, false, error);
} }
return ReturnStatus(fd); return ReturnStatus(fd);
@ -1365,9 +1367,9 @@ bool ParseArgument(int argc, char* argv[], int& port)
continue; continue;
case 'r': { case 'r': {
string invalid_id = SetReservedIds(optarg); string error = SetReservedIds(optarg);
if (!invalid_id.empty()) { if (!error.empty()) {
cerr << "Invalid ID " << invalid_id << " for " << PbOperation_Name(RESERVE); cerr << error << endl;
return false; return false;
} }
} }
@ -1446,7 +1448,7 @@ bool ParseArgument(int argc, char* argv[], int& port)
// Display and log the device list // Display and log the device list
PbServerInfo server_info; PbServerInfo server_info;
response_helper.GetDevices(server_info, devices, default_image_folder); response_helper.GetDevices(server_info, devices, default_image_folder);
const list<PbDevice>& devices = { server_info.devices().devices().begin(), server_info.devices().devices().end() }; const list<PbDevice>& devices = { server_info.devices_info().devices().begin(), server_info.devices_info().devices().end() };
const string device_list = ListDevices(devices); const string device_list = ListDevices(devices);
LogDevices(device_list); LogDevices(device_list);
cout << device_list << endl; cout << device_list << endl;
@ -1556,7 +1558,7 @@ static void *MonThread(void *param)
// For backwards compatibility: Log device list if information on all devices was requested. // For backwards compatibility: Log device list if information on all devices was requested.
if (!command.devices_size()) { if (!command.devices_size()) {
const list<PbDevice>& devices = { result.device_info().devices().begin(), result.device_info().devices().end() }; const list<PbDevice>& devices = { result.devices_info().devices().begin(), result.devices_info().devices().end() };
LogDevices(ListDevices(devices)); LogDevices(ListDevices(devices));
} }
break; break;
@ -1571,7 +1573,6 @@ static void *MonThread(void *param)
break; break;
} }
case SERVER_INFO: { case SERVER_INFO: {
LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str()); LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str());
@ -1582,6 +1583,24 @@ static void *MonThread(void *param)
break; break;
} }
case VERSION_INFO: {
LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str());
PbResult result;
result.set_allocated_version_info(response_helper.GetVersionInfo(result));
SerializeMessage(fd, result);
break;
}
case LOG_LEVEL_INFO: {
LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str());
PbResult result;
result.set_allocated_log_level_info(response_helper.GetLogLevelInfo(result, current_log_level));
SerializeMessage(fd, result);
break;
}
case DEFAULT_IMAGE_FILES_INFO: { case DEFAULT_IMAGE_FILES_INFO: {
LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str()); LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str());
@ -1632,6 +1651,15 @@ static void *MonThread(void *param)
break; break;
} }
case RESERVED_IDS_INFO: {
LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str());
PbResult result;
result.set_allocated_reserved_ids_info(response_helper.GetReservedIds(result, reserved_ids));
SerializeMessage(fd, result);
break;
}
default: { default: {
// Wait until we become idle // Wait until we become idle
while (active) { while (active) {

View File

@ -66,76 +66,85 @@ enum PbOperation {
// Gets the server information // Gets the server information
SERVER_INFO = 10; SERVER_INFO = 10;
// Gets information on attached devices. Returns data for all attached devices if empty. // Get rascsi version information
DEVICES_INFO = 11; VERSION_INFO = 11;
// Device properties by device type
DEVICE_TYPES_INFO = 12;
// Gets information on available image files in the default image folder. // Get information on attached devices. Returns data for all attached devices if the device list is empty.
DEFAULT_IMAGE_FILES_INFO = 13; DEVICES_INFO = 12;
// Get device properties by device type
DEVICE_TYPES_INFO = 13;
// Get information on available image files in the default image folder.
DEFAULT_IMAGE_FILES_INFO = 14;
// Gets information on an image file (not necessarily in the default image folder) based on an absolute path. // Get information on an image file (not necessarily in the default image folder) based on an absolute path.
// Parameters: // Parameters:
// "file": The filename. Either an absolute path or a path relative to the default image folder. // "file": The filename. Either an absolute path or a path relative to the default image folder.
IMAGE_FILE_INFO = 14; IMAGE_FILE_INFO = 15;
// Gets the names of the available network interfaces. Only lists interfaces that are up. // Get information on the available log levels and the current log level
NETWORK_INTERFACES_INFO = 15; LOG_LEVEL_INFO = 16;
// Get the names of the available network interfaces. Only lists interfaces that are up.
NETWORK_INTERFACES_INFO = 17;
// Gets the mapping of extensions to device types // Get the mapping of extensions to device types
MAPPING_INFO = 16; MAPPING_INFO = 18;
// Get the list of reserved device IDs
RESERVED_IDS_INFO = 19;
// Set the default folder for image files. // Set the default folder for image files.
// Parameters: // Parameters:
// "folder": The default folder name. // "folder": The default folder name.
DEFAULT_FOLDER = 17; DEFAULT_FOLDER = 20;
// Set server log level. // Set a new log level.
// Parameters: // Parameters:
// "level": The new log level // "level": The new log level
LOG_LEVEL = 18; LOG_LEVEL = 21;
// Block IDs from being used, usually the IDs of the initiators (computers) in the SCSI chain. // Block IDs from being used, usually the IDs of the initiators (computers) in the SCSI chain.
// Parameters: // Parameters:
// "ids": A comma-separated list of IDs to reserve, or an empty string in order not to reserve any ID. // "ids": A comma-separated list of IDs to reserve, or an empty string in order not to reserve any ID.
RESERVE = 19; RESERVE_IDS = 22;
// Create an image file. The image file must not yet exist. // Create an image file. The image file must not yet exist.
// Parameters: // Parameters:
// "file": The filename, relative to the default image folder. It must not contain a slash. // "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 // "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" // "read_only": "true" (case-insensitive) in order to create a read-only file, otherwise "false"
CREATE_IMAGE = 20; CREATE_IMAGE = 23;
// Delete an image file. // Delete an image file.
// Parameters: // Parameters:
// "file": The filename, relative to the default image folder. It must not contain a slash. // "file": The filename, relative to the default image folder. It must not contain a slash.
DELETE_IMAGE = 21; DELETE_IMAGE = 24;
// Rename an image file. // Rename an image file.
// Parameters: // Parameters:
// "from": The old filename, relative to the default image folder. It must not contain a slash. // "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. // "to": The new filename, relative to the default image folder. It must not contain a slash.
// The new filename must not yet exist. // The new filename must not yet exist.
RENAME_IMAGE = 22; RENAME_IMAGE = 25;
// Copy an image file. // Copy an image file.
// Parameters: // Parameters:
// "from": The source filename, relative to the default image folder. It must not contain a slash. // "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. // "to": The destination filename, relative to the default image folder. It must not contain a slash.
// The destination filename must not yet exist. // The destination filename must not yet exist.
COPY_IMAGE = 23; COPY_IMAGE = 26;
// Write-protect an image file. // Write-protect an image file.
// Parameters: // Parameters:
// "file": The filename, relative to the default image folder. It must not contain a slash. // "file": The filename, relative to the default image folder. It must not contain a slash.
PROTECT_IMAGE = 24; PROTECT_IMAGE = 27;
// Make an image file writable. // Make an image file writable.
// Parameters: // Parameters:
// "file": The filename, relative to the default image folder. It must not contain a slash. // "file": The filename, relative to the default image folder. It must not contain a slash.
UNPROTECT_IMAGE = 25; UNPROTECT_IMAGE = 28;
} }
// The supported file extensions mapped to their respective device types // The supported file extensions mapped to their respective device types
@ -162,7 +171,7 @@ message PbDeviceProperties {
// List of default parameters, if any (requires supports_params to be true) // List of default parameters, if any (requires supports_params to be true)
map<string, string> default_params = 8; map<string, string> default_params = 8;
// Number of supported LUNs, at least 1 (for LUN 0) // Number of supported LUNs, at least 1 (for LUN 0)
uint32 luns = 9; int32 luns = 9;
// Unordered list of permitted block sizes in bytes, empty if the block size is not configurable // Unordered list of permitted block sizes in bytes, empty if the block size is not configurable
repeated uint32 block_sizes = 10; repeated uint32 block_sizes = 10;
} }
@ -205,6 +214,13 @@ message PbImageFilesInfo {
repeated PbImageFile image_files = 2; repeated PbImageFile image_files = 2;
} }
// Log level information
message PbLogLevelInfo {
// List of available log levels, ordered by increasing by severity
repeated string log_levels = 2;
string current_log_level = 3;
}
// The network interfaces information // The network interfaces information
message PbNetworkInterfacesInfo { message PbNetworkInterfacesInfo {
repeated string name = 1; repeated string name = 1;
@ -244,13 +260,27 @@ message PbDevice {
// Block size in bytes // Block size in bytes
int32 block_size = 11; int32 block_size = 11;
// Number of blocks // Number of blocks
int64 block_count = 12; uint64 block_count = 12;
} }
message PbDevices { message PbDevicesInfo {
repeated PbDevice devices = 1; repeated PbDevice devices = 1;
} }
// The reserved device IDs
message PbReservedIdsInfo {
repeated int32 ids = 1;
}
// Rascsi server version information
message PbVersionInfo {
// The rascsi version
int32 major_version = 1;
int32 minor_version = 2;
// < 0 for a development version, = 0 if there is no patch yet
int32 patch_version = 3;
}
// Commands rascsi can execute and their parameters // Commands rascsi can execute and their parameters
message PbCommand { message PbCommand {
PbOperation operation = 1; PbOperation operation = 1;
@ -270,41 +300,43 @@ message PbResult {
oneof result { oneof result {
// The result of a SERVER_INFO command // The result of a SERVER_INFO command
PbServerInfo server_info = 3; PbServerInfo server_info = 3;
// The result of a DEVICE_INFO command // The result of a VERSION_INFO command
PbDevices device_info = 4; PbVersionInfo version_info = 4;
// The result of a LOG_LEVEL_INFO command
PbLogLevelInfo log_level_info = 5;
// The result of a DEVICES_INFO command
PbDevicesInfo devices_info = 6;
// The result of a DEVICE_TYPES_INFO command // The result of a DEVICE_TYPES_INFO command
PbDeviceTypesInfo device_types_info = 5; PbDeviceTypesInfo device_types_info = 7;
// The result of a DEFAULT_IMAGE_FILES_INFO command // The result of a DEFAULT_IMAGE_FILES_INFO command
PbImageFilesInfo image_files_info = 6; PbImageFilesInfo image_files_info = 8;
// The result of an IMAGE_FILE_INFO command // The result of an IMAGE_FILE_INFO command
PbImageFile image_file_info = 7; PbImageFile image_file_info = 9;
// The result of a NETWORK_INTERFACES_INFO command // The result of a NETWORK_INTERFACES_INFO command
PbNetworkInterfacesInfo network_interfaces_info = 8; PbNetworkInterfacesInfo network_interfaces_info = 10;
// The result of an MAPPING_INFO command // The result of an MAPPING_INFO command
PbMappingInfo mapping_info = 9; PbMappingInfo mapping_info = 11;
// The result of a RESERVED_IDS_INFO command
PbReservedIdsInfo reserved_ids_info = 12;
} }
} }
// The rascsi server information // The rascsi server information. All data can also be requested with individual commands.
message PbServerInfo { message PbServerInfo {
// The rascsi server version // The rascsi server version data
uint32 major_version = 1; PbVersionInfo version_info = 1;
uint32 minor_version = 2; // The available log levels and the current log level
// < 0 for a development version, = 0 if there is no patch yet PbLogLevelInfo log_level_info = 2;
int32 patch_version = 3; // Supported device types and their properties
// List of available log levels, ordered by increasing by severity PbDeviceTypesInfo device_types_info = 3;
repeated string log_levels = 4; // The image files in the default folder
string current_log_level = 5; PbImageFilesInfo image_files_info = 4;
// Supported device types and their properties, also available separately // The available (up) network interfaces
PbDeviceTypesInfo device_types_info = 6; PbNetworkInterfacesInfo network_interfaces_info = 5;
// The image files in the default folder, also available separately
PbImageFilesInfo image_files_info = 7;
// The available (up) network interfaces, also available separately
PbNetworkInterfacesInfo network_interfaces_info = 8;
// The extensions to device types mapping // The extensions to device types mapping
PbMappingInfo mapping_info = 9; PbMappingInfo mapping_info = 6;
// The attached devices, also available separately // The reserved device IDs
PbDevices devices = 10; PbReservedIdsInfo reserved_ids_info = 7;
// The unsorted list of reserved IDs // The attached devices
repeated uint32 reserved_ids = 11; PbDevicesInfo devices_info = 8;
} }

View File

@ -9,14 +9,12 @@
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#include <netdb.h>
#include "os.h" #include "os.h"
#include "rascsi_version.h" #include "rascsi_version.h"
#include "exceptions.h"
#include "protobuf_util.h" #include "protobuf_util.h"
#include "rasutil.h" #include "rasutil.h"
#include "rasctl_commands.h"
#include "rascsi_interface.pb.h" #include "rascsi_interface.pb.h"
#include <sstream>
#include <iostream> #include <iostream>
#include <list> #include <list>
@ -26,490 +24,6 @@
using namespace std; using namespace std;
using namespace rascsi_interface; using namespace rascsi_interface;
void SendCommand(const string& hostname, int port, const PbCommand& command, PbResult& result)
{
// Send command
int fd = -1;
try {
struct hostent *host = gethostbyname(hostname.c_str());
if (!host) {
throw io_exception("Can't resolve hostname '" + hostname + "'");
}
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0) {
throw io_exception("Can't create socket");
}
struct sockaddr_in server;
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
memcpy(&server.sin_addr.s_addr, host->h_addr, host->h_length);
if (connect(fd, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0) {
ostringstream error;
error << "Can't connect to rascsi process on host '" << hostname << "', port " << port;
throw io_exception(error.str());
}
SerializeMessage(fd, command);
}
catch(const io_exception& e) {
cerr << "Error: " << e.getmsg() << endl;
if (fd >= 0) {
close(fd);
}
exit(fd < 0 ? ENOTCONN : EXIT_FAILURE);
}
// Receive result
try {
DeserializeMessage(fd, result);
if (!result.status()) {
throw io_exception(result.msg());
}
}
catch(const io_exception& e) {
close(fd);
cerr << "Error: " << e.getmsg() << endl;
exit(EXIT_FAILURE);
}
close(fd);
if (!result.msg().empty()) {
cout << result.msg() << endl;
}
}
void DisplayDeviceInfo(const PbDevice& pb_device)
{
cout << " " << pb_device.id() << ":" << pb_device.unit() << " " << PbDeviceType_Name(pb_device.type())
<< " " << pb_device.vendor() << ":" << pb_device.product() << ":" << pb_device.revision();
if (pb_device.block_size()) {
cout << " " << pb_device.block_size() << " bytes per sector";
if (pb_device.block_count()) {
cout << " " << pb_device.block_size() * pb_device.block_count() << " bytes capacity";
}
}
if (pb_device.properties().supports_file() && !pb_device.file().name().empty()) {
cout << " " << pb_device.file().name();
}
cout << " ";
bool hasProperty = false;
if (pb_device.properties().read_only()) {
cout << "read-only";
hasProperty = true;
}
if (pb_device.properties().protectable() && pb_device.status().protected_()) {
if (hasProperty) {
cout << ", ";
}
cout << "protected";
hasProperty = true;
}
if (pb_device.properties().stoppable() && pb_device.status().stopped()) {
if (hasProperty) {
cout << ", ";
}
cout << "stopped";
hasProperty = true;
}
if (pb_device.properties().removable() && pb_device.status().removed()) {
if (hasProperty) {
cout << ", ";
}
cout << "removed";
hasProperty = true;
}
if (pb_device.properties().lockable() && pb_device.status().locked()) {
if (hasProperty) {
cout << ", ";
}
cout << "locked";
}
if (hasProperty) {
cout << " ";
}
bool isFirst = true;
for (const auto& param : pb_device.params()) {
if (!isFirst) {
cout << " ";
}
isFirst = false;
cout << param.first << "=" << param.second;
}
cout << endl;
}
void DisplayDeviceTypesInfo(const PbDeviceTypesInfo& device_types_info)
{
cout << "Supported device types and their properties:" << endl;
for (auto it = device_types_info.properties().begin(); it != device_types_info.properties().end(); ++it) {
cout << " " << PbDeviceType_Name(it->type());
const PbDeviceProperties& properties = it->properties();
cout << " Supported LUNs: " << properties.luns() << endl;
if (properties.read_only() || properties.protectable() || properties.stoppable() || properties.read_only()
|| properties.lockable()) {
cout << " Properties: ";
bool has_property = false;
if (properties.read_only()) {
cout << "read-only";
has_property = true;
}
if (properties.protectable()) {
cout << (has_property ? ", " : "") << "protectable";
has_property = true;
}
if (properties.stoppable()) {
cout << (has_property ? ", " : "") << "stoppable";
has_property = true;
}
if (properties.removable()) {
cout << (has_property ? ", " : "") << "removable";
has_property = true;
}
if (properties.lockable()) {
cout << (has_property ? ", " : "") << "lockable";
}
cout << endl;
}
if (properties.supports_file()) {
cout << " Image file support" << endl;
}
else if (properties.supports_params()) {
cout << " Parameter support" << endl;
}
if (properties.supports_params() && properties.default_params_size()) {
map<string, string> params = { properties.default_params().begin(), properties.default_params().end() };
cout << " Default parameters: ";
bool isFirst = true;
for (const auto& param : params) {
if (!isFirst) {
cout << ", ";
}
cout << param.first << "=" << param.second;
isFirst = false;
}
cout << endl;
}
if (properties.block_sizes_size()) {
list<uint32_t> block_sizes = { properties.block_sizes().begin(), properties.block_sizes().end() };
block_sizes.sort([](const auto& a, const auto& b) { return a < b; });
cout << " Configurable block sizes in bytes: ";
bool isFirst = true;
for (const auto& block_size : block_sizes) {
if (!isFirst) {
cout << ", ";
}
cout << block_size;
isFirst = false;
}
cout << endl;
}
}
}
void DisplayImageFile(const PbImageFile& image_file_info)
{
cout << image_file_info.name() << " " << image_file_info.size() << " bytes";
if (image_file_info.read_only()) {
cout << " read-only";
}
if (image_file_info.type() != UNDEFINED) {
cout << " " << PbDeviceType_Name(image_file_info.type());
}
cout << endl;
}
void DisplayImageFiles(const PbImageFilesInfo& image_files_info)
{
const list<PbImageFile> image_files = { image_files_info.image_files().begin(), image_files_info.image_files().end() };
cout << "Default image file folder: " << image_files_info.default_image_folder() << endl;
if (image_files.empty()) {
cout << " No image files available" << endl;
}
else {
list<PbImageFile> files = { image_files.begin(), image_files.end() };
files.sort([](const auto& a, const auto& b) { return a.name() < b.name(); });
cout << "Available image files:" << endl;
for (const auto& file : files) {
cout << " ";
DisplayImageFile(file);
}
}
}
void DisplayNetworkInterfaces(const PbNetworkInterfacesInfo& network_interfaces_info)
{
const list<string> interfaces = { network_interfaces_info.name().begin(), network_interfaces_info.name().end() };
cout << "Available (up) network interfaces:" << endl;
bool isFirst = true;
for (const auto& interface : interfaces) {
if (!isFirst) {
cout << ", ";
}
isFirst = false;
cout << interface;
}
cout << endl;
}
void DisplayMappingInfo(const PbMappingInfo& mapping_info)
{
const map<string, PbDeviceType> mappings = { mapping_info.mapping().begin(), mapping_info.mapping().end() };
cout << "Supported image file extension to device type mappings:" << endl;
for (const auto& mapping : mappings) {
cout << " " << mapping.first << "->" << PbDeviceType_Name(mapping.second) << endl;
}
}
//---------------------------------------------------------------------------
//
// Command implementations
//
//---------------------------------------------------------------------------
void CommandList(const string& hostname, int port)
{
PbCommand command;
command.set_operation(DEVICES_INFO);
PbResult result;
SendCommand(hostname.c_str(), port, command, result);
const list<PbDevice>& devices = { result.device_info().devices().begin(), result.device_info().devices().end() };
cout << ListDevices(devices) << endl;
}
const PbServerInfo GetServerInfo(const PbCommand& command, const string& hostname, int port)
{
PbResult result;
SendCommand(hostname.c_str(), port, command, result);
return result.server_info();
}
void CommandLogLevel(PbCommand& command, const string& hostname, int port, const string& log_level)
{
AddParam(command, "level", log_level);
PbResult result;
SendCommand(hostname.c_str(), port, command, result);
}
void CommandReserve(PbCommand& command, const string&hostname, int port, const string& reserved_ids)
{
AddParam(command, "ids", reserved_ids);
PbResult result;
SendCommand(hostname.c_str(), port, command, result);
}
void CommandCreateImage(PbCommand& command, const string&hostname, int port, const string& image_params)
{
size_t separatorPos = image_params.find(COMPONENT_SEPARATOR);
if (separatorPos != string::npos) {
AddParam(command, "file", image_params.substr(0, separatorPos));
AddParam(command, "size", image_params.substr(separatorPos + 1));
}
else {
cerr << "Error: Invalid file descriptor '" << image_params << "', format is NAME:SIZE" << endl;
exit(EXIT_FAILURE);
}
AddParam(command, "read_only", "false");
PbResult result;
SendCommand(hostname.c_str(), port, command, result);
}
void CommandDeleteImage(PbCommand& command, const string&hostname, int port, const string& filename)
{
AddParam(command, "file", filename);
PbResult result;
SendCommand(hostname.c_str(), port, command, result);
}
void CommandRenameImage(PbCommand& command, const string&hostname, int port, const string& image_params)
{
size_t separatorPos = image_params.find(COMPONENT_SEPARATOR);
if (separatorPos != string::npos) {
AddParam(command, "from", image_params.substr(0, separatorPos));
AddParam(command, "to", image_params.substr(separatorPos + 1));
}
else {
cerr << "Error: Invalid file descriptor '" << image_params << "', format is CURRENT_NAME:NEW_NAME" << endl;
exit(EXIT_FAILURE);
}
PbResult result;
SendCommand(hostname.c_str(), port, command, result);
}
void CommandCopyImage(PbCommand& command, const string&hostname, int port, const string& image_params)
{
size_t separatorPos = image_params.find(COMPONENT_SEPARATOR);
if (separatorPos != string::npos) {
AddParam(command, "from", image_params.substr(0, separatorPos));
AddParam(command, "to", image_params.substr(separatorPos + 1));
}
else {
cerr << "Error: Invalid file descriptor '" << image_params << "', format is CURRENT_NAME:NEW_NAME" << endl;
exit(EXIT_FAILURE);
}
PbResult result;
SendCommand(hostname.c_str(), port, command, result);
}
void CommandDefaultImageFolder(PbCommand& command, const string& hostname, int port, const string& folder)
{
AddParam(command, "folder", folder);
PbResult result;
SendCommand(hostname.c_str(), port, command, result);
}
void CommandDeviceInfo(const PbCommand& command, const string& hostname, int port)
{
PbResult result;
SendCommand(hostname.c_str(), port, command, result);
for (const auto& pb_device : result.device_info().devices()) {
DisplayDeviceInfo(pb_device);
}
}
void CommandDeviceTypesInfo(const PbCommand& command, const string& hostname, int port)
{
PbResult result;
SendCommand(hostname.c_str(), port, command, result);
DisplayDeviceTypesInfo(result.device_types_info());
}
void CommandServerInfo(PbCommand& command, const string& hostname, int port)
{
PbResult result;
SendCommand(hostname.c_str(), port, command, result);
PbServerInfo server_info = result.server_info();
cout << "rascsi server version: " << server_info.major_version() << "." << server_info.minor_version();
if (server_info.patch_version() > 0) {
cout << "." << server_info.patch_version();
}
else if (server_info.patch_version() < 0) {
cout << " (development version)";
}
cout << endl;
if (!server_info.log_levels_size()) {
cout << " No log level settings available" << endl;
}
else {
cout << "rascsi log levels, sorted by severity:" << endl;
for (const auto& log_level : server_info.log_levels()) {
cout << " " << log_level << endl;
}
cout << "Current rascsi log level: " << server_info.current_log_level() << endl;
}
DisplayImageFiles(server_info.image_files_info());
DisplayMappingInfo(server_info.mapping_info());
DisplayNetworkInterfaces(server_info.network_interfaces_info());
DisplayDeviceTypesInfo(server_info.device_types_info());
if (server_info.reserved_ids_size()) {
cout << "Reserved device IDs: ";
for (int i = 0; i < server_info.reserved_ids_size(); i++) {
if(i) {
cout << ", ";
}
cout << server_info.reserved_ids(i);
}
cout <<endl;
}
if (server_info.devices().devices_size()) {
list<PbDevice> sorted_devices = { server_info.devices().devices().begin(), server_info.devices().devices().end() };
sorted_devices.sort([](const auto& a, const auto& b) { return a.id() < b.id(); });
cout << "Attached devices:" << endl;
for (const auto& device : sorted_devices) {
DisplayDeviceInfo(device);
}
}
}
void CommandDefaultImageFilesInfo(const PbCommand& command, const string& hostname, int port)
{
PbResult result;
SendCommand(hostname.c_str(), port, command, result);
DisplayImageFiles(result.image_files_info());
}
void CommandImageFileInfo(PbCommand& command, const string& hostname, int port, const string& filename)
{
AddParam(command, "file", filename);
PbResult result;
SendCommand(hostname.c_str(), port, command, result);
DisplayImageFile(result.image_file_info());
}
void CommandNetworkInterfacesInfo(const PbCommand& command, const string&hostname, int port)
{
PbResult result;
SendCommand(hostname.c_str(), port, command, result);
DisplayNetworkInterfaces(result.network_interfaces_info());
}
void CommandMappingInfo(const PbCommand& command, const string&hostname, int port)
{
PbResult result;
SendCommand(hostname.c_str(), port, command, result);
DisplayMappingInfo(result.mapping_info());
}
PbOperation ParseOperation(const char *optarg) PbOperation ParseOperation(const char *optarg)
{ {
switch (tolower(optarg[0])) { switch (tolower(optarg[0])) {
@ -549,7 +63,7 @@ PbDeviceType ParseType(const char *optarg)
return type; return type;
} }
else { else {
// Parse convenience types (shortcuts) // Parse convenience device types (shortcuts)
switch (tolower(optarg[0])) { switch (tolower(optarg[0])) {
case 'c': case 'c':
return SCCD; return SCCD;
@ -574,11 +88,6 @@ PbDeviceType ParseType(const char *optarg)
return UNDEFINED; return UNDEFINED;
} }
//---------------------------------------------------------------------------
//
// Main processing
//
//---------------------------------------------------------------------------
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
GOOGLE_PROTOBUF_VERIFY_VERSION; GOOGLE_PROTOBUF_VERIFY_VERSION;
@ -590,7 +99,7 @@ int main(int argc, char* argv[])
cerr << "Usage: " << argv[0] << " -i ID [-u UNIT] [-c CMD] [-C FILE] [-t TYPE] [-b BLOCK_SIZE] [-n NAME] [-f FILE|PARAM] "; cerr << "Usage: " << argv[0] << " -i ID [-u UNIT] [-c CMD] [-C FILE] [-t TYPE] [-b BLOCK_SIZE] [-n NAME] [-f FILE|PARAM] ";
cerr << "[-F IMAGE_FOLDER] [-L LOG_LEVEL] [-h HOST] [-p PORT] [-r RESERVED_IDS] "; cerr << "[-F IMAGE_FOLDER] [-L LOG_LEVEL] [-h HOST] [-p PORT] [-r RESERVED_IDS] ";
cerr << "[-C FILENAME:FILESIZE] [-w FILENAME] [-R CURRENT_NAME:NEW_NAME] [-x CURRENT_NAME:NEW_NAME] "; cerr << "[-C FILENAME:FILESIZE] [-w FILENAME] [-R CURRENT_NAME:NEW_NAME] [-x CURRENT_NAME:NEW_NAME] ";
cerr << "[-e] [-E FILENAME] [-l] [-L] [-m] [-s] [-v] [-y]" << endl; cerr << "[-e] [-E FILENAME] [-I] [-l] [-L] [-m] [-O] [-s] [-v] [-V] [-y]" << endl;
cerr << " where ID := {0-7}" << endl; cerr << " where ID := {0-7}" << endl;
cerr << " UNIT := {0|1}, default is 0" << endl; cerr << " UNIT := {0|1}, default is 0" << endl;
cerr << " CMD := {attach|detach|insert|eject|protect|unprotect|show}" << endl; cerr << " CMD := {attach|detach|insert|eject|protect|unprotect|show}" << endl;
@ -610,7 +119,6 @@ int main(int argc, char* argv[])
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
// Parse the arguments
PbCommand command; PbCommand command;
list<PbDeviceDefinition> devices; list<PbDeviceDefinition> devices;
PbDeviceDefinition* device = command.add_devices(); PbDeviceDefinition* device = command.add_devices();
@ -627,7 +135,7 @@ int main(int argc, char* argv[])
opterr = 1; opterr = 1;
int opt; int opt;
while ((opt = getopt(argc, argv, "elmsvNTD:L:R:a:b:c:f:h:i:n:p:r:t:u:x:C:E:F:L:")) != -1) { while ((opt = getopt(argc, argv, "elmsvINOTVa:b:c:f:h:i:n:p:r:t:u:x:C:D:E:F:L:R:")) != -1) {
switch (opt) { switch (opt) {
case 'i': case 'i':
device->set_id(optarg[0] - '0'); device->set_id(optarg[0] - '0');
@ -677,6 +185,23 @@ int main(int argc, char* argv[])
param = optarg; param = optarg;
break; break;
case 'h':
hostname = optarg;
break;
case 'I':
command.set_operation(RESERVED_IDS_INFO);
break;
case 'L':
command.set_operation(LOG_LEVEL);
log_level = optarg;
break;
case 'l':
list = true;
break;
case 'm': case 'm':
command.set_operation(MAPPING_INFO); command.set_operation(MAPPING_INFO);
break; break;
@ -685,6 +210,10 @@ int main(int argc, char* argv[])
command.set_operation(NETWORK_INTERFACES_INFO); command.set_operation(NETWORK_INTERFACES_INFO);
break; break;
case 'O':
command.set_operation(LOG_LEVEL_INFO);
break;
case 't': case 't':
device->set_type(ParseType(optarg)); device->set_type(ParseType(optarg));
if (device->type() == UNDEFINED) { if (device->type() == UNDEFINED) {
@ -693,17 +222,9 @@ int main(int argc, char* argv[])
} }
break; break;
case 'L': case 'r':
command.set_operation(LOG_LEVEL); command.set_operation(RESERVE_IDS);
log_level = optarg; reserved_ids = optarg;
break;
case 'h':
hostname = optarg;
break;
case 'l':
list = true;
break; break;
case 'R': case 'R':
@ -747,20 +268,19 @@ int main(int argc, char* argv[])
} }
break; break;
case 'r':
command.set_operation(RESERVE);
reserved_ids = optarg;
break;
case 's': case 's':
command.set_operation(SERVER_INFO); command.set_operation(SERVER_INFO);
break; break;
case 'v': case 'v':
cout << rascsi_get_version_string() << endl; cout << "rasctl version: " << rascsi_get_version_string() << endl;
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
break; break;
case 'V':
command.set_operation(VERSION_INFO);
break;
case 'x': case 'x':
command.set_operation(COPY_IMAGE); command.set_operation(COPY_IMAGE);
image_params = optarg; image_params = optarg;
@ -781,83 +301,96 @@ int main(int argc, char* argv[])
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
switch(command.operation()) { // Listing devices is a special case (rasctl backwards compatibility)
case LOG_LEVEL:
CommandLogLevel(command, hostname, port, log_level);
exit(EXIT_SUCCESS);
case DEFAULT_FOLDER:
CommandDefaultImageFolder(command, hostname, port, default_folder);
exit(EXIT_SUCCESS);
case RESERVE:
CommandReserve(command, hostname, port, reserved_ids);
exit(EXIT_SUCCESS);
case CREATE_IMAGE:
CommandCreateImage(command, hostname, port, image_params);
exit(EXIT_SUCCESS);
case DELETE_IMAGE:
CommandDeleteImage(command, hostname, port, image_params);
exit(EXIT_SUCCESS);
case RENAME_IMAGE:
CommandRenameImage(command, hostname, port, image_params);
exit(EXIT_SUCCESS);
case COPY_IMAGE:
CommandCopyImage(command, hostname, port, image_params);
exit(EXIT_SUCCESS);
case DEVICES_INFO:
CommandDeviceInfo(command, hostname, port);
exit(EXIT_SUCCESS);
case DEVICE_TYPES_INFO:
CommandDeviceTypesInfo(command, hostname, port);
exit(EXIT_SUCCESS);
case SERVER_INFO:
CommandServerInfo(command, hostname, port);
exit(EXIT_SUCCESS);
case DEFAULT_IMAGE_FILES_INFO:
CommandDefaultImageFilesInfo(command, hostname, port);
exit(EXIT_SUCCESS);
case IMAGE_FILE_INFO:
CommandImageFileInfo(command, hostname, port, filename);
exit(EXIT_SUCCESS);
case NETWORK_INTERFACES_INFO:
CommandNetworkInterfacesInfo(command, hostname, port);
exit(EXIT_SUCCESS);
case MAPPING_INFO:
CommandMappingInfo(command, hostname, port);
exit(EXIT_SUCCESS);
default:
break;
}
if (list) { if (list) {
CommandList(hostname, port); PbCommand command_list;
command_list.set_operation(DEVICES_INFO);
RasctlCommands rasctl_commands(command_list, hostname, port);
rasctl_commands.CommandDevicesInfo();
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
if (!param.empty()) { if (!param.empty()) {
if (device->type() == SCBR || device->type() == SCDP) { // Only one of these parameters will be used, depending on the device type
AddParam(*device, "interfaces", param); AddParam(*device, "interfaces", param);
} AddParam(*device, "file", param);
else {
AddParam(*device, "file", param);
}
} }
PbResult result; RasctlCommands rasctl_commands(command, hostname, port);
SendCommand(hostname, port, command, result);
switch(command.operation()) {
case LOG_LEVEL:
rasctl_commands.CommandLogLevel(log_level);
break;
case DEFAULT_FOLDER:
rasctl_commands.CommandDefaultImageFolder(default_folder);
break;
case RESERVE_IDS:
rasctl_commands.CommandReserveIds(reserved_ids);
break;
case CREATE_IMAGE:
rasctl_commands.CommandCreateImage(image_params);
break;
case DELETE_IMAGE:
rasctl_commands.CommandDeleteImage(image_params);
break;
case RENAME_IMAGE:
rasctl_commands.CommandRenameImage(image_params);
break;
case COPY_IMAGE:
rasctl_commands.CommandCopyImage(image_params);
break;
case DEVICES_INFO:
rasctl_commands.CommandDeviceInfo();
break;
case DEVICE_TYPES_INFO:
rasctl_commands.CommandDeviceTypesInfo();
break;
case VERSION_INFO:
rasctl_commands.CommandVersionInfo();
break;
case SERVER_INFO:
rasctl_commands.CommandServerInfo();
break;
case DEFAULT_IMAGE_FILES_INFO:
rasctl_commands.CommandDefaultImageFilesInfo();
break;
case IMAGE_FILE_INFO:
rasctl_commands.CommandImageFileInfo(hostname);
break;
case NETWORK_INTERFACES_INFO:
rasctl_commands.CommandNetworkInterfacesInfo();
break;
case LOG_LEVEL_INFO:
rasctl_commands.CommandLogLevelInfo();
break;
case RESERVED_IDS_INFO:
rasctl_commands.CommandReservedIdsInfo();
break;
case MAPPING_INFO:
rasctl_commands.CommandMappingInfo();
break;
default:
rasctl_commands.SendCommand();
break;
}
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }

View File

@ -0,0 +1,270 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2021 Uwe Seimet
//
//---------------------------------------------------------------------------
#include <netdb.h>
#include "os.h"
#include "exceptions.h"
#include "protobuf_util.h"
#include "rasutil.h"
#include "rasctl_commands.h"
#include "rascsi_interface.pb.h"
#include <sstream>
#include <iostream>
#include <list>
// Separator for the INQUIRY name components
#define COMPONENT_SEPARATOR ':'
using namespace std;
using namespace rascsi_interface;
RasctlCommands::RasctlCommands(PbCommand& command, const string& hostname, int port)
{
this->command = command;
this->hostname = hostname;
this->port = port;
}
void RasctlCommands::SendCommand()
{
// Send command
int fd = -1;
try {
struct hostent *host = gethostbyname(hostname.c_str());
if (!host) {
throw io_exception("Can't resolve hostname '" + hostname + "'");
}
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0) {
throw io_exception("Can't create socket");
}
struct sockaddr_in server;
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
memcpy(&server.sin_addr.s_addr, host->h_addr, host->h_length);
if (connect(fd, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0) {
ostringstream error;
error << "Can't connect to rascsi process on host '" << hostname << "', port " << port;
throw io_exception(error.str());
}
SerializeMessage(fd, command);
}
catch(const io_exception& e) {
cerr << "Error: " << e.getmsg() << endl;
if (fd >= 0) {
close(fd);
}
exit(fd < 0 ? ENOTCONN : EXIT_FAILURE);
}
// Receive result
try {
DeserializeMessage(fd, result);
if (!result.status()) {
throw io_exception(result.msg());
}
}
catch(const io_exception& e) {
close(fd);
cerr << "Error: " << e.getmsg() << endl;
exit(EXIT_FAILURE);
}
close(fd);
if (!result.msg().empty()) {
cout << result.msg() << endl;
}
}
void RasctlCommands::CommandDevicesInfo()
{
SendCommand();
rasctl_display.DisplayDevices(result.devices_info());
}
void RasctlCommands::CommandLogLevel(const string& log_level)
{
AddParam(command, "level", log_level);
SendCommand();
}
void RasctlCommands::CommandReserveIds(const string& reserved_ids)
{
AddParam(command, "ids", reserved_ids);
SendCommand();
}
void RasctlCommands::CommandCreateImage(const string& image_params)
{
size_t separatorPos = image_params.find(COMPONENT_SEPARATOR);
if (separatorPos != string::npos) {
AddParam(command, "file", image_params.substr(0, separatorPos));
AddParam(command, "size", image_params.substr(separatorPos + 1));
}
else {
cerr << "Error: Invalid file descriptor '" << image_params << "', format is NAME:SIZE" << endl;
exit(EXIT_FAILURE);
}
AddParam(command, "read_only", "false");
SendCommand();
}
void RasctlCommands::CommandDeleteImage(const string& filename)
{
AddParam(command, "file", filename);
SendCommand();
}
void RasctlCommands::CommandRenameImage(const string& image_params)
{
size_t separatorPos = image_params.find(COMPONENT_SEPARATOR);
if (separatorPos != string::npos) {
AddParam(command, "from", image_params.substr(0, separatorPos));
AddParam(command, "to", image_params.substr(separatorPos + 1));
}
else {
cerr << "Error: Invalid file descriptor '" << image_params << "', format is CURRENT_NAME:NEW_NAME" << endl;
exit(EXIT_FAILURE);
}
SendCommand();
}
void RasctlCommands::CommandCopyImage(const string& image_params)
{
size_t separatorPos = image_params.find(COMPONENT_SEPARATOR);
if (separatorPos != string::npos) {
AddParam(command, "from", image_params.substr(0, separatorPos));
AddParam(command, "to", image_params.substr(separatorPos + 1));
}
else {
cerr << "Error: Invalid file descriptor '" << image_params << "', format is CURRENT_NAME:NEW_NAME" << endl;
exit(EXIT_FAILURE);
}
SendCommand();
}
void RasctlCommands::CommandDefaultImageFolder(const string& folder)
{
AddParam(command, "folder", folder);
SendCommand();
}
void RasctlCommands::CommandDeviceInfo()
{
SendCommand();
for (const auto& device : result.devices_info().devices()) {
rasctl_display.DisplayDeviceInfo(device);
}
}
void RasctlCommands::CommandDeviceTypesInfo()
{
SendCommand();
rasctl_display.DisplayDeviceTypesInfo(result.device_types_info());
}
void RasctlCommands::CommandVersionInfo()
{
SendCommand();
rasctl_display.DisplayVersionInfo(result.version_info());
}
void RasctlCommands::CommandServerInfo()
{
SendCommand();
PbServerInfo server_info = result.server_info();
rasctl_display.DisplayVersionInfo(server_info.version_info());
rasctl_display.DisplayLogLevelInfo(server_info.log_level_info());
rasctl_display.DisplayImageFiles(server_info.image_files_info());
rasctl_display.DisplayMappingInfo(server_info.mapping_info());
rasctl_display.DisplayNetworkInterfaces(server_info.network_interfaces_info());
rasctl_display.DisplayDeviceTypesInfo(server_info.device_types_info());
rasctl_display.DisplayReservedIdsInfo(server_info.reserved_ids_info());
if (server_info.devices_info().devices_size()) {
list<PbDevice> sorted_devices = { server_info.devices_info().devices().begin(), server_info.devices_info().devices().end() };
sorted_devices.sort([](const auto& a, const auto& b) { return a.id() < b.id(); });
cout << "Attached devices:" << endl;
for (const auto& device : sorted_devices) {
rasctl_display.DisplayDeviceInfo(device);
}
}
}
void RasctlCommands::CommandDefaultImageFilesInfo()
{
SendCommand();
rasctl_display.DisplayImageFiles(result.image_files_info());
}
void RasctlCommands::CommandImageFileInfo(const string& filename)
{
AddParam(command, "file", filename);
SendCommand();
rasctl_display.DisplayImageFile(result.image_file_info());
}
void RasctlCommands::CommandNetworkInterfacesInfo()
{
SendCommand();
rasctl_display.DisplayNetworkInterfaces(result.network_interfaces_info());
}
void RasctlCommands::CommandLogLevelInfo()
{
SendCommand();
rasctl_display.DisplayLogLevelInfo(result.log_level_info());
}
void RasctlCommands::CommandReservedIdsInfo()
{
SendCommand();
rasctl_display.DisplayReservedIdsInfo(result.reserved_ids_info());
}
void RasctlCommands::CommandMappingInfo()
{
SendCommand();
rasctl_display.DisplayMappingInfo(result.mapping_info());
}

View File

@ -0,0 +1,55 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2021 Uwe Seimet
//
//---------------------------------------------------------------------------
#pragma once
#include "rascsi_interface.pb.h"
#include "rasctl_display.h"
#include <string>
using namespace std;
using namespace rascsi_interface;
class RasctlCommands
{
public:
RasctlCommands(PbCommand&, const string&, int);
~RasctlCommands() {};
void SendCommand();
void CommandDevicesInfo();
void CommandLogLevel(const string&);
void CommandReserveIds(const string&);
void CommandCreateImage(const string&);
void CommandDeleteImage(const string&);
void CommandRenameImage(const string&);
void CommandCopyImage(const string&);
void CommandDefaultImageFolder(const string&);
void CommandDeviceInfo();
void CommandDeviceTypesInfo();
void CommandVersionInfo();
void CommandServerInfo();
void CommandDefaultImageFilesInfo();
void CommandImageFileInfo(const string&);
void CommandNetworkInterfacesInfo();
void CommandLogLevelInfo();
void CommandReservedIdsInfo();
void CommandMappingInfo();
private:
PbCommand command;
string hostname;
int port;
PbResult result;
RasctlDisplay rasctl_display;
};

View File

@ -0,0 +1,268 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2021 Uwe Seimet
//
//---------------------------------------------------------------------------
#include "rascsi_interface.pb.h"
#include "rasutil.h"
#include "rasctl_display.h"
#include <iostream>
#include <list>
using namespace std;
using namespace rascsi_interface;
void RasctlDisplay::DisplayDevices(const PbDevicesInfo& devices_info)
{
const list<PbDevice>& devices = { devices_info.devices().begin(), devices_info.devices().end() };
cout << ListDevices(devices) << endl;
}
void RasctlDisplay::DisplayDeviceInfo(const PbDevice& pb_device)
{
cout << " " << pb_device.id() << ":" << pb_device.unit() << " " << PbDeviceType_Name(pb_device.type())
<< " " << pb_device.vendor() << ":" << pb_device.product() << ":" << pb_device.revision();
if (pb_device.block_size()) {
cout << " " << pb_device.block_size() << " bytes per sector";
if (pb_device.block_count()) {
cout << " " << pb_device.block_size() * pb_device.block_count() << " bytes capacity";
}
}
if (pb_device.properties().supports_file() && !pb_device.file().name().empty()) {
cout << " " << pb_device.file().name();
}
cout << " ";
bool hasProperty = false;
if (pb_device.properties().read_only()) {
cout << "read-only";
hasProperty = true;
}
if (pb_device.properties().protectable() && pb_device.status().protected_()) {
if (hasProperty) {
cout << ", ";
}
cout << "protected";
hasProperty = true;
}
if (pb_device.properties().stoppable() && pb_device.status().stopped()) {
if (hasProperty) {
cout << ", ";
}
cout << "stopped";
hasProperty = true;
}
if (pb_device.properties().removable() && pb_device.status().removed()) {
if (hasProperty) {
cout << ", ";
}
cout << "removed";
hasProperty = true;
}
if (pb_device.properties().lockable() && pb_device.status().locked()) {
if (hasProperty) {
cout << ", ";
}
cout << "locked";
}
if (hasProperty) {
cout << " ";
}
bool isFirst = true;
for (const auto& param : pb_device.params()) {
if (!isFirst) {
cout << " ";
}
isFirst = false;
cout << param.first << "=" << param.second;
}
cout << endl;
}
void RasctlDisplay::DisplayVersionInfo(const PbVersionInfo& version_info)
{
cout << "rascsi server version: " << version_info.major_version() << "." << version_info.minor_version();
if (version_info.patch_version() > 0) {
cout << "." << version_info.patch_version();
}
else if (version_info.patch_version() < 0) {
cout << " (development version)";
}
cout << endl;
}
void RasctlDisplay::DisplayLogLevelInfo(const PbLogLevelInfo& log_level_info)
{
if (!log_level_info.log_levels_size()) {
cout << " No log level settings available" << endl;
}
else {
cout << "rascsi log levels, sorted by severity:" << endl;
for (const auto& log_level : log_level_info.log_levels()) {
cout << " " << log_level << endl;
}
}
cout << "Current rascsi log level: " << log_level_info.current_log_level() << endl;
}
void RasctlDisplay::DisplayDeviceTypesInfo(const PbDeviceTypesInfo& device_types_info)
{
cout << "Supported device types and their properties:" << endl;
for (auto it = device_types_info.properties().begin(); it != device_types_info.properties().end(); ++it) {
cout << " " << PbDeviceType_Name(it->type());
const PbDeviceProperties& properties = it->properties();
cout << " Supported LUNs: " << properties.luns() << endl;
if (properties.read_only() || properties.protectable() || properties.stoppable() || properties.read_only()
|| properties.lockable()) {
cout << " Properties: ";
bool has_property = false;
if (properties.read_only()) {
cout << "read-only";
has_property = true;
}
if (properties.protectable()) {
cout << (has_property ? ", " : "") << "protectable";
has_property = true;
}
if (properties.stoppable()) {
cout << (has_property ? ", " : "") << "stoppable";
has_property = true;
}
if (properties.removable()) {
cout << (has_property ? ", " : "") << "removable";
has_property = true;
}
if (properties.lockable()) {
cout << (has_property ? ", " : "") << "lockable";
}
cout << endl;
}
if (properties.supports_file()) {
cout << " Image file support" << endl;
}
else if (properties.supports_params()) {
cout << " Parameter support" << endl;
}
if (properties.supports_params() && properties.default_params_size()) {
map<string, string> params = { properties.default_params().begin(), properties.default_params().end() };
cout << " Default parameters: ";
bool isFirst = true;
for (const auto& param : params) {
if (!isFirst) {
cout << ", ";
}
cout << param.first << "=" << param.second;
isFirst = false;
}
cout << endl;
}
if (properties.block_sizes_size()) {
set<uint32_t> block_sizes = { properties.block_sizes().begin(), properties.block_sizes().end() };
cout << " Configurable block sizes in bytes: ";
bool isFirst = true;
for (const auto& block_size : block_sizes) {
if (!isFirst) {
cout << ", ";
}
cout << block_size;
isFirst = false;
}
cout << endl;
}
}
}
void RasctlDisplay::DisplayReservedIdsInfo(const PbReservedIdsInfo& reserved_ids_info)
{
if (reserved_ids_info.ids_size()) {
cout << "Reserved device IDs: ";
for (int i = 0; i < reserved_ids_info.ids_size(); i++) {
if(i) {
cout << ", ";
}
cout << reserved_ids_info.ids(i);
}
cout <<endl;
}
}
void RasctlDisplay::DisplayImageFile(const PbImageFile& image_file_info)
{
cout << image_file_info.name() << " " << image_file_info.size() << " bytes";
if (image_file_info.read_only()) {
cout << " read-only";
}
if (image_file_info.type() != UNDEFINED) {
cout << " " << PbDeviceType_Name(image_file_info.type());
}
cout << endl;
}
void RasctlDisplay::DisplayImageFiles(const PbImageFilesInfo& image_files_info)
{
const list<PbImageFile> image_files = { image_files_info.image_files().begin(), image_files_info.image_files().end() };
cout << "Default image file folder: " << image_files_info.default_image_folder() << endl;
if (image_files.empty()) {
cout << " No image files available" << endl;
}
else {
list<PbImageFile> files = { image_files.begin(), image_files.end() };
files.sort([](const auto& a, const auto& b) { return a.name() < b.name(); });
cout << "Available image files:" << endl;
for (const auto& file : files) {
cout << " ";
DisplayImageFile(file);
}
}
}
void RasctlDisplay::DisplayNetworkInterfaces(const PbNetworkInterfacesInfo& network_interfaces_info)
{
const list<string> interfaces = { network_interfaces_info.name().begin(), network_interfaces_info.name().end() };
cout << "Available (up) network interfaces:" << endl;
bool isFirst = true;
for (const auto& interface : interfaces) {
if (!isFirst) {
cout << ", ";
}
isFirst = false;
cout << interface;
}
cout << endl;
}
void RasctlDisplay::DisplayMappingInfo(const PbMappingInfo& mapping_info)
{
const map<string, PbDeviceType> mappings = { mapping_info.mapping().begin(), mapping_info.mapping().end() };
cout << "Supported image file extension to device type mappings:" << endl;
for (const auto& mapping : mappings) {
cout << " " << mapping.first << "->" << PbDeviceType_Name(mapping.second) << endl;
}
}

View File

@ -0,0 +1,33 @@
//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2021 Uwe Seimet
//
//---------------------------------------------------------------------------
#pragma once
#include "rascsi_interface.pb.h"
using namespace rascsi_interface;
class RasctlDisplay
{
public:
RasctlDisplay() {};
~RasctlDisplay() {};
void DisplayDevices(const PbDevicesInfo&);
void DisplayDeviceInfo(const PbDevice&);
void DisplayVersionInfo(const PbVersionInfo&);
void DisplayLogLevelInfo(const PbLogLevelInfo&);
void DisplayDeviceTypesInfo(const PbDeviceTypesInfo&);
void DisplayReservedIdsInfo(const PbReservedIdsInfo&);
void DisplayImageFile(const PbImageFile&);
void DisplayImageFiles(const PbImageFilesInfo&);
void DisplayNetworkInterfaces(const PbNetworkInterfacesInfo&);
void DisplayMappingInfo(const PbMappingInfo&);
};

View File

@ -21,12 +21,12 @@ def get_server_info():
data = send_pb_command(command.SerializeToString()) data = send_pb_command(command.SerializeToString())
result = proto.PbResult() result = proto.PbResult()
result.ParseFromString(data) result.ParseFromString(data)
version = str(result.server_info.major_version) + "." +\ version = str(result.server_info.version_info.major_version) + "." +\
str(result.server_info.minor_version) + "." +\ str(result.server_info.version_info.minor_version) + "." +\
str(result.server_info.patch_version) str(result.server_info.version_info.patch_version)
log_levels = result.server_info.log_levels log_levels = result.server_info.log_level_info.log_levels
current_log_level = result.server_info.current_log_level current_log_level = result.server_info.log_level_info.current_log_level
reserved_ids = list(result.server_info.reserved_ids) reserved_ids = list(result.server_info.reserved_ids_info.ids)
# Creates lists of file endings recognized by RaSCSI # Creates lists of file endings recognized by RaSCSI
mappings = result.server_info.mapping_info.mapping mappings = result.server_info.mapping_info.mapping
@ -280,15 +280,15 @@ def list_devices(scsi_id=None):
n = 0 n = 0
# Return an empty list if no devices are attached # Return an empty list if no devices are attached
if len(result.device_info.devices) == 0: if len(result.devices_info.devices) == 0:
return {"status": False, "device_list": []} return {"status": False, "device_list": []}
while n < len(result.device_info.devices): while n < len(result.devices_info.devices):
did = result.device_info.devices[n].id did = result.devices_info.devices[n].id
dun = result.device_info.devices[n].unit dun = result.devices_info.devices[n].unit
dtype = proto.PbDeviceType.Name(result.device_info.devices[n].type) dtype = proto.PbDeviceType.Name(result.devices_info.devices[n].type)
dstat = result.device_info.devices[n].status dstat = result.devices_info.devices[n].status
dprop = result.device_info.devices[n].properties dprop = result.devices_info.devices[n].properties
# Building the status string # Building the status string
# TODO: This formatting should probably be moved elsewhere # TODO: This formatting should probably be moved elsewhere
@ -302,13 +302,13 @@ def list_devices(scsi_id=None):
if dstat.locked == True and dprop.lockable == True: if dstat.locked == True and dprop.lockable == True:
dstat_msg.append("Locked") dstat_msg.append("Locked")
dpath = result.device_info.devices[n].file.name dpath = result.devices_info.devices[n].file.name
dfile = path.basename(dpath) dfile = path.basename(dpath)
dparam = result.device_info.devices[n].params dparam = result.devices_info.devices[n].params
dven = result.device_info.devices[n].vendor dven = result.devices_info.devices[n].vendor
dprod = result.device_info.devices[n].product dprod = result.devices_info.devices[n].product
drev = result.device_info.devices[n].revision drev = result.devices_info.devices[n].revision
dblock = result.device_info.devices[n].block_size dblock = result.devices_info.devices[n].block_size
device_list.append({"id": did, "un": dun, "device_type": dtype, \ device_list.append({"id": did, "un": dun, "device_type": dtype, \
"status": ", ".join(dstat_msg), "image": dpath, "file": dfile, "params": dparam,\ "status": ", ".join(dstat_msg), "image": dpath, "file": dfile, "params": dparam,\