[v6,08/16] config: Look up IPA configurables in configuration file
diff mbox series

Message ID 20241206171148.1189292-9-mzamazal@redhat.com
State New
Headers show
Series
  • Add global configuration file
Related show

Commit Message

Milan Zamazal Dec. 6, 2024, 5:11 p.m. UTC
The configuration snippet:

  configuration:
    ipa:
      config_paths:
      - config path 1
      - config path 2
      - ...
      module_paths:
      - module path 1
      - module path 2
      - ...
      force_isolation: BOOL

Signed-off-by: Milan Zamazal <mzamazal@redhat.com>
---
 .../libcamera/internal/global_configuration.h |  4 ++
 src/libcamera/base/global_configuration.cpp   | 51 +++++++++++++++++++
 src/libcamera/ipa_manager.cpp                 | 32 ++++++++----
 src/libcamera/ipa_proxy.cpp                   | 47 ++++++++---------
 4 files changed, 100 insertions(+), 34 deletions(-)

Patch
diff mbox series

diff --git a/include/libcamera/internal/global_configuration.h b/include/libcamera/internal/global_configuration.h
index a6e21a2d..ffa6454c 100644
--- a/include/libcamera/internal/global_configuration.h
+++ b/include/libcamera/internal/global_configuration.h
@@ -48,8 +48,12 @@  std::optional<T> option(const std::string &confPath)
 	return c->get<T>();
 }
 
+std::vector<std::string> listOption(const std::string &confPath);
 std::optional<std::string> envOption(const char *const envVariable,
 				     const std::string &confPath);
+std::vector<std::string> envListOption(
+	const char *const envVariable,
+	const std::string &confPath);
 
 } /* namespace GlobalConfiguration */
 
diff --git a/src/libcamera/base/global_configuration.cpp b/src/libcamera/base/global_configuration.cpp
index 3dc31c48..e69951b4 100644
--- a/src/libcamera/base/global_configuration.cpp
+++ b/src/libcamera/base/global_configuration.cpp
@@ -9,11 +9,14 @@ 
 
 #include <filesystem>
 #include <memory>
+#include <optional>
 #include <string>
 #include <sys/types.h>
+#include <vector>
 
 #include <libcamera/base/file.h>
 #include <libcamera/base/log.h>
+#include <libcamera/base/utils.h>
 
 #include "libcamera/internal/yaml_parser.h"
 
@@ -152,6 +155,24 @@  void initialize()
  * in the configuration file and matches type \a T, no value otherwise
  */
 
+/**
+ * \brief Return values of the configuration option identified by \a confPath
+ * \tparam T The type of the retrieved configuration value
+ * \param[in] confPath Sequence of the YAML section names (excluding
+ * `configuration') leading to the requested list option, separated by dots
+ * \return A vector of strings (empty one if the option is not found)
+ */
+std::vector<std::string> listOption(const std::string &confPath)
+{
+	const YamlObject *c = &configuration();
+	for (auto part : utils::split(confPath, ".")) {
+		c = &(*c)[part];
+		if (!*c)
+			return {};
+	}
+	return c->getList<std::string>().value_or(std::vector<std::string>());
+}
+
 /**
  * \brief Return value of the configuration option from a file or environment
  * \param[in] envVariable Environment variable to get the value from
@@ -179,6 +200,36 @@  std::optional<std::string> envOption(
 	return option<std::string>(confPath);
 }
 
+/**
+ * \brief Return values of the configuration option from a file or environment
+ * \param[in] envVariable Environment variable to get the value from
+ * \param[in] confPath The same as in GlobalConfiguration::option
+ *
+ * This helper looks first at the given environment variable and if it is
+ * defined (even if it is empty) then it splits its value by semicolons and
+ * returns the resulting list of strings. Otherwise it looks for \a confPath the
+ * same way as in GlobalConfiguration::option, value of which must be a list of
+ * strings.
+ *
+ * \note Support for using environment variables to configure libcamera behavior
+ * is provided here mostly for backward compatibility reasons. Introducing new
+ * configuration environment variables is discouraged.
+ *
+ * \return A vector of strings retrieved from the given environment option or
+ * configuration file (an empty vector is returned if nothing is found)
+ */
+std::vector<std::string> envListOption(
+	const char *const envVariable,
+	const std::string &confPath)
+{
+	const char *envValue = utils::secure_getenv(envVariable);
+	if (envValue) {
+		auto items = utils::split(envValue, ":");
+		return std::vector<std::string>(items.begin(), items.end());
+	}
+	return listOption(confPath);
+}
+
 /**
  * \brief Return configuration version
  *
diff --git a/src/libcamera/ipa_manager.cpp b/src/libcamera/ipa_manager.cpp
index 33ae74e8..21753eb6 100644
--- a/src/libcamera/ipa_manager.cpp
+++ b/src/libcamera/ipa_manager.cpp
@@ -9,6 +9,7 @@ 
 
 #include <algorithm>
 #include <dirent.h>
+#include <numeric>
 #include <string.h>
 #include <sys/types.h>
 
@@ -114,18 +115,25 @@  IPAManager::IPAManager()
 	unsigned int ipaCount = 0;
 
 	/* User-specified paths take precedence. */
-	const char *modulePaths = utils::secure_getenv("LIBCAMERA_IPA_MODULE_PATH");
-	if (modulePaths) {
-		for (const auto &dir : utils::split(modulePaths, ":")) {
-			if (dir.empty())
-				continue;
+	const auto modulePaths =
+		GlobalConfiguration::envListOption(
+			"LIBCAMERA_IPA_MODULE_PATH", "ipa.module_paths");
+	for (const auto &dir : modulePaths) {
+		if (dir.empty())
+			continue;
 
-			ipaCount += addDir(dir.c_str());
-		}
+		ipaCount += addDir(dir.c_str());
+	}
 
-		if (!ipaCount)
-			LOG(IPAManager, Warning)
-				<< "No IPA found in '" << modulePaths << "'";
+	if (!ipaCount) {
+		std::string paths;
+		if (!modulePaths.empty()) {
+			paths = std::accumulate(std::next(modulePaths.begin()),
+						modulePaths.end(),
+						modulePaths[0],
+						[](std::string s1, std::string s2) { return s1 + ":" + s2; });
+		}
+		LOG(IPAManager, Warning) << "No IPA found in '" << paths << "'";
 	}
 
 	/*
@@ -289,7 +297,9 @@  bool IPAManager::isSignatureValid([[maybe_unused]] IPAModule *ipa) const
 {
 #if HAVE_IPA_PUBKEY
 	char *force = utils::secure_getenv("LIBCAMERA_IPA_FORCE_ISOLATION");
-	if (force && force[0] != '\0') {
+	if ((force && force[0] != '\0') ||
+	    (!force && GlobalConfiguration::option<bool>("ipa.force_isolation")
+			       .value_or(false))) {
 		LOG(IPAManager, Debug)
 			<< "Isolation of IPA module " << ipa->path()
 			<< " forced through environment variable";
diff --git a/src/libcamera/ipa_proxy.cpp b/src/libcamera/ipa_proxy.cpp
index 85004737..c3630de0 100644
--- a/src/libcamera/ipa_proxy.cpp
+++ b/src/libcamera/ipa_proxy.cpp
@@ -14,6 +14,7 @@ 
 #include <libcamera/base/log.h>
 #include <libcamera/base/utils.h>
 
+#include "libcamera/internal/global_configuration.h"
 #include "libcamera/internal/ipa_module.h"
 
 /**
@@ -107,18 +108,18 @@  std::string IPAProxy::configurationFile(const std::string &name,
 	 */
 	std::string ipaName = ipam_->info().name;
 
-	/* Check the environment variable first. */
-	const char *confPaths = utils::secure_getenv("LIBCAMERA_IPA_CONFIG_PATH");
-	if (confPaths) {
-		for (const auto &dir : utils::split(confPaths, ":")) {
-			if (dir.empty())
-				continue;
+	/* Check the configuration first. */
+	auto confPaths =
+		GlobalConfiguration::envListOption(
+			"LIBCAMERA_IPA_CONFIG_PATH", "ipa.config_paths");
+	for (const auto &dir : confPaths) {
+		if (dir.empty())
+			continue;
 
-			std::string confPath = dir + "/" + ipaName + "/" + name;
-			ret = stat(confPath.c_str(), &statbuf);
-			if (ret == 0 && (statbuf.st_mode & S_IFMT) == S_IFREG)
-				return confPath;
-		}
+		std::string confPath = dir + "/" + ipaName + "/" + name;
+		ret = stat(confPath.c_str(), &statbuf);
+		if (ret == 0 && (statbuf.st_mode & S_IFMT) == S_IFREG)
+			return confPath;
 	}
 
 	std::string root = utils::libcameraSourcePath();
@@ -182,18 +183,18 @@  std::string IPAProxy::resolvePath(const std::string &file) const
 {
 	std::string proxyFile = "/" + file;
 
-	/* Check env variable first. */
-	const char *execPaths = utils::secure_getenv("LIBCAMERA_IPA_PROXY_PATH");
-	if (execPaths) {
-		for (const auto &dir : utils::split(execPaths, ":")) {
-			if (dir.empty())
-				continue;
-
-			std::string proxyPath = dir;
-			proxyPath += proxyFile;
-			if (!access(proxyPath.c_str(), X_OK))
-				return proxyPath;
-		}
+	/* Check the configuration first. */
+	const auto execPaths =
+		GlobalConfiguration::envListOption(
+			"LIBCAMERA_IPA_PROXY_PATH", "ipa.proxy_paths");
+	for (const auto &dir : execPaths) {
+		if (dir.empty())
+			continue;
+
+		std::string proxyPath = dir;
+		proxyPath += proxyFile;
+		if (!access(proxyPath.c_str(), X_OK))
+			return proxyPath;
 	}
 
 	/*