Fixed issue with protected devices/media, added IMAGE_FILE_INFO command (#288)

* Fixed issue with attaching protected devices

* Fixed same issue when inserting a file

* Added IMAGE_FILE_INFO command

* rasctl output update

* Added file mode and type

* Datat type update

* Reverted change

* Update web ui for protobuf changes

Co-authored-by: Daniel Markstedt <markstedt@gmail.com>
This commit is contained in:
Uwe Seimet 2021-09-30 19:22:57 +02:00 committed by GitHub
parent 998cc2d66f
commit 969220565b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 154 additions and 80 deletions

View File

@ -9,6 +9,7 @@ rasctl \- Sends management commands to the rascsi process
\fB\-m\fR |
\fB\-s\fR |
\fB\-T\fR |
[\fB\-E\fR \fIFILENAME\fR]
[\fB\-F\fR \fIIMAGE_FOLDER\fR]
[\fB\-C\fR \fIFILENAME:FILESIZE\fR]
[\fB\-x\fR \fICURRENT_NAME:NEW_NAME\fR]
@ -39,6 +40,9 @@ Note: The command and type arguments are case insensitive. Only the first letter
.BR \-C\fI " "\fIFILENAME:FILESIZE
Create an image file in the default image folder with the specified name and size in bytes.
.TP
.BR \-E\fI " " \fIFILENAME
Display information on an image file.
.TP
.BR \-F\fI " "\fIIMAGE_FOLDER
Set the default image folder.
.TP

View File

@ -6,10 +6,11 @@ NAME
rasctl - Sends management commands to the rascsi process
SYNOPSIS
rasctl -L | -e | -l | -m | -s | -T | [-F IMAGE_FOLDER] [-C FILE
NAME:FILESIZE] [-x CURRENT_NAME:NEW_NAME] [-R CURRENT_NAME:NEW_NAME]
[-g LOG_LEVEL] [-h HOST] [-p PORT] [-r RESERVED_IDS] [-v] -i ID [-c
CMD] [-f FILE|PARAM] [-n NAME] [-t TYPE] [-u UNIT]
rasctl -L | -e | -l | -m | -s | -T | [-E FILENAME] [-F IMAGE_FOLDER]
[-C FILENAME:FILESIZE] [-x CURRENT_NAME:NEW_NAME] [-R CUR
RENT_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
UNIT]
DESCRIPTION
rasctl Sends commands to the rascsi process to make configuration ad
@ -27,6 +28,9 @@ OPTIONS
Create an image file in the default image folder with the speci
fied name and size in bytes.
-E FILENAME
Display information on an image file.
-F IMAGE_FOLDER
Set the default image folder.

View File

@ -131,10 +131,10 @@ void ProtobufResponseHandler::GetDevice(const Device *device, PbDevice *pb_devic
}
}
void ProtobufResponseHandler::GetImageFile(PbImageFile *image_file, const string& filename, const string& image_folder)
bool ProtobufResponseHandler::GetImageFile(PbImageFile *image_file, const string& filename, const string& image_folder)
{
image_file->set_name(filename);
if (!filename.empty()) {
image_file->set_name(filename);
image_file->set_type(device_factory.GetTypeForFile(filename));
string f = filename[0] == '/' ? filename : image_folder + "/" + filename;
@ -144,8 +144,11 @@ void ProtobufResponseHandler::GetImageFile(PbImageFile *image_file, const string
struct stat st;
if (!stat(f.c_str(), &st)) {
image_file->set_size(st.st_size);
return true;
}
}
return false;
}
PbImageFilesInfo *ProtobufResponseHandler::GetAvailableImages(PbResult& result, const string& image_folder)

View File

@ -30,6 +30,7 @@ public:
static ProtobufResponseHandler& instance();
bool GetImageFile(PbImageFile *, const string&, const string&);
PbImageFilesInfo *GetAvailableImages(PbResult&, const string&);
void GetDevices(PbServerInfo&, const vector<Device *>&, const string&);
void GetDevicesInfo(PbResult&, const PbCommand&, const vector<Device *>&, const string&, int);
@ -49,6 +50,5 @@ private:
void GetAllDeviceTypeProperties(PbDeviceTypesInfo&);
void GetDeviceTypeProperties(PbDeviceTypesInfo&, PbDeviceType);
void GetAvailableImages(PbResult& result, PbServerInfo&, const string&);
void GetImageFile(PbImageFile *, const string&, const string&);
void GetLogLevels(PbServerInfo&);
};

