mirror of
https://github.com/akuker/RASCSI.git
synced 2024-11-18 21:07:52 +00:00
MAPPING_INFO command, returning the mapping of extensions to types (#275)
* Added MAPPING_INFO command, returning the mapping of extensions to types * Updated help message * Set explicit vendor/product/revision for .hda extension * Added leading blanks to vendor and product for .hda * Product string update * Fixed typo in help string * Manpage update * Spoof hda as a Quantum Fireball Co-authored-by: Daniel Markstedt <markstedt@gmail.com>
This commit is contained in:
parent
c98dec8f44
commit
97c2a11329
@ -5,8 +5,8 @@ rasctl \- Sends management commands to the rascsi process
|
||||
.B rasctl
|
||||
\fB\-L\fR |
|
||||
\fB\-e\fR |
|
||||
\fB\-k\fR |
|
||||
\fB\-l\fR |
|
||||
\fB\-m\fR |
|
||||
\fB\-s\fR |
|
||||
\fB\-T\fR |
|
||||
[\fB\-F\fR \fIIMAGE_FOLDER\fR]
|
||||
@ -57,6 +57,9 @@ Lists all available network interfaces provided that they are up.
|
||||
.BR \-l\fI
|
||||
List all of the devices that are currently being emulated by RaSCSI, as well as their current status.
|
||||
.TP
|
||||
.BR \-m\fI
|
||||
List all file extensions recognized by RaSCSI and the device types they map to.
|
||||
.TP
|
||||
.BR \-R\fI " "\fICURRENT_NAME:NEW_NAME
|
||||
Rename an image file in the default image folder.
|
||||
.TP
|
||||
|
@ -6,7 +6,7 @@ NAME
|
||||
rasctl - Sends management commands to the rascsi process
|
||||
|
||||
SYNOPSIS
|
||||
rasctl -L | -e | -k | -l | -s | -T | [-F IMAGE_FOLDER] [-C FILE‐
|
||||
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]
|
||||
@ -45,6 +45,9 @@ OPTIONS
|
||||
-l List all of the devices that are currently being emulated by
|
||||
RaSCSI, as well as their current status.
|
||||
|
||||
-m List all file extensions recognized by RaSCSI and the device
|
||||
types they map to.
|
||||
|
||||
-R CURRENT_NAME:NEW_NAME
|
||||
Rename an image file in the default image folder.
|
||||
|
||||
@ -54,7 +57,7 @@ OPTIONS
|
||||
-r RESERVED_IDS
|
||||
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.
|
||||
|
||||
-T Display all device types and their properties.
|
||||
@ -74,7 +77,7 @@ OPTIONS
|
||||
d(etach): Detach disk
|
||||
i(nsert): Insert 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)
|
||||
u(nprotect): Remove write protection from the medium (not for
|
||||
CD-ROMs, which are always read-only)
|
||||
@ -84,18 +87,18 @@ OPTIONS
|
||||
|
||||
-b BLOCK_SIZE
|
||||
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.
|
||||
|
||||
-f FILE|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.
|
||||
|
||||
-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
|
||||
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):
|
||||
hd: SCSI hard disk drive
|
||||
rm: SCSI removable media drive
|
||||
@ -105,16 +108,16 @@ OPTIONS
|
||||
daynaport: DaynaPORT network adapter
|
||||
|
||||
-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
|
||||
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‐
|
||||
tomatically applied. Once set the name of a device cannot be
|
||||
tomatically applied. Once set the name of a device cannot be
|
||||
changed.
|
||||
|
||||
-u UNIT
|
||||
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
|
||||
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
|
||||
controller. (This is not common)
|
||||
|
||||
EXAMPLES
|
||||
|
@ -64,6 +64,16 @@ DeviceFactory::DeviceFactory()
|
||||
default_params[SCCD] = {};
|
||||
default_params[SCBR]["interfaces"] = network_interfaces;
|
||||
default_params[SCDP]["interfaces"] = network_interfaces;
|
||||
|
||||
extension_mapping["hdf"] = SAHD;
|
||||
extension_mapping["hds"] = SCHD;
|
||||
extension_mapping["hda"] = SCHD;
|
||||
extension_mapping["hdn"] = SCHD;
|
||||
extension_mapping["hdi"] = SCHD;
|
||||
extension_mapping["nhd"] = SCHD;
|
||||
extension_mapping["hdr"] = SCRM;
|
||||
extension_mapping["mos"] = SCMO;
|
||||
extension_mapping["iso"] = SCCD;
|
||||
}
|
||||
|
||||
DeviceFactory& DeviceFactory::instance()
|
||||
@ -72,7 +82,7 @@ DeviceFactory& DeviceFactory::instance()
|
||||
return instance;
|
||||
}
|
||||
|
||||
string DeviceFactory::GetExtension(const string& filename)
|
||||
string DeviceFactory::GetExtension(const string& filename) const
|
||||
{
|
||||
string ext;
|
||||
size_t separator = filename.rfind('.');
|
||||
@ -87,18 +97,9 @@ string DeviceFactory::GetExtension(const string& filename)
|
||||
PbDeviceType DeviceFactory::GetTypeForFile(const string& filename)
|
||||
{
|
||||
string ext = GetExtension(filename);
|
||||
if (ext == "hdf") {
|
||||
return SAHD;
|
||||
}
|
||||
else if (ext == "hds" || ext == "hdn" || ext == "hdi" || ext == "nhd" || ext == "hda") {
|
||||
return SCHD;
|
||||
}
|
||||
else if (ext == "hdr") {
|
||||
return SCRM;
|
||||
} else if (ext == "mos") {
|
||||
return SCMO;
|
||||
} else if (ext == "iso") {
|
||||
return SCCD;
|
||||
|
||||
if (extension_mapping.find(ext) != extension_mapping.end()) {
|
||||
return extension_mapping[ext];
|
||||
}
|
||||
else if (filename == "bridge") {
|
||||
return SCBR;
|
||||
@ -137,6 +138,12 @@ Device *DeviceFactory::CreateDevice(PbDeviceType type, const string& filename)
|
||||
} else {
|
||||
device = new SCSIHD(false);
|
||||
((Disk *)device)->SetSectorSizes(sector_sizes[SCHD]);
|
||||
|
||||
// Some Apple tools require a particular drive identification
|
||||
if (ext == "hda") {
|
||||
device->SetVendor("QUANTUM");
|
||||
device->SetProduct("FIREBALL");
|
||||
}
|
||||
}
|
||||
device->SetSupportedLuns(1);
|
||||
device->SetProtectable(true);
|
||||
|
@ -33,15 +33,14 @@ public:
|
||||
|
||||
static DeviceFactory& instance();
|
||||
|
||||
static PbDeviceType GetTypeForFile(const string&);
|
||||
|
||||
Device *CreateDevice(PbDeviceType, const string&);
|
||||
|
||||
PbDeviceType GetTypeForFile(const string&);
|
||||
const set<uint32_t>& GetSectorSizes(PbDeviceType type) { return sector_sizes[type]; }
|
||||
const set<uint32_t>& GetSectorSizes(const string&);
|
||||
const set<uint64_t> GetCapacities(PbDeviceType);
|
||||
const map<string, string>& GetDefaultParams(PbDeviceType type) { return default_params[type]; }
|
||||
const list<string> GetNetworkInterfaces() const;
|
||||
const map<string, PbDeviceType> GetExtensionMapping() const { return extension_mapping; }
|
||||
|
||||
private:
|
||||
|
||||
@ -51,5 +50,7 @@ private:
|
||||
|
||||
map<PbDeviceType, map<string, string>> default_params;
|
||||
|
||||
static string GetExtension(const string&);
|
||||
map<string, PbDeviceType> extension_mapping;
|
||||
|
||||
string GetExtension(const string&) const;
|
||||
};
|
||||
|
@ -139,7 +139,7 @@ void ProtobufResponseHandler::GetImageFile(PbImageFile *image_file, const string
|
||||
{
|
||||
image_file->set_name(filename);
|
||||
if (!filename.empty()) {
|
||||
image_file->set_type(DeviceFactory::GetTypeForFile(filename));
|
||||
image_file->set_type(device_factory.GetTypeForFile(filename));
|
||||
|
||||
string f = filename[0] == '/' ? filename : image_folder + "/" + filename;
|
||||
|
||||
@ -275,6 +275,7 @@ PbServerInfo *ProtobufResponseHandler::GetServerInfo(PbResult& result, const vec
|
||||
GetAllDeviceTypeProperties(*server_info->mutable_device_types_info());
|
||||
GetAvailableImages(result, *server_info, image_folder);
|
||||
server_info->set_allocated_network_interfaces_info(GetNetworkInterfacesInfo(result));
|
||||
server_info->set_allocated_mapping_info(GetMappingInfo(result));
|
||||
GetDevices(*server_info, devices, image_folder);
|
||||
for (int id : reserved_ids) {
|
||||
server_info->add_reserved_ids(id);
|
||||
@ -304,3 +305,16 @@ PbNetworkInterfacesInfo *ProtobufResponseHandler::GetNetworkInterfacesInfo(PbRes
|
||||
|
||||
return network_interfaces_info;
|
||||
}
|
||||
|
||||
PbMappingInfo *ProtobufResponseHandler::GetMappingInfo(PbResult& result)
|
||||
{
|
||||
PbMappingInfo *mapping_info = new PbMappingInfo();
|
||||
|
||||
for (const auto& mapping : device_factory.GetExtensionMapping()) {
|
||||
(*mapping_info->mutable_mapping())[mapping.first] = mapping.second;
|
||||
}
|
||||
|
||||
result.set_status(true);
|
||||
|
||||
return mapping_info;
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ public:
|
||||
PbDeviceTypesInfo *GetDeviceTypesInfo(PbResult&, const PbCommand&);
|
||||
PbServerInfo *GetServerInfo(PbResult&, const vector<Device *>&, const set<int>&, const string&, const string&);
|
||||
PbNetworkInterfacesInfo *GetNetworkInterfacesInfo(PbResult&);
|
||||
PbMappingInfo *GetMappingInfo(PbResult&);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -1592,6 +1592,15 @@ static void *MonThread(void *param)
|
||||
break;
|
||||
}
|
||||
|
||||
case MAPPING_INFO: {
|
||||
LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str());
|
||||
|
||||
PbResult result;
|
||||
result.set_allocated_mapping_info(response_helper.GetMappingInfo(result));
|
||||
SerializeMessage(fd, result);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
// Wait until we become idle
|
||||
while (active) {
|
||||
|
@ -78,56 +78,64 @@ enum PbOperation {
|
||||
// Gets the names of the available network interfaces. Only lists interfaces that are up.
|
||||
NETWORK_INTERFACES_INFO = 14;
|
||||
|
||||
// Gets the mapping of extensions to device types
|
||||
MAPPING_INFO = 15;
|
||||
|
||||
// Set the default folder for image files.
|
||||
// Parameters:
|
||||
// "folder": The default folder name.
|
||||
DEFAULT_FOLDER = 15;
|
||||
DEFAULT_FOLDER = 16;
|
||||
|
||||
// Set server log level.
|
||||
// Parameters:
|
||||
// "level": The new log level
|
||||
LOG_LEVEL = 16;
|
||||
LOG_LEVEL = 17;
|
||||
|
||||
// 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 = 17;
|
||||
RESERVE = 18;
|
||||
|
||||
// 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 = 18;
|
||||
CREATE_IMAGE = 19;
|
||||
|
||||
// Delete an image file.
|
||||
// Parameters:
|
||||
// "file": The filename, relative to the default image folder. It must not contain a slash.
|
||||
DELETE_IMAGE = 19;
|
||||
DELETE_IMAGE = 20;
|
||||
|
||||
// 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 = 20;
|
||||
RENAME_IMAGE = 21;
|
||||
|
||||
// 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 = 21;
|
||||
COPY_IMAGE = 22;
|
||||
|
||||
// Write-protect an image file.
|
||||
// Parameters:
|
||||
// "file": The filename, relative to the default image folder. It must not contain a slash.
|
||||
PROTECT_IMAGE = 22;
|
||||
PROTECT_IMAGE = 23;
|
||||
|
||||
// Make an image file writable.
|
||||
// Parameters:
|
||||
// "file": The filename, relative to the default image folder. It must not contain a slash.
|
||||
UNPROTECT_IMAGE = 23;
|
||||
UNPROTECT_IMAGE = 24;
|
||||
}
|
||||
|
||||
// The supported file extensions mapped to their respective device types
|
||||
message PbMappingInfo {
|
||||
map<string, PbDeviceType> mapping = 1;
|
||||
}
|
||||
|
||||
// The properties supported by a device
|
||||
@ -267,6 +275,8 @@ message PbResult {
|
||||
PbImageFilesInfo image_files_info = 6;
|
||||
// The result of a NETWORK_INTERFACES_INFO command
|
||||
PbNetworkInterfacesInfo network_interfaces_info = 7;
|
||||
// The result of an MAPPING_INFO command
|
||||
PbMappingInfo mapping_info = 8;
|
||||
}
|
||||
}
|
||||
|
||||
@ -286,8 +296,10 @@ message PbServerInfo {
|
||||
PbImageFilesInfo image_files_info = 7;
|
||||
// The available (up) network interfaces, also available separately
|
||||
PbNetworkInterfacesInfo network_interfaces_info = 8;
|
||||
// The extensions to device types mapping
|
||||
PbMappingInfo mapping_info = 9;
|
||||
// The attached devices, also available separately
|
||||
PbDevices devices = 9;
|
||||
PbDevices devices = 10;
|
||||
// The unsorted list of reserved IDs
|
||||
repeated uint32 reserved_ids = 10;
|
||||
repeated uint32 reserved_ids = 11;
|
||||
}
|
||||
|
@ -252,9 +252,11 @@ void DisplayDeviceTypesInfo(const PbDeviceTypesInfo& device_types_info)
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayImageFiles(const list<PbImageFile> image_files, const string& default_image_folder)
|
||||
void DisplayImageFiles(const PbImageFilesInfo& image_files_info)
|
||||
{
|
||||
cout << "Default image file folder: " << default_image_folder << endl;
|
||||
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;
|
||||
@ -277,9 +279,9 @@ void DisplayImageFiles(const list<PbImageFile> image_files, const string& defaul
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayNetworkInterfaces(list<string> interfaces)
|
||||
void DisplayNetworkInterfaces(const PbNetworkInterfacesInfo& network_interfaces_info)
|
||||
{
|
||||
interfaces.sort([](const auto& a, const auto& b) { return a < b; });
|
||||
const list<string> interfaces = { network_interfaces_info.name().begin(), network_interfaces_info.name().end() };
|
||||
|
||||
cout << "Available (up) network interfaces:" << endl;
|
||||
bool isFirst = true;
|
||||
@ -293,6 +295,16 @@ void DisplayNetworkInterfaces(list<string> interfaces)
|
||||
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
|
||||
@ -447,14 +459,9 @@ void CommandServerInfo(PbCommand& command, const string& hostname, int port)
|
||||
cout << "Current rascsi log level: " << server_info.current_log_level() << endl;
|
||||
}
|
||||
|
||||
const list<PbImageFile> image_files =
|
||||
{ server_info.image_files_info().image_files().begin(), server_info.image_files_info().image_files().end() };
|
||||
DisplayImageFiles(image_files, server_info.image_files_info().default_image_folder());
|
||||
|
||||
const list<string> network_interfaces =
|
||||
{ server_info.network_interfaces_info().name().begin(), server_info.network_interfaces_info().name().end() };
|
||||
DisplayNetworkInterfaces(network_interfaces);
|
||||
|
||||
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()) {
|
||||
@ -485,9 +492,7 @@ void CommandImageFilesInfo(const PbCommand& command, const string& hostname, int
|
||||
PbResult result;
|
||||
SendCommand(hostname.c_str(), port, command, result);
|
||||
|
||||
const list<PbImageFile> image_files =
|
||||
{ result.image_files_info().image_files().begin(),result.image_files_info().image_files().end() };
|
||||
DisplayImageFiles(image_files, result.image_files_info().default_image_folder());
|
||||
DisplayImageFiles(result.image_files_info());
|
||||
}
|
||||
|
||||
void CommandNetworkInterfacesInfo(const PbCommand& command, const string&hostname, int port)
|
||||
@ -495,9 +500,15 @@ void CommandNetworkInterfacesInfo(const PbCommand& command, const string&hostnam
|
||||
PbResult result;
|
||||
SendCommand(hostname.c_str(), port, command, result);
|
||||
|
||||
list<string> network_interfaces =
|
||||
{ result.network_interfaces_info().name().begin(), result.network_interfaces_info().name().end() };
|
||||
DisplayNetworkInterfaces(network_interfaces);
|
||||
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)
|
||||
@ -580,7 +591,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] [-k] [-l] [-v] [-y]" << endl;
|
||||
cerr << "[-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;
|
||||
@ -616,7 +627,7 @@ int main(int argc, char* argv[])
|
||||
|
||||
opterr = 1;
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "elsvNTD: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:F:L:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'i':
|
||||
device->set_id(optarg[0] - '0');
|
||||
@ -661,6 +672,10 @@ int main(int argc, char* argv[])
|
||||
param = optarg;
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
command.set_operation(MAPPING_INFO);
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
command.set_operation(NETWORK_INTERFACES_INFO);
|
||||
break;
|
||||
@ -810,6 +825,10 @@ int main(int argc, char* argv[])
|
||||
CommandNetworkInterfacesInfo(command, hostname, port);
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
case MAPPING_INFO:
|
||||
CommandMappingInfo(command, hostname, port);
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user