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 <akuker@gmail.com>
This commit is contained in:
Uwe Seimet 2021-08-08 17:08:58 +02:00 committed by GitHub
parent 3d14950548
commit 0a5298b8ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 382 additions and 321 deletions

View File

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

View File

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

View File

@ -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;
}
//---------------------------------------------------------------------------

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -34,6 +34,8 @@
//---------------------------------------------------------------------------
SCSIBR::SCSIBR() : Disk("SCBR")
{
disk.supports_file = false;
fsoptlen = 0;
fsoutlen = 0;
fsresult = 0;

View File

@ -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;
}
//---------------------------------------------------------------------------

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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;
}
//---------------------------------------------------------------------------

View File

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

View File

@ -12,6 +12,8 @@
//
//---------------------------------------------------------------------------
#include <sys/mman.h>
#include "os.h"
#include "xm6.h"
#include "gpiobus.h"

View File

@ -35,19 +35,16 @@
//
//---------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stddef.h>
#include <assert.h>
#include <cstdio>
#include <cstdlib>
#include <cstddef>
#include <cstdarg>
#include <cstring>
#include <csignal>
#include <cassert>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#include <utime.h>
#include <fcntl.h>
#include <signal.h>
#include <stdarg.h>
#include <string.h>
#include <sched.h>
#include <pthread.h>
#include <iconv.h>
@ -58,14 +55,13 @@
#include <poll.h>
#include <dirent.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <linux/gpio.h>
#if defined(__linux__)
#include <linux/gpio.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#elif defined(__NetBSD__)

View File

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

View File

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

View File

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

View File

@ -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 "????";
}
}

View File

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