View File

@ -839,11 +839,6 @@ bool Attach(int fd, const PbDeviceDefinition& pb_device, Device *map[], bool dry
device->SetId(id);
device->SetLun(unit);
// Only non read-only devices support protect/unprotect
if (!device->IsReadOnly()) {
device->SetProtected(pb_device.protected_());
}
try {
if (!pb_device.vendor().empty()) {
device->SetVendor(pb_device.vendor());
@ -859,19 +854,6 @@ bool Attach(int fd, const PbDeviceDefinition& pb_device, Device *map[], bool dry
return ReturnStatus(fd, false, e.getmsg());
}
if (pb_device.block_size()) {
Disk *disk = dynamic_cast<Disk *>(device);
if (disk && disk->IsSectorSizeConfigurable()) {
if (!disk->SetConfiguredSectorSize(pb_device.block_size())) {
error << "Invalid block size " << pb_device.block_size() << " bytes";
return ReturnStatus(fd, false, error);
}
}
else {
return ReturnStatus(fd, false, "Block size is not configurable for device type " + PbDeviceType_Name(type));
}
}
// File check (type is HD, for removable media drives, CD and MO the medium (=file) may be inserted later)
if (file_support && !device->IsRemovable() && filename.empty()) {
delete device;
@ -912,6 +894,26 @@ bool Attach(int fd, const PbDeviceDefinition& pb_device, Device *map[], bool dry
file_support->ReserveFile(filepath, device->GetId(), device->GetLun());
}
// The operations below must not be executed before Open() because Open() overrides some settings
if (pb_device.block_size()) {
Disk *disk = dynamic_cast<Disk *>(device);
if (disk && disk->IsSectorSizeConfigurable()) {
if (!disk->SetConfiguredSectorSize(pb_device.block_size())) {
error << "Invalid block size " << pb_device.block_size() << " bytes";
return ReturnStatus(fd, false, error);
}
}
else {
return ReturnStatus(fd, false, "Block size is not configurable for device type " + PbDeviceType_Name(type));
}
}
// Only non read-only devices support protect/unprotect
if (device->IsProtectable() && !device->IsReadOnly()) {
device->SetProtected(pb_device.protected_());
}
// Stop the dry run here, before permanently modifying something
if (dryRun) {
delete device;
@ -1027,7 +1029,6 @@ bool Insert(int fd, const PbDeviceDefinition& pb_device, Device *device, bool dr
}
FileSupport *file_support = dynamic_cast<FileSupport *>(device);
try {
try {
file_support->Open(filepath);
@ -1041,9 +1042,14 @@ bool Insert(int fd, const PbDeviceDefinition& pb_device, Device *device, bool dr
catch(const io_exception& e) {
return ReturnStatus(fd, false, "Tried to open an invalid file '" + initial_filename + "': " + e.getmsg());
}
file_support->ReserveFile(filepath, device->GetId(), device->GetLun());
// Only non read-only devices support protect/unprotect.
// This operation must not be executed before Open() because Open() overrides some settings.
if (device->IsProtectable() && !device->IsReadOnly()) {
device->SetProtected(pb_device.protected_());
}
return true;
}
@ -1574,7 +1580,7 @@ static void *MonThread(void *param)
break;
}
case IMAGE_FILES_INFO: {
case DEFAULT_IMAGE_FILES_INFO: {
LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str());
PbResult result;
@ -1583,6 +1589,29 @@ static void *MonThread(void *param)
break;
}
case IMAGE_FILE_INFO: {
LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str());
string filename = GetParam(command, "file");
if (filename.empty()) {
ReturnStatus(fd, false, "Can't get image file info: Missing filename");
}
else {
PbResult result;
PbImageFile* image_file = new PbImageFile();
bool status = response_helper.GetImageFile(image_file, filename, default_image_folder);
if (status) {
result.set_status(true);
result.set_allocated_image_file_info(image_file);
SerializeMessage(fd, result);
}
else {
ReturnStatus(fd, false, "Can't get image file info for '" + filename + "'");
}
}
break;
}
case NETWORK_INTERFACES_INFO: {
LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str());

View File

@ -72,65 +72,70 @@ enum PbOperation {
// Device properties by device type
DEVICE_TYPES_INFO = 12;
// Gets information on available image files. A lightweight alternative to getting the complete server info.
IMAGE_FILES_INFO = 13;
// Gets information on available image files in the default image folder.
DEFAULT_IMAGE_FILES_INFO = 13;
// Gets information on an image file (not necessarily in the default image folder) based on an absolute path.
// Parameters:
// "file": The filename. Either an absolute path or a path relative to the default image folder.
IMAGE_FILE_INFO = 14;
// Gets the names of the available network interfaces. Only lists interfaces that are up.
NETWORK_INTERFACES_INFO = 14;
NETWORK_INTERFACES_INFO = 15;
// Gets the mapping of extensions to device types
MAPPING_INFO = 15;
MAPPING_INFO = 16;
// Set the default folder for image files.
// Parameters:
// "folder": The default folder name.
DEFAULT_FOLDER = 16;
DEFAULT_FOLDER = 17;
// Set server log level.
// Parameters:
// "level": The new log level
LOG_LEVEL = 17;
LOG_LEVEL = 18;
// Block IDs from being used, usually the IDs of the initiators (computers) in the SCSI chain.
// Parameters:
// "ids": A comma-separated list of IDs to reserve, or an empty string in order not to reserve any ID.
RESERVE = 18;
RESERVE = 19;
// Create an image file. The image file must not yet exist.
// Parameters:
// "file": The filename, relative to the default image folder. It must not contain a slash.
// "size": The file size in bytes, must be a multiple of 512
// "read_only": "true" (case-insensitive) in order to create a read-only file, otherwise "false"
CREATE_IMAGE = 19;
CREATE_IMAGE = 20;
// Delete an image file.
// Parameters:
// "file": The filename, relative to the default image folder. It must not contain a slash.
DELETE_IMAGE = 20;
DELETE_IMAGE = 21;
// Rename an image file.
// Parameters:
// "from": The old filename, relative to the default image folder. It must not contain a slash.
// "to": The new filename, relative to the default image folder. It must not contain a slash.
// The new filename must not yet exist.
RENAME_IMAGE = 21;
RENAME_IMAGE = 22;
// Copy an image file.
// Parameters:
// "from": The source filename, relative to the default image folder. It must not contain a slash.
// "to": The destination filename, relative to the default image folder. It must not contain a slash.
// The destination filename must not yet exist.
COPY_IMAGE = 22;
COPY_IMAGE = 23;
// Write-protect an image file.
// Parameters:
// "file": The filename, relative to the default image folder. It must not contain a slash.
PROTECT_IMAGE = 23;
PROTECT_IMAGE = 24;
// Make an image file writable.
// Parameters:
// "file": The filename, relative to the default image folder. It must not contain a slash.
UNPROTECT_IMAGE = 24;
UNPROTECT_IMAGE = 25;
}
// The supported file extensions mapped to their respective device types
@ -189,9 +194,9 @@ message PbImageFile {
string name = 1;
// The assumed device type, based on the filename extension
PbDeviceType type = 2;
bool read_only = 3;
// The file size in bytes, 0 for block devices
int64 size = 4;
uint64 size = 3;
bool read_only = 4;
}
// The default image folder and the image files it contains
@ -269,12 +274,14 @@ message PbResult {
PbDevices device_info = 4;
// The result of a DEVICE_TYPES_INFO command
PbDeviceTypesInfo device_types_info = 5;
// The result of an IMAGE_FILES_INFO command
// The result of a DEFAULT_IMAGE_FILES_INFO command
PbImageFilesInfo image_files_info = 6;
// The result of an IMAGE_FILE_INFO command
PbImageFile image_file_info = 7;
// The result of a NETWORK_INTERFACES_INFO command
PbNetworkInterfacesInfo network_interfaces_info = 7;
PbNetworkInterfacesInfo network_interfaces_info = 8;
// The result of an MAPPING_INFO command
PbMappingInfo mapping_info = 8;
PbMappingInfo mapping_info = 9;
}
}

View File

@ -234,6 +234,19 @@ void DisplayDeviceTypesInfo(const PbDeviceTypesInfo& device_types_info)
}
}
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() };
@ -249,14 +262,8 @@ void DisplayImageFiles(const PbImageFilesInfo& image_files_info)
cout << "Available image files:" << endl;
for (const auto& file : files) {
cout << " " << file.name() << " " << file.size() << " bytes";
if (file.read_only()) {
cout << " read-only";
}
if (file.type() != UNDEFINED) {
cout << " " << PbDeviceType_Name(file.type());
}
cout << endl;
cout << " ";
DisplayImageFile(file);
}
}
}
@ -469,7 +476,7 @@ void CommandServerInfo(PbCommand& command, const string& hostname, int port)
}
}
void CommandImageFilesInfo(const PbCommand& command, const string& hostname, int port)
void CommandDefaultImageFilesInfo(const PbCommand& command, const string& hostname, int port)
{
PbResult result;
SendCommand(hostname.c_str(), port, command, result);
@ -477,6 +484,16 @@ void CommandImageFilesInfo(const PbCommand& command, const string& hostname, int
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;
@ -573,7 +590,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 << "[-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 << "[-L] [-l] [-m] [-s] [-v] [-y]" << endl;
cerr << "[-e] [-E FILENAME] [-l] [-L] [-m] [-s] [-v] [-y]" << endl;
cerr << " where ID := {0-7}" << endl;
cerr << " UNIT := {0|1}, default is 0" << endl;
cerr << " CMD := {attach|detach|insert|eject|protect|unprotect|show}" << endl;
@ -605,11 +622,12 @@ int main(int argc, char* argv[])
string default_folder;
string reserved_ids;
string image_params;
string filename;
bool list = false;
opterr = 1;
int opt;
while ((opt = getopt(argc, argv, "elmsvNTD:L:R:a:b:c:f:h:i:n:p:r:t:u:x:C:F:L:")) != -1) {
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) {
switch (opt) {
case 'i':
device->set_id(optarg[0] - '0');
@ -641,13 +659,18 @@ int main(int argc, char* argv[])
}
break;
case 'F':
command.set_operation(DEFAULT_FOLDER);
default_folder = optarg;
case 'E':
command.set_operation(IMAGE_FILE_INFO);
filename = optarg;
break;
case 'e':
command.set_operation(IMAGE_FILES_INFO);
command.set_operation(DEFAULT_IMAGE_FILES_INFO);
break;
case 'F':
command.set_operation(DEFAULT_FOLDER);
default_folder = optarg;
break;
case 'f':
@ -799,8 +822,12 @@ int main(int argc, char* argv[])
CommandServerInfo(command, hostname, port);
exit(EXIT_SUCCESS);
case IMAGE_FILES_INFO:
CommandImageFilesInfo(command, hostname, port);
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:

View File

@ -13,7 +13,7 @@ import rascsi_interface_pb2 as proto
def list_files():
command = proto.PbCommand()
command.operation = proto.PbOperation.IMAGE_FILES_INFO
command.operation = proto.PbOperation.DEFAULT_IMAGE_FILES_INFO
data = send_pb_command(command.SerializeToString())
result = proto.PbResult()