mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 15:42:44 +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:
		
							parent
							
								
									2a898a7e4a
								
							
						
					
					
						commit
						a91da67216
					
				
					 2 changed files with 69 additions and 18 deletions
				
			
		|  | @ -15,7 +15,7 @@ and devices connected to them. It shows a brief list of devices. | ||||||
| 
 | 
 | ||||||
| ## Files | ## Files | ||||||
| 
 | 
 | ||||||
| * `/proc/pci` - source of the PCI devices list. | * `/sys/bus/pci` - source of the PCI devices list. | ||||||
| * `/res/pci.ids` - a database of PCI identifiers used to match available devices to their vendor, device and class names. | * `/res/pci.ids` - a database of PCI identifiers used to match available devices to their vendor, device and class names. | ||||||
| 
 | 
 | ||||||
| ## Examples | ## Examples | ||||||
|  |  | ||||||
|  | @ -4,10 +4,13 @@ | ||||||
|  * SPDX-License-Identifier: BSD-2-Clause |  * SPDX-License-Identifier: BSD-2-Clause | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
|  | #include <AK/Hex.h> | ||||||
| #include <AK/JsonArray.h> | #include <AK/JsonArray.h> | ||||||
| #include <AK/JsonObject.h> | #include <AK/JsonObject.h> | ||||||
| #include <AK/String.h> | #include <AK/String.h> | ||||||
|  | #include <AK/StringUtils.h> | ||||||
| #include <LibCore/ArgsParser.h> | #include <LibCore/ArgsParser.h> | ||||||
|  | #include <LibCore/DirIterator.h> | ||||||
| #include <LibCore/File.h> | #include <LibCore/File.h> | ||||||
| #include <LibCore/System.h> | #include <LibCore/System.h> | ||||||
| #include <LibMain/Main.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_numerical = "{:04x}:{:02x}:{:02x}.{} {}: {}:{} (rev {:02x})"; | ||||||
| static const char* format_textual = "{: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) | ErrorOr<int> serenity_main(Main::Arguments arguments) | ||||||
| { | { | ||||||
|     TRY(Core::System::pledge("stdio rpath")); |     TRY(Core::System::pledge("stdio rpath")); | ||||||
|     TRY(Core::System::unveil("/res/pci.ids", "r")); |     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)); |     TRY(Core::System::unveil(nullptr, nullptr)); | ||||||
| 
 | 
 | ||||||
|     Core::ArgsParser args_parser; |     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(); |     while (di.has_next()) { | ||||||
|     auto json = TRY(JsonValue::from_string(file_contents)); |         auto dir = di.next_path(); | ||||||
|     json.as_array().for_each([db, format](auto& value) { |         auto domain_bus_device_parts = dir.split(':'); | ||||||
|         auto& dev = value.as_object(); |         VERIFY(domain_bus_device_parts.size() == 3); | ||||||
|         auto domain = dev.get("domain").to_u32(); |         auto domain = convert_sysfs_value_to_uint(domain_bus_device_parts[0]); | ||||||
|         auto bus = dev.get("bus").to_u32(); |         auto bus = convert_sysfs_value_to_uint(domain_bus_device_parts[1]); | ||||||
|         auto device = dev.get("device").to_u32(); |         auto device = convert_sysfs_value_to_uint(domain_bus_device_parts[2].split('.')[0]); | ||||||
|         auto function = dev.get("function").to_u32(); | 
 | ||||||
|         auto vendor_id = dev.get("vendor_id").to_u32(); |         auto function_parts = dir.split('.'); | ||||||
|         auto device_id = dev.get("device_id").to_u32(); |         VERIFY(function_parts.size() == 2); | ||||||
|         auto revision_id = dev.get("revision_id").to_u32(); |         auto function = convert_sysfs_value_to_uint(function_parts[1]); | ||||||
|         auto class_id = dev.get("class").to_u32(); | 
 | ||||||
|         auto subclass_id = dev.get("subclass").to_u32(); |         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 vendor_name; | ||||||
|         String device_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); |             class_name = String::formatted("{:02x}{:02x}", class_id, subclass_id); | ||||||
| 
 | 
 | ||||||
|         outln(format, domain, bus, device, function, class_name, vendor_name, device_name, revision_id); |         outln(format, domain, bus, device, function, class_name, vendor_name, device_name, revision_id); | ||||||
|     }); |     } | ||||||
| 
 | 
 | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Liav A
						Liav A