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,6 +46,8 @@ 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.

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 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,7 +30,7 @@ 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,7 +30,7 @@ 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

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

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
if (bus) {
bus->Cleanup();
// 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,10 +522,10 @@ 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 un = command.un();
@ -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;
// 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 (map[id]) {
error << "Duplicate ID " << id;
return ReturnStatus(fd, false, error);
}
// If the extension is not SASI type, replace with SCSI
ext = params.substr(len - 3);
if (ext != "hdf") {
// If no type was specified try to derive the file type from the extension
if (type == UNDEFINED) {
if (ext == "hdf") {
type = SASI_HD;
}
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