mirror of
https://github.com/aaru-dps/Aaru.git
synced 2026-07-08 18:16:24 +00:00
On Linux prefer SCSI generic device if available.
This commit is contained in:
@@ -54,7 +54,7 @@ partial class Device : Devices.Device, IDisposable
|
||||
private nuint _capacity;
|
||||
/// <summary>Gets the file handle representing this device</summary>
|
||||
/// <value>The file handle</value>
|
||||
int _fileDescriptor;
|
||||
int _fileDescriptor;
|
||||
|
||||
// Persistent, aligned native buffer
|
||||
private nuint _nativeBuffer;
|
||||
@@ -88,13 +88,33 @@ partial class Device : Devices.Device, IDisposable
|
||||
{
|
||||
errno = ErrorNumber.NoError;
|
||||
|
||||
// Prefer /dev/sg* over block devices (/dev/sr*, /dev/sd*, /dev/st*) so that the kernel
|
||||
// does not apply SCSI command filtering, which blocks vendor-specific opcodes (e.g. OmniDrive
|
||||
// 0xC0) without CAP_SYS_RAWIO. The sg device is looked up via sysfs and used only for
|
||||
// opening; all other sysfs queries below continue to use the original devicePath.
|
||||
string openPath = devicePath;
|
||||
|
||||
if(devicePath.StartsWith("/dev/sr", StringComparison.Ordinal) ||
|
||||
devicePath.StartsWith("/dev/sd", StringComparison.Ordinal) ||
|
||||
devicePath.StartsWith("/dev/st", StringComparison.Ordinal))
|
||||
{
|
||||
string sgDir = "/sys/block/" + Path.GetFileName(devicePath) + "/device/scsi_generic";
|
||||
|
||||
if(Directory.Exists(sgDir))
|
||||
{
|
||||
string[] sgEntries = Directory.GetFileSystemEntries(sgDir, "*", SearchOption.TopDirectoryOnly);
|
||||
|
||||
if(sgEntries.Length > 0) openPath = "/dev/" + Path.GetFileName(sgEntries[0]);
|
||||
}
|
||||
}
|
||||
|
||||
var dev = new Device
|
||||
{
|
||||
PlatformId = DetectOS.GetRealPlatformID(),
|
||||
Timeout = 15,
|
||||
Error = false,
|
||||
IsRemovable = false,
|
||||
_fileDescriptor = Extern.open(devicePath, FileFlags.ReadWrite | FileFlags.NonBlocking | FileFlags.CreateNew)
|
||||
_fileDescriptor = Extern.open(openPath, FileFlags.ReadWrite | FileFlags.NonBlocking | FileFlags.CreateNew)
|
||||
};
|
||||
|
||||
if(dev._fileDescriptor < 0)
|
||||
@@ -103,7 +123,7 @@ partial class Device : Devices.Device, IDisposable
|
||||
|
||||
if(dev.LastError is 13 or 30) // EACCES or EROFS
|
||||
{
|
||||
dev._fileDescriptor = Extern.open(devicePath, FileFlags.Readonly | FileFlags.NonBlocking);
|
||||
dev._fileDescriptor = Extern.open(openPath, FileFlags.Readonly | FileFlags.NonBlocking);
|
||||
|
||||
if(dev._fileDescriptor < 0)
|
||||
{
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Text;
|
||||
@@ -151,6 +152,84 @@ public static class ListDevices
|
||||
};
|
||||
}
|
||||
|
||||
// Add /dev/sg* devices that have no block-device counterpart (sd*, sr*, st*).
|
||||
// Devices that do have a counterpart will be opened via their sg node transparently
|
||||
// by Device.Create(), so they should not appear twice in the list.
|
||||
const string PATH_SYS_SG = "/sys/class/scsi_generic/";
|
||||
|
||||
if(Directory.Exists(PATH_SYS_SG))
|
||||
{
|
||||
string[] sgDevs = Directory.GetFileSystemEntries(PATH_SYS_SG, "*", SearchOption.TopDirectoryOnly);
|
||||
|
||||
var sgList = new List<DeviceInfo>(devices);
|
||||
|
||||
foreach(string sgSysPath in sgDevs)
|
||||
{
|
||||
string sgName = Path.GetFileName(sgSysPath);
|
||||
string blockPath = Path.Combine(PATH_SYS_SG, sgName, "device", "block");
|
||||
|
||||
// Skip if this sg device has a block-device counterpart
|
||||
if(Directory.Exists(blockPath) &&
|
||||
Directory.GetFileSystemEntries(blockPath, "*", SearchOption.TopDirectoryOnly).Length > 0)
|
||||
continue;
|
||||
|
||||
string sgDevPath = "/dev/" + sgName;
|
||||
|
||||
var sgInfo = new DeviceInfo
|
||||
{
|
||||
Path = sgDevPath
|
||||
};
|
||||
|
||||
if(hasUdev)
|
||||
{
|
||||
IntPtr udevDev = Extern.udev_device_new_from_subsystem_sysname(udev, "scsi_generic", sgName);
|
||||
sgInfo.Vendor = Extern.udev_device_get_property_value(udevDev, "ID_VENDOR");
|
||||
sgInfo.Model = Extern.udev_device_get_property_value(udevDev, "ID_MODEL");
|
||||
|
||||
if(!string.IsNullOrEmpty(sgInfo.Model)) sgInfo.Model = sgInfo.Model.Replace('_', ' ');
|
||||
|
||||
sgInfo.Serial = Extern.udev_device_get_property_value(udevDev, "ID_SCSI_SERIAL");
|
||||
|
||||
if(string.IsNullOrEmpty(sgInfo.Serial))
|
||||
sgInfo.Serial = Extern.udev_device_get_property_value(udevDev, "ID_SERIAL_SHORT");
|
||||
|
||||
sgInfo.Bus = Extern.udev_device_get_property_value(udevDev, "ID_BUS");
|
||||
}
|
||||
|
||||
string sgDevicePath = Path.Combine(PATH_SYS_SG, sgName, "device");
|
||||
|
||||
if(File.Exists(Path.Combine(sgDevicePath, "vendor")) && string.IsNullOrEmpty(sgInfo.Vendor))
|
||||
{
|
||||
var sr = new StreamReader(Path.Combine(sgDevicePath, "vendor"), Encoding.ASCII);
|
||||
sgInfo.Vendor = sr.ReadLine()?.Trim();
|
||||
}
|
||||
|
||||
if(File.Exists(Path.Combine(sgDevicePath, "model")) && string.IsNullOrEmpty(sgInfo.Model))
|
||||
{
|
||||
var sr = new StreamReader(Path.Combine(sgDevicePath, "model"), Encoding.ASCII);
|
||||
sgInfo.Model = sr.ReadLine()?.Trim();
|
||||
}
|
||||
|
||||
if(File.Exists(Path.Combine(sgDevicePath, "serial")) && string.IsNullOrEmpty(sgInfo.Serial))
|
||||
{
|
||||
var sr = new StreamReader(Path.Combine(sgDevicePath, "serial"), Encoding.ASCII);
|
||||
sgInfo.Serial = sr.ReadLine()?.Trim();
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(sgInfo.Bus)) sgInfo.Bus = sgInfo.Bus.ToUpper();
|
||||
|
||||
sgInfo.Supported = sgInfo.Bus switch
|
||||
{
|
||||
"ATA" or "ATAPI" or "SCSI" or "USB" or "PCMCIA" or "FireWire" => true,
|
||||
_ => sgInfo.Supported
|
||||
};
|
||||
|
||||
sgList.Add(sgInfo);
|
||||
}
|
||||
|
||||
devices = [.. sgList];
|
||||
}
|
||||
|
||||
return devices;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user