mirror of
https://github.com/akuker/RASCSI.git
synced 2025-02-06 14:30:36 +00:00
Add statistics and make scsictl accept generic key/value parameters (#1237/#1238) (#1262)
* Add statistics and make scsictl accept generic key/value parameters
This commit is contained in:
parent
8f45e4f491
commit
b7cb23e391
@ -273,6 +273,9 @@ bool Disk::Eject(bool force)
|
||||
|
||||
// The image file for this drive is not in use anymore
|
||||
UnreserveFile();
|
||||
|
||||
sector_read_count = 0;
|
||||
sector_write_count = 0;
|
||||
}
|
||||
|
||||
return status;
|
||||
@ -506,6 +509,8 @@ int Disk::Read(span<uint8_t> buf, uint64_t block)
|
||||
throw scsi_exception(sense_key::medium_error, asc::read_fault);
|
||||
}
|
||||
|
||||
++sector_read_count;
|
||||
|
||||
return GetSectorSizeInBytes();
|
||||
}
|
||||
|
||||
@ -518,6 +523,8 @@ void Disk::Write(span<const uint8_t> buf, uint64_t block)
|
||||
if (!cache->WriteSector(buf, static_cast<uint32_t>(block))) {
|
||||
throw scsi_exception(sense_key::medium_error, asc::write_fault);
|
||||
}
|
||||
|
||||
++sector_write_count;
|
||||
}
|
||||
|
||||
void Disk::Seek()
|
||||
@ -711,3 +718,35 @@ bool Disk::SetConfiguredSectorSize(const DeviceFactory& device_factory, uint32_t
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
vector<PbStatistics> Disk::GetStatistics() const
|
||||
{
|
||||
vector<PbStatistics> statistics = PrimaryDevice::GetStatistics();
|
||||
|
||||
// Enrich cache statistics with device information before adding them to device statistics
|
||||
if (cache) {
|
||||
for (auto& s : cache->GetStatistics(IsReadOnly())) {
|
||||
s.set_id(GetId());
|
||||
s.set_unit(GetLun());
|
||||
statistics.push_back(s);
|
||||
}
|
||||
}
|
||||
|
||||
PbStatistics s;
|
||||
s.set_id(GetId());
|
||||
s.set_unit(GetLun());
|
||||
|
||||
s.set_category(PbStatisticsCategory::CATEGORY_INFO);
|
||||
|
||||
s.set_key(SECTOR_READ_COUNT);
|
||||
s.set_value(sector_read_count);
|
||||
statistics.push_back(s);
|
||||
|
||||
if (!IsReadOnly()) {
|
||||
s.set_key(SECTOR_WRITE_COUNT);
|
||||
s.set_value(sector_write_count);
|
||||
statistics.push_back(s);
|
||||
}
|
||||
|
||||
return statistics;
|
||||
}
|
||||
|
@ -8,7 +8,6 @@
|
||||
// XM6i
|
||||
// Copyright (C) 2010-2015 isaki@NetBSD.org
|
||||
//
|
||||
// Imported sava's Anex86/T98Next image and MO format support patch.
|
||||
// Comments translated to english by akuker.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
@ -16,6 +15,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "shared/scsi.h"
|
||||
#include "shared/piscsi_util.h"
|
||||
#include "device_factory.h"
|
||||
#include "disk_track.h"
|
||||
#include "disk_cache.h"
|
||||
@ -42,6 +42,12 @@ class Disk : public StorageDevice, private ScsiBlockCommands
|
||||
// Sector size shift count (9=512, 10=1024, 11=2048, 12=4096)
|
||||
uint32_t size_shift_count = 0;
|
||||
|
||||
uint64_t sector_read_count = 0;
|
||||
uint64_t sector_write_count = 0;
|
||||
|
||||
inline static const string SECTOR_READ_COUNT = "sector_read_count";
|
||||
inline static const string SECTOR_WRITE_COUNT = "sector_write_count";
|
||||
|
||||
public:
|
||||
|
||||
using StorageDevice::StorageDevice;
|
||||
@ -62,6 +68,8 @@ public:
|
||||
bool SetConfiguredSectorSize(const DeviceFactory&, uint32_t);
|
||||
void FlushCache() override;
|
||||
|
||||
vector<PbStatistics> GetStatistics() const override;
|
||||
|
||||
private:
|
||||
|
||||
// Commands covered by the SCSI specifications (see https://www.t10.org/drafts.htm)
|
||||
|
@ -27,11 +27,11 @@ DiskCache::DiskCache(const string& path, int size, uint32_t blocks, off_t imgoff
|
||||
assert(imgoff >= 0);
|
||||
}
|
||||
|
||||
bool DiskCache::Save() const
|
||||
bool DiskCache::Save()
|
||||
{
|
||||
// Save valid tracks
|
||||
return ranges::none_of(cache.begin(), cache.end(), [this](const cache_t& c)
|
||||
{ return c.disktrk != nullptr && !c.disktrk->Save(sec_path); });
|
||||
{ return c.disktrk != nullptr && !c.disktrk->Save(sec_path, cache_miss_write_count); });
|
||||
}
|
||||
|
||||
shared_ptr<DiskTrack> DiskCache::GetTrack(uint32_t block)
|
||||
@ -120,7 +120,7 @@ shared_ptr<DiskTrack> DiskCache::Assign(int track)
|
||||
}
|
||||
|
||||
// Save this track
|
||||
if (!cache[c].disktrk->Save(sec_path)) {
|
||||
if (!cache[c].disktrk->Save(sec_path, cache_miss_write_count)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -156,17 +156,16 @@ bool DiskCache::Load(int index, int track, shared_ptr<DiskTrack> disktrk)
|
||||
sectors = 0x100;
|
||||
}
|
||||
|
||||
// Create a disk track
|
||||
if (disktrk == nullptr) {
|
||||
disktrk = make_shared<DiskTrack>();
|
||||
}
|
||||
|
||||
// Initialize disk track
|
||||
disktrk->Init(track, sec_size, sectors, cd_raw, imgoffset);
|
||||
|
||||
// Try loading
|
||||
if (!disktrk->Load(sec_path)) {
|
||||
// Failure
|
||||
if (!disktrk->Load(sec_path, cache_miss_read_count)) {
|
||||
++read_error_count;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -190,3 +189,35 @@ void DiskCache::UpdateSerialNumber()
|
||||
}
|
||||
}
|
||||
|
||||
vector<PbStatistics> DiskCache::GetStatistics(bool is_read_only) const
|
||||
{
|
||||
vector<PbStatistics> statistics;
|
||||
|
||||
PbStatistics s;
|
||||
|
||||
s.set_category(PbStatisticsCategory::CATEGORY_INFO);
|
||||
|
||||
s.set_key(CACHE_MISS_READ_COUNT);
|
||||
s.set_value(cache_miss_read_count);
|
||||
statistics.push_back(s);
|
||||
|
||||
if (!is_read_only) {
|
||||
s.set_key(CACHE_MISS_WRITE_COUNT);
|
||||
s.set_value(cache_miss_write_count);
|
||||
statistics.push_back(s);
|
||||
}
|
||||
|
||||
s.set_category(PbStatisticsCategory::CATEGORY_ERROR);
|
||||
|
||||
s.set_key(READ_ERROR_COUNT);
|
||||
s.set_value(read_error_count);
|
||||
statistics.push_back(s);
|
||||
|
||||
if (!is_read_only) {
|
||||
s.set_key(WRITE_ERROR_COUNT);
|
||||
s.set_value(write_error_count);
|
||||
statistics.push_back(s);
|
||||
}
|
||||
|
||||
return statistics;
|
||||
}
|
||||
|
@ -15,18 +15,30 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "generated/piscsi_interface.pb.h"
|
||||
#include <span>
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
using namespace piscsi_interface;
|
||||
|
||||
class DiskCache
|
||||
{
|
||||
// Number of tracks to cache
|
||||
static const int CACHE_MAX = 16;
|
||||
|
||||
uint64_t read_error_count = 0;
|
||||
uint64_t write_error_count = 0;
|
||||
uint64_t cache_miss_read_count = 0;
|
||||
uint64_t cache_miss_write_count = 0;
|
||||
|
||||
inline static const string READ_ERROR_COUNT = "read_error_count";
|
||||
inline static const string WRITE_ERROR_COUNT = "write_error_count";
|
||||
inline static const string CACHE_MISS_READ_COUNT = "cache_miss_read_count";
|
||||
inline static const string CACHE_MISS_WRITE_COUNT = "cache_miss_write_count";
|
||||
|
||||
public:
|
||||
|
||||
// Internal data definition
|
||||
@ -40,11 +52,12 @@ public:
|
||||
|
||||
void SetRawMode(bool b) { cd_raw = b; } // CD-ROM raw mode setting
|
||||
|
||||
// Access
|
||||
bool Save() const; // Save and release all
|
||||
bool Save(); // Save and release all
|
||||
bool ReadSector(span<uint8_t>, uint32_t); // Sector Read
|
||||
bool WriteSector(span<const uint8_t>, uint32_t); // Sector Write
|
||||
|
||||
vector<PbStatistics> GetStatistics(bool) const;
|
||||
|
||||
private:
|
||||
|
||||
// Internal Management
|
||||
|
@ -48,7 +48,7 @@ void DiskTrack::Init(int track, int size, int sectors, bool raw, off_t imgoff)
|
||||
dt.imgoffset = imgoff;
|
||||
}
|
||||
|
||||
bool DiskTrack::Load(const string& path)
|
||||
bool DiskTrack::Load(const string& path, uint64_t& cache_miss_read_count)
|
||||
{
|
||||
// Not needed if already loaded
|
||||
if (dt.init) {
|
||||
@ -56,6 +56,8 @@ bool DiskTrack::Load(const string& path)
|
||||
return true;
|
||||
}
|
||||
|
||||
++cache_miss_read_count;
|
||||
|
||||
// Calculate offset (previous tracks are considered to hold 256 sectors)
|
||||
off_t offset = ((off_t)dt.track << 8);
|
||||
if (dt.raw) {
|
||||
@ -138,7 +140,7 @@ bool DiskTrack::Load(const string& path)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DiskTrack::Save(const string& path)
|
||||
bool DiskTrack::Save(const string& path, uint64_t& cache_miss_write_count)
|
||||
{
|
||||
// Not needed if not initialized
|
||||
if (!dt.init) {
|
||||
@ -150,6 +152,8 @@ bool DiskTrack::Save(const string& path)
|
||||
return true;
|
||||
}
|
||||
|
||||
++cache_miss_write_count;
|
||||
|
||||
// Need to write
|
||||
assert(dt.buffer);
|
||||
assert((dt.sectors > 0) && (dt.sectors <= 0x100));
|
||||
|
@ -50,10 +50,9 @@ private:
|
||||
friend class DiskCache;
|
||||
|
||||
void Init(int track, int size, int sectors, bool raw = false, off_t imgoff = 0);
|
||||
bool Load(const string& path);
|
||||
bool Save(const string& path);
|
||||
bool Load(const string& path, uint64_t&);
|
||||
bool Save(const string& path, uint64_t&);
|
||||
|
||||
// Read / Write
|
||||
bool ReadSector(span<uint8_t>, int) const; // Sector Read
|
||||
bool WriteSector(span<const uint8_t> buf, int); // Sector Write
|
||||
|
||||
|
@ -54,7 +54,13 @@ public:
|
||||
void Reset() override;
|
||||
|
||||
virtual void FlushCache() {
|
||||
// Devices with a cache have to implement this method
|
||||
// Devices with a cache have to override this method
|
||||
}
|
||||
|
||||
virtual vector<PbStatistics> GetStatistics() const {
|
||||
// Devices which provide statistics have to override this method
|
||||
|
||||
return vector<PbStatistics>();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -119,7 +119,7 @@ vector<uint8_t> SCSIDaynaPort::InquiryInternal() const
|
||||
// - The SCSI/Link apparently has about 6KB buffer space for packets.
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
int SCSIDaynaPort::Read(cdb_t cdb, vector<uint8_t>& buf, uint64_t) const
|
||||
int SCSIDaynaPort::Read(cdb_t cdb, vector<uint8_t>& buf, uint64_t)
|
||||
{
|
||||
int rx_packet_size = 0;
|
||||
const auto response = (scsi_resp_read_t*)buf.data();
|
||||
@ -155,6 +155,8 @@ int SCSIDaynaPort::Read(cdb_t cdb, vector<uint8_t>& buf, uint64_t) const
|
||||
return DAYNAPORT_READ_HEADER_SZ;
|
||||
}
|
||||
|
||||
byte_read_count += rx_packet_size * read_count;
|
||||
|
||||
LogTrace("Packet Size " + to_string(rx_packet_size) + ", read count: " + to_string(read_count));
|
||||
|
||||
// This is a very basic filter to prevent unnecessary packets from
|
||||
@ -252,17 +254,19 @@ int SCSIDaynaPort::Read(cdb_t cdb, vector<uint8_t>& buf, uint64_t) const
|
||||
// XX XX ... is the actual packet
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
bool SCSIDaynaPort::Write(cdb_t cdb, span<const uint8_t> buf) const
|
||||
bool SCSIDaynaPort::Write(cdb_t cdb, span<const uint8_t> buf)
|
||||
{
|
||||
if (const int data_format = cdb[5]; data_format == 0x00) {
|
||||
const int data_length = GetInt16(cdb, 3);
|
||||
tap.Send(buf.data(), data_length);
|
||||
byte_write_count += data_length;
|
||||
LogTrace("Transmitted " + to_string(data_length) + " byte(s) (00 format)");
|
||||
}
|
||||
else if (data_format == 0x80) {
|
||||
// The data length is specified in the first 2 bytes of the payload
|
||||
const int data_length = buf[1] + ((static_cast<int>(buf[0]) & 0xff) << 8);
|
||||
tap.Send(&(buf.data()[4]), data_length);
|
||||
byte_write_count += data_length;
|
||||
LogTrace("Transmitted " + to_string(data_length) + "byte(s) (80 format)");
|
||||
}
|
||||
else {
|
||||
@ -305,7 +309,7 @@ void SCSIDaynaPort::TestUnitReady()
|
||||
EnterStatusPhase();
|
||||
}
|
||||
|
||||
void SCSIDaynaPort::Read6() const
|
||||
void SCSIDaynaPort::Read6()
|
||||
{
|
||||
// Get record number and block number
|
||||
const uint32_t record = GetInt24(GetController()->GetCmd(), 1) & 0x1fffff;
|
||||
@ -478,3 +482,23 @@ void SCSIDaynaPort::EnableInterface() const
|
||||
EnterStatusPhase();
|
||||
}
|
||||
|
||||
vector<PbStatistics> SCSIDaynaPort::GetStatistics() const
|
||||
{
|
||||
vector<PbStatistics> statistics = PrimaryDevice::GetStatistics();
|
||||
|
||||
PbStatistics s;
|
||||
s.set_id(GetId());
|
||||
s.set_unit(GetLun());
|
||||
|
||||
s.set_category(PbStatisticsCategory::CATEGORY_INFO);
|
||||
|
||||
s.set_key(BYTE_READ_COUNT);
|
||||
s.set_value(byte_read_count);
|
||||
statistics.push_back(s);
|
||||
|
||||
s.set_key(BYTE_WRITE_COUNT);
|
||||
s.set_value(byte_write_count);
|
||||
statistics.push_back(s);
|
||||
|
||||
return statistics;
|
||||
}
|
||||
|
@ -44,6 +44,12 @@
|
||||
//===========================================================================
|
||||
class SCSIDaynaPort : public PrimaryDevice
|
||||
{
|
||||
uint64_t byte_read_count = 0;
|
||||
uint64_t byte_write_count = 0;
|
||||
|
||||
inline static const string BYTE_READ_COUNT = "byte_read_count";
|
||||
inline static const string BYTE_WRITE_COUNT = "byte_write_count";
|
||||
|
||||
public:
|
||||
|
||||
explicit SCSIDaynaPort(int);
|
||||
@ -56,19 +62,21 @@ public:
|
||||
|
||||
// Commands
|
||||
vector<uint8_t> InquiryInternal() const override;
|
||||
int Read(cdb_t, vector<uint8_t>&, uint64_t) const;
|
||||
bool Write(cdb_t, span<const uint8_t>) const;
|
||||
int Read(cdb_t, vector<uint8_t>&, uint64_t);
|
||||
bool Write(cdb_t, span<const uint8_t>);
|
||||
|
||||
int RetrieveStats(cdb_t, vector<uint8_t>&) const;
|
||||
|
||||
void TestUnitReady() override;
|
||||
void Read6() const;
|
||||
void Read6();
|
||||
void Write6() const;
|
||||
void RetrieveStatistics() const;
|
||||
void SetInterfaceMode() const;
|
||||
void SetMcastAddr() const;
|
||||
void EnableInterface() const;
|
||||
|
||||
vector<PbStatistics> GetStatistics() const override;
|
||||
|
||||
static const int DAYNAPORT_BUFFER_SIZE = 0x1000000;
|
||||
|
||||
static const int CMD_SCSILINK_STATS = 0x09;
|
||||
|
@ -115,6 +115,8 @@ void SCSIPrinter::Print()
|
||||
LogError("Transfer buffer overflow: Buffer size is " + to_string(GetController()->GetBuffer().size()) +
|
||||
" bytes, " + to_string(length) + " bytes expected");
|
||||
|
||||
++print_error_count;
|
||||
|
||||
throw scsi_exception(sense_key::illegal_request, asc::invalid_field_in_cdb);
|
||||
}
|
||||
|
||||
@ -129,6 +131,8 @@ void SCSIPrinter::SynchronizeBuffer()
|
||||
if (!out.is_open()) {
|
||||
LogWarn("Nothing to print");
|
||||
|
||||
++print_warning_count;
|
||||
|
||||
throw scsi_exception(sense_key::aborted_command);
|
||||
}
|
||||
|
||||
@ -145,6 +149,8 @@ void SCSIPrinter::SynchronizeBuffer()
|
||||
if (system(cmd.c_str())) {
|
||||
LogError("Printing file '" + filename + "' failed, the printing system might not be configured");
|
||||
|
||||
++print_error_count;
|
||||
|
||||
CleanUp();
|
||||
|
||||
throw scsi_exception(sense_key::aborted_command);
|
||||
@ -157,6 +163,8 @@ void SCSIPrinter::SynchronizeBuffer()
|
||||
|
||||
bool SCSIPrinter::WriteByteSequence(span<const uint8_t> buf)
|
||||
{
|
||||
byte_receive_count += buf.size();
|
||||
|
||||
if (!out.is_open()) {
|
||||
vector<char> f(file_template.begin(), file_template.end());
|
||||
f.push_back(0);
|
||||
@ -165,6 +173,9 @@ bool SCSIPrinter::WriteByteSequence(span<const uint8_t> buf)
|
||||
const int fd = mkstemp(f.data());
|
||||
if (fd == -1) {
|
||||
LogError("Can't create printer output file for pattern '" + filename + "': " + strerror(errno));
|
||||
|
||||
++print_error_count;
|
||||
|
||||
return false;
|
||||
}
|
||||
close(fd);
|
||||
@ -173,6 +184,8 @@ bool SCSIPrinter::WriteByteSequence(span<const uint8_t> buf)
|
||||
|
||||
out.open(filename, ios::binary);
|
||||
if (out.fail()) {
|
||||
++print_error_count;
|
||||
|
||||
throw scsi_exception(sense_key::aborted_command);
|
||||
}
|
||||
|
||||
@ -183,5 +196,43 @@ bool SCSIPrinter::WriteByteSequence(span<const uint8_t> buf)
|
||||
|
||||
out.write((const char *)buf.data(), buf.size());
|
||||
|
||||
return !out.fail();
|
||||
const bool status = out.fail();
|
||||
if (!status) {
|
||||
++print_error_count;
|
||||
}
|
||||
|
||||
return !status;
|
||||
}
|
||||
|
||||
vector<PbStatistics> SCSIPrinter::GetStatistics() const
|
||||
{
|
||||
vector<PbStatistics> statistics = PrimaryDevice::GetStatistics();
|
||||
|
||||
PbStatistics s;
|
||||
s.set_id(GetId());
|
||||
s.set_unit(GetLun());
|
||||
|
||||
s.set_category(PbStatisticsCategory::CATEGORY_INFO);
|
||||
|
||||
s.set_key(FILE_PRINT_COUNT);
|
||||
s.set_value(file_print_count);
|
||||
statistics.push_back(s);
|
||||
|
||||
s.set_key(BYTE_RECEIVE_COUNT);
|
||||
s.set_value(byte_receive_count);
|
||||
statistics.push_back(s);
|
||||
|
||||
s.set_category(PbStatisticsCategory::CATEGORY_ERROR);
|
||||
|
||||
s.set_key(PRINT_ERROR_COUNT);
|
||||
s.set_value(print_error_count);
|
||||
statistics.push_back(s);
|
||||
|
||||
s.set_category(PbStatisticsCategory::CATEGORY_WARNING);
|
||||
|
||||
s.set_key(PRINT_WARNING_COUNT);
|
||||
s.set_value(print_warning_count);
|
||||
statistics.push_back(s);
|
||||
|
||||
return statistics;
|
||||
}
|
||||
|
@ -21,10 +21,20 @@ using namespace std;
|
||||
|
||||
class SCSIPrinter : public PrimaryDevice, private ScsiPrinterCommands
|
||||
{
|
||||
uint64_t file_print_count = 0;
|
||||
uint64_t byte_receive_count = 0;
|
||||
uint64_t print_error_count = 0;
|
||||
uint64_t print_warning_count = 0;
|
||||
|
||||
static const int NOT_RESERVED = -2;
|
||||
|
||||
static constexpr const char *PRINTER_FILE_PATTERN = "/piscsi_sclp-XXXXXX";
|
||||
|
||||
inline static const string FILE_PRINT_COUNT = "file_print_count";
|
||||
inline static const string BYTE_RECEIVE_COUNT = "byte_receive_count";
|
||||
inline static const string PRINT_ERROR_COUNT = "print_error_count";
|
||||
inline static const string PRINT_WARNING_COUNT = "print_warning_count";
|
||||
|
||||
public:
|
||||
|
||||
explicit SCSIPrinter(int);
|
||||
@ -39,6 +49,8 @@ public:
|
||||
|
||||
bool WriteByteSequence(span<const uint8_t>) override;
|
||||
|
||||
vector<PbStatistics> GetStatistics() const override;
|
||||
|
||||
private:
|
||||
|
||||
void TestUnitReady() override;
|
||||
|
@ -357,9 +357,8 @@ bool Piscsi::ExecuteCommand(CommandContext& context)
|
||||
break;
|
||||
|
||||
case SERVER_INFO:
|
||||
response.GetServerInfo(*result.mutable_server_info(), controller_manager.GetAllDevices(),
|
||||
executor->GetReservedIds(), piscsi_image.GetDefaultFolder(),
|
||||
GetParam(command, "folder_pattern"), GetParam(command, "file_pattern"), piscsi_image.GetDepth());
|
||||
response.GetServerInfo(*result.mutable_server_info(), command, controller_manager.GetAllDevices(),
|
||||
executor->GetReservedIds(), piscsi_image.GetDefaultFolder(), piscsi_image.GetDepth());
|
||||
context.WriteSuccessResult(result);
|
||||
break;
|
||||
|
||||
@ -408,6 +407,11 @@ bool Piscsi::ExecuteCommand(CommandContext& context)
|
||||
context.WriteSuccessResult(result);
|
||||
break;
|
||||
|
||||
case STATISTICS_INFO:
|
||||
response.GetStatisticsInfo(*result.mutable_statistics_info(), controller_manager.GetAllDevices());
|
||||
context.WriteSuccessResult(result);
|
||||
break;
|
||||
|
||||
case OPERATION_INFO:
|
||||
response.GetOperationInfo(*result.mutable_operation_info(), piscsi_image.GetDepth());
|
||||
context.WriteSuccessResult(result);
|
||||
|
@ -227,19 +227,62 @@ void PiscsiResponse::GetDevicesInfo(const unordered_set<shared_ptr<PrimaryDevice
|
||||
result.set_status(true);
|
||||
}
|
||||
|
||||
void PiscsiResponse::GetServerInfo(PbServerInfo& server_info, const unordered_set<shared_ptr<PrimaryDevice>>& devices,
|
||||
const unordered_set<int>& reserved_ids, const string& default_folder, const string& folder_pattern,
|
||||
const string& file_pattern, int scan_depth) const
|
||||
void PiscsiResponse::GetServerInfo(PbServerInfo& server_info, const PbCommand& command,
|
||||
const unordered_set<shared_ptr<PrimaryDevice>>& devices, const unordered_set<int>& reserved_ids,
|
||||
const string& default_folder, int scan_depth) const
|
||||
{
|
||||
GetVersionInfo(*server_info.mutable_version_info());
|
||||
GetLogLevelInfo(*server_info.mutable_log_level_info());
|
||||
GetDeviceTypesInfo(*server_info.mutable_device_types_info());
|
||||
GetAvailableImages(server_info, default_folder, folder_pattern, file_pattern, scan_depth);
|
||||
GetNetworkInterfacesInfo(*server_info.mutable_network_interfaces_info());
|
||||
GetMappingInfo(*server_info.mutable_mapping_info());
|
||||
GetDevices(devices, server_info, default_folder);
|
||||
GetReservedIds(*server_info.mutable_reserved_ids_info(), reserved_ids);
|
||||
GetOperationInfo(*server_info.mutable_operation_info(), scan_depth);
|
||||
const vector<string> command_operations = Split(GetParam(command, "operations"), ',');
|
||||
set<string, less<>> operations;
|
||||
for (const string& operation : command_operations) {
|
||||
string op;
|
||||
ranges::transform(operation, back_inserter(op), ::toupper);
|
||||
operations.insert(op);
|
||||
}
|
||||
|
||||
if (!operations.empty()) {
|
||||
spdlog::trace("Requested operation(s): " + Join(operations, ","));
|
||||
}
|
||||
|
||||
if (HasOperation(operations, PbOperation::VERSION_INFO)) {
|
||||
GetVersionInfo(*server_info.mutable_version_info());
|
||||
}
|
||||
|
||||
if (HasOperation(operations, PbOperation::LOG_LEVEL_INFO)) {
|
||||
GetLogLevelInfo(*server_info.mutable_log_level_info());
|
||||
}
|
||||
|
||||
if (HasOperation(operations, PbOperation::DEVICE_TYPES_INFO)) {
|
||||
GetDeviceTypesInfo(*server_info.mutable_device_types_info());
|
||||
}
|
||||
|
||||
if (HasOperation(operations, PbOperation::DEFAULT_IMAGE_FILES_INFO)) {
|
||||
GetAvailableImages(server_info, default_folder, GetParam(command, "folder_pattern"),
|
||||
GetParam(command, "file_pattern"), scan_depth);
|
||||
}
|
||||
|
||||
if (HasOperation(operations, PbOperation::NETWORK_INTERFACES_INFO)) {
|
||||
GetNetworkInterfacesInfo(*server_info.mutable_network_interfaces_info());
|
||||
}
|
||||
|
||||
if (HasOperation(operations, PbOperation::MAPPING_INFO)) {
|
||||
GetMappingInfo(*server_info.mutable_mapping_info());
|
||||
}
|
||||
|
||||
if (HasOperation(operations, PbOperation::STATISTICS_INFO)) {
|
||||
GetStatisticsInfo(*server_info.mutable_statistics_info(), devices);
|
||||
}
|
||||
|
||||
if (HasOperation(operations, PbOperation::DEVICES_INFO)) {
|
||||
GetDevices(devices, server_info, default_folder);
|
||||
}
|
||||
|
||||
if (HasOperation(operations, PbOperation::RESERVED_IDS_INFO)) {
|
||||
GetReservedIds(*server_info.mutable_reserved_ids_info(), reserved_ids);
|
||||
}
|
||||
|
||||
if (HasOperation(operations, PbOperation::OPERATION_INFO)) {
|
||||
GetOperationInfo(*server_info.mutable_operation_info(), scan_depth);
|
||||
}
|
||||
}
|
||||
|
||||
void PiscsiResponse::GetVersionInfo(PbVersionInfo& version_info) const
|
||||
@ -272,6 +315,21 @@ void PiscsiResponse::GetMappingInfo(PbMappingInfo& mapping_info) const
|
||||
}
|
||||
}
|
||||
|
||||
void PiscsiResponse::GetStatisticsInfo(PbStatisticsInfo& statistics_info,
|
||||
const unordered_set<shared_ptr<PrimaryDevice>>& devices) const
|
||||
{
|
||||
for (const auto& device : devices) {
|
||||
for (const auto& statistics : device->GetStatistics()) {
|
||||
auto s = statistics_info.add_statistics();
|
||||
s->set_id(statistics.id());
|
||||
s->set_unit(statistics.unit());
|
||||
s->set_category(statistics.category());
|
||||
s->set_key(statistics.key());
|
||||
s->set_value(statistics.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PiscsiResponse::GetOperationInfo(PbOperationInfo& operation_info, int depth) const
|
||||
{
|
||||
auto operation = CreateOperation(operation_info, ATTACH, "Attach device, device-specific parameters are required");
|
||||
@ -324,6 +382,8 @@ void PiscsiResponse::GetOperationInfo(PbOperationInfo& operation_info, int depth
|
||||
|
||||
CreateOperation(operation_info, MAPPING_INFO, "Get mapping of extensions to device types");
|
||||
|
||||
CreateOperation(operation_info, STATISTICS_INFO, "Get statistics");
|
||||
|
||||
CreateOperation(operation_info, RESERVED_IDS_INFO, "Get list of reserved device IDs");
|
||||
|
||||
operation = CreateOperation(operation_info, DEFAULT_FOLDER, "Set default image file folder");
|
||||
@ -469,3 +529,8 @@ bool PiscsiResponse::FilterMatches(const string& input, string_view pattern_lowe
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PiscsiResponse::HasOperation(const set<string, less<>>& operations, PbOperation operation)
|
||||
{
|
||||
return operations.empty() || operations.contains(PbOperation_Name(operation));
|
||||
}
|
||||
|
@ -11,9 +11,11 @@
|
||||
|
||||
#include "devices/device_factory.h"
|
||||
#include "devices/primary_device.h"
|
||||
#include "shared/piscsi_util.h"
|
||||
#include "generated/piscsi_interface.pb.h"
|
||||
#include <string>
|
||||
#include <span>
|
||||
#include <set>
|
||||
|
||||
using namespace std;
|
||||
using namespace filesystem;
|
||||
@ -33,17 +35,19 @@ public:
|
||||
void GetDevicesInfo(const unordered_set<shared_ptr<PrimaryDevice>>&, PbResult&, const PbCommand&, const string&) const;
|
||||
void GetDeviceTypesInfo(PbDeviceTypesInfo&) const;
|
||||
void GetVersionInfo(PbVersionInfo&) const;
|
||||
void GetServerInfo(PbServerInfo&, const unordered_set<shared_ptr<PrimaryDevice>>&, const unordered_set<int>&,
|
||||
const string&, const string&, const string&, int) const;
|
||||
void GetServerInfo(PbServerInfo&, const PbCommand&, const unordered_set<shared_ptr<PrimaryDevice>>&,
|
||||
const unordered_set<int>&, const string&, int) const;
|
||||
void GetNetworkInterfacesInfo(PbNetworkInterfacesInfo&) const;
|
||||
void GetMappingInfo(PbMappingInfo&) const;
|
||||
void GetLogLevelInfo(PbLogLevelInfo&) const;
|
||||
void GetStatisticsInfo(PbStatisticsInfo&, const unordered_set<shared_ptr<PrimaryDevice>>&) const;
|
||||
void GetOperationInfo(PbOperationInfo&, int) const;
|
||||
|
||||
private:
|
||||
|
||||
inline static const vector<string> EMPTY_VECTOR;
|
||||
|
||||
// TODO Try to get rid of this field by having the device instead of the factory providing the device data
|
||||
const DeviceFactory device_factory;
|
||||
|
||||
void GetDeviceProperties(const Device&, PbDeviceProperties&) const;
|
||||
@ -59,4 +63,6 @@ private:
|
||||
static bool ValidateImageFile(const path&);
|
||||
|
||||
static bool FilterMatches(const string&, string_view);
|
||||
|
||||
static bool HasOperation(const set<string, less<>>&, PbOperation);
|
||||
};
|
||||
|
@ -82,9 +82,12 @@ enum PbOperation {
|
||||
// Make medium writable (not possible for read-only media)
|
||||
UNPROTECT = 9;
|
||||
|
||||
// Gets the server information (PbServerInfo). Calling this operation should be avoided because it
|
||||
// may return a lot of data. More specific other operations should be used instead.
|
||||
// Gets the server information (PbServerInfo). Calling this operation without a list of operations should
|
||||
// be avoided because this may return a lot of data. More specific other operations should be used instead.
|
||||
// Parameters:
|
||||
// "operations": Optional case insensitive comma-separated list of operation names to return data for,
|
||||
// e.g. "version_info,log_level_info". Unknown operation names are ignored. If this parameter is missing
|
||||
// the full set of data supported by PbServerInfo is returned.
|
||||
// "folder_pattern": Optional filter, only folder names containing the case-insensitive pattern are returned
|
||||
// "file_pattern": Optional filter, only filenames containing the case-insensitive pattern are returned
|
||||
SERVER_INFO = 10;
|
||||
@ -190,6 +193,9 @@ enum PbOperation {
|
||||
|
||||
// Get operation meta data (PbOperationInfo)
|
||||
OPERATION_INFO = 31;
|
||||
|
||||
// Get statistics (PbStatisticsInfo)
|
||||
STATISTICS_INFO = 32;
|
||||
}
|
||||
|
||||
// The operation parameter meta data. The parameter data type is provided by the protobuf API.
|
||||
@ -286,7 +292,7 @@ message PbImageFile {
|
||||
string name = 1;
|
||||
// The assumed device type, based on the filename extension
|
||||
PbDeviceType type = 2;
|
||||
// The file size in bytes, 0 for block devices
|
||||
// The file size in bytes, 0 for block devices in /dev
|
||||
uint64 size = 3;
|
||||
bool read_only = 4;
|
||||
}
|
||||
@ -311,6 +317,41 @@ message PbNetworkInterfacesInfo {
|
||||
repeated string name = 1;
|
||||
}
|
||||
|
||||
// Statistics categories ordered by increasing severity
|
||||
enum PbStatisticsCategory {
|
||||
CATEGORY_NONE = 0;
|
||||
CATEGORY_INFO = 1;
|
||||
CATEGORY_WARNING = 2;
|
||||
CATEGORY_ERROR = 3;
|
||||
}
|
||||
|
||||
message PbStatistics {
|
||||
PbStatisticsCategory category = 1;
|
||||
// The device ID and LUN for this statistics item. Both are -1 if the item is not device specific.
|
||||
int32 id = 2;
|
||||
int32 unit = 3;
|
||||
// A symbolic unique item name, may be used for I18N. Supported values and their categories:
|
||||
// "read_error_count" (ERROR, SCHD/SCRM/SCMO/SCCD)
|
||||
// "write_error_count" (ERROR, SCHD/SCRM/SCMO)
|
||||
// "cache_miss_read_count" (INFO, SCHD/SCRM/SCMO/SCCD)
|
||||
// "cache_miss_write_count" (INFO, SCHD/SCRM/SCMO)
|
||||
// "sector_read_count" (INFO, SCHD/SCRM/SCMO/SCCD)
|
||||
// "sector_write_count" (INFO, SCHD/SCRM/SCMO)
|
||||
// "byte_read_count" (INFO, SCDP)
|
||||
// "byte_write_count" (INFO, SCDP)
|
||||
// "print_error_count" (ERROR, SCLP)
|
||||
// "print_warning_count" (WARNING, SCLP)
|
||||
// "file_print_count" (INFO, SCLP)
|
||||
// "byte_receive_count" (INFO, SCLP)
|
||||
string key = 4;
|
||||
uint64 value = 5;
|
||||
}
|
||||
|
||||
// The information on collected statistics
|
||||
message PbStatisticsInfo {
|
||||
repeated PbStatistics statistics = 1;
|
||||
}
|
||||
|
||||
// The device definition, sent from the client to the server
|
||||
message PbDeviceDefinition {
|
||||
int32 id = 1;
|
||||
@ -407,6 +448,8 @@ message PbResult {
|
||||
PbReservedIdsInfo reserved_ids_info = 12;
|
||||
// The result of an OPERATION_INFO command
|
||||
PbOperationInfo operation_info = 13;
|
||||
// The result of a STATISTICS_INFO command
|
||||
PbStatisticsInfo statistics_info = 15;
|
||||
}
|
||||
}
|
||||
|
||||
@ -430,4 +473,6 @@ message PbServerInfo {
|
||||
PbDevicesInfo devices_info = 8;
|
||||
// The operation meta data
|
||||
PbOperationInfo operation_info = 9;
|
||||
// The statistics
|
||||
PbStatisticsInfo statistics_info = 10;
|
||||
}
|
||||
|
@ -81,6 +81,9 @@ bool ScsictlCommands::Execute(string_view log_level, string_view default_folder,
|
||||
case MAPPING_INFO:
|
||||
return CommandMappingInfo();
|
||||
|
||||
case STATISTICS_INFO:
|
||||
return CommandStatisticsInfo();
|
||||
|
||||
case OPERATION_INFO:
|
||||
return CommandOperationInfo();
|
||||
|
||||
@ -245,16 +248,43 @@ bool ScsictlCommands::CommandServerInfo()
|
||||
|
||||
PbServerInfo server_info = result.server_info();
|
||||
|
||||
cout << scsictl_display.DisplayVersionInfo(server_info.version_info());
|
||||
cout << scsictl_display.DisplayLogLevelInfo(server_info.log_level_info());
|
||||
cout << scsictl_display.DisplayImageFilesInfo(server_info.image_files_info());
|
||||
cout << scsictl_display.DisplayMappingInfo(server_info.mapping_info());
|
||||
cout << scsictl_display.DisplayNetworkInterfaces(server_info.network_interfaces_info());
|
||||
cout << scsictl_display.DisplayDeviceTypesInfo(server_info.device_types_info());
|
||||
cout << scsictl_display.DisplayReservedIdsInfo(server_info.reserved_ids_info());
|
||||
cout << scsictl_display.DisplayOperationInfo(server_info.operation_info());
|
||||
if (server_info.has_version_info()) {
|
||||
cout << scsictl_display.DisplayVersionInfo(server_info.version_info());
|
||||
}
|
||||
|
||||
if (server_info.devices_info().devices_size()) {
|
||||
if (server_info.has_log_level_info()) {
|
||||
cout << scsictl_display.DisplayLogLevelInfo(server_info.log_level_info());
|
||||
}
|
||||
|
||||
if (server_info.has_image_files_info()) {
|
||||
cout << scsictl_display.DisplayImageFilesInfo(server_info.image_files_info());
|
||||
}
|
||||
|
||||
if (server_info.has_mapping_info()) {
|
||||
cout << scsictl_display.DisplayMappingInfo(server_info.mapping_info());
|
||||
}
|
||||
|
||||
if (server_info.has_network_interfaces_info()) {
|
||||
cout << scsictl_display.DisplayNetworkInterfaces(server_info.network_interfaces_info());
|
||||
}
|
||||
|
||||
if (server_info.has_device_types_info()) {
|
||||
cout << scsictl_display.DisplayDeviceTypesInfo(server_info.device_types_info());
|
||||
}
|
||||
|
||||
if (server_info.has_reserved_ids_info()) {
|
||||
cout << scsictl_display.DisplayReservedIdsInfo(server_info.reserved_ids_info());
|
||||
}
|
||||
|
||||
if (server_info.has_statistics_info()) {
|
||||
cout << scsictl_display.DisplayStatisticsInfo(server_info.statistics_info());
|
||||
}
|
||||
|
||||
if (server_info.has_operation_info()) {
|
||||
cout << scsictl_display.DisplayOperationInfo(server_info.operation_info());
|
||||
}
|
||||
|
||||
if (server_info.has_devices_info() && server_info.devices_info().devices_size()) {
|
||||
vector<PbDevice> sorted_devices = { server_info.devices_info().devices().begin(), server_info.devices_info().devices().end() };
|
||||
ranges::sort(sorted_devices, [](const auto& a, const auto& b) { return a.id() < b.id() || a.unit() < b.unit(); });
|
||||
|
||||
@ -326,6 +356,15 @@ bool ScsictlCommands::CommandMappingInfo()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ScsictlCommands::CommandStatisticsInfo()
|
||||
{
|
||||
SendCommand();
|
||||
|
||||
cout << scsictl_display.DisplayStatisticsInfo(result.statistics_info()) << flush;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ScsictlCommands::CommandOperationInfo()
|
||||
{
|
||||
SendCommand();
|
||||
|
@ -48,6 +48,7 @@ private:
|
||||
bool CommandLogLevelInfo();
|
||||
bool CommandReservedIdsInfo();
|
||||
bool CommandMappingInfo();
|
||||
bool CommandStatisticsInfo();
|
||||
bool CommandOperationInfo();
|
||||
bool SendCommand();
|
||||
bool EvaluateParams(string_view, const string&, const string&);
|
||||
|
@ -35,7 +35,7 @@ void ScsiCtl::Banner(const vector<char *>& args) const
|
||||
<< "[-F IMAGE_FOLDER] [-L LOG_LEVEL] [-h HOST] [-p PORT] [-r RESERVED_IDS] "
|
||||
<< "[-C FILENAME:FILESIZE] [-d FILENAME] [-w FILENAME] [-R CURRENT_NAME:NEW_NAME] "
|
||||
<< "[-x CURRENT_NAME:NEW_NAME] [-z LOCALE] "
|
||||
<< "[-e] [-E FILENAME] [-D] [-I] [-l] [-m] [o] [-O] [-P] [-s] [-v] [-V] [-y] [-X]\n"
|
||||
<< "[-e] [-E FILENAME] [-D] [-I] [-l] [-m] [o] [-O] [-P] [-s] [-S] [-v] [-V] [-y] [-X]\n"
|
||||
<< " where ID[:LUN] ID := {0-" << (ControllerManager::GetScsiIdMax() - 1) << "},"
|
||||
<< " LUN := {0-" << (ControllerManager::GetScsiLunMax() - 1) << "}, default is 0\n"
|
||||
<< " CMD := {attach|detach|insert|eject|protect|unprotect|show}\n"
|
||||
@ -82,7 +82,7 @@ int ScsiCtl::run(const vector<char *>& args) const
|
||||
opterr = 1;
|
||||
int opt;
|
||||
while ((opt = getopt(static_cast<int>(args.size()), args.data(),
|
||||
"e::lmos::vDINOTVXa:b:c:d:f:h:i:n:p:r:t:x:z:C:E:F:L:P::R:")) != -1) {
|
||||
"e::lmos::vDINOSTVXa:b:c:d:f:h:i:n:p:r:t:x:z:C:E:F:L:P::R:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'i':
|
||||
if (const string error = SetIdAndLun(*device, optarg); !error.empty()) {
|
||||
@ -130,7 +130,7 @@ int ScsiCtl::run(const vector<char *>& args) const
|
||||
case 'e':
|
||||
command.set_operation(DEFAULT_IMAGE_FILES_INFO);
|
||||
if (optarg) {
|
||||
SetPatternParams(command, optarg);
|
||||
SetCommandParams(command, optarg);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -208,10 +208,14 @@ int ScsiCtl::run(const vector<char *>& args) const
|
||||
case 's':
|
||||
command.set_operation(SERVER_INFO);
|
||||
if (optarg) {
|
||||
SetPatternParams(command, optarg);
|
||||
SetCommandParams(command, optarg);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
command.set_operation(STATISTICS_INFO);
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
cout << "scsictl version: " << piscsi_get_version_string() << '\n';
|
||||
exit(EXIT_SUCCESS);
|
||||
|
@ -231,6 +231,38 @@ string ScsictlDisplay::DisplayMappingInfo(const PbMappingInfo& mapping_info) con
|
||||
return s.str();
|
||||
}
|
||||
|
||||
string ScsictlDisplay::DisplayStatisticsInfo(const PbStatisticsInfo& statistics_info) const
|
||||
{
|
||||
ostringstream s;
|
||||
|
||||
s << "Statistics:\n";
|
||||
|
||||
// Sort by ascending ID, LUN and key and by descending category
|
||||
vector<PbStatistics> sorted_statistics = { statistics_info.statistics().begin(), statistics_info.statistics().end() };
|
||||
ranges::sort(sorted_statistics, [] (const PbStatistics& a, const PbStatistics& b) {
|
||||
if (a.category() > b.category()) return true;
|
||||
if (a.category() < b.category()) return false;
|
||||
if (a.id() < b.id()) return true;
|
||||
if (a.id() > b.id()) return false;
|
||||
if (a.unit() < b.unit()) return true;
|
||||
if (a.unit() > b.unit()) return false;
|
||||
return a.key() < b.key();
|
||||
});
|
||||
|
||||
PbStatisticsCategory prev_category = PbStatisticsCategory::CATEGORY_NONE;
|
||||
for (const auto& statistics : sorted_statistics) {
|
||||
if (statistics.category() != prev_category) {
|
||||
// Strip leading "CATEGORY_"
|
||||
s << " " << PbStatisticsCategory_Name(statistics.category()).substr(9) << '\n';
|
||||
prev_category = statistics.category();
|
||||
}
|
||||
|
||||
s << " " << statistics.id() << ":" << statistics.unit() << " " << statistics.key() << ": " << statistics.value() << '\n';
|
||||
}
|
||||
|
||||
return s.str();
|
||||
}
|
||||
|
||||
string ScsictlDisplay::DisplayOperationInfo(const PbOperationInfo& operation_info) const
|
||||
{
|
||||
ostringstream s;
|
||||
|
@ -32,6 +32,7 @@ public:
|
||||
string DisplayImageFilesInfo(const PbImageFilesInfo&) const;
|
||||
string DisplayNetworkInterfaces(const PbNetworkInterfacesInfo&) const;
|
||||
string DisplayMappingInfo(const PbMappingInfo&) const;
|
||||
string DisplayStatisticsInfo(const PbStatisticsInfo&) const;
|
||||
string DisplayOperationInfo(const PbOperationInfo&) const;
|
||||
|
||||
private:
|
||||
|
@ -42,21 +42,33 @@ void protobuf_util::ParseParameters(PbDeviceDefinition& device, const string& pa
|
||||
}
|
||||
}
|
||||
|
||||
void protobuf_util::SetPatternParams(PbCommand& command, const string& patterns)
|
||||
void protobuf_util::SetCommandParams(PbCommand& command, const string& params)
|
||||
{
|
||||
string folder_pattern;
|
||||
string file_pattern;
|
||||
string operations;
|
||||
|
||||
if (const auto& components = Split(patterns, ':', 2); components.size() == 2) {
|
||||
folder_pattern = components[0];
|
||||
file_pattern = components[1];
|
||||
}
|
||||
else {
|
||||
file_pattern = patterns;
|
||||
switch (const auto& components = Split(params, COMPONENT_SEPARATOR, 3); components.size()) {
|
||||
case 3:
|
||||
operations = components[2];
|
||||
[[fallthrough]];
|
||||
|
||||
case 2:
|
||||
folder_pattern = components[0];
|
||||
file_pattern = components[1];
|
||||
break;
|
||||
|
||||
case 1:
|
||||
file_pattern = components[0];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
SetParam(command, "folder_pattern", folder_pattern);
|
||||
SetParam(command, "file_pattern", file_pattern);
|
||||
SetParam(command, "operations", operations);
|
||||
}
|
||||
|
||||
void protobuf_util::SetProductData(PbDeviceDefinition& device, const string& data)
|
||||
|
@ -38,7 +38,7 @@ namespace protobuf_util
|
||||
}
|
||||
|
||||
void ParseParameters(PbDeviceDefinition&, const string&);
|
||||
void SetPatternParams(PbCommand&, const string&);
|
||||
void SetCommandParams(PbCommand&, const string&);
|
||||
void SetProductData(PbDeviceDefinition&, const string&);
|
||||
string SetIdAndLun(PbDeviceDefinition&, const string&);
|
||||
string ListDevices(const vector<PbDevice>&);
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "mocks.h"
|
||||
#include "shared/piscsi_version.h"
|
||||
#include "shared/protobuf_util.h"
|
||||
#include "controllers/controller_manager.h"
|
||||
#include "devices/device_factory.h"
|
||||
#include "generated/piscsi_interface.pb.h"
|
||||
@ -16,6 +17,7 @@
|
||||
#include <sys/stat.h>
|
||||
|
||||
using namespace piscsi_interface;
|
||||
using namespace protobuf_util;
|
||||
|
||||
TEST(PiscsiResponseTest, Operation_Count)
|
||||
{
|
||||
@ -178,15 +180,41 @@ TEST(PiscsiResponseTest, GetServerInfo)
|
||||
const unordered_set<shared_ptr<PrimaryDevice>> devices;
|
||||
const unordered_set<int> ids = { 1, 3 };
|
||||
|
||||
PbServerInfo info;
|
||||
response.GetServerInfo(info, devices, ids, "default_folder", "", "", 1234);
|
||||
EXPECT_EQ(piscsi_major_version, info.version_info().major_version());
|
||||
EXPECT_EQ(piscsi_minor_version, info.version_info().minor_version());
|
||||
EXPECT_EQ(piscsi_patch_version, info.version_info().patch_version());
|
||||
EXPECT_EQ(level::level_string_views[get_level()], info.log_level_info().current_log_level());
|
||||
EXPECT_EQ("default_folder", info.image_files_info().default_image_folder());
|
||||
EXPECT_EQ(1234, info.image_files_info().depth());
|
||||
EXPECT_EQ(2, info.reserved_ids_info().ids().size());
|
||||
PbCommand command;
|
||||
PbServerInfo info1;
|
||||
response.GetServerInfo(info1, command, devices, ids, "default_folder", 1234);
|
||||
EXPECT_TRUE(info1.has_version_info());
|
||||
EXPECT_TRUE(info1.has_log_level_info());
|
||||
EXPECT_TRUE(info1.has_device_types_info());
|
||||
EXPECT_TRUE(info1.has_image_files_info());
|
||||
EXPECT_TRUE(info1.has_network_interfaces_info());
|
||||
EXPECT_TRUE(info1.has_mapping_info());
|
||||
EXPECT_TRUE(info1.has_statistics_info());
|
||||
EXPECT_FALSE(info1.has_devices_info());
|
||||
EXPECT_TRUE(info1.has_reserved_ids_info());
|
||||
EXPECT_TRUE(info1.has_operation_info());
|
||||
|
||||
EXPECT_EQ(piscsi_major_version, info1.version_info().major_version());
|
||||
EXPECT_EQ(piscsi_minor_version, info1.version_info().minor_version());
|
||||
EXPECT_EQ(piscsi_patch_version, info1.version_info().patch_version());
|
||||
EXPECT_EQ(level::level_string_views[get_level()], info1.log_level_info().current_log_level());
|
||||
EXPECT_EQ("default_folder", info1.image_files_info().default_image_folder());
|
||||
EXPECT_EQ(1234, info1.image_files_info().depth());
|
||||
EXPECT_EQ(2, info1.reserved_ids_info().ids().size());
|
||||
|
||||
SetParam(command, "operations", "log_level_info,mapping_info");
|
||||
PbServerInfo info2;
|
||||
response.GetServerInfo(info2, command, devices, ids, "default_folder", 1234);
|
||||
EXPECT_FALSE(info2.has_version_info());
|
||||
EXPECT_TRUE(info2.has_log_level_info());
|
||||
EXPECT_FALSE(info2.has_device_types_info());
|
||||
EXPECT_FALSE(info2.has_image_files_info());
|
||||
EXPECT_FALSE(info2.has_network_interfaces_info());
|
||||
EXPECT_TRUE(info2.has_mapping_info());
|
||||
EXPECT_FALSE(info2.has_statistics_info());
|
||||
EXPECT_FALSE(info2.has_devices_info());
|
||||
EXPECT_FALSE(info2.has_reserved_ids_info());
|
||||
EXPECT_FALSE(info2.has_operation_info());
|
||||
}
|
||||
|
||||
TEST(PiscsiResponseTest, GetVersionInfo)
|
||||
|
@ -53,27 +53,38 @@ TEST(ProtobufUtil, ParseParameters)
|
||||
TestSpecialDevice("services");
|
||||
}
|
||||
|
||||
TEST(ProtobufUtil, SetPatternParams)
|
||||
TEST(ProtobufUtil, SetCommandParams)
|
||||
{
|
||||
PbCommand command1;
|
||||
SetPatternParams(command1, "file");
|
||||
SetCommandParams(command1, "file");
|
||||
EXPECT_EQ("", GetParam(command1, "folder_pattern"));
|
||||
EXPECT_EQ("file", GetParam(command1, "file_pattern"));
|
||||
|
||||
PbCommand command2;
|
||||
SetPatternParams(command2, ":file");
|
||||
SetCommandParams(command2, ":file");
|
||||
EXPECT_EQ("", GetParam(command2, "folder_pattern"));
|
||||
EXPECT_EQ("file", GetParam(command2, "file_pattern"));
|
||||
|
||||
PbCommand command3;
|
||||
SetPatternParams(command3, "folder:");
|
||||
EXPECT_EQ("folder", GetParam(command3, "folder_pattern"));
|
||||
EXPECT_EQ("", GetParam(command3, "file_pattern"));
|
||||
SetCommandParams(command3, "file:");
|
||||
EXPECT_EQ("file", GetParam(command3, "file_pattern"));
|
||||
EXPECT_EQ("", GetParam(command3, "folder_pattern"));
|
||||
|
||||
PbCommand command4;
|
||||
SetPatternParams(command4, "folder:file");
|
||||
SetCommandParams(command4, "folder:file");
|
||||
EXPECT_EQ("folder", GetParam(command4, "folder_pattern"));
|
||||
EXPECT_EQ("file", GetParam(command4, "file_pattern"));
|
||||
|
||||
PbCommand command5;
|
||||
SetCommandParams(command5, "folder:file:");
|
||||
EXPECT_EQ("folder", GetParam(command5, "folder_pattern"));
|
||||
EXPECT_EQ("file", GetParam(command5, "file_pattern"));
|
||||
|
||||
PbCommand command6;
|
||||
SetCommandParams(command6, "folder:file:operations");
|
||||
EXPECT_EQ("folder", GetParam(command6, "folder_pattern"));
|
||||
EXPECT_EQ("file", GetParam(command6, "file_pattern"));
|
||||
EXPECT_EQ("operations", GetParam(command6, "operations"));
|
||||
}
|
||||
|
||||
TEST(ProtobufUtil, ListDevices)
|
||||
|
@ -7,30 +7,31 @@ scsictl \- Sends management commands to the piscsi process
|
||||
\fB\-l\fR |
|
||||
\fB\-m\fR |
|
||||
\fB\-o\fR |
|
||||
\fB\-s\fR |
|
||||
\fB\-v\fR |
|
||||
\fB\-D\fR |
|
||||
\fB\-I\fR |
|
||||
\fB\-L\fR |
|
||||
\fB\-O\fR |
|
||||
\fB\-P\fR |
|
||||
\fB\-S\fR |
|
||||
\fB\-T\fR |
|
||||
\fB\-V\fR |
|
||||
\fB\-X\fR |
|
||||
[\fB\-C\fR \fIFILENAME:FILESIZE\fR]
|
||||
[\fB\-E\fR \fIFILENAME\fR]
|
||||
[\fB\-F\fR \fIIMAGE_FOLDER\fR]
|
||||
[\fB\-R\fR \fICURRENT_NAME:NEW_NAME\fR]
|
||||
[\fB\-c\fR \fICMD\fR]
|
||||
[\fB\-f\fR \fIFILE|PARAM\fR]
|
||||
[\fB\-g\fR \fILOG_LEVEL\fR]
|
||||
[\fB\-h\fR \fIHOST\fR]
|
||||
[\fB\-i\fR \fIID[:LUN]\fR
|
||||
[\fB\-n\fR \fINAME\fR]
|
||||
[\fB\-p\fR \fIPORT\fR]
|
||||
[\fB\-r\fR \fIRESERVED_IDS\fR]
|
||||
[\fB\-t\fR \fITYPE\fR]
|
||||
[\fB\-x\fR \fICURRENT_NAME:NEW_NAME\fR]
|
||||
[\fB\-C\fR \fIFILENAME:FILESIZE\fR] |
|
||||
[\fB\-E\fR \fIFILENAME\fR] |
|
||||
[\fB\-F\fR \fIIMAGE_FOLDER\fR] |
|
||||
[\fB\-R\fR \fICURRENT_NAME:NEW_NAME\fR] |
|
||||
[\fB\-c\fR \fICMD\fR] |
|
||||
[\fB\-f\fR \fIFILE|PARAM\fR] |
|
||||
[\fB\-g\fR \fILOG_LEVEL\fR] |
|
||||
[\fB\-h\fR \fIHOST\fR] |
|
||||
[\fB\-i\fR \fIID[:LUN]\fR] |
|
||||
[\fB\-n\fR \fINAME\fR] |
|
||||
[\fB\-p\fR \fIPORT\fR] |
|
||||
[\fB\-r\fR \fIRESERVED_IDS\fR] |
|
||||
[\fB\-s\fR \fI[FOLDER_PATTERN:FILE_PATTERN:OPERATIONS]\fR] |
|
||||
[\fB\-t\fR \fITYPE\fR] |
|
||||
[\fB\-x\fR \fICURRENT_NAME:NEW_NAME\fR] |
|
||||
[\fB\-z\fR \fILOCALE\fR]
|
||||
.SH DESCRIPTION
|
||||
.B scsictl
|
||||
@ -38,7 +39,7 @@ sends commands to the piscsi process to make configuration adjustments at runtim
|
||||
|
||||
Either the -i or -l option should be specified at one time. Not both.
|
||||
|
||||
You do NOT need root privileges to use scsictl.
|
||||
You do NOT need root privileges to use scsictl. scsictl also runs on non-Pi Linux platforms.
|
||||
|
||||
Note: The command and type arguments are case insensitive. Only the first letter of the command/type is evaluated by the tool.
|
||||
|
||||
@ -95,9 +96,12 @@ The piscsi port to connect to, default is 6868.
|
||||
.BR \-r\fI " " \fIRESERVED_IDS
|
||||
Comma-separated list of IDs to reserve. Pass an empty list in order to not reserve anything.
|
||||
.TP
|
||||
.BR \-s\fI
|
||||
.BR \-s\fI " " \fI[FOLDER_PATTERN:FILE_PATTERN:OPERATIONS]
|
||||
Display server-side settings like available images or supported device types.
|
||||
.TP
|
||||
.BR \-S\fI
|
||||
Display statistics.
|
||||
.TP
|
||||
.BR \-T\fI
|
||||
Display all device types and their properties.
|
||||
.TP
|
||||
|
@ -6,19 +6,21 @@ NAME
|
||||
scsictl - Sends management commands to the piscsi process
|
||||
|
||||
SYNOPSIS
|
||||
scsictl -e | -l | -m | -o | -s | -v | -D | -I | -L | -O | -P | -T | -V
|
||||
| -X | [-C FILENAME:FILESIZE] [-E FILENAME] [-F IMAGE_FOLDER] [-R CUR‐
|
||||
RENT_NAME:NEW_NAME] [-c CMD] [-f FILE|PARAM] [-g LOG_LEVEL] [-h HOST]
|
||||
[-i ID[:LUN] [-n NAME] [-p PORT] [-r RESERVED_IDS] [-t TYPE] [-x CUR‐
|
||||
RENT_NAME:NEW_NAME] [-z LOCALE]
|
||||
scsictl -e | -l | -m | -o | -v | -D | -I | -L | -O | -P | -S | -T | -V
|
||||
| -X | [-C FILENAME:FILESIZE] | [-E FILENAME] | [-F IMAGE_FOLDER] | [-R
|
||||
CURRENT_NAME:NEW_NAME] | [-c CMD] | [-f FILE|PARAM] | [-g LOG_LEVEL] |
|
||||
[-h HOST] | [-i ID[:LUN]] | [-n NAME] | [-p PORT] | [-r RESERVED_IDS] |
|
||||
[-s [FOLDER_PATTERN:FILE_PATTERN:OPERATIONS]] | [-t TYPE] | [-x CUR‐
|
||||
RENT_NAME:NEW_NAME] | [-z LOCALE]
|
||||
|
||||
DESCRIPTION
|
||||
scsictl sends commands to the piscsi process to make configuration ad‐
|
||||
scsictl sends commands to the piscsi process to make configuration ad‐
|
||||
justments at runtime or to check the status of the devices.
|
||||
|
||||
Either the -i or -l option should be specified at one time. Not both.
|
||||
|
||||
You do NOT need root privileges to use scsictl.
|
||||
You do NOT need root privileges to use scsictl. scsictl also runs on
|
||||
non-Pi Linux platforms.
|
||||
|
||||
Note: The command and type arguments are case insensitive. Only the
|
||||
first letter of the command/type is evaluated by the tool.
|
||||
@ -74,9 +76,12 @@ OPTIONS
|
||||
Comma-separated list of IDs to reserve. Pass an empty list in
|
||||
order to not reserve anything.
|
||||
|
||||
-s Display server-side settings like available images or supported
|
||||
-s [FOLDER_PATTERN:FILE_PATTERN:OPERATIONS]
|
||||
Display server-side settings like available images or supported
|
||||
device types.
|
||||
|
||||
-S Display statistics.
|
||||
|
||||
-T Display all device types and their properties.
|
||||
|
||||
-v Display the piscsi server version.
|
||||
|
Loading…
x
Reference in New Issue
Block a user