Added support for operation meta data, code cleanup (#534)

* Added messages

* Comment update

* Interface update

* Support for localized descriptions

* Sort operations

* Completed meta data

* rasctl -s returns operation meta data

* Manpage update

* Type update

* Comment update

* Description updates

* Comment update

* Added convenience method

* Added convenience method

* Code cleanup

* Comment update

* Display permitted values

* For completeness sake added permitted boolean values

* Added support for default value

* Removed redundant message field

* Description update

* Description upddate

* Squashed commit of the following:

commit 8171c6ea27982c736c30c0db69a7fdde07ee10ce
Author: Uwe Seimet <Uwe.Seimet@seimet.de>
Date:   Sat Dec 18 12:43:14 2021 +0100

    The data type is implicit

commit fb01dc9d82e8ff7456b05a0cb9d08069adacc64c
Author: Uwe Seimet <Uwe.Seimet@seimet.de>
Date:   Sat Dec 18 12:37:49 2021 +0100

    Renaming

commit 057dbf1aca7be3f7e76a5ff89a582a276b6d3089
Author: Uwe Seimet <Uwe.Seimet@seimet.de>
Date:   Sat Dec 18 12:29:54 2021 +0100

    Comment update

commit 5f699aad2f835f72accdb445d1e59f094aeb108f
Author: Uwe Seimet <Uwe.Seimet@seimet.de>
Date:   Sat Dec 18 12:24:25 2021 +0100

    Signature update

commit cbcf8b09f9d1ba7b82f816269bcfe91d9f00eb6e
Author: Uwe Seimet <Uwe.Seimet@seimet.de>
Date:   Sat Dec 18 12:22:45 2021 +0100

    Signature update

commit a8148ef802ca809e5a305d2caa69856c9033d932
Author: Uwe Seimet <Uwe.Seimet@seimet.de>
Date:   Sat Dec 18 12:16:46 2021 +0100

    Comment update

commit ce685a92d4827e131d80d10ecd56e2b3baf173f8
Author: Uwe Seimet <Uwe.Seimet@seimet.de>
Date:   Sat Dec 18 12:15:46 2021 +0100

    Use map instead of list

commit 454c0438f3589904f5dbe5253963dd200ea416dd
Author: Uwe Seimet <Uwe.Seimet@seimet.de>
Date:   Sat Dec 18 10:47:36 2021 +0100

    Updated size check

commit b386dbba4b0262f4f6f02aecb2a1daeffd41f4a2
Author: Uwe Seimet <Uwe.Seimet@seimet.de>
Date:   Sat Dec 18 01:23:43 2021 +0100

    Initial improvements

* Default value update

* Comment update

* Comment update

* Map operations by ordinal

* Added safeguard against unknown operations

* Added cast

* Data type update

* Sort map by operation name

* Renaming

* Code cleanup

* Comment update

* Renaming

* Comment update

* Description updates

* Fixed typo

* Added operation

* Logging update

* Interface comment update

* Fixed typo

* Aded operation parameters

* Updated handling of mandatory parameters

* Updated assertion handling

* Added missing condition

* Removed duplicate cod3

* Code cleanup

* Logging update

* Removed duplicate code

* Code cleanup

* Squashed commit of the following:

commit 4ae273ccbd
Author: akuker <34318535+akuker@users.noreply.github.com>
Date:   Sun Dec 19 22:30:22 2021 -0600

    Loopback tester pcb (#545)

commit 46c5c1966f
Author: akuker <34318535+akuker@users.noreply.github.com>
Date:   Sun Dec 19 22:29:59 2021 -0600

    RaSCSI Zero version 1.0 (#546)

commit d09df31d67
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 20:25:23 2021 -0800

    Remove redundant code from OLED script (#547)

commit d8828da690
Author: akuker <34318535+akuker@users.noreply.github.com>
Date:   Sun Dec 19 21:02:50 2021 -0600

    Added list of sponsors

commit bcd7e8396d
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 15:51:45 2021 -0800

    Second attempt at properly creating the manpage dir (#542)

commit c887edfc8c
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 15:50:03 2021 -0800

    Remove special elevated privileges for the Web Interface (#536)

    * Use the pi_shutdown method to restart the rascsi service

    * Use the pi_shutdown method to restart the rascsi service

    * Remove modifications to sudoers no longer needed

    * Introduce sleeps attempting to connect to socket; reduce overall number of retries

    * Remove systemd helped methods and the functionality that depends on it

    * Attempts to speed up splash code

    * Remove unneccessary verbosity

    * Attempt to optimize service definition

commit 801aebfb96
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 15:47:22 2021 -0800

    More readable message when downloading a file (#531)

commit 29cf58288f
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 15:47:03 2021 -0800

    Add a warning notice when ejecting removable media (#526)

commit 7efa895239
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 15:46:22 2021 -0800

    Unzip zipfiles before storing to iso (#525)

    * Unzip zipfiles before storing to iso

    * Add helptext

    * Skip unzip for MacZip format

    * Should not be an fstring

commit 39bc485671
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 15:28:22 2021 -0800

    Add pip3 to global dependencies; remove duplicates from monitor_rascs… (#523)

    * Add pip3 to global dependencies; remove duplicates from monitor_rascsi dependencies

    * Cleanup

* Shutdown functionality is only available if started with root permissions

* Only restrict shutdown parameters, not everything if not root

* Updated operation count check
This commit is contained in:
Uwe Seimet 2021-12-21 08:43:21 +01:00 committed by GitHub
parent 693ade2967
commit 94786aec54
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 321 additions and 50 deletions

View File

@ -6,6 +6,7 @@ rasctl \- Sends management commands to the rascsi process
\fB\-e\fR |
\fB\-l\fR |
\fB\-m\fR |
\fB\-o\fR |
\fB\-s\fR |
\fB\-v\fR |
\fB\-D\fR |
@ -82,6 +83,9 @@ List all of the devices that are currently being emulated by RaSCSI, as well as
.BR \-m\fI
List all file extensions recognized by RaSCSI and the device types they map to.
.TP
.BR \-o\fI
Display operation meta data information.
.TP
.BR \-R\fI " "\fICURRENT_NAME:NEW_NAME
Rename an image file in the default image folder.
.TP

View File

@ -6,8 +6,8 @@ NAME
rasctl - Sends management commands to the rascsi process
SYNOPSIS
rasctl -e | -l | -m | -s | -v | -D | -I | -L | -O | -P | -T | -V | -X |
[-C FILENAME:FILESIZE] [-E FILENAME] [-F IMAGE_FOLDER] [-R CUR
rasctl -e | -l | -m | -o | -s | -v | -D | -I | -L | -O | -P | -T | -V |
-X | [-C FILENAME:FILESIZE] [-E FILENAME] [-F IMAGE_FOLDER] [-R CUR
RENT_NAME:NEW_NAME] [-c CMD] [-f FILE|PARAM] [-g LOG_LEVEL] [-h HOST]
[-i ID [-n NAME] [-p PORT] [-r RESERVED_IDS] [-t TYPE] [-u UNIT] [-x
CURRENT_NAME:NEW_NAME]
@ -62,6 +62,8 @@ OPTIONS
-m List all file extensions recognized by RaSCSI and the device
types they map to.
-o Display operation meta data information.
-R CURRENT_NAME:NEW_NAME
Rename an image file in the default image folder.

View File

@ -484,6 +484,8 @@ bool SetLogLevel(const string& log_level)
current_log_level = log_level;
LOGINFO("Set log level to '%s'", current_log_level.c_str());
return true;
}
@ -1431,10 +1433,19 @@ static void *MonThread(void *param)
}
}
if (!PbOperation_IsValid(command.operation())) {
LOGTRACE("Received unknown command %d", command.operation());
ReturnStatus(fd, false, "Unknown command", UNKNOWN_OPERATION);
continue;
}
LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str());
PbResult result;
switch(command.operation()) {
case LOG_LEVEL: {
LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str());
string log_level = GetParam(command, "level");
bool status = SetLogLevel(log_level);
if (!status) {
@ -1447,8 +1458,6 @@ static void *MonThread(void *param)
}
case DEFAULT_FOLDER: {
LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str());
string folder = GetParam(command, "folder");
if (folder.empty()) {
ReturnStatus(fd, false, "Can't set default image folder: Missing folder name");
@ -1465,28 +1474,18 @@ static void *MonThread(void *param)
}
case DEVICES_INFO: {
LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str());
PbResult result;
rascsi_response.GetDevicesInfo(result, command, devices, UnitNum);
SerializeMessage(fd, result);
break;
}
case DEVICE_TYPES_INFO: {
LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str());
PbResult result;
result.set_allocated_device_types_info(rascsi_response.GetDeviceTypesInfo(result, command));
SerializeMessage(fd, result);
break;
}
case SERVER_INFO: {
LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str());
PbResult result;
result.set_allocated_server_info(rascsi_response.GetServerInfo(
result, devices, reserved_ids, current_log_level, GetParam(command, "filename_pattern"),
scan_depth));
@ -1495,27 +1494,18 @@ static void *MonThread(void *param)
}
case VERSION_INFO: {
LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str());
PbResult result;
result.set_allocated_version_info(rascsi_response.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(rascsi_response.GetLogLevelInfo(result, current_log_level));
SerializeMessage(fd, result);
break;
}
case DEFAULT_IMAGE_FILES_INFO: {
LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str());
PbResult result;
result.set_allocated_image_files_info(rascsi_response.GetAvailableImages(result,
GetParam(command, "filename_pattern"), scan_depth));
SerializeMessage(fd, result);
@ -1523,14 +1513,11 @@ static void *MonThread(void *param)
}
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 = rascsi_response.GetImageFile(image_file, filename);
if (status) {
@ -1546,35 +1533,30 @@ static void *MonThread(void *param)
}
case NETWORK_INTERFACES_INFO: {
LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str());
PbResult result;
result.set_allocated_network_interfaces_info(rascsi_response.GetNetworkInterfacesInfo(result));
SerializeMessage(fd, result);
break;
}
case MAPPING_INFO: {
LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str());
PbResult result;
result.set_allocated_mapping_info(rascsi_response.GetMappingInfo(result));
SerializeMessage(fd, result);
break;
}
case RESERVED_IDS_INFO: {
LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str());
case OPERATION_INFO: {
result.set_allocated_operation_info(rascsi_response.GetOperationInfo(result));
SerializeMessage(fd, result);
break;
}
PbResult result;
case RESERVED_IDS_INFO: {
result.set_allocated_reserved_ids_info(rascsi_response.GetReservedIds(result, reserved_ids));
SerializeMessage(fd, result);
break;
}
case SHUT_DOWN: {
LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str());
ShutDown(fd, GetParam(command, "mode"));
break;
}
@ -1613,6 +1595,10 @@ int main(int argc, char* argv[])
{
GOOGLE_PROTOBUF_VERIFY_VERSION;
// Get temporary operation info, in order to trigger an assertion on startup if the operation list is incomplete
PbResult pb_operation_info_result;
rascsi_response.GetOperationInfo(pb_operation_info_result);
int actid;
BUS::phase_t phase;
// added setvbuf to override stdout buffering, so logs are written immediately and not when the process exits.

View File

@ -71,7 +71,7 @@ enum PbOperation {
// "filename_pattern": Optional filter, only filenames containing the case-insensitive pattern are returned
SERVER_INFO = 10;
// Get rascsi version information (PbVersionInfo)
// Get rascsi server version (PbVersionInfo)
VERSION_INFO = 11;
// Get information on attached devices (PbDevicesInfo)
@ -109,7 +109,7 @@ enum PbOperation {
// "folder": The path of the default folder, relative to the user's home folder if relative.
DEFAULT_FOLDER = 20;
// Set a new log level.
// Set the log level.
// Parameters:
// "level": The new log level
LOG_LEVEL = 21;
@ -119,7 +119,7 @@ enum PbOperation {
// "ids": A comma-separated list of IDs to reserve, or an empty string in order not to reserve any ID.
RESERVE_IDS = 22;
// Shut down the rascsi process
// Shut down the rascsi process or shut down/reboot the Raspberry Pi
// Parameters:
// "mode": The shutdown mode, one of "rascsi", "system", "reboot"
SHUT_DOWN = 23;
@ -160,19 +160,54 @@ enum PbOperation {
// Parameters:
// "file": The filename, relative to the default image folder. It must not contain a slash.
UNPROTECT_IMAGE = 29;
// Check whether an authentication token is valid. A client can use this in operation in order to
// Check whether an authentication token is valid. A client can use this operation in order to
// find out whether rascsi authentication is enable or to use rascsi authentication for securing
// client-internal operations.
CHECK_AUTHENTICATION = 30;
// Get operation meta data (PbOperationInfo)
OPERATION_INFO = 31;
}
// rascsi special purpose error codes for cases where a textual error message is not sufficient
// The operation parameter meta data. The parameter data type is provided by the protobuf API.
message PbOperationParameter {
string name = 1;
// Optional short localized description, key is the lower case locale (e.g. en, de).
// Falling back to "en" is recommended if a description for a particular language is missing.
map<string, string> description = 2;
// There is no specific set of permitted values if empty
repeated string permitted_values = 3;
// Optional default value
string default_value = 4;
// True if this parameter is mandatory
bool is_mandatory = 5;
}
// The list of parameters supported by an operation
message PbOperationMetaData {
// The operation name at the time the server-side protobuf code was generated.
string server_side_name = 1;
// Optional short localized description, key is the lower case locale (e.g. en, de).
// Falling back to "en" is recommended if a description for a particular language is missing.
map<string, string> description = 2;
repeated PbOperationParameter parameters = 3;
}
// Mapping of operations to their ordinals
message PbOperationInfo {
map<int32, PbOperationMetaData> operations = 1;
}
// rascsi special purpose error codes for cases where a textual error message may not be not sufficient.
// The client may react on this code, e.g. by prompting the user for an authentication token.
enum PbErrorCode {
// No error code available
NO_ERROR_CODE = 0;
// The client sent an operation code not supported by this server
UNKNOWN_OPERATION = 1;
// Authentication/Authorization error
UNAUTHORIZED = 1;
UNAUTHORIZED = 2;
}
// The supported file extensions mapped to their respective device types
@ -325,7 +360,7 @@ message PbResult {
// An optional error or information message, depending on the status. A string without trailing CR/LF.
string msg = 2;
// An optional error code. Only to be used in cases where textual information is not sufficient.
PbErrorCode error_code = 13;
PbErrorCode error_code = 14;
// Optional additional result data
oneof result {
// The result of a SERVER_INFO command
@ -348,6 +383,8 @@ message PbResult {
PbMappingInfo mapping_info = 11;
// The result of a RESERVED_IDS_INFO command
PbReservedIdsInfo reserved_ids_info = 12;
// The result of an OPERATION_INFO command
PbOperationInfo operation_info = 13;
}
}
@ -369,4 +406,6 @@ message PbServerInfo {
PbReservedIdsInfo reserved_ids_info = 7;
// The attached devices
PbDevicesInfo devices_info = 8;
// The operation meta data
PbOperationInfo operation_info = 9;
}

View File

@ -295,6 +295,7 @@ PbServerInfo *RascsiResponse::GetServerInfo(PbResult& result, const vector<Devic
server_info->set_allocated_mapping_info(GetMappingInfo(result));
GetDevices(*server_info, devices);
server_info->set_allocated_reserved_ids_info(GetReservedIds(result, reserved_ids));
server_info->set_allocated_operation_info(GetOperationInfo(result));
result.set_status(true);
@ -354,3 +355,161 @@ PbMappingInfo *RascsiResponse::GetMappingInfo(PbResult& result)
return mapping_info;
}
PbOperationInfo *RascsiResponse::GetOperationInfo(PbResult& result)
{
PbOperationInfo *operation_info = new PbOperationInfo();
PbOperationMetaData *meta_data = new PbOperationMetaData();
AddOperationParameter(meta_data, "name", "Image file name in case of a mass storage device");
AddOperationParameter(meta_data, "interfaces", "Comma-separated prioritized network interface list");
CreateOperation(operation_info, meta_data, ATTACH, "Attach device, device-specific parameters are required");
meta_data = new PbOperationMetaData();
CreateOperation(operation_info, meta_data, DETACH, "Detach device, device-specific parameters are required");
meta_data = new PbOperationMetaData();
CreateOperation(operation_info, meta_data, DETACH_ALL, "Detach all devices");
meta_data = new PbOperationMetaData();
CreateOperation(operation_info, meta_data, START, "Start device, device-specific parameters are required");
meta_data = new PbOperationMetaData();
CreateOperation(operation_info, meta_data, STOP, "Stop device, device-specific parameters are required");
meta_data = new PbOperationMetaData();
AddOperationParameter(meta_data, "file", "Image file name", "", true);
CreateOperation(operation_info, meta_data, INSERT, "Insert medium, device-specific parameters are required");
meta_data = new PbOperationMetaData();
CreateOperation(operation_info, meta_data, EJECT, "Eject medium, device-specific parameters are required");
meta_data = new PbOperationMetaData();
CreateOperation(operation_info, meta_data, PROTECT, "Protect medium, device-specific parameters are required");
meta_data = new PbOperationMetaData();
CreateOperation(operation_info, meta_data, UNPROTECT, "Unprotect medium, device-specific parameters are required");
meta_data = new PbOperationMetaData();
AddOperationParameter(meta_data, "filename_pattern", "Pattern for filtering image file names");
CreateOperation(operation_info, meta_data, SERVER_INFO, "Get rascsi server information");
meta_data = new PbOperationMetaData();
CreateOperation(operation_info, meta_data, VERSION_INFO, "Get rascsi server version");
meta_data = new PbOperationMetaData();
CreateOperation(operation_info, meta_data, DEVICES_INFO, "Get information on attached devices");
meta_data = new PbOperationMetaData();
CreateOperation(operation_info, meta_data, DEVICE_TYPES_INFO, "Get device properties by device type");
meta_data = new PbOperationMetaData();
AddOperationParameter(meta_data, "filename_pattern", "Pattern for filtering image file names");
CreateOperation(operation_info, meta_data, DEFAULT_IMAGE_FILES_INFO, "Get information on available image files");
meta_data = new PbOperationMetaData();
AddOperationParameter(meta_data, "file", "Image file name", "", true);
CreateOperation(operation_info, meta_data, IMAGE_FILE_INFO, "Get information on image file");
meta_data = new PbOperationMetaData();
CreateOperation(operation_info, meta_data, LOG_LEVEL_INFO, "Get log level information");
meta_data = new PbOperationMetaData();
CreateOperation(operation_info, meta_data, NETWORK_INTERFACES_INFO, "Get the available network interfaces");
meta_data = new PbOperationMetaData();
CreateOperation(operation_info, meta_data, MAPPING_INFO, "Get mapping of extensions to device types");
meta_data = new PbOperationMetaData();
CreateOperation(operation_info, meta_data, RESERVED_IDS_INFO, "Get list of reserved device IDs");
meta_data = new PbOperationMetaData();
AddOperationParameter(meta_data, "folder", "Default image file folder name", "", true);
CreateOperation(operation_info, meta_data, DEFAULT_FOLDER, "Set default image file folder");
meta_data = new PbOperationMetaData();
AddOperationParameter(meta_data, "level", "New log level", "", true);
CreateOperation(operation_info, meta_data, LOG_LEVEL, "Set log level");
meta_data = new PbOperationMetaData();
AddOperationParameter(meta_data, "ids", "Comma-separated device ID list", "", true);
CreateOperation(operation_info, meta_data, RESERVE_IDS, "Reserve device IDs");
meta_data = new PbOperationMetaData();
PbOperationParameter *parameter = AddOperationParameter(meta_data, "mode", "Shutdown mode", "", true);
parameter->add_permitted_values("rascsi");
// System shutdown/reboot requires root permissions
if (!getuid()) {
parameter->add_permitted_values("system");
parameter->add_permitted_values("reboot");
}
CreateOperation(operation_info, meta_data, SHUT_DOWN, "Shut down or reboot");
meta_data = new PbOperationMetaData();
AddOperationParameter(meta_data, "file", "Image file name", "", true);
AddOperationParameter(meta_data, "size", "Image file size in bytes", "", true);
parameter = AddOperationParameter(meta_data, "read_only", "Read-only flag", "false");
parameter->add_permitted_values("true");
parameter->add_permitted_values("false");
CreateOperation(operation_info, meta_data, CREATE_IMAGE, "Create an image file");
meta_data = new PbOperationMetaData();
AddOperationParameter(meta_data, "file", "Image file name", "", true);
CreateOperation(operation_info, meta_data, DELETE_IMAGE, "Delete image file");
meta_data = new PbOperationMetaData();
AddOperationParameter(meta_data, "from", "Source image file name", "", true);
AddOperationParameter(meta_data, "to", "Destination image file name", "", true);
CreateOperation(operation_info, meta_data, RENAME_IMAGE, "Rename image file");
meta_data = new PbOperationMetaData();
AddOperationParameter(meta_data, "from", "Source image file name image file name", "", true);
AddOperationParameter(meta_data, "to", "Destination image file name", "", true);
parameter = AddOperationParameter(meta_data, "read_only", "Read-only flag", "false");
parameter->add_permitted_values("true");
parameter->add_permitted_values("false");
CreateOperation(operation_info, meta_data, COPY_IMAGE, "Copy image file");
meta_data = new PbOperationMetaData();
AddOperationParameter(meta_data, "file", "Image file name", "", true);
CreateOperation(operation_info, meta_data, PROTECT_IMAGE, "Write-protect image file");
meta_data = new PbOperationMetaData();
AddOperationParameter(meta_data, "file", "Image file name", "", true);
CreateOperation(operation_info, meta_data, UNPROTECT_IMAGE, "Make image file writable");
meta_data = new PbOperationMetaData();
AddOperationParameter(meta_data, "token", "Authentication token to be checked", "", true);
CreateOperation(operation_info, meta_data, CHECK_AUTHENTICATION, "Check whether an authentication token is valid");
meta_data = new PbOperationMetaData();
CreateOperation(operation_info, meta_data, OPERATION_INFO, "Get operation meta data");
// Ensure that the complete set of operations is covered
assert(operation_info->operations_size() == PbOperation_ARRAYSIZE - 1);
result.set_status(true);
return operation_info;
}
void RascsiResponse::CreateOperation(PbOperationInfo *operation_info, PbOperationMetaData *meta_data,
const PbOperation& operation, const string& description)
{
meta_data->set_server_side_name(PbOperation_Name(operation));
(*meta_data->mutable_description())["en"] = description;
int ordinal = PbOperation_descriptor()->FindValueByName(PbOperation_Name(operation))->index();
(*operation_info->mutable_operations())[ordinal] = *meta_data;
}
PbOperationParameter *RascsiResponse::AddOperationParameter(PbOperationMetaData *meta_data, const string& name,
const string& description, const string& default_value, bool is_mandatory)
{
PbOperationParameter *parameter = meta_data->add_parameters();
parameter->set_name(name);
(*parameter->mutable_description())["en"] = description;
parameter->set_default_value(default_value);
parameter->set_is_mandatory(is_mandatory);
return parameter;
}

View File

@ -39,6 +39,7 @@ public:
PbNetworkInterfacesInfo *GetNetworkInterfacesInfo(PbResult&);
PbMappingInfo *GetMappingInfo(PbResult&);
PbLogLevelInfo *GetLogLevelInfo(PbResult&, const string&);
PbOperationInfo *GetOperationInfo(PbResult&);
private:
@ -53,4 +54,7 @@ private:
void GetDeviceTypeProperties(PbDeviceTypesInfo&, PbDeviceType);
void GetAvailableImages(PbImageFilesInfo&, const string&, const string&, const string&, int);
void GetAvailableImages(PbResult& result, PbServerInfo&, const string&, int);
void CreateOperation(PbOperationInfo *, PbOperationMetaData *, const PbOperation&, const string&);
PbOperationParameter *AddOperationParameter(PbOperationMetaData *, const string&, const string&,
const string& = "", bool = false);
};

View File

@ -101,8 +101,8 @@ int main(int argc, char* argv[])
cerr << "version " << rascsi_get_version_string() << " (" << __DATE__ << ", " << __TIME__ << ")" << endl;
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] [-d FILENAME] [-w FILENAME] [-P TOKEN] [-R CURRENT_NAME:NEW_NAME] [-x CURRENT_NAME:NEW_NAME] ";
cerr << "[-e] [-E FILENAME] [-D] [-I] [-l] [-L] [-m] [-O] [-s] [-v] [-V] [-y] [-X]" << endl;
cerr << "[-C FILENAME:FILESIZE] [-d FILENAME] [-w FILENAME] [-R CURRENT_NAME:NEW_NAME] [-x CURRENT_NAME:NEW_NAME] ";
cerr << "[-e] [-E FILENAME] [-D] [-I] [-l] [-L] [-m] [o] [-O] [-s] [-v] [-V] [-y] [-X]" << endl;
cerr << " where ID := {0-7}" << endl;
cerr << " UNIT := {0-31}, default is 0" << endl;
cerr << " CMD := {attach|detach|insert|eject|protect|unprotect|show}" << endl;
@ -139,7 +139,7 @@ int main(int argc, char* argv[])
opterr = 1;
int opt;
while ((opt = getopt(argc, argv, "elmsvDINOTVXa:b:c:d:f:h:i:n:p:r:t:u:x:C:E:F:L:R:P::")) != -1) {
while ((opt = getopt(argc, argv, "elmosvDINOTVXa:b:c:d:f:h:i:n:p:r:t:u:x:C:E:F:L:R:P::")) != -1) {
switch (opt) {
case 'i': {
int id;
@ -239,6 +239,10 @@ int main(int argc, char* argv[])
command.set_operation(LOG_LEVEL_INFO);
break;
case 'o':
command.set_operation(OPERATION_INFO);
break;
case 't':
device->set_type(ParseType(optarg));
if (device->type() == UNDEFINED) {
@ -416,6 +420,10 @@ int main(int argc, char* argv[])
rasctl_commands.CommandMappingInfo();
break;
case OPERATION_INFO:
rasctl_commands.CommandOperationInfo();
break;
default:
rasctl_commands.SendCommand();
break;

View File

@ -222,6 +222,7 @@ void RasctlCommands::CommandServerInfo()
rasctl_display.DisplayNetworkInterfaces(server_info.network_interfaces_info());
rasctl_display.DisplayDeviceTypesInfo(server_info.device_types_info());
rasctl_display.DisplayReservedIdsInfo(server_info.reserved_ids_info());
rasctl_display.DisplayOperationInfo(server_info.operation_info());
if (server_info.devices_info().devices_size()) {
list<PbDevice> sorted_devices = { server_info.devices_info().devices().begin(), server_info.devices_info().devices().end() };
@ -278,3 +279,10 @@ void RasctlCommands::CommandMappingInfo()
rasctl_display.DisplayMappingInfo(result.mapping_info());
}
void RasctlCommands::CommandOperationInfo()
{
SendCommand();
rasctl_display.DisplayOperationInfo(result.operation_info());
}

View File

@ -42,6 +42,7 @@ public:
void CommandLogLevelInfo();
void CommandReservedIdsInfo();
void CommandMappingInfo();
void CommandOperationInfo();
private:

View File

@ -273,3 +273,62 @@ void RasctlDisplay::DisplayMappingInfo(const PbMappingInfo& mapping_info)
cout << " " << mapping.first << "->" << PbDeviceType_Name(mapping.second) << endl;
}
}
void RasctlDisplay::DisplayOperationInfo(const PbOperationInfo& operation_info)
{
const map<int, PbOperationMetaData> operations = { operation_info.operations().begin(), operation_info.operations().end() };
// Copies result into a map sorted by operation name
const PbOperationMetaData *unknown_operation = new PbOperationMetaData();
map<string, PbOperationMetaData> sorted_operations;
for (const auto& operation : operations) {
if (PbOperation_IsValid(static_cast<PbOperation>(operation.first))) {
sorted_operations[PbOperation_Name(static_cast<PbOperation>(operation.first))] = operation.second;
}
else {
// If the server-side operation is unknown for the client use the server-provided operation name
// No further operation information is available in this case
sorted_operations[operation.second.server_side_name()] = *unknown_operation;
}
}
cout << "Remote operations supported by rascsi and their parameters:" << endl;
for (const auto& operation : sorted_operations) {
if (!operation.second.server_side_name().empty()) {
cout << " " << operation.first;
if (!operation.second.description().empty()) {
cout << " (" << operation.second.description().at("en") << ")";
}
cout << endl;
for (const auto& parameter : operation.second.parameters()) {
cout << " " << parameter.name() << ": "
<< (parameter.is_mandatory() ? "mandatory" : "optional");
if (!parameter.description().empty()) {
cout << " (" << parameter.description().at("en") << ")";
}
cout << endl;
if (parameter.permitted_values_size()) {
cout << " Permitted values: ";
bool isFirst = true;
for (const auto& permitted_value : parameter.permitted_values()) {
if (!isFirst) {
cout << ", ";
}
isFirst = false;
cout << permitted_value;
}
cout << endl;
}
if (!parameter.default_value().empty()) {
cout << " Default value: " << parameter.default_value() << endl;
}
}
}
else {
cout << " " << operation.first << " (Unknown server-side operation)" << endl;
}
}
}

View File

@ -30,4 +30,5 @@ public:
void DisplayImageFiles(const PbImageFilesInfo&);
void DisplayNetworkInterfaces(const PbNetworkInterfacesInfo&);
void DisplayMappingInfo(const PbMappingInfo&);
void DisplayOperationInfo(const PbOperationInfo&);
};