Revert "scsictl: Create files with binary/JSON or text format protobuf data (#1369)"

This reverts commit abc5c4b9ac.
This commit is contained in:
Daniel Markstedt 2023-11-26 13:13:26 +09:00
parent 4d1a10cb6b
commit 28959aaf97
4 changed files with 183 additions and 309 deletions

View File

@ -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 <google/protobuf/util/json_util.h>
#include <google/protobuf/text_format.h>
#include <unistd.h>
#include <clocale>
#include <iostream>
#include <fstream>
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<char *>& 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<char *>& 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<char *>& 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<char *>& args) const
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: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<char *>& 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<char *>& 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;
}

View File

@ -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<char *>&) const;
int ExportAsBinary(const PbCommand&, const string&) const;
int ExportAsJson(const PbCommand&, const string&) const;
int ExportAsText(const PbCommand&, const string&) const;
};

View File

@ -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

View File

@ -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.