2018-05-03 13:47:57 +00:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// SCSI Target Emulator RaSCSI (*^..^*)
|
|
|
|
// for Raspberry Pi
|
|
|
|
//
|
|
|
|
// Powered by XM6 TypeG Technology.
|
2020-07-04 14:57:44 +00:00
|
|
|
// Copyright (C) 2016-2020 GIMONS
|
2020-07-05 16:47:17 +00:00
|
|
|
// [ Send Control Command ]
|
2018-05-03 13:47:57 +00:00
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2021-07-19 23:41:00 +00:00
|
|
|
#include <netdb.h>
|
2021-07-24 00:13:05 +00:00
|
|
|
#include "google/protobuf/message_lite.h"
|
2018-05-03 13:47:57 +00:00
|
|
|
#include "os.h"
|
2021-01-25 16:07:30 +00:00
|
|
|
#include "rascsi_version.h"
|
2021-07-18 22:15:13 +00:00
|
|
|
#include "exceptions.h"
|
|
|
|
#include "rasutil.h"
|
2021-07-22 12:47:08 +00:00
|
|
|
#include "rascsi_interface.pb.h"
|
|
|
|
#include <sstream>
|
|
|
|
#include <iostream>
|
2021-08-06 01:56:07 +00:00
|
|
|
#include <list>
|
2021-07-18 22:15:13 +00:00
|
|
|
|
|
|
|
using namespace std;
|
2021-07-22 12:47:08 +00:00
|
|
|
using namespace rascsi_interface;
|
2018-05-03 13:47:57 +00:00
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
2020-07-05 16:47:17 +00:00
|
|
|
// Send Command
|
2018-05-03 13:47:57 +00:00
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
2021-07-27 14:47:22 +00:00
|
|
|
int SendCommand(const string& hostname, int port, const PbCommand& command)
|
2018-05-03 13:47:57 +00:00
|
|
|
{
|
2021-07-24 00:30:56 +00:00
|
|
|
int fd = -1;
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2021-07-24 00:13:05 +00:00
|
|
|
try {
|
|
|
|
struct hostent *host = gethostbyname(hostname.c_str());
|
|
|
|
if (!host) {
|
|
|
|
throw ioexception("Can't resolve hostname '" + hostname + "'");
|
|
|
|
}
|
2021-07-18 22:15:13 +00:00
|
|
|
|
2021-07-24 00:13:05 +00:00
|
|
|
fd = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
if (fd < 0) {
|
|
|
|
throw ioexception("Can't create socket");
|
|
|
|
}
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2021-07-24 00:13:05 +00:00
|
|
|
struct sockaddr_in server;
|
|
|
|
memset(&server, 0, sizeof(server));
|
|
|
|
server.sin_family = AF_INET;
|
2021-07-27 14:47:22 +00:00
|
|
|
server.sin_port = htons(port);
|
2021-07-24 00:13:05 +00:00
|
|
|
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) {
|
2021-08-08 15:08:58 +00:00
|
|
|
ostringstream error;
|
|
|
|
error << "Can't connect to rascsi process on host '" << hostname << "', port " << port;
|
|
|
|
throw ioexception(error.str());
|
2021-07-24 00:13:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SerializeMessage(fd, command);
|
2021-07-22 12:47:08 +00:00
|
|
|
}
|
|
|
|
catch(const ioexception& e) {
|
2021-07-24 00:13:05 +00:00
|
|
|
cerr << "Error: " << e.getmsg() << endl;
|
2021-07-22 12:47:08 +00:00
|
|
|
|
2021-07-24 00:13:05 +00:00
|
|
|
if (fd >= 0) {
|
|
|
|
close(fd);
|
|
|
|
}
|
2021-07-19 23:41:00 +00:00
|
|
|
|
2021-08-08 15:08:58 +00:00
|
|
|
exit(fd < 0 ? ENOTCONN : -1);
|
2021-07-22 12:47:08 +00:00
|
|
|
}
|
|
|
|
|
2021-07-24 00:13:05 +00:00
|
|
|
return fd;
|
2021-07-22 12:47:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Receive command result
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
2021-08-08 15:08:58 +00:00
|
|
|
bool ReceiveResult(int fd)
|
|
|
|
{
|
2021-07-22 12:47:08 +00:00
|
|
|
try {
|
2021-07-24 00:13:05 +00:00
|
|
|
PbResult result;
|
|
|
|
DeserializeMessage(fd, result);
|
2021-08-08 15:08:58 +00:00
|
|
|
close(fd);
|
2021-07-18 22:15:13 +00:00
|
|
|
|
2021-08-08 15:08:58 +00:00
|
|
|
if (!result.status()) {
|
|
|
|
throw ioexception(result.msg());
|
2021-07-18 22:15:13 +00:00
|
|
|
}
|
2021-08-08 15:08:58 +00:00
|
|
|
|
|
|
|
cout << result.msg() << endl;
|
2021-07-18 22:15:13 +00:00
|
|
|
}
|
|
|
|
catch(const ioexception& e) {
|
2021-07-22 12:47:08 +00:00
|
|
|
cerr << "Error: " << e.getmsg() << endl;
|
2021-07-18 22:15:13 +00:00
|
|
|
|
2021-08-08 15:08:58 +00:00
|
|
|
return false;
|
2021-07-18 22:15:13 +00:00
|
|
|
}
|
2018-05-03 13:47:57 +00:00
|
|
|
|
2021-08-08 15:08:58 +00:00
|
|
|
return true;
|
2021-07-22 12:47:08 +00:00
|
|
|
}
|
|
|
|
|
2021-07-24 00:13:05 +00:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Command implementations
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
2021-07-27 14:47:22 +00:00
|
|
|
void CommandList(const string& hostname, int port)
|
2021-07-24 00:13:05 +00:00
|
|
|
{
|
|
|
|
PbCommand command;
|
|
|
|
command.set_cmd(LIST);
|
2021-07-22 12:47:08 +00:00
|
|
|
|
2021-07-27 14:47:22 +00:00
|
|
|
int fd = SendCommand(hostname.c_str(), port, command);
|
2021-07-24 00:13:05 +00:00
|
|
|
|
|
|
|
PbDevices devices;
|
|
|
|
try {
|
|
|
|
DeserializeMessage(fd, devices);
|
2021-07-22 12:47:08 +00:00
|
|
|
}
|
2021-07-24 00:13:05 +00:00
|
|
|
catch(const ioexception& e) {
|
|
|
|
cerr << "Error: " << e.getmsg() << endl;
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
exit(-1);
|
2021-07-22 12:47:08 +00:00
|
|
|
}
|
|
|
|
|
2021-07-24 00:13:05 +00:00
|
|
|
close (fd);
|
2021-07-22 12:47:08 +00:00
|
|
|
|
2021-07-24 00:13:05 +00:00
|
|
|
cout << ListDevices(devices) << endl;
|
|
|
|
}
|
|
|
|
|
2021-07-27 14:47:22 +00:00
|
|
|
void CommandLogLevel(const string& hostname, int port, const string& log_level)
|
2021-07-24 00:13:05 +00:00
|
|
|
{
|
|
|
|
PbCommand command;
|
|
|
|
command.set_cmd(LOG_LEVEL);
|
|
|
|
command.set_params(log_level);
|
|
|
|
|
2021-07-27 14:47:22 +00:00
|
|
|
int fd = SendCommand(hostname.c_str(), port, command);
|
2021-07-24 00:13:05 +00:00
|
|
|
ReceiveResult(fd);
|
|
|
|
close(fd);
|
2018-05-03 13:47:57 +00:00
|
|
|
}
|
|
|
|
|
2021-08-06 01:56:07 +00:00
|
|
|
void CommandServerInfo(const string& hostname, int port)
|
|
|
|
{
|
|
|
|
PbCommand command;
|
|
|
|
command.set_cmd(SERVER_INFO);
|
|
|
|
|
|
|
|
int fd = SendCommand(hostname.c_str(), port, command);
|
|
|
|
|
|
|
|
PbServerInfo serverInfo;
|
|
|
|
try {
|
|
|
|
DeserializeMessage(fd, serverInfo);
|
|
|
|
}
|
|
|
|
catch(const ioexception& e) {
|
|
|
|
cerr << "Error: " << e.getmsg() << endl;
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
|
2021-08-08 15:08:58 +00:00
|
|
|
cout << "rascsi server version: " << serverInfo.rascsi_version() << endl;
|
2021-08-06 01:56:07 +00:00
|
|
|
|
|
|
|
if (!serverInfo.available_log_levels_size()) {
|
|
|
|
cout << " No log level settings available" << endl;
|
|
|
|
}
|
|
|
|
else {
|
2021-08-08 15:08:58 +00:00
|
|
|
cout << "Available rascsi log levels, sorted by severity:" << endl;
|
2021-08-06 01:56:07 +00:00
|
|
|
for (int i = 0; i < serverInfo.available_log_levels_size(); i++) {
|
|
|
|
cout << " " << serverInfo.available_log_levels(i) << endl;
|
|
|
|
}
|
|
|
|
|
2021-08-08 15:08:58 +00:00
|
|
|
cout << "Current rascsi log level: " << serverInfo.current_log_level() << endl;
|
2021-08-06 01:56:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cout << "Default image file folder: " << serverInfo.default_image_folder() << endl;
|
|
|
|
if (!serverInfo.available_image_files_size()) {
|
|
|
|
cout << " No image files available in the default folder" << endl;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
list<string> sorted_image_files;
|
|
|
|
for (int i = 0; i < serverInfo.available_image_files_size(); i++) {
|
|
|
|
sorted_image_files.push_back(serverInfo.available_image_files(i));
|
|
|
|
}
|
|
|
|
sorted_image_files.sort();
|
|
|
|
|
|
|
|
cout << "Image files available in the default folder:" << endl;
|
|
|
|
for (auto it = sorted_image_files.begin(); it != sorted_image_files.end(); ++it) {
|
|
|
|
cout << " " << *it << endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-03 13:47:57 +00:00
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
2020-07-05 16:47:17 +00:00
|
|
|
// Main processing
|
2018-05-03 13:47:57 +00:00
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
int main(int argc, char* argv[])
|
|
|
|
{
|
2021-07-19 23:41:00 +00:00
|
|
|
GOOGLE_PROTOBUF_VERIFY_VERSION;
|
|
|
|
|
2020-07-05 16:47:17 +00:00
|
|
|
// Display help
|
2018-05-03 13:47:57 +00:00
|
|
|
if (argc < 2) {
|
2021-07-18 22:15:13 +00:00
|
|
|
cerr << "SCSI Target Emulator RaSCSI Controller" << endl;
|
|
|
|
cerr << "version " << rascsi_get_version_string() << " (" << __DATE__ << ", " << __TIME__ << ")" << endl;
|
2021-08-07 00:30:35 +00:00
|
|
|
cerr << "Usage: " << argv[0] << " -i ID [-u UNIT] [-c CMD] [-t TYPE] [-f FILE] [-g LOG_LEVEL] [-h HOST] [-p PORT] [-v]" << endl;
|
2021-07-18 22:15:13 +00:00
|
|
|
cerr << " where ID := {0|1|2|3|4|5|6|7}" << endl;
|
|
|
|
cerr << " UNIT := {0|1} default setting is 0." << endl;
|
2021-08-08 15:08:58 +00:00
|
|
|
cerr << " CMD := {attach|detach|insert|eject|protect|unprotect}" << endl;
|
2021-07-18 22:15:13 +00:00
|
|
|
cerr << " TYPE := {hd|mo|cd|bridge|daynaport}" << endl;
|
|
|
|
cerr << " FILE := image file path" << endl;
|
2021-08-07 00:30:35 +00:00
|
|
|
cerr << " HOST := rascsi host to connect to, default is 'localhost'" << endl;
|
2021-07-27 14:47:22 +00:00
|
|
|
cerr << " PORT := rascsi port to connect to, default is 6868" << endl;
|
2021-07-19 23:41:00 +00:00
|
|
|
cerr << " LOG_LEVEL := log level {trace|debug|info|warn|err|critical|off}, default is 'trace'" << endl;
|
2021-07-18 22:15:13 +00:00
|
|
|
cerr << " If CMD is 'attach' or 'insert' the FILE parameter is required." << endl;
|
|
|
|
cerr << "Usage: " << argv[0] << " -l" << endl;
|
|
|
|
cerr << " Print device list." << endl;
|
|
|
|
|
2018-05-03 13:47:57 +00:00
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
2020-07-05 16:47:17 +00:00
|
|
|
// Parse the arguments
|
2021-07-18 22:15:13 +00:00
|
|
|
int opt;
|
|
|
|
int id = -1;
|
|
|
|
int un = 0;
|
2021-07-24 00:13:05 +00:00
|
|
|
PbOperation cmd = LIST;
|
|
|
|
PbDeviceType type = UNDEFINED;
|
2021-07-19 23:41:00 +00:00
|
|
|
const char *hostname = "localhost";
|
2021-07-27 14:47:22 +00:00
|
|
|
int port = 6868;
|
2021-07-18 22:15:13 +00:00
|
|
|
string params;
|
2018-05-03 13:47:57 +00:00
|
|
|
opterr = 0;
|
2021-08-08 15:08:58 +00:00
|
|
|
while ((opt = getopt(argc, argv, "i:u:c:t:f:h:p:u:g:lsv")) != -1) {
|
2018-05-03 13:47:57 +00:00
|
|
|
switch (opt) {
|
|
|
|
case 'i':
|
|
|
|
id = optarg[0] - '0';
|
|
|
|
break;
|
|
|
|
|
2020-07-04 14:57:44 +00:00
|
|
|
case 'u':
|
|
|
|
un = optarg[0] - '0';
|
|
|
|
break;
|
|
|
|
|
2018-05-03 13:47:57 +00:00
|
|
|
case 'c':
|
2021-07-18 22:15:13 +00:00
|
|
|
switch (tolower(optarg[0])) {
|
|
|
|
case 'a':
|
|
|
|
cmd = ATTACH;
|
2018-05-03 13:47:57 +00:00
|
|
|
break;
|
2021-07-18 22:15:13 +00:00
|
|
|
|
|
|
|
case 'd':
|
|
|
|
cmd = DETACH;
|
2018-05-03 13:47:57 +00:00
|
|
|
break;
|
2021-07-18 22:15:13 +00:00
|
|
|
|
|
|
|
case 'i':
|
|
|
|
cmd = INSERT;
|
2018-05-03 13:47:57 +00:00
|
|
|
break;
|
2021-07-18 22:15:13 +00:00
|
|
|
|
|
|
|
case 'e':
|
|
|
|
cmd = EJECT;
|
2018-05-03 13:47:57 +00:00
|
|
|
break;
|
2021-07-18 22:15:13 +00:00
|
|
|
|
|
|
|
case 'p':
|
|
|
|
cmd = PROTECT;
|
2018-05-03 13:47:57 +00:00
|
|
|
break;
|
2021-08-08 15:08:58 +00:00
|
|
|
|
|
|
|
case 'u':
|
|
|
|
cmd = UNPROTECT;
|
|
|
|
break;
|
2018-05-03 13:47:57 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 't':
|
2021-07-18 22:15:13 +00:00
|
|
|
switch (tolower(optarg[0])) {
|
|
|
|
case 's':
|
|
|
|
type = SASI_HD;
|
2018-05-03 13:47:57 +00:00
|
|
|
break;
|
2021-07-18 22:15:13 +00:00
|
|
|
|
|
|
|
case 'h':
|
|
|
|
type = SCSI_HD;
|
2018-05-03 13:47:57 +00:00
|
|
|
break;
|
2021-07-18 22:15:13 +00:00
|
|
|
|
|
|
|
case 'm':
|
|
|
|
type = MO;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'c':
|
|
|
|
type = CD;
|
2018-05-03 13:47:57 +00:00
|
|
|
break;
|
2021-07-18 22:15:13 +00:00
|
|
|
|
|
|
|
case 'b':
|
|
|
|
type = BR;
|
2021-02-07 19:00:48 +00:00
|
|
|
break;
|
2021-07-18 22:15:13 +00:00
|
|
|
|
|
|
|
// case 'n':
|
|
|
|
// type = NUVOLINK;
|
2021-02-07 19:00:48 +00:00
|
|
|
// break;
|
2021-07-18 22:15:13 +00:00
|
|
|
|
|
|
|
case 'd':
|
|
|
|
type = DAYNAPORT;
|
2018-05-03 13:47:57 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'f':
|
2021-07-18 22:15:13 +00:00
|
|
|
params = optarg;
|
2018-05-03 13:47:57 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'l':
|
2021-07-18 22:15:13 +00:00
|
|
|
cmd = LIST;
|
|
|
|
break;
|
|
|
|
|
2021-07-19 23:41:00 +00:00
|
|
|
case 'h':
|
|
|
|
hostname = optarg;
|
|
|
|
break;
|
|
|
|
|
2021-07-27 14:47:22 +00:00
|
|
|
case 'p':
|
|
|
|
port = atoi(optarg);
|
|
|
|
if (port <= 0 || port > 65535) {
|
|
|
|
cerr << "Invalid port " << optarg << ", port must be between 1 and 65535" << endl;
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2021-07-22 12:47:08 +00:00
|
|
|
case 'g':
|
2021-07-18 22:15:13 +00:00
|
|
|
cmd = LOG_LEVEL;
|
|
|
|
params = optarg;
|
2018-05-03 13:47:57 +00:00
|
|
|
break;
|
2021-08-06 01:56:07 +00:00
|
|
|
|
|
|
|
case 's':
|
|
|
|
cmd = SERVER_INFO;
|
|
|
|
break;
|
2021-08-07 00:30:35 +00:00
|
|
|
|
|
|
|
case 'v':
|
|
|
|
cout << rascsi_get_version_string() << endl;
|
|
|
|
exit(0);
|
|
|
|
break;
|
2018-05-03 13:47:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-18 22:15:13 +00:00
|
|
|
if (cmd == LOG_LEVEL) {
|
2021-07-27 14:47:22 +00:00
|
|
|
CommandLogLevel(hostname, port, params);
|
2021-07-18 22:15:13 +00:00
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
2021-08-06 01:56:07 +00:00
|
|
|
if (cmd == SERVER_INFO) {
|
|
|
|
CommandServerInfo(hostname, port);
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
2020-07-05 16:47:17 +00:00
|
|
|
// List display only
|
2021-07-18 22:15:13 +00:00
|
|
|
if (cmd == LIST || (id < 0 && type == UNDEFINED && params.empty())) {
|
2021-07-27 14:47:22 +00:00
|
|
|
CommandList(hostname, port);
|
2018-05-03 13:47:57 +00:00
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
2020-07-05 16:47:17 +00:00
|
|
|
// Generate the command and send it
|
2021-08-08 15:08:58 +00:00
|
|
|
PbCommand command;
|
2021-07-18 22:15:13 +00:00
|
|
|
command.set_id(id);
|
|
|
|
command.set_un(un);
|
|
|
|
command.set_cmd(cmd);
|
|
|
|
command.set_type(type);
|
|
|
|
if (!params.empty()) {
|
|
|
|
command.set_params(params);
|
2018-05-03 13:47:57 +00:00
|
|
|
}
|
2021-07-22 12:47:08 +00:00
|
|
|
|
2021-07-27 14:47:22 +00:00
|
|
|
int fd = SendCommand(hostname, port, command);
|
2021-07-22 12:47:08 +00:00
|
|
|
bool status = ReceiveResult(fd);
|
|
|
|
close(fd);
|
|
|
|
|
2020-07-05 16:47:17 +00:00
|
|
|
// All done!
|
2021-07-22 12:47:08 +00:00
|
|
|
exit(status ? 0 : -1);
|
2018-05-03 13:47:57 +00:00
|
|
|
}
|