mirror of
https://github.com/akuker/RASCSI.git
synced 2024-09-29 13:54:48 +00:00
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:
parent
95607cd603
commit
a638fec8a8
20
doc/rasctl.1
20
doc/rasctl.1
@ -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.
|
||||||
|
@ -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/>
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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&);
|
|
||||||
};
|
};
|
||||||
|
@ -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&);
|
||||||
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
270
src/raspberrypi/rasctl_commands.cpp
Normal file
270
src/raspberrypi/rasctl_commands.cpp
Normal 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());
|
||||||
|
}
|
55
src/raspberrypi/rasctl_commands.h
Normal file
55
src/raspberrypi/rasctl_commands.h
Normal 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;
|
||||||
|
};
|
268
src/raspberrypi/rasctl_display.cpp
Normal file
268
src/raspberrypi/rasctl_display.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
33
src/raspberrypi/rasctl_display.h
Normal file
33
src/raspberrypi/rasctl_display.h
Normal 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&);
|
||||||
|
};
|
@ -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,\
|
||||||
|
Loading…
Reference in New Issue
Block a user