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