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 4ae273ccbd3e2b9bfda6426a9c1f71844b48b2d9
Author: akuker <34318535+akuker@users.noreply.github.com>
Date:   Sun Dec 19 22:30:22 2021 -0600

    Loopback tester pcb (#545)

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

    RaSCSI Zero version 1.0 (#546)

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

    Remove redundant code from OLED script (#547)

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

    Added list of sponsors

commit bcd7e8396d945f5a051e01080354d3ac7ba63704
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 c887edfc8c9956aa9dcac3764abe6cef16ffb596
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 801aebfb96e968a3bef1575b0301db4bd7625a35
Author: Daniel Markstedt <markstedt@gmail.com>
Date:   Sun Dec 19 15:47:22 2021 -0800

    More readable message when downloading a file (#531)

commit 29cf58288f228fe235b7d6fe2f0dd5852cf9a411
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 7efa89523905a6985bea261f1dcf078ec76faf27
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 39bc485671fa5163c6fc87860eed53b2966637ca
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\-e\fR |
\fB\-l\fR | \fB\-l\fR |
\fB\-m\fR | \fB\-m\fR |
\fB\-o\fR |
\fB\-s\fR | \fB\-s\fR |
\fB\-v\fR | \fB\-v\fR |
\fB\-D\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 .BR \-m\fI
List all file extensions recognized by RaSCSI and the device types they map to. List all file extensions recognized by RaSCSI and the device types they map to.
.TP .TP
.BR \-o\fI
Display operation meta data information.
.TP
.BR \-R\fI " "\fICURRENT_NAME:NEW_NAME .BR \-R\fI " "\fICURRENT_NAME:NEW_NAME
Rename an image file in the default image folder. Rename an image file in the default image folder.
.TP .TP

View File

@ -6,8 +6,8 @@ NAME
rasctl - Sends management commands to the rascsi process rasctl - Sends management commands to the rascsi process
SYNOPSIS SYNOPSIS
rasctl -e | -l | -m | -s | -v | -D | -I | -L | -O | -P | -T | -V | -X | rasctl -e | -l | -m | -o | -s | -v | -D | -I | -L | -O | -P | -T | -V |
[-C FILENAME:FILESIZE] [-E FILENAME] [-F IMAGE_FOLDER] [-R CUR -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] 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 [-i ID [-n NAME] [-p PORT] [-r RESERVED_IDS] [-t TYPE] [-u UNIT] [-x
CURRENT_NAME:NEW_NAME] CURRENT_NAME:NEW_NAME]
@ -62,6 +62,8 @@ OPTIONS
-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.
-o Display operation meta data information.
-R CURRENT_NAME:NEW_NAME -R CURRENT_NAME:NEW_NAME
Rename an image file in the default image folder. 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; current_log_level = log_level;
LOGINFO("Set log level to '%s'", current_log_level.c_str());
return true; 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()) { switch(command.operation()) {
case LOG_LEVEL: { case LOG_LEVEL: {
LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str());
string log_level = GetParam(command, "level"); string log_level = GetParam(command, "level");
bool status = SetLogLevel(log_level); bool status = SetLogLevel(log_level);
if (!status) { if (!status) {
@ -1447,8 +1458,6 @@ static void *MonThread(void *param)
} }
case DEFAULT_FOLDER: { case DEFAULT_FOLDER: {
LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str());
string folder = GetParam(command, "folder"); string folder = GetParam(command, "folder");
if (folder.empty()) { if (folder.empty()) {
ReturnStatus(fd, false, "Can't set default image folder: Missing folder name"); ReturnStatus(fd, false, "Can't set default image folder: Missing folder name");
@ -1465,28 +1474,18 @@ static void *MonThread(void *param)
} }
case DEVICES_INFO: { case DEVICES_INFO: {
LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str());
PbResult result;
rascsi_response.GetDevicesInfo(result, command, devices, UnitNum); rascsi_response.GetDevicesInfo(result, command, devices, UnitNum);
SerializeMessage(fd, result); SerializeMessage(fd, result);
break; break;
} }
case DEVICE_TYPES_INFO: { 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)); result.set_allocated_device_types_info(rascsi_response.GetDeviceTypesInfo(result, command));
SerializeMessage(fd, result); SerializeMessage(fd, result);
break; break;
} }
case SERVER_INFO: { case SERVER_INFO: {
LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str());
PbResult result;
result.set_allocated_server_info(rascsi_response.GetServerInfo( result.set_allocated_server_info(rascsi_response.GetServerInfo(
result, devices, reserved_ids, current_log_level, GetParam(command, "filename_pattern"), result, devices, reserved_ids, current_log_level, GetParam(command, "filename_pattern"),
scan_depth)); scan_depth));
@ -1495,27 +1494,18 @@ static void *MonThread(void *param)
} }
case VERSION_INFO: { case VERSION_INFO: {
LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str());
PbResult result;
result.set_allocated_version_info(rascsi_response.GetVersionInfo(result)); result.set_allocated_version_info(rascsi_response.GetVersionInfo(result));
SerializeMessage(fd, result); SerializeMessage(fd, result);
break; break;
} }
case LOG_LEVEL_INFO: { 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)); result.set_allocated_log_level_info(rascsi_response.GetLogLevelInfo(result, current_log_level));
SerializeMessage(fd, result); SerializeMessage(fd, result);
break; break;
} }
case DEFAULT_IMAGE_FILES_INFO: { 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, result.set_allocated_image_files_info(rascsi_response.GetAvailableImages(result,
GetParam(command, "filename_pattern"), scan_depth)); GetParam(command, "filename_pattern"), scan_depth));
SerializeMessage(fd, result); SerializeMessage(fd, result);
@ -1523,14 +1513,11 @@ static void *MonThread(void *param)
} }
case IMAGE_FILE_INFO: { case IMAGE_FILE_INFO: {
LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str());
string filename = GetParam(command, "file"); string filename = GetParam(command, "file");
if (filename.empty()) { if (filename.empty()) {
ReturnStatus(fd, false, "Can't get image file info: Missing filename"); ReturnStatus(fd, false, "Can't get image file info: Missing filename");
} }
else { else {
PbResult result;
PbImageFile* image_file = new PbImageFile(); PbImageFile* image_file = new PbImageFile();
bool status = rascsi_response.GetImageFile(image_file, filename); bool status = rascsi_response.GetImageFile(image_file, filename);
if (status) { if (status) {
@ -1546,35 +1533,30 @@ static void *MonThread(void *param)
} }
case NETWORK_INTERFACES_INFO: { 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)); result.set_allocated_network_interfaces_info(rascsi_response.GetNetworkInterfacesInfo(result));
SerializeMessage(fd, result); SerializeMessage(fd, result);
break; break;
} }
case MAPPING_INFO: { case MAPPING_INFO: {
LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str());
PbResult result;
result.set_allocated_mapping_info(rascsi_response.GetMappingInfo(result)); result.set_allocated_mapping_info(rascsi_response.GetMappingInfo(result));
SerializeMessage(fd, result); SerializeMessage(fd, result);
break; break;
} }
case RESERVED_IDS_INFO: { case OPERATION_INFO: {
LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str()); 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)); result.set_allocated_reserved_ids_info(rascsi_response.GetReservedIds(result, reserved_ids));
SerializeMessage(fd, result); SerializeMessage(fd, result);
break; break;
} }
case SHUT_DOWN: { case SHUT_DOWN: {
LOGTRACE("Received %s command", PbOperation_Name(command.operation()).c_str());
ShutDown(fd, GetParam(command, "mode")); ShutDown(fd, GetParam(command, "mode"));
break; break;
} }
@ -1613,6 +1595,10 @@ int main(int argc, char* argv[])
{ {
GOOGLE_PROTOBUF_VERIFY_VERSION; 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; int actid;
BUS::phase_t phase; BUS::phase_t phase;
// added setvbuf to override stdout buffering, so logs are written immediately and not when the process exits. // 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 // "filename_pattern": Optional filter, only filenames containing the case-insensitive pattern are returned
SERVER_INFO = 10; SERVER_INFO = 10;
// Get rascsi version information (PbVersionInfo) // Get rascsi server version (PbVersionInfo)
VERSION_INFO = 11; VERSION_INFO = 11;
// Get information on attached devices (PbDevicesInfo) // 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. // "folder": The path of the default folder, relative to the user's home folder if relative.
DEFAULT_FOLDER = 20; DEFAULT_FOLDER = 20;
// Set a new log level. // Set the log level.
// Parameters: // Parameters:
// "level": The new log level // "level": The new log level
LOG_LEVEL = 21; 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. // "ids": A comma-separated list of IDs to reserve, or an empty string in order not to reserve any ID.
RESERVE_IDS = 22; RESERVE_IDS = 22;
// Shut down the rascsi process // Shut down the rascsi process or shut down/reboot the Raspberry Pi
// Parameters: // Parameters:
// "mode": The shutdown mode, one of "rascsi", "system", "reboot" // "mode": The shutdown mode, one of "rascsi", "system", "reboot"
SHUT_DOWN = 23; SHUT_DOWN = 23;
@ -160,19 +160,54 @@ enum PbOperation {
// 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 = 29; 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 // find out whether rascsi authentication is enable or to use rascsi authentication for securing
// client-internal operations. // client-internal operations.
CHECK_AUTHENTICATION = 30; 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 { enum PbErrorCode {
// No error code available // No error code available
NO_ERROR_CODE = 0; NO_ERROR_CODE = 0;
// The client sent an operation code not supported by this server
UNKNOWN_OPERATION = 1;
// Authentication/Authorization error // Authentication/Authorization error
UNAUTHORIZED = 1; UNAUTHORIZED = 2;
} }
// The supported file extensions mapped to their respective device types // 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. // An optional error or information message, depending on the status. A string without trailing CR/LF.
string msg = 2; string msg = 2;
// An optional error code. Only to be used in cases where textual information is not sufficient. // 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 // Optional additional result data
oneof result { oneof result {
// The result of a SERVER_INFO command // The result of a SERVER_INFO command
@ -348,6 +383,8 @@ message PbResult {
PbMappingInfo mapping_info = 11; PbMappingInfo mapping_info = 11;
// The result of a RESERVED_IDS_INFO command // The result of a RESERVED_IDS_INFO command
PbReservedIdsInfo reserved_ids_info = 12; 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; PbReservedIdsInfo reserved_ids_info = 7;
// The attached devices // The attached devices
PbDevicesInfo devices_info = 8; 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)); server_info->set_allocated_mapping_info(GetMappingInfo(result));
GetDevices(*server_info, devices); GetDevices(*server_info, devices);
server_info->set_allocated_reserved_ids_info(GetReservedIds(result, reserved_ids)); server_info->set_allocated_reserved_ids_info(GetReservedIds(result, reserved_ids));
server_info->set_allocated_operation_info(GetOperationInfo(result));
result.set_status(true); result.set_status(true);
@ -354,3 +355,161 @@ PbMappingInfo *RascsiResponse::GetMappingInfo(PbResult& result)
return mapping_info; 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&); PbNetworkInterfacesInfo *GetNetworkInterfacesInfo(PbResult&);
PbMappingInfo *GetMappingInfo(PbResult&); PbMappingInfo *GetMappingInfo(PbResult&);
PbLogLevelInfo *GetLogLevelInfo(PbResult&, const string&); PbLogLevelInfo *GetLogLevelInfo(PbResult&, const string&);
PbOperationInfo *GetOperationInfo(PbResult&);
private: private:
@ -53,4 +54,7 @@ private:
void GetDeviceTypeProperties(PbDeviceTypesInfo&, PbDeviceType); void GetDeviceTypeProperties(PbDeviceTypesInfo&, PbDeviceType);
void GetAvailableImages(PbImageFilesInfo&, const string&, const string&, const string&, int); void GetAvailableImages(PbImageFilesInfo&, const string&, const string&, const string&, int);
void GetAvailableImages(PbResult& result, PbServerInfo&, 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 << "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 << "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] [-d FILENAME] [-w FILENAME] [-P TOKEN] [-R CURRENT_NAME:NEW_NAME] [-x CURRENT_NAME:NEW_NAME] "; 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] [-s] [-v] [-V] [-y] [-X]" << endl; cerr << "[-e] [-E FILENAME] [-D] [-I] [-l] [-L] [-m] [o] [-O] [-s] [-v] [-V] [-y] [-X]" << endl;
cerr << " where ID := {0-7}" << endl; cerr << " where ID := {0-7}" << endl;
cerr << " UNIT := {0-31}, default is 0" << endl; cerr << " UNIT := {0-31}, default is 0" << endl;
cerr << " CMD := {attach|detach|insert|eject|protect|unprotect|show}" << endl; cerr << " CMD := {attach|detach|insert|eject|protect|unprotect|show}" << endl;
@ -139,7 +139,7 @@ int main(int argc, char* argv[])
opterr = 1; opterr = 1;
int opt; 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) { switch (opt) {
case 'i': { case 'i': {
int id; int id;
@ -239,6 +239,10 @@ int main(int argc, char* argv[])
command.set_operation(LOG_LEVEL_INFO); command.set_operation(LOG_LEVEL_INFO);
break; break;
case 'o':
command.set_operation(OPERATION_INFO);
break;
case 't': case 't':
device->set_type(ParseType(optarg)); device->set_type(ParseType(optarg));
if (device->type() == UNDEFINED) { if (device->type() == UNDEFINED) {
@ -416,6 +420,10 @@ int main(int argc, char* argv[])
rasctl_commands.CommandMappingInfo(); rasctl_commands.CommandMappingInfo();
break; break;
case OPERATION_INFO:
rasctl_commands.CommandOperationInfo();
break;
default: default:
rasctl_commands.SendCommand(); rasctl_commands.SendCommand();
break; break;

View File

@ -222,6 +222,7 @@ void RasctlCommands::CommandServerInfo()
rasctl_display.DisplayNetworkInterfaces(server_info.network_interfaces_info()); rasctl_display.DisplayNetworkInterfaces(server_info.network_interfaces_info());
rasctl_display.DisplayDeviceTypesInfo(server_info.device_types_info()); rasctl_display.DisplayDeviceTypesInfo(server_info.device_types_info());
rasctl_display.DisplayReservedIdsInfo(server_info.reserved_ids_info()); rasctl_display.DisplayReservedIdsInfo(server_info.reserved_ids_info());
rasctl_display.DisplayOperationInfo(server_info.operation_info());
if (server_info.devices_info().devices_size()) { if (server_info.devices_info().devices_size()) {
list<PbDevice> sorted_devices = { server_info.devices_info().devices().begin(), server_info.devices_info().devices().end() }; 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()); 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 CommandLogLevelInfo();
void CommandReservedIdsInfo(); void CommandReservedIdsInfo();
void CommandMappingInfo(); void CommandMappingInfo();
void CommandOperationInfo();
private: private:

View File

@ -273,3 +273,62 @@ void RasctlDisplay::DisplayMappingInfo(const PbMappingInfo& mapping_info)
cout << " " << mapping.first << "->" << PbDeviceType_Name(mapping.second) << endl; 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 DisplayImageFiles(const PbImageFilesInfo&);
void DisplayNetworkInterfaces(const PbNetworkInterfacesInfo&); void DisplayNetworkInterfaces(const PbNetworkInterfacesInfo&);
void DisplayMappingInfo(const PbMappingInfo&); void DisplayMappingInfo(const PbMappingInfo&);
void DisplayOperationInfo(const PbOperationInfo&);
}; };