diff --git a/cpp/scsictl/scsictl_core.cpp b/cpp/scsictl/scsictl_core.cpp index 6cee760b..6f6b8860 100644 --- a/cpp/scsictl/scsictl_core.cpp +++ b/cpp/scsictl/scsictl_core.cpp @@ -1,12 +1,11 @@ //--------------------------------------------------------------------------- // -// SCSI Target Emulator PiSCSI -// for Raspberry Pi +// 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 -// Copyright (C) 2021-2023 Uwe Seimet +// Powered by XM6 TypeG Technology. +// Copyright (C) 2016-2020 GIMONS +// Copyright (C) 2020-2023 Contributors to the PiSCSI project // //--------------------------------------------------------------------------- @@ -19,16 +18,11 @@ #include "scsictl/scsictl_parser.h" #include "scsictl/scsictl_commands.h" #include "scsictl/scsictl_core.h" -#include -#include #include #include #include -#include using namespace std; -using namespace google::protobuf; -using namespace google::protobuf::util; using namespace piscsi_interface; using namespace piscsi_util; using namespace protobuf_util; @@ -39,8 +33,8 @@ void ScsiCtl::Banner(const vector& args) const cout << piscsi_util::Banner("(Controller App)") << "\nUsage: " << args[0] << " -i ID[:LUN] [-c CMD] [-C FILE] [-t TYPE] [-b BLOCK_SIZE] [-n NAME] [-f FILE|PARAM] " << "[-F IMAGE_FOLDER] [-L LOG_LEVEL] [-h HOST] [-p PORT] [-r RESERVED_IDS] " - << "[-C FILENAME:FILESIZE] [-d FILENAME] [-B FILENAME] [-J FILENAME] [-T FILENAME] [-R CURRENT_NAME:NEW_NAME] " - << "[-x CURRENT_NAME:NEW_NAME] [-z LOCALE] " + << "[-C FILENAME:FILESIZE] [-d FILENAME] [-w FILENAME] [-R CURRENT_NAME:NEW_NAME] " + << "[-x CURRENT_NAME:NEW_NAME] [-z LOCALE] " << "[-e] [-E FILENAME] [-D] [-I] [-l] [-m] [o] [-O] [-P] [-s] [-S] [-v] [-V] [-y] [-X]\n" << " where ID[:LUN] ID := {0-" << (ControllerManager::GetScsiIdMax() - 1) << "}," << " LUN := {0-" << (ControllerManager::GetScsiLunMax() - 1) << "}, default is 0\n" @@ -72,7 +66,7 @@ int ScsiCtl::run(const vector& args) const PbCommand command; PbDeviceDefinition* device = command.add_devices(); device->set_id(-1); - string hostname = "localhost"; + const char *hostname = "localhost"; int port = 6868; string param; string log_level; @@ -80,10 +74,7 @@ int ScsiCtl::run(const vector& args) const string reserved_ids; string image_params; string filename; - string filename_json; - string filename_binary; - string filename_text; - string token; + string token; bool list = false; string locale = GetLocale(); @@ -91,228 +82,186 @@ int ScsiCtl::run(const vector& args) const opterr = 1; int opt; while ((opt = getopt(static_cast(args.size()), args.data(), - "e::lmos::vDINOSTVXa:b:c:d:f:h:i:n:p:r:t:x:z:B:C:E:F:J:L:P::R:Z:")) != -1) { - switch (opt) { - case 'i': - if (const string error = SetIdAndLun(*device, optarg); !error.empty()) { - cerr << "Error: " << error << endl; - exit(EXIT_FAILURE); - } - break; + "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 '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 '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 '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(DETACH_ALL); + break; - case 'd': - command.set_operation(DELETE_IMAGE); - image_params = optarg; - break; + case 'd': + command.set_operation(DELETE_IMAGE); + image_params = optarg; + break; - case 'E': - filename = optarg; - if (filename.empty()) { - cerr << "Error: Missing filename" << endl; - exit(EXIT_FAILURE); - } - command.set_operation(IMAGE_FILE_INFO); - 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; - if (hostname.empty()) { - cerr << "Error: Missing hostname" << endl; - exit(EXIT_FAILURE); - } - break; - - case 'B': - filename_binary = optarg; - if (filename_binary.empty()) { - cerr << "Error: Missing filename" << endl; - exit(EXIT_FAILURE); - } - break; - - case 'J': - filename_json = optarg; - if (filename_json.empty()) { - cerr << "Error: Missing filename" << endl; - exit(EXIT_FAILURE); - } - break; - - case 'Z': - filename_text = optarg; - if (filename_text.empty()) { - cerr << "Error: Missing filename" << endl; - exit(EXIT_FAILURE); - } - 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); + case 'e': + command.set_operation(DEFAULT_IMAGE_FILES_INFO); + if (optarg) { + SetCommandParams(command, optarg); } - } - break; + break; - case 'S': - command.set_operation(STATISTICS_INFO); - break; + case 'F': + command.set_operation(DEFAULT_FOLDER); + default_folder = optarg; + break; - case 'v': - cout << "scsictl version: " << piscsi_get_version_string() << '\n'; - exit(EXIT_SUCCESS); - break; + case 'f': + param = optarg; + break; - case 'P': - token = optarg ? optarg : getpass("Password: "); - break; + case 'h': + hostname = optarg; + break; - case 'V': - command.set_operation(VERSION_INFO); - break; + case 'I': + command.set_operation(RESERVED_IDS_INFO); + break; - case 'x': - command.set_operation(COPY_IMAGE); - image_params = optarg; - break; + case 'L': + command.set_operation(LOG_LEVEL); + log_level = optarg; + break; - case 'T': - command.set_operation(DEVICE_TYPES_INFO); - break; + case 'l': + list = true; + break; - case 'X': - command.set_operation(SHUT_DOWN); - SetParam(command, "mode", "rascsi"); - break; + case 'm': + command.set_operation(MAPPING_INFO); + break; - case 'z': - locale = optarg; - break; + case 'N': + command.set_operation(NETWORK_INTERFACES_INFO); + break; - default: - 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); } - if (!filename_json.empty()) { - return ExportAsJson(command, filename_json); - } - if (!filename_binary.empty()) { - return ExportAsBinary(command, filename_binary); - } - if (!filename_text.empty()) { - return ExportAsText(command, filename_text); - } - - SetParam(command, "token", token); - SetParam(command, "locale", locale); + SetParam(command, "token", token); + SetParam(command, "locale", locale); ScsictlCommands scsictl_commands(command, hostname, port); @@ -328,7 +277,7 @@ int ScsiCtl::run(const vector& args) const else { ParseParameters(*device, param); - status = scsictl_commands.Execute(log_level, default_folder, reserved_ids, image_params, filename); + status = scsictl_commands.Execute(log_level, default_folder, reserved_ids, image_params, filename); } } catch(const io_exception& e) { @@ -341,48 +290,3 @@ int ScsiCtl::run(const vector& args) const return status ? EXIT_SUCCESS : EXIT_FAILURE; } - -int ScsiCtl::ExportAsBinary(const PbCommand &command, const string &filename) const -{ - const string binary = command.SerializeAsString(); - - ofstream out; - out.open(filename, ios::binary); - out << binary; - if (out.fail()) { - cerr << "Error: Can't create protobuf binary file '" << filename << "'" << endl; - return EXIT_FAILURE; - } - - return EXIT_SUCCESS; -} - -int ScsiCtl::ExportAsJson(const PbCommand &command, const string &filename) const -{ - string json; - MessageToJsonString(command, &json); - - ofstream out(filename); - out << json; - if (out.fail()) { - cerr << "Error: Can't create protobuf JSON file '" << filename << "'" << endl; - return EXIT_FAILURE; - } - - return EXIT_SUCCESS; -} - -int ScsiCtl::ExportAsText(const PbCommand &command, const string &filename) const -{ - string text; - TextFormat::PrintToString(command, &text); - - ofstream out(filename); - out << text; - if (out.fail()) { - cerr << "Error: Can't create protobuf text format file '" << filename << "'" << endl; - return EXIT_FAILURE; - } - - return EXIT_SUCCESS; -} diff --git a/cpp/scsictl/scsictl_core.h b/cpp/scsictl/scsictl_core.h index 4b8025ec..a96076f4 100644 --- a/cpp/scsictl/scsictl_core.h +++ b/cpp/scsictl/scsictl_core.h @@ -3,7 +3,7 @@ // SCSI Target Emulator PiSCSI // for Raspberry Pi // -// Copyright (C) 2022-2023 Uwe Seimet +// Copyright (C) 2022 Uwe Seimet // //--------------------------------------------------------------------------- @@ -28,8 +28,4 @@ class ScsiCtl private: void Banner(const vector&) const; - - int ExportAsBinary(const PbCommand&, const string&) const; - int ExportAsJson(const PbCommand&, const string&) const; - int ExportAsText(const PbCommand&, const string&) const; }; diff --git a/doc/scsictl.1 b/doc/scsictl.1 index 7737e939..3df74fba 100644 --- a/doc/scsictl.1 +++ b/doc/scsictl.1 @@ -17,10 +17,6 @@ scsictl \- Sends management commands to the piscsi process \fB\-T\fR | \fB\-V\fR | \fB\-X\fR | -\fB\-Z\fR | -[\fB\-d\fR \fIFILENAME\fR] | -[\fB\-B\fR \fIFILENAME\fR] | -[\fB\-J\fR \fIFILENAME\fR] | [\fB\-C\fR \fIFILENAME:FILESIZE\fR] | [\fB\-E\fR \fIFILENAME\fR] | [\fB\-F\fR \fIIMAGE_FOLDER\fR] | @@ -121,15 +117,6 @@ Shut down the piscsi process. .BR \-d\fI " "\fIFILENAME Delete an image file in the default image folder. .TP -.BR \-B\fI " "\fIFILENAME -Do not send command to piscsi but write it to a protobuf binary file. -.TP -.BR \-J\fI " "\fIFILENAME -Do not send command to piscsi but write it to a protobuf JSON file. -.TP -.BR \-Z\fI " "\fIFILENAME -Do not send command to piscsi but write it to a protobuf text format file. -.TP .BR \-x\fI " "\fICURRENT_NAME:NEW_NAME Copy an image file in the default image folder. .TP diff --git a/doc/scsictl_man_page.txt b/doc/scsictl_man_page.txt index 7dfc6e10..f98b7208 100644 --- a/doc/scsictl_man_page.txt +++ b/doc/scsictl_man_page.txt @@ -7,23 +7,22 @@ NAME SYNOPSIS scsictl -e | -l | -m | -o | -v | -D | -I | -L | -O | -P | -S | -T | -V - | -X | -Z | [-d FILENAME] | [-B FILENAME] | [-J FILENAME] | [-C FILE‐ - NAME:FILESIZE] | [-E FILENAME] | [-F IMAGE_FOLDER] | [-R CUR‐ - RENT_NAME:NEW_NAME] | [-c CMD] | [-f FILE|PARAM] | [-g LOG_LEVEL] | [-h - HOST] | [-i ID[:LUN]] | [-n NAME] | [-p PORT] | [-r RESERVED_IDS] | [-s - [FOLDER_PATTERN:FILE_PATTERN:OPERATIONS]] | [-t TYPE] | [-x CUR‐ + | -X | [-C FILENAME:FILESIZE] | [-E FILENAME] | [-F IMAGE_FOLDER] | [-R + CURRENT_NAME:NEW_NAME] | [-c CMD] | [-f FILE|PARAM] | [-g LOG_LEVEL] | + [-h HOST] | [-i ID[:LUN]] | [-n NAME] | [-p PORT] | [-r RESERVED_IDS] | + [-s [FOLDER_PATTERN:FILE_PATTERN:OPERATIONS]] | [-t TYPE] | [-x CUR‐ RENT_NAME:NEW_NAME] | [-z LOCALE] DESCRIPTION - scsictl sends commands to the piscsi process to make configuration ad‐ + scsictl sends commands to the piscsi process to make configuration ad‐ justments at runtime or to check the status of the devices. Either the -i or -l option should be specified at one time. Not both. - You do NOT need root privileges to use scsictl. scsictl also runs on + You do NOT need root privileges to use scsictl. scsictl also runs on non-Pi Linux platforms. - Note: The command and type arguments are case insensitive. Only the + Note: The command and type arguments are case insensitive. Only the first letter of the command/type is evaluated by the tool. OPTIONS @@ -42,7 +41,7 @@ OPTIONS -I Gets the list of reserved device IDs. -L LOG_LEVEL - Set the piscsi log level (trace, debug, info, warning, error, + Set the piscsi log level (trace, debug, info, warning, error, off). -h HOST @@ -50,19 +49,19 @@ OPTIONS -e List all images files in the default image folder. - -N Lists all available network interfaces provided that they are + -N Lists all available network interfaces provided that they are up. - -O Display the available piscsi server log levels and the current + -O Display the available piscsi server log levels and the current log level. - -P Prompt for the access token in case piscsi requires authentica‐ + -P Prompt for the access token in case piscsi requires authentica‐ tion. - -l List all of the devices that are currently being emulated by + -l List all of the devices that are currently being emulated by PiSCSI, as well as their current status. - -m List all file extensions recognized by PiSCSI and the device + -m List all file extensions recognized by PiSCSI and the device types they map to. -o Display operation meta data information. @@ -74,11 +73,11 @@ OPTIONS The piscsi port to connect to, default is 6868. -r RESERVED_IDS - Comma-separated list of IDs to reserve. Pass an empty list in + Comma-separated list of IDs to reserve. Pass an empty list in order to not reserve anything. -s [FOLDER_PATTERN:FILE_PATTERN:OPERATIONS] - Display server-side settings like available images or supported + Display server-side settings like available images or supported device types. -S Display statistics. @@ -94,18 +93,6 @@ OPTIONS -d FILENAME Delete an image file in the default image folder. - -B FILENAME - Do not send command to piscsi but write it to a protobuf binary - file. - - -J FILENAME - Do not send command to piscsi but write it to a protobuf JSON - file. - - -Z FILENAME - Do not send command to piscsi but write it to a protobuf text - format file. - -x CURRENT_NAME:NEW_NAME Copy an image file in the default image folder.