From 8e17b43da6b4fcb3789ff2d588e087cd34b244cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Fri, 14 Oct 2022 10:47:32 +0200 Subject: [PATCH] kernel/device_manager: Implement B_GET_DRIVER_FOR_DEVICE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit for legacy and new drivers. This is an opcode for ioctl that can be used on almost any device entry found in /dev. When used, ioctl will fill a buffer with the absolute path to the driver file that is being used by the device. This opcode was available in BeOS R5, though remained unimplemented in Haiku since the introduction of the Device Manager almost two decades ago. Original change by Jacob Secunda. Change-Id: Ic49141b677b4158a63918459d4048450c825447c Reviewed-on: https://review.haiku-os.org/c/haiku/+/5078 Tested-by: Commit checker robot Reviewed-by: Jérôme Duval --- headers/private/kernel/kmodule.h | 1 + src/system/kernel/device_manager/devfs.cpp | 15 ----------- .../kernel/device_manager/device_manager.cpp | 27 ++++++++++++++++++- .../kernel/device_manager/legacy_drivers.cpp | 16 +++++++++++ src/system/kernel/module.cpp | 24 ++++++++++++++++- 5 files changed, 66 insertions(+), 17 deletions(-) diff --git a/headers/private/kernel/kmodule.h b/headers/private/kernel/kmodule.h index d93e6cf512..08d1d0b5bb 100644 --- a/headers/private/kernel/kmodule.h +++ b/headers/private/kernel/kmodule.h @@ -32,6 +32,7 @@ extern status_t load_module(const char *path, module_info ***_modules); extern status_t module_init(struct kernel_args *args); extern status_t module_init_post_threads(void); extern status_t module_init_post_boot_device(bool bootingFromBootLoaderVolume); +extern status_t module_get_path(const char* moduleName, char** path); #ifdef __cplusplus } diff --git a/src/system/kernel/device_manager/devfs.cpp b/src/system/kernel/device_manager/devfs.cpp index 61d8d04a62..d0659f9ba1 100644 --- a/src/system/kernel/device_manager/devfs.cpp +++ b/src/system/kernel/device_manager/devfs.cpp @@ -1534,21 +1534,6 @@ devfs_ioctl(fs_volume* _volume, fs_vnode* _vnode, void* _cookie, uint32 op, return status; } - case B_GET_DRIVER_FOR_DEVICE: - { -#if 0 - const char* path; - if (!vnode->stream.u.dev.driver) - return B_ENTRY_NOT_FOUND; - path = vnode->stream.u.dev.driver->path; - if (path == NULL) - return B_ENTRY_NOT_FOUND; - - return user_strlcpy((char*)buffer, path, B_FILE_NAME_LENGTH); -#endif - return B_ERROR; - } - case B_GET_PARTITION_INFO: { struct devfs_partition* partition diff --git a/src/system/kernel/device_manager/device_manager.cpp b/src/system/kernel/device_manager/device_manager.cpp index b929971dd2..22365e1d45 100644 --- a/src/system/kernel/device_manager/device_manager.cpp +++ b/src/system/kernel/device_manager/device_manager.cpp @@ -21,8 +21,9 @@ #include #include #include -#include #include +#include +#include #include #include #include @@ -91,6 +92,8 @@ public: virtual void Removed(); + virtual status_t Control(void* cookie, int32 op, void* buffer, size_t length); + void SetRemovedFromParent(bool removed) { fRemovedFromParent = removed; } @@ -1251,6 +1254,28 @@ Device::Removed() } +status_t +Device::Control(void* _cookie, int32 op, void* buffer, size_t length) +{ + switch (op) { + case B_GET_DRIVER_FOR_DEVICE: + { + char* path = NULL; + status_t status = module_get_path(ModuleName(), &path); + if (status != B_OK) + return status; + if (length != 0 && length <= strlen(path)) + return ERANGE; + status = user_strlcpy(static_cast(buffer), path, length); + free(path); + return status; + } + default: + return AbstractModuleDevice::Control(_cookie, op, buffer, length);; + } +} + + // #pragma mark - device_node diff --git a/src/system/kernel/device_manager/legacy_drivers.cpp b/src/system/kernel/device_manager/legacy_drivers.cpp index 50b5430df8..2e0ca6e932 100644 --- a/src/system/kernel/device_manager/legacy_drivers.cpp +++ b/src/system/kernel/device_manager/legacy_drivers.cpp @@ -71,6 +71,8 @@ public: void** _cookie); virtual status_t Select(void* cookie, uint8 event, selectsync* sync); + virtual status_t Control(void* cookie, int32 op, void* buffer, size_t length); + bool Republished() const { return fRepublished; } void SetRepublished(bool republished) { fRepublished = republished; } @@ -1323,6 +1325,20 @@ LegacyDevice::Removed() } +status_t +LegacyDevice::Control(void* _cookie, int32 op, void* buffer, size_t length) +{ + switch (op) { + case B_GET_DRIVER_FOR_DEVICE: + if (length != 0 && length <= strlen(fDriver->path)) + return ERANGE; + return user_strlcpy(static_cast(buffer), fDriver->path, length); + default: + return AbstractModuleDevice::Control(_cookie, op, buffer, length); + } +} + + void LegacyDevice::SetHooks(device_hooks* hooks) { diff --git a/src/system/kernel/module.cpp b/src/system/kernel/module.cpp index c4e869fc4f..1f02be10f6 100644 --- a/src/system/kernel/module.cpp +++ b/src/system/kernel/module.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008, Haiku Inc. All rights reserved. + * Copyright 2002-2022, Haiku Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Copyright 2001, Thomas Kurschel. All rights reserved. @@ -1742,6 +1742,28 @@ load_module(const char* path, module_info*** _modules) } +status_t +module_get_path(const char* moduleName, char** filePath) +{ + if (moduleName == NULL || filePath == NULL) + return B_BAD_VALUE; + + RecursiveLocker _(sModulesLock); + + // Check if the module and its image are already cached in the module system. + module* foundModule = sModulesHash->Lookup(moduleName); + if (foundModule != NULL) { + if (foundModule->module_image == NULL) + return ENOTSUP; + // The module is built-in and has no associated image. + *filePath = strdup(foundModule->module_image->path); + return *filePath != NULL ? B_OK : B_NO_MEMORY; + } + + return B_NAME_NOT_FOUND; +} + + status_t start_watching_modules(const char* prefix, NotificationListener& listener) {