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\-m\fR |
\fB\-s\fR | \fB\-s\fR |
\fB\-T\fR | \fB\-T\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]
[\fB\-x\fR \fICURRENT_NAME:NEW_NAME\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 .BR \-C\fI " "\fIFILENAME:FILESIZE
Create an image file in the default image folder with the specified name and size in bytes. Create an image file in the default image folder with the specified name and size in bytes.
.TP .TP
.BR \-E\fI " " \fIFILENAME
Display information on an image file.
.TP
.BR \-F\fI " "\fIIMAGE_FOLDER .BR \-F\fI " "\fIIMAGE_FOLDER
Set the default image folder. Set the default image folder.
.TP .TP

View File

@ -6,10 +6,11 @@ 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 | [-F IMAGE_FOLDER] [-C FILE rasctl -L | -e | -l | -m | -s | -T | [-E FILENAME] [-F IMAGE_FOLDER]
NAME:FILESIZE] [-x CURRENT_NAME:NEW_NAME] [-R CURRENT_NAME:NEW_NAME] [-C FILENAME:FILESIZE] [-x CURRENT_NAME:NEW_NAME] [-R CUR
[-g LOG_LEVEL] [-h HOST] [-p PORT] [-r RESERVED_IDS] [-v] -i ID [-c RENT_NAME:NEW_NAME] [-g LOG_LEVEL] [-h HOST] [-p PORT] [-r RE
CMD] [-f FILE|PARAM] [-n NAME] [-t TYPE] [-u UNIT] SERVED_IDS] [-v] -i ID [-c CMD] [-f FILE|PARAM] [-n NAME] [-t TYPE] [-u
UNIT]
DESCRIPTION DESCRIPTION
rasctl Sends commands to the rascsi process to make configuration ad 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 Create an image file in the default image folder with the speci
fied name and size in bytes. fied name and size in bytes.
-E FILENAME
Display information on an image file.
-F IMAGE_FOLDER -F IMAGE_FOLDER
Set the default 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()) { if (!filename.empty()) {
image_file->set_name(filename);
image_file->set_type(device_factory.GetTypeForFile(filename)); image_file->set_type(device_factory.GetTypeForFile(filename));
string f = filename[0] == '/' ? filename : image_folder + "/" + filename; string f = filename[0] == '/' ? filename : image_folder + "/" + filename;
@ -144,8 +144,11 @@ void ProtobufResponseHandler::GetImageFile(PbImageFile *image_file, const string
struct stat st; struct stat st;
if (!stat(f.c_str(), &st)) { if (!stat(f.c_str(), &st)) {
image_file->set_size(st.st_size); image_file->set_size(st.st_size);
return true;
} }
} }
return false;
} }
PbImageFilesInfo *ProtobufResponseHandler::GetAvailableImages(PbResult& result, const string& image_folder) PbImageFilesInfo *ProtobufResponseHandler::GetAvailableImages(PbResult& result, const string& image_folder)

View File

@ -30,6 +30,7 @@ public:
static ProtobufResponseHandler& instance(); static ProtobufResponseHandler& instance();
bool GetImageFile(PbImageFile *, const string&, const string&);
PbImageFilesInfo *GetAvailableImages(PbResult&, const string&); PbImageFilesInfo *GetAvailableImages(PbResult&, const string&);
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);
@ -49,6 +50,5 @@ 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 GetImageFile(PbImageFile *, const string&, const string&);
void GetLogLevels(PbServerInfo&); 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->SetId(id);
device->SetLun(unit); device->SetLun(unit);
// Only non read-only devices support protect/unprotect
if (!device->IsReadOnly()) {
device->SetProtected(pb_device.protected_());
}
try { try {
if (!pb_device.vendor().empty()) { if (!pb_device.vendor().empty()) {
device->SetVendor(pb_device.vendor()); 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()); 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) // 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()) { if (file_support && !device->IsRemovable() && filename.empty()) {
delete device; 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()); 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 // Stop the dry run here, before permanently modifying something
if (dryRun) { if (dryRun) {
delete device; 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); FileSupport *file_support = dynamic_cast<FileSupport *>(device);
try { try {
try { try {
file_support->Open(filepath); 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) { catch(const io_exception& e) {
return ReturnStatus(fd, false, "Tried to open an invalid file '" + initial_filename + "': " + e.getmsg()); return ReturnStatus(fd, false, "Tried to open an invalid file '" + initial_filename + "': " + e.getmsg());
} }
file_support->ReserveFile(filepath, device->GetId(), device->GetLun()); 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; return true;
} }
@ -1574,7 +1580,7 @@ static void *MonThread(void *param)
break; break;
} }
case 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());
PbResult result; PbResult result;
@ -1583,6 +1589,29 @@ static void *MonThread(void *param)
break; 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: { case NETWORK_INTERFACES_INFO: {
LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str()); LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str());

View File

@ -72,65 +72,70 @@ enum PbOperation {
// Device properties by device type // Device properties by device type
DEVICE_TYPES_INFO = 12; DEVICE_TYPES_INFO = 12;
// Gets information on available image files. A lightweight alternative to getting the complete server info. // Gets information on available image files in the default image folder.
IMAGE_FILES_INFO = 13; 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. // 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 // Gets the mapping of extensions to device types
MAPPING_INFO = 15; MAPPING_INFO = 16;
// 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 = 16; DEFAULT_FOLDER = 17;
// Set server log level. // Set server log level.
// Parameters: // Parameters:
// "level": The new log level // "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. // 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 = 18; RESERVE = 19;
// 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 = 19; CREATE_IMAGE = 20;
// 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 = 20; DELETE_IMAGE = 21;
// 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 = 21; RENAME_IMAGE = 22;
// 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 = 22; COPY_IMAGE = 23;
// 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 = 23; PROTECT_IMAGE = 24;
// 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 = 24; UNPROTECT_IMAGE = 25;
} }
// The supported file extensions mapped to their respective device types // The supported file extensions mapped to their respective device types
@ -189,9 +194,9 @@ message PbImageFile {
string name = 1; string name = 1;
// The assumed device type, based on the filename extension // The assumed device type, based on the filename extension
PbDeviceType type = 2; PbDeviceType type = 2;
bool read_only = 3;
// The file size in bytes, 0 for block devices // 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 // The default image folder and the image files it contains
@ -269,12 +274,14 @@ message PbResult {
PbDevices device_info = 4; PbDevices device_info = 4;
// 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 = 5;
// The result of an IMAGE_FILES_INFO command // The result of a DEFAULT_IMAGE_FILES_INFO command
PbImageFilesInfo image_files_info = 6; 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 // 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 // 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) void DisplayImageFiles(const PbImageFilesInfo& image_files_info)
{ {
const list<PbImageFile> image_files = { image_files_info.image_files().begin(), image_files_info.image_files().end() }; 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; cout << "Available image files:" << endl;
for (const auto& file : files) { for (const auto& file : files) {
cout << " " << file.name() << " " << file.size() << " bytes"; cout << " ";
if (file.read_only()) { DisplayImageFile(file);
cout << " read-only";
}
if (file.type() != UNDEFINED) {
cout << " " << PbDeviceType_Name(file.type());
}
cout << endl;
} }
} }
} }
@ -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; PbResult result;
SendCommand(hostname.c_str(), port, command, 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()); 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) void CommandNetworkInterfacesInfo(const PbCommand& command, const string&hostname, int port)
{ {
PbResult result; 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 << "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 << "[-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 << " 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;
@ -605,11 +622,12 @@ int main(int argc, char* argv[])
string default_folder; string default_folder;
string reserved_ids; string reserved_ids;
string image_params; string image_params;
string filename;
bool list = false; bool list = false;
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: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) { switch (opt) {
case 'i': case 'i':
device->set_id(optarg[0] - '0'); device->set_id(optarg[0] - '0');
@ -641,13 +659,18 @@ int main(int argc, char* argv[])
} }
break; break;
case 'F': case 'E':
command.set_operation(DEFAULT_FOLDER); command.set_operation(IMAGE_FILE_INFO);
default_folder = optarg; filename = optarg;
break; break;
case 'e': 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; break;
case 'f': case 'f':
@ -799,8 +822,12 @@ int main(int argc, char* argv[])
CommandServerInfo(command, hostname, port); CommandServerInfo(command, hostname, port);
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
case IMAGE_FILES_INFO: case DEFAULT_IMAGE_FILES_INFO:
CommandImageFilesInfo(command, hostname, port); CommandDefaultImageFilesInfo(command, hostname, port);
exit(EXIT_SUCCESS);
case IMAGE_FILE_INFO:
CommandImageFileInfo(command, hostname, port, filename);
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
case NETWORK_INTERFACES_INFO: case NETWORK_INTERFACES_INFO:

View File

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