blob: 36da28f5ffe4b37ce7115b2be8ef9a7a3d730018 [file] [log] [blame]
Enrico Granata60b1cbc2019-05-20 11:06:46 -07001// Copyright 2019 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Enrico Granata10e19de2019-05-21 14:17:36 -07005#include <grp.h>
Enrico Granata60b1cbc2019-05-20 11:06:46 -07006#include <stdlib.h>
Enrico Granata10e19de2019-05-21 14:17:36 -07007#include <sys/types.h>
8#include <unistd.h>
9
10#include <memory>
Enrico Granata60b1cbc2019-05-20 11:06:46 -070011
12#include <vector>
13
Qijiang Fan713061e2021-03-08 15:45:12 +090014#include <base/check.h>
Enrico Granata60b1cbc2019-05-20 11:06:46 -070015#include <base/files/file.h>
16#include <base/files/file_path.h>
17#include <base/files/file_util.h>
18#include <base/logging.h>
19#include <base/process/launch.h>
20#include <base/strings/stringprintf.h>
21
22#include "mems_setup/delegate_impl.h"
23
24namespace mems_setup {
25
26namespace {
27const char kVpdDataPath[] =
28 "/mnt/stateful_partition/unencrypted/cache/vpd/full-v2.txt";
29const char kSysModulePath[] = "/sys/module";
30} // namespace
31
32bool LoadVpdFromString(const std::string& vpd_data,
33 std::map<std::string, std::string>* cache) {
34 CHECK(cache);
35
36 size_t nl_pos = 0;
37 const size_t vpd_len = vpd_data.size();
38 while (nl_pos < vpd_len) {
39 const auto i_eq = vpd_data.find('=', nl_pos);
40 if (i_eq == std::string::npos)
41 break;
42
43 auto i_nl = vpd_data.find('\n', i_eq + 1);
44 if (i_nl == std::string::npos)
45 i_nl = vpd_len;
46
47 // VPD entries come in "key"="value" form, including the quotes;
48 // the purpose of the substring operations here is to remove those
Enrico Granata51cdb942019-06-18 16:40:17 -070049 // quotes, as they are inconvenient to deal with from C++ code.
Enrico Granata60b1cbc2019-05-20 11:06:46 -070050 const auto key = vpd_data.substr(nl_pos + 1, i_eq - nl_pos - 2);
51 const auto value = vpd_data.substr(i_eq + 2, i_nl - i_eq - 3);
52 cache->emplace(key, value);
53
54 nl_pos = i_nl + 1;
55 }
56
57 return true;
58}
59
60void DelegateImpl::LoadVpdIfNeeded() {
61 if (vpd_loaded_)
62 return;
63
64 std::string vpd_data;
65 base::FilePath vpd_path(kVpdDataPath);
66 if (!base::ReadFileToString(vpd_path, &vpd_data)) {
67 LOG(ERROR) << "failed to read VPD data";
68 return;
69 }
70
71 vpd_loaded_ = LoadVpdFromString(vpd_data, &vpd_cache_);
72}
73
74base::Optional<std::string> DelegateImpl::ReadVpdValue(const std::string& key) {
75 LoadVpdIfNeeded();
76
77 auto k = vpd_cache_.find(key);
78 if (k != vpd_cache_.end())
79 return k->second;
80 else
81 return base::nullopt;
82}
83
84bool DelegateImpl::ProbeKernelModule(const std::string& module) {
85 base::FilePath init_path(kSysModulePath);
86 init_path = init_path.Append(module).Append("initstate");
87
88 std::string init_data;
89
90 // If we can tell that a module has been loaded, then just return along
91 // the happy path instead of forking a new process.
92 if (base::ReadFileToString(init_path, &init_data)) {
93 if (init_data == "live\n")
94 return true;
95 }
96
97 std::vector<std::string> argv;
98 argv.emplace_back("/sbin/modprobe");
99 argv.emplace_back("-q");
100 argv.emplace_back(module);
101
102 base::Process process(base::LaunchProcess(argv, base::LaunchOptions()));
103 if (!process.IsValid()) {
104 LOG(ERROR) << "failed to launch modprobe";
105 return false;
106 }
107 int exit_code = -1;
108 if (!process.WaitForExit(&exit_code)) {
109 LOG(ERROR) << "modprobe exit could not be detected";
110 return false;
111 }
112 return exit_code == 0;
113}
114
Harvey Yang06ce00f2020-12-01 18:05:23 +0800115bool DelegateImpl::CreateDirectory(const base::FilePath& fp) {
116 return base::CreateDirectory(fp);
117}
118
Enrico Granata60b1cbc2019-05-20 11:06:46 -0700119bool DelegateImpl::Exists(const base::FilePath& fp) {
120 return base::PathExists(fp);
121}
122
Enrico Granata10e19de2019-05-21 14:17:36 -0700123base::Optional<gid_t> DelegateImpl::FindGroupId(const char* group) {
124 size_t len = 1024;
125 const auto max_len = sysconf(_SC_GETGR_R_SIZE_MAX);
Tom Hughes09483d12020-08-27 15:55:08 -0700126 if (max_len != -1)
127 len = max_len;
Enrico Granata10e19de2019-05-21 14:17:36 -0700128
Harvey Yang01020822020-07-28 18:16:26 +0800129 std::vector<char> buf(len);
Enrico Granata10e19de2019-05-21 14:17:36 -0700130 struct group result;
Gwendal Grignoua99b5622020-09-11 13:33:47 -0700131 struct group* resultp = nullptr;
Enrico Granata10e19de2019-05-21 14:17:36 -0700132
Gwendal Grignoua99b5622020-09-11 13:33:47 -0700133 getgrnam_r(group, &result, buf.data(), len, &resultp);
134 if (!resultp)
Enrico Granata10e19de2019-05-21 14:17:36 -0700135 return base::nullopt;
Gwendal Grignoua99b5622020-09-11 13:33:47 -0700136
137 return resultp->gr_gid;
Enrico Granata10e19de2019-05-21 14:17:36 -0700138}
139
140int DelegateImpl::GetPermissions(const base::FilePath& path) {
141 int mode = 0;
142 bool ok = base::GetPosixFilePermissions(path, &mode);
143 if (ok)
144 return mode;
145 return 0;
146}
147
148bool DelegateImpl::SetPermissions(const base::FilePath& path, int mode) {
149 return base::SetPosixFilePermissions(path, mode);
150}
151
152bool DelegateImpl::SetOwnership(const base::FilePath& path,
153 uid_t user,
154 gid_t group) {
155 return lchown(path.value().c_str(), user, group) == 0;
156}
157
Enrico Granata60b1cbc2019-05-20 11:06:46 -0700158} // namespace mems_setup