blob: e639947988952b659571f4718ed7aea67291ba91 [file] [log] [blame]
// Copyright 2019 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Fallback CrosConfig when running on non-unibuild platforms that
// gets info by calling out to external commands (e.g., mosys)
#include "chromeos-config/libcros_config/cros_config_fallback.h"
#include <iostream>
#include <string>
#include <vector>
#include <base/callback.h>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/optional.h>
#include <base/process/launch.h>
#include <base/strings/string_split.h>
#include <base/system/sys_info.h>
#include <brillo/file_utils.h>
#include "chromeos-config/libcros_config/cros_config_interface.h"
namespace brillo {
namespace {
struct FunctionMapEntry {
// The path and property to match on
const char* path;
const char* property;
// The function to run to generate the contents for the property.
base::RepeatingCallback<base::Optional<std::string>()> function;
// Helper function to get the form factor from /etc/lsb-release
base::Optional<std::string> GetFormFactor() {
std::string device_type;
if (!base::SysInfo::GetLsbReleaseValue("DEVICETYPE", &device_type)) {
CROS_CONFIG_LOG(ERROR) << "Unable to get DEVICETYPE from /etc/lsb-release";
return base::nullopt;
return device_type;
// Helper function to determine if the device has a backlight.
base::Optional<std::string> GetHasBacklight() {
// Assume the device has a backlight unless it is a CHROMEBOX or CHROMEBIT.
std::string device_type;
if (!base::SysInfo::GetLsbReleaseValue("DEVICETYPE", &device_type)) {
CROS_CONFIG_LOG(ERROR) << "Unable to get DEVICETYPE from /etc/lsb-release";
return base::nullopt;
if (device_type == "CHROMEBOX" || device_type == "CHROMEBIT") {
return "false";
return "true";
// Helper function to run a provided command and return the result on success.
// |command| is just a space-separated argv (not parsed by shell)
base::Optional<std::string> GetOutputForCommand(const std::string& command) {
std::string result;
std::vector<std::string> argv{"/usr/bin/env", "-S",
"I_AM_CROS_CONFIG=1 " + command};
if (!base::GetAppOutput(argv, &result)) {
CROS_CONFIG_LOG(ERROR) << "\"" << command << "\" has non-zero exit code";
return base::nullopt;
// Trim off (one) trailing newline from command response.
if (result.back() == '\n')
return result;
const FunctionMapEntry kFunctionMap[] = {
{"/firmware", "image-name",
base::BindRepeating(&GetOutputForCommand, "mosys platform model")},
{"/", "name",
base::BindRepeating(&GetOutputForCommand, "mosys platform model")},
{"/", "brand-code",
base::BindRepeating(&GetOutputForCommand, "mosys platform brand")},
{"/identity", "sku-id",
base::BindRepeating(&GetOutputForCommand, "mosys platform sku")},
{"/identity", "platform-name",
base::BindRepeating(&GetOutputForCommand, "mosys platform name")},
{"/hardware-properties", "form-factor",
{"/hardware-properties", "psu-type",
base::BindRepeating(&GetOutputForCommand, "mosys psu type")},
{"/hardware-properties", "has-backlight",
{"/ui", "help-content-id",
base::BindRepeating(&GetOutputForCommand, "mosys platform customization")},
// Helper function to write a single value to ConfigFS at the given path.
// Returns true if successful and false otherwise.
bool WriteConfigValue(const base::FilePath& output_dir,
const std::string& path,
const std::string& property,
const std::string& value) {
auto path_dir = output_dir;
for (const auto& part : base::SplitStringPiece(
path, "/", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) {
path_dir = path_dir.Append(part);
if (!MkdirRecursively(path_dir, 0755).is_valid()) {
CROS_CONFIG_LOG(ERROR) << "Unable to create directory " << path_dir.value()
<< ": "
<< logging::SystemErrorCodeToString(
return false;
const auto property_file = path_dir.Append(property);
if (base::WriteFile(property_file,, value.length()) < 0) {
CROS_CONFIG_LOG(ERROR) << "Unable to create file " << property_file.value();
return false;
return true;
} // namespace
CrosConfigFallback::CrosConfigFallback() {}
CrosConfigFallback::~CrosConfigFallback() {}
bool CrosConfigFallback::WriteConfigFS(const base::FilePath& output_dir) {
for (auto entry : kFunctionMap) {
auto value = entry.function.Run();
// Not all commands may be supported on every board. Don't
// write the property if the board does not support it.
if (!value)
if (!WriteConfigValue(output_dir, entry.path,,
return false;
return true;
} // namespace brillo