1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 05:08:13 +00:00

Utilities/lspci: Iterate over /sys/bus/pci instead of reading /proc/pci

This opens many opportunities to add more data printed in lspci in a
flexible manner - so instead of reading an ever-expanding JSON encoded
file, we can add more features and let the utility read the directory
entries from sysfs.

This also allows not only filtering data on devices but to easily filter
non-wanted devices when printing the output.
This commit is contained in:
Liav A 2022-02-08 19:28:08 +02:00 committed by Andreas Kling
parent 2a898a7e4a
commit a91da67216
2 changed files with 69 additions and 18 deletions

View file

@ -4,10 +4,13 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Hex.h>
#include <AK/JsonArray.h>
#include <AK/JsonObject.h>
#include <AK/String.h>
#include <AK/StringUtils.h>
#include <LibCore/ArgsParser.h>
#include <LibCore/DirIterator.h>
#include <LibCore/File.h>
#include <LibCore/System.h>
#include <LibMain/Main.h>
@ -18,11 +21,25 @@ static bool flag_show_numerical = false;
static const char* format_numerical = "{:04x}:{:02x}:{:02x}.{} {}: {}:{} (rev {:02x})";
static const char* format_textual = "{:04x}:{:02x}:{:02x}.{} {}: {} {} (rev {:02x})";
static u32 read_hex_string_from_bytebuffer(ByteBuffer const& buf)
{
return AK::StringUtils::convert_to_uint_from_hex(String(buf.slice(2, buf.size() - 2).bytes())).release_value();
}
static u32 convert_sysfs_value_to_uint(String const& value)
{
if (auto result = AK::StringUtils::convert_to_uint_from_hex(value); result.has_value())
return result.release_value();
if (auto result = AK::StringUtils::convert_to_uint(value); result.has_value())
return result.release_value();
VERIFY_NOT_REACHED();
}
ErrorOr<int> serenity_main(Main::Arguments arguments)
{
TRY(Core::System::pledge("stdio rpath"));
TRY(Core::System::unveil("/res/pci.ids", "r"));
TRY(Core::System::unveil("/proc/pci", "r"));
TRY(Core::System::unveil("/sys/bus/pci", "r"));
TRY(Core::System::unveil(nullptr, nullptr));
Core::ArgsParser args_parser;
@ -41,23 +58,57 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
}
}
auto proc_pci = TRY(Core::File::open("/proc/pci", Core::OpenMode::ReadOnly));
Core::DirIterator di("/sys/bus/pci/", Core::DirIterator::SkipParentAndBaseDir);
if (di.has_error()) {
warnln("Failed to open /sys/bus/pci - {}", di.error());
return 1;
}
TRY(Core::System::pledge("stdio"));
TRY(Core::System::pledge("stdio rpath"));
auto file_contents = proc_pci->read_all();
auto json = TRY(JsonValue::from_string(file_contents));
json.as_array().for_each([db, format](auto& value) {
auto& dev = value.as_object();
auto domain = dev.get("domain").to_u32();
auto bus = dev.get("bus").to_u32();
auto device = dev.get("device").to_u32();
auto function = dev.get("function").to_u32();
auto vendor_id = dev.get("vendor_id").to_u32();
auto device_id = dev.get("device_id").to_u32();
auto revision_id = dev.get("revision_id").to_u32();
auto class_id = dev.get("class").to_u32();
auto subclass_id = dev.get("subclass").to_u32();
while (di.has_next()) {
auto dir = di.next_path();
auto domain_bus_device_parts = dir.split(':');
VERIFY(domain_bus_device_parts.size() == 3);
auto domain = convert_sysfs_value_to_uint(domain_bus_device_parts[0]);
auto bus = convert_sysfs_value_to_uint(domain_bus_device_parts[1]);
auto device = convert_sysfs_value_to_uint(domain_bus_device_parts[2].split('.')[0]);
auto function_parts = dir.split('.');
VERIFY(function_parts.size() == 2);
auto function = convert_sysfs_value_to_uint(function_parts[1]);
auto vendor_id_file = Core::File::construct(String::formatted("/sys/bus/pci/{}/vendor", dir));
if (!vendor_id_file->open(Core::OpenMode::ReadOnly)) {
dbgln("Error: Could not open {}: {}", vendor_id_file->name(), vendor_id_file->error_string());
continue;
}
auto device_id_file = Core::File::construct(String::formatted("/sys/bus/pci/{}/device_id", dir));
if (!device_id_file->open(Core::OpenMode::ReadOnly)) {
dbgln("Error: Could not open {}: {}", device_id_file->name(), device_id_file->error_string());
continue;
}
auto class_id_file = Core::File::construct(String::formatted("/sys/bus/pci/{}/class", dir));
if (!class_id_file->open(Core::OpenMode::ReadOnly)) {
dbgln("Error: Could not open {}: {}", class_id_file->name(), class_id_file->error_string());
continue;
}
auto subclass_id_file = Core::File::construct(String::formatted("/sys/bus/pci/{}/subclass", dir));
if (!subclass_id_file->open(Core::OpenMode::ReadOnly)) {
dbgln("Error: Could not open {}: {}", subclass_id_file->name(), subclass_id_file->error_string());
continue;
}
auto revision_id_file = Core::File::construct(String::formatted("/sys/bus/pci/{}/revision", dir));
if (!revision_id_file->open(Core::OpenMode::ReadOnly)) {
dbgln("Error: Could not open {}: {}", revision_id_file->name(), revision_id_file->error_string());
continue;
}
u32 vendor_id = read_hex_string_from_bytebuffer(vendor_id_file->read_all());
u32 device_id = read_hex_string_from_bytebuffer(device_id_file->read_all());
u32 revision_id = read_hex_string_from_bytebuffer(revision_id_file->read_all());
u32 class_id = read_hex_string_from_bytebuffer(class_id_file->read_all());
u32 subclass_id = read_hex_string_from_bytebuffer(subclass_id_file->read_all());
String vendor_name;
String device_name;
@ -77,7 +128,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
class_name = String::formatted("{:02x}{:02x}", class_id, subclass_id);
outln(format, domain, bus, device, function, class_name, vendor_name, device_name, revision_id);
});
}
return 0;
}