mirror of
https://github.com/akuker/RASCSI.git
synced 2026-01-23 12:16:06 +00:00
This will reduce the recurring maintenance overhead of keeping the same information up to date in multiple places Only the most common use cases are covered in the usage help text now
280 lines
6.3 KiB
C++
280 lines
6.3 KiB
C++
//---------------------------------------------------------------------------
|
|
//
|
|
// SCSI Target Emulator PiSCSI
|
|
// for Raspberry Pi
|
|
//
|
|
// Powered by XM6 TypeG Technology.
|
|
// Copyright (C) 2016-2020 GIMONS
|
|
// Copyright (C) 2020-2023 Contributors to the PiSCSI project
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
#include "controllers/controller_manager.h"
|
|
#include "controllers/scsi_controller.h"
|
|
#include "shared/piscsi_util.h"
|
|
#include "shared/protobuf_util.h"
|
|
#include "shared/piscsi_exceptions.h"
|
|
#include "shared/piscsi_version.h"
|
|
#include "scsictl/scsictl_parser.h"
|
|
#include "scsictl/scsictl_commands.h"
|
|
#include "scsictl/scsictl_core.h"
|
|
#include <unistd.h>
|
|
#include <clocale>
|
|
#include <iostream>
|
|
|
|
using namespace std;
|
|
using namespace piscsi_interface;
|
|
using namespace piscsi_util;
|
|
using namespace protobuf_util;
|
|
|
|
void ScsiCtl::Banner(const vector<char *>& args) const
|
|
{
|
|
if (args.size() < 2) {
|
|
cout << piscsi_util::Banner("(Controller App)")
|
|
<< "\nUsage: " << args[0] << " -i ID[:LUN] [-c CMD] [-C FILE] [-t TYPE] ...\n"
|
|
<< " where ID[:LUN] ID := {0-" << (ControllerManager::GetScsiIdMax() - 1) << "},"
|
|
<< " LUN := {0-" << (ControllerManager::GetScsiLunMax() - 1) << "}, default is 0\n"
|
|
<< "Usage: " << args[0] << " -l\n"
|
|
<< " Print device list.\n\n"
|
|
<< "See the scsictl man page for all supported commands, types, and other parameters\n"
|
|
<< flush;
|
|
|
|
exit(EXIT_SUCCESS);
|
|
}
|
|
}
|
|
|
|
int ScsiCtl::run(const vector<char *>& args) const
|
|
{
|
|
GOOGLE_PROTOBUF_VERIFY_VERSION;
|
|
|
|
Banner(args);
|
|
|
|
ScsictlParser parser;
|
|
PbCommand command;
|
|
PbDeviceDefinition* device = command.add_devices();
|
|
device->set_id(-1);
|
|
const char *hostname = "localhost";
|
|
int port = 6868;
|
|
string param;
|
|
string log_level;
|
|
string default_folder;
|
|
string reserved_ids;
|
|
string image_params;
|
|
string filename;
|
|
string token;
|
|
bool list = false;
|
|
|
|
string locale = GetLocale();
|
|
|
|
opterr = 1;
|
|
int opt;
|
|
while ((opt = getopt(static_cast<int>(args.size()), args.data(),
|
|
"e::lmos::vDINOSTVXa:b:c:d:f:h:i:n:p:r:t:x:z:C:E:F:L:P::R:")) != -1) {
|
|
switch (opt) {
|
|
case 'i':
|
|
if (const string error = SetIdAndLun(*device, optarg); !error.empty()) {
|
|
cerr << "Error: " << error << endl;
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
break;
|
|
|
|
case 'C':
|
|
command.set_operation(CREATE_IMAGE);
|
|
image_params = optarg;
|
|
break;
|
|
|
|
case 'b':
|
|
int block_size;
|
|
if (!GetAsUnsignedInt(optarg, block_size)) {
|
|
cerr << "Error: Invalid block size " << optarg << endl;
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
device->set_block_size(block_size);
|
|
break;
|
|
|
|
case 'c':
|
|
command.set_operation(parser.ParseOperation(optarg));
|
|
if (command.operation() == NO_OPERATION) {
|
|
cerr << "Error: Unknown operation '" << optarg << "'" << endl;
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
break;
|
|
|
|
case 'D':
|
|
command.set_operation(DETACH_ALL);
|
|
break;
|
|
|
|
case 'd':
|
|
command.set_operation(DELETE_IMAGE);
|
|
image_params = optarg;
|
|
break;
|
|
|
|
case 'E':
|
|
command.set_operation(IMAGE_FILE_INFO);
|
|
filename = optarg;
|
|
break;
|
|
|
|
case 'e':
|
|
command.set_operation(DEFAULT_IMAGE_FILES_INFO);
|
|
if (optarg) {
|
|
SetCommandParams(command, optarg);
|
|
}
|
|
break;
|
|
|
|
case 'F':
|
|
command.set_operation(DEFAULT_FOLDER);
|
|
default_folder = optarg;
|
|
break;
|
|
|
|
case 'f':
|
|
param = optarg;
|
|
break;
|
|
|
|
case 'h':
|
|
hostname = optarg;
|
|
break;
|
|
|
|
case 'I':
|
|
command.set_operation(RESERVED_IDS_INFO);
|
|
break;
|
|
|
|
case 'L':
|
|
command.set_operation(LOG_LEVEL);
|
|
log_level = optarg;
|
|
break;
|
|
|
|
case 'l':
|
|
list = true;
|
|
break;
|
|
|
|
case 'm':
|
|
command.set_operation(MAPPING_INFO);
|
|
break;
|
|
|
|
case 'N':
|
|
command.set_operation(NETWORK_INTERFACES_INFO);
|
|
break;
|
|
|
|
case 'O':
|
|
command.set_operation(LOG_LEVEL_INFO);
|
|
break;
|
|
|
|
case 'o':
|
|
command.set_operation(OPERATION_INFO);
|
|
break;
|
|
|
|
case 't':
|
|
device->set_type(parser.ParseType(optarg));
|
|
if (device->type() == UNDEFINED) {
|
|
cerr << "Error: Unknown device type '" << optarg << "'" << endl;
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
break;
|
|
|
|
case 'r':
|
|
command.set_operation(RESERVE_IDS);
|
|
reserved_ids = optarg;
|
|
break;
|
|
|
|
case 'R':
|
|
command.set_operation(RENAME_IMAGE);
|
|
image_params = optarg;
|
|
break;
|
|
|
|
case 'n':
|
|
SetProductData(*device, optarg);
|
|
break;
|
|
|
|
case 'p':
|
|
if (!GetAsUnsignedInt(optarg, port) || port <= 0 || port > 65535) {
|
|
cerr << "Error: Invalid port " << optarg << ", port must be between 1 and 65535" << endl;
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
break;
|
|
|
|
case 's':
|
|
command.set_operation(SERVER_INFO);
|
|
if (optarg) {
|
|
if (const string error = SetCommandParams(command, optarg); !error.empty()) {
|
|
cerr << "Error: " << error << endl;
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'S':
|
|
command.set_operation(STATISTICS_INFO);
|
|
break;
|
|
|
|
case 'v':
|
|
cout << "scsictl version: " << piscsi_get_version_string() << '\n';
|
|
exit(EXIT_SUCCESS);
|
|
break;
|
|
|
|
case 'P':
|
|
token = optarg ? optarg : getpass("Password: ");
|
|
break;
|
|
|
|
case 'V':
|
|
command.set_operation(VERSION_INFO);
|
|
break;
|
|
|
|
case 'x':
|
|
command.set_operation(COPY_IMAGE);
|
|
image_params = optarg;
|
|
break;
|
|
|
|
case 'T':
|
|
command.set_operation(DEVICE_TYPES_INFO);
|
|
break;
|
|
|
|
case 'X':
|
|
command.set_operation(SHUT_DOWN);
|
|
SetParam(command, "mode", "rascsi");
|
|
break;
|
|
|
|
case 'z':
|
|
locale = optarg;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// For macos only 'optind != argc' appears to work, but then non-argument options do not reject arguments
|
|
if (optopt) {
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
SetParam(command, "token", token);
|
|
SetParam(command, "locale", locale);
|
|
|
|
ScsictlCommands scsictl_commands(command, hostname, port);
|
|
|
|
bool status;
|
|
try {
|
|
// Listing devices is a special case (legacy rasctl backwards compatibility)
|
|
if (list) {
|
|
command.clear_devices();
|
|
command.set_operation(DEVICES_INFO);
|
|
|
|
status = scsictl_commands.CommandDevicesInfo();
|
|
}
|
|
else {
|
|
ParseParameters(*device, param);
|
|
|
|
status = scsictl_commands.Execute(log_level, default_folder, reserved_ids, image_params, filename);
|
|
}
|
|
}
|
|
catch(const io_exception& e) {
|
|
cerr << "Error: " << e.what() << endl;
|
|
|
|
status = false;
|
|
|
|
// Fall through
|
|
}
|
|
|
|
return status ? EXIT_SUCCESS : EXIT_FAILURE;
|
|
}
|