From 0a5298b8acb26636309056c00142bb094f700398 Mon Sep 17 00:00:00 2001 From: Uwe Seimet <48174652+uweseimet@users.noreply.github.com> Date: Sun, 8 Aug 2021 17:08:58 +0200 Subject: [PATCH] Feature extended server information (#169) * PbDevice returns information on whether a device is removable * Fixed log message * Added additional status data (ejectable, protctable, removable) * Assume ejectable == removable * Removed obsolete fields * Added locked/lockable to interface * Code review * Logging update * The user should be allowed to also write protect hard disk drives * Updated error handling * Testing * INSERT also has to search in the default file folder * Added TODO * Manpage update * Message updates * Moved some sanity checks to the server, so that they are run for any client * Updated error handling * Moved CR/LF handling to the client, the server should not format too much * rascsi should not mention "rasctl" in its messages, there may be other clients * Improved error messages * Improved error handling by returning an error string * Added TODO * Moved check for duplicate ID to ProcessCmd() * Removed debug output * Moved include * Removed obsolete includes, updated includes * Reverted ready check * Fixed error messages * Added convenience method * Simplified error handling * Socket/error handling review * "NO MEDIA" is added by the client, not by the server * Added missing include * Only check for duplicate ID when attaching a device * Added type/string converters for PbDeviceType * PbDevice indicates whether image files are supported * Write-protecing a read-only devices is not treated as an error anymore * Updated read-only check * Made difference between read-only and protected more explicit * Added comment * Comment update * Made hard disk drives write-protectable by the user * Resolved https://github.com/akuker/RASCSI/issues/166 * Addressing compiler error - type needs to be initialized Co-authored-by: akuker --- doc/rasctl.1 | 1 + doc/rasctl_man_page.txt | 22 +- src/raspberrypi/devices/ctapdriver.cpp | 6 +- src/raspberrypi/devices/ctapdriver.h | 2 +- src/raspberrypi/devices/disk.cpp | 90 +++---- src/raspberrypi/devices/disk.h | 31 ++- src/raspberrypi/devices/sasihd.cpp | 13 +- src/raspberrypi/devices/sasihd.h | 4 +- src/raspberrypi/devices/scsi_daynaport.cpp | 4 +- src/raspberrypi/devices/scsi_daynaport.h | 2 +- src/raspberrypi/devices/scsi_host_bridge.cpp | 2 + src/raspberrypi/devices/scsicd.cpp | 20 +- src/raspberrypi/devices/scsicd.h | 2 +- src/raspberrypi/devices/scsihd.cpp | 12 +- src/raspberrypi/devices/scsihd.h | 4 +- src/raspberrypi/devices/scsihd_nec.cpp | 16 +- src/raspberrypi/devices/scsihd_nec.h | 4 +- src/raspberrypi/devices/scsimo.cpp | 13 +- src/raspberrypi/devices/scsimo.h | 2 +- src/raspberrypi/gpiobus.cpp | 2 + src/raspberrypi/os.h | 20 +- src/raspberrypi/rascsi.cpp | 234 ++++++++++--------- src/raspberrypi/rascsi_interface.proto | 30 ++- src/raspberrypi/rasctl.cpp | 105 ++------- src/raspberrypi/rasutil.cpp | 60 ++++- src/raspberrypi/rasutil.h | 2 + 26 files changed, 382 insertions(+), 321 deletions(-) diff --git a/doc/rasctl.1 b/doc/rasctl.1 index 6e9c695b..caa5c1c3 100644 --- a/doc/rasctl.1 +++ b/doc/rasctl.1 @@ -54,6 +54,7 @@ Command is the operation being requested. options are: insert: insert media (Magneto-Optical and CD only) eject: eject media (Magneto-Optical and CD only) protect: Write protect the media (Magneto-Optical only) + unprotect: Remove write protection from the media (Magneto-Optical only) .IP When the command is omitted, rasctl will default to the 'attach' command. .TP diff --git a/doc/rasctl_man_page.txt b/doc/rasctl_man_page.txt index 35ebe34b..fb5f7504 100644 --- a/doc/rasctl_man_page.txt +++ b/doc/rasctl_man_page.txt @@ -6,8 +6,8 @@ NAME rasctl - Sends management commands to the rascsi process SYNOPSIS - rasctl -l | -s | [-g LOG_LEVEL] [-h HOST] [-p PORT] -i ID [-c CMD] [-f - FILE] [-t TYPE] [-u UNIT] + rasctl -l | -s | [-g LOG_LEVEL] [-h HOST] [-p PORT] [-v] -i ID [-c CMD] + [-f FILE] [-t TYPE] [-u UNIT] DESCRIPTION rasctl Sends commands to the rascsi process to make configuration ad‐ @@ -34,7 +34,9 @@ OPTIONS -p PORT The rascsi port to connect to, default is 6868. - -s Display server-side configuration settings. + -s Display the server-side configuration settings. + + -v Display the rascsi version. -i ID ID is the SCSI ID that you want to control. (0-7) @@ -44,27 +46,29 @@ OPTIONS insert: insert media (Magneto-Optical and CD only) eject: eject media (Magneto-Optical and CD only) protect: Write protect the media (Magneto-Optical only) + unprotect: Remove write protection from the media (Magneto- + Optical only) When the command is omitted, rasctl will default to the 'attach' command. -f FILE - Path to the disk image file. See the rascsi(1) man page for al‐ + Path to the disk image file. See the rascsi(1) man page for al‐ lowable file types. -t TYPE - Specifies the type of disk. If this disagrees with the file ex‐ - tension of the specified image, the TYPE argument is ignored. + Specifies the type of disk. If this disagrees with the file ex‐ + tension of the specified image, the TYPE argument is ignored. Available drive types are: hd: Hard disk (SCSI or SASI) mo: Magneto-Optical disk) cd: CD-ROM - bridge: Bridge device (This is only applicable to the Sharp + bridge: Bridge device (This is only applicable to the Sharp X68000) -u UNIT - Unit number (0 or 1). This will default to 0. This option is - only used when there are multiple SCSI devices on a shared SCSI + Unit number (0 or 1). This will default to 0. This option is + only used when there are multiple SCSI devices on a shared SCSI controller. (This is not common) EXAMPLES diff --git a/src/raspberrypi/devices/ctapdriver.cpp b/src/raspberrypi/devices/ctapdriver.cpp index e5ccdd24..8fd97411 100644 --- a/src/raspberrypi/devices/ctapdriver.cpp +++ b/src/raspberrypi/devices/ctapdriver.cpp @@ -247,7 +247,7 @@ BOOL CTapDriver::Init() } #endif // __NetBSD__ -BOOL CTapDriver::OpenDump(const Filepath& path) { +const char *CTapDriver::OpenDump(const Filepath& path) { if (m_pcap == NULL) { m_pcap = pcap_open_dead(DLT_EN10MB, 65535); } @@ -257,10 +257,10 @@ BOOL CTapDriver::OpenDump(const Filepath& path) { m_pcap_dumper = pcap_dump_open(m_pcap, path.GetPath()); if (m_pcap_dumper == NULL) { LOGERROR("Error: can't open pcap file: %s", pcap_geterr(m_pcap)); - return FALSE; + return "Can't open pcap file"; } LOGTRACE("%s Opened %s for dumping", __PRETTY_FUNCTION__, path.GetPath()); - return TRUE; + return NULL; } //--------------------------------------------------------------------------- diff --git a/src/raspberrypi/devices/ctapdriver.h b/src/raspberrypi/devices/ctapdriver.h index 84efc925..68705238 100644 --- a/src/raspberrypi/devices/ctapdriver.h +++ b/src/raspberrypi/devices/ctapdriver.h @@ -34,7 +34,7 @@ public: // Basic Functionality CTapDriver(); // Constructor BOOL Init(); // Initilization - BOOL OpenDump(const Filepath& path); + const char *OpenDump(const Filepath& path); // Capture packets void Cleanup(); // Cleanup void GetMacAddr(BYTE *mac); // Get Mac Address diff --git a/src/raspberrypi/devices/disk.cpp b/src/raspberrypi/devices/disk.cpp index b1a8ed6c..b9be0abe 100644 --- a/src/raspberrypi/devices/disk.cpp +++ b/src/raspberrypi/devices/disk.cpp @@ -711,12 +711,16 @@ Disk::Disk(std::string id) // Work initialization disk.ready = FALSE; - disk.writep = FALSE; - disk.readonly = FALSE; - disk.removable = FALSE; - disk.lock = FALSE; - disk.attn = FALSE; - disk.reset = FALSE; + disk.protectable = false; + disk.writep = false; + disk.readonly = false; + disk.removable = false; + disk.removed = false; + disk.lockable = false; + disk.locked = false; + disk.supports_file = true; + disk.attn = false; + disk.reset = false; disk.size = 0; disk.blocks = 0; disk.lun = 0; @@ -758,9 +762,9 @@ Disk::~Disk() void Disk::Reset() { // no lock, no attention, reset - disk.lock = FALSE; - disk.attn = FALSE; - disk.reset = TRUE; + disk.locked = false; + disk.attn = false; + disk.reset = false; } //--------------------------------------------------------------------------- @@ -839,9 +843,10 @@ bool Disk::IsNuvolink() const // // Open // * Call as a post-process after successful opening in a derived class +// TODO Use exceptions for error handling instead of returning a string // //--------------------------------------------------------------------------- -BOOL Disk::Open(const Filepath& path, BOOL /*attn*/) +const char *Disk::Open(const Filepath& path, BOOL /*attn*/) { ASSERT((disk.size >= 8) && (disk.size <= 11)); ASSERT(disk.blocks > 0); @@ -851,54 +856,55 @@ BOOL Disk::Open(const Filepath& path, BOOL /*attn*/) // Cache initialization ASSERT(!disk.dcache); - disk.dcache = - new DiskCache(path, disk.size, disk.blocks, disk.imgoffset); + disk.dcache = new DiskCache(path, disk.size, disk.blocks, disk.imgoffset); // Can read/write open Fileio fio; if (fio.Open(path, Fileio::ReadWrite)) { // Write permission, not read only - disk.writep = FALSE; - disk.readonly = FALSE; + disk.writep = false; + disk.readonly = false; fio.Close(); } else { // Write protected, read only - disk.writep = TRUE; - disk.readonly = TRUE; + disk.writep = true; + disk.readonly = true; } - // Not locked - disk.lock = FALSE; + // Not locked, not removed + disk.locked = false; + disk.removed = false; // Save path diskpath = path; // Success - return TRUE; + return NULL; } //--------------------------------------------------------------------------- // // Eject +// TODO This implemenation appears to be wrong: If a device is locked there +// is no way to eject the medium without unlocking. In other words, there is +// no "force" mode. // //--------------------------------------------------------------------------- -void Disk::Eject(BOOL force) +bool Disk::Eject(bool force) { // Can only be ejected if it is removable if (!disk.removable) { - return; + return false; } // If you're not ready, you don't need to eject if (!disk.ready) { - return; + return false; } // Must be unlocked if there is no force flag - if (!force) { - if (disk.lock) { - return; - } + if (!force && disk.locked) { + return false; } // Remove disk cache @@ -908,9 +914,12 @@ void Disk::Eject(BOOL force) // Not ready, no attention disk.ready = FALSE; - disk.writep = FALSE; - disk.readonly = FALSE; - disk.attn = FALSE; + disk.writep = false; + disk.readonly = false; + disk.removed = true; + disk.attn = false; + + return true; } //--------------------------------------------------------------------------- @@ -918,21 +927,22 @@ void Disk::Eject(BOOL force) // Write Protected // //--------------------------------------------------------------------------- -void Disk::WriteP(BOOL writep) +bool Disk::WriteP(bool writep) { // be ready if (!disk.ready) { - return; + return false; } // Read Only, protect only - if (disk.readonly) { - ASSERT(disk.writep); - return; + if (disk.readonly && !writep) { + return false; } // Write protect flag setting disk.writep = writep; + + return true; } //--------------------------------------------------------------------------- @@ -971,7 +981,7 @@ BOOL Disk::CheckReady() // Not ready if reset if (disk.reset) { disk.code = DISK_DEVRESET; - disk.reset = FALSE; + disk.reset = false; LOGTRACE("%s Disk in reset", __PRETTY_FUNCTION__); return FALSE; } @@ -979,7 +989,7 @@ BOOL Disk::CheckReady() // Not ready if it needs attention if (disk.attn) { disk.code = DISK_ATTENTION; - disk.attn = FALSE; + disk.attn = false; LOGTRACE("%s Disk in needs attention", __PRETTY_FUNCTION__); return FALSE; } @@ -1896,14 +1906,14 @@ BOOL Disk::StartStop(const DWORD *cdb) // Look at the eject bit and eject if necessary if (cdb[4] & 0x02) { - if (disk.lock) { + if (disk.locked) { // Cannot be ejected because it is locked disk.code = DISK_PREVENT; return FALSE; } // Eject - Eject(FALSE); + Eject(false); } // OK @@ -1955,9 +1965,9 @@ BOOL Disk::Removal(const DWORD *cdb) // Set Lock flag if (cdb[4] & 0x01) { - disk.lock = TRUE; + disk.locked = true; } else { - disk.lock = FALSE; + disk.locked = false; } // REMOVAL Success diff --git a/src/raspberrypi/devices/disk.h b/src/raspberrypi/devices/disk.h index 155405fe..377ae489 100644 --- a/src/raspberrypi/devices/disk.h +++ b/src/raspberrypi/devices/disk.h @@ -167,12 +167,17 @@ public: typedef struct { std::string id; // Media ID BOOL ready; // Valid Disk - BOOL writep; // Write protected - BOOL readonly; // Read only - BOOL removable; // Removable - BOOL lock; // Locked - BOOL attn; // Attention - BOOL reset; // Reset + bool readonly; // Read only + bool protectable; + bool writep; // Write protected + bool removable; // Removable + bool removed; + bool lockable; + bool locked; // Locked + // TODO Non-disk devices must not inherit from Disk class + bool supports_file; + bool attn; // Attention + bool reset; // Reset int size; // Sector Size DWORD blocks; // Total number of sectors DWORD lun; // LUN @@ -198,15 +203,19 @@ public: bool IsNuvolink() const; // Media Operations - virtual BOOL Open(const Filepath& path, BOOL attn = TRUE); // Open + virtual const char *Open(const Filepath& path, BOOL attn = TRUE); // Open void GetPath(Filepath& path) const; // Get the path - void Eject(BOOL force); // Eject + bool Eject(bool); // Eject bool IsReady() const { return disk.ready; } // Ready check - void WriteP(BOOL flag); // Set Write Protect flag + bool IsProtectable() const { return disk.protectable; } + bool WriteP(bool); // Set Write Protect flag bool IsWriteP() const { return disk.writep; } // Get write protect flag - bool IsReadOnly() const { return disk.readonly; } // Get read only flag + bool IsReadOnly() const { return disk.readonly; } // Get read only flag bool IsRemovable() const { return disk.removable; } // Get is removable flag - bool IsLocked() const { return disk.lock; } // Get locked status + bool IsRemoved() const { return disk.removed; } + bool IsLockable() const { return disk.lockable; } + bool IsLocked() const { return disk.locked; } // Get locked status + bool SupportsFile() const { return disk.supports_file; } bool IsAttn() const { return disk.attn; } // Get attention flag bool Flush(); // Flush the cache diff --git a/src/raspberrypi/devices/sasihd.cpp b/src/raspberrypi/devices/sasihd.cpp index 208296f3..890bd287 100644 --- a/src/raspberrypi/devices/sasihd.cpp +++ b/src/raspberrypi/devices/sasihd.cpp @@ -31,6 +31,7 @@ //--------------------------------------------------------------------------- SASIHD::SASIHD() : Disk("SAHD") { + disk.protectable = true; } //--------------------------------------------------------------------------- @@ -41,7 +42,7 @@ SASIHD::SASIHD() : Disk("SAHD") void SASIHD::Reset() { // Unlock, clear attention - disk.lock = FALSE; + disk.locked = FALSE; disk.attn = FALSE; // Reset, clear the code @@ -54,14 +55,14 @@ void SASIHD::Reset() // Open // //--------------------------------------------------------------------------- -BOOL SASIHD::Open(const Filepath& path, BOOL /*attn*/) +const char *SASIHD::Open(const Filepath& path, BOOL /*attn*/) { ASSERT(!disk.ready); // Open as read-only Fileio fio; if (!fio.Open(path, Fileio::ReadOnly)) { - return FALSE; + return "Can't open hard disk file read-only"; } // Get file size @@ -84,7 +85,7 @@ BOOL SASIHD::Open(const Filepath& path, BOOL /*attn*/) #if defined(REMOVE_FIXED_SASIHD_SIZE) // Must be in 256-byte units if (size & 0xff) { - return FALSE; + return "File size must be a multiple of 512"; } // 10MB or more @@ -94,7 +95,7 @@ BOOL SASIHD::Open(const Filepath& path, BOOL /*attn*/) // Limit to about 512MB if (size > 512 * 1024 * 1024) { - return FALSE; + return "File size must not exceed 512 MB"; } #else // 10MB, 20MB, 40MBのみ @@ -113,7 +114,7 @@ BOOL SASIHD::Open(const Filepath& path, BOOL /*attn*/) // Other (Not supported ) default: - return FALSE; + return "Unsupported file size"; } #endif // REMOVE_FIXED_SASIHD_SIZE diff --git a/src/raspberrypi/devices/sasihd.h b/src/raspberrypi/devices/sasihd.h index a272e805..ce993e73 100644 --- a/src/raspberrypi/devices/sasihd.h +++ b/src/raspberrypi/devices/sasihd.h @@ -30,8 +30,8 @@ public: // Basic Functions SASIHD(); // Constructor void Reset(); // Reset - BOOL Open(const Filepath& path, BOOL attn = TRUE); // Open + const char *Open(const Filepath& path, BOOL attn = TRUE); // Open // commands int RequestSense(const DWORD *cdb, BYTE *buf); // REQUEST SENSE command -}; \ No newline at end of file +}; diff --git a/src/raspberrypi/devices/scsi_daynaport.cpp b/src/raspberrypi/devices/scsi_daynaport.cpp index c1c44049..ac2eead3 100644 --- a/src/raspberrypi/devices/scsi_daynaport.cpp +++ b/src/raspberrypi/devices/scsi_daynaport.cpp @@ -49,6 +49,8 @@ const BYTE SCSIDaynaPort::m_apple_talk_addr[6] = { 0x09, 0x00, 0x07, 0xff, 0xff, //--------------------------------------------------------------------------- SCSIDaynaPort::SCSIDaynaPort() : Disk("SCDP") { + disk.supports_file = false; + #ifdef __linux__ // TAP Driver Generation m_tap = new CTapDriver(); @@ -102,7 +104,7 @@ SCSIDaynaPort::~SCSIDaynaPort() } } -BOOL SCSIDaynaPort::Open(const Filepath& path, BOOL attn) +const char *SCSIDaynaPort::Open(const Filepath& path, BOOL attn) { LOGTRACE("SCSIDaynaPort Open"); return m_tap->OpenDump(path); diff --git a/src/raspberrypi/devices/scsi_daynaport.h b/src/raspberrypi/devices/scsi_daynaport.h index 0aa068de..39c82b17 100644 --- a/src/raspberrypi/devices/scsi_daynaport.h +++ b/src/raspberrypi/devices/scsi_daynaport.h @@ -46,7 +46,7 @@ public: // Constructor virtual ~SCSIDaynaPort(); // Destructor - BOOL Open(const Filepath& path, BOOL attn = TRUE); + const char *Open(const Filepath& path, BOOL attn = TRUE); // Capture packets // commands diff --git a/src/raspberrypi/devices/scsi_host_bridge.cpp b/src/raspberrypi/devices/scsi_host_bridge.cpp index 89648812..d606255d 100644 --- a/src/raspberrypi/devices/scsi_host_bridge.cpp +++ b/src/raspberrypi/devices/scsi_host_bridge.cpp @@ -34,6 +34,8 @@ //--------------------------------------------------------------------------- SCSIBR::SCSIBR() : Disk("SCBR") { + disk.supports_file = false; + fsoptlen = 0; fsoutlen = 0; fsresult = 0; diff --git a/src/raspberrypi/devices/scsicd.cpp b/src/raspberrypi/devices/scsicd.cpp index 59eba93e..b615be96 100644 --- a/src/raspberrypi/devices/scsicd.cpp +++ b/src/raspberrypi/devices/scsicd.cpp @@ -251,9 +251,9 @@ CDDABuf::~CDDABuf() //--------------------------------------------------------------------------- SCSICD::SCSICD() : Disk("SCCD") { - // removable, write protected - disk.removable = TRUE; - disk.writep = TRUE; + disk.removable = true; + disk.lockable = true; + disk.writep = true; // NOT in raw format rawfile = FALSE; @@ -286,7 +286,7 @@ SCSICD::~SCSICD() // Open // //--------------------------------------------------------------------------- -BOOL SCSICD::Open(const Filepath& path, BOOL attn) +const char *SCSICD::Open(const Filepath& path, BOOL attn) { Fileio fio; off64_t size; @@ -301,7 +301,7 @@ BOOL SCSICD::Open(const Filepath& path, BOOL attn) // Open as read-only if (!fio.Open(path, Fileio::ReadOnly)) { - return FALSE; + return "Can't open CD-ROM file read-only"; } // Close and transfer for physical CD access @@ -311,14 +311,14 @@ BOOL SCSICD::Open(const Filepath& path, BOOL attn) // Open physical CD if (!OpenPhysical(path)) { - return FALSE; + return "Can't open physical CD"; } } else { // Get file size size = fio.GetFileSize(); if (size <= 4) { fio.Close(); - return FALSE; + return "Invalid file size"; } // Judge whether it is a CUE sheet or an ISO file @@ -330,12 +330,12 @@ BOOL SCSICD::Open(const Filepath& path, BOOL attn) if (xstrncasecmp(file, _T("FILE"), 4) == 0) { // Open as CUE if (!OpenCue(path)) { - return FALSE; + return "Can't open as CUE"; } } else { // Open as ISO if (!OpenIso(path)) { - return FALSE; + return "Can't open as ISO"; } } } @@ -359,7 +359,7 @@ BOOL SCSICD::Open(const Filepath& path, BOOL attn) disk.attn = TRUE; } - return TRUE; + return NULL; } //--------------------------------------------------------------------------- diff --git a/src/raspberrypi/devices/scsicd.h b/src/raspberrypi/devices/scsicd.h index deb33e4d..4f620921 100644 --- a/src/raspberrypi/devices/scsicd.h +++ b/src/raspberrypi/devices/scsicd.h @@ -114,7 +114,7 @@ public: // Basic Functions SCSICD(); // Constructor virtual ~SCSICD(); // Destructor - BOOL Open(const Filepath& path, BOOL attn = TRUE); // Open + const char *Open(const Filepath& path, BOOL attn = TRUE); // Open // commands int Inquiry(const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor); // INQUIRY command diff --git a/src/raspberrypi/devices/scsihd.cpp b/src/raspberrypi/devices/scsihd.cpp index 4aaa1cd9..399d740e 100644 --- a/src/raspberrypi/devices/scsihd.cpp +++ b/src/raspberrypi/devices/scsihd.cpp @@ -30,6 +30,7 @@ //--------------------------------------------------------------------------- SCSIHD::SCSIHD() : Disk("SCHD") { + disk.protectable = true; } //--------------------------------------------------------------------------- @@ -40,7 +41,7 @@ SCSIHD::SCSIHD() : Disk("SCHD") void SCSIHD::Reset() { // Unlock and release attention - disk.lock = FALSE; + disk.locked = FALSE; disk.attn = FALSE; // No reset, clear code @@ -53,14 +54,14 @@ void SCSIHD::Reset() // Open // //--------------------------------------------------------------------------- -BOOL SCSIHD::Open(const Filepath& path, BOOL /*attn*/) +const char *SCSIHD::Open(const Filepath& path, BOOL /*attn*/) { ASSERT(!disk.ready); // read open required Fileio fio; if (!fio.Open(path, Fileio::ReadOnly)) { - return FALSE; + return "Can't open hard disk file read-only"; } // Get file size @@ -69,13 +70,14 @@ BOOL SCSIHD::Open(const Filepath& path, BOOL /*attn*/) // Must be 512 bytes if (size & 0x1ff) { - return FALSE; + return "File size must be a multiple of 512 bytes"; } // 2TB according to xm6i // There is a similar one in wxw/wxw_cfg.cpp + // Bigger files/drives require READ/WRITE(16) to be implemented if (size > 2LL * 1024 * 1024 * 1024 * 1024) { - return FALSE; + return "File size must not exceed 2 TB"; } // sector size and number of blocks diff --git a/src/raspberrypi/devices/scsihd.h b/src/raspberrypi/devices/scsihd.h index 6421cc0c..eb411b84 100644 --- a/src/raspberrypi/devices/scsihd.h +++ b/src/raspberrypi/devices/scsihd.h @@ -30,9 +30,9 @@ public: // Basic Functions SCSIHD(); // Constructor void Reset(); // Reset - BOOL Open(const Filepath& path, BOOL attn = TRUE); // Open + const char *Open(const Filepath& path, BOOL attn = TRUE); // Open // commands int Inquiry(const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor); // INQUIRY command BOOL ModeSelect(const DWORD *cdb, const BYTE *buf, int length); // MODE SELECT(6) command -}; \ No newline at end of file +}; diff --git a/src/raspberrypi/devices/scsihd_nec.cpp b/src/raspberrypi/devices/scsihd_nec.cpp index b072a0fb..d38f2b77 100644 --- a/src/raspberrypi/devices/scsihd_nec.cpp +++ b/src/raspberrypi/devices/scsihd_nec.cpp @@ -65,7 +65,7 @@ static inline DWORD getDwordLE(const BYTE *b) // Open // //--------------------------------------------------------------------------- -BOOL SCSIHD_NEC::Open(const Filepath& path, BOOL /*attn*/) +const char *SCSIHD_NEC::Open(const Filepath& path, BOOL /*attn*/) { Fileio fio; off64_t size; @@ -76,7 +76,7 @@ BOOL SCSIHD_NEC::Open(const Filepath& path, BOOL /*attn*/) // Open as read-only if (!fio.Open(path, Fileio::ReadOnly)) { - return FALSE; + return "Can't open hard disk file read-only"; } // Get file size @@ -86,14 +86,14 @@ BOOL SCSIHD_NEC::Open(const Filepath& path, BOOL /*attn*/) if (size >= (off64_t)sizeof(hdr)) { if (!fio.Read(hdr, sizeof(hdr))) { fio.Close(); - return FALSE; + return "Can't read hard disk file header"; } } fio.Close(); // Must be in 512 byte units if (size & 0x1ff) { - return FALSE; + return "File size must be a multiple of 512"; } // 10MB or more @@ -102,7 +102,7 @@ BOOL SCSIHD_NEC::Open(const Filepath& path, BOOL /*attn*/) } // 2TB according to xm6i if (size > 2LL * 1024 * 1024 * 1024 * 1024) { - return FALSE; + return "File size must not exceed 2 TB"; } // Determine parameters by extension @@ -136,12 +136,12 @@ BOOL SCSIHD_NEC::Open(const Filepath& path, BOOL /*attn*/) // Supports 256 or 512 sector sizes if (sectorsize != 256 && sectorsize != 512) { - return FALSE; + return "Sector size must be 256 or 512"; } // Image size consistency check if (imgoffset + imgsize > size || (imgsize % sectorsize != 0)) { - return FALSE; + return "Image size consistency check failed"; } // Sector size @@ -150,7 +150,7 @@ BOOL SCSIHD_NEC::Open(const Filepath& path, BOOL /*attn*/) break; } if (disk.size <= 0 || disk.size > 16) { - return FALSE; + return "Invalid disk size"; } // Number of blocks diff --git a/src/raspberrypi/devices/scsihd_nec.h b/src/raspberrypi/devices/scsihd_nec.h index 9a68463b..684e8301 100644 --- a/src/raspberrypi/devices/scsihd_nec.h +++ b/src/raspberrypi/devices/scsihd_nec.h @@ -27,7 +27,7 @@ class SCSIHD_NEC : public SCSIHD public: // Basic Functions SCSIHD_NEC(); // Constructor - BOOL Open(const Filepath& path, BOOL attn = TRUE); // Open + const char *Open(const Filepath& path, BOOL attn = TRUE); // Open // commands int Inquiry(const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor); // INQUIRY command @@ -44,4 +44,4 @@ private: int sectorsize; // Sector size off64_t imgoffset; // Image offset off64_t imgsize; // Image size -}; \ No newline at end of file +}; diff --git a/src/raspberrypi/devices/scsimo.cpp b/src/raspberrypi/devices/scsimo.cpp index 7312ad65..676c5d16 100644 --- a/src/raspberrypi/devices/scsimo.cpp +++ b/src/raspberrypi/devices/scsimo.cpp @@ -31,8 +31,9 @@ //--------------------------------------------------------------------------- SCSIMO::SCSIMO() : Disk("SCMO") { - // Set as removable - disk.removable = TRUE; + disk.removable = true; + disk.lockable = true; + disk.protectable = true; } //--------------------------------------------------------------------------- @@ -40,14 +41,14 @@ SCSIMO::SCSIMO() : Disk("SCMO") // Open // //--------------------------------------------------------------------------- -BOOL SCSIMO::Open(const Filepath& path, BOOL attn) +const char *SCSIMO::Open(const Filepath& path, BOOL attn) { ASSERT(!disk.ready); // Open as read-only Fileio fio; if (!fio.Open(path, Fileio::ReadOnly)) { - return FALSE; + return "Can't open MO file read-only"; } // Get file size @@ -81,7 +82,7 @@ BOOL SCSIMO::Open(const Filepath& path, BOOL attn) // Other (this is an error) default: - return FALSE; + return "Invalid MO size"; } // Call the base class @@ -92,7 +93,7 @@ BOOL SCSIMO::Open(const Filepath& path, BOOL attn) disk.attn = TRUE; } - return TRUE; + return NULL; } //--------------------------------------------------------------------------- diff --git a/src/raspberrypi/devices/scsimo.h b/src/raspberrypi/devices/scsimo.h index 48e1fea2..66dc5f31 100644 --- a/src/raspberrypi/devices/scsimo.h +++ b/src/raspberrypi/devices/scsimo.h @@ -29,7 +29,7 @@ class SCSIMO : public Disk public: // Basic Functions SCSIMO(); // Constructor - BOOL Open(const Filepath& path, BOOL attn = TRUE); // Open + const char *Open(const Filepath& path, BOOL attn = TRUE); // Open // commands int Inquiry(const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor); // INQUIRY command diff --git a/src/raspberrypi/gpiobus.cpp b/src/raspberrypi/gpiobus.cpp index dd021a85..8fa855fe 100644 --- a/src/raspberrypi/gpiobus.cpp +++ b/src/raspberrypi/gpiobus.cpp @@ -12,6 +12,8 @@ // //--------------------------------------------------------------------------- +#include + #include "os.h" #include "xm6.h" #include "gpiobus.h" diff --git a/src/raspberrypi/os.h b/src/raspberrypi/os.h index f261a4e6..4fa7afce 100644 --- a/src/raspberrypi/os.h +++ b/src/raspberrypi/os.h @@ -35,19 +35,16 @@ // //--------------------------------------------------------------------------- -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include -#include -#include #include #include -#include -#include -#include #include #include #include @@ -58,14 +55,13 @@ #include #include -#include #include #include #include #include -#include #if defined(__linux__) +#include #include #include #elif defined(__NetBSD__) diff --git a/src/raspberrypi/rascsi.cpp b/src/raspberrypi/rascsi.cpp index ded0d1de..207b279a 100644 --- a/src/raspberrypi/rascsi.cpp +++ b/src/raspberrypi/rascsi.cpp @@ -176,18 +176,24 @@ BOOL InitService(int port) return true; } -bool InitBusAndDisks() { +bool InitBus() +{ // GPIOBUS creation bus = new GPIOBUS(); // GPIO Initialization if (!bus->Init()) { - return FALSE; + return false; } // Bus Reset bus->Reset(); + return true; +} + +void InitDisks() +{ // Controller initialization for (int i = 0; i < CtrlMax; i++) { ctrl[i] = NULL; @@ -197,8 +203,6 @@ bool InitBusAndDisks() { for (int i = 0; i < CtrlMax; i++) { disk[i] = NULL; } - - return TRUE; } //--------------------------------------------------------------------------- @@ -225,10 +229,12 @@ void Cleanup() } // Cleanup the Bus - bus->Cleanup(); + if (bus) { + bus->Cleanup(); - // Discard the GPIOBUS object - delete bus; + // Discard the GPIOBUS object + delete bus; + } // Close the monitor socket if (monsocket >= 0) { @@ -278,7 +284,7 @@ PbDevices GetDevices() { device->set_un(i % UnitNum); // ID,UNIT,Type,Device Status - device->set_type(pUnit->GetID()); + device->set_type(MapIdToType(pUnit->GetID(), pUnit->IsSASI())); // mount status output if (pUnit->IsBridge()) { @@ -288,10 +294,16 @@ PbDevices GetDevices() { } else { Filepath filepath; pUnit->GetPath(filepath); - device->set_file(pUnit->IsRemovable() && !pUnit->IsReady() ? "NO MEDIA" : filepath.GetPath()); + device->set_file(pUnit->IsRemovable() && !pUnit->IsReady() ? "" : filepath.GetPath()); } + device->set_protectable(pUnit->IsProtectable()); + device->set_protected_(pUnit->IsProtectable() && pUnit->IsWriteP()); device->set_removable(pUnit->IsRemovable()); + device->set_removed(pUnit->IsRemoved()); + device->set_lockable(pUnit->IsLockable()); + device->set_locked(pUnit->IsLocked()); + device->set_supports_file(pUnit->SupportsFile()); // Write protection status if (pUnit->IsRemovable() && pUnit->IsReady() && pUnit->IsWriteP()) { @@ -419,9 +431,11 @@ bool MapController(Disk **map) return status; } -bool ReturnStatus(int fd, bool status = true, const string msg = "") { +bool ReturnStatus(int fd, bool status = true, const string msg = "") +{ if (fd == -1) { if (msg.length()) { + FPRT(stderr, "Error: "); FPRT(stderr, msg.c_str()); FPRT(stderr, "\n"); } @@ -429,14 +443,20 @@ bool ReturnStatus(int fd, bool status = true, const string msg = "") { else { PbResult result; result.set_status(status); - result.set_msg(msg + "\n"); + result.set_msg(msg); SerializeMessage(fd, result); } return status; } -bool SetLogLevel(const string& log_level) { +bool ReturnStatus(int fd, bool status, const ostringstream& msg) +{ + return ReturnStatus(fd, status, msg.str()); +} + +bool SetLogLevel(const string& log_level) +{ if (log_level == "trace") { set_level(level::trace); } @@ -502,12 +522,12 @@ void GetAvailableImages(PbServerInfo& serverInfo) //--------------------------------------------------------------------------- bool ProcessCmd(int fd, const PbCommand &command) { - Disk *map[CtrlMax * UnitNum]; Filepath filepath; Disk *pUnit; - char type_str[5]; + ostringstream error; + const char *result; - int id = command.id(); + int id = command.id(); int un = command.un(); PbOperation cmd = command.cmd(); PbDeviceType type = command.type(); @@ -518,37 +538,53 @@ bool ProcessCmd(int fd, const PbCommand &command) LOGINFO("%s", s.str().c_str()); // Copy the Unit List + Disk *map[CtrlMax * UnitNum]; memcpy(map, disk, sizeof(disk)); // Check the Controller Number if (id < 0 || id >= CtrlMax) { - return ReturnStatus(fd, false, "Error : Invalid ID"); + error << "Invalid ID " << id << " (0-" << CtrlMax - 1 << ")"; + return ReturnStatus(fd, false, error); } // Check the Unit Number if (un < 0 || un >= UnitNum) { - return ReturnStatus(fd, false, "Error : Invalid unit number"); + error << "Invalid unit " << un << " (0-" << UnitNum - 1 << ")"; + return ReturnStatus(fd, false, error); + } + + string ext; + int len = params.length(); + if (len > 4 && params[len - 4] == '.') { + ext = params.substr(len - 3); } // Connect Command if (cmd == ATTACH) { - string ext; + if (map[id]) { + error << "Duplicate ID " << id; + return ReturnStatus(fd, false, error); + } - // Distinguish between SASI and SCSI - if (type == SASI_HD) { - // Check the extension - int len = params.length(); - if (len < 5 || params[len - 4] != '.') { - return ReturnStatus(fd, false); + // If no type was specified try to derive the file type from the extension + if (type == UNDEFINED) { + if (ext == "hdf") { + type = SASI_HD; } - - // If the extension is not SASI type, replace with SCSI - ext = params.substr(len - 3); - if (ext != "hdf") { + else if (ext == "hds" || ext == "hdn" || ext == "hdi" || ext == "nhd" || ext == "hda") { type = SCSI_HD; + } else if (ext == "mos") { + type = MO; + } else if (ext == "iso") { + type = CD; } } + // File check (type is HD, for CD and MO the medium (=file) may be inserted later) + if ((type == SASI_HD || type == SCSI_HD) && params.empty()) { + return ReturnStatus(fd, false, "Missing filename"); + } + // Create a new drive, based upon type pUnit = NULL; switch (type) { @@ -580,9 +616,8 @@ bool ProcessCmd(int fd, const PbCommand &command) pUnit = new SCSIDaynaPort(); break; default: - ostringstream error; - error << "rasctl sent a command for an invalid drive type: " << PbDeviceType_Name(type); - return ReturnStatus(fd, false, error.str()); + error << "Received a command for an invalid drive type: " << PbDeviceType_Name(type); + return ReturnStatus(fd, false, error); } // drive checks files @@ -594,25 +629,24 @@ bool ProcessCmd(int fd, const PbCommand &command) filepath.SetPath(file.c_str()); // Open the file path - if (!pUnit->Open(filepath)) { + result = pUnit->Open(filepath); + if (result) { // If the file does not exist search for it in the default image folder string default_file = default_image_folder + "/" + file; filepath.SetPath(default_file.c_str()); - if (!pUnit->Open(filepath)) { + result = pUnit->Open(filepath); + if (result) { delete pUnit; - LOGWARN("rasctl tried to open an invalid file %s", file.c_str()); - - ostringstream error; - error << "File open error [" << file << "]"; - return ReturnStatus(fd, false, error.str()); + error << "Tried to open an invalid file '" << file << "': " << result; + LOGWARN("%s", error.str().c_str()); + return ReturnStatus(fd, false, error); } } if (files_in_use.find(filepath.GetPath()) != files_in_use.end()) { - ostringstream error; error << "Image file '" << file << "' is already in use"; - return ReturnStatus(fd, false, error.str()); + return ReturnStatus(fd, false, error); } files_in_use.insert(filepath.GetPath()); @@ -627,30 +661,30 @@ bool ProcessCmd(int fd, const PbCommand &command) // Re-map the controller bool status = MapController(map); if (status) { - LOGINFO("rasctl added new %s device. ID: %d UN: %d", pUnit->GetID().c_str(), id, un); + LOGINFO("Added new %s device. ID: %d UN: %d", pUnit->GetID().c_str(), id, un); } - return ReturnStatus(fd, status, status ? "" : "Error : SASI and SCSI can't be mixed\n"); + return ReturnStatus(fd, status, status ? "" : "SASI and SCSI can't be mixed"); } // Does the controller exist? if (ctrl[id] == NULL) { - LOGWARN("rasctl sent a command for invalid controller %d", id); + LOGWARN("Received a command for invalid controller %d", id); - return ReturnStatus(fd, false, "Error : No such device"); + return ReturnStatus(fd, false, "No such device"); } // Does the unit exist? pUnit = disk[id * UnitNum + un]; if (pUnit == NULL) { - LOGWARN("rasctl sent a command for invalid unit ID %d UN %d", id, un); + LOGWARN("Received a command for invalid unit ID %d UN %d", id, un); - return ReturnStatus(fd, false, "Error : No such device"); + return ReturnStatus(fd, false, "No such device"); } // Disconnect Command if (cmd == DETACH) { - LOGINFO("rasctl command disconnect %s at ID: %d UN: %d", pUnit->GetID().c_str(), id, un); + LOGINFO("Disconnect %s at ID: %d UN: %d", pUnit->GetID().c_str(), id, un); // Free the existing unit map[id * UnitNum + un] = NULL; @@ -662,54 +696,69 @@ bool ProcessCmd(int fd, const PbCommand &command) // Re-map the controller bool status = MapController(map); - return ReturnStatus(fd, status, status ? "" : "Error : SASI and SCSI can't be mixed\n"); + return ReturnStatus(fd, status, status ? "" : "SASI and SCSI can't be mixed"); } - // Valid only for MO or CD - if (!pUnit->IsMo() && !pUnit->IsCdRom()) { - LOGWARN("rasctl sent an Insert/Eject/Protect command (%d) for incompatible type %s", cmd, pUnit->GetID().c_str()); + // Only MOs or CDs may be inserted/ejected, only MOs, CDs or hard disks may be protected + if ((cmd == INSERT || cmd == EJECT) && !pUnit->IsRemovable()) { + LOGWARN("%s requested for incompatible type %s", PbOperation_Name(cmd).c_str(), pUnit->GetID().c_str()); - ostringstream error; - error << "Operation denied (Device type " << type_str << " isn't removable)"; - return ReturnStatus(fd, false, error.str()); + error << "Operation denied (Device type " << pUnit->GetID().c_str() << " isn't removable)"; + return ReturnStatus(fd, false, error); + } + + if ((cmd == PROTECT || cmd == UNPROTECT) && (!pUnit->IsProtectable() || pUnit->IsReadOnly())) { + LOGWARN("%s requested for incompatible type %s", PbOperation_Name(cmd).c_str(), pUnit->GetID().c_str()); + + error << "Operation denied (Device type " << pUnit->GetID().c_str() << " isn't protectable)"; + return ReturnStatus(fd, false, error); } switch (cmd) { case INSERT: + if (params.empty()) { + return ReturnStatus(fd, false, "Missing filename"); + } + filepath.SetPath(params.c_str()); - LOGINFO("rasctl commanded insert file %s into %s ID: %d UN: %d", params.c_str(), pUnit->GetID().c_str(), id, un); + LOGINFO("Insert file '%s' requested into %s ID: %d UN: %d", params.c_str(), pUnit->GetID().c_str(), id, un); - if (!pUnit->Open(filepath)) { - ostringstream error; - error << "File open error [" << params << "]"; - - return ReturnStatus(fd, false, error.str()); + result = pUnit->Open(filepath); + if (result) { + // If the file does not exist search for it in the default image folder + string default_file = default_image_folder + "/" + params; + filepath.SetPath(default_file.c_str()); + result = pUnit->Open(filepath); + if (result) { + error << "Tried to open an invalid file '" << params << "': " << result; + LOGWARN("%s", error.str().c_str()); + return ReturnStatus(fd, false, error); + } } break; case EJECT: - LOGINFO("rasctl commanded eject for %s ID: %d UN: %d", pUnit->GetID().c_str(), id, un); - pUnit->Eject(TRUE); + LOGINFO("Eject requested for %s ID: %d UN: %d", pUnit->GetID().c_str(), id, un); + pUnit->Eject(true); break; case PROTECT: - if (!pUnit->IsMo()) { - LOGWARN("rasctl sent an invalid PROTECT command for %s ID: %d UN: %d", pUnit->GetID().c_str(), id, un); + LOGINFO("Write protection requested for %s ID: %d UN: %d", pUnit->GetID().c_str(), id, un); + pUnit->WriteP(true); + break; - return ReturnStatus(fd, false, "Error : Operation denied (Device isn't MO)"); - } - LOGINFO("rasctl is setting write protect to %d for %s ID: %d UN: %d",!pUnit->IsWriteP(), pUnit->GetID().c_str(), id, un); - pUnit->WriteP(!pUnit->IsWriteP()); + case UNPROTECT: + LOGINFO("Write unprotection requested for %s ID: %d UN: %d", pUnit->GetID().c_str(), id, un); + pUnit->WriteP(false); break; default: - ostringstream error; - error << "Received unknown command from rasctl: " << PbOperation_Name(cmd); + error << "Received unknown command: " << PbOperation_Name(cmd); LOGWARN("%s", error.str().c_str()); - return ReturnStatus(fd, false, error.str()); + return ReturnStatus(fd, false, error); } - return ReturnStatus(fd, true); + return ReturnStatus(fd); } bool has_suffix(const string& filename, const string& suffix) { @@ -788,32 +837,6 @@ bool ParseArgument(int argc, char* argv[], int& port) break; } - if (id < 0) { - cerr << optarg << ": ID not specified" << endl; - return false; - } else if (disk[id]) { - cerr << id << ": duplicate ID" << endl; - return false; - } - - string path = optarg; - PbDeviceType type = SASI_HD; - if (has_suffix(path, ".hdf") || has_suffix(path, ".hds") || has_suffix(path, ".hdn") - || has_suffix(path, ".hdi") || has_suffix(path, ".hda") || has_suffix(path, ".nhd")) { - type = SASI_HD; - } else if (has_suffix(path, ".mos")) { - type = MO; - } else if (has_suffix(path, ".iso")) { - type = CD; - } else if (path == "bridge") { - type = BR; - } else if (path == "daynaport") { - type = DAYNAPORT; - } else { - cerr << path << ": unknown file extension or basename is missing" << endl; - return false; - } - int un = 0; if (is_sasi) { un = id % UnitNum; @@ -825,8 +848,7 @@ bool ParseArgument(int argc, char* argv[], int& port) command.set_id(id); command.set_un(un); command.set_cmd(ATTACH); - command.set_type(type); - command.set_params(path); + command.set_params(optarg); if (!ProcessCmd(-1, command)) { return false; } @@ -920,7 +942,7 @@ static void *MonThread(void *param) if (!status) { ostringstream error; error << "Invalid log level: " << command.params(); - ReturnStatus(fd, false, error.str()); + ReturnStatus(fd, false, error); } else { ReturnStatus(fd); @@ -1003,16 +1025,18 @@ int main(int argc, char* argv[]) int ret = 0; int port = 6868; - if (!InitBusAndDisks()) { - ret = EPERM; - goto init_exit; - } + InitDisks(); if (!ParseArgument(argc, argv, port)) { ret = EINVAL; goto err_exit; } + if (!InitBus()) { + ret = EPERM; + goto init_exit; + } + if (!InitService(port)) { ret = EPERM; goto init_exit; diff --git a/src/raspberrypi/rascsi_interface.proto b/src/raspberrypi/rascsi_interface.proto index a7eba989..ef14135c 100644 --- a/src/raspberrypi/rascsi_interface.proto +++ b/src/raspberrypi/rascsi_interface.proto @@ -18,13 +18,14 @@ enum PbDeviceType { enum PbOperation { NONE = 0; SERVER_INFO = 1; - LIST = 2; - ATTACH = 3; - DETACH = 4; - INSERT = 5; - EJECT = 6; - PROTECT = 7; - LOG_LEVEL = 8; + LOG_LEVEL = 2; + LIST = 3; + ATTACH = 4; + DETACH = 5; + INSERT = 6; + EJECT = 7; + PROTECT = 8; + UNPROTECT = 9; } // Commands rascsi can execute @@ -42,14 +43,23 @@ message PbResult { string msg = 2; } + // The device meta data message PbDevice { int32 id = 1; int32 un = 2; - string type = 3; + PbDeviceType type = 3; string file = 4; - bool removable = 5; - bool read_only = 6; + bool read_only = 5; + // Note: Read-only media (e.g. CD-ROMs) are not protectable + bool protectable = 6; + // Note: Read-only media (e.g. CD-ROMs) are not protected by just read-only + bool protected = 7; + bool removable = 8; + bool removed = 9; + bool lockable = 10; + bool locked = 11; + bool supports_file = 12; } message PbDevices { diff --git a/src/raspberrypi/rasctl.cpp b/src/raspberrypi/rasctl.cpp index 27ef4c08..7711e459 100644 --- a/src/raspberrypi/rasctl.cpp +++ b/src/raspberrypi/rasctl.cpp @@ -51,9 +51,9 @@ int SendCommand(const string& hostname, int port, const PbCommand& command) memcpy(&server.sin_addr.s_addr, host->h_addr, host->h_length); if (connect(fd, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0) { - ostringstream s; - s << "Can't connect to rascsi process on host '" << hostname << "', port " << port; - throw ioexception(s.str()); + ostringstream error; + error << "Can't connect to rascsi process on host '" << hostname << "', port " << port; + throw ioexception(error.str()); } SerializeMessage(fd, command); @@ -65,7 +65,7 @@ int SendCommand(const string& hostname, int port, const PbCommand& command) close(fd); } - return -1; + exit(fd < 0 ? ENOTCONN : -1); } return fd; @@ -76,32 +76,26 @@ int SendCommand(const string& hostname, int port, const PbCommand& command) // Receive command result // //--------------------------------------------------------------------------- -bool ReceiveResult(int fd) { - bool status = true; - +bool ReceiveResult(int fd) +{ try { PbResult result; DeserializeMessage(fd, result); + close(fd); - status = result.status(); - if (status) { - cerr << result.msg(); - } - else { - cout << result.msg(); + if (!result.status()) { + throw ioexception(result.msg()); } + + cout << result.msg() << endl; } catch(const ioexception& e) { cerr << "Error: " << e.getmsg() << endl; - // Fall through - - status = false; + return false; } - close(fd); - - return status; + return true; } //--------------------------------------------------------------------------- @@ -116,9 +110,6 @@ void CommandList(const string& hostname, int port) command.set_cmd(LIST); int fd = SendCommand(hostname.c_str(), port, command); - if (fd < 0) { - exit(ENOTCONN); - } PbDevices devices; try { @@ -144,12 +135,7 @@ void CommandLogLevel(const string& hostname, int port, const string& log_level) command.set_params(log_level); int fd = SendCommand(hostname.c_str(), port, command); - if (fd < 0) { - exit(ENOTCONN); - } - ReceiveResult(fd); - close(fd); } @@ -159,10 +145,6 @@ void CommandServerInfo(const string& hostname, int port) command.set_cmd(SERVER_INFO); int fd = SendCommand(hostname.c_str(), port, command); - if (fd < 0) { - exit(ENOTCONN); - } - PbServerInfo serverInfo; try { @@ -178,18 +160,18 @@ void CommandServerInfo(const string& hostname, int port) close(fd); - cout << "rascsi version: " << serverInfo.rascsi_version() << endl; + cout << "rascsi server version: " << serverInfo.rascsi_version() << endl; if (!serverInfo.available_log_levels_size()) { cout << " No log level settings available" << endl; } else { - cout << "Available log levels, sorted by severity:" << endl; + cout << "Available rascsi log levels, sorted by severity:" << endl; for (int i = 0; i < serverInfo.available_log_levels_size(); i++) { cout << " " << serverInfo.available_log_levels(i) << endl; } - cout << "Current log level: " << serverInfo.current_log_level() << endl; + cout << "Current rascsi log level: " << serverInfo.current_log_level() << endl; } cout << "Default image file folder: " << serverInfo.default_image_folder() << endl; @@ -226,7 +208,7 @@ int main(int argc, char* argv[]) cerr << "Usage: " << argv[0] << " -i ID [-u UNIT] [-c CMD] [-t TYPE] [-f FILE] [-g LOG_LEVEL] [-h HOST] [-p PORT] [-v]" << 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; + cerr << " CMD := {attach|detach|insert|eject|protect|unprotect}" << endl; cerr << " TYPE := {hd|mo|cd|bridge|daynaport}" << endl; cerr << " FILE := image file path" << endl; cerr << " HOST := rascsi host to connect to, default is 'localhost'" << endl; @@ -249,7 +231,7 @@ int main(int argc, char* argv[]) int port = 6868; string params; opterr = 0; - while ((opt = getopt(argc, argv, "i:u:c:t:f:h:p:g:lsv")) != -1) { + while ((opt = getopt(argc, argv, "i:u:c:t:f:h:p:u:g:lsv")) != -1) { switch (opt) { case 'i': id = optarg[0] - '0'; @@ -280,6 +262,10 @@ int main(int argc, char* argv[]) case 'p': cmd = PROTECT; break; + + case 'u': + cmd = UNPROTECT; + break; } break; @@ -351,8 +337,6 @@ int main(int argc, char* argv[]) } } - PbCommand command; - if (cmd == LOG_LEVEL) { CommandLogLevel(hostname, port, params); exit(0); @@ -369,47 +353,8 @@ int main(int argc, char* argv[]) exit(0); } - // Check the ID number - if (id < 0 || id > 7) { - cerr << __PRETTY_FUNCTION__ << " Error : Invalid ID " << id << endl; - exit(EINVAL); - } - - // Check the unit number - if (un < 0 || un > 1) { - cerr << __PRETTY_FUNCTION__ << " Error : Invalid UNIT " << un << endl; - exit(EINVAL); - } - - // Type Check - if (cmd == ATTACH && type == UNDEFINED) { - // Try to determine the file type from the extension - int len = params.length(); - if (len > 4 && params[len - 4] == '.') { - string ext = params.substr(len - 3); - if (ext == "hdf" || ext == "hds" || ext == "hdn" || ext == "hdi" || ext == "nhd" || ext == "hda") { - type = SASI_HD; - } else if (ext == "mos") { - type = MO; - } else if (ext == "iso") { - type = CD; - } - } - } - - // File check (command is ATTACH and type is HD, for CD and MO the medium (=file) may be inserted later) - if (cmd == ATTACH && (type == SASI_HD || type == SCSI_HD) && params.empty()) { - cerr << "Error : Invalid file path" << endl; - exit(EINVAL); - } - - // File check (command is INSERT) - if (cmd == INSERT && params.empty()) { - cerr << "Error : Invalid file path" << endl; - exit(EINVAL); - } - // Generate the command and send it + PbCommand command; command.set_id(id); command.set_un(un); command.set_cmd(cmd); @@ -419,10 +364,6 @@ int main(int argc, char* argv[]) } int fd = SendCommand(hostname, port, command); - if (fd < 0) { - exit(ENOTCONN); - } - bool status = ReceiveResult(fd); close(fd); diff --git a/src/raspberrypi/rasutil.cpp b/src/raspberrypi/rasutil.cpp index 8f6336f6..bd4b0b70 100644 --- a/src/raspberrypi/rasutil.cpp +++ b/src/raspberrypi/rasutil.cpp @@ -86,7 +86,8 @@ int ReadNBytes(int fd, uint8_t *buf, int n) // List devices // //--------------------------------------------------------------------------- -string ListDevices(const PbDevices& devices) { +string ListDevices(const PbDevices& devices) +{ ostringstream s; if (devices.devices_size()) { @@ -102,11 +103,64 @@ string ListDevices(const PbDevices& devices) { for (int i = 0; i < devices.devices_size() ; i++) { PbDevice device = devices.devices(i); - s << "| " << device.id() << " | " << device.un() << " | " << device.type() << " | " - << device.file() << (device.read_only() ? " (WRITEPROTECT)" : "") << endl; + s << "| " << device.id() << " | " << device.un() << " | " << MapTypeToId(device.type()) << " | " + << (device.file().empty() ? "NO MEDIA" : device.file()) + << (device.read_only() ? " (WRITEPROTECT)" : "") << endl; } s << "+----+----+------+-------------------------------------" << endl; return s.str(); } + +//--------------------------------------------------------------------------- +// +// Map the device ID to the PbDeviceType and vice versa +// +//--------------------------------------------------------------------------- + +PbDeviceType MapIdToType(const string& id, bool is_sasi) +{ + if (id == "SCHD") { + return is_sasi ? SASI_HD : SCSI_HD; + } + else if (id == "SCMO") { + return MO; + } + else if (id == "SCCD") { + return CD; + } + else if (id == "SCBR") { + return BR; + } + else if (id == "SCDP") { + return DAYNAPORT; + } + else { + return UNDEFINED; + } +} + +string MapTypeToId(const PbDeviceType type) +{ + switch (type) { + case SASI_HD: + case SCSI_HD: + return "SCHD"; + + case MO: + return "SCMO"; + + case CD: + return "SCCD"; + + case BR: + return "SCBR"; + + case DAYNAPORT: + return "SCDP"; + + default: + return "????"; + } +} diff --git a/src/raspberrypi/rasutil.h b/src/raspberrypi/rasutil.h index 9d974321..cfb3ea80 100644 --- a/src/raspberrypi/rasutil.h +++ b/src/raspberrypi/rasutil.h @@ -19,5 +19,7 @@ void SerializeMessage(int, const google::protobuf::MessageLite&); void DeserializeMessage(int, google::protobuf::MessageLite&); int ReadNBytes(int, uint8_t *, int); string ListDevices(const rascsi_interface::PbDevices&); +rascsi_interface::PbDeviceType MapIdToType(const string&, bool); +string MapTypeToId(const rascsi_interface::PbDeviceType); #endif