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>
18 #include <dirent.h>
19 #include <errno.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/mount.h>
24 #include <unistd.h>
25
26 #include <algorithm>
27 #include <array>
28 #include <utility>
29 #include <vector>
30
31 #include <android-base/file.h>
32 #include <android-base/parseint.h>
33 #include <android-base/properties.h>
34 #include <android-base/stringprintf.h>
35 #include <android-base/strings.h>
36 #include <libgsi/libgsi.h>
37
38 #include "fs_mgr_priv.h"
39
40 using android::base::EndsWith;
41 using android::base::ParseByteCount;
42 using android::base::ParseInt;
43 using android::base::ReadFileToString;
44 using android::base::Readlink;
45 using android::base::Split;
46 using android::base::StartsWith;
47
48 namespace android {
49 namespace fs_mgr {
50 namespace {
51
52 constexpr char kDefaultAndroidDtDir[] = "/proc/device-tree/firmware/android";
53
54 struct FlagList {
55 const char *name;
56 uint64_t flag;
57 };
58
59 FlagList kMountFlagsList[] = {
60 {"noatime", MS_NOATIME},
61 {"noexec", MS_NOEXEC},
62 {"nosuid", MS_NOSUID},
63 {"nodev", MS_NODEV},
64 {"nodiratime", MS_NODIRATIME},
65 {"ro", MS_RDONLY},
66 {"rw", 0},
67 {"sync", MS_SYNCHRONOUS},
68 {"remount", MS_REMOUNT},
69 {"bind", MS_BIND},
70 {"rec", MS_REC},
71 {"unbindable", MS_UNBINDABLE},
72 {"private", MS_PRIVATE},
73 {"slave", MS_SLAVE},
74 {"shared", MS_SHARED},
75 {"defaults", 0},
76 };
77
CalculateZramSize(int percentage)78 off64_t CalculateZramSize(int percentage) {
79 off64_t total;
80
81 total = sysconf(_SC_PHYS_PAGES);
82 total *= percentage;
83 total /= 100;
84
85 total *= sysconf(_SC_PAGESIZE);
86
87 return total;
88 }
89
90 // Fills 'dt_value' with the underlying device tree value string without the trailing '\0'.
91 // Returns true if 'dt_value' has a valid string, 'false' otherwise.
ReadDtFile(const std::string & file_name,std::string * dt_value)92 bool ReadDtFile(const std::string& file_name, std::string* dt_value) {
93 if (android::base::ReadFileToString(file_name, dt_value)) {
94 if (!dt_value->empty()) {
95 // Trim the trailing '\0' out, otherwise the comparison will produce false-negatives.
96 dt_value->resize(dt_value->size() - 1);
97 return true;
98 }
99 }
100
101 return false;
102 }
103
ParseFileEncryption(const std::string & arg,FstabEntry * entry)104 void ParseFileEncryption(const std::string& arg, FstabEntry* entry) {
105 entry->fs_mgr_flags.file_encryption = true;
106 entry->encryption_options = arg;
107 }
108
SetMountFlag(const std::string & flag,FstabEntry * entry)109 bool SetMountFlag(const std::string& flag, FstabEntry* entry) {
110 for (const auto& [name, value] : kMountFlagsList) {
111 if (flag == name) {
112 entry->flags |= value;
113 return true;
114 }
115 }
116 return false;
117 }
118
ParseMountFlags(const std::string & flags,FstabEntry * entry)119 void ParseMountFlags(const std::string& flags, FstabEntry* entry) {
120 std::string fs_options;
121 for (const auto& flag : Split(flags, ",")) {
122 if (!SetMountFlag(flag, entry)) {
123 // Unknown flag, so it must be a filesystem specific option.
124 if (!fs_options.empty()) {
125 fs_options.append(","); // appends a comma if not the first
126 }
127 fs_options.append(flag);
128
129 if (entry->fs_type == "f2fs" && StartsWith(flag, "reserve_root=")) {
130 std::string arg;
131 if (auto equal_sign = flag.find('='); equal_sign != std::string::npos) {
132 arg = flag.substr(equal_sign + 1);
133 }
134 if (!ParseInt(arg, &entry->reserved_size)) {
135 LWARNING << "Warning: reserve_root= flag malformed: " << arg;
136 } else {
137 entry->reserved_size <<= 12;
138 }
139 }
140 }
141 }
142 entry->fs_options = std::move(fs_options);
143 }
144
ParseFsMgrFlags(const std::string & flags,FstabEntry * entry)145 void ParseFsMgrFlags(const std::string& flags, FstabEntry* entry) {
146 for (const auto& flag : Split(flags, ",")) {
147 if (flag.empty() || flag == "defaults") continue;
148 std::string arg;
149 if (auto equal_sign = flag.find('='); equal_sign != std::string::npos) {
150 arg = flag.substr(equal_sign + 1);
151 }
152
153 // First handle flags that simply set a boolean.
154 #define CheckFlag(flag_name, value) \
155 if (flag == flag_name) { \
156 entry->fs_mgr_flags.value = true; \
157 continue; \
158 }
159
160 CheckFlag("wait", wait);
161 CheckFlag("check", check);
162 CheckFlag("nonremovable", nonremovable);
163 CheckFlag("recoveryonly", recovery_only);
164 CheckFlag("noemulatedsd", no_emulated_sd);
165 CheckFlag("notrim", no_trim);
166 CheckFlag("verify", verify);
167 CheckFlag("formattable", formattable);
168 CheckFlag("slotselect", slot_select);
169 CheckFlag("latemount", late_mount);
170 CheckFlag("nofail", no_fail);
171 CheckFlag("verifyatboot", verify_at_boot);
172 CheckFlag("quota", quota);
173 CheckFlag("avb", avb);
174 CheckFlag("logical", logical);
175 CheckFlag("checkpoint=block", checkpoint_blk);
176 CheckFlag("checkpoint=fs", checkpoint_fs);
177 CheckFlag("first_stage_mount", first_stage_mount);
178 CheckFlag("slotselect_other", slot_select_other);
179 CheckFlag("fsverity", fs_verity);
180 CheckFlag("metadata_csum", ext_meta_csum);
181 CheckFlag("fscompress", fs_compress);
182
183 #undef CheckFlag
184
185 // Then handle flags that take an argument.
186 if (StartsWith(flag, "encryptable=")) {
187 // The encryptable flag is followed by an = and the location of the keys.
188 entry->fs_mgr_flags.crypt = true;
189 entry->key_loc = arg;
190 } else if (StartsWith(flag, "voldmanaged=")) {
191 // The voldmanaged flag is followed by an = and the label, a colon and the partition
192 // number or the word "auto", e.g. voldmanaged=sdcard:3
193 entry->fs_mgr_flags.vold_managed = true;
194 auto parts = Split(arg, ":");
195 if (parts.size() != 2) {
196 LWARNING << "Warning: voldmanaged= flag malformed: " << arg;
197 continue;
198 }
199
200 entry->label = std::move(parts[0]);
201 if (parts[1] == "auto") {
202 entry->partnum = -1;
203 } else {
204 if (!ParseInt(parts[1], &entry->partnum)) {
205 entry->partnum = -1;
206 LWARNING << "Warning: voldmanaged= flag malformed: " << arg;
207 continue;
208 }
209 }
210 } else if (StartsWith(flag, "length=")) {
211 // The length flag is followed by an = and the size of the partition.
212 if (!ParseInt(arg, &entry->length)) {
213 LWARNING << "Warning: length= flag malformed: " << arg;
214 }
215 } else if (StartsWith(flag, "swapprio=")) {
216 if (!ParseInt(arg, &entry->swap_prio)) {
217 LWARNING << "Warning: swapprio= flag malformed: " << arg;
218 }
219 } else if (StartsWith(flag, "zramsize=")) {
220 if (!arg.empty() && arg.back() == '%') {
221 arg.pop_back();
222 int val;
223 if (ParseInt(arg, &val, 0, 100)) {
224 entry->zram_size = CalculateZramSize(val);
225 } else {
226 LWARNING << "Warning: zramsize= flag malformed: " << arg;
227 }
228 } else {
229 if (!ParseInt(arg, &entry->zram_size)) {
230 LWARNING << "Warning: zramsize= flag malformed: " << arg;
231 }
232 }
233 } else if (StartsWith(flag, "forceencrypt=")) {
234 // The forceencrypt flag is followed by an = and the location of the keys.
235 entry->fs_mgr_flags.force_crypt = true;
236 entry->key_loc = arg;
237 } else if (StartsWith(flag, "fileencryption=")) {
238 ParseFileEncryption(arg, entry);
239 } else if (StartsWith(flag, "forcefdeorfbe=")) {
240 // The forcefdeorfbe flag is followed by an = and the location of the keys. Get it and
241 // return it.
242 entry->fs_mgr_flags.force_fde_or_fbe = true;
243 entry->key_loc = arg;
244 entry->encryption_options = "aes-256-xts:aes-256-cts";
245 } else if (StartsWith(flag, "max_comp_streams=")) {
246 if (!ParseInt(arg, &entry->max_comp_streams)) {
247 LWARNING << "Warning: max_comp_streams= flag malformed: " << arg;
248 }
249 } else if (StartsWith(flag, "reservedsize=")) {
250 // The reserved flag is followed by an = and the reserved size of the partition.
251 uint64_t size;
252 if (!ParseByteCount(arg, &size)) {
253 LWARNING << "Warning: reservedsize= flag malformed: " << arg;
254 } else {
255 entry->reserved_size = static_cast<off64_t>(size);
256 }
257 } else if (StartsWith(flag, "eraseblk=")) {
258 // The erase block size flag is followed by an = and the flash erase block size. Get it,
259 // check that it is a power of 2 and at least 4096, and return it.
260 off64_t val;
261 if (!ParseInt(arg, &val) || val < 4096 || (val & (val - 1)) != 0) {
262 LWARNING << "Warning: eraseblk= flag malformed: " << arg;
263 } else {
264 entry->erase_blk_size = val;
265 }
266 } else if (StartsWith(flag, "logicalblk=")) {
267 // The logical block size flag is followed by an = and the flash logical block size. Get
268 // it, check that it is a power of 2 and at least 4096, and return it.
269 off64_t val;
270 if (!ParseInt(arg, &val) || val < 4096 || (val & (val - 1)) != 0) {
271 LWARNING << "Warning: logicalblk= flag malformed: " << arg;
272 } else {
273 entry->logical_blk_size = val;
274 }
275 } else if (StartsWith(flag, "avb_keys=")) { // must before the following "avb"
276 entry->avb_keys = arg;
277 } else if (StartsWith(flag, "avb")) {
278 entry->fs_mgr_flags.avb = true;
279 entry->vbmeta_partition = arg;
280 } else if (StartsWith(flag, "keydirectory=")) {
281 // The metadata flag is followed by an = and the directory for the keys.
282 entry->metadata_key_dir = arg;
283 } else if (StartsWith(flag, "metadata_encryption=")) {
284 // Specify the cipher and flags to use for metadata encryption
285 entry->metadata_encryption = arg;
286 } else if (StartsWith(flag, "sysfs_path=")) {
287 // The path to trigger device gc by idle-maint of vold.
288 entry->sysfs_path = arg;
289 } else if (StartsWith(flag, "zram_loopback_path=")) {
290 // The path to use loopback for zram.
291 entry->zram_loopback_path = arg;
292 } else if (StartsWith(flag, "zram_loopback_size=")) {
293 if (!ParseByteCount(arg, &entry->zram_loopback_size)) {
294 LWARNING << "Warning: zram_loopback_size= flag malformed: " << arg;
295 }
296 } else if (StartsWith(flag, "zram_backing_dev_path=")) {
297 entry->zram_backing_dev_path = arg;
298 } else {
299 LWARNING << "Warning: unknown flag: " << flag;
300 }
301 }
302 }
303
InitAndroidDtDir()304 std::string InitAndroidDtDir() {
305 std::string android_dt_dir;
306 // The platform may specify a custom Android DT path in kernel cmdline
307 if (!fs_mgr_get_boot_config_from_kernel_cmdline("android_dt_dir", &android_dt_dir)) {
308 // Fall back to the standard procfs-based path
309 android_dt_dir = kDefaultAndroidDtDir;
310 }
311 return android_dt_dir;
312 }
313
IsDtFstabCompatible()314 bool IsDtFstabCompatible() {
315 std::string dt_value;
316 std::string file_name = get_android_dt_dir() + "/fstab/compatible";
317
318 if (ReadDtFile(file_name, &dt_value) && dt_value == "android,fstab") {
319 // If there's no status property or its set to "ok" or "okay", then we use the DT fstab.
320 std::string status_value;
321 std::string status_file_name = get_android_dt_dir() + "/fstab/status";
322 return !ReadDtFile(status_file_name, &status_value) || status_value == "ok" ||
323 status_value == "okay";
324 }
325
326 return false;
327 }
328
ReadFstabFromDt()329 std::string ReadFstabFromDt() {
330 if (!is_dt_compatible() || !IsDtFstabCompatible()) {
331 return {};
332 }
333
334 std::string fstabdir_name = get_android_dt_dir() + "/fstab";
335 std::unique_ptr<DIR, int (*)(DIR*)> fstabdir(opendir(fstabdir_name.c_str()), closedir);
336 if (!fstabdir) return {};
337
338 dirent* dp;
339 // Each element in fstab_dt_entries is <mount point, the line format in fstab file>.
340 std::vector<std::pair<std::string, std::string>> fstab_dt_entries;
341 while ((dp = readdir(fstabdir.get())) != NULL) {
342 // skip over name, compatible and .
343 if (dp->d_type != DT_DIR || dp->d_name[0] == '.') continue;
344
345 // create <dev> <mnt_point> <type> <mnt_flags> <fsmgr_flags>\n
346 std::vector<std::string> fstab_entry;
347 std::string file_name;
348 std::string value;
349 // skip a partition entry if the status property is present and not set to ok
350 file_name = android::base::StringPrintf("%s/%s/status", fstabdir_name.c_str(), dp->d_name);
351 if (ReadDtFile(file_name, &value)) {
352 if (value != "okay" && value != "ok") {
353 LINFO << "dt_fstab: Skip disabled entry for partition " << dp->d_name;
354 continue;
355 }
356 }
357
358 file_name = android::base::StringPrintf("%s/%s/dev", fstabdir_name.c_str(), dp->d_name);
359 if (!ReadDtFile(file_name, &value)) {
360 LERROR << "dt_fstab: Failed to find device for partition " << dp->d_name;
361 return {};
362 }
363 fstab_entry.push_back(value);
364
365 std::string mount_point;
366 file_name =
367 android::base::StringPrintf("%s/%s/mnt_point", fstabdir_name.c_str(), dp->d_name);
368 if (ReadDtFile(file_name, &value)) {
369 LINFO << "dt_fstab: Using a specified mount point " << value << " for " << dp->d_name;
370 mount_point = value;
371 } else {
372 mount_point = android::base::StringPrintf("/%s", dp->d_name);
373 }
374 fstab_entry.push_back(mount_point);
375
376 file_name = android::base::StringPrintf("%s/%s/type", fstabdir_name.c_str(), dp->d_name);
377 if (!ReadDtFile(file_name, &value)) {
378 LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
379 return {};
380 }
381 fstab_entry.push_back(value);
382
383 file_name = android::base::StringPrintf("%s/%s/mnt_flags", fstabdir_name.c_str(), dp->d_name);
384 if (!ReadDtFile(file_name, &value)) {
385 LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
386 return {};
387 }
388 fstab_entry.push_back(value);
389
390 file_name = android::base::StringPrintf("%s/%s/fsmgr_flags", fstabdir_name.c_str(), dp->d_name);
391 if (!ReadDtFile(file_name, &value)) {
392 LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
393 return {};
394 }
395 fstab_entry.push_back(value);
396 // Adds a fstab_entry to fstab_dt_entries, to be sorted by mount_point later.
397 fstab_dt_entries.emplace_back(mount_point, android::base::Join(fstab_entry, " "));
398 }
399
400 // Sort fstab_dt entries, to ensure /vendor is mounted before /vendor/abc is attempted.
401 std::sort(fstab_dt_entries.begin(), fstab_dt_entries.end(),
402 [](const auto& a, const auto& b) { return a.first < b.first; });
403
404 std::string fstab_result;
405 for (const auto& [_, dt_entry] : fstab_dt_entries) {
406 fstab_result += dt_entry + "\n";
407 }
408 return fstab_result;
409 }
410
411 // Identify path to fstab file. Lookup is based on pattern
412 // fstab.<fstab_suffix>, fstab.<hardware>, fstab.<hardware.platform> in
413 // folders /odm/etc, vendor/etc, or /.
GetFstabPath()414 std::string GetFstabPath() {
415 for (const char* prop : {"fstab_suffix", "hardware", "hardware.platform"}) {
416 std::string suffix;
417
418 if (!fs_mgr_get_boot_config(prop, &suffix)) continue;
419
420 for (const char* prefix : {"/odm/etc/fstab.", "/vendor/etc/fstab.", "/fstab."}) {
421 std::string fstab_path = prefix + suffix;
422 if (access(fstab_path.c_str(), F_OK) == 0) {
423 return fstab_path;
424 }
425 }
426 }
427
428 return "";
429 }
430
ReadFstabFile(FILE * fstab_file,bool proc_mounts,Fstab * fstab_out)431 bool ReadFstabFile(FILE* fstab_file, bool proc_mounts, Fstab* fstab_out) {
432 ssize_t len;
433 size_t alloc_len = 0;
434 char *line = NULL;
435 const char *delim = " \t";
436 char *save_ptr, *p;
437 Fstab fstab;
438
439 while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
440 /* if the last character is a newline, shorten the string by 1 byte */
441 if (line[len - 1] == '\n') {
442 line[len - 1] = '\0';
443 }
444
445 /* Skip any leading whitespace */
446 p = line;
447 while (isspace(*p)) {
448 p++;
449 }
450 /* ignore comments or empty lines */
451 if (*p == '#' || *p == '\0')
452 continue;
453
454 FstabEntry entry;
455
456 if (!(p = strtok_r(line, delim, &save_ptr))) {
457 LERROR << "Error parsing mount source";
458 goto err;
459 }
460 entry.blk_device = p;
461
462 if (!(p = strtok_r(NULL, delim, &save_ptr))) {
463 LERROR << "Error parsing mount_point";
464 goto err;
465 }
466 entry.mount_point = p;
467
468 if (!(p = strtok_r(NULL, delim, &save_ptr))) {
469 LERROR << "Error parsing fs_type";
470 goto err;
471 }
472 entry.fs_type = p;
473
474 if (!(p = strtok_r(NULL, delim, &save_ptr))) {
475 LERROR << "Error parsing mount_flags";
476 goto err;
477 }
478
479 ParseMountFlags(p, &entry);
480
481 // For /proc/mounts, ignore everything after mnt_freq and mnt_passno
482 if (proc_mounts) {
483 p += strlen(p);
484 } else if (!(p = strtok_r(NULL, delim, &save_ptr))) {
485 LERROR << "Error parsing fs_mgr_options";
486 goto err;
487 }
488
489 ParseFsMgrFlags(p, &entry);
490
491 if (entry.fs_mgr_flags.logical) {
492 entry.logical_partition_name = entry.blk_device;
493 }
494
495 fstab.emplace_back(std::move(entry));
496 }
497
498 if (fstab.empty()) {
499 LERROR << "No entries found in fstab";
500 goto err;
501 }
502
503 /* If an A/B partition, modify block device to be the real block device */
504 if (!fs_mgr_update_for_slotselect(&fstab)) {
505 LERROR << "Error updating for slotselect";
506 goto err;
507 }
508 free(line);
509 *fstab_out = std::move(fstab);
510 return true;
511
512 err:
513 free(line);
514 return false;
515 }
516
517 /* Extracts <device>s from the by-name symlinks specified in a fstab:
518 * /dev/block/<type>/<device>/by-name/<partition>
519 *
520 * <type> can be: platform, pci or vbd.
521 *
522 * For example, given the following entries in the input fstab:
523 * /dev/block/platform/soc/1da4000.ufshc/by-name/system
524 * /dev/block/pci/soc.0/f9824900.sdhci/by-name/vendor
525 * it returns a set { "soc/1da4000.ufshc", "soc.0/f9824900.sdhci" }.
526 */
ExtraBootDevices(const Fstab & fstab)527 std::set<std::string> ExtraBootDevices(const Fstab& fstab) {
528 std::set<std::string> boot_devices;
529
530 for (const auto& entry : fstab) {
531 std::string blk_device = entry.blk_device;
532 // Skips blk_device that doesn't conform to the format.
533 if (!android::base::StartsWith(blk_device, "/dev/block") ||
534 android::base::StartsWith(blk_device, "/dev/block/by-name") ||
535 android::base::StartsWith(blk_device, "/dev/block/bootdevice/by-name")) {
536 continue;
537 }
538 // Skips non-by_name blk_device.
539 // /dev/block/<type>/<device>/by-name/<partition>
540 // ^ slash_by_name
541 auto slash_by_name = blk_device.find("/by-name");
542 if (slash_by_name == std::string::npos) continue;
543 blk_device.erase(slash_by_name); // erases /by-name/<partition>
544
545 // Erases /dev/block/, now we have <type>/<device>
546 blk_device.erase(0, std::string("/dev/block/").size());
547
548 // <type>/<device>
549 // ^ first_slash
550 auto first_slash = blk_device.find('/');
551 if (first_slash == std::string::npos) continue;
552
553 auto boot_device = blk_device.substr(first_slash + 1);
554 if (!boot_device.empty()) boot_devices.insert(std::move(boot_device));
555 }
556
557 return boot_devices;
558 }
559
BuildDsuUserdataFstabEntry()560 FstabEntry BuildDsuUserdataFstabEntry() {
561 constexpr uint32_t kFlags = MS_NOATIME | MS_NOSUID | MS_NODEV;
562
563 FstabEntry userdata = {
564 .blk_device = "userdata_gsi",
565 .mount_point = "/data",
566 .fs_type = "ext4",
567 .flags = kFlags,
568 .reserved_size = 128 * 1024 * 1024,
569 };
570 userdata.fs_mgr_flags.wait = true;
571 userdata.fs_mgr_flags.check = true;
572 userdata.fs_mgr_flags.logical = true;
573 userdata.fs_mgr_flags.quota = true;
574 userdata.fs_mgr_flags.late_mount = true;
575 userdata.fs_mgr_flags.formattable = true;
576 return userdata;
577 }
578
EraseFstabEntry(Fstab * fstab,const std::string & mount_point)579 bool EraseFstabEntry(Fstab* fstab, const std::string& mount_point) {
580 auto iter = std::remove_if(fstab->begin(), fstab->end(),
581 [&](const auto& entry) { return entry.mount_point == mount_point; });
582 if (iter != fstab->end()) {
583 fstab->erase(iter, fstab->end());
584 return true;
585 }
586 return false;
587 }
588
589 } // namespace
590
TransformFstabForDsu(Fstab * fstab,const std::vector<std::string> & dsu_partitions)591 void TransformFstabForDsu(Fstab* fstab, const std::vector<std::string>& dsu_partitions) {
592 static constexpr char kDsuKeysDir[] = "/avb";
593 // Convert userdata
594 // Inherit fstab properties for userdata.
595 FstabEntry userdata;
596 if (FstabEntry* entry = GetEntryForMountPoint(fstab, "/data")) {
597 userdata = *entry;
598 userdata.blk_device = "userdata_gsi";
599 userdata.fs_mgr_flags.logical = true;
600 userdata.fs_mgr_flags.formattable = true;
601 if (!userdata.metadata_key_dir.empty()) {
602 userdata.metadata_key_dir += "/gsi";
603 }
604 } else {
605 userdata = BuildDsuUserdataFstabEntry();
606 }
607
608 if (EraseFstabEntry(fstab, "/data")) {
609 fstab->emplace_back(userdata);
610 }
611
612 // Convert others
613 for (auto&& partition : dsu_partitions) {
614 if (!EndsWith(partition, gsi::kDsuPostfix)) {
615 continue;
616 }
617 // userdata has been handled
618 if (StartsWith(partition, "user")) {
619 continue;
620 }
621 // dsu_partition_name = corresponding_partition_name + kDsuPostfix
622 // e.g.
623 // system_gsi for system
624 // product_gsi for product
625 // vendor_gsi for vendor
626 std::string lp_name = partition.substr(0, partition.length() - strlen(gsi::kDsuPostfix));
627 std::string mount_point = "/" + lp_name;
628 std::vector<FstabEntry*> entries = GetEntriesForMountPoint(fstab, mount_point);
629 if (entries.empty()) {
630 FstabEntry entry = {
631 .blk_device = partition,
632 // .logical_partition_name is required to look up AVB Hashtree descriptors.
633 .logical_partition_name = "system",
634 .mount_point = mount_point,
635 .fs_type = "ext4",
636 .flags = MS_RDONLY,
637 .fs_options = "barrier=1",
638 .avb_keys = kDsuKeysDir,
639 };
640 entry.fs_mgr_flags.wait = true;
641 entry.fs_mgr_flags.logical = true;
642 entry.fs_mgr_flags.first_stage_mount = true;
643 } else {
644 // If the corresponding partition exists, transform all its Fstab
645 // by pointing .blk_device to the DSU partition.
646 for (auto&& entry : entries) {
647 entry->blk_device = partition;
648 // AVB keys for DSU should always be under kDsuKeysDir.
649 entry->avb_keys += kDsuKeysDir;
650 }
651 // Make sure the ext4 is included to support GSI.
652 auto partition_ext4 =
653 std::find_if(fstab->begin(), fstab->end(), [&](const auto& entry) {
654 return entry.mount_point == mount_point && entry.fs_type == "ext4";
655 });
656 if (partition_ext4 == fstab->end()) {
657 auto new_entry = *GetEntryForMountPoint(fstab, mount_point);
658 new_entry.fs_type = "ext4";
659 fstab->emplace_back(new_entry);
660 }
661 }
662 }
663 }
664
EnableMandatoryFlags(Fstab * fstab)665 void EnableMandatoryFlags(Fstab* fstab) {
666 // Devices launched in R and after should enable fs_verity on userdata. The flag causes tune2fs
667 // to enable the feature. A better alternative would be to enable on mkfs at the beginning.
668 if (android::base::GetIntProperty("ro.product.first_api_level", 0) >= 30) {
669 std::vector<FstabEntry*> data_entries = GetEntriesForMountPoint(fstab, "/data");
670 for (auto&& entry : data_entries) {
671 // Besides ext4, f2fs is also supported. But the image is already created with verity
672 // turned on when it was first introduced.
673 if (entry->fs_type == "ext4") {
674 entry->fs_mgr_flags.fs_verity = true;
675 }
676 }
677 }
678 }
679
ReadFstabFromFile(const std::string & path,Fstab * fstab)680 bool ReadFstabFromFile(const std::string& path, Fstab* fstab) {
681 auto fstab_file = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
682 if (!fstab_file) {
683 PERROR << __FUNCTION__ << "(): cannot open file: '" << path << "'";
684 return false;
685 }
686
687 bool is_proc_mounts = path == "/proc/mounts";
688
689 if (!ReadFstabFile(fstab_file.get(), is_proc_mounts, fstab)) {
690 LERROR << __FUNCTION__ << "(): failed to load fstab from : '" << path << "'";
691 return false;
692 }
693 if (!is_proc_mounts && !access(android::gsi::kGsiBootedIndicatorFile, F_OK)) {
694 std::string lp_names;
695 ReadFileToString(gsi::kGsiLpNamesFile, &lp_names);
696 TransformFstabForDsu(fstab, Split(lp_names, ","));
697 }
698
699 #ifndef NO_SKIP_MOUNT
700 SkipMountingPartitions(fstab);
701 #endif
702 EnableMandatoryFlags(fstab);
703
704 return true;
705 }
706
707 // Returns fstab entries parsed from the device tree if they exist
ReadFstabFromDt(Fstab * fstab,bool log)708 bool ReadFstabFromDt(Fstab* fstab, bool log) {
709 std::string fstab_buf = ReadFstabFromDt();
710 if (fstab_buf.empty()) {
711 if (log) LINFO << __FUNCTION__ << "(): failed to read fstab from dt";
712 return false;
713 }
714
715 std::unique_ptr<FILE, decltype(&fclose)> fstab_file(
716 fmemopen(static_cast<void*>(const_cast<char*>(fstab_buf.c_str())),
717 fstab_buf.length(), "r"), fclose);
718 if (!fstab_file) {
719 if (log) PERROR << __FUNCTION__ << "(): failed to create a file stream for fstab dt";
720 return false;
721 }
722
723 if (!ReadFstabFile(fstab_file.get(), false, fstab)) {
724 if (log) {
725 LERROR << __FUNCTION__ << "(): failed to load fstab from kernel:" << std::endl
726 << fstab_buf;
727 }
728 return false;
729 }
730
731 #ifndef NO_SKIP_MOUNT
732 SkipMountingPartitions(fstab);
733 #endif
734
735 return true;
736 }
737
738 #ifndef NO_SKIP_MOUNT
739 // For GSI to skip mounting /product and /system_ext, until there are well-defined interfaces
740 // between them and /system. Otherwise, the GSI flashed on /system might not be able to work with
741 // device-specific /product and /system_ext. skip_mount.cfg belongs to system_ext partition because
742 // only common files for all targets can be put into system partition. It is under
743 // /system/system_ext because GSI is a single system.img that includes the contents of system_ext
744 // partition and product partition under /system/system_ext and /system/product, respectively.
SkipMountingPartitions(Fstab * fstab)745 bool SkipMountingPartitions(Fstab* fstab) {
746 constexpr const char kSkipMountConfig[] = "/system/system_ext/etc/init/config/skip_mount.cfg";
747
748 std::string skip_config;
749 auto save_errno = errno;
750 if (!ReadFileToString(kSkipMountConfig, &skip_config)) {
751 errno = save_errno; // missing file is expected
752 return true;
753 }
754
755 for (const auto& skip_mount_point : Split(skip_config, "\n")) {
756 if (skip_mount_point.empty()) {
757 continue;
758 }
759 auto it = std::remove_if(fstab->begin(), fstab->end(),
760 [&skip_mount_point](const auto& entry) {
761 return entry.mount_point == skip_mount_point;
762 });
763 if (it == fstab->end()) continue;
764 fstab->erase(it, fstab->end());
765 LOG(INFO) << "Skip mounting partition: " << skip_mount_point;
766 }
767
768 return true;
769 }
770 #endif
771
772 // Loads the fstab file and combines with fstab entries passed in from device tree.
ReadDefaultFstab(Fstab * fstab)773 bool ReadDefaultFstab(Fstab* fstab) {
774 Fstab dt_fstab;
775 ReadFstabFromDt(&dt_fstab, false);
776
777 *fstab = std::move(dt_fstab);
778
779 std::string default_fstab_path;
780 // Use different fstab paths for normal boot and recovery boot, respectively
781 if (access("/system/bin/recovery", F_OK) == 0) {
782 default_fstab_path = "/etc/recovery.fstab";
783 } else { // normal boot
784 default_fstab_path = GetFstabPath();
785 }
786
787 Fstab default_fstab;
788 if (!default_fstab_path.empty()) {
789 ReadFstabFromFile(default_fstab_path, &default_fstab);
790 } else {
791 LINFO << __FUNCTION__ << "(): failed to find device default fstab";
792 }
793
794 for (auto&& entry : default_fstab) {
795 fstab->emplace_back(std::move(entry));
796 }
797
798 return !fstab->empty();
799 }
800
GetEntryForMountPoint(Fstab * fstab,const std::string & path)801 FstabEntry* GetEntryForMountPoint(Fstab* fstab, const std::string& path) {
802 if (fstab == nullptr) {
803 return nullptr;
804 }
805
806 for (auto& entry : *fstab) {
807 if (entry.mount_point == path) {
808 return &entry;
809 }
810 }
811
812 return nullptr;
813 }
814
GetEntriesForMountPoint(Fstab * fstab,const std::string & path)815 std::vector<FstabEntry*> GetEntriesForMountPoint(Fstab* fstab, const std::string& path) {
816 std::vector<FstabEntry*> entries;
817 if (fstab == nullptr) {
818 return entries;
819 }
820
821 for (auto& entry : *fstab) {
822 if (entry.mount_point == path) {
823 entries.emplace_back(&entry);
824 }
825 }
826
827 return entries;
828 }
829
GetBootDevices()830 std::set<std::string> GetBootDevices() {
831 // First check the kernel commandline, then try the device tree otherwise
832 std::string dt_file_name = get_android_dt_dir() + "/boot_devices";
833 std::string value;
834 if (fs_mgr_get_boot_config_from_kernel_cmdline("boot_devices", &value) ||
835 ReadDtFile(dt_file_name, &value)) {
836 auto boot_devices = Split(value, ",");
837 return std::set<std::string>(boot_devices.begin(), boot_devices.end());
838 }
839
840 std::string cmdline;
841 if (android::base::ReadFileToString("/proc/cmdline", &cmdline)) {
842 std::set<std::string> boot_devices;
843 const std::string cmdline_key = "androidboot.boot_device";
844 for (const auto& [key, value] : fs_mgr_parse_boot_config(cmdline)) {
845 if (key == cmdline_key) {
846 boot_devices.emplace(value);
847 }
848 }
849 if (!boot_devices.empty()) {
850 return boot_devices;
851 }
852 }
853
854 // Fallback to extract boot devices from fstab.
855 Fstab fstab;
856 if (!ReadDefaultFstab(&fstab)) {
857 return {};
858 }
859
860 return ExtraBootDevices(fstab);
861 }
862
GetVerityDeviceName(const FstabEntry & entry)863 std::string GetVerityDeviceName(const FstabEntry& entry) {
864 std::string base_device;
865 if (entry.mount_point == "/") {
866 // When using system-as-root, the device name is fixed as "vroot".
867 if (entry.fs_mgr_flags.avb) {
868 return "vroot";
869 }
870 base_device = "system";
871 } else {
872 base_device = android::base::Basename(entry.mount_point);
873 }
874 return base_device + "-verity";
875 }
876
877 } // namespace fs_mgr
878 } // namespace android
879
880 // FIXME: The same logic is duplicated in system/core/init/
get_android_dt_dir()881 const std::string& get_android_dt_dir() {
882 // Set once and saves time for subsequent calls to this function
883 static const std::string kAndroidDtDir = android::fs_mgr::InitAndroidDtDir();
884 return kAndroidDtDir;
885 }
886
is_dt_compatible()887 bool is_dt_compatible() {
888 std::string file_name = get_android_dt_dir() + "/compatible";
889 std::string dt_value;
890 if (android::fs_mgr::ReadDtFile(file_name, &dt_value)) {
891 if (dt_value == "android,firmware") {
892 return true;
893 }
894 }
895
896 return false;
897 }
898