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