Colin Cross | 5edee2a | 2014-01-23 14:22:48 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2014 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #include <ctype.h> |
Sandeep Patil | c20c0c2 | 2017-02-23 16:09:34 -0800 | [diff] [blame] | 18 | #include <dirent.h> |
Iliyan Malchev | 3ea902f | 2015-05-01 14:05:04 -0700 | [diff] [blame] | 19 | #include <errno.h> |
Yi-Yo Chiang | 2f2fe4a | 2021-03-31 20:39:22 +0800 | [diff] [blame] | 20 | #include <fnmatch.h> |
Colin Cross | 5edee2a | 2014-01-23 14:22:48 -0800 | [diff] [blame] | 21 | #include <stdio.h> |
| 22 | #include <stdlib.h> |
| 23 | #include <string.h> |
| 24 | #include <sys/mount.h> |
Iliyan Malchev | 3ea902f | 2015-05-01 14:05:04 -0700 | [diff] [blame] | 25 | #include <unistd.h> |
Colin Cross | 5edee2a | 2014-01-23 14:22:48 -0800 | [diff] [blame] | 26 | |
Bowgo Tsai | 8028189 | 2017-12-12 00:47:43 +0800 | [diff] [blame] | 27 | #include <algorithm> |
Tom Cherry | 7e34f75 | 2019-01-22 15:37:08 -0800 | [diff] [blame] | 28 | #include <array> |
Bowgo Tsai | 8028189 | 2017-12-12 00:47:43 +0800 | [diff] [blame] | 29 | #include <utility> |
| 30 | #include <vector> |
| 31 | |
Sandeep Patil | c20c0c2 | 2017-02-23 16:09:34 -0800 | [diff] [blame] | 32 | #include <android-base/file.h> |
Jaegeuk Kim | 2aedc82 | 2018-11-20 13:27:06 -0800 | [diff] [blame] | 33 | #include <android-base/parseint.h> |
Victor Hsieh | 98296fc | 2020-02-24 16:02:32 -0800 | [diff] [blame] | 34 | #include <android-base/properties.h> |
Sandeep Patil | c20c0c2 | 2017-02-23 16:09:34 -0800 | [diff] [blame] | 35 | #include <android-base/stringprintf.h> |
| 36 | #include <android-base/strings.h> |
David Anderson | 0e330f1 | 2019-01-03 18:16:56 -0800 | [diff] [blame] | 37 | #include <libgsi/libgsi.h> |
Sandeep Patil | c20c0c2 | 2017-02-23 16:09:34 -0800 | [diff] [blame] | 38 | |
Colin Cross | 5edee2a | 2014-01-23 14:22:48 -0800 | [diff] [blame] | 39 | #include "fs_mgr_priv.h" |
| 40 | |
Howard Chen | 1b09493 | 2019-09-11 18:22:01 +0800 | [diff] [blame] | 41 | using android::base::EndsWith; |
Tom Cherry | 151a17f | 2019-01-21 16:49:13 -0800 | [diff] [blame] | 42 | using android::base::ParseByteCount; |
| 43 | using android::base::ParseInt; |
SzuWei Lin | 77c2847 | 2019-04-22 17:27:52 +0800 | [diff] [blame] | 44 | using android::base::ReadFileToString; |
Nikita Ioffe | 5110628 | 2019-11-21 21:40:03 +0000 | [diff] [blame] | 45 | using android::base::Readlink; |
Tom Cherry | 6bbe947 | 2018-12-13 10:58:37 -0800 | [diff] [blame] | 46 | using android::base::Split; |
Tom Marshall | 66f6a6d | 2018-03-06 16:19:18 +0100 | [diff] [blame] | 47 | using android::base::StartsWith; |
| 48 | |
Tom Cherry | a3530e6 | 2019-01-30 13:25:35 -0800 | [diff] [blame] | 49 | namespace android { |
| 50 | namespace fs_mgr { |
| 51 | namespace { |
| 52 | |
Vic Yang | 5caa3e9 | 2019-08-06 14:15:33 -0700 | [diff] [blame] | 53 | constexpr char kDefaultAndroidDtDir[] = "/proc/device-tree/firmware/android"; |
Yu Ning | c01022a | 2017-07-26 17:54:08 +0800 | [diff] [blame] | 54 | |
Tom Cherry | a3530e6 | 2019-01-30 13:25:35 -0800 | [diff] [blame] | 55 | struct FlagList { |
Colin Cross | 5edee2a | 2014-01-23 14:22:48 -0800 | [diff] [blame] | 56 | const char *name; |
Bowgo Tsai | 4c80edf | 2018-12-12 23:21:13 +0800 | [diff] [blame] | 57 | uint64_t flag; |
Colin Cross | 5edee2a | 2014-01-23 14:22:48 -0800 | [diff] [blame] | 58 | }; |
| 59 | |
Tom Cherry | a3530e6 | 2019-01-30 13:25:35 -0800 | [diff] [blame] | 60 | FlagList kMountFlagsList[] = { |
Tom Cherry | 151a17f | 2019-01-21 16:49:13 -0800 | [diff] [blame] | 61 | {"noatime", MS_NOATIME}, |
| 62 | {"noexec", MS_NOEXEC}, |
| 63 | {"nosuid", MS_NOSUID}, |
| 64 | {"nodev", MS_NODEV}, |
| 65 | {"nodiratime", MS_NODIRATIME}, |
| 66 | {"ro", MS_RDONLY}, |
| 67 | {"rw", 0}, |
Jaegeuk Kim | 5ffa970 | 2019-06-05 17:43:47 -0700 | [diff] [blame] | 68 | {"sync", MS_SYNCHRONOUS}, |
Tom Cherry | 151a17f | 2019-01-21 16:49:13 -0800 | [diff] [blame] | 69 | {"remount", MS_REMOUNT}, |
| 70 | {"bind", MS_BIND}, |
| 71 | {"rec", MS_REC}, |
| 72 | {"unbindable", MS_UNBINDABLE}, |
| 73 | {"private", MS_PRIVATE}, |
| 74 | {"slave", MS_SLAVE}, |
| 75 | {"shared", MS_SHARED}, |
Daniel Rosenberg | 4c93b25 | 2018-08-28 01:41:18 -0700 | [diff] [blame] | 76 | {"defaults", 0}, |
Colin Cross | 5edee2a | 2014-01-23 14:22:48 -0800 | [diff] [blame] | 77 | }; |
| 78 | |
Tom Cherry | a3530e6 | 2019-01-30 13:25:35 -0800 | [diff] [blame] | 79 | off64_t CalculateZramSize(int percentage) { |
Tom Cherry | fafbb64 | 2018-11-29 13:24:09 -0800 | [diff] [blame] | 80 | off64_t total; |
Iliyan Malchev | 3ea902f | 2015-05-01 14:05:04 -0700 | [diff] [blame] | 81 | |
| 82 | total = sysconf(_SC_PHYS_PAGES); |
| 83 | total *= percentage; |
| 84 | total /= 100; |
| 85 | |
| 86 | total *= sysconf(_SC_PAGESIZE); |
| 87 | |
| 88 | return total; |
| 89 | } |
| 90 | |
Tom Cherry | a3530e6 | 2019-01-30 13:25:35 -0800 | [diff] [blame] | 91 | // Fills 'dt_value' with the underlying device tree value string without the trailing '\0'. |
| 92 | // Returns true if 'dt_value' has a valid string, 'false' otherwise. |
| 93 | bool ReadDtFile(const std::string& file_name, std::string* dt_value) { |
Sandeep Patil | 4cd9a46 | 2017-02-24 13:03:39 -0800 | [diff] [blame] | 94 | if (android::base::ReadFileToString(file_name, dt_value)) { |
| 95 | if (!dt_value->empty()) { |
Tom Cherry | a3530e6 | 2019-01-30 13:25:35 -0800 | [diff] [blame] | 96 | // Trim the trailing '\0' out, otherwise the comparison will produce false-negatives. |
Sandeep Patil | 4cd9a46 | 2017-02-24 13:03:39 -0800 | [diff] [blame] | 97 | dt_value->resize(dt_value->size() - 1); |
| 98 | return true; |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | return false; |
| 103 | } |
| 104 | |
Tom Cherry | a3530e6 | 2019-01-30 13:25:35 -0800 | [diff] [blame] | 105 | void ParseFileEncryption(const std::string& arg, FstabEntry* entry) { |
Tom Cherry | 151a17f | 2019-01-21 16:49:13 -0800 | [diff] [blame] | 106 | entry->fs_mgr_flags.file_encryption = true; |
Paul Crowley | 4fa8413 | 2019-10-24 23:33:12 -0700 | [diff] [blame] | 107 | entry->encryption_options = arg; |
Tom Cherry | 7e34f75 | 2019-01-22 15:37:08 -0800 | [diff] [blame] | 108 | } |
| 109 | |
Tom Cherry | a3530e6 | 2019-01-30 13:25:35 -0800 | [diff] [blame] | 110 | bool SetMountFlag(const std::string& flag, FstabEntry* entry) { |
| 111 | for (const auto& [name, value] : kMountFlagsList) { |
Tom Cherry | 151a17f | 2019-01-21 16:49:13 -0800 | [diff] [blame] | 112 | if (flag == name) { |
| 113 | entry->flags |= value; |
| 114 | return true; |
| 115 | } |
| 116 | } |
| 117 | return false; |
| 118 | } |
Colin Cross | 5edee2a | 2014-01-23 14:22:48 -0800 | [diff] [blame] | 119 | |
Tom Cherry | a3530e6 | 2019-01-30 13:25:35 -0800 | [diff] [blame] | 120 | void ParseMountFlags(const std::string& flags, FstabEntry* entry) { |
Tom Cherry | 151a17f | 2019-01-21 16:49:13 -0800 | [diff] [blame] | 121 | std::string fs_options; |
| 122 | for (const auto& flag : Split(flags, ",")) { |
| 123 | if (!SetMountFlag(flag, entry)) { |
| 124 | // Unknown flag, so it must be a filesystem specific option. |
| 125 | if (!fs_options.empty()) { |
| 126 | fs_options.append(","); // appends a comma if not the first |
Colin Cross | 5edee2a | 2014-01-23 14:22:48 -0800 | [diff] [blame] | 127 | } |
Tom Cherry | 151a17f | 2019-01-21 16:49:13 -0800 | [diff] [blame] | 128 | fs_options.append(flag); |
Jaegeuk Kim | f07d07b | 2019-06-13 17:37:01 -0700 | [diff] [blame] | 129 | |
Yi-Yo Chiang | 7b81023 | 2021-05-22 00:35:09 +0800 | [diff] [blame] | 130 | if (auto equal_sign = flag.find('='); equal_sign != std::string::npos) { |
| 131 | const auto arg = flag.substr(equal_sign + 1); |
| 132 | if (entry->fs_type == "f2fs" && StartsWith(flag, "reserve_root=")) { |
Yi-Yo Chiang | fb62a71 | 2021-10-25 21:47:57 +0800 | [diff] [blame] | 133 | off64_t size_in_4k_blocks; |
| 134 | if (!ParseInt(arg, &size_in_4k_blocks, static_cast<off64_t>(0), |
| 135 | std::numeric_limits<off64_t>::max() >> 12)) { |
Yi-Yo Chiang | 7b81023 | 2021-05-22 00:35:09 +0800 | [diff] [blame] | 136 | LWARNING << "Warning: reserve_root= flag malformed: " << arg; |
| 137 | } else { |
Yi-Yo Chiang | fb62a71 | 2021-10-25 21:47:57 +0800 | [diff] [blame] | 138 | entry->reserved_size = size_in_4k_blocks << 12; |
Yi-Yo Chiang | 7b81023 | 2021-05-22 00:35:09 +0800 | [diff] [blame] | 139 | } |
| 140 | } else if (StartsWith(flag, "lowerdir=")) { |
Yi-Yo Chiang | eee9fe4 | 2021-11-12 21:45:24 +0800 | [diff] [blame] | 141 | entry->lowerdir = arg; |
Jaegeuk Kim | f07d07b | 2019-06-13 17:37:01 -0700 | [diff] [blame] | 142 | } |
| 143 | } |
Tom Cherry | 151a17f | 2019-01-21 16:49:13 -0800 | [diff] [blame] | 144 | } |
| 145 | } |
| 146 | entry->fs_options = std::move(fs_options); |
| 147 | } |
| 148 | |
Eric Biggers | b662530 | 2021-11-08 16:38:52 -0800 | [diff] [blame] | 149 | bool ParseFsMgrFlags(const std::string& flags, FstabEntry* entry) { |
Tom Cherry | 151a17f | 2019-01-21 16:49:13 -0800 | [diff] [blame] | 150 | for (const auto& flag : Split(flags, ",")) { |
Mark Salyzyn | c0d09a2 | 2019-02-05 07:30:23 -0800 | [diff] [blame] | 151 | if (flag.empty() || flag == "defaults") continue; |
Tom Cherry | 151a17f | 2019-01-21 16:49:13 -0800 | [diff] [blame] | 152 | std::string arg; |
| 153 | if (auto equal_sign = flag.find('='); equal_sign != std::string::npos) { |
| 154 | arg = flag.substr(equal_sign + 1); |
Colin Cross | 5edee2a | 2014-01-23 14:22:48 -0800 | [diff] [blame] | 155 | } |
| 156 | |
Tom Cherry | 151a17f | 2019-01-21 16:49:13 -0800 | [diff] [blame] | 157 | // First handle flags that simply set a boolean. |
| 158 | #define CheckFlag(flag_name, value) \ |
| 159 | if (flag == flag_name) { \ |
| 160 | entry->fs_mgr_flags.value = true; \ |
| 161 | continue; \ |
Colin Cross | 5edee2a | 2014-01-23 14:22:48 -0800 | [diff] [blame] | 162 | } |
| 163 | |
Tom Cherry | 151a17f | 2019-01-21 16:49:13 -0800 | [diff] [blame] | 164 | CheckFlag("wait", wait); |
| 165 | CheckFlag("check", check); |
| 166 | CheckFlag("nonremovable", nonremovable); |
| 167 | CheckFlag("recoveryonly", recovery_only); |
| 168 | CheckFlag("noemulatedsd", no_emulated_sd); |
| 169 | CheckFlag("notrim", no_trim); |
Tom Cherry | 151a17f | 2019-01-21 16:49:13 -0800 | [diff] [blame] | 170 | CheckFlag("formattable", formattable); |
| 171 | CheckFlag("slotselect", slot_select); |
| 172 | CheckFlag("latemount", late_mount); |
| 173 | CheckFlag("nofail", no_fail); |
Tom Cherry | 151a17f | 2019-01-21 16:49:13 -0800 | [diff] [blame] | 174 | CheckFlag("quota", quota); |
| 175 | CheckFlag("avb", avb); |
| 176 | CheckFlag("logical", logical); |
| 177 | CheckFlag("checkpoint=block", checkpoint_blk); |
| 178 | CheckFlag("checkpoint=fs", checkpoint_fs); |
| 179 | CheckFlag("first_stage_mount", first_stage_mount); |
| 180 | CheckFlag("slotselect_other", slot_select_other); |
| 181 | CheckFlag("fsverity", fs_verity); |
Jaegeuk Kim | 78f040c | 2020-02-11 15:22:46 -0800 | [diff] [blame] | 182 | CheckFlag("metadata_csum", ext_meta_csum); |
Jaegeuk Kim | 4076dc9 | 2020-01-13 11:02:28 -0800 | [diff] [blame] | 183 | CheckFlag("fscompress", fs_compress); |
Yi-Yo Chiang | e7783a9 | 2021-08-03 01:02:31 +0800 | [diff] [blame] | 184 | CheckFlag("overlayfs_remove_missing_lowerdir", overlayfs_remove_missing_lowerdir); |
Tom Cherry | 151a17f | 2019-01-21 16:49:13 -0800 | [diff] [blame] | 185 | |
| 186 | #undef CheckFlag |
| 187 | |
| 188 | // Then handle flags that take an argument. |
Eric Biggers | 9e21700 | 2021-11-12 12:13:30 -0800 | [diff] [blame] | 189 | if (StartsWith(flag, "encryptable=")) { |
Eric Biggers | b662530 | 2021-11-08 16:38:52 -0800 | [diff] [blame] | 190 | // The "encryptable" flag identifies adoptable storage volumes. The |
Eric Biggers | 9e21700 | 2021-11-12 12:13:30 -0800 | [diff] [blame] | 191 | // argument to this flag is ignored, but it should be "userdata". |
Eric Biggers | b662530 | 2021-11-08 16:38:52 -0800 | [diff] [blame] | 192 | // |
| 193 | // Historical note: this flag was originally meant just for /data, |
| 194 | // to indicate that FDE (full disk encryption) can be enabled. |
| 195 | // Unfortunately, it was also overloaded to identify adoptable |
| 196 | // storage volumes. Today, FDE is no longer supported, leaving only |
| 197 | // the adoptable storage volume meaning for this flag. |
Tom Cherry | 151a17f | 2019-01-21 16:49:13 -0800 | [diff] [blame] | 198 | entry->fs_mgr_flags.crypt = true; |
Eric Biggers | 9e21700 | 2021-11-12 12:13:30 -0800 | [diff] [blame] | 199 | } else if (StartsWith(flag, "forceencrypt=") || StartsWith(flag, "forcefdeorfbe=")) { |
Eric Biggers | b662530 | 2021-11-08 16:38:52 -0800 | [diff] [blame] | 200 | LERROR << "flag no longer supported: " << flag; |
| 201 | return false; |
Tom Cherry | 151a17f | 2019-01-21 16:49:13 -0800 | [diff] [blame] | 202 | } else if (StartsWith(flag, "voldmanaged=")) { |
| 203 | // The voldmanaged flag is followed by an = and the label, a colon and the partition |
| 204 | // number or the word "auto", e.g. voldmanaged=sdcard:3 |
| 205 | entry->fs_mgr_flags.vold_managed = true; |
| 206 | auto parts = Split(arg, ":"); |
| 207 | if (parts.size() != 2) { |
| 208 | LWARNING << "Warning: voldmanaged= flag malformed: " << arg; |
| 209 | continue; |
| 210 | } |
| 211 | |
| 212 | entry->label = std::move(parts[0]); |
| 213 | if (parts[1] == "auto") { |
| 214 | entry->partnum = -1; |
| 215 | } else { |
| 216 | if (!ParseInt(parts[1], &entry->partnum)) { |
| 217 | entry->partnum = -1; |
| 218 | LWARNING << "Warning: voldmanaged= flag malformed: " << arg; |
| 219 | continue; |
| 220 | } |
| 221 | } |
| 222 | } else if (StartsWith(flag, "length=")) { |
| 223 | // The length flag is followed by an = and the size of the partition. |
Tom Cherry | 151a17f | 2019-01-21 16:49:13 -0800 | [diff] [blame] | 224 | if (!ParseInt(arg, &entry->length)) { |
| 225 | LWARNING << "Warning: length= flag malformed: " << arg; |
| 226 | } |
| 227 | } else if (StartsWith(flag, "swapprio=")) { |
Tom Cherry | 151a17f | 2019-01-21 16:49:13 -0800 | [diff] [blame] | 228 | if (!ParseInt(arg, &entry->swap_prio)) { |
Felix | 92ed423 | 2020-02-12 17:29:54 +0100 | [diff] [blame] | 229 | LWARNING << "Warning: swapprio= flag malformed: " << arg; |
Tom Cherry | 151a17f | 2019-01-21 16:49:13 -0800 | [diff] [blame] | 230 | } |
| 231 | } else if (StartsWith(flag, "zramsize=")) { |
Tom Cherry | 151a17f | 2019-01-21 16:49:13 -0800 | [diff] [blame] | 232 | if (!arg.empty() && arg.back() == '%') { |
| 233 | arg.pop_back(); |
| 234 | int val; |
| 235 | if (ParseInt(arg, &val, 0, 100)) { |
Tom Cherry | a3530e6 | 2019-01-30 13:25:35 -0800 | [diff] [blame] | 236 | entry->zram_size = CalculateZramSize(val); |
Tom Cherry | 151a17f | 2019-01-21 16:49:13 -0800 | [diff] [blame] | 237 | } else { |
| 238 | LWARNING << "Warning: zramsize= flag malformed: " << arg; |
| 239 | } |
| 240 | } else { |
| 241 | if (!ParseInt(arg, &entry->zram_size)) { |
| 242 | LWARNING << "Warning: zramsize= flag malformed: " << arg; |
| 243 | } |
| 244 | } |
Tom Cherry | 151a17f | 2019-01-21 16:49:13 -0800 | [diff] [blame] | 245 | } else if (StartsWith(flag, "fileencryption=")) { |
| 246 | ParseFileEncryption(arg, entry); |
Tom Cherry | 151a17f | 2019-01-21 16:49:13 -0800 | [diff] [blame] | 247 | } else if (StartsWith(flag, "max_comp_streams=")) { |
Tom Cherry | 151a17f | 2019-01-21 16:49:13 -0800 | [diff] [blame] | 248 | if (!ParseInt(arg, &entry->max_comp_streams)) { |
| 249 | LWARNING << "Warning: max_comp_streams= flag malformed: " << arg; |
| 250 | } |
| 251 | } else if (StartsWith(flag, "reservedsize=")) { |
| 252 | // The reserved flag is followed by an = and the reserved size of the partition. |
Tom Cherry | 151a17f | 2019-01-21 16:49:13 -0800 | [diff] [blame] | 253 | uint64_t size; |
| 254 | if (!ParseByteCount(arg, &size)) { |
| 255 | LWARNING << "Warning: reservedsize= flag malformed: " << arg; |
| 256 | } else { |
| 257 | entry->reserved_size = static_cast<off64_t>(size); |
| 258 | } |
Jaegeuk Kim | 05ca915 | 2021-04-02 21:28:51 -0700 | [diff] [blame] | 259 | } else if (StartsWith(flag, "readahead_size_kb=")) { |
| 260 | int val; |
| 261 | if (ParseInt(arg, &val, 0, 16 * 1024)) { |
| 262 | entry->readahead_size_kb = val; |
| 263 | } else { |
| 264 | LWARNING << "Warning: readahead_size_kb= flag malformed (0 ~ 16MB): " << arg; |
| 265 | } |
Tom Cherry | 151a17f | 2019-01-21 16:49:13 -0800 | [diff] [blame] | 266 | } else if (StartsWith(flag, "eraseblk=")) { |
| 267 | // The erase block size flag is followed by an = and the flash erase block size. Get it, |
| 268 | // check that it is a power of 2 and at least 4096, and return it. |
Tom Cherry | 151a17f | 2019-01-21 16:49:13 -0800 | [diff] [blame] | 269 | off64_t val; |
| 270 | if (!ParseInt(arg, &val) || val < 4096 || (val & (val - 1)) != 0) { |
| 271 | LWARNING << "Warning: eraseblk= flag malformed: " << arg; |
| 272 | } else { |
| 273 | entry->erase_blk_size = val; |
| 274 | } |
| 275 | } else if (StartsWith(flag, "logicalblk=")) { |
| 276 | // The logical block size flag is followed by an = and the flash logical block size. Get |
| 277 | // it, check that it is a power of 2 and at least 4096, and return it. |
Tom Cherry | 151a17f | 2019-01-21 16:49:13 -0800 | [diff] [blame] | 278 | off64_t val; |
| 279 | if (!ParseInt(arg, &val) || val < 4096 || (val & (val - 1)) != 0) { |
| 280 | LWARNING << "Warning: logicalblk= flag malformed: " << arg; |
| 281 | } else { |
| 282 | entry->logical_blk_size = val; |
| 283 | } |
Bowgo Tsai | d214b40 | 2019-02-27 22:56:56 +0800 | [diff] [blame] | 284 | } else if (StartsWith(flag, "avb_keys=")) { // must before the following "avb" |
| 285 | entry->avb_keys = arg; |
Tom Cherry | 151a17f | 2019-01-21 16:49:13 -0800 | [diff] [blame] | 286 | } else if (StartsWith(flag, "avb")) { |
| 287 | entry->fs_mgr_flags.avb = true; |
| 288 | entry->vbmeta_partition = arg; |
| 289 | } else if (StartsWith(flag, "keydirectory=")) { |
Eric Biggers | 20a5f92 | 2022-03-17 23:09:52 +0000 | [diff] [blame] | 290 | // The keydirectory flag enables metadata encryption. It is |
| 291 | // followed by an = and the directory containing the metadata |
| 292 | // encryption key. |
Paul Crowley | 7823e32 | 2020-01-30 16:03:45 -0800 | [diff] [blame] | 293 | entry->metadata_key_dir = arg; |
Barani Muthukumaran | 2ca1d83 | 2020-02-06 23:46:37 -0800 | [diff] [blame] | 294 | } else if (StartsWith(flag, "metadata_encryption=")) { |
Eric Biggers | 20a5f92 | 2022-03-17 23:09:52 +0000 | [diff] [blame] | 295 | // The metadata_encryption flag specifies the cipher and flags to |
| 296 | // use for metadata encryption, if the defaults aren't sufficient. |
| 297 | // It doesn't actually enable metadata encryption; that is done by |
| 298 | // "keydirectory". |
| 299 | entry->metadata_encryption_options = arg; |
Tom Cherry | 151a17f | 2019-01-21 16:49:13 -0800 | [diff] [blame] | 300 | } else if (StartsWith(flag, "sysfs_path=")) { |
| 301 | // The path to trigger device gc by idle-maint of vold. |
Tom Cherry | 151a17f | 2019-01-21 16:49:13 -0800 | [diff] [blame] | 302 | entry->sysfs_path = arg; |
Minchan Kim | 12e9615 | 2019-10-15 14:41:18 -0700 | [diff] [blame] | 303 | } else if (StartsWith(flag, "zram_backingdev_size=")) { |
| 304 | if (!ParseByteCount(arg, &entry->zram_backingdev_size)) { |
| 305 | LWARNING << "Warning: zram_backingdev_size= flag malformed: " << arg; |
Tom Cherry | 151a17f | 2019-01-21 16:49:13 -0800 | [diff] [blame] | 306 | } |
Tom Cherry | 151a17f | 2019-01-21 16:49:13 -0800 | [diff] [blame] | 307 | } else { |
| 308 | LWARNING << "Warning: unknown flag: " << flag; |
| 309 | } |
| 310 | } |
Eric Biggers | b662530 | 2021-11-08 16:38:52 -0800 | [diff] [blame] | 311 | |
Eric Biggers | efe2093 | 2021-11-12 13:07:04 -0800 | [diff] [blame] | 312 | // FDE is no longer supported, so reject "encryptable" when used without |
| 313 | // "vold_managed". For now skip this check when in recovery mode, since |
| 314 | // some recovery fstabs still contain the FDE options since they didn't do |
| 315 | // anything in recovery mode anyway (except possibly to cause the |
| 316 | // reservation of a crypto footer) and thus never got removed. |
| 317 | if (entry->fs_mgr_flags.crypt && !entry->fs_mgr_flags.vold_managed && |
| 318 | access("/system/bin/recovery", F_OK) != 0) { |
Eric Biggers | b662530 | 2021-11-08 16:38:52 -0800 | [diff] [blame] | 319 | LERROR << "FDE is no longer supported; 'encryptable' can only be used for adoptable " |
| 320 | "storage"; |
| 321 | return false; |
| 322 | } |
| 323 | return true; |
Colin Cross | 5edee2a | 2014-01-23 14:22:48 -0800 | [diff] [blame] | 324 | } |
| 325 | |
Tom Cherry | a3530e6 | 2019-01-30 13:25:35 -0800 | [diff] [blame] | 326 | std::string InitAndroidDtDir() { |
Yu Ning | c01022a | 2017-07-26 17:54:08 +0800 | [diff] [blame] | 327 | std::string android_dt_dir; |
| 328 | // The platform may specify a custom Android DT path in kernel cmdline |
Devin Moore | 20b7425 | 2021-03-04 08:23:31 -0800 | [diff] [blame] | 329 | if (!fs_mgr_get_boot_config_from_bootconfig_source("android_dt_dir", &android_dt_dir) && |
| 330 | !fs_mgr_get_boot_config_from_kernel_cmdline("android_dt_dir", &android_dt_dir)) { |
Yu Ning | c01022a | 2017-07-26 17:54:08 +0800 | [diff] [blame] | 331 | // Fall back to the standard procfs-based path |
| 332 | android_dt_dir = kDefaultAndroidDtDir; |
| 333 | } |
| 334 | return android_dt_dir; |
| 335 | } |
| 336 | |
Tom Cherry | a3530e6 | 2019-01-30 13:25:35 -0800 | [diff] [blame] | 337 | bool IsDtFstabCompatible() { |
Sandeep Patil | c20c0c2 | 2017-02-23 16:09:34 -0800 | [diff] [blame] | 338 | std::string dt_value; |
Yu Ning | c01022a | 2017-07-26 17:54:08 +0800 | [diff] [blame] | 339 | std::string file_name = get_android_dt_dir() + "/fstab/compatible"; |
Tom Cherry | 1eb0456 | 2018-11-06 10:42:09 -0800 | [diff] [blame] | 340 | |
Tom Cherry | a3530e6 | 2019-01-30 13:25:35 -0800 | [diff] [blame] | 341 | if (ReadDtFile(file_name, &dt_value) && dt_value == "android,fstab") { |
Tom Cherry | 1eb0456 | 2018-11-06 10:42:09 -0800 | [diff] [blame] | 342 | // If there's no status property or its set to "ok" or "okay", then we use the DT fstab. |
| 343 | std::string status_value; |
| 344 | std::string status_file_name = get_android_dt_dir() + "/fstab/status"; |
Tom Cherry | a3530e6 | 2019-01-30 13:25:35 -0800 | [diff] [blame] | 345 | return !ReadDtFile(status_file_name, &status_value) || status_value == "ok" || |
Tom Cherry | 1eb0456 | 2018-11-06 10:42:09 -0800 | [diff] [blame] | 346 | status_value == "okay"; |
Sandeep Patil | c20c0c2 | 2017-02-23 16:09:34 -0800 | [diff] [blame] | 347 | } |
| 348 | |
| 349 | return false; |
| 350 | } |
| 351 | |
Tom Cherry | a3530e6 | 2019-01-30 13:25:35 -0800 | [diff] [blame] | 352 | std::string ReadFstabFromDt() { |
| 353 | if (!is_dt_compatible() || !IsDtFstabCompatible()) { |
Bowgo Tsai | 8028189 | 2017-12-12 00:47:43 +0800 | [diff] [blame] | 354 | return {}; |
Sandeep Patil | c20c0c2 | 2017-02-23 16:09:34 -0800 | [diff] [blame] | 355 | } |
| 356 | |
Yu Ning | c01022a | 2017-07-26 17:54:08 +0800 | [diff] [blame] | 357 | std::string fstabdir_name = get_android_dt_dir() + "/fstab"; |
Sandeep Patil | c20c0c2 | 2017-02-23 16:09:34 -0800 | [diff] [blame] | 358 | std::unique_ptr<DIR, int (*)(DIR*)> fstabdir(opendir(fstabdir_name.c_str()), closedir); |
Bowgo Tsai | 8028189 | 2017-12-12 00:47:43 +0800 | [diff] [blame] | 359 | if (!fstabdir) return {}; |
Sandeep Patil | c20c0c2 | 2017-02-23 16:09:34 -0800 | [diff] [blame] | 360 | |
| 361 | dirent* dp; |
Bowgo Tsai | 8028189 | 2017-12-12 00:47:43 +0800 | [diff] [blame] | 362 | // Each element in fstab_dt_entries is <mount point, the line format in fstab file>. |
| 363 | std::vector<std::pair<std::string, std::string>> fstab_dt_entries; |
Sandeep Patil | c20c0c2 | 2017-02-23 16:09:34 -0800 | [diff] [blame] | 364 | while ((dp = readdir(fstabdir.get())) != NULL) { |
Bowgo Tsai | 06ed613 | 2017-06-08 10:43:41 +0800 | [diff] [blame] | 365 | // skip over name, compatible and . |
| 366 | if (dp->d_type != DT_DIR || dp->d_name[0] == '.') continue; |
Sandeep Patil | c20c0c2 | 2017-02-23 16:09:34 -0800 | [diff] [blame] | 367 | |
| 368 | // create <dev> <mnt_point> <type> <mnt_flags> <fsmgr_flags>\n |
| 369 | std::vector<std::string> fstab_entry; |
| 370 | std::string file_name; |
| 371 | std::string value; |
Sandeep Patil | be4302b | 2017-05-26 18:09:06 -0700 | [diff] [blame] | 372 | // skip a partition entry if the status property is present and not set to ok |
| 373 | file_name = android::base::StringPrintf("%s/%s/status", fstabdir_name.c_str(), dp->d_name); |
Tom Cherry | a3530e6 | 2019-01-30 13:25:35 -0800 | [diff] [blame] | 374 | if (ReadDtFile(file_name, &value)) { |
Sandeep Patil | be4302b | 2017-05-26 18:09:06 -0700 | [diff] [blame] | 375 | if (value != "okay" && value != "ok") { |
| 376 | LINFO << "dt_fstab: Skip disabled entry for partition " << dp->d_name; |
| 377 | continue; |
| 378 | } |
| 379 | } |
| 380 | |
Sandeep Patil | c20c0c2 | 2017-02-23 16:09:34 -0800 | [diff] [blame] | 381 | file_name = android::base::StringPrintf("%s/%s/dev", fstabdir_name.c_str(), dp->d_name); |
Tom Cherry | a3530e6 | 2019-01-30 13:25:35 -0800 | [diff] [blame] | 382 | if (!ReadDtFile(file_name, &value)) { |
Sandeep Patil | c20c0c2 | 2017-02-23 16:09:34 -0800 | [diff] [blame] | 383 | LERROR << "dt_fstab: Failed to find device for partition " << dp->d_name; |
Bowgo Tsai | 8028189 | 2017-12-12 00:47:43 +0800 | [diff] [blame] | 384 | return {}; |
Sandeep Patil | c20c0c2 | 2017-02-23 16:09:34 -0800 | [diff] [blame] | 385 | } |
Sandeep Patil | c20c0c2 | 2017-02-23 16:09:34 -0800 | [diff] [blame] | 386 | fstab_entry.push_back(value); |
Bowgo Tsai | 8028189 | 2017-12-12 00:47:43 +0800 | [diff] [blame] | 387 | |
| 388 | std::string mount_point; |
| 389 | file_name = |
| 390 | android::base::StringPrintf("%s/%s/mnt_point", fstabdir_name.c_str(), dp->d_name); |
Tom Cherry | a3530e6 | 2019-01-30 13:25:35 -0800 | [diff] [blame] | 391 | if (ReadDtFile(file_name, &value)) { |
Bowgo Tsai | 8028189 | 2017-12-12 00:47:43 +0800 | [diff] [blame] | 392 | LINFO << "dt_fstab: Using a specified mount point " << value << " for " << dp->d_name; |
| 393 | mount_point = value; |
| 394 | } else { |
| 395 | mount_point = android::base::StringPrintf("/%s", dp->d_name); |
| 396 | } |
| 397 | fstab_entry.push_back(mount_point); |
Sandeep Patil | c20c0c2 | 2017-02-23 16:09:34 -0800 | [diff] [blame] | 398 | |
| 399 | file_name = android::base::StringPrintf("%s/%s/type", fstabdir_name.c_str(), dp->d_name); |
Tom Cherry | a3530e6 | 2019-01-30 13:25:35 -0800 | [diff] [blame] | 400 | if (!ReadDtFile(file_name, &value)) { |
Sandeep Patil | c20c0c2 | 2017-02-23 16:09:34 -0800 | [diff] [blame] | 401 | LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name; |
Bowgo Tsai | 8028189 | 2017-12-12 00:47:43 +0800 | [diff] [blame] | 402 | return {}; |
Sandeep Patil | c20c0c2 | 2017-02-23 16:09:34 -0800 | [diff] [blame] | 403 | } |
Sandeep Patil | c20c0c2 | 2017-02-23 16:09:34 -0800 | [diff] [blame] | 404 | fstab_entry.push_back(value); |
| 405 | |
| 406 | file_name = android::base::StringPrintf("%s/%s/mnt_flags", fstabdir_name.c_str(), dp->d_name); |
Tom Cherry | a3530e6 | 2019-01-30 13:25:35 -0800 | [diff] [blame] | 407 | if (!ReadDtFile(file_name, &value)) { |
Sandeep Patil | c20c0c2 | 2017-02-23 16:09:34 -0800 | [diff] [blame] | 408 | LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name; |
Bowgo Tsai | 8028189 | 2017-12-12 00:47:43 +0800 | [diff] [blame] | 409 | return {}; |
Sandeep Patil | c20c0c2 | 2017-02-23 16:09:34 -0800 | [diff] [blame] | 410 | } |
Sandeep Patil | c20c0c2 | 2017-02-23 16:09:34 -0800 | [diff] [blame] | 411 | fstab_entry.push_back(value); |
| 412 | |
| 413 | file_name = android::base::StringPrintf("%s/%s/fsmgr_flags", fstabdir_name.c_str(), dp->d_name); |
Tom Cherry | a3530e6 | 2019-01-30 13:25:35 -0800 | [diff] [blame] | 414 | if (!ReadDtFile(file_name, &value)) { |
Sandeep Patil | c20c0c2 | 2017-02-23 16:09:34 -0800 | [diff] [blame] | 415 | LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name; |
Bowgo Tsai | 8028189 | 2017-12-12 00:47:43 +0800 | [diff] [blame] | 416 | return {}; |
Sandeep Patil | c20c0c2 | 2017-02-23 16:09:34 -0800 | [diff] [blame] | 417 | } |
Sandeep Patil | c20c0c2 | 2017-02-23 16:09:34 -0800 | [diff] [blame] | 418 | fstab_entry.push_back(value); |
Bowgo Tsai | 8028189 | 2017-12-12 00:47:43 +0800 | [diff] [blame] | 419 | // Adds a fstab_entry to fstab_dt_entries, to be sorted by mount_point later. |
| 420 | fstab_dt_entries.emplace_back(mount_point, android::base::Join(fstab_entry, " ")); |
Sandeep Patil | c20c0c2 | 2017-02-23 16:09:34 -0800 | [diff] [blame] | 421 | } |
| 422 | |
Bowgo Tsai | 8028189 | 2017-12-12 00:47:43 +0800 | [diff] [blame] | 423 | // Sort fstab_dt entries, to ensure /vendor is mounted before /vendor/abc is attempted. |
| 424 | std::sort(fstab_dt_entries.begin(), fstab_dt_entries.end(), |
| 425 | [](const auto& a, const auto& b) { return a.first < b.first; }); |
| 426 | |
| 427 | std::string fstab_result; |
| 428 | for (const auto& [_, dt_entry] : fstab_dt_entries) { |
| 429 | fstab_result += dt_entry + "\n"; |
| 430 | } |
| 431 | return fstab_result; |
Sandeep Patil | c20c0c2 | 2017-02-23 16:09:34 -0800 | [diff] [blame] | 432 | } |
| 433 | |
Eric Biggers | e98afa2 | 2021-07-29 19:04:41 -0700 | [diff] [blame] | 434 | // Return the path to the fstab file. There may be multiple fstab files; the |
| 435 | // one that is returned will be the first that exists of fstab.<fstab_suffix>, |
| 436 | // fstab.<hardware>, and fstab.<hardware.platform>. The fstab is searched for |
| 437 | // in /odm/etc/ and /vendor/etc/, as well as in the locations where it may be in |
| 438 | // the first stage ramdisk during early boot. Previously, the first stage |
| 439 | // ramdisk's copy of the fstab had to be located in the root directory, but now |
| 440 | // the system/etc directory is supported too and is the preferred location. |
Tom Cherry | a3530e6 | 2019-01-30 13:25:35 -0800 | [diff] [blame] | 441 | std::string GetFstabPath() { |
Alistair Delva | a2cc1eb | 2020-05-20 16:24:00 -0700 | [diff] [blame] | 442 | for (const char* prop : {"fstab_suffix", "hardware", "hardware.platform"}) { |
| 443 | std::string suffix; |
Tom Cherry | a3530e6 | 2019-01-30 13:25:35 -0800 | [diff] [blame] | 444 | |
Alistair Delva | a2cc1eb | 2020-05-20 16:24:00 -0700 | [diff] [blame] | 445 | if (!fs_mgr_get_boot_config(prop, &suffix)) continue; |
Tom Cherry | a3530e6 | 2019-01-30 13:25:35 -0800 | [diff] [blame] | 446 | |
Eric Biggers | e98afa2 | 2021-07-29 19:04:41 -0700 | [diff] [blame] | 447 | for (const char* prefix : {// late-boot/post-boot locations |
| 448 | "/odm/etc/fstab.", "/vendor/etc/fstab.", |
| 449 | // early boot locations |
| 450 | "/system/etc/fstab.", "/first_stage_ramdisk/system/etc/fstab.", |
| 451 | "/fstab.", "/first_stage_ramdisk/fstab."}) { |
Alistair Delva | a2cc1eb | 2020-05-20 16:24:00 -0700 | [diff] [blame] | 452 | std::string fstab_path = prefix + suffix; |
Tom Cherry | a3530e6 | 2019-01-30 13:25:35 -0800 | [diff] [blame] | 453 | if (access(fstab_path.c_str(), F_OK) == 0) { |
| 454 | return fstab_path; |
| 455 | } |
Sandeep Patil | e396c60 | 2017-02-24 11:04:49 -0800 | [diff] [blame] | 456 | } |
| 457 | } |
| 458 | |
Tom Cherry | a3530e6 | 2019-01-30 13:25:35 -0800 | [diff] [blame] | 459 | return ""; |
Sandeep Patil | e396c60 | 2017-02-24 11:04:49 -0800 | [diff] [blame] | 460 | } |
Sandeep Patil | c20c0c2 | 2017-02-23 16:09:34 -0800 | [diff] [blame] | 461 | |
Yi-Yo Chiang | b398a0b | 2021-10-25 21:34:05 +0800 | [diff] [blame] | 462 | /* Extracts <device>s from the by-name symlinks specified in a fstab: |
| 463 | * /dev/block/<type>/<device>/by-name/<partition> |
| 464 | * |
| 465 | * <type> can be: platform, pci or vbd. |
| 466 | * |
| 467 | * For example, given the following entries in the input fstab: |
| 468 | * /dev/block/platform/soc/1da4000.ufshc/by-name/system |
| 469 | * /dev/block/pci/soc.0/f9824900.sdhci/by-name/vendor |
| 470 | * it returns a set { "soc/1da4000.ufshc", "soc.0/f9824900.sdhci" }. |
| 471 | */ |
| 472 | std::set<std::string> ExtraBootDevices(const Fstab& fstab) { |
| 473 | std::set<std::string> boot_devices; |
| 474 | |
| 475 | for (const auto& entry : fstab) { |
| 476 | std::string blk_device = entry.blk_device; |
| 477 | // Skips blk_device that doesn't conform to the format. |
| 478 | if (!android::base::StartsWith(blk_device, "/dev/block") || |
| 479 | android::base::StartsWith(blk_device, "/dev/block/by-name") || |
| 480 | android::base::StartsWith(blk_device, "/dev/block/bootdevice/by-name")) { |
| 481 | continue; |
| 482 | } |
| 483 | // Skips non-by_name blk_device. |
| 484 | // /dev/block/<type>/<device>/by-name/<partition> |
| 485 | // ^ slash_by_name |
| 486 | auto slash_by_name = blk_device.find("/by-name"); |
| 487 | if (slash_by_name == std::string::npos) continue; |
| 488 | blk_device.erase(slash_by_name); // erases /by-name/<partition> |
| 489 | |
| 490 | // Erases /dev/block/, now we have <type>/<device> |
| 491 | blk_device.erase(0, std::string("/dev/block/").size()); |
| 492 | |
| 493 | // <type>/<device> |
| 494 | // ^ first_slash |
| 495 | auto first_slash = blk_device.find('/'); |
| 496 | if (first_slash == std::string::npos) continue; |
| 497 | |
| 498 | auto boot_device = blk_device.substr(first_slash + 1); |
| 499 | if (!boot_device.empty()) boot_devices.insert(std::move(boot_device)); |
| 500 | } |
| 501 | |
| 502 | return boot_devices; |
| 503 | } |
| 504 | |
| 505 | FstabEntry BuildDsuUserdataFstabEntry() { |
| 506 | constexpr uint32_t kFlags = MS_NOATIME | MS_NOSUID | MS_NODEV; |
| 507 | |
| 508 | FstabEntry userdata = { |
| 509 | .blk_device = "userdata_gsi", |
| 510 | .mount_point = "/data", |
| 511 | .fs_type = "ext4", |
| 512 | .flags = kFlags, |
| 513 | .reserved_size = 128 * 1024 * 1024, |
| 514 | }; |
| 515 | userdata.fs_mgr_flags.wait = true; |
| 516 | userdata.fs_mgr_flags.check = true; |
| 517 | userdata.fs_mgr_flags.logical = true; |
| 518 | userdata.fs_mgr_flags.quota = true; |
| 519 | userdata.fs_mgr_flags.late_mount = true; |
| 520 | userdata.fs_mgr_flags.formattable = true; |
| 521 | return userdata; |
| 522 | } |
| 523 | |
| 524 | bool EraseFstabEntry(Fstab* fstab, const std::string& mount_point) { |
| 525 | auto iter = std::remove_if(fstab->begin(), fstab->end(), |
| 526 | [&](const auto& entry) { return entry.mount_point == mount_point; }); |
| 527 | if (iter != fstab->end()) { |
| 528 | fstab->erase(iter, fstab->end()); |
| 529 | return true; |
| 530 | } |
| 531 | return false; |
| 532 | } |
| 533 | |
| 534 | } // namespace |
| 535 | |
Yi-Yo Chiang | 97f2fdf | 2021-11-12 19:19:29 +0800 | [diff] [blame] | 536 | bool ParseFstabFromString(const std::string& fstab_str, bool proc_mounts, Fstab* fstab_out) { |
Yi-Yo Chiang | b883739 | 2021-11-11 22:17:35 +0800 | [diff] [blame] | 537 | const int expected_fields = proc_mounts ? 4 : 5; |
Yi-Yo Chiang | 97f2fdf | 2021-11-12 19:19:29 +0800 | [diff] [blame] | 538 | |
Tom Cherry | d0be7a5 | 2018-11-29 13:04:52 -0800 | [diff] [blame] | 539 | Fstab fstab; |
Colin Cross | 5edee2a | 2014-01-23 14:22:48 -0800 | [diff] [blame] | 540 | |
Yi-Yo Chiang | 97f2fdf | 2021-11-12 19:19:29 +0800 | [diff] [blame] | 541 | for (const auto& line : android::base::Split(fstab_str, "\n")) { |
Yi-Yo Chiang | b883739 | 2021-11-11 22:17:35 +0800 | [diff] [blame] | 542 | auto fields = android::base::Tokenize(line, " \t"); |
Yi-Yo Chiang | 97f2fdf | 2021-11-12 19:19:29 +0800 | [diff] [blame] | 543 | |
| 544 | // Ignore empty lines and comments. |
| 545 | if (fields.empty() || android::base::StartsWith(fields.front(), '#')) { |
| 546 | continue; |
| 547 | } |
| 548 | |
Yi-Yo Chiang | b883739 | 2021-11-11 22:17:35 +0800 | [diff] [blame] | 549 | if (fields.size() < expected_fields) { |
| 550 | LERROR << "Error parsing fstab: expected " << expected_fields << " fields, got " |
| 551 | << fields.size(); |
Yi-Yo Chiang | 97f2fdf | 2021-11-12 19:19:29 +0800 | [diff] [blame] | 552 | return false; |
Yi-Yo Chiang | b883739 | 2021-11-11 22:17:35 +0800 | [diff] [blame] | 553 | } |
| 554 | |
Tom Cherry | d0be7a5 | 2018-11-29 13:04:52 -0800 | [diff] [blame] | 555 | FstabEntry entry; |
Yi-Yo Chiang | b883739 | 2021-11-11 22:17:35 +0800 | [diff] [blame] | 556 | auto it = fields.begin(); |
Colin Cross | 5edee2a | 2014-01-23 14:22:48 -0800 | [diff] [blame] | 557 | |
Yi-Yo Chiang | b883739 | 2021-11-11 22:17:35 +0800 | [diff] [blame] | 558 | entry.blk_device = std::move(*it++); |
| 559 | entry.mount_point = std::move(*it++); |
| 560 | entry.fs_type = std::move(*it++); |
| 561 | ParseMountFlags(std::move(*it++), &entry); |
Colin Cross | 5edee2a | 2014-01-23 14:22:48 -0800 | [diff] [blame] | 562 | |
Mark Salyzyn | eba4706 | 2018-06-20 13:07:28 -0700 | [diff] [blame] | 563 | // For /proc/mounts, ignore everything after mnt_freq and mnt_passno |
Yi-Yo Chiang | b883739 | 2021-11-11 22:17:35 +0800 | [diff] [blame] | 564 | if (!proc_mounts && !ParseFsMgrFlags(std::move(*it++), &entry)) { |
Eric Biggers | b662530 | 2021-11-08 16:38:52 -0800 | [diff] [blame] | 565 | LERROR << "Error parsing fs_mgr_flags"; |
Yi-Yo Chiang | 97f2fdf | 2021-11-12 19:19:29 +0800 | [diff] [blame] | 566 | return false; |
Eric Biggers | b662530 | 2021-11-08 16:38:52 -0800 | [diff] [blame] | 567 | } |
Tom Cherry | 151a17f | 2019-01-21 16:49:13 -0800 | [diff] [blame] | 568 | |
Tom Cherry | d0be7a5 | 2018-11-29 13:04:52 -0800 | [diff] [blame] | 569 | if (entry.fs_mgr_flags.logical) { |
| 570 | entry.logical_partition_name = entry.blk_device; |
David Anderson | 62e5b20 | 2018-05-01 17:09:17 -0700 | [diff] [blame] | 571 | } |
| 572 | |
Tom Cherry | d0be7a5 | 2018-11-29 13:04:52 -0800 | [diff] [blame] | 573 | fstab.emplace_back(std::move(entry)); |
Colin Cross | 5edee2a | 2014-01-23 14:22:48 -0800 | [diff] [blame] | 574 | } |
Tom Cherry | d0be7a5 | 2018-11-29 13:04:52 -0800 | [diff] [blame] | 575 | |
| 576 | if (fstab.empty()) { |
| 577 | LERROR << "No entries found in fstab"; |
Yi-Yo Chiang | 97f2fdf | 2021-11-12 19:19:29 +0800 | [diff] [blame] | 578 | return false; |
Tom Cherry | d0be7a5 | 2018-11-29 13:04:52 -0800 | [diff] [blame] | 579 | } |
| 580 | |
David Zeuthen | 227ef3c | 2015-09-03 12:23:12 -0400 | [diff] [blame] | 581 | /* If an A/B partition, modify block device to be the real block device */ |
Tom Cherry | d0be7a5 | 2018-11-29 13:04:52 -0800 | [diff] [blame] | 582 | if (!fs_mgr_update_for_slotselect(&fstab)) { |
bowgotsai | 47878de | 2017-01-23 14:04:34 +0800 | [diff] [blame] | 583 | LERROR << "Error updating for slotselect"; |
Yi-Yo Chiang | 97f2fdf | 2021-11-12 19:19:29 +0800 | [diff] [blame] | 584 | return false; |
David Zeuthen | 227ef3c | 2015-09-03 12:23:12 -0400 | [diff] [blame] | 585 | } |
Yi-Yo Chiang | 97f2fdf | 2021-11-12 19:19:29 +0800 | [diff] [blame] | 586 | |
Tom Cherry | d0be7a5 | 2018-11-29 13:04:52 -0800 | [diff] [blame] | 587 | *fstab_out = std::move(fstab); |
| 588 | return true; |
Bowgo Tsai | 47d3427 | 2017-03-06 22:22:07 +0800 | [diff] [blame] | 589 | } |
| 590 | |
Yo Chiang | 165d9ae | 2020-09-23 19:48:05 +0800 | [diff] [blame] | 591 | void TransformFstabForDsu(Fstab* fstab, const std::string& dsu_slot, |
| 592 | const std::vector<std::string>& dsu_partitions) { |
Bowgo Tsai | a2ac846 | 2019-12-11 15:03:00 +0800 | [diff] [blame] | 593 | static constexpr char kDsuKeysDir[] = "/avb"; |
Howard Chen | 1b09493 | 2019-09-11 18:22:01 +0800 | [diff] [blame] | 594 | // Convert userdata |
David Anderson | 88045ae | 2019-02-04 19:02:19 -0800 | [diff] [blame] | 595 | // Inherit fstab properties for userdata. |
| 596 | FstabEntry userdata; |
| 597 | if (FstabEntry* entry = GetEntryForMountPoint(fstab, "/data")) { |
| 598 | userdata = *entry; |
Yo Chiang | 62c75b1 | 2020-10-21 21:43:13 +0800 | [diff] [blame] | 599 | userdata.blk_device = android::gsi::kDsuUserdata; |
David Anderson | 88045ae | 2019-02-04 19:02:19 -0800 | [diff] [blame] | 600 | userdata.fs_mgr_flags.logical = true; |
| 601 | userdata.fs_mgr_flags.formattable = true; |
Paul Crowley | 7823e32 | 2020-01-30 16:03:45 -0800 | [diff] [blame] | 602 | if (!userdata.metadata_key_dir.empty()) { |
Yo Chiang | 165d9ae | 2020-09-23 19:48:05 +0800 | [diff] [blame] | 603 | userdata.metadata_key_dir = android::gsi::GetDsuMetadataKeyDir(dsu_slot); |
David Anderson | 88045ae | 2019-02-04 19:02:19 -0800 | [diff] [blame] | 604 | } |
| 605 | } else { |
Howard Chen | 1b09493 | 2019-09-11 18:22:01 +0800 | [diff] [blame] | 606 | userdata = BuildDsuUserdataFstabEntry(); |
Bowgo Tsai | 9bbaa7b | 2019-02-18 17:56:58 +0800 | [diff] [blame] | 607 | } |
David Anderson | 88045ae | 2019-02-04 19:02:19 -0800 | [diff] [blame] | 608 | |
Bowgo Tsai | 9bbaa7b | 2019-02-18 17:56:58 +0800 | [diff] [blame] | 609 | if (EraseFstabEntry(fstab, "/data")) { |
| 610 | fstab->emplace_back(userdata); |
| 611 | } |
David Anderson | 0e330f1 | 2019-01-03 18:16:56 -0800 | [diff] [blame] | 612 | |
Howard Chen | 1b09493 | 2019-09-11 18:22:01 +0800 | [diff] [blame] | 613 | // Convert others |
| 614 | for (auto&& partition : dsu_partitions) { |
| 615 | if (!EndsWith(partition, gsi::kDsuPostfix)) { |
| 616 | continue; |
| 617 | } |
| 618 | // userdata has been handled |
Yo Chiang | 62c75b1 | 2020-10-21 21:43:13 +0800 | [diff] [blame] | 619 | if (partition == android::gsi::kDsuUserdata) { |
| 620 | continue; |
| 621 | } |
| 622 | // scratch is handled by fs_mgr_overlayfs |
| 623 | if (partition == android::gsi::kDsuScratch) { |
Howard Chen | 1b09493 | 2019-09-11 18:22:01 +0800 | [diff] [blame] | 624 | continue; |
| 625 | } |
| 626 | // dsu_partition_name = corresponding_partition_name + kDsuPostfix |
| 627 | // e.g. |
| 628 | // system_gsi for system |
| 629 | // product_gsi for product |
| 630 | // vendor_gsi for vendor |
| 631 | std::string lp_name = partition.substr(0, partition.length() - strlen(gsi::kDsuPostfix)); |
| 632 | std::string mount_point = "/" + lp_name; |
| 633 | std::vector<FstabEntry*> entries = GetEntriesForMountPoint(fstab, mount_point); |
| 634 | if (entries.empty()) { |
| 635 | FstabEntry entry = { |
| 636 | .blk_device = partition, |
Nick Desaulniers | 8e04844 | 2019-10-11 10:52:16 -0700 | [diff] [blame] | 637 | // .logical_partition_name is required to look up AVB Hashtree descriptors. |
| 638 | .logical_partition_name = "system", |
Howard Chen | 1b09493 | 2019-09-11 18:22:01 +0800 | [diff] [blame] | 639 | .mount_point = mount_point, |
| 640 | .fs_type = "ext4", |
| 641 | .flags = MS_RDONLY, |
| 642 | .fs_options = "barrier=1", |
Bowgo Tsai | a2ac846 | 2019-12-11 15:03:00 +0800 | [diff] [blame] | 643 | .avb_keys = kDsuKeysDir, |
Nick Desaulniers | 8e04844 | 2019-10-11 10:52:16 -0700 | [diff] [blame] | 644 | }; |
Howard Chen | 1b09493 | 2019-09-11 18:22:01 +0800 | [diff] [blame] | 645 | entry.fs_mgr_flags.wait = true; |
| 646 | entry.fs_mgr_flags.logical = true; |
| 647 | entry.fs_mgr_flags.first_stage_mount = true; |
Yo Chiang | e48dbc2 | 2020-08-19 14:17:37 +0800 | [diff] [blame] | 648 | fstab->emplace_back(entry); |
Howard Chen | 1b09493 | 2019-09-11 18:22:01 +0800 | [diff] [blame] | 649 | } else { |
| 650 | // If the corresponding partition exists, transform all its Fstab |
| 651 | // by pointing .blk_device to the DSU partition. |
| 652 | for (auto&& entry : entries) { |
| 653 | entry->blk_device = partition; |
Bowgo Tsai | a2ac846 | 2019-12-11 15:03:00 +0800 | [diff] [blame] | 654 | // AVB keys for DSU should always be under kDsuKeysDir. |
Yo Chiang | e48dbc2 | 2020-08-19 14:17:37 +0800 | [diff] [blame] | 655 | entry->avb_keys = kDsuKeysDir; |
Tim Zimmermann | 496132b | 2022-04-16 22:37:08 +0200 | [diff] [blame] | 656 | entry->fs_mgr_flags.logical = true; |
Howard Chen | 1b09493 | 2019-09-11 18:22:01 +0800 | [diff] [blame] | 657 | } |
| 658 | // Make sure the ext4 is included to support GSI. |
| 659 | auto partition_ext4 = |
| 660 | std::find_if(fstab->begin(), fstab->end(), [&](const auto& entry) { |
| 661 | return entry.mount_point == mount_point && entry.fs_type == "ext4"; |
| 662 | }); |
| 663 | if (partition_ext4 == fstab->end()) { |
| 664 | auto new_entry = *GetEntryForMountPoint(fstab, mount_point); |
| 665 | new_entry.fs_type = "ext4"; |
Yi-Yo Chiang | 6bcabc0 | 2022-02-18 22:54:50 +0800 | [diff] [blame] | 666 | auto it = std::find_if(fstab->rbegin(), fstab->rend(), |
| 667 | [&mount_point](const auto& entry) { |
| 668 | return entry.mount_point == mount_point; |
| 669 | }); |
| 670 | auto end_of_mount_point_group = fstab->begin() + std::distance(it, fstab->rend()); |
| 671 | fstab->insert(end_of_mount_point_group, new_entry); |
Howard Chen | 1b09493 | 2019-09-11 18:22:01 +0800 | [diff] [blame] | 672 | } |
| 673 | } |
| 674 | } |
| 675 | } |
Tom Cherry | a3530e6 | 2019-01-30 13:25:35 -0800 | [diff] [blame] | 676 | |
Victor Hsieh | 98296fc | 2020-02-24 16:02:32 -0800 | [diff] [blame] | 677 | void EnableMandatoryFlags(Fstab* fstab) { |
Jeff Vander Stoep | eb74938 | 2021-11-22 10:22:09 +0100 | [diff] [blame] | 678 | // Devices launched in R and after must support fs_verity. Set flag to cause tune2fs |
| 679 | // to enable the feature on userdata and metadata partitions. |
Victor Hsieh | 98296fc | 2020-02-24 16:02:32 -0800 | [diff] [blame] | 680 | if (android::base::GetIntProperty("ro.product.first_api_level", 0) >= 30) { |
Jeff Vander Stoep | eb74938 | 2021-11-22 10:22:09 +0100 | [diff] [blame] | 681 | // Devices launched in R and after should enable fs_verity on userdata. |
| 682 | // A better alternative would be to enable on mkfs at the beginning. |
Victor Hsieh | 98296fc | 2020-02-24 16:02:32 -0800 | [diff] [blame] | 683 | std::vector<FstabEntry*> data_entries = GetEntriesForMountPoint(fstab, "/data"); |
| 684 | for (auto&& entry : data_entries) { |
| 685 | // Besides ext4, f2fs is also supported. But the image is already created with verity |
| 686 | // turned on when it was first introduced. |
| 687 | if (entry->fs_type == "ext4") { |
| 688 | entry->fs_mgr_flags.fs_verity = true; |
| 689 | } |
| 690 | } |
Jeff Vander Stoep | eb74938 | 2021-11-22 10:22:09 +0100 | [diff] [blame] | 691 | // Devices shipping with S and earlier likely do not already have fs_verity enabled via |
| 692 | // mkfs, so enable it here. |
| 693 | std::vector<FstabEntry*> metadata_entries = GetEntriesForMountPoint(fstab, "/metadata"); |
| 694 | for (auto&& entry : metadata_entries) { |
| 695 | entry->fs_mgr_flags.fs_verity = true; |
| 696 | } |
Victor Hsieh | 98296fc | 2020-02-24 16:02:32 -0800 | [diff] [blame] | 697 | } |
| 698 | } |
| 699 | |
Yi-Yo Chiang | 1a3c050 | 2021-03-30 20:28:21 +0800 | [diff] [blame] | 700 | bool ReadFstabFromFile(const std::string& path, Fstab* fstab_out) { |
Yi-Yo Chiang | 97f2fdf | 2021-11-12 19:19:29 +0800 | [diff] [blame] | 701 | const bool is_proc_mounts = (path == "/proc/mounts"); |
| 702 | |
| 703 | std::string fstab_str; |
| 704 | if (!android::base::ReadFileToString(path, &fstab_str, /* follow_symlinks = */ true)) { |
| 705 | PERROR << __FUNCTION__ << "(): failed to read file: '" << path << "'"; |
Tom Cherry | d0be7a5 | 2018-11-29 13:04:52 -0800 | [diff] [blame] | 706 | return false; |
| 707 | } |
| 708 | |
Yi-Yo Chiang | 1a3c050 | 2021-03-30 20:28:21 +0800 | [diff] [blame] | 709 | Fstab fstab; |
Yi-Yo Chiang | 97f2fdf | 2021-11-12 19:19:29 +0800 | [diff] [blame] | 710 | if (!ParseFstabFromString(fstab_str, is_proc_mounts, &fstab)) { |
Tom Cherry | d0be7a5 | 2018-11-29 13:04:52 -0800 | [diff] [blame] | 711 | LERROR << __FUNCTION__ << "(): failed to load fstab from : '" << path << "'"; |
| 712 | return false; |
| 713 | } |
Yi-Yo Chiang | ea4369d | 2021-03-22 13:45:09 +0800 | [diff] [blame] | 714 | if (!is_proc_mounts) { |
| 715 | if (!access(android::gsi::kGsiBootedIndicatorFile, F_OK)) { |
| 716 | // This is expected to fail if host is android Q, since Q doesn't |
| 717 | // support DSU slotting. The DSU "active" indicator file would be |
| 718 | // non-existent or empty if DSU is enabled within the guest system. |
| 719 | // In that case, just use the default slot name "dsu". |
| 720 | std::string dsu_slot; |
| 721 | if (!android::gsi::GetActiveDsu(&dsu_slot) && errno != ENOENT) { |
| 722 | PERROR << __FUNCTION__ << "(): failed to get active DSU slot"; |
| 723 | return false; |
| 724 | } |
| 725 | if (dsu_slot.empty()) { |
| 726 | dsu_slot = "dsu"; |
| 727 | LWARNING << __FUNCTION__ << "(): assuming default DSU slot: " << dsu_slot; |
| 728 | } |
| 729 | // This file is non-existent on Q vendor. |
| 730 | std::string lp_names; |
| 731 | if (!ReadFileToString(gsi::kGsiLpNamesFile, &lp_names) && errno != ENOENT) { |
| 732 | PERROR << __FUNCTION__ << "(): failed to read DSU LP names"; |
| 733 | return false; |
| 734 | } |
Yi-Yo Chiang | 1a3c050 | 2021-03-30 20:28:21 +0800 | [diff] [blame] | 735 | TransformFstabForDsu(&fstab, dsu_slot, Split(lp_names, ",")); |
Yi-Yo Chiang | ea4369d | 2021-03-22 13:45:09 +0800 | [diff] [blame] | 736 | } else if (errno != ENOENT) { |
| 737 | PERROR << __FUNCTION__ << "(): failed to access() DSU booted indicator"; |
| 738 | return false; |
Yo Chiang | cb1d0d9 | 2020-11-09 17:45:35 +0800 | [diff] [blame] | 739 | } |
David Anderson | 0e330f1 | 2019-01-03 18:16:56 -0800 | [diff] [blame] | 740 | } |
Tom Cherry | d0be7a5 | 2018-11-29 13:04:52 -0800 | [diff] [blame] | 741 | |
Yi-Yo Chiang | 1a3c050 | 2021-03-30 20:28:21 +0800 | [diff] [blame] | 742 | SkipMountingPartitions(&fstab, false /* verbose */); |
| 743 | EnableMandatoryFlags(&fstab); |
SzuWei Lin | 77c2847 | 2019-04-22 17:27:52 +0800 | [diff] [blame] | 744 | |
Yi-Yo Chiang | 1a3c050 | 2021-03-30 20:28:21 +0800 | [diff] [blame] | 745 | *fstab_out = std::move(fstab); |
Tom Cherry | d0be7a5 | 2018-11-29 13:04:52 -0800 | [diff] [blame] | 746 | return true; |
| 747 | } |
| 748 | |
Tom Cherry | d0be7a5 | 2018-11-29 13:04:52 -0800 | [diff] [blame] | 749 | // Returns fstab entries parsed from the device tree if they exist |
Yi-Yo Chiang | 2057901 | 2021-04-01 20:14:54 +0800 | [diff] [blame] | 750 | bool ReadFstabFromDt(Fstab* fstab, bool verbose) { |
Tom Cherry | a3530e6 | 2019-01-30 13:25:35 -0800 | [diff] [blame] | 751 | std::string fstab_buf = ReadFstabFromDt(); |
Sandeep Patil | c20c0c2 | 2017-02-23 16:09:34 -0800 | [diff] [blame] | 752 | if (fstab_buf.empty()) { |
Yi-Yo Chiang | 2057901 | 2021-04-01 20:14:54 +0800 | [diff] [blame] | 753 | if (verbose) LINFO << __FUNCTION__ << "(): failed to read fstab from dt"; |
Tom Cherry | d0be7a5 | 2018-11-29 13:04:52 -0800 | [diff] [blame] | 754 | return false; |
Sandeep Patil | c20c0c2 | 2017-02-23 16:09:34 -0800 | [diff] [blame] | 755 | } |
| 756 | |
Yi-Yo Chiang | 97f2fdf | 2021-11-12 19:19:29 +0800 | [diff] [blame] | 757 | if (!ParseFstabFromString(fstab_buf, /* proc_mounts = */ false, fstab)) { |
Yi-Yo Chiang | 2057901 | 2021-04-01 20:14:54 +0800 | [diff] [blame] | 758 | if (verbose) { |
Mark Salyzyn | f98d6c4 | 2019-01-25 09:08:42 -0800 | [diff] [blame] | 759 | LERROR << __FUNCTION__ << "(): failed to load fstab from kernel:" << std::endl |
| 760 | << fstab_buf; |
| 761 | } |
Tom Cherry | d0be7a5 | 2018-11-29 13:04:52 -0800 | [diff] [blame] | 762 | return false; |
| 763 | } |
| 764 | |
Yi-Yo Chiang | 2057901 | 2021-04-01 20:14:54 +0800 | [diff] [blame] | 765 | SkipMountingPartitions(fstab, verbose); |
SzuWei Lin | 77c2847 | 2019-04-22 17:27:52 +0800 | [diff] [blame] | 766 | |
| 767 | return true; |
| 768 | } |
| 769 | |
Yi-Yo Chiang | 2057901 | 2021-04-01 20:14:54 +0800 | [diff] [blame] | 770 | #ifdef NO_SKIP_MOUNT |
| 771 | bool SkipMountingPartitions(Fstab*, bool) { |
| 772 | return true; |
| 773 | } |
| 774 | #else |
Justin Yun | 7eaf9b5 | 2019-06-28 14:28:00 +0900 | [diff] [blame] | 775 | // For GSI to skip mounting /product and /system_ext, until there are well-defined interfaces |
| 776 | // between them and /system. Otherwise, the GSI flashed on /system might not be able to work with |
Bowgo Tsai | 79f875f | 2019-09-04 22:20:01 +0800 | [diff] [blame] | 777 | // device-specific /product and /system_ext. skip_mount.cfg belongs to system_ext partition because |
| 778 | // only common files for all targets can be put into system partition. It is under |
| 779 | // /system/system_ext because GSI is a single system.img that includes the contents of system_ext |
| 780 | // partition and product partition under /system/system_ext and /system/product, respectively. |
Yi-Yo Chiang | 2057901 | 2021-04-01 20:14:54 +0800 | [diff] [blame] | 781 | bool SkipMountingPartitions(Fstab* fstab, bool verbose) { |
| 782 | static constexpr char kSkipMountConfig[] = "/system/system_ext/etc/init/config/skip_mount.cfg"; |
SzuWei Lin | 77c2847 | 2019-04-22 17:27:52 +0800 | [diff] [blame] | 783 | |
| 784 | std::string skip_config; |
Mark Salyzyn | 98a0128 | 2019-05-13 09:14:55 -0700 | [diff] [blame] | 785 | auto save_errno = errno; |
SzuWei Lin | 77c2847 | 2019-04-22 17:27:52 +0800 | [diff] [blame] | 786 | if (!ReadFileToString(kSkipMountConfig, &skip_config)) { |
Mark Salyzyn | 98a0128 | 2019-05-13 09:14:55 -0700 | [diff] [blame] | 787 | errno = save_errno; // missing file is expected |
SzuWei Lin | 77c2847 | 2019-04-22 17:27:52 +0800 | [diff] [blame] | 788 | return true; |
| 789 | } |
| 790 | |
Yi-Yo Chiang | 2f2fe4a | 2021-03-31 20:39:22 +0800 | [diff] [blame] | 791 | std::vector<std::string> skip_mount_patterns; |
| 792 | for (const auto& line : Split(skip_config, "\n")) { |
| 793 | if (line.empty() || StartsWith(line, "#")) { |
SzuWei Lin | 77c2847 | 2019-04-22 17:27:52 +0800 | [diff] [blame] | 794 | continue; |
| 795 | } |
Yi-Yo Chiang | 2f2fe4a | 2021-03-31 20:39:22 +0800 | [diff] [blame] | 796 | skip_mount_patterns.push_back(line); |
SzuWei Lin | 77c2847 | 2019-04-22 17:27:52 +0800 | [diff] [blame] | 797 | } |
| 798 | |
Yi-Yo Chiang | 2f2fe4a | 2021-03-31 20:39:22 +0800 | [diff] [blame] | 799 | // Returns false if mount_point matches any of the skip mount patterns, so that the FstabEntry |
| 800 | // would be partitioned to the second group. |
| 801 | auto glob_pattern_mismatch = [&skip_mount_patterns](const FstabEntry& entry) -> bool { |
| 802 | for (const auto& pattern : skip_mount_patterns) { |
| 803 | if (!fnmatch(pattern.c_str(), entry.mount_point.c_str(), 0 /* flags */)) { |
| 804 | return false; |
| 805 | } |
| 806 | } |
| 807 | return true; |
| 808 | }; |
| 809 | auto remove_from = std::stable_partition(fstab->begin(), fstab->end(), glob_pattern_mismatch); |
| 810 | if (verbose) { |
| 811 | for (auto it = remove_from; it != fstab->end(); ++it) { |
| 812 | LINFO << "Skip mounting mountpoint: " << it->mount_point; |
| 813 | } |
| 814 | } |
| 815 | fstab->erase(remove_from, fstab->end()); |
Tom Cherry | d0be7a5 | 2018-11-29 13:04:52 -0800 | [diff] [blame] | 816 | return true; |
| 817 | } |
Hung-ying Tyan | e7cb09d | 2020-07-03 14:26:59 +0800 | [diff] [blame] | 818 | #endif |
Tom Cherry | d0be7a5 | 2018-11-29 13:04:52 -0800 | [diff] [blame] | 819 | |
Tom Cherry | d0be7a5 | 2018-11-29 13:04:52 -0800 | [diff] [blame] | 820 | // Loads the fstab file and combines with fstab entries passed in from device tree. |
| 821 | bool ReadDefaultFstab(Fstab* fstab) { |
Yi-Yo Chiang | 1a3c050 | 2021-03-30 20:28:21 +0800 | [diff] [blame] | 822 | fstab->clear(); |
| 823 | ReadFstabFromDt(fstab, false /* verbose */); |
Tom Cherry | d0be7a5 | 2018-11-29 13:04:52 -0800 | [diff] [blame] | 824 | |
| 825 | std::string default_fstab_path; |
Bowgo Tsai | d05a2f7 | 2017-03-28 01:28:29 +0800 | [diff] [blame] | 826 | // Use different fstab paths for normal boot and recovery boot, respectively |
Jerry Zhang | 5de2be5 | 2018-07-03 16:03:28 -0700 | [diff] [blame] | 827 | if (access("/system/bin/recovery", F_OK) == 0) { |
Tom Cherry | d0be7a5 | 2018-11-29 13:04:52 -0800 | [diff] [blame] | 828 | default_fstab_path = "/etc/recovery.fstab"; |
Oleg Matcovschi | 018d7f6 | 2017-10-30 19:26:32 -0700 | [diff] [blame] | 829 | } else { // normal boot |
Tom Cherry | a3530e6 | 2019-01-30 13:25:35 -0800 | [diff] [blame] | 830 | default_fstab_path = GetFstabPath(); |
Oleg Matcovschi | 018d7f6 | 2017-10-30 19:26:32 -0700 | [diff] [blame] | 831 | } |
| 832 | |
Tom Cherry | d0be7a5 | 2018-11-29 13:04:52 -0800 | [diff] [blame] | 833 | Fstab default_fstab; |
Yi-Yo Chiang | ea4369d | 2021-03-22 13:45:09 +0800 | [diff] [blame] | 834 | if (!default_fstab_path.empty() && ReadFstabFromFile(default_fstab_path, &default_fstab)) { |
| 835 | for (auto&& entry : default_fstab) { |
| 836 | fstab->emplace_back(std::move(entry)); |
| 837 | } |
Chris Morin | b183e05 | 2018-01-04 17:59:45 -0800 | [diff] [blame] | 838 | } else { |
| 839 | LINFO << __FUNCTION__ << "(): failed to find device default fstab"; |
Sandeep Patil | c20c0c2 | 2017-02-23 16:09:34 -0800 | [diff] [blame] | 840 | } |
| 841 | |
Tom Cherry | d0be7a5 | 2018-11-29 13:04:52 -0800 | [diff] [blame] | 842 | return !fstab->empty(); |
| 843 | } |
| 844 | |
Tom Cherry | a3530e6 | 2019-01-30 13:25:35 -0800 | [diff] [blame] | 845 | FstabEntry* GetEntryForMountPoint(Fstab* fstab, const std::string& path) { |
| 846 | if (fstab == nullptr) { |
| 847 | return nullptr; |
| 848 | } |
| 849 | |
| 850 | for (auto& entry : *fstab) { |
| 851 | if (entry.mount_point == path) { |
| 852 | return &entry; |
| 853 | } |
| 854 | } |
| 855 | |
| 856 | return nullptr; |
| 857 | } |
| 858 | |
Howard Chen | 1b09493 | 2019-09-11 18:22:01 +0800 | [diff] [blame] | 859 | std::vector<FstabEntry*> GetEntriesForMountPoint(Fstab* fstab, const std::string& path) { |
| 860 | std::vector<FstabEntry*> entries; |
| 861 | if (fstab == nullptr) { |
| 862 | return entries; |
| 863 | } |
| 864 | |
| 865 | for (auto& entry : *fstab) { |
| 866 | if (entry.mount_point == path) { |
| 867 | entries.emplace_back(&entry); |
| 868 | } |
| 869 | } |
| 870 | |
| 871 | return entries; |
| 872 | } |
| 873 | |
Tom Cherry | a3530e6 | 2019-01-30 13:25:35 -0800 | [diff] [blame] | 874 | std::set<std::string> GetBootDevices() { |
Devin Moore | 20b7425 | 2021-03-04 08:23:31 -0800 | [diff] [blame] | 875 | // First check bootconfig, then kernel commandline, then the device tree |
Tom Cherry | a3530e6 | 2019-01-30 13:25:35 -0800 | [diff] [blame] | 876 | std::string dt_file_name = get_android_dt_dir() + "/boot_devices"; |
| 877 | std::string value; |
Devin Moore | 20b7425 | 2021-03-04 08:23:31 -0800 | [diff] [blame] | 878 | if (fs_mgr_get_boot_config_from_bootconfig_source("boot_devices", &value) || |
| 879 | fs_mgr_get_boot_config_from_bootconfig_source("boot_device", &value)) { |
| 880 | std::set<std::string> boot_devices; |
| 881 | // remove quotes and split by spaces |
| 882 | auto boot_device_strings = base::Split(base::StringReplace(value, "\"", "", true), " "); |
| 883 | for (std::string_view device : boot_device_strings) { |
| 884 | // trim the trailing comma, keep the rest. |
| 885 | base::ConsumeSuffix(&device, ","); |
| 886 | boot_devices.emplace(device); |
| 887 | } |
| 888 | return boot_devices; |
| 889 | } |
| 890 | |
Tom Cherry | a3530e6 | 2019-01-30 13:25:35 -0800 | [diff] [blame] | 891 | if (fs_mgr_get_boot_config_from_kernel_cmdline("boot_devices", &value) || |
| 892 | ReadDtFile(dt_file_name, &value)) { |
| 893 | auto boot_devices = Split(value, ","); |
| 894 | return std::set<std::string>(boot_devices.begin(), boot_devices.end()); |
| 895 | } |
| 896 | |
David Anderson | fabc364 | 2020-04-01 19:46:42 -0700 | [diff] [blame] | 897 | std::string cmdline; |
| 898 | if (android::base::ReadFileToString("/proc/cmdline", &cmdline)) { |
| 899 | std::set<std::string> boot_devices; |
| 900 | const std::string cmdline_key = "androidboot.boot_device"; |
Devin Moore | a4ef15b | 2020-12-15 16:14:37 -0800 | [diff] [blame] | 901 | for (const auto& [key, value] : fs_mgr_parse_cmdline(cmdline)) { |
David Anderson | fabc364 | 2020-04-01 19:46:42 -0700 | [diff] [blame] | 902 | if (key == cmdline_key) { |
| 903 | boot_devices.emplace(value); |
| 904 | } |
| 905 | } |
| 906 | if (!boot_devices.empty()) { |
| 907 | return boot_devices; |
| 908 | } |
| 909 | } |
| 910 | |
Tom Cherry | a3530e6 | 2019-01-30 13:25:35 -0800 | [diff] [blame] | 911 | // Fallback to extract boot devices from fstab. |
| 912 | Fstab fstab; |
| 913 | if (!ReadDefaultFstab(&fstab)) { |
| 914 | return {}; |
| 915 | } |
| 916 | |
| 917 | return ExtraBootDevices(fstab); |
| 918 | } |
| 919 | |
David Anderson | 7082f68 | 2019-03-18 19:17:11 -0700 | [diff] [blame] | 920 | std::string GetVerityDeviceName(const FstabEntry& entry) { |
| 921 | std::string base_device; |
| 922 | if (entry.mount_point == "/") { |
David Anderson | 9655c7b | 2019-05-09 17:55:18 -0700 | [diff] [blame] | 923 | // When using system-as-root, the device name is fixed as "vroot". |
| 924 | if (entry.fs_mgr_flags.avb) { |
| 925 | return "vroot"; |
| 926 | } |
| 927 | base_device = "system"; |
David Anderson | 7082f68 | 2019-03-18 19:17:11 -0700 | [diff] [blame] | 928 | } else { |
| 929 | base_device = android::base::Basename(entry.mount_point); |
| 930 | } |
| 931 | return base_device + "-verity"; |
| 932 | } |
| 933 | |
Tom Cherry | a3530e6 | 2019-01-30 13:25:35 -0800 | [diff] [blame] | 934 | } // namespace fs_mgr |
| 935 | } // namespace android |
| 936 | |
| 937 | // FIXME: The same logic is duplicated in system/core/init/ |
| 938 | const std::string& get_android_dt_dir() { |
| 939 | // Set once and saves time for subsequent calls to this function |
| 940 | static const std::string kAndroidDtDir = android::fs_mgr::InitAndroidDtDir(); |
| 941 | return kAndroidDtDir; |
| 942 | } |
| 943 | |
| 944 | bool is_dt_compatible() { |
| 945 | std::string file_name = get_android_dt_dir() + "/compatible"; |
| 946 | std::string dt_value; |
| 947 | if (android::fs_mgr::ReadDtFile(file_name, &dt_value)) { |
| 948 | if (dt_value == "android,firmware") { |
| 949 | return true; |
| 950 | } |
| 951 | } |
| 952 | |
| 953 | return false; |
| 954 | } |