From 62e7727a48709309d6cf0563943adc1d234a9444 Mon Sep 17 00:00:00 2001 From: Uwe Seimet <48174652+uweseimet@users.noreply.github.com> Date: Thu, 22 Jul 2021 14:47:08 +0200 Subject: [PATCH] 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) --- src/raspberrypi/.gitignore | 5 + src/raspberrypi/Makefile | 12 +-- src/raspberrypi/rascsi.cpp | 142 ++++++++++++++----------- src/raspberrypi/rascsi_interface.proto | 57 ++++++++++ src/raspberrypi/rasctl.cpp | 126 +++++++++++++++++----- src/raspberrypi/rasctl_interface.proto | 39 ------- 6 files changed, 249 insertions(+), 132 deletions(-) create mode 100644 src/raspberrypi/rascsi_interface.proto delete mode 100644 src/raspberrypi/rasctl_interface.proto diff --git a/src/raspberrypi/.gitignore b/src/raspberrypi/.gitignore index b3172ad3..d81380e1 100644 --- a/src/raspberrypi/.gitignore +++ b/src/raspberrypi/.gitignore @@ -12,3 +12,8 @@ sasidump rasdump obj bin +/rascsi_interface.pb.cpp +/rascsi_interface.pb.h +.project +.cproject +.settings diff --git a/src/raspberrypi/Makefile b/src/raspberrypi/Makefile index 60cea44d..eadac00f 100644 --- a/src/raspberrypi/Makefile +++ b/src/raspberrypi/Makefile @@ -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) diff --git a/src/raspberrypi/rascsi.cpp b/src/raspberrypi/rascsi.cpp index 586699a3..ab675ea7 100644 --- a/src/raspberrypi/rascsi.cpp +++ b/src/raspberrypi/rascsi.cpp @@ -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 @@ -38,7 +38,7 @@ using namespace std; using namespace spdlog; -using namespace rasctl_interface; +using namespace rascsi_interface; //--------------------------------------------------------------------------- // @@ -250,76 +250,89 @@ 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( "+----+----+------+-------------------------------------"); + + 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; diff --git a/src/raspberrypi/rascsi_interface.proto b/src/raspberrypi/rascsi_interface.proto new file mode 100644 index 00000000..66d47abe --- /dev/null +++ b/src/raspberrypi/rascsi_interface.proto @@ -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; +} \ No newline at end of file diff --git a/src/raspberrypi/rasctl.cpp b/src/raspberrypi/rasctl.cpp index fb0a03ef..fa922770 100644 --- a/src/raspberrypi/rasctl.cpp +++ b/src/raspberrypi/rasctl.cpp @@ -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 +#include 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,36 +45,82 @@ 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); - - Result result; - result.ParseFromString(DeserializeProtobufData(fd)); - - status = result.status(); - - if (!result.msg().empty()) { - cout << result.msg(); - } } 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 (status) { + cerr << result.msg(); + } + else { + cout << result.msg(); + } + } + catch(const ioexception& e) { + cerr << "Error: " << e.getmsg() << endl; + // Fall through + + status = false; } close(fd); - return status; + 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(); } //--------------------------------------------------------------------------- @@ -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); } diff --git a/src/raspberrypi/rasctl_interface.proto b/src/raspberrypi/rasctl_interface.proto deleted file mode 100644 index f53adc90..00000000 --- a/src/raspberrypi/rasctl_interface.proto +++ /dev/null @@ -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; -} \ No newline at end of file