kernel/device_manager: Implement B_GET_DRIVER_FOR_DEVICE

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 <no-reply+buildbot@haiku-os.org>
Reviewed-by: Jérôme Duval <jerome.duval@gmail.com>
This commit is contained in:
Jérôme Duval 2022-10-14 10:47:32 +02:00
parent d3e920ba77
commit 8e17b43da6
5 changed files with 66 additions and 17 deletions

View File

@ -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
}

View File

@ -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

View File

@ -21,8 +21,9 @@
#include <device_manager_defs.h>
#include <fs/devfs.h>
#include <fs/KPath.h>
#include <kernel.h>
#include <generic_syscall.h>
#include <kernel.h>
#include <kmodule.h>
#include <util/AutoLock.h>
#include <util/DoublyLinkedList.h>
#include <util/Stack.h>
@ -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<char*>(buffer), path, length);
free(path);
return status;
}
default:
return AbstractModuleDevice::Control(_cookie, op, buffer, length);;
}
}
// #pragma mark - device_node

View File

@ -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<char*>(buffer), fDriver->path, length);
default:
return AbstractModuleDevice::Control(_cookie, op, buffer, length);
}
}
void
LegacyDevice::SetHooks(device_hooks* hooks)
{

View File

@ -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)
{