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