mirror of
https://github.com/akuker/RASCSI.git
synced 2024-11-22 16:33:17 +00:00
153 lines
3.3 KiB
C++
153 lines
3.3 KiB
C++
//---------------------------------------------------------------------------
|
|
//
|
|
// SCSI Target Emulator PiSCSI
|
|
// for Raspberry Pi
|
|
//
|
|
// Copyright (C) 2021-2023 Uwe Seimet
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
#include "controllers/controller_manager.h"
|
|
#include "piscsi_version.h"
|
|
#include "piscsi_util.h"
|
|
#include <spdlog/spdlog.h>
|
|
#include <cassert>
|
|
#include <cstring>
|
|
#include <sstream>
|
|
#include <filesystem>
|
|
#include <algorithm>
|
|
|
|
using namespace std;
|
|
using namespace filesystem;
|
|
|
|
vector<string> piscsi_util::Split(const string& s, char separator, int limit)
|
|
{
|
|
assert(limit >= 0);
|
|
|
|
string component;
|
|
vector<string> result;
|
|
stringstream str(s);
|
|
|
|
while (--limit > 0 && getline(str, component, separator)) {
|
|
result.push_back(component);
|
|
}
|
|
|
|
if (!str.eof()) {
|
|
getline(str, component);
|
|
result.push_back(component);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
string piscsi_util::GetLocale()
|
|
{
|
|
const char *locale = setlocale(LC_MESSAGES, "");
|
|
if (locale == nullptr || !strcmp(locale, "C")) {
|
|
locale = "en";
|
|
}
|
|
|
|
return locale;
|
|
}
|
|
|
|
bool piscsi_util::GetAsUnsignedInt(const string& value, int& result)
|
|
{
|
|
if (value.find_first_not_of("0123456789") != string::npos) {
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
auto v = stoul(value);
|
|
result = (int)v;
|
|
}
|
|
catch(const invalid_argument&) {
|
|
return false;
|
|
}
|
|
catch(const out_of_range&) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
string piscsi_util::ProcessId(const string& id_spec, int& id, int& lun)
|
|
{
|
|
id = -1;
|
|
lun = -1;
|
|
|
|
if (id_spec.empty()) {
|
|
return "Missing device ID";
|
|
}
|
|
|
|
const int id_max = ControllerManager::GetScsiIdMax();
|
|
const int lun_max = ControllerManager::GetScsiLunMax();
|
|
|
|
if (const auto& components = Split(id_spec, COMPONENT_SEPARATOR, 2); !components.empty()) {
|
|
if (components.size() == 1) {
|
|
if (!GetAsUnsignedInt(components[0], id) || id >= id_max) {
|
|
id = -1;
|
|
|
|
return "Invalid device ID (0-" + to_string(ControllerManager::GetScsiIdMax() - 1) + ")";
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
if (!GetAsUnsignedInt(components[0], id) || id >= id_max || !GetAsUnsignedInt(components[1], lun) || lun >= lun_max) {
|
|
id = -1;
|
|
lun = -1;
|
|
|
|
return "Invalid LUN (0-" + to_string(lun_max - 1) + ")";
|
|
}
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
string piscsi_util::Banner(string_view app)
|
|
{
|
|
ostringstream s;
|
|
|
|
s << "SCSI Target Emulator PiSCSI " << app << "\n";
|
|
s << "Version " << piscsi_get_version_string() << " (" << __DATE__ << ' ' << __TIME__ << ")\n";
|
|
s << "Powered by XM6 TypeG Technology / ";
|
|
s << "Copyright (C) 2016-2020 GIMONS\n";
|
|
s << "Copyright (C) 2020-2024 Contributors to the PiSCSI project\n";
|
|
|
|
return s.str();
|
|
}
|
|
|
|
string piscsi_util::GetExtensionLowerCase(string_view filename)
|
|
{
|
|
string ext;
|
|
ranges::transform(path(filename).extension().string(), back_inserter(ext), ::tolower);
|
|
|
|
// Remove the leading dot
|
|
return ext.empty() ? "" : ext.substr(1);
|
|
}
|
|
|
|
void piscsi_util::LogErrno(const string& msg)
|
|
{
|
|
spdlog::error(errno ? msg + ": " + string(strerror(errno)) : msg);
|
|
}
|
|
|
|
// Pin the thread to a specific CPU
|
|
// TODO Check whether just using a single CPU really makes sense
|
|
void piscsi_util::FixCpu(int cpu)
|
|
{
|
|
#ifdef __linux__
|
|
// Get the number of CPUs
|
|
cpu_set_t mask;
|
|
CPU_ZERO(&mask);
|
|
sched_getaffinity(0, sizeof(cpu_set_t), &mask);
|
|
const int cpus = CPU_COUNT(&mask);
|
|
|
|
// Set the thread affinity
|
|
if (cpu < cpus) {
|
|
CPU_ZERO(&mask);
|
|
CPU_SET(cpu, &mask);
|
|
sched_setaffinity(0, sizeof(cpu_set_t), &mask);
|
|
}
|
|
#endif
|
|
}
|