mirror of
https://github.com/akuker/RASCSI.git
synced 2025-02-20 00:29:18 +00:00
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:
parent
3d14950548
commit
0a5298b8ac
@ -54,6 +54,7 @@ Command is the operation being requested. options are:
|
|||||||
insert: insert media (Magneto-Optical and CD only)
|
insert: insert media (Magneto-Optical and CD only)
|
||||||
eject: eject media (Magneto-Optical and CD only)
|
eject: eject media (Magneto-Optical and CD only)
|
||||||
protect: Write protect the media (Magneto-Optical only)
|
protect: Write protect the media (Magneto-Optical only)
|
||||||
|
unprotect: Remove write protection from the media (Magneto-Optical only)
|
||||||
.IP
|
.IP
|
||||||
When the command is omitted, rasctl will default to the 'attach' command.
|
When the command is omitted, rasctl will default to the 'attach' command.
|
||||||
.TP
|
.TP
|
||||||
|
@ -6,8 +6,8 @@ NAME
|
|||||||
rasctl - Sends management commands to the rascsi process
|
rasctl - Sends management commands to the rascsi process
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
rasctl -l | -s | [-g LOG_LEVEL] [-h HOST] [-p PORT] -i ID [-c CMD] [-f
|
rasctl -l | -s | [-g LOG_LEVEL] [-h HOST] [-p PORT] [-v] -i ID [-c CMD]
|
||||||
FILE] [-t TYPE] [-u UNIT]
|
[-f FILE] [-t TYPE] [-u UNIT]
|
||||||
|
|
||||||
DESCRIPTION
|
DESCRIPTION
|
||||||
rasctl Sends commands to the rascsi process to make configuration ad‐
|
rasctl Sends commands to the rascsi process to make configuration ad‐
|
||||||
@ -34,7 +34,9 @@ OPTIONS
|
|||||||
-p PORT
|
-p PORT
|
||||||
The rascsi port to connect to, default is 6868.
|
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)
|
-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)
|
insert: insert media (Magneto-Optical and CD only)
|
||||||
eject: eject media (Magneto-Optical and CD only)
|
eject: eject media (Magneto-Optical and CD only)
|
||||||
protect: Write protect the media (Magneto-Optical 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'
|
When the command is omitted, rasctl will default to the 'attach'
|
||||||
command.
|
command.
|
||||||
|
|
||||||
-f FILE
|
-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.
|
lowable file types.
|
||||||
|
|
||||||
-t TYPE
|
-t TYPE
|
||||||
Specifies the type of disk. If this disagrees with the file ex‐
|
Specifies the type of disk. If this disagrees with the file ex‐
|
||||||
tension of the specified image, the TYPE argument is ignored.
|
tension of the specified image, the TYPE argument is ignored.
|
||||||
Available drive types are:
|
Available drive types are:
|
||||||
hd: Hard disk (SCSI or SASI)
|
hd: Hard disk (SCSI or SASI)
|
||||||
mo: Magneto-Optical disk)
|
mo: Magneto-Optical disk)
|
||||||
cd: CD-ROM
|
cd: CD-ROM
|
||||||
bridge: Bridge device (This is only applicable to the Sharp
|
bridge: Bridge device (This is only applicable to the Sharp
|
||||||
X68000)
|
X68000)
|
||||||
|
|
||||||
-u UNIT
|
-u UNIT
|
||||||
Unit number (0 or 1). This will default to 0. This option is
|
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
|
only used when there are multiple SCSI devices on a shared SCSI
|
||||||
controller. (This is not common)
|
controller. (This is not common)
|
||||||
|
|
||||||
EXAMPLES
|
EXAMPLES
|
||||||
|
@ -247,7 +247,7 @@ BOOL CTapDriver::Init()
|
|||||||
}
|
}
|
||||||
#endif // __NetBSD__
|
#endif // __NetBSD__
|
||||||
|
|
||||||
BOOL CTapDriver::OpenDump(const Filepath& path) {
|
const char *CTapDriver::OpenDump(const Filepath& path) {
|
||||||
if (m_pcap == NULL) {
|
if (m_pcap == NULL) {
|
||||||
m_pcap = pcap_open_dead(DLT_EN10MB, 65535);
|
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());
|
m_pcap_dumper = pcap_dump_open(m_pcap, path.GetPath());
|
||||||
if (m_pcap_dumper == NULL) {
|
if (m_pcap_dumper == NULL) {
|
||||||
LOGERROR("Error: can't open pcap file: %s", pcap_geterr(m_pcap));
|
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());
|
LOGTRACE("%s Opened %s for dumping", __PRETTY_FUNCTION__, path.GetPath());
|
||||||
return TRUE;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
@ -34,7 +34,7 @@ public:
|
|||||||
// Basic Functionality
|
// Basic Functionality
|
||||||
CTapDriver(); // Constructor
|
CTapDriver(); // Constructor
|
||||||
BOOL Init(); // Initilization
|
BOOL Init(); // Initilization
|
||||||
BOOL OpenDump(const Filepath& path);
|
const char *OpenDump(const Filepath& path);
|
||||||
// Capture packets
|
// Capture packets
|
||||||
void Cleanup(); // Cleanup
|
void Cleanup(); // Cleanup
|
||||||
void GetMacAddr(BYTE *mac); // Get Mac Address
|
void GetMacAddr(BYTE *mac); // Get Mac Address
|
||||||
|
@ -711,12 +711,16 @@ Disk::Disk(std::string id)
|
|||||||
|
|
||||||
// Work initialization
|
// Work initialization
|
||||||
disk.ready = FALSE;
|
disk.ready = FALSE;
|
||||||
disk.writep = FALSE;
|
disk.protectable = false;
|
||||||
disk.readonly = FALSE;
|
disk.writep = false;
|
||||||
disk.removable = FALSE;
|
disk.readonly = false;
|
||||||
disk.lock = FALSE;
|
disk.removable = false;
|
||||||
disk.attn = FALSE;
|
disk.removed = false;
|
||||||
disk.reset = FALSE;
|
disk.lockable = false;
|
||||||
|
disk.locked = false;
|
||||||
|
disk.supports_file = true;
|
||||||
|
disk.attn = false;
|
||||||
|
disk.reset = false;
|
||||||
disk.size = 0;
|
disk.size = 0;
|
||||||
disk.blocks = 0;
|
disk.blocks = 0;
|
||||||
disk.lun = 0;
|
disk.lun = 0;
|
||||||
@ -758,9 +762,9 @@ Disk::~Disk()
|
|||||||
void Disk::Reset()
|
void Disk::Reset()
|
||||||
{
|
{
|
||||||
// no lock, no attention, reset
|
// no lock, no attention, reset
|
||||||
disk.lock = FALSE;
|
disk.locked = false;
|
||||||
disk.attn = FALSE;
|
disk.attn = false;
|
||||||
disk.reset = TRUE;
|
disk.reset = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
@ -839,9 +843,10 @@ bool Disk::IsNuvolink() const
|
|||||||
//
|
//
|
||||||
// Open
|
// Open
|
||||||
// * Call as a post-process after successful opening in a derived class
|
// * 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.size >= 8) && (disk.size <= 11));
|
||||||
ASSERT(disk.blocks > 0);
|
ASSERT(disk.blocks > 0);
|
||||||
@ -851,54 +856,55 @@ BOOL Disk::Open(const Filepath& path, BOOL /*attn*/)
|
|||||||
|
|
||||||
// Cache initialization
|
// Cache initialization
|
||||||
ASSERT(!disk.dcache);
|
ASSERT(!disk.dcache);
|
||||||
disk.dcache =
|
disk.dcache = new DiskCache(path, disk.size, disk.blocks, disk.imgoffset);
|
||||||
new DiskCache(path, disk.size, disk.blocks, disk.imgoffset);
|
|
||||||
|
|
||||||
// Can read/write open
|
// Can read/write open
|
||||||
Fileio fio;
|
Fileio fio;
|
||||||
if (fio.Open(path, Fileio::ReadWrite)) {
|
if (fio.Open(path, Fileio::ReadWrite)) {
|
||||||
// Write permission, not read only
|
// Write permission, not read only
|
||||||
disk.writep = FALSE;
|
disk.writep = false;
|
||||||
disk.readonly = FALSE;
|
disk.readonly = false;
|
||||||
fio.Close();
|
fio.Close();
|
||||||
} else {
|
} else {
|
||||||
// Write protected, read only
|
// Write protected, read only
|
||||||
disk.writep = TRUE;
|
disk.writep = true;
|
||||||
disk.readonly = TRUE;
|
disk.readonly = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not locked
|
// Not locked, not removed
|
||||||
disk.lock = FALSE;
|
disk.locked = false;
|
||||||
|
disk.removed = false;
|
||||||
|
|
||||||
// Save path
|
// Save path
|
||||||
diskpath = path;
|
diskpath = path;
|
||||||
|
|
||||||
// Success
|
// Success
|
||||||
return TRUE;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// Eject
|
// 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
|
// Can only be ejected if it is removable
|
||||||
if (!disk.removable) {
|
if (!disk.removable) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If you're not ready, you don't need to eject
|
// If you're not ready, you don't need to eject
|
||||||
if (!disk.ready) {
|
if (!disk.ready) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must be unlocked if there is no force flag
|
// Must be unlocked if there is no force flag
|
||||||
if (!force) {
|
if (!force && disk.locked) {
|
||||||
if (disk.lock) {
|
return false;
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove disk cache
|
// Remove disk cache
|
||||||
@ -908,9 +914,12 @@ void Disk::Eject(BOOL force)
|
|||||||
|
|
||||||
// Not ready, no attention
|
// Not ready, no attention
|
||||||
disk.ready = FALSE;
|
disk.ready = FALSE;
|
||||||
disk.writep = FALSE;
|
disk.writep = false;
|
||||||
disk.readonly = FALSE;
|
disk.readonly = false;
|
||||||
disk.attn = FALSE;
|
disk.removed = true;
|
||||||
|
disk.attn = false;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
@ -918,21 +927,22 @@ void Disk::Eject(BOOL force)
|
|||||||
// Write Protected
|
// Write Protected
|
||||||
//
|
//
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
void Disk::WriteP(BOOL writep)
|
bool Disk::WriteP(bool writep)
|
||||||
{
|
{
|
||||||
// be ready
|
// be ready
|
||||||
if (!disk.ready) {
|
if (!disk.ready) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read Only, protect only
|
// Read Only, protect only
|
||||||
if (disk.readonly) {
|
if (disk.readonly && !writep) {
|
||||||
ASSERT(disk.writep);
|
return false;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write protect flag setting
|
// Write protect flag setting
|
||||||
disk.writep = writep;
|
disk.writep = writep;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
@ -971,7 +981,7 @@ BOOL Disk::CheckReady()
|
|||||||
// Not ready if reset
|
// Not ready if reset
|
||||||
if (disk.reset) {
|
if (disk.reset) {
|
||||||
disk.code = DISK_DEVRESET;
|
disk.code = DISK_DEVRESET;
|
||||||
disk.reset = FALSE;
|
disk.reset = false;
|
||||||
LOGTRACE("%s Disk in reset", __PRETTY_FUNCTION__);
|
LOGTRACE("%s Disk in reset", __PRETTY_FUNCTION__);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -979,7 +989,7 @@ BOOL Disk::CheckReady()
|
|||||||
// Not ready if it needs attention
|
// Not ready if it needs attention
|
||||||
if (disk.attn) {
|
if (disk.attn) {
|
||||||
disk.code = DISK_ATTENTION;
|
disk.code = DISK_ATTENTION;
|
||||||
disk.attn = FALSE;
|
disk.attn = false;
|
||||||
LOGTRACE("%s Disk in needs attention", __PRETTY_FUNCTION__);
|
LOGTRACE("%s Disk in needs attention", __PRETTY_FUNCTION__);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -1896,14 +1906,14 @@ BOOL Disk::StartStop(const DWORD *cdb)
|
|||||||
|
|
||||||
// Look at the eject bit and eject if necessary
|
// Look at the eject bit and eject if necessary
|
||||||
if (cdb[4] & 0x02) {
|
if (cdb[4] & 0x02) {
|
||||||
if (disk.lock) {
|
if (disk.locked) {
|
||||||
// Cannot be ejected because it is locked
|
// Cannot be ejected because it is locked
|
||||||
disk.code = DISK_PREVENT;
|
disk.code = DISK_PREVENT;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Eject
|
// Eject
|
||||||
Eject(FALSE);
|
Eject(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// OK
|
// OK
|
||||||
@ -1955,9 +1965,9 @@ BOOL Disk::Removal(const DWORD *cdb)
|
|||||||
|
|
||||||
// Set Lock flag
|
// Set Lock flag
|
||||||
if (cdb[4] & 0x01) {
|
if (cdb[4] & 0x01) {
|
||||||
disk.lock = TRUE;
|
disk.locked = true;
|
||||||
} else {
|
} else {
|
||||||
disk.lock = FALSE;
|
disk.locked = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// REMOVAL Success
|
// REMOVAL Success
|
||||||
|
@ -167,12 +167,17 @@ public:
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
std::string id; // Media ID
|
std::string id; // Media ID
|
||||||
BOOL ready; // Valid Disk
|
BOOL ready; // Valid Disk
|
||||||
BOOL writep; // Write protected
|
bool readonly; // Read only
|
||||||
BOOL readonly; // Read only
|
bool protectable;
|
||||||
BOOL removable; // Removable
|
bool writep; // Write protected
|
||||||
BOOL lock; // Locked
|
bool removable; // Removable
|
||||||
BOOL attn; // Attention
|
bool removed;
|
||||||
BOOL reset; // Reset
|
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
|
int size; // Sector Size
|
||||||
DWORD blocks; // Total number of sectors
|
DWORD blocks; // Total number of sectors
|
||||||
DWORD lun; // LUN
|
DWORD lun; // LUN
|
||||||
@ -198,15 +203,19 @@ public:
|
|||||||
bool IsNuvolink() const;
|
bool IsNuvolink() const;
|
||||||
|
|
||||||
// Media Operations
|
// 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 GetPath(Filepath& path) const; // Get the path
|
||||||
void Eject(BOOL force); // Eject
|
bool Eject(bool); // Eject
|
||||||
bool IsReady() const { return disk.ready; } // Ready check
|
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 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 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 IsAttn() const { return disk.attn; } // Get attention flag
|
||||||
bool Flush(); // Flush the cache
|
bool Flush(); // Flush the cache
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
SASIHD::SASIHD() : Disk("SAHD")
|
SASIHD::SASIHD() : Disk("SAHD")
|
||||||
{
|
{
|
||||||
|
disk.protectable = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
@ -41,7 +42,7 @@ SASIHD::SASIHD() : Disk("SAHD")
|
|||||||
void SASIHD::Reset()
|
void SASIHD::Reset()
|
||||||
{
|
{
|
||||||
// Unlock, clear attention
|
// Unlock, clear attention
|
||||||
disk.lock = FALSE;
|
disk.locked = FALSE;
|
||||||
disk.attn = FALSE;
|
disk.attn = FALSE;
|
||||||
|
|
||||||
// Reset, clear the code
|
// Reset, clear the code
|
||||||
@ -54,14 +55,14 @@ void SASIHD::Reset()
|
|||||||
// Open
|
// Open
|
||||||
//
|
//
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
BOOL SASIHD::Open(const Filepath& path, BOOL /*attn*/)
|
const char *SASIHD::Open(const Filepath& path, BOOL /*attn*/)
|
||||||
{
|
{
|
||||||
ASSERT(!disk.ready);
|
ASSERT(!disk.ready);
|
||||||
|
|
||||||
// Open as read-only
|
// Open as read-only
|
||||||
Fileio fio;
|
Fileio fio;
|
||||||
if (!fio.Open(path, Fileio::ReadOnly)) {
|
if (!fio.Open(path, Fileio::ReadOnly)) {
|
||||||
return FALSE;
|
return "Can't open hard disk file read-only";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get file size
|
// Get file size
|
||||||
@ -84,7 +85,7 @@ BOOL SASIHD::Open(const Filepath& path, BOOL /*attn*/)
|
|||||||
#if defined(REMOVE_FIXED_SASIHD_SIZE)
|
#if defined(REMOVE_FIXED_SASIHD_SIZE)
|
||||||
// Must be in 256-byte units
|
// Must be in 256-byte units
|
||||||
if (size & 0xff) {
|
if (size & 0xff) {
|
||||||
return FALSE;
|
return "File size must be a multiple of 512";
|
||||||
}
|
}
|
||||||
|
|
||||||
// 10MB or more
|
// 10MB or more
|
||||||
@ -94,7 +95,7 @@ BOOL SASIHD::Open(const Filepath& path, BOOL /*attn*/)
|
|||||||
|
|
||||||
// Limit to about 512MB
|
// Limit to about 512MB
|
||||||
if (size > 512 * 1024 * 1024) {
|
if (size > 512 * 1024 * 1024) {
|
||||||
return FALSE;
|
return "File size must not exceed 512 MB";
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
// 10MB, 20MB, 40MBのみ
|
// 10MB, 20MB, 40MBのみ
|
||||||
@ -113,7 +114,7 @@ BOOL SASIHD::Open(const Filepath& path, BOOL /*attn*/)
|
|||||||
|
|
||||||
// Other (Not supported )
|
// Other (Not supported )
|
||||||
default:
|
default:
|
||||||
return FALSE;
|
return "Unsupported file size";
|
||||||
}
|
}
|
||||||
#endif // REMOVE_FIXED_SASIHD_SIZE
|
#endif // REMOVE_FIXED_SASIHD_SIZE
|
||||||
|
|
||||||
|
@ -30,8 +30,8 @@ public:
|
|||||||
// Basic Functions
|
// Basic Functions
|
||||||
SASIHD(); // Constructor
|
SASIHD(); // Constructor
|
||||||
void Reset(); // Reset
|
void Reset(); // Reset
|
||||||
BOOL Open(const Filepath& path, BOOL attn = TRUE); // Open
|
const char *Open(const Filepath& path, BOOL attn = TRUE); // Open
|
||||||
|
|
||||||
// commands
|
// commands
|
||||||
int RequestSense(const DWORD *cdb, BYTE *buf); // REQUEST SENSE command
|
int RequestSense(const DWORD *cdb, BYTE *buf); // REQUEST SENSE command
|
||||||
};
|
};
|
||||||
|
@ -49,6 +49,8 @@ const BYTE SCSIDaynaPort::m_apple_talk_addr[6] = { 0x09, 0x00, 0x07, 0xff, 0xff,
|
|||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
SCSIDaynaPort::SCSIDaynaPort() : Disk("SCDP")
|
SCSIDaynaPort::SCSIDaynaPort() : Disk("SCDP")
|
||||||
{
|
{
|
||||||
|
disk.supports_file = false;
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
// TAP Driver Generation
|
// TAP Driver Generation
|
||||||
m_tap = new CTapDriver();
|
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");
|
LOGTRACE("SCSIDaynaPort Open");
|
||||||
return m_tap->OpenDump(path);
|
return m_tap->OpenDump(path);
|
||||||
|
@ -46,7 +46,7 @@ public:
|
|||||||
// Constructor
|
// Constructor
|
||||||
virtual ~SCSIDaynaPort();
|
virtual ~SCSIDaynaPort();
|
||||||
// Destructor
|
// Destructor
|
||||||
BOOL Open(const Filepath& path, BOOL attn = TRUE);
|
const char *Open(const Filepath& path, BOOL attn = TRUE);
|
||||||
// Capture packets
|
// Capture packets
|
||||||
|
|
||||||
// commands
|
// commands
|
||||||
|
@ -34,6 +34,8 @@
|
|||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
SCSIBR::SCSIBR() : Disk("SCBR")
|
SCSIBR::SCSIBR() : Disk("SCBR")
|
||||||
{
|
{
|
||||||
|
disk.supports_file = false;
|
||||||
|
|
||||||
fsoptlen = 0;
|
fsoptlen = 0;
|
||||||
fsoutlen = 0;
|
fsoutlen = 0;
|
||||||
fsresult = 0;
|
fsresult = 0;
|
||||||
|
@ -251,9 +251,9 @@ CDDABuf::~CDDABuf()
|
|||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
SCSICD::SCSICD() : Disk("SCCD")
|
SCSICD::SCSICD() : Disk("SCCD")
|
||||||
{
|
{
|
||||||
// removable, write protected
|
disk.removable = true;
|
||||||
disk.removable = TRUE;
|
disk.lockable = true;
|
||||||
disk.writep = TRUE;
|
disk.writep = true;
|
||||||
|
|
||||||
// NOT in raw format
|
// NOT in raw format
|
||||||
rawfile = FALSE;
|
rawfile = FALSE;
|
||||||
@ -286,7 +286,7 @@ SCSICD::~SCSICD()
|
|||||||
// Open
|
// Open
|
||||||
//
|
//
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
BOOL SCSICD::Open(const Filepath& path, BOOL attn)
|
const char *SCSICD::Open(const Filepath& path, BOOL attn)
|
||||||
{
|
{
|
||||||
Fileio fio;
|
Fileio fio;
|
||||||
off64_t size;
|
off64_t size;
|
||||||
@ -301,7 +301,7 @@ BOOL SCSICD::Open(const Filepath& path, BOOL attn)
|
|||||||
|
|
||||||
// Open as read-only
|
// Open as read-only
|
||||||
if (!fio.Open(path, Fileio::ReadOnly)) {
|
if (!fio.Open(path, Fileio::ReadOnly)) {
|
||||||
return FALSE;
|
return "Can't open CD-ROM file read-only";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close and transfer for physical CD access
|
// Close and transfer for physical CD access
|
||||||
@ -311,14 +311,14 @@ BOOL SCSICD::Open(const Filepath& path, BOOL attn)
|
|||||||
|
|
||||||
// Open physical CD
|
// Open physical CD
|
||||||
if (!OpenPhysical(path)) {
|
if (!OpenPhysical(path)) {
|
||||||
return FALSE;
|
return "Can't open physical CD";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Get file size
|
// Get file size
|
||||||
size = fio.GetFileSize();
|
size = fio.GetFileSize();
|
||||||
if (size <= 4) {
|
if (size <= 4) {
|
||||||
fio.Close();
|
fio.Close();
|
||||||
return FALSE;
|
return "Invalid file size";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Judge whether it is a CUE sheet or an ISO file
|
// 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) {
|
if (xstrncasecmp(file, _T("FILE"), 4) == 0) {
|
||||||
// Open as CUE
|
// Open as CUE
|
||||||
if (!OpenCue(path)) {
|
if (!OpenCue(path)) {
|
||||||
return FALSE;
|
return "Can't open as CUE";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Open as ISO
|
// Open as ISO
|
||||||
if (!OpenIso(path)) {
|
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;
|
disk.attn = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
@ -114,7 +114,7 @@ public:
|
|||||||
// Basic Functions
|
// Basic Functions
|
||||||
SCSICD(); // Constructor
|
SCSICD(); // Constructor
|
||||||
virtual ~SCSICD(); // Destructor
|
virtual ~SCSICD(); // Destructor
|
||||||
BOOL Open(const Filepath& path, BOOL attn = TRUE); // Open
|
const char *Open(const Filepath& path, BOOL attn = TRUE); // Open
|
||||||
|
|
||||||
// commands
|
// commands
|
||||||
int Inquiry(const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor); // INQUIRY command
|
int Inquiry(const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor); // INQUIRY command
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
SCSIHD::SCSIHD() : Disk("SCHD")
|
SCSIHD::SCSIHD() : Disk("SCHD")
|
||||||
{
|
{
|
||||||
|
disk.protectable = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
@ -40,7 +41,7 @@ SCSIHD::SCSIHD() : Disk("SCHD")
|
|||||||
void SCSIHD::Reset()
|
void SCSIHD::Reset()
|
||||||
{
|
{
|
||||||
// Unlock and release attention
|
// Unlock and release attention
|
||||||
disk.lock = FALSE;
|
disk.locked = FALSE;
|
||||||
disk.attn = FALSE;
|
disk.attn = FALSE;
|
||||||
|
|
||||||
// No reset, clear code
|
// No reset, clear code
|
||||||
@ -53,14 +54,14 @@ void SCSIHD::Reset()
|
|||||||
// Open
|
// Open
|
||||||
//
|
//
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
BOOL SCSIHD::Open(const Filepath& path, BOOL /*attn*/)
|
const char *SCSIHD::Open(const Filepath& path, BOOL /*attn*/)
|
||||||
{
|
{
|
||||||
ASSERT(!disk.ready);
|
ASSERT(!disk.ready);
|
||||||
|
|
||||||
// read open required
|
// read open required
|
||||||
Fileio fio;
|
Fileio fio;
|
||||||
if (!fio.Open(path, Fileio::ReadOnly)) {
|
if (!fio.Open(path, Fileio::ReadOnly)) {
|
||||||
return FALSE;
|
return "Can't open hard disk file read-only";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get file size
|
// Get file size
|
||||||
@ -69,13 +70,14 @@ BOOL SCSIHD::Open(const Filepath& path, BOOL /*attn*/)
|
|||||||
|
|
||||||
// Must be 512 bytes
|
// Must be 512 bytes
|
||||||
if (size & 0x1ff) {
|
if (size & 0x1ff) {
|
||||||
return FALSE;
|
return "File size must be a multiple of 512 bytes";
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2TB according to xm6i
|
// 2TB according to xm6i
|
||||||
// There is a similar one in wxw/wxw_cfg.cpp
|
// 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) {
|
if (size > 2LL * 1024 * 1024 * 1024 * 1024) {
|
||||||
return FALSE;
|
return "File size must not exceed 2 TB";
|
||||||
}
|
}
|
||||||
|
|
||||||
// sector size and number of blocks
|
// sector size and number of blocks
|
||||||
|
@ -30,9 +30,9 @@ public:
|
|||||||
// Basic Functions
|
// Basic Functions
|
||||||
SCSIHD(); // Constructor
|
SCSIHD(); // Constructor
|
||||||
void Reset(); // Reset
|
void Reset(); // Reset
|
||||||
BOOL Open(const Filepath& path, BOOL attn = TRUE); // Open
|
const char *Open(const Filepath& path, BOOL attn = TRUE); // Open
|
||||||
|
|
||||||
// commands
|
// commands
|
||||||
int Inquiry(const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor); // INQUIRY command
|
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
|
BOOL ModeSelect(const DWORD *cdb, const BYTE *buf, int length); // MODE SELECT(6) command
|
||||||
};
|
};
|
||||||
|
@ -65,7 +65,7 @@ static inline DWORD getDwordLE(const BYTE *b)
|
|||||||
// Open
|
// Open
|
||||||
//
|
//
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
BOOL SCSIHD_NEC::Open(const Filepath& path, BOOL /*attn*/)
|
const char *SCSIHD_NEC::Open(const Filepath& path, BOOL /*attn*/)
|
||||||
{
|
{
|
||||||
Fileio fio;
|
Fileio fio;
|
||||||
off64_t size;
|
off64_t size;
|
||||||
@ -76,7 +76,7 @@ BOOL SCSIHD_NEC::Open(const Filepath& path, BOOL /*attn*/)
|
|||||||
|
|
||||||
// Open as read-only
|
// Open as read-only
|
||||||
if (!fio.Open(path, Fileio::ReadOnly)) {
|
if (!fio.Open(path, Fileio::ReadOnly)) {
|
||||||
return FALSE;
|
return "Can't open hard disk file read-only";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get file size
|
// Get file size
|
||||||
@ -86,14 +86,14 @@ BOOL SCSIHD_NEC::Open(const Filepath& path, BOOL /*attn*/)
|
|||||||
if (size >= (off64_t)sizeof(hdr)) {
|
if (size >= (off64_t)sizeof(hdr)) {
|
||||||
if (!fio.Read(hdr, sizeof(hdr))) {
|
if (!fio.Read(hdr, sizeof(hdr))) {
|
||||||
fio.Close();
|
fio.Close();
|
||||||
return FALSE;
|
return "Can't read hard disk file header";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fio.Close();
|
fio.Close();
|
||||||
|
|
||||||
// Must be in 512 byte units
|
// Must be in 512 byte units
|
||||||
if (size & 0x1ff) {
|
if (size & 0x1ff) {
|
||||||
return FALSE;
|
return "File size must be a multiple of 512";
|
||||||
}
|
}
|
||||||
|
|
||||||
// 10MB or more
|
// 10MB or more
|
||||||
@ -102,7 +102,7 @@ BOOL SCSIHD_NEC::Open(const Filepath& path, BOOL /*attn*/)
|
|||||||
}
|
}
|
||||||
// 2TB according to xm6i
|
// 2TB according to xm6i
|
||||||
if (size > 2LL * 1024 * 1024 * 1024 * 1024) {
|
if (size > 2LL * 1024 * 1024 * 1024 * 1024) {
|
||||||
return FALSE;
|
return "File size must not exceed 2 TB";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine parameters by extension
|
// Determine parameters by extension
|
||||||
@ -136,12 +136,12 @@ BOOL SCSIHD_NEC::Open(const Filepath& path, BOOL /*attn*/)
|
|||||||
|
|
||||||
// Supports 256 or 512 sector sizes
|
// Supports 256 or 512 sector sizes
|
||||||
if (sectorsize != 256 && sectorsize != 512) {
|
if (sectorsize != 256 && sectorsize != 512) {
|
||||||
return FALSE;
|
return "Sector size must be 256 or 512";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Image size consistency check
|
// Image size consistency check
|
||||||
if (imgoffset + imgsize > size || (imgsize % sectorsize != 0)) {
|
if (imgoffset + imgsize > size || (imgsize % sectorsize != 0)) {
|
||||||
return FALSE;
|
return "Image size consistency check failed";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sector size
|
// Sector size
|
||||||
@ -150,7 +150,7 @@ BOOL SCSIHD_NEC::Open(const Filepath& path, BOOL /*attn*/)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (disk.size <= 0 || disk.size > 16) {
|
if (disk.size <= 0 || disk.size > 16) {
|
||||||
return FALSE;
|
return "Invalid disk size";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Number of blocks
|
// Number of blocks
|
||||||
|
@ -27,7 +27,7 @@ class SCSIHD_NEC : public SCSIHD
|
|||||||
public:
|
public:
|
||||||
// Basic Functions
|
// Basic Functions
|
||||||
SCSIHD_NEC(); // Constructor
|
SCSIHD_NEC(); // Constructor
|
||||||
BOOL Open(const Filepath& path, BOOL attn = TRUE); // Open
|
const char *Open(const Filepath& path, BOOL attn = TRUE); // Open
|
||||||
|
|
||||||
// commands
|
// commands
|
||||||
int Inquiry(const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor); // INQUIRY command
|
int Inquiry(const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor); // INQUIRY command
|
||||||
@ -44,4 +44,4 @@ private:
|
|||||||
int sectorsize; // Sector size
|
int sectorsize; // Sector size
|
||||||
off64_t imgoffset; // Image offset
|
off64_t imgoffset; // Image offset
|
||||||
off64_t imgsize; // Image size
|
off64_t imgsize; // Image size
|
||||||
};
|
};
|
||||||
|
@ -31,8 +31,9 @@
|
|||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
SCSIMO::SCSIMO() : Disk("SCMO")
|
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
|
// Open
|
||||||
//
|
//
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
BOOL SCSIMO::Open(const Filepath& path, BOOL attn)
|
const char *SCSIMO::Open(const Filepath& path, BOOL attn)
|
||||||
{
|
{
|
||||||
ASSERT(!disk.ready);
|
ASSERT(!disk.ready);
|
||||||
|
|
||||||
// Open as read-only
|
// Open as read-only
|
||||||
Fileio fio;
|
Fileio fio;
|
||||||
if (!fio.Open(path, Fileio::ReadOnly)) {
|
if (!fio.Open(path, Fileio::ReadOnly)) {
|
||||||
return FALSE;
|
return "Can't open MO file read-only";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get file size
|
// Get file size
|
||||||
@ -81,7 +82,7 @@ BOOL SCSIMO::Open(const Filepath& path, BOOL attn)
|
|||||||
|
|
||||||
// Other (this is an error)
|
// Other (this is an error)
|
||||||
default:
|
default:
|
||||||
return FALSE;
|
return "Invalid MO size";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call the base class
|
// Call the base class
|
||||||
@ -92,7 +93,7 @@ BOOL SCSIMO::Open(const Filepath& path, BOOL attn)
|
|||||||
disk.attn = TRUE;
|
disk.attn = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
@ -29,7 +29,7 @@ class SCSIMO : public Disk
|
|||||||
public:
|
public:
|
||||||
// Basic Functions
|
// Basic Functions
|
||||||
SCSIMO(); // Constructor
|
SCSIMO(); // Constructor
|
||||||
BOOL Open(const Filepath& path, BOOL attn = TRUE); // Open
|
const char *Open(const Filepath& path, BOOL attn = TRUE); // Open
|
||||||
|
|
||||||
// commands
|
// commands
|
||||||
int Inquiry(const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor); // INQUIRY command
|
int Inquiry(const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor); // INQUIRY command
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
//
|
//
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
#include "xm6.h"
|
#include "xm6.h"
|
||||||
#include "gpiobus.h"
|
#include "gpiobus.h"
|
||||||
|
@ -35,19 +35,16 @@
|
|||||||
//
|
//
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <cstdio>
|
||||||
#include <stdlib.h>
|
#include <cstdlib>
|
||||||
#include <stdint.h>
|
#include <cstddef>
|
||||||
#include <stddef.h>
|
#include <cstdarg>
|
||||||
#include <assert.h>
|
#include <cstring>
|
||||||
|
#include <csignal>
|
||||||
|
#include <cassert>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <errno.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <utime.h>
|
#include <utime.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <signal.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sched.h>
|
#include <sched.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <iconv.h>
|
#include <iconv.h>
|
||||||
@ -58,14 +55,13 @@
|
|||||||
|
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/epoll.h>
|
#include <sys/epoll.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <linux/gpio.h>
|
|
||||||
|
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
|
#include <linux/gpio.h>
|
||||||
#include <linux/if.h>
|
#include <linux/if.h>
|
||||||
#include <linux/if_tun.h>
|
#include <linux/if_tun.h>
|
||||||
#elif defined(__NetBSD__)
|
#elif defined(__NetBSD__)
|
||||||
|
@ -176,18 +176,24 @@ BOOL InitService(int port)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InitBusAndDisks() {
|
bool InitBus()
|
||||||
|
{
|
||||||
// GPIOBUS creation
|
// GPIOBUS creation
|
||||||
bus = new GPIOBUS();
|
bus = new GPIOBUS();
|
||||||
|
|
||||||
// GPIO Initialization
|
// GPIO Initialization
|
||||||
if (!bus->Init()) {
|
if (!bus->Init()) {
|
||||||
return FALSE;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bus Reset
|
// Bus Reset
|
||||||
bus->Reset();
|
bus->Reset();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitDisks()
|
||||||
|
{
|
||||||
// Controller initialization
|
// Controller initialization
|
||||||
for (int i = 0; i < CtrlMax; i++) {
|
for (int i = 0; i < CtrlMax; i++) {
|
||||||
ctrl[i] = NULL;
|
ctrl[i] = NULL;
|
||||||
@ -197,8 +203,6 @@ bool InitBusAndDisks() {
|
|||||||
for (int i = 0; i < CtrlMax; i++) {
|
for (int i = 0; i < CtrlMax; i++) {
|
||||||
disk[i] = NULL;
|
disk[i] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
@ -225,10 +229,12 @@ void Cleanup()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup the Bus
|
// Cleanup the Bus
|
||||||
bus->Cleanup();
|
if (bus) {
|
||||||
|
bus->Cleanup();
|
||||||
|
|
||||||
// Discard the GPIOBUS object
|
// Discard the GPIOBUS object
|
||||||
delete bus;
|
delete bus;
|
||||||
|
}
|
||||||
|
|
||||||
// Close the monitor socket
|
// Close the monitor socket
|
||||||
if (monsocket >= 0) {
|
if (monsocket >= 0) {
|
||||||
@ -278,7 +284,7 @@ PbDevices GetDevices() {
|
|||||||
device->set_un(i % UnitNum);
|
device->set_un(i % UnitNum);
|
||||||
|
|
||||||
// ID,UNIT,Type,Device Status
|
// ID,UNIT,Type,Device Status
|
||||||
device->set_type(pUnit->GetID());
|
device->set_type(MapIdToType(pUnit->GetID(), pUnit->IsSASI()));
|
||||||
|
|
||||||
// mount status output
|
// mount status output
|
||||||
if (pUnit->IsBridge()) {
|
if (pUnit->IsBridge()) {
|
||||||
@ -288,10 +294,16 @@ PbDevices GetDevices() {
|
|||||||
} else {
|
} else {
|
||||||
Filepath filepath;
|
Filepath filepath;
|
||||||
pUnit->GetPath(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_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
|
// Write protection status
|
||||||
if (pUnit->IsRemovable() && pUnit->IsReady() && pUnit->IsWriteP()) {
|
if (pUnit->IsRemovable() && pUnit->IsReady() && pUnit->IsWriteP()) {
|
||||||
@ -419,9 +431,11 @@ bool MapController(Disk **map)
|
|||||||
return status;
|
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 (fd == -1) {
|
||||||
if (msg.length()) {
|
if (msg.length()) {
|
||||||
|
FPRT(stderr, "Error: ");
|
||||||
FPRT(stderr, msg.c_str());
|
FPRT(stderr, msg.c_str());
|
||||||
FPRT(stderr, "\n");
|
FPRT(stderr, "\n");
|
||||||
}
|
}
|
||||||
@ -429,14 +443,20 @@ bool ReturnStatus(int fd, bool status = true, const string msg = "") {
|
|||||||
else {
|
else {
|
||||||
PbResult result;
|
PbResult result;
|
||||||
result.set_status(status);
|
result.set_status(status);
|
||||||
result.set_msg(msg + "\n");
|
result.set_msg(msg);
|
||||||
SerializeMessage(fd, result);
|
SerializeMessage(fd, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
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") {
|
if (log_level == "trace") {
|
||||||
set_level(level::trace);
|
set_level(level::trace);
|
||||||
}
|
}
|
||||||
@ -502,12 +522,12 @@ void GetAvailableImages(PbServerInfo& serverInfo)
|
|||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
bool ProcessCmd(int fd, const PbCommand &command)
|
bool ProcessCmd(int fd, const PbCommand &command)
|
||||||
{
|
{
|
||||||
Disk *map[CtrlMax * UnitNum];
|
|
||||||
Filepath filepath;
|
Filepath filepath;
|
||||||
Disk *pUnit;
|
Disk *pUnit;
|
||||||
char type_str[5];
|
ostringstream error;
|
||||||
|
const char *result;
|
||||||
|
|
||||||
int id = command.id();
|
int id = command.id();
|
||||||
int un = command.un();
|
int un = command.un();
|
||||||
PbOperation cmd = command.cmd();
|
PbOperation cmd = command.cmd();
|
||||||
PbDeviceType type = command.type();
|
PbDeviceType type = command.type();
|
||||||
@ -518,37 +538,53 @@ bool ProcessCmd(int fd, const PbCommand &command)
|
|||||||
LOGINFO("%s", s.str().c_str());
|
LOGINFO("%s", s.str().c_str());
|
||||||
|
|
||||||
// Copy the Unit List
|
// Copy the Unit List
|
||||||
|
Disk *map[CtrlMax * UnitNum];
|
||||||
memcpy(map, disk, sizeof(disk));
|
memcpy(map, disk, sizeof(disk));
|
||||||
|
|
||||||
// Check the Controller Number
|
// Check the Controller Number
|
||||||
if (id < 0 || id >= CtrlMax) {
|
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
|
// Check the Unit Number
|
||||||
if (un < 0 || un >= UnitNum) {
|
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
|
// Connect Command
|
||||||
if (cmd == ATTACH) {
|
if (cmd == ATTACH) {
|
||||||
string ext;
|
if (map[id]) {
|
||||||
|
error << "Duplicate ID " << id;
|
||||||
|
return ReturnStatus(fd, false, error);
|
||||||
|
}
|
||||||
|
|
||||||
// Distinguish between SASI and SCSI
|
// If no type was specified try to derive the file type from the extension
|
||||||
if (type == SASI_HD) {
|
if (type == UNDEFINED) {
|
||||||
// Check the extension
|
if (ext == "hdf") {
|
||||||
int len = params.length();
|
type = SASI_HD;
|
||||||
if (len < 5 || params[len - 4] != '.') {
|
|
||||||
return ReturnStatus(fd, false);
|
|
||||||
}
|
}
|
||||||
|
else if (ext == "hds" || ext == "hdn" || ext == "hdi" || ext == "nhd" || ext == "hda") {
|
||||||
// If the extension is not SASI type, replace with SCSI
|
|
||||||
ext = params.substr(len - 3);
|
|
||||||
if (ext != "hdf") {
|
|
||||||
type = SCSI_HD;
|
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
|
// Create a new drive, based upon type
|
||||||
pUnit = NULL;
|
pUnit = NULL;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@ -580,9 +616,8 @@ bool ProcessCmd(int fd, const PbCommand &command)
|
|||||||
pUnit = new SCSIDaynaPort();
|
pUnit = new SCSIDaynaPort();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ostringstream error;
|
error << "Received a command for an invalid drive type: " << PbDeviceType_Name(type);
|
||||||
error << "rasctl sent a command for an invalid drive type: " << PbDeviceType_Name(type);
|
return ReturnStatus(fd, false, error);
|
||||||
return ReturnStatus(fd, false, error.str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// drive checks files
|
// drive checks files
|
||||||
@ -594,25 +629,24 @@ bool ProcessCmd(int fd, const PbCommand &command)
|
|||||||
filepath.SetPath(file.c_str());
|
filepath.SetPath(file.c_str());
|
||||||
|
|
||||||
// Open the file path
|
// 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
|
// If the file does not exist search for it in the default image folder
|
||||||
string default_file = default_image_folder + "/" + file;
|
string default_file = default_image_folder + "/" + file;
|
||||||
filepath.SetPath(default_file.c_str());
|
filepath.SetPath(default_file.c_str());
|
||||||
if (!pUnit->Open(filepath)) {
|
result = pUnit->Open(filepath);
|
||||||
|
if (result) {
|
||||||
delete pUnit;
|
delete pUnit;
|
||||||
|
|
||||||
LOGWARN("rasctl tried to open an invalid file %s", file.c_str());
|
error << "Tried to open an invalid file '" << file << "': " << result;
|
||||||
|
LOGWARN("%s", error.str().c_str());
|
||||||
ostringstream error;
|
return ReturnStatus(fd, false, error);
|
||||||
error << "File open error [" << file << "]";
|
|
||||||
return ReturnStatus(fd, false, error.str());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (files_in_use.find(filepath.GetPath()) != files_in_use.end()) {
|
if (files_in_use.find(filepath.GetPath()) != files_in_use.end()) {
|
||||||
ostringstream error;
|
|
||||||
error << "Image file '" << file << "' is already in use";
|
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());
|
files_in_use.insert(filepath.GetPath());
|
||||||
@ -627,30 +661,30 @@ bool ProcessCmd(int fd, const PbCommand &command)
|
|||||||
// Re-map the controller
|
// Re-map the controller
|
||||||
bool status = MapController(map);
|
bool status = MapController(map);
|
||||||
if (status) {
|
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?
|
// Does the controller exist?
|
||||||
if (ctrl[id] == NULL) {
|
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?
|
// Does the unit exist?
|
||||||
pUnit = disk[id * UnitNum + un];
|
pUnit = disk[id * UnitNum + un];
|
||||||
if (pUnit == NULL) {
|
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
|
// Disconnect Command
|
||||||
if (cmd == DETACH) {
|
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
|
// Free the existing unit
|
||||||
map[id * UnitNum + un] = NULL;
|
map[id * UnitNum + un] = NULL;
|
||||||
@ -662,54 +696,69 @@ bool ProcessCmd(int fd, const PbCommand &command)
|
|||||||
// Re-map the controller
|
// Re-map the controller
|
||||||
bool status = MapController(map);
|
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
|
// Only MOs or CDs may be inserted/ejected, only MOs, CDs or hard disks may be protected
|
||||||
if (!pUnit->IsMo() && !pUnit->IsCdRom()) {
|
if ((cmd == INSERT || cmd == EJECT) && !pUnit->IsRemovable()) {
|
||||||
LOGWARN("rasctl sent an Insert/Eject/Protect command (%d) for incompatible type %s", cmd, pUnit->GetID().c_str());
|
LOGWARN("%s requested for incompatible type %s", PbOperation_Name(cmd).c_str(), pUnit->GetID().c_str());
|
||||||
|
|
||||||
ostringstream error;
|
error << "Operation denied (Device type " << pUnit->GetID().c_str() << " isn't removable)";
|
||||||
error << "Operation denied (Device type " << type_str << " isn't removable)";
|
return ReturnStatus(fd, false, error);
|
||||||
return ReturnStatus(fd, false, error.str());
|
}
|
||||||
|
|
||||||
|
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) {
|
switch (cmd) {
|
||||||
case INSERT:
|
case INSERT:
|
||||||
|
if (params.empty()) {
|
||||||
|
return ReturnStatus(fd, false, "Missing filename");
|
||||||
|
}
|
||||||
|
|
||||||
filepath.SetPath(params.c_str());
|
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)) {
|
result = pUnit->Open(filepath);
|
||||||
ostringstream error;
|
if (result) {
|
||||||
error << "File open error [" << params << "]";
|
// If the file does not exist search for it in the default image folder
|
||||||
|
string default_file = default_image_folder + "/" + params;
|
||||||
return ReturnStatus(fd, false, error.str());
|
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;
|
break;
|
||||||
|
|
||||||
case EJECT:
|
case EJECT:
|
||||||
LOGINFO("rasctl commanded eject for %s ID: %d UN: %d", pUnit->GetID().c_str(), id, un);
|
LOGINFO("Eject requested for %s ID: %d UN: %d", pUnit->GetID().c_str(), id, un);
|
||||||
pUnit->Eject(TRUE);
|
pUnit->Eject(true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PROTECT:
|
case PROTECT:
|
||||||
if (!pUnit->IsMo()) {
|
LOGINFO("Write protection requested for %s ID: %d UN: %d", pUnit->GetID().c_str(), id, un);
|
||||||
LOGWARN("rasctl sent an invalid PROTECT command 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)");
|
case UNPROTECT:
|
||||||
}
|
LOGINFO("Write unprotection requested for %s ID: %d UN: %d", pUnit->GetID().c_str(), id, un);
|
||||||
LOGINFO("rasctl is setting write protect to %d for %s ID: %d UN: %d",!pUnit->IsWriteP(), pUnit->GetID().c_str(), id, un);
|
pUnit->WriteP(false);
|
||||||
pUnit->WriteP(!pUnit->IsWriteP());
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ostringstream error;
|
error << "Received unknown command: " << PbOperation_Name(cmd);
|
||||||
error << "Received unknown command from rasctl: " << PbOperation_Name(cmd);
|
|
||||||
LOGWARN("%s", error.str().c_str());
|
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) {
|
bool has_suffix(const string& filename, const string& suffix) {
|
||||||
@ -788,32 +837,6 @@ bool ParseArgument(int argc, char* argv[], int& port)
|
|||||||
break;
|
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;
|
int un = 0;
|
||||||
if (is_sasi) {
|
if (is_sasi) {
|
||||||
un = id % UnitNum;
|
un = id % UnitNum;
|
||||||
@ -825,8 +848,7 @@ bool ParseArgument(int argc, char* argv[], int& port)
|
|||||||
command.set_id(id);
|
command.set_id(id);
|
||||||
command.set_un(un);
|
command.set_un(un);
|
||||||
command.set_cmd(ATTACH);
|
command.set_cmd(ATTACH);
|
||||||
command.set_type(type);
|
command.set_params(optarg);
|
||||||
command.set_params(path);
|
|
||||||
if (!ProcessCmd(-1, command)) {
|
if (!ProcessCmd(-1, command)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -920,7 +942,7 @@ static void *MonThread(void *param)
|
|||||||
if (!status) {
|
if (!status) {
|
||||||
ostringstream error;
|
ostringstream error;
|
||||||
error << "Invalid log level: " << command.params();
|
error << "Invalid log level: " << command.params();
|
||||||
ReturnStatus(fd, false, error.str());
|
ReturnStatus(fd, false, error);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ReturnStatus(fd);
|
ReturnStatus(fd);
|
||||||
@ -1003,16 +1025,18 @@ int main(int argc, char* argv[])
|
|||||||
int ret = 0;
|
int ret = 0;
|
||||||
int port = 6868;
|
int port = 6868;
|
||||||
|
|
||||||
if (!InitBusAndDisks()) {
|
InitDisks();
|
||||||
ret = EPERM;
|
|
||||||
goto init_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ParseArgument(argc, argv, port)) {
|
if (!ParseArgument(argc, argv, port)) {
|
||||||
ret = EINVAL;
|
ret = EINVAL;
|
||||||
goto err_exit;
|
goto err_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!InitBus()) {
|
||||||
|
ret = EPERM;
|
||||||
|
goto init_exit;
|
||||||
|
}
|
||||||
|
|
||||||
if (!InitService(port)) {
|
if (!InitService(port)) {
|
||||||
ret = EPERM;
|
ret = EPERM;
|
||||||
goto init_exit;
|
goto init_exit;
|
||||||
|
@ -18,13 +18,14 @@ enum PbDeviceType {
|
|||||||
enum PbOperation {
|
enum PbOperation {
|
||||||
NONE = 0;
|
NONE = 0;
|
||||||
SERVER_INFO = 1;
|
SERVER_INFO = 1;
|
||||||
LIST = 2;
|
LOG_LEVEL = 2;
|
||||||
ATTACH = 3;
|
LIST = 3;
|
||||||
DETACH = 4;
|
ATTACH = 4;
|
||||||
INSERT = 5;
|
DETACH = 5;
|
||||||
EJECT = 6;
|
INSERT = 6;
|
||||||
PROTECT = 7;
|
EJECT = 7;
|
||||||
LOG_LEVEL = 8;
|
PROTECT = 8;
|
||||||
|
UNPROTECT = 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Commands rascsi can execute
|
// Commands rascsi can execute
|
||||||
@ -42,14 +43,23 @@ message PbResult {
|
|||||||
string msg = 2;
|
string msg = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// The device meta data
|
// The device meta data
|
||||||
message PbDevice {
|
message PbDevice {
|
||||||
int32 id = 1;
|
int32 id = 1;
|
||||||
int32 un = 2;
|
int32 un = 2;
|
||||||
string type = 3;
|
PbDeviceType type = 3;
|
||||||
string file = 4;
|
string file = 4;
|
||||||
bool removable = 5;
|
bool read_only = 5;
|
||||||
bool read_only = 6;
|
// 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 {
|
message PbDevices {
|
||||||
|
@ -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);
|
memcpy(&server.sin_addr.s_addr, host->h_addr, host->h_length);
|
||||||
|
|
||||||
if (connect(fd, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0) {
|
if (connect(fd, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0) {
|
||||||
ostringstream s;
|
ostringstream error;
|
||||||
s << "Can't connect to rascsi process on host '" << hostname << "', port " << port;
|
error << "Can't connect to rascsi process on host '" << hostname << "', port " << port;
|
||||||
throw ioexception(s.str());
|
throw ioexception(error.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
SerializeMessage(fd, command);
|
SerializeMessage(fd, command);
|
||||||
@ -65,7 +65,7 @@ int SendCommand(const string& hostname, int port, const PbCommand& command)
|
|||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
exit(fd < 0 ? ENOTCONN : -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fd;
|
return fd;
|
||||||
@ -76,32 +76,26 @@ int SendCommand(const string& hostname, int port, const PbCommand& command)
|
|||||||
// Receive command result
|
// Receive command result
|
||||||
//
|
//
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
bool ReceiveResult(int fd) {
|
bool ReceiveResult(int fd)
|
||||||
bool status = true;
|
{
|
||||||
|
|
||||||
try {
|
try {
|
||||||
PbResult result;
|
PbResult result;
|
||||||
DeserializeMessage(fd, result);
|
DeserializeMessage(fd, result);
|
||||||
|
close(fd);
|
||||||
|
|
||||||
status = result.status();
|
if (!result.status()) {
|
||||||
if (status) {
|
throw ioexception(result.msg());
|
||||||
cerr << result.msg();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
cout << result.msg();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cout << result.msg() << endl;
|
||||||
}
|
}
|
||||||
catch(const ioexception& e) {
|
catch(const ioexception& e) {
|
||||||
cerr << "Error: " << e.getmsg() << endl;
|
cerr << "Error: " << e.getmsg() << endl;
|
||||||
|
|
||||||
// Fall through
|
return false;
|
||||||
|
|
||||||
status = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
close(fd);
|
return true;
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
@ -116,9 +110,6 @@ void CommandList(const string& hostname, int port)
|
|||||||
command.set_cmd(LIST);
|
command.set_cmd(LIST);
|
||||||
|
|
||||||
int fd = SendCommand(hostname.c_str(), port, command);
|
int fd = SendCommand(hostname.c_str(), port, command);
|
||||||
if (fd < 0) {
|
|
||||||
exit(ENOTCONN);
|
|
||||||
}
|
|
||||||
|
|
||||||
PbDevices devices;
|
PbDevices devices;
|
||||||
try {
|
try {
|
||||||
@ -144,12 +135,7 @@ void CommandLogLevel(const string& hostname, int port, const string& log_level)
|
|||||||
command.set_params(log_level);
|
command.set_params(log_level);
|
||||||
|
|
||||||
int fd = SendCommand(hostname.c_str(), port, command);
|
int fd = SendCommand(hostname.c_str(), port, command);
|
||||||
if (fd < 0) {
|
|
||||||
exit(ENOTCONN);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReceiveResult(fd);
|
ReceiveResult(fd);
|
||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,10 +145,6 @@ void CommandServerInfo(const string& hostname, int port)
|
|||||||
command.set_cmd(SERVER_INFO);
|
command.set_cmd(SERVER_INFO);
|
||||||
|
|
||||||
int fd = SendCommand(hostname.c_str(), port, command);
|
int fd = SendCommand(hostname.c_str(), port, command);
|
||||||
if (fd < 0) {
|
|
||||||
exit(ENOTCONN);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PbServerInfo serverInfo;
|
PbServerInfo serverInfo;
|
||||||
try {
|
try {
|
||||||
@ -178,18 +160,18 @@ void CommandServerInfo(const string& hostname, int port)
|
|||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
cout << "rascsi version: " << serverInfo.rascsi_version() << endl;
|
cout << "rascsi server version: " << serverInfo.rascsi_version() << endl;
|
||||||
|
|
||||||
if (!serverInfo.available_log_levels_size()) {
|
if (!serverInfo.available_log_levels_size()) {
|
||||||
cout << " No log level settings available" << endl;
|
cout << " No log level settings available" << endl;
|
||||||
}
|
}
|
||||||
else {
|
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++) {
|
for (int i = 0; i < serverInfo.available_log_levels_size(); i++) {
|
||||||
cout << " " << serverInfo.available_log_levels(i) << endl;
|
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;
|
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 << "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 << " where ID := {0|1|2|3|4|5|6|7}" << endl;
|
||||||
cerr << " UNIT := {0|1} default setting is 0." << 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 << " TYPE := {hd|mo|cd|bridge|daynaport}" << endl;
|
||||||
cerr << " FILE := image file path" << endl;
|
cerr << " FILE := image file path" << endl;
|
||||||
cerr << " HOST := rascsi host to connect to, default is 'localhost'" << 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;
|
int port = 6868;
|
||||||
string params;
|
string params;
|
||||||
opterr = 0;
|
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) {
|
switch (opt) {
|
||||||
case 'i':
|
case 'i':
|
||||||
id = optarg[0] - '0';
|
id = optarg[0] - '0';
|
||||||
@ -280,6 +262,10 @@ int main(int argc, char* argv[])
|
|||||||
case 'p':
|
case 'p':
|
||||||
cmd = PROTECT;
|
cmd = PROTECT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'u':
|
||||||
|
cmd = UNPROTECT;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -351,8 +337,6 @@ int main(int argc, char* argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PbCommand command;
|
|
||||||
|
|
||||||
if (cmd == LOG_LEVEL) {
|
if (cmd == LOG_LEVEL) {
|
||||||
CommandLogLevel(hostname, port, params);
|
CommandLogLevel(hostname, port, params);
|
||||||
exit(0);
|
exit(0);
|
||||||
@ -369,47 +353,8 @@ int main(int argc, char* argv[])
|
|||||||
exit(0);
|
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
|
// Generate the command and send it
|
||||||
|
PbCommand command;
|
||||||
command.set_id(id);
|
command.set_id(id);
|
||||||
command.set_un(un);
|
command.set_un(un);
|
||||||
command.set_cmd(cmd);
|
command.set_cmd(cmd);
|
||||||
@ -419,10 +364,6 @@ int main(int argc, char* argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
int fd = SendCommand(hostname, port, command);
|
int fd = SendCommand(hostname, port, command);
|
||||||
if (fd < 0) {
|
|
||||||
exit(ENOTCONN);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool status = ReceiveResult(fd);
|
bool status = ReceiveResult(fd);
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
|
@ -86,7 +86,8 @@ int ReadNBytes(int fd, uint8_t *buf, int n)
|
|||||||
// List devices
|
// List devices
|
||||||
//
|
//
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
string ListDevices(const PbDevices& devices) {
|
string ListDevices(const PbDevices& devices)
|
||||||
|
{
|
||||||
ostringstream s;
|
ostringstream s;
|
||||||
|
|
||||||
if (devices.devices_size()) {
|
if (devices.devices_size()) {
|
||||||
@ -102,11 +103,64 @@ string ListDevices(const PbDevices& devices) {
|
|||||||
for (int i = 0; i < devices.devices_size() ; i++) {
|
for (int i = 0; i < devices.devices_size() ; i++) {
|
||||||
PbDevice device = devices.devices(i);
|
PbDevice device = devices.devices(i);
|
||||||
|
|
||||||
s << "| " << device.id() << " | " << device.un() << " | " << device.type() << " | "
|
s << "| " << device.id() << " | " << device.un() << " | " << MapTypeToId(device.type()) << " | "
|
||||||
<< device.file() << (device.read_only() ? " (WRITEPROTECT)" : "") << endl;
|
<< (device.file().empty() ? "NO MEDIA" : device.file())
|
||||||
|
<< (device.read_only() ? " (WRITEPROTECT)" : "") << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
s << "+----+----+------+-------------------------------------" << endl;
|
s << "+----+----+------+-------------------------------------" << endl;
|
||||||
|
|
||||||
return s.str();
|
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 "????";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -19,5 +19,7 @@ void SerializeMessage(int, const google::protobuf::MessageLite&);
|
|||||||
void DeserializeMessage(int, google::protobuf::MessageLite&);
|
void DeserializeMessage(int, google::protobuf::MessageLite&);
|
||||||
int ReadNBytes(int, uint8_t *, int);
|
int ReadNBytes(int, uint8_t *, int);
|
||||||
string ListDevices(const rascsi_interface::PbDevices&);
|
string ListDevices(const rascsi_interface::PbDevices&);
|
||||||
|
rascsi_interface::PbDeviceType MapIdToType(const string&, bool);
|
||||||
|
string MapTypeToId(const rascsi_interface::PbDeviceType);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user