blob: af5329cb46fdad9ab16c7307b1b5f21e97cea8b5 [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.
#include <grp.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <memory>
#include <vector>
#include <base/files/file.h>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/logging.h>
#include <base/process/launch.h>
#include <base/strings/stringprintf.h>
#include "mems_setup/delegate_impl.h"
namespace mems_setup {
namespace {
const char kVpdDataPath[] =
"/mnt/stateful_partition/unencrypted/cache/vpd/full-v2.txt";
const char kSysModulePath[] = "/sys/module";
} // namespace
bool LoadVpdFromString(const std::string& vpd_data,
std::map<std::string, std::string>* cache) {
CHECK(cache);
size_t nl_pos = 0;
const size_t vpd_len = vpd_data.size();
while (nl_pos < vpd_len) {
const auto i_eq = vpd_data.find('=', nl_pos);
if (i_eq == std::string::npos)
break;
auto i_nl = vpd_data.find('\n', i_eq + 1);
if (i_nl == std::string::npos)
i_nl = vpd_len;
// VPD entries come in "key"="value" form, including the quotes;
// the purpose of the substring operations here is to remove those
// quotes, as they are inconvenient to deal with from C++ code.
const auto key = vpd_data.substr(nl_pos + 1, i_eq - nl_pos - 2);
const auto value = vpd_data.substr(i_eq + 2, i_nl - i_eq - 3);
cache->emplace(key, value);
nl_pos = i_nl + 1;
}
return true;
}
void DelegateImpl::LoadVpdIfNeeded() {
if (vpd_loaded_)
return;
std::string vpd_data;
base::FilePath vpd_path(kVpdDataPath);
if (!base::ReadFileToString(vpd_path, &vpd_data)) {
LOG(ERROR) << "failed to read VPD data";
return;
}
vpd_loaded_ = LoadVpdFromString(vpd_data, &vpd_cache_);
}
base::Optional<std::string> DelegateImpl::ReadVpdValue(const std::string& key) {
LoadVpdIfNeeded();
auto k = vpd_cache_.find(key);
if (k != vpd_cache_.end())
return k->second;
else
return base::nullopt;
}
bool DelegateImpl::ProbeKernelModule(const std::string& module) {
base::FilePath init_path(kSysModulePath);
init_path = init_path.Append(module).Append("initstate");
std::string init_data;
// If we can tell that a module has been loaded, then just return along
// the happy path instead of forking a new process.
if (base::ReadFileToString(init_path, &init_data)) {
if (init_data == "live\n")
return true;
}
std::vector<std::string> argv;
argv.emplace_back("/sbin/modprobe");
argv.emplace_back("-q");
argv.emplace_back(module);
base::Process process(base::LaunchProcess(argv, base::LaunchOptions()));
if (!process.IsValid()) {
LOG(ERROR) << "failed to launch modprobe";
return false;
}
int exit_code = -1;
if (!process.WaitForExit(&exit_code)) {
LOG(ERROR) << "modprobe exit could not be detected";
return false;
}
return exit_code == 0;
}
bool DelegateImpl::Exists(const base::FilePath& fp) {
return base::PathExists(fp);
}
base::Optional<gid_t> DelegateImpl::FindGroupId(const char* group) {
size_t len = 1024;
const auto max_len = sysconf(_SC_GETGR_R_SIZE_MAX);
if (max_len != -1)
len = max_len;
std::vector<char> buf(len);
struct group result;
struct group* resultp = nullptr;
getgrnam_r(group, &result, buf.data(), len, &resultp);
if (!resultp)
return base::nullopt;
return resultp->gr_gid;
}
int DelegateImpl::GetPermissions(const base::FilePath& path) {
int mode = 0;
bool ok = base::GetPosixFilePermissions(path, &mode);
if (ok)
return mode;
return 0;
}
bool DelegateImpl::SetPermissions(const base::FilePath& path, int mode) {
return base::SetPosixFilePermissions(path, mode);
}
bool DelegateImpl::SetOwnership(const base::FilePath& path,
uid_t user,
gid_t group) {
return lchown(path.value().c_str(), user, group) == 0;
}
} // namespace mems_setup