Enrico Granata | 60b1cbc | 2019-05-20 11:06:46 -0700 | [diff] [blame] | 1 | // 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 Granata | 10e19de | 2019-05-21 14:17:36 -0700 | [diff] [blame] | 5 | #include <grp.h> |
Enrico Granata | 60b1cbc | 2019-05-20 11:06:46 -0700 | [diff] [blame] | 6 | #include <stdlib.h> |
Enrico Granata | 10e19de | 2019-05-21 14:17:36 -0700 | [diff] [blame] | 7 | #include <sys/types.h> |
| 8 | #include <unistd.h> |
| 9 | |
| 10 | #include <memory> |
Enrico Granata | 60b1cbc | 2019-05-20 11:06:46 -0700 | [diff] [blame] | 11 | |
| 12 | #include <vector> |
| 13 | |
Qijiang Fan | 713061e | 2021-03-08 15:45:12 +0900 | [diff] [blame] | 14 | #include <base/check.h> |
Enrico Granata | 60b1cbc | 2019-05-20 11:06:46 -0700 | [diff] [blame] | 15 | #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 | |
| 24 | namespace mems_setup { |
| 25 | |
| 26 | namespace { |
| 27 | const char kVpdDataPath[] = |
| 28 | "/mnt/stateful_partition/unencrypted/cache/vpd/full-v2.txt"; |
| 29 | const char kSysModulePath[] = "/sys/module"; |
| 30 | } // namespace |
| 31 | |
| 32 | bool 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 Granata | 51cdb94 | 2019-06-18 16:40:17 -0700 | [diff] [blame] | 49 | // quotes, as they are inconvenient to deal with from C++ code. |
Enrico Granata | 60b1cbc | 2019-05-20 11:06:46 -0700 | [diff] [blame] | 50 | 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 | |
| 60 | void 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 | |
| 74 | base::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 | |
| 84 | bool 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 Yang | 06ce00f | 2020-12-01 18:05:23 +0800 | [diff] [blame] | 115 | bool DelegateImpl::CreateDirectory(const base::FilePath& fp) { |
| 116 | return base::CreateDirectory(fp); |
| 117 | } |
| 118 | |
Enrico Granata | 60b1cbc | 2019-05-20 11:06:46 -0700 | [diff] [blame] | 119 | bool DelegateImpl::Exists(const base::FilePath& fp) { |
| 120 | return base::PathExists(fp); |
| 121 | } |
| 122 | |
Enrico Granata | 10e19de | 2019-05-21 14:17:36 -0700 | [diff] [blame] | 123 | base::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 Hughes | 09483d1 | 2020-08-27 15:55:08 -0700 | [diff] [blame] | 126 | if (max_len != -1) |
| 127 | len = max_len; |
Enrico Granata | 10e19de | 2019-05-21 14:17:36 -0700 | [diff] [blame] | 128 | |
Harvey Yang | 0102082 | 2020-07-28 18:16:26 +0800 | [diff] [blame] | 129 | std::vector<char> buf(len); |
Enrico Granata | 10e19de | 2019-05-21 14:17:36 -0700 | [diff] [blame] | 130 | struct group result; |
Gwendal Grignou | a99b562 | 2020-09-11 13:33:47 -0700 | [diff] [blame] | 131 | struct group* resultp = nullptr; |
Enrico Granata | 10e19de | 2019-05-21 14:17:36 -0700 | [diff] [blame] | 132 | |
Gwendal Grignou | a99b562 | 2020-09-11 13:33:47 -0700 | [diff] [blame] | 133 | getgrnam_r(group, &result, buf.data(), len, &resultp); |
| 134 | if (!resultp) |
Enrico Granata | 10e19de | 2019-05-21 14:17:36 -0700 | [diff] [blame] | 135 | return base::nullopt; |
Gwendal Grignou | a99b562 | 2020-09-11 13:33:47 -0700 | [diff] [blame] | 136 | |
| 137 | return resultp->gr_gid; |
Enrico Granata | 10e19de | 2019-05-21 14:17:36 -0700 | [diff] [blame] | 138 | } |
| 139 | |
| 140 | int 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 | |
| 148 | bool DelegateImpl::SetPermissions(const base::FilePath& path, int mode) { |
| 149 | return base::SetPosixFilePermissions(path, mode); |
| 150 | } |
| 151 | |
| 152 | bool 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 Granata | 60b1cbc | 2019-05-20 11:06:46 -0700 | [diff] [blame] | 158 | } // namespace mems_setup |