blob: 83c43c613684169003d8ab52e59a70fa79381e0e [file] [log] [blame]
Colin Cross5edee2a2014-01-23 14:22:48 -08001/*
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 Patilc20c0c22017-02-23 16:09:34 -080018#include <dirent.h>
Iliyan Malchev3ea902f2015-05-01 14:05:04 -070019#include <errno.h>
Colin Cross5edee2a2014-01-23 14:22:48 -080020#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <sys/mount.h>
Iliyan Malchev3ea902f2015-05-01 14:05:04 -070024#include <unistd.h>
Colin Cross5edee2a2014-01-23 14:22:48 -080025
Bowgo Tsai80281892017-12-12 00:47:43 +080026#include <algorithm>
Tom Cherry7e34f752019-01-22 15:37:08 -080027#include <array>
Bowgo Tsai80281892017-12-12 00:47:43 +080028#include <utility>
29#include <vector>
30
Sandeep Patilc20c0c22017-02-23 16:09:34 -080031#include <android-base/file.h>
Jaegeuk Kim2aedc822018-11-20 13:27:06 -080032#include <android-base/parseint.h>
Sandeep Patilc20c0c22017-02-23 16:09:34 -080033#include <android-base/stringprintf.h>
34#include <android-base/strings.h>
David Anderson0e330f12019-01-03 18:16:56 -080035#include <libgsi/libgsi.h>
Sandeep Patilc20c0c22017-02-23 16:09:34 -080036
Colin Cross5edee2a2014-01-23 14:22:48 -080037#include "fs_mgr_priv.h"
38
Howard Chen1b094932019-09-11 18:22:01 +080039using android::base::EndsWith;
Tom Cherry151a17f2019-01-21 16:49:13 -080040using android::base::ParseByteCount;
41using android::base::ParseInt;
SzuWei Lin77c28472019-04-22 17:27:52 +080042using android::base::ReadFileToString;
Nikita Ioffe51106282019-11-21 21:40:03 +000043using android::base::Readlink;
Tom Cherry6bbe9472018-12-13 10:58:37 -080044using android::base::Split;
Tom Marshall66f6a6d2018-03-06 16:19:18 +010045using android::base::StartsWith;
46
Tom Cherrya3530e62019-01-30 13:25:35 -080047namespace android {
48namespace fs_mgr {
49namespace {
50
Vic Yang5caa3e92019-08-06 14:15:33 -070051constexpr char kDefaultAndroidDtDir[] = "/proc/device-tree/firmware/android";
Yu Ningc01022a2017-07-26 17:54:08 +080052
Tom Cherrya3530e62019-01-30 13:25:35 -080053struct FlagList {
Colin Cross5edee2a2014-01-23 14:22:48 -080054 const char *name;
Bowgo Tsai4c80edf2018-12-12 23:21:13 +080055 uint64_t flag;
Colin Cross5edee2a2014-01-23 14:22:48 -080056};
57
Tom Cherrya3530e62019-01-30 13:25:35 -080058FlagList kMountFlagsList[] = {
Tom Cherry151a17f2019-01-21 16:49:13 -080059 {"noatime", MS_NOATIME},
60 {"noexec", MS_NOEXEC},
61 {"nosuid", MS_NOSUID},
62 {"nodev", MS_NODEV},
63 {"nodiratime", MS_NODIRATIME},
64 {"ro", MS_RDONLY},
65 {"rw", 0},
Jaegeuk Kim5ffa9702019-06-05 17:43:47 -070066 {"sync", MS_SYNCHRONOUS},
Tom Cherry151a17f2019-01-21 16:49:13 -080067 {"remount", MS_REMOUNT},
68 {"bind", MS_BIND},
69 {"rec", MS_REC},
70 {"unbindable", MS_UNBINDABLE},
71 {"private", MS_PRIVATE},
72 {"slave", MS_SLAVE},
73 {"shared", MS_SHARED},
Daniel Rosenberg4c93b252018-08-28 01:41:18 -070074 {"defaults", 0},
Colin Cross5edee2a2014-01-23 14:22:48 -080075};
76
Tom Cherrya3530e62019-01-30 13:25:35 -080077off64_t CalculateZramSize(int percentage) {
Tom Cherryfafbb642018-11-29 13:24:09 -080078 off64_t total;
Iliyan Malchev3ea902f2015-05-01 14:05:04 -070079
80 total = sysconf(_SC_PHYS_PAGES);
81 total *= percentage;
82 total /= 100;
83
84 total *= sysconf(_SC_PAGESIZE);
85
86 return total;
87}
88
Tom Cherrya3530e62019-01-30 13:25:35 -080089// Fills 'dt_value' with the underlying device tree value string without the trailing '\0'.
90// Returns true if 'dt_value' has a valid string, 'false' otherwise.
91bool ReadDtFile(const std::string& file_name, std::string* dt_value) {
Sandeep Patil4cd9a462017-02-24 13:03:39 -080092 if (android::base::ReadFileToString(file_name, dt_value)) {
93 if (!dt_value->empty()) {
Tom Cherrya3530e62019-01-30 13:25:35 -080094 // Trim the trailing '\0' out, otherwise the comparison will produce false-negatives.
Sandeep Patil4cd9a462017-02-24 13:03:39 -080095 dt_value->resize(dt_value->size() - 1);
96 return true;
97 }
98 }
99
100 return false;
101}
102
Tom Cherrya3530e62019-01-30 13:25:35 -0800103void ParseFileEncryption(const std::string& arg, FstabEntry* entry) {
Tom Cherry151a17f2019-01-21 16:49:13 -0800104 entry->fs_mgr_flags.file_encryption = true;
Paul Crowley4fa84132019-10-24 23:33:12 -0700105 entry->encryption_options = arg;
Tom Cherry7e34f752019-01-22 15:37:08 -0800106}
107
Tom Cherrya3530e62019-01-30 13:25:35 -0800108bool SetMountFlag(const std::string& flag, FstabEntry* entry) {
109 for (const auto& [name, value] : kMountFlagsList) {
Tom Cherry151a17f2019-01-21 16:49:13 -0800110 if (flag == name) {
111 entry->flags |= value;
112 return true;
113 }
114 }
115 return false;
116}
Colin Cross5edee2a2014-01-23 14:22:48 -0800117
Tom Cherrya3530e62019-01-30 13:25:35 -0800118void ParseMountFlags(const std::string& flags, FstabEntry* entry) {
Tom Cherry151a17f2019-01-21 16:49:13 -0800119 std::string fs_options;
120 for (const auto& flag : Split(flags, ",")) {
121 if (!SetMountFlag(flag, entry)) {
122 // Unknown flag, so it must be a filesystem specific option.
123 if (!fs_options.empty()) {
124 fs_options.append(","); // appends a comma if not the first
Colin Cross5edee2a2014-01-23 14:22:48 -0800125 }
Tom Cherry151a17f2019-01-21 16:49:13 -0800126 fs_options.append(flag);
Jaegeuk Kimf07d07b2019-06-13 17:37:01 -0700127
128 if (entry->fs_type == "f2fs" && StartsWith(flag, "reserve_root=")) {
129 std::string arg;
130 if (auto equal_sign = flag.find('='); equal_sign != std::string::npos) {
131 arg = flag.substr(equal_sign + 1);
132 }
133 if (!ParseInt(arg, &entry->reserved_size)) {
134 LWARNING << "Warning: reserve_root= flag malformed: " << arg;
135 } else {
136 entry->reserved_size <<= 12;
137 }
138 }
Tom Cherry151a17f2019-01-21 16:49:13 -0800139 }
140 }
141 entry->fs_options = std::move(fs_options);
142}
143
Tom Cherrya3530e62019-01-30 13:25:35 -0800144void ParseFsMgrFlags(const std::string& flags, FstabEntry* entry) {
Tom Cherry151a17f2019-01-21 16:49:13 -0800145 for (const auto& flag : Split(flags, ",")) {
Mark Salyzync0d09a22019-02-05 07:30:23 -0800146 if (flag.empty() || flag == "defaults") continue;
Tom Cherry151a17f2019-01-21 16:49:13 -0800147 std::string arg;
148 if (auto equal_sign = flag.find('='); equal_sign != std::string::npos) {
149 arg = flag.substr(equal_sign + 1);
Colin Cross5edee2a2014-01-23 14:22:48 -0800150 }
151
Tom Cherry151a17f2019-01-21 16:49:13 -0800152 // First handle flags that simply set a boolean.
153#define CheckFlag(flag_name, value) \
154 if (flag == flag_name) { \
155 entry->fs_mgr_flags.value = true; \
156 continue; \
Colin Cross5edee2a2014-01-23 14:22:48 -0800157 }
158
Tom Cherry151a17f2019-01-21 16:49:13 -0800159 CheckFlag("wait", wait);
160 CheckFlag("check", check);
161 CheckFlag("nonremovable", nonremovable);
162 CheckFlag("recoveryonly", recovery_only);
163 CheckFlag("noemulatedsd", no_emulated_sd);
164 CheckFlag("notrim", no_trim);
165 CheckFlag("verify", verify);
166 CheckFlag("formattable", formattable);
167 CheckFlag("slotselect", slot_select);
168 CheckFlag("latemount", late_mount);
169 CheckFlag("nofail", no_fail);
170 CheckFlag("verifyatboot", verify_at_boot);
171 CheckFlag("quota", quota);
172 CheckFlag("avb", avb);
173 CheckFlag("logical", logical);
174 CheckFlag("checkpoint=block", checkpoint_blk);
175 CheckFlag("checkpoint=fs", checkpoint_fs);
176 CheckFlag("first_stage_mount", first_stage_mount);
177 CheckFlag("slotselect_other", slot_select_other);
178 CheckFlag("fsverity", fs_verity);
179
180#undef CheckFlag
181
182 // Then handle flags that take an argument.
183 if (StartsWith(flag, "encryptable=")) {
184 // The encryptable flag is followed by an = and the location of the keys.
185 entry->fs_mgr_flags.crypt = true;
186 entry->key_loc = arg;
187 } else if (StartsWith(flag, "voldmanaged=")) {
188 // The voldmanaged flag is followed by an = and the label, a colon and the partition
189 // number or the word "auto", e.g. voldmanaged=sdcard:3
190 entry->fs_mgr_flags.vold_managed = true;
191 auto parts = Split(arg, ":");
192 if (parts.size() != 2) {
193 LWARNING << "Warning: voldmanaged= flag malformed: " << arg;
194 continue;
195 }
196
197 entry->label = std::move(parts[0]);
198 if (parts[1] == "auto") {
199 entry->partnum = -1;
200 } else {
201 if (!ParseInt(parts[1], &entry->partnum)) {
202 entry->partnum = -1;
203 LWARNING << "Warning: voldmanaged= flag malformed: " << arg;
204 continue;
205 }
206 }
207 } else if (StartsWith(flag, "length=")) {
208 // The length flag is followed by an = and the size of the partition.
Tom Cherry151a17f2019-01-21 16:49:13 -0800209 if (!ParseInt(arg, &entry->length)) {
210 LWARNING << "Warning: length= flag malformed: " << arg;
211 }
212 } else if (StartsWith(flag, "swapprio=")) {
Tom Cherry151a17f2019-01-21 16:49:13 -0800213 if (!ParseInt(arg, &entry->swap_prio)) {
Felix92ed4232020-02-12 17:29:54 +0100214 LWARNING << "Warning: swapprio= flag malformed: " << arg;
Tom Cherry151a17f2019-01-21 16:49:13 -0800215 }
216 } else if (StartsWith(flag, "zramsize=")) {
Tom Cherry151a17f2019-01-21 16:49:13 -0800217 if (!arg.empty() && arg.back() == '%') {
218 arg.pop_back();
219 int val;
220 if (ParseInt(arg, &val, 0, 100)) {
Tom Cherrya3530e62019-01-30 13:25:35 -0800221 entry->zram_size = CalculateZramSize(val);
Tom Cherry151a17f2019-01-21 16:49:13 -0800222 } else {
223 LWARNING << "Warning: zramsize= flag malformed: " << arg;
224 }
225 } else {
226 if (!ParseInt(arg, &entry->zram_size)) {
227 LWARNING << "Warning: zramsize= flag malformed: " << arg;
228 }
229 }
Tom Cherry151a17f2019-01-21 16:49:13 -0800230 } else if (StartsWith(flag, "forceencrypt=")) {
231 // The forceencrypt flag is followed by an = and the location of the keys.
232 entry->fs_mgr_flags.force_crypt = true;
233 entry->key_loc = arg;
234 } else if (StartsWith(flag, "fileencryption=")) {
235 ParseFileEncryption(arg, entry);
236 } else if (StartsWith(flag, "forcefdeorfbe=")) {
237 // The forcefdeorfbe flag is followed by an = and the location of the keys. Get it and
238 // return it.
239 entry->fs_mgr_flags.force_fde_or_fbe = true;
240 entry->key_loc = arg;
Paul Crowley4fa84132019-10-24 23:33:12 -0700241 entry->encryption_options = "aes-256-xts:aes-256-cts";
Tom Cherry151a17f2019-01-21 16:49:13 -0800242 } else if (StartsWith(flag, "max_comp_streams=")) {
Tom Cherry151a17f2019-01-21 16:49:13 -0800243 if (!ParseInt(arg, &entry->max_comp_streams)) {
244 LWARNING << "Warning: max_comp_streams= flag malformed: " << arg;
245 }
246 } else if (StartsWith(flag, "reservedsize=")) {
247 // The reserved flag is followed by an = and the reserved size of the partition.
Tom Cherry151a17f2019-01-21 16:49:13 -0800248 uint64_t size;
249 if (!ParseByteCount(arg, &size)) {
250 LWARNING << "Warning: reservedsize= flag malformed: " << arg;
251 } else {
252 entry->reserved_size = static_cast<off64_t>(size);
253 }
254 } else if (StartsWith(flag, "eraseblk=")) {
255 // The erase block size flag is followed by an = and the flash erase block size. Get it,
256 // check that it is a power of 2 and at least 4096, and return it.
Tom Cherry151a17f2019-01-21 16:49:13 -0800257 off64_t val;
258 if (!ParseInt(arg, &val) || val < 4096 || (val & (val - 1)) != 0) {
259 LWARNING << "Warning: eraseblk= flag malformed: " << arg;
260 } else {
261 entry->erase_blk_size = val;
262 }
263 } else if (StartsWith(flag, "logicalblk=")) {
264 // The logical block size flag is followed by an = and the flash logical block size. Get
265 // it, check that it is a power of 2 and at least 4096, and return it.
Tom Cherry151a17f2019-01-21 16:49:13 -0800266 off64_t val;
267 if (!ParseInt(arg, &val) || val < 4096 || (val & (val - 1)) != 0) {
268 LWARNING << "Warning: logicalblk= flag malformed: " << arg;
269 } else {
270 entry->logical_blk_size = val;
271 }
Bowgo Tsaid214b402019-02-27 22:56:56 +0800272 } else if (StartsWith(flag, "avb_keys=")) { // must before the following "avb"
273 entry->avb_keys = arg;
Tom Cherry151a17f2019-01-21 16:49:13 -0800274 } else if (StartsWith(flag, "avb")) {
275 entry->fs_mgr_flags.avb = true;
276 entry->vbmeta_partition = arg;
277 } else if (StartsWith(flag, "keydirectory=")) {
278 // The metadata flag is followed by an = and the directory for the keys.
Paul Crowley7823e322020-01-30 16:03:45 -0800279 entry->metadata_key_dir = arg;
Barani Muthukumaran2ca1d832020-02-06 23:46:37 -0800280 } else if (StartsWith(flag, "metadata_encryption=")) {
281 // Specify the cipher and flags to use for metadata encryption
282 entry->metadata_encryption = arg;
Tom Cherry151a17f2019-01-21 16:49:13 -0800283 } else if (StartsWith(flag, "sysfs_path=")) {
284 // The path to trigger device gc by idle-maint of vold.
Tom Cherry151a17f2019-01-21 16:49:13 -0800285 entry->sysfs_path = arg;
286 } else if (StartsWith(flag, "zram_loopback_path=")) {
287 // The path to use loopback for zram.
Tom Cherry151a17f2019-01-21 16:49:13 -0800288 entry->zram_loopback_path = arg;
289 } else if (StartsWith(flag, "zram_loopback_size=")) {
Tom Cherry151a17f2019-01-21 16:49:13 -0800290 if (!ParseByteCount(arg, &entry->zram_loopback_size)) {
291 LWARNING << "Warning: zram_loopback_size= flag malformed: " << arg;
292 }
293 } else if (StartsWith(flag, "zram_backing_dev_path=")) {
Tom Cherry151a17f2019-01-21 16:49:13 -0800294 entry->zram_backing_dev_path = arg;
295 } else {
296 LWARNING << "Warning: unknown flag: " << flag;
297 }
298 }
Colin Cross5edee2a2014-01-23 14:22:48 -0800299}
300
Tom Cherrya3530e62019-01-30 13:25:35 -0800301std::string InitAndroidDtDir() {
Yu Ningc01022a2017-07-26 17:54:08 +0800302 std::string android_dt_dir;
303 // The platform may specify a custom Android DT path in kernel cmdline
304 if (!fs_mgr_get_boot_config_from_kernel_cmdline("android_dt_dir", &android_dt_dir)) {
305 // Fall back to the standard procfs-based path
306 android_dt_dir = kDefaultAndroidDtDir;
307 }
308 return android_dt_dir;
309}
310
Tom Cherrya3530e62019-01-30 13:25:35 -0800311bool IsDtFstabCompatible() {
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800312 std::string dt_value;
Yu Ningc01022a2017-07-26 17:54:08 +0800313 std::string file_name = get_android_dt_dir() + "/fstab/compatible";
Tom Cherry1eb04562018-11-06 10:42:09 -0800314
Tom Cherrya3530e62019-01-30 13:25:35 -0800315 if (ReadDtFile(file_name, &dt_value) && dt_value == "android,fstab") {
Tom Cherry1eb04562018-11-06 10:42:09 -0800316 // If there's no status property or its set to "ok" or "okay", then we use the DT fstab.
317 std::string status_value;
318 std::string status_file_name = get_android_dt_dir() + "/fstab/status";
Tom Cherrya3530e62019-01-30 13:25:35 -0800319 return !ReadDtFile(status_file_name, &status_value) || status_value == "ok" ||
Tom Cherry1eb04562018-11-06 10:42:09 -0800320 status_value == "okay";
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800321 }
322
323 return false;
324}
325
Tom Cherrya3530e62019-01-30 13:25:35 -0800326std::string ReadFstabFromDt() {
327 if (!is_dt_compatible() || !IsDtFstabCompatible()) {
Bowgo Tsai80281892017-12-12 00:47:43 +0800328 return {};
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800329 }
330
Yu Ningc01022a2017-07-26 17:54:08 +0800331 std::string fstabdir_name = get_android_dt_dir() + "/fstab";
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800332 std::unique_ptr<DIR, int (*)(DIR*)> fstabdir(opendir(fstabdir_name.c_str()), closedir);
Bowgo Tsai80281892017-12-12 00:47:43 +0800333 if (!fstabdir) return {};
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800334
335 dirent* dp;
Bowgo Tsai80281892017-12-12 00:47:43 +0800336 // Each element in fstab_dt_entries is <mount point, the line format in fstab file>.
337 std::vector<std::pair<std::string, std::string>> fstab_dt_entries;
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800338 while ((dp = readdir(fstabdir.get())) != NULL) {
Bowgo Tsai06ed6132017-06-08 10:43:41 +0800339 // skip over name, compatible and .
340 if (dp->d_type != DT_DIR || dp->d_name[0] == '.') continue;
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800341
342 // create <dev> <mnt_point> <type> <mnt_flags> <fsmgr_flags>\n
343 std::vector<std::string> fstab_entry;
344 std::string file_name;
345 std::string value;
Sandeep Patilbe4302b2017-05-26 18:09:06 -0700346 // skip a partition entry if the status property is present and not set to ok
347 file_name = android::base::StringPrintf("%s/%s/status", fstabdir_name.c_str(), dp->d_name);
Tom Cherrya3530e62019-01-30 13:25:35 -0800348 if (ReadDtFile(file_name, &value)) {
Sandeep Patilbe4302b2017-05-26 18:09:06 -0700349 if (value != "okay" && value != "ok") {
350 LINFO << "dt_fstab: Skip disabled entry for partition " << dp->d_name;
351 continue;
352 }
353 }
354
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800355 file_name = android::base::StringPrintf("%s/%s/dev", fstabdir_name.c_str(), dp->d_name);
Tom Cherrya3530e62019-01-30 13:25:35 -0800356 if (!ReadDtFile(file_name, &value)) {
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800357 LERROR << "dt_fstab: Failed to find device for partition " << dp->d_name;
Bowgo Tsai80281892017-12-12 00:47:43 +0800358 return {};
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800359 }
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800360 fstab_entry.push_back(value);
Bowgo Tsai80281892017-12-12 00:47:43 +0800361
362 std::string mount_point;
363 file_name =
364 android::base::StringPrintf("%s/%s/mnt_point", fstabdir_name.c_str(), dp->d_name);
Tom Cherrya3530e62019-01-30 13:25:35 -0800365 if (ReadDtFile(file_name, &value)) {
Bowgo Tsai80281892017-12-12 00:47:43 +0800366 LINFO << "dt_fstab: Using a specified mount point " << value << " for " << dp->d_name;
367 mount_point = value;
368 } else {
369 mount_point = android::base::StringPrintf("/%s", dp->d_name);
370 }
371 fstab_entry.push_back(mount_point);
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800372
373 file_name = android::base::StringPrintf("%s/%s/type", fstabdir_name.c_str(), dp->d_name);
Tom Cherrya3530e62019-01-30 13:25:35 -0800374 if (!ReadDtFile(file_name, &value)) {
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800375 LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
Bowgo Tsai80281892017-12-12 00:47:43 +0800376 return {};
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800377 }
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800378 fstab_entry.push_back(value);
379
380 file_name = android::base::StringPrintf("%s/%s/mnt_flags", fstabdir_name.c_str(), dp->d_name);
Tom Cherrya3530e62019-01-30 13:25:35 -0800381 if (!ReadDtFile(file_name, &value)) {
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800382 LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
Bowgo Tsai80281892017-12-12 00:47:43 +0800383 return {};
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800384 }
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800385 fstab_entry.push_back(value);
386
387 file_name = android::base::StringPrintf("%s/%s/fsmgr_flags", fstabdir_name.c_str(), dp->d_name);
Tom Cherrya3530e62019-01-30 13:25:35 -0800388 if (!ReadDtFile(file_name, &value)) {
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800389 LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
Bowgo Tsai80281892017-12-12 00:47:43 +0800390 return {};
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800391 }
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800392 fstab_entry.push_back(value);
Bowgo Tsai80281892017-12-12 00:47:43 +0800393 // Adds a fstab_entry to fstab_dt_entries, to be sorted by mount_point later.
394 fstab_dt_entries.emplace_back(mount_point, android::base::Join(fstab_entry, " "));
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800395 }
396
Bowgo Tsai80281892017-12-12 00:47:43 +0800397 // Sort fstab_dt entries, to ensure /vendor is mounted before /vendor/abc is attempted.
398 std::sort(fstab_dt_entries.begin(), fstab_dt_entries.end(),
399 [](const auto& a, const auto& b) { return a.first < b.first; });
400
401 std::string fstab_result;
402 for (const auto& [_, dt_entry] : fstab_dt_entries) {
403 fstab_result += dt_entry + "\n";
404 }
405 return fstab_result;
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800406}
407
Tom Cherrya3530e62019-01-30 13:25:35 -0800408// Identify path to fstab file. Lookup is based on pattern fstab.<hardware>,
409// fstab.<hardware.platform> in folders /odm/etc, vendor/etc, or /.
410std::string GetFstabPath() {
411 for (const char* prop : {"hardware", "hardware.platform"}) {
412 std::string hw;
413
414 if (!fs_mgr_get_boot_config(prop, &hw)) continue;
415
416 for (const char* prefix : {"/odm/etc/fstab.", "/vendor/etc/fstab.", "/fstab."}) {
417 std::string fstab_path = prefix + hw;
418 if (access(fstab_path.c_str(), F_OK) == 0) {
419 return fstab_path;
420 }
Sandeep Patile396c602017-02-24 11:04:49 -0800421 }
422 }
423
Tom Cherrya3530e62019-01-30 13:25:35 -0800424 return "";
Sandeep Patile396c602017-02-24 11:04:49 -0800425}
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800426
Tom Cherrya3530e62019-01-30 13:25:35 -0800427bool ReadFstabFile(FILE* fstab_file, bool proc_mounts, Fstab* fstab_out) {
Colin Cross5edee2a2014-01-23 14:22:48 -0800428 ssize_t len;
429 size_t alloc_len = 0;
430 char *line = NULL;
431 const char *delim = " \t";
432 char *save_ptr, *p;
Tom Cherryd0be7a52018-11-29 13:04:52 -0800433 Fstab fstab;
Colin Cross5edee2a2014-01-23 14:22:48 -0800434
Colin Cross5edee2a2014-01-23 14:22:48 -0800435 while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
436 /* if the last character is a newline, shorten the string by 1 byte */
437 if (line[len - 1] == '\n') {
438 line[len - 1] = '\0';
439 }
440
441 /* Skip any leading whitespace */
442 p = line;
443 while (isspace(*p)) {
444 p++;
445 }
446 /* ignore comments or empty lines */
447 if (*p == '#' || *p == '\0')
448 continue;
449
Tom Cherryd0be7a52018-11-29 13:04:52 -0800450 FstabEntry entry;
Colin Cross5edee2a2014-01-23 14:22:48 -0800451
452 if (!(p = strtok_r(line, delim, &save_ptr))) {
bowgotsai47878de2017-01-23 14:04:34 +0800453 LERROR << "Error parsing mount source";
Colin Cross5edee2a2014-01-23 14:22:48 -0800454 goto err;
455 }
Tom Cherryd0be7a52018-11-29 13:04:52 -0800456 entry.blk_device = p;
Colin Cross5edee2a2014-01-23 14:22:48 -0800457
458 if (!(p = strtok_r(NULL, delim, &save_ptr))) {
bowgotsai47878de2017-01-23 14:04:34 +0800459 LERROR << "Error parsing mount_point";
Colin Cross5edee2a2014-01-23 14:22:48 -0800460 goto err;
461 }
Tom Cherryd0be7a52018-11-29 13:04:52 -0800462 entry.mount_point = p;
Colin Cross5edee2a2014-01-23 14:22:48 -0800463
464 if (!(p = strtok_r(NULL, delim, &save_ptr))) {
bowgotsai47878de2017-01-23 14:04:34 +0800465 LERROR << "Error parsing fs_type";
Colin Cross5edee2a2014-01-23 14:22:48 -0800466 goto err;
467 }
Tom Cherryd0be7a52018-11-29 13:04:52 -0800468 entry.fs_type = p;
Colin Cross5edee2a2014-01-23 14:22:48 -0800469
470 if (!(p = strtok_r(NULL, delim, &save_ptr))) {
bowgotsai47878de2017-01-23 14:04:34 +0800471 LERROR << "Error parsing mount_flags";
Colin Cross5edee2a2014-01-23 14:22:48 -0800472 goto err;
473 }
Tom Cherry151a17f2019-01-21 16:49:13 -0800474
475 ParseMountFlags(p, &entry);
Colin Cross5edee2a2014-01-23 14:22:48 -0800476
Mark Salyzyneba47062018-06-20 13:07:28 -0700477 // For /proc/mounts, ignore everything after mnt_freq and mnt_passno
478 if (proc_mounts) {
479 p += strlen(p);
480 } else if (!(p = strtok_r(NULL, delim, &save_ptr))) {
bowgotsai47878de2017-01-23 14:04:34 +0800481 LERROR << "Error parsing fs_mgr_options";
Colin Cross5edee2a2014-01-23 14:22:48 -0800482 goto err;
483 }
Tom Cherryd0be7a52018-11-29 13:04:52 -0800484
Tom Cherry151a17f2019-01-21 16:49:13 -0800485 ParseFsMgrFlags(p, &entry);
486
Tom Cherryd0be7a52018-11-29 13:04:52 -0800487 if (entry.fs_mgr_flags.logical) {
488 entry.logical_partition_name = entry.blk_device;
David Anderson62e5b202018-05-01 17:09:17 -0700489 }
490
Tom Cherryd0be7a52018-11-29 13:04:52 -0800491 fstab.emplace_back(std::move(entry));
Colin Cross5edee2a2014-01-23 14:22:48 -0800492 }
Tom Cherryd0be7a52018-11-29 13:04:52 -0800493
494 if (fstab.empty()) {
495 LERROR << "No entries found in fstab";
496 goto err;
497 }
498
David Zeuthen227ef3c2015-09-03 12:23:12 -0400499 /* If an A/B partition, modify block device to be the real block device */
Tom Cherryd0be7a52018-11-29 13:04:52 -0800500 if (!fs_mgr_update_for_slotselect(&fstab)) {
bowgotsai47878de2017-01-23 14:04:34 +0800501 LERROR << "Error updating for slotselect";
David Zeuthen744a8f82015-09-09 18:03:13 -0400502 goto err;
David Zeuthen227ef3c2015-09-03 12:23:12 -0400503 }
Colin Cross5edee2a2014-01-23 14:22:48 -0800504 free(line);
Tom Cherryd0be7a52018-11-29 13:04:52 -0800505 *fstab_out = std::move(fstab);
506 return true;
Colin Cross5edee2a2014-01-23 14:22:48 -0800507
508err:
Colin Cross5edee2a2014-01-23 14:22:48 -0800509 free(line);
Tom Cherryd0be7a52018-11-29 13:04:52 -0800510 return false;
Bowgo Tsai47d34272017-03-06 22:22:07 +0800511}
512
Bowgo Tsai8eec38f2018-05-16 18:33:44 +0800513/* Extracts <device>s from the by-name symlinks specified in a fstab:
514 * /dev/block/<type>/<device>/by-name/<partition>
515 *
516 * <type> can be: platform, pci or vbd.
517 *
518 * For example, given the following entries in the input fstab:
519 * /dev/block/platform/soc/1da4000.ufshc/by-name/system
520 * /dev/block/pci/soc.0/f9824900.sdhci/by-name/vendor
521 * it returns a set { "soc/1da4000.ufshc", "soc.0/f9824900.sdhci" }.
522 */
Tom Cherrya3530e62019-01-30 13:25:35 -0800523std::set<std::string> ExtraBootDevices(const Fstab& fstab) {
Bowgo Tsai8eec38f2018-05-16 18:33:44 +0800524 std::set<std::string> boot_devices;
525
Tom Cherryd0be7a52018-11-29 13:04:52 -0800526 for (const auto& entry : fstab) {
527 std::string blk_device = entry.blk_device;
Bowgo Tsai8eec38f2018-05-16 18:33:44 +0800528 // Skips blk_device that doesn't conform to the format.
529 if (!android::base::StartsWith(blk_device, "/dev/block") ||
530 android::base::StartsWith(blk_device, "/dev/block/by-name") ||
531 android::base::StartsWith(blk_device, "/dev/block/bootdevice/by-name")) {
532 continue;
533 }
534 // Skips non-by_name blk_device.
535 // /dev/block/<type>/<device>/by-name/<partition>
536 // ^ slash_by_name
537 auto slash_by_name = blk_device.find("/by-name");
538 if (slash_by_name == std::string::npos) continue;
539 blk_device.erase(slash_by_name); // erases /by-name/<partition>
540
541 // Erases /dev/block/, now we have <type>/<device>
542 blk_device.erase(0, std::string("/dev/block/").size());
543
544 // <type>/<device>
545 // ^ first_slash
546 auto first_slash = blk_device.find('/');
547 if (first_slash == std::string::npos) continue;
548
549 auto boot_device = blk_device.substr(first_slash + 1);
550 if (!boot_device.empty()) boot_devices.insert(std::move(boot_device));
551 }
552
553 return boot_devices;
554}
555
Howard Chen1b094932019-09-11 18:22:01 +0800556FstabEntry BuildDsuUserdataFstabEntry() {
David Anderson0e330f12019-01-03 18:16:56 -0800557 constexpr uint32_t kFlags = MS_NOATIME | MS_NOSUID | MS_NODEV;
558
559 FstabEntry userdata = {
560 .blk_device = "userdata_gsi",
561 .mount_point = "/data",
562 .fs_type = "ext4",
563 .flags = kFlags,
564 .reserved_size = 128 * 1024 * 1024,
565 };
566 userdata.fs_mgr_flags.wait = true;
567 userdata.fs_mgr_flags.check = true;
568 userdata.fs_mgr_flags.logical = true;
569 userdata.fs_mgr_flags.quota = true;
570 userdata.fs_mgr_flags.late_mount = true;
David Andersonc45026f2019-01-24 11:45:52 -0800571 userdata.fs_mgr_flags.formattable = true;
David Anderson88045ae2019-02-04 19:02:19 -0800572 return userdata;
573}
574
Bowgo Tsai9bbaa7b2019-02-18 17:56:58 +0800575bool EraseFstabEntry(Fstab* fstab, const std::string& mount_point) {
David Anderson88045ae2019-02-04 19:02:19 -0800576 auto iter = std::remove_if(fstab->begin(), fstab->end(),
577 [&](const auto& entry) { return entry.mount_point == mount_point; });
Bowgo Tsai9bbaa7b2019-02-18 17:56:58 +0800578 if (iter != fstab->end()) {
579 fstab->erase(iter, fstab->end());
580 return true;
581 }
582 return false;
David Anderson88045ae2019-02-04 19:02:19 -0800583}
584
Howard Chen1b094932019-09-11 18:22:01 +0800585} // namespace
586
587void TransformFstabForDsu(Fstab* fstab, const std::vector<std::string>& dsu_partitions) {
Bowgo Tsaia2ac8462019-12-11 15:03:00 +0800588 static constexpr char kDsuKeysDir[] = "/avb";
Howard Chen1b094932019-09-11 18:22:01 +0800589 // Convert userdata
David Anderson88045ae2019-02-04 19:02:19 -0800590 // Inherit fstab properties for userdata.
591 FstabEntry userdata;
592 if (FstabEntry* entry = GetEntryForMountPoint(fstab, "/data")) {
593 userdata = *entry;
594 userdata.blk_device = "userdata_gsi";
595 userdata.fs_mgr_flags.logical = true;
596 userdata.fs_mgr_flags.formattable = true;
Paul Crowley7823e322020-01-30 16:03:45 -0800597 if (!userdata.metadata_key_dir.empty()) {
598 userdata.metadata_key_dir += "/gsi";
David Anderson88045ae2019-02-04 19:02:19 -0800599 }
600 } else {
Howard Chen1b094932019-09-11 18:22:01 +0800601 userdata = BuildDsuUserdataFstabEntry();
Bowgo Tsai9bbaa7b2019-02-18 17:56:58 +0800602 }
David Anderson88045ae2019-02-04 19:02:19 -0800603
Bowgo Tsai9bbaa7b2019-02-18 17:56:58 +0800604 if (EraseFstabEntry(fstab, "/data")) {
605 fstab->emplace_back(userdata);
606 }
David Anderson0e330f12019-01-03 18:16:56 -0800607
Howard Chen1b094932019-09-11 18:22:01 +0800608 // Convert others
609 for (auto&& partition : dsu_partitions) {
610 if (!EndsWith(partition, gsi::kDsuPostfix)) {
611 continue;
612 }
613 // userdata has been handled
614 if (StartsWith(partition, "user")) {
615 continue;
616 }
617 // dsu_partition_name = corresponding_partition_name + kDsuPostfix
618 // e.g.
619 // system_gsi for system
620 // product_gsi for product
621 // vendor_gsi for vendor
622 std::string lp_name = partition.substr(0, partition.length() - strlen(gsi::kDsuPostfix));
623 std::string mount_point = "/" + lp_name;
624 std::vector<FstabEntry*> entries = GetEntriesForMountPoint(fstab, mount_point);
625 if (entries.empty()) {
626 FstabEntry entry = {
627 .blk_device = partition,
Nick Desaulniers8e048442019-10-11 10:52:16 -0700628 // .logical_partition_name is required to look up AVB Hashtree descriptors.
629 .logical_partition_name = "system",
Howard Chen1b094932019-09-11 18:22:01 +0800630 .mount_point = mount_point,
631 .fs_type = "ext4",
632 .flags = MS_RDONLY,
633 .fs_options = "barrier=1",
Bowgo Tsaia2ac8462019-12-11 15:03:00 +0800634 .avb_keys = kDsuKeysDir,
Nick Desaulniers8e048442019-10-11 10:52:16 -0700635 };
Howard Chen1b094932019-09-11 18:22:01 +0800636 entry.fs_mgr_flags.wait = true;
637 entry.fs_mgr_flags.logical = true;
638 entry.fs_mgr_flags.first_stage_mount = true;
Howard Chen1b094932019-09-11 18:22:01 +0800639 } else {
640 // If the corresponding partition exists, transform all its Fstab
641 // by pointing .blk_device to the DSU partition.
642 for (auto&& entry : entries) {
643 entry->blk_device = partition;
Bowgo Tsaia2ac8462019-12-11 15:03:00 +0800644 // AVB keys for DSU should always be under kDsuKeysDir.
645 entry->avb_keys += kDsuKeysDir;
Howard Chen1b094932019-09-11 18:22:01 +0800646 }
647 // Make sure the ext4 is included to support GSI.
648 auto partition_ext4 =
649 std::find_if(fstab->begin(), fstab->end(), [&](const auto& entry) {
650 return entry.mount_point == mount_point && entry.fs_type == "ext4";
651 });
652 if (partition_ext4 == fstab->end()) {
653 auto new_entry = *GetEntryForMountPoint(fstab, mount_point);
654 new_entry.fs_type = "ext4";
655 fstab->emplace_back(new_entry);
656 }
657 }
658 }
659}
Tom Cherrya3530e62019-01-30 13:25:35 -0800660
Tom Cherryd0be7a52018-11-29 13:04:52 -0800661bool ReadFstabFromFile(const std::string& path, Fstab* fstab) {
662 auto fstab_file = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
Hung-ying Tyan99c4a8a2016-02-01 15:07:40 +0800663 if (!fstab_file) {
Tom Cherryd0be7a52018-11-29 13:04:52 -0800664 PERROR << __FUNCTION__ << "(): cannot open file: '" << path << "'";
665 return false;
666 }
667
David Anderson0e330f12019-01-03 18:16:56 -0800668 bool is_proc_mounts = path == "/proc/mounts";
669
Tom Cherrya3530e62019-01-30 13:25:35 -0800670 if (!ReadFstabFile(fstab_file.get(), is_proc_mounts, fstab)) {
Tom Cherryd0be7a52018-11-29 13:04:52 -0800671 LERROR << __FUNCTION__ << "(): failed to load fstab from : '" << path << "'";
672 return false;
673 }
David Anderson0e330f12019-01-03 18:16:56 -0800674 if (!is_proc_mounts && !access(android::gsi::kGsiBootedIndicatorFile, F_OK)) {
Howard Chen1b094932019-09-11 18:22:01 +0800675 std::string lp_names;
676 ReadFileToString(gsi::kGsiLpNamesFile, &lp_names);
677 TransformFstabForDsu(fstab, Split(lp_names, ","));
David Anderson0e330f12019-01-03 18:16:56 -0800678 }
Tom Cherryd0be7a52018-11-29 13:04:52 -0800679
SzuWei Lin77c28472019-04-22 17:27:52 +0800680 SkipMountingPartitions(fstab);
681
Tom Cherryd0be7a52018-11-29 13:04:52 -0800682 return true;
683}
684
Tom Cherryd0be7a52018-11-29 13:04:52 -0800685// Returns fstab entries parsed from the device tree if they exist
Mark Salyzynf98d6c42019-01-25 09:08:42 -0800686bool ReadFstabFromDt(Fstab* fstab, bool log) {
Tom Cherrya3530e62019-01-30 13:25:35 -0800687 std::string fstab_buf = ReadFstabFromDt();
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800688 if (fstab_buf.empty()) {
Mark Salyzynf98d6c42019-01-25 09:08:42 -0800689 if (log) LINFO << __FUNCTION__ << "(): failed to read fstab from dt";
Tom Cherryd0be7a52018-11-29 13:04:52 -0800690 return false;
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800691 }
692
693 std::unique_ptr<FILE, decltype(&fclose)> fstab_file(
694 fmemopen(static_cast<void*>(const_cast<char*>(fstab_buf.c_str())),
695 fstab_buf.length(), "r"), fclose);
696 if (!fstab_file) {
Mark Salyzynf98d6c42019-01-25 09:08:42 -0800697 if (log) PERROR << __FUNCTION__ << "(): failed to create a file stream for fstab dt";
Tom Cherryd0be7a52018-11-29 13:04:52 -0800698 return false;
699 }
700
Tom Cherrya3530e62019-01-30 13:25:35 -0800701 if (!ReadFstabFile(fstab_file.get(), false, fstab)) {
Mark Salyzynf98d6c42019-01-25 09:08:42 -0800702 if (log) {
703 LERROR << __FUNCTION__ << "(): failed to load fstab from kernel:" << std::endl
704 << fstab_buf;
705 }
Tom Cherryd0be7a52018-11-29 13:04:52 -0800706 return false;
707 }
708
SzuWei Lin77c28472019-04-22 17:27:52 +0800709 SkipMountingPartitions(fstab);
710
711 return true;
712}
713
Justin Yun7eaf9b52019-06-28 14:28:00 +0900714// For GSI to skip mounting /product and /system_ext, until there are well-defined interfaces
715// between them and /system. Otherwise, the GSI flashed on /system might not be able to work with
Bowgo Tsai79f875f2019-09-04 22:20:01 +0800716// device-specific /product and /system_ext. skip_mount.cfg belongs to system_ext partition because
717// only common files for all targets can be put into system partition. It is under
718// /system/system_ext because GSI is a single system.img that includes the contents of system_ext
719// partition and product partition under /system/system_ext and /system/product, respectively.
SzuWei Lin77c28472019-04-22 17:27:52 +0800720bool SkipMountingPartitions(Fstab* fstab) {
Bowgo Tsai79f875f2019-09-04 22:20:01 +0800721 constexpr const char kSkipMountConfig[] = "/system/system_ext/etc/init/config/skip_mount.cfg";
SzuWei Lin77c28472019-04-22 17:27:52 +0800722
723 std::string skip_config;
Mark Salyzyn98a01282019-05-13 09:14:55 -0700724 auto save_errno = errno;
SzuWei Lin77c28472019-04-22 17:27:52 +0800725 if (!ReadFileToString(kSkipMountConfig, &skip_config)) {
Mark Salyzyn98a01282019-05-13 09:14:55 -0700726 errno = save_errno; // missing file is expected
SzuWei Lin77c28472019-04-22 17:27:52 +0800727 return true;
728 }
729
730 for (const auto& skip_mount_point : Split(skip_config, "\n")) {
731 if (skip_mount_point.empty()) {
732 continue;
733 }
734 auto it = std::remove_if(fstab->begin(), fstab->end(),
735 [&skip_mount_point](const auto& entry) {
736 return entry.mount_point == skip_mount_point;
737 });
bohu42b28b02019-06-05 10:53:43 -0700738 if (it == fstab->end()) continue;
SzuWei Lin77c28472019-04-22 17:27:52 +0800739 fstab->erase(it, fstab->end());
740 LOG(INFO) << "Skip mounting partition: " << skip_mount_point;
741 }
742
Tom Cherryd0be7a52018-11-29 13:04:52 -0800743 return true;
744}
745
Tom Cherryd0be7a52018-11-29 13:04:52 -0800746// Loads the fstab file and combines with fstab entries passed in from device tree.
747bool ReadDefaultFstab(Fstab* fstab) {
748 Fstab dt_fstab;
Mark Salyzynf98d6c42019-01-25 09:08:42 -0800749 ReadFstabFromDt(&dt_fstab, false);
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800750
Tom Cherryd0be7a52018-11-29 13:04:52 -0800751 *fstab = std::move(dt_fstab);
752
753 std::string default_fstab_path;
Bowgo Tsaid05a2f72017-03-28 01:28:29 +0800754 // Use different fstab paths for normal boot and recovery boot, respectively
Jerry Zhang5de2be52018-07-03 16:03:28 -0700755 if (access("/system/bin/recovery", F_OK) == 0) {
Tom Cherryd0be7a52018-11-29 13:04:52 -0800756 default_fstab_path = "/etc/recovery.fstab";
Oleg Matcovschi018d7f62017-10-30 19:26:32 -0700757 } else { // normal boot
Tom Cherrya3530e62019-01-30 13:25:35 -0800758 default_fstab_path = GetFstabPath();
Oleg Matcovschi018d7f62017-10-30 19:26:32 -0700759 }
760
Tom Cherryd0be7a52018-11-29 13:04:52 -0800761 Fstab default_fstab;
762 if (!default_fstab_path.empty()) {
763 ReadFstabFromFile(default_fstab_path, &default_fstab);
Chris Morinb183e052018-01-04 17:59:45 -0800764 } else {
765 LINFO << __FUNCTION__ << "(): failed to find device default fstab";
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800766 }
767
Tom Cherryd0be7a52018-11-29 13:04:52 -0800768 for (auto&& entry : default_fstab) {
769 fstab->emplace_back(std::move(entry));
770 }
Chris Morinb183e052018-01-04 17:59:45 -0800771
Tom Cherryd0be7a52018-11-29 13:04:52 -0800772 return !fstab->empty();
773}
774
Tom Cherrya3530e62019-01-30 13:25:35 -0800775FstabEntry* GetEntryForMountPoint(Fstab* fstab, const std::string& path) {
776 if (fstab == nullptr) {
777 return nullptr;
778 }
779
780 for (auto& entry : *fstab) {
781 if (entry.mount_point == path) {
782 return &entry;
783 }
784 }
785
786 return nullptr;
787}
788
Howard Chen1b094932019-09-11 18:22:01 +0800789std::vector<FstabEntry*> GetEntriesForMountPoint(Fstab* fstab, const std::string& path) {
790 std::vector<FstabEntry*> entries;
791 if (fstab == nullptr) {
792 return entries;
793 }
794
795 for (auto& entry : *fstab) {
796 if (entry.mount_point == path) {
797 entries.emplace_back(&entry);
798 }
799 }
800
801 return entries;
802}
803
Nikita Ioffe51106282019-11-21 21:40:03 +0000804static std::string ResolveBlockDevice(const std::string& block_device) {
805 if (!StartsWith(block_device, "/dev/block/")) {
806 LWARNING << block_device << " is not a block device";
807 return block_device;
808 }
809 std::string name = block_device.substr(5);
810 if (!StartsWith(name, "block/dm-")) {
811 // Not a dm-device, but might be a symlink. Optimistically try to readlink.
812 std::string result;
813 if (Readlink(block_device, &result)) {
814 return result;
815 } else if (errno == EINVAL) {
816 // After all, it wasn't a symlink.
817 return block_device;
818 } else {
819 LERROR << "Failed to readlink " << block_device;
820 return "";
821 }
822 }
823 // It's a dm-device, let's find what's inside!
824 std::string sys_dir = "/sys/" + name;
825 while (true) {
826 std::string slaves_dir = sys_dir + "/slaves";
827 std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(slaves_dir.c_str()), closedir);
828 if (!dir) {
829 LERROR << "Failed to open " << slaves_dir;
830 return "";
831 }
832 std::string sub_device_name = "";
833 for (auto entry = readdir(dir.get()); entry; entry = readdir(dir.get())) {
834 if (entry->d_type != DT_LNK) continue;
835 if (!sub_device_name.empty()) {
836 LERROR << "Too many slaves in " << slaves_dir;
837 return "";
838 }
839 sub_device_name = entry->d_name;
840 }
841 if (sub_device_name.empty()) {
842 LERROR << "No slaves in " << slaves_dir;
843 return "";
844 }
845 if (!StartsWith(sub_device_name, "dm-")) {
846 // Not a dm-device! We can stop now.
847 return "/dev/block/" + sub_device_name;
848 }
849 // Still a dm-device, keep digging.
850 sys_dir = "/sys/block/" + sub_device_name;
851 }
852}
853
854FstabEntry* GetMountedEntryForUserdata(Fstab* fstab) {
855 Fstab mounts;
856 if (!ReadFstabFromFile("/proc/mounts", &mounts)) {
857 LERROR << "Failed to read /proc/mounts";
858 return nullptr;
859 }
860 auto mounted_entry = GetEntryForMountPoint(&mounts, "/data");
861 if (mounted_entry == nullptr) {
862 LWARNING << "/data is not mounted";
863 return nullptr;
864 }
865 std::string resolved_block_device = ResolveBlockDevice(mounted_entry->blk_device);
866 if (resolved_block_device.empty()) {
867 return nullptr;
868 }
869 LINFO << "/data is mounted on " << resolved_block_device;
870 for (auto& entry : *fstab) {
871 if (entry.mount_point != "/data") {
872 continue;
873 }
874 std::string block_device;
875 if (!Readlink(entry.blk_device, &block_device)) {
876 LWARNING << "Failed to readlink " << entry.blk_device;
877 block_device = entry.blk_device;
878 }
879 if (block_device == resolved_block_device) {
880 return &entry;
881 }
882 }
883 LERROR << "Didn't find entry that was used to mount /data";
884 return nullptr;
885}
886
Tom Cherrya3530e62019-01-30 13:25:35 -0800887std::set<std::string> GetBootDevices() {
888 // First check the kernel commandline, then try the device tree otherwise
889 std::string dt_file_name = get_android_dt_dir() + "/boot_devices";
890 std::string value;
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
897 // Fallback to extract boot devices from fstab.
898 Fstab fstab;
899 if (!ReadDefaultFstab(&fstab)) {
900 return {};
901 }
902
903 return ExtraBootDevices(fstab);
904}
905
David Anderson7082f682019-03-18 19:17:11 -0700906std::string GetVerityDeviceName(const FstabEntry& entry) {
907 std::string base_device;
908 if (entry.mount_point == "/") {
David Anderson9655c7b2019-05-09 17:55:18 -0700909 // When using system-as-root, the device name is fixed as "vroot".
910 if (entry.fs_mgr_flags.avb) {
911 return "vroot";
912 }
913 base_device = "system";
David Anderson7082f682019-03-18 19:17:11 -0700914 } else {
915 base_device = android::base::Basename(entry.mount_point);
916 }
917 return base_device + "-verity";
918}
919
Tom Cherrya3530e62019-01-30 13:25:35 -0800920} // namespace fs_mgr
921} // namespace android
922
923// FIXME: The same logic is duplicated in system/core/init/
924const std::string& get_android_dt_dir() {
925 // Set once and saves time for subsequent calls to this function
926 static const std::string kAndroidDtDir = android::fs_mgr::InitAndroidDtDir();
927 return kAndroidDtDir;
928}
929
930bool is_dt_compatible() {
931 std::string file_name = get_android_dt_dir() + "/compatible";
932 std::string dt_value;
933 if (android::fs_mgr::ReadDtFile(file_name, &dt_value)) {
934 if (dt_value == "android,firmware") {
935 return true;
936 }
937 }
938
939 return false;
940}