blob: 11beb89782122aba722876be82004dfb3a89ab37 [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 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 = base::SplitString(
command, " ", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
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')
result.pop_back();
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", "psu-type",
base::BindRepeating(&GetOutputForCommand, "mosys psu type")},
{"/hardware-properties", "has-backlight",
base::BindRepeating(&GetHasBacklight)},
{"/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(
logging::GetLastSystemErrorCode());
return false;
}
const auto property_file = path_dir.Append(property);
if (base::WriteFile(property_file, value.data(), 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)
continue;
if (!WriteConfigValue(output_dir, entry.path, entry.property,
value.value()))
return false;
}
return true;
}
} // namespace brillo