Files
external_libcamera/src/libcamera/sysfs.cpp
Niklas Söderlund 7415c139cd libcamera: sysfs: Fix directory exists check
The scope of File::exists() was changed to only validate that a file
exists and is therefore not usable to check if a directory exists. This
breaks the persistent name generation for DT based systems as it uses
File::exists() to check for directories, fix this by using stat()
directly.

On Scarlet the persistent names of the cameras are impacted by this and
where incorrectly reported as:

    $ cam -l
    Available cameras:
    1: Internal front camera (platform/ff160000.i2c/i2c-7/7-003c ov2685)
    2: Internal front camera (platform/ff160000.i2c/i2c-7/7-0036 ov5695

While the expected ones are restored with this fix:

    $ cam -l
    Available cameras:
    1: Internal front camera (/base/i2c@ff160000/camera@3c)
    2: Internal front camera (/base/i2c@ff160000/camera@36)

Fixes: 8f4e16f014 ("test: file: Check that directories are not treated as files")
Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2021-01-13 13:20:06 +01:00

112 lines
2.7 KiB
C++

/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Copyright (C) 2020, Google Inc.
*
* sysfs.cpp - Miscellaneous utility functions to access sysfs
*/
#include "libcamera/internal/sysfs.h"
#include <fstream>
#include <sstream>
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include "libcamera/internal/file.h"
#include "libcamera/internal/log.h"
/**
* \file sysfs.h
* \brief Miscellaneous utility functions to access sysfs
*/
namespace libcamera {
LOG_DEFINE_CATEGORY(SysFs)
namespace sysfs {
/**
* \brief Retrieve the sysfs path for a character device
* \param[in] deviceNode Path to character device node
* \return The sysfs path on success or an empty string on failure
*/
std::string charDevPath(const std::string &deviceNode)
{
struct stat st;
int ret = stat(deviceNode.c_str(), &st);
if (ret < 0) {
ret = -errno;
LOG(SysFs, Error)
<< "Unable to stat '" << deviceNode << "': "
<< strerror(-ret);
return {};
}
std::ostringstream dev("/sys/dev/char/", std::ios_base::ate);
dev << major(st.st_rdev) << ":" << minor(st.st_rdev);
return dev.str();
}
/**
* \brief Retrieve the path of the firmware node for a device
* \param[in] device Path in sysfs to search
*
* Physical devices in a system are described by the system firmware. Depending
* on the type of platform, devices are identified using different naming
* schemes. The Linux kernel abstract those differences with "firmware nodes".
* This function retrieves the firmware node path corresponding to the
* \a device.
*
* For DT-based systems, the path is the full name of the DT node that
* represents the device. For ACPI-based systems, the path is the absolute
* namespace path to the ACPI object that represents the device. In both cases,
* the path is guaranteed to be unique and persistent as long as the system
* firmware is not modified.
*
* \return The firmware node path on success or an empty string on failure
*/
std::string firmwareNodePath(const std::string &device)
{
std::string fwPath, node;
struct stat st;
/* Lookup for DT-based systems */
node = device + "/of_node";
if (!stat(node.c_str(), &st)) {
char *ofPath = realpath(node.c_str(), nullptr);
if (!ofPath)
return {};
static const char prefix[] = "/sys/firmware/devicetree";
if (strncmp(ofPath, prefix, strlen(prefix)) == 0)
fwPath = ofPath + strlen(prefix);
else
fwPath = ofPath;
free(ofPath);
return fwPath;
}
/* Lookup for ACPI-based systems */
node = device + "/firmware_node/path";
if (File::exists(node)) {
std::ifstream file(node);
if (!file.is_open())
return {};
std::getline(file, fwPath);
file.close();
return fwPath;
}
return {};
}
} /* namespace sysfs */
} /* namespace libcamera */