Added Devices message to protobuf interface (#141)

* Removed all BAREMETAL ifdefs

* Cleaned up subfolders

* Fixed regression

* Re-added underscores

* Fixed merge conflicts

* Assume RASCSI is always defined

* Fixed mege issue

* Re-added result message

* Added Devices message to protobuf interface

* Fixed typo

* Fixed include file names

* Updated files to be ignored by git

* Merge with develop branch

* Synchronized output with develop branch

* Fixed missing dependency, causing issues when running "make -j1"

* Fixed handling of connection errors

* Improved protobuf interface upwards compatibility

* Use -g instead of -s, this has less conflict potential with future options

* Made log level options consistent (rascsi and rasctl used a different option)
This commit is contained in:
Uwe Seimet 2021-07-22 14:47:08 +02:00 committed by GitHub
parent 3c5a0003a4
commit 62e7727a48
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 249 additions and 132 deletions

View File

@ -12,3 +12,8 @@ sasidump
rasdump
obj
bin
/rascsi_interface.pb.cpp
/rascsi_interface.pb.h
.project
.cproject
.settings

View File

@ -74,10 +74,10 @@ BINDIR := ./bin/$(shell echo $(CONNECT_TYPE) | tr '[:upper:]' '[:lower:]')
BIN_ALL = $(BINDIR)/$(RASCSI) $(BINDIR)/$(RASCTL) $(BINDIR)/$(SCSIMON)
SRC_PROTOC = \
rasctl_interface.proto
rascsi_interface.proto
SRC_PROTOBUF = \
rasctl_interface.pb.cpp
rascsi_interface.pb.cpp
SRC_RASCSI = \
rascsi.cpp \
@ -138,7 +138,7 @@ OBJ_RASDUMP := $(addprefix $(OBJDIR)/,$(notdir $(SRC_RASDUMP:%.cpp=%.o)))
OBJ_SASIDUMP := $(addprefix $(OBJDIR)/,$(notdir $(SRC_SASIDUMP:%.cpp=%.o)))
OBJ_SCSIMON := $(addprefix $(OBJDIR)/,$(notdir $(SRC_SCSIMON:%.cpp=%.o)))
GEN_PROTOBUF := $(SRC_PROTOBUF) rasctl_interface.pb.h
GEN_PROTOBUF := $(SRC_PROTOBUF) rascsi_interface.pb.h
# The following will include all of the auto-generated dependency files (*.d)
@ -156,7 +156,7 @@ $(OBJDIR)/%.o: %.cpp | $(OBJDIR)
$(SRC_PROTOBUF): $(SRC_PROTOC)
echo "-- Generating protobuf-based source files"
protoc --cpp_out=. $(SRC_PROTOC)
mv rasctl_interface.pb.cc $@
mv rascsi_interface.pb.cc $@
## Build Targets:
## all : Rebuild all of the executable files and re-generate
@ -169,10 +169,10 @@ ALL: all
docs: $(DOC_DIR)/rascsi_man_page.txt $(DOC_DIR)/rasctl_man_page.txt $(DOC_DIR)/scsimon_man_page.txt
$(BINDIR)/$(RASCSI): $(OBJ_RASCSI) | $(BINDIR)
$(BINDIR)/$(RASCSI): $(SRC_PROTOBUF) $(OBJ_RASCSI) | $(BINDIR)
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCSI) -lpthread -lz -lpcap -lprotobuf-lite
$(BINDIR)/$(RASCTL): $(OBJ_RASCTL) | $(BINDIR)
$(BINDIR)/$(RASCTL): $(SRC_PROTOBUF) $(OBJ_RASCTL) | $(BINDIR)
$(CXX) $(CXXFLAGS) -o $@ $(OBJ_RASCTL) -lprotobuf-lite
$(BINDIR)/$(RASDUMP): $(OBJ_RASDUMP) | $(BINDIR)

View File

@ -28,7 +28,7 @@
#include "exceptions.h"
#include "rascsi_version.h"
#include "rasutil.h"
#include "rasctl_interface.pb.h"
#include "rascsi_interface.pb.h"
#include "spdlog/spdlog.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include <spdlog/async.h>
@ -38,7 +38,7 @@
using namespace std;
using namespace spdlog;
using namespace rasctl_interface;
using namespace rascsi_interface;
//---------------------------------------------------------------------------
//
@ -250,75 +250,88 @@ void Reset()
//---------------------------------------------------------------------------
//
// List Devices
// Get the list of attached devices
//
//---------------------------------------------------------------------------
string ListDevice() {
char type[5];
char dev_status[_MAX_FNAME+26];
ostringstream s;
bool has_header = false;
type[4] = 0;
Devices GetDevices() {
Devices devices;
for (int i = 0; i < CtrlMax * UnitNum; i++) {
strncpy(dev_status,"",sizeof(dev_status));
// Initialize ID and unit number
int id = i / UnitNum;
int un = i % UnitNum;
Disk *pUnit = disk[i];
// skip if unit does not exist or null disk
if (pUnit == NULL || pUnit->IsNULL()) {
Disk *pUnit = disk[i];
if (!pUnit || pUnit->IsNULL()) {
continue;
}
// Output the header
if (!has_header) {
s << endl
<< "+----+----+------+-------------------------------------" << endl
<< "| ID | UN | TYPE | DEVICE STATUS" << endl
<< "+----+----+------+-------------------------------------" << endl;
LOGINFO( "+----+----+------+-------------------------------------");
LOGINFO( "| ID | UN | TYPE | DEVICE STATUS");
LOGINFO( "+----+----+------+-------------------------------------\n");
has_header = true;
}
Device *device = devices.add_devices();
// Initialize ID and unit number
device->set_id(i / UnitNum);
device->set_un(i % UnitNum);
// ID,UNIT,Type,Device Status
char type[5];
type[0] = (char)(pUnit->GetID() >> 24);
type[1] = (char)(pUnit->GetID() >> 16);
type[2] = (char)(pUnit->GetID() >> 8);
type[3] = (char)(pUnit->GetID());
type[4] = 0;
device->set_type(type);
// mount status output
if (pUnit->GetID() == MAKEID('S', 'C', 'B', 'R')) {
strncpy(dev_status,"X68000 HOST BRIDGE",sizeof(dev_status));
device->set_file("X68000 HOST BRIDGE");
} else if (pUnit->GetID() == MAKEID('S', 'C', 'D', 'P')) {
strncpy(dev_status,"DaynaPort SCSI/Link",sizeof(dev_status));
device->set_file("DaynaPort SCSI/Link");
} else {
Filepath filepath;
pUnit->GetPath(filepath);
snprintf(dev_status, sizeof(dev_status), "%s",
(pUnit->IsRemovable() && !pUnit->IsReady()) ?
"NO MEDIA" : filepath.GetPath());
device->set_file(pUnit->IsRemovable() && !pUnit->IsReady() ? "NO MEDIA" : filepath.GetPath());
}
// Write protection status
if (pUnit->IsRemovable() && pUnit->IsReady() && pUnit->IsWriteP()) {
strcat(dev_status, " (WRITEPROTECT)");
device->set_read_only(true);
}
s << "| " << id << " | " << un << " | " << type << " | " << dev_status << endl;
LOGINFO( "| %d | %d | %s | %s", id, un, type, dev_status);
}
// If there is no controller, find will be null
if (!has_header) {
return devices;
}
//---------------------------------------------------------------------------
//
// List and log devices
//
//---------------------------------------------------------------------------
string ListDevices(Devices devices) {
ostringstream s;
if (devices.devices_size()) {
s << endl
<< "+----+----+------+-------------------------------------" << endl
<< "| ID | UN | TYPE | DEVICE STATUS" << endl
<< "+----+----+------+-------------------------------------" << endl;
LOGINFO( "+----+----+------+-------------------------------------");
LOGINFO( "| ID | UN | TYPE | DEVICE STATUS");
LOGINFO( "+----+----+------+-------------------------------------\n");
}
else {
return "No images currently attached.\n";
}
for (int i = 0; i < devices.devices_size() ; i++) {
Device device = devices.devices(i);
s << "| " << device.id() << " | " << device.un() << " | " << device.type() << " | "
<< device.file() << (device.read_only() ? " (WRITEPROTECT)" : "") << endl;
LOGINFO( "| %d | %d | %s | %s%s", device.id(), device.un(), device.type().c_str(),
device.file().c_str(), device.read_only() ? " (WRITEPROTECT)" : "");
}
s << "+----+----+------+-------------------------------------" << endl;
LOGINFO( "+----+----+------+-------------------------------------");
return s.str();
@ -574,9 +587,9 @@ bool ProcessCmd(int fd, const Command &command)
pUnit = new SCSIDaynaPort();
break;
default:
ostringstream msg;
msg << "rasctl sent a command for an invalid drive type: " << type;
return ReturnStatus(fd, false, msg.str());
ostringstream error;
error << "rasctl sent a command for an invalid drive type: " << type;
return ReturnStatus(fd, false, error.str());
}
// drive checks files
@ -593,9 +606,9 @@ bool ProcessCmd(int fd, const Command &command)
LOGWARN("rasctl tried to open an invalid file %s", file.c_str());
ostringstream msg;
msg << "Error : File open error [" << file << "]";
return ReturnStatus(fd, false, msg.str());
ostringstream error;
error << "File open error [" << file << "]";
return ReturnStatus(fd, false, error.str());
}
}
@ -658,9 +671,9 @@ bool ProcessCmd(int fd, const Command &command)
pUnit->GetID() != MAKEID('S', 'C', 'C', 'D')) {
LOGWARN("rasctl sent an Insert/Eject/Protect command (%d) for incompatible type %s", cmd, type_str);
ostringstream msg;
msg << "Error : Operation denied (Device type " << type_str << " isn't removable)";
return ReturnStatus(fd, false, msg.str());
ostringstream error;
error << "Operation denied (Device type " << type_str << " isn't removable)";
return ReturnStatus(fd, false, error.str());
}
switch (cmd) {
@ -669,10 +682,10 @@ bool ProcessCmd(int fd, const Command &command)
LOGINFO("rasctl commanded insert file %s into %s ID: %d UN: %d", params.c_str(), type_str, id, un);
if (!pUnit->Open(filepath)) {
ostringstream msg;
msg << "Error : File open error [" << params << "]";
ostringstream error;
error << "File open error [" << params << "]";
return ReturnStatus(fd, false, msg.str());
return ReturnStatus(fd, false, error.str());
}
break;
@ -692,10 +705,10 @@ bool ProcessCmd(int fd, const Command &command)
break;
default:
ostringstream msg;
msg << "Received unknown command from rasctl: " << cmd;
LOGWARN("%s", msg.str().c_str());
return ReturnStatus(fd, false, msg.str());
ostringstream error;
error << "Received unknown command from rasctl: " << cmd;
LOGWARN("%s", error.str().c_str());
return ReturnStatus(fd, false, error.str());
}
return ReturnStatus(fd, true);
@ -718,7 +731,7 @@ bool ParseArgument(int argc, char* argv[])
string log_level = "trace";
int opt;
while ((opt = getopt(argc, argv, "-IiHhL:l:D:d:")) != -1) {
while ((opt = getopt(argc, argv, "-IiHhG:g:D:d:")) != -1) {
switch (tolower(opt)) {
case 'i':
is_sasi = false;
@ -732,7 +745,7 @@ bool ParseArgument(int argc, char* argv[])
id = -1;
continue;
case 'l':
case 'g':
log_level = optarg;
continue;
@ -801,7 +814,9 @@ bool ParseArgument(int argc, char* argv[])
SetLogLevel(log_level);
// Display the device list
fprintf(stdout, "%s", ListDevice().c_str());
Devices devices = GetDevices();
cout << ListDevices(devices) << endl;
return true;
}
@ -868,12 +883,11 @@ static void *MonThread(void *param)
// List all of the devices
if (command.cmd() == LIST) {
Result result;
result.set_msg(ListDevice() + "\n");
result.set_status(true);
Devices devices = GetDevices();
ListDevices(devices);
string data;
result.SerializeToString(&data);
devices.SerializeToString(&data);
SerializeProtobufData(fd, data);
}
else if (command.cmd() == LOG_LEVEL) {
@ -912,6 +926,8 @@ static void *MonThread(void *param)
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
GOOGLE_PROTOBUF_VERIFY_VERSION;
int i;
int actid;
DWORD now;

View File

@ -0,0 +1,57 @@
syntax = "proto3";
option optimize_for = LITE_RUNTIME;
package rascsi_interface;
// The supported device types
enum DeviceType {
UNDEFINED = 0;
SASI_HD = 1;
SCSI_HD = 2;
MO = 3;
CD = 4;
BR = 5;
NUVOLINK = 6;
DAYNAPORT = 7;
}
// rascsi remote operations
enum Operation {
NONE = 0;
LIST = 1;
ATTACH = 2;
DETACH = 3;
INSERT = 4;
EJECT = 5;
PROTECT = 6;
LOG_LEVEL = 7;
}
// Commands rascsi can execute
message Command {
Operation cmd = 1;
int32 id = 2;
int32 un = 3;
DeviceType type = 4;
string params = 5;
}
// The result of a command
message Result {
bool status = 1;
string msg = 2;
}
// The device meta data
message Device {
int32 id = 1;
int32 un = 2;
string type = 3;
string file = 4;
bool read_only = 5;
}
message Devices {
repeated Device devices = 1;
}

View File

@ -14,17 +14,19 @@
#include "rascsi_version.h"
#include "exceptions.h"
#include "rasutil.h"
#include "rasctl_interface.pb.h"
#include "rascsi_interface.pb.h"
#include <sstream>
#include <iostream>
using namespace std;
using namespace rasctl_interface;
using namespace rascsi_interface;
//---------------------------------------------------------------------------
//
// Send Command
//
//---------------------------------------------------------------------------
BOOL SendCommand(const char *hostname, const Command& command)
int SendCommand(const char *hostname, const Command& command)
{
// Create a socket to send the command
int fd = socket(AF_INET, SOCK_STREAM, 0);
@ -43,24 +45,43 @@ BOOL SendCommand(const char *hostname, const Command& command)
// Connect
if (connect(fd, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0) {
fprintf(stderr, "Error : Can't connect to rascsi process on host '%s'\n", hostname);
return false;
cerr << "Error: Can't connect to rascsi process on host '" << hostname << "'" << endl;
return -1;
}
string data;
command.SerializeToString(&data);
// Receive the message
bool status = true;
try {
SerializeProtobufData(fd, data);
}
catch(const ioexception& e) {
cerr << "Error : " << e.getmsg() << endl;
close(fd);
return -1;
}
return fd;
}
//---------------------------------------------------------------------------
//
// Receive command result
//
//---------------------------------------------------------------------------
bool ReceiveResult(int fd) {
bool status = true;
try {
Result result;
result.ParseFromString(DeserializeProtobufData(fd));
status = result.status();
if (!result.msg().empty()) {
if (status) {
cerr << result.msg();
}
else {
cout << result.msg();
}
}
@ -68,6 +89,8 @@ BOOL SendCommand(const char *hostname, const Command& command)
cerr << "Error: " << e.getmsg() << endl;
// Fall through
status = false;
}
close(fd);
@ -75,6 +98,31 @@ BOOL SendCommand(const char *hostname, const Command& command)
return status;
}
string ListDevices(const Devices& devices) {
ostringstream s;
if (devices.devices_size()) {
s << endl
<< "+----+----+------+-------------------------------------" << endl
<< "| ID | UN | TYPE | DEVICE STATUS" << endl
<< "+----+----+------+-------------------------------------" << endl;
}
else {
return "No images currently attached.\n";
}
for (int i = 0; i < devices.devices_size() ; i++) {
Device device = devices.devices(i);
s << "| " << device.id() << " | " << device.un() << " | " << device.type() << " | "
<< device.file() << (device.read_only() ? " (WRITEPROTECT)" : "") << endl;
}
s << "+----+----+------+-------------------------------------" << endl;
return s.str();
}
//---------------------------------------------------------------------------
//
// Main processing
@ -88,7 +136,7 @@ int main(int argc, char* argv[])
if (argc < 2) {
cerr << "SCSI Target Emulator RaSCSI Controller" << endl;
cerr << "version " << rascsi_get_version_string() << " (" << __DATE__ << ", " << __TIME__ << ")" << endl;
cerr << "Usage: " << argv[0] << " -i ID [-u UNIT] [-c CMD] [-t TYPE] [-f FILE] [-h HOSTNAME] [-s LOG_LEVEL]" << endl;
cerr << "Usage: " << argv[0] << " -i ID [-u UNIT] [-c CMD] [-t TYPE] [-f FILE] [-h HOSTNAME] [-g LOG_LEVEL]" << endl;
cerr << " where ID := {0|1|2|3|4|5|6|7}" << endl;
cerr << " UNIT := {0|1} default setting is 0." << endl;
cerr << " CMD := {attach|detach|insert|eject|protect}" << endl;
@ -112,7 +160,7 @@ int main(int argc, char* argv[])
const char *hostname = "localhost";
string params;
opterr = 0;
while ((opt = getopt(argc, argv, "i:u:c:t:f:h:s:l")) != -1) {
while ((opt = getopt(argc, argv, "i:u:c:t:f:h:g:l")) != -1) {
switch (opt) {
case 'i':
id = optarg[0] - '0';
@ -190,7 +238,7 @@ int main(int argc, char* argv[])
hostname = optarg;
break;
case 's':
case 'g':
cmd = LOG_LEVEL;
params = optarg;
break;
@ -202,14 +250,39 @@ int main(int argc, char* argv[])
if (cmd == LOG_LEVEL) {
command.set_cmd(LOG_LEVEL);
command.set_params(params);
SendCommand(hostname, command);
int fd = SendCommand(hostname, command);
if (fd < 0) {
exit(ENOTCONN);
}
ReceiveResult(fd);
exit(0);
}
// List display only
if (cmd == LIST || (id < 0 && type == UNDEFINED && params.empty())) {
command.set_cmd(LIST);
SendCommand(hostname, command);
int fd = SendCommand(hostname, command);
if (fd < 0) {
exit(ENOTCONN);
}
Devices devices;
try {
devices.ParseFromString(DeserializeProtobufData(fd));
}
catch(const ioexception& e) {
cerr << "Error : " << e.getmsg() << endl;
close(fd);
exit(-1);
}
close (fd);
cout << ListDevices(devices) << endl;
exit(0);
}
@ -261,10 +334,15 @@ int main(int argc, char* argv[])
if (!params.empty()) {
command.set_params(params);
}
if (!SendCommand(hostname, command)) {
int fd = SendCommand(hostname, command);
if (fd == -1) {
exit(ENOTCONN);
}
bool status = ReceiveResult(fd);
close(fd);
// All done!
exit(0);
exit(status ? 0 : -1);
}

View File

@ -1,39 +0,0 @@
syntax = "proto3";
option optimize_for = LITE_RUNTIME;
package rasctl_interface;
enum Operation {
LIST = 0;
ATTACH = 1;
DETACH = 2;
INSERT = 3;
EJECT = 4;
PROTECT = 5;
LOG_LEVEL = 6;
}
enum DeviceType {
UNDEFINED = 0;
SASI_HD = 1;
SCSI_HD = 2;
MO = 3;
CD = 4;
BR = 5;
NUVOLINK = 6;
DAYNAPORT = 7;
}
message Command {
Operation cmd = 1;
int32 id = 2;
int32 un = 3;
DeviceType type = 4;
string params = 5;
}
message Result {
bool status = 1;
string msg = 2;
}