mirror of https://github.com/akuker/RASCSI.git
368 lines
8.5 KiB
C++
368 lines
8.5 KiB
C++
//---------------------------------------------------------------------------
|
|
//
|
|
// SCSI Target Emulator RaSCSI Reloaded
|
|
// for Raspberry Pi
|
|
//
|
|
// Copyright (C) 2021-2022 Uwe Seimet
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
#include "rascsi_exceptions.h"
|
|
#include "protobuf_serializer.h"
|
|
#include "command_util.h"
|
|
#include "rasutil.h"
|
|
#include "rasctl_commands.h"
|
|
#include "rascsi_interface.pb.h"
|
|
#include <unistd.h>
|
|
#include <netdb.h>
|
|
#include <iostream>
|
|
#include <list>
|
|
|
|
using namespace std;
|
|
using namespace rascsi_interface;
|
|
using namespace command_util;
|
|
|
|
// Separator for the INQUIRY name components
|
|
static const char COMPONENT_SEPARATOR = ':';
|
|
|
|
RasctlCommands::RasctlCommands(const PbCommand& command, const string& hostname, int port, const string& token,
|
|
const string& locale)
|
|
: command(command), hostname(hostname), port(port), token(token), locale(locale)
|
|
{
|
|
}
|
|
|
|
void RasctlCommands::Execute(const string& log_level, const string& default_folder, const string& reserved_ids,
|
|
const string& image_params, const string& filename)
|
|
{
|
|
switch(command.operation()) {
|
|
case LOG_LEVEL:
|
|
CommandLogLevel(log_level);
|
|
break;
|
|
|
|
case DEFAULT_FOLDER:
|
|
CommandDefaultImageFolder(default_folder);
|
|
break;
|
|
|
|
case RESERVE_IDS:
|
|
CommandReserveIds(reserved_ids);
|
|
break;
|
|
|
|
case CREATE_IMAGE:
|
|
CommandCreateImage(image_params);
|
|
break;
|
|
|
|
case DELETE_IMAGE:
|
|
CommandDeleteImage(image_params);
|
|
break;
|
|
|
|
case RENAME_IMAGE:
|
|
CommandRenameImage(image_params);
|
|
break;
|
|
|
|
case COPY_IMAGE:
|
|
CommandCopyImage(image_params);
|
|
break;
|
|
|
|
case DEVICES_INFO:
|
|
CommandDeviceInfo();
|
|
break;
|
|
|
|
case DEVICE_TYPES_INFO:
|
|
CommandDeviceTypesInfo();
|
|
break;
|
|
|
|
case VERSION_INFO:
|
|
CommandVersionInfo();
|
|
break;
|
|
|
|
case SERVER_INFO:
|
|
CommandServerInfo();
|
|
break;
|
|
|
|
case DEFAULT_IMAGE_FILES_INFO:
|
|
CommandDefaultImageFilesInfo();
|
|
break;
|
|
|
|
case IMAGE_FILE_INFO:
|
|
CommandImageFileInfo(filename);
|
|
break;
|
|
|
|
case NETWORK_INTERFACES_INFO:
|
|
CommandNetworkInterfacesInfo();
|
|
break;
|
|
|
|
case LOG_LEVEL_INFO:
|
|
CommandLogLevelInfo();
|
|
break;
|
|
|
|
case RESERVED_IDS_INFO:
|
|
CommandReservedIdsInfo();
|
|
break;
|
|
|
|
case MAPPING_INFO:
|
|
CommandMappingInfo();
|
|
break;
|
|
|
|
case OPERATION_INFO:
|
|
CommandOperationInfo();
|
|
break;
|
|
|
|
default:
|
|
SendCommand();
|
|
break;
|
|
}
|
|
}
|
|
|
|
void RasctlCommands::SendCommand()
|
|
{
|
|
if (!token.empty()) {
|
|
AddParam(command, "token", token);
|
|
}
|
|
|
|
if (!locale.empty()) {
|
|
AddParam(command, "locale", locale);
|
|
}
|
|
|
|
// Send command
|
|
int fd = -1;
|
|
try {
|
|
const hostent *host = gethostbyname(hostname.c_str());
|
|
if (!host) {
|
|
throw io_exception("Can't resolve hostname '" + hostname + "'");
|
|
}
|
|
|
|
fd = socket(AF_INET, SOCK_STREAM, 0);
|
|
if (fd < 0) {
|
|
throw io_exception("Can't create socket");
|
|
}
|
|
|
|
sockaddr_in server = {};
|
|
server.sin_family = AF_INET;
|
|
server.sin_port = htons((uint16_t)port);
|
|
server.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
|
memcpy(&server.sin_addr.s_addr, host->h_addr, host->h_length);
|
|
|
|
if (connect(fd, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0) {
|
|
throw io_exception("Can't connect to rascsi process on host '" + hostname + "', port "
|
|
+ to_string(port));
|
|
}
|
|
|
|
if (write(fd, "RASCSI", 6) != 6) {
|
|
throw io_exception("Can't write magic");
|
|
}
|
|
|
|
serializer.SerializeMessage(fd, command);
|
|
}
|
|
catch(const io_exception& e) {
|
|
cerr << "Error: " << e.get_msg() << endl;
|
|
|
|
if (fd >= 0) {
|
|
close(fd);
|
|
}
|
|
|
|
exit(fd < 0 ? ENOTCONN : EXIT_FAILURE);
|
|
}
|
|
|
|
// Receive result
|
|
try {
|
|
serializer.DeserializeMessage(fd, result);
|
|
|
|
if (!result.status()) {
|
|
throw io_exception(result.msg());
|
|
}
|
|
}
|
|
catch(const io_exception& e) {
|
|
close(fd);
|
|
|
|
cerr << "Error: " << e.get_msg() << endl;
|
|
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
close(fd);
|
|
|
|
if (!result.msg().empty()) {
|
|
cout << result.msg() << endl;
|
|
}
|
|
}
|
|
|
|
void RasctlCommands::CommandDevicesInfo()
|
|
{
|
|
SendCommand();
|
|
|
|
rasctl_display.DisplayDevices(result.devices_info());
|
|
}
|
|
|
|
void RasctlCommands::CommandLogLevel(const string& log_level)
|
|
{
|
|
AddParam(command, "level", log_level);
|
|
|
|
SendCommand();
|
|
}
|
|
|
|
void RasctlCommands::CommandReserveIds(const string& reserved_ids)
|
|
{
|
|
AddParam(command, "ids", reserved_ids);
|
|
|
|
SendCommand();
|
|
}
|
|
|
|
void RasctlCommands::CommandCreateImage(const string& image_params)
|
|
{
|
|
if (size_t separator_pos = image_params.find(COMPONENT_SEPARATOR); separator_pos != string::npos) {
|
|
AddParam(command, "file", string_view(image_params).substr(0, separator_pos));
|
|
AddParam(command, "size", string_view(image_params).substr(separator_pos + 1));
|
|
}
|
|
else {
|
|
cerr << "Error: Invalid file descriptor '" << image_params << "', format is NAME:SIZE" << endl;
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
AddParam(command, "read_only", "false");
|
|
|
|
SendCommand();
|
|
}
|
|
|
|
void RasctlCommands::CommandDeleteImage(const string& filename)
|
|
{
|
|
AddParam(command, "file", filename);
|
|
|
|
SendCommand();
|
|
}
|
|
|
|
void RasctlCommands::CommandRenameImage(const string& image_params)
|
|
{
|
|
if (size_t separator_pos = image_params.find(COMPONENT_SEPARATOR); separator_pos != string::npos) {
|
|
AddParam(command, "from", string_view(image_params).substr(0, separator_pos));
|
|
AddParam(command, "to", string_view(image_params).substr(separator_pos + 1));
|
|
}
|
|
else {
|
|
cerr << "Error: Invalid file descriptor '" << image_params << "', format is CURRENT_NAME:NEW_NAME" << endl;
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
SendCommand();
|
|
}
|
|
|
|
void RasctlCommands::CommandCopyImage(const string& image_params)
|
|
{
|
|
if (size_t separator_pos = image_params.find(COMPONENT_SEPARATOR); separator_pos != string::npos) {
|
|
AddParam(command, "from", string_view(image_params).substr(0, separator_pos));
|
|
AddParam(command, "to", string_view(image_params).substr(separator_pos + 1));
|
|
}
|
|
else {
|
|
cerr << "Error: Invalid file descriptor '" << image_params << "', format is CURRENT_NAME:NEW_NAME" << endl;
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
SendCommand();
|
|
}
|
|
|
|
void RasctlCommands::CommandDefaultImageFolder(const string& folder)
|
|
{
|
|
AddParam(command, "folder", folder);
|
|
|
|
SendCommand();
|
|
}
|
|
|
|
void RasctlCommands::CommandDeviceInfo()
|
|
{
|
|
SendCommand();
|
|
|
|
for (const auto& device : result.devices_info().devices()) {
|
|
rasctl_display.DisplayDeviceInfo(device);
|
|
}
|
|
}
|
|
|
|
void RasctlCommands::CommandDeviceTypesInfo()
|
|
{
|
|
SendCommand();
|
|
|
|
rasctl_display.DisplayDeviceTypesInfo(result.device_types_info());
|
|
}
|
|
|
|
void RasctlCommands::CommandVersionInfo()
|
|
{
|
|
SendCommand();
|
|
|
|
rasctl_display.DisplayVersionInfo(result.version_info());
|
|
}
|
|
|
|
void RasctlCommands::CommandServerInfo()
|
|
{
|
|
SendCommand();
|
|
|
|
PbServerInfo server_info = result.server_info();
|
|
|
|
rasctl_display.DisplayVersionInfo(server_info.version_info());
|
|
rasctl_display.DisplayLogLevelInfo(server_info.log_level_info());
|
|
rasctl_display.DisplayImageFiles(server_info.image_files_info());
|
|
rasctl_display.DisplayMappingInfo(server_info.mapping_info());
|
|
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() };
|
|
sorted_devices.sort([](const auto& a, const auto& b) { return a.id() < b.id() || a.unit() < b.unit(); });
|
|
|
|
cout << "Attached devices:" << endl;
|
|
|
|
for (const auto& device : sorted_devices) {
|
|
rasctl_display.DisplayDeviceInfo(device);
|
|
}
|
|
}
|
|
}
|
|
|
|
void RasctlCommands::CommandDefaultImageFilesInfo()
|
|
{
|
|
SendCommand();
|
|
|
|
rasctl_display.DisplayImageFiles(result.image_files_info());
|
|
}
|
|
|
|
void RasctlCommands::CommandImageFileInfo(const string& filename)
|
|
{
|
|
AddParam(command, "file", filename);
|
|
|
|
SendCommand();
|
|
|
|
rasctl_display.DisplayImageFile(result.image_file_info());
|
|
}
|
|
|
|
void RasctlCommands::CommandNetworkInterfacesInfo()
|
|
{
|
|
SendCommand();
|
|
|
|
rasctl_display.DisplayNetworkInterfaces(result.network_interfaces_info());
|
|
}
|
|
|
|
void RasctlCommands::CommandLogLevelInfo()
|
|
{
|
|
SendCommand();
|
|
|
|
rasctl_display.DisplayLogLevelInfo(result.log_level_info());
|
|
}
|
|
|
|
void RasctlCommands::CommandReservedIdsInfo()
|
|
{
|
|
SendCommand();
|
|
|
|
rasctl_display.DisplayReservedIdsInfo(result.reserved_ids_info());
|
|
}
|
|
|
|
void RasctlCommands::CommandMappingInfo()
|
|
{
|
|
SendCommand();
|
|
|
|
rasctl_display.DisplayMappingInfo(result.mapping_info());
|
|
}
|
|
|
|
void RasctlCommands::CommandOperationInfo()
|
|
{
|
|
SendCommand();
|
|
|
|
rasctl_display.DisplayOperationInfo(result.operation_info());
|
|
}
|