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 <fnmatch.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/mount.h>
25 #include <unistd.h>
26 
27 #include <algorithm>
28 #include <array>
29 #include <utility>
30 #include <vector>
31 
32 #include <android-base/file.h>
33 #include <android-base/parseint.h>
34 #include <android-base/properties.h>
35 #include <android-base/stringprintf.h>
36 #include <android-base/strings.h>
37 #include <libgsi/libgsi.h>
38 
39 #include "fs_mgr_priv.h"
40 
41 using android::base::EndsWith;
42 using android::base::ParseByteCount;
43 using android::base::ParseInt;
44 using android::base::ReadFileToString;
45 using android::base::Readlink;
46 using android::base::Split;
47 using android::base::StartsWith;
48 
49 namespace android {
50 namespace fs_mgr {
51 namespace {
52 
53 constexpr char kDefaultAndroidDtDir[] = "/proc/device-tree/firmware/android";
54 
55 struct FlagList {
56     const char *name;
57     uint64_t flag;
58 };
59 
60 FlagList kMountFlagsList[] = {
61         {"noatime", MS_NOATIME},
62         {"noexec", MS_NOEXEC},
63         {"nosuid", MS_NOSUID},
64         {"nodev", MS_NODEV},
65         {"nodiratime", MS_NODIRATIME},
66         {"ro", MS_RDONLY},
67         {"rw", 0},
68         {"sync", MS_SYNCHRONOUS},
69         {"remount", MS_REMOUNT},
70         {"bind", MS_BIND},
71         {"rec", MS_REC},
72         {"unbindable", MS_UNBINDABLE},
73         {"private", MS_PRIVATE},
74         {"slave", MS_SLAVE},
75         {"shared", MS_SHARED},
76         {"defaults", 0},
77 };
78 
CalculateZramSize(int percentage)79 off64_t CalculateZramSize(int percentage) {
80     off64_t total;
81 
82     total  = sysconf(_SC_PHYS_PAGES);
83     total *= percentage;
84     total /= 100;
85 
86     total *= sysconf(_SC_PAGESIZE);
87 
88     return total;
89 }
90 
91 // Fills 'dt_value' with the underlying device tree value string without the trailing '\0'.
92 // Returns true if 'dt_value' has a valid string, 'false' otherwise.
ReadDtFile(const std::string & file_name,std::string * dt_value)93 bool ReadDtFile(const std::string& file_name, std::string* dt_value) {
94     if (android::base::ReadFileToString(file_name, dt_value)) {
95         if (!dt_value->empty()) {
96             // Trim the trailing '\0' out, otherwise the comparison will produce false-negatives.
97             dt_value->resize(dt_value->size() - 1);
98             return true;
99         }
100     }
101 
102     return false;
103 }
104 
ParseFileEncryption(const std::string & arg,FstabEntry * entry)105 void ParseFileEncryption(const std::string& arg, FstabEntry* entry) {
106     entry->fs_mgr_flags.file_encryption = true;
107     entry->encryption_options = arg;
108 }
109 
SetMountFlag(const std::string & flag,FstabEntry * entry)110 bool SetMountFlag(const std::string& flag, FstabEntry* entry) {
111     for (const auto& [name, value] : kMountFlagsList) {
112         if (flag == name) {
113             entry->flags |= value;
114             return true;
115         }
116     }
117     return false;
118 }
119 
ParseMountFlags(const std::string & flags,FstabEntry * entry)120 void ParseMountFlags(const std::string& flags, FstabEntry* entry) {
121     std::string fs_options;
122     for (const auto& flag : Split(flags, ",")) {
123         if (!SetMountFlag(flag, entry)) {
124             // Unknown flag, so it must be a filesystem specific option.
125             if (!fs_options.empty()) {
126                 fs_options.append(",");  // appends a comma if not the first
127             }
128             fs_options.append(flag);
129 
130             if (auto equal_sign = flag.find('='); equal_sign != std::string::npos) {
131                 const auto arg = flag.substr(equal_sign + 1);
132                 if (entry->fs_type == "f2fs" && StartsWith(flag, "reserve_root=")) {
133                     off64_t size_in_4k_blocks;
134                     if (!ParseInt(arg, &size_in_4k_blocks, static_cast<off64_t>(0),
135                                   std::numeric_limits<off64_t>::max() >> 12)) {
136                         LWARNING << "Warning: reserve_root= flag malformed: " << arg;
137                     } else {
138                         entry->reserved_size = size_in_4k_blocks << 12;
139                     }
140                 } else if (StartsWith(flag, "lowerdir=")) {
141                     entry->lowerdir = arg;
142                 }
143             }
144         }
145     }
146     entry->fs_options = std::move(fs_options);
147 }
148 
ParseFsMgrFlags(const std::string & flags,FstabEntry * entry)149 bool ParseFsMgrFlags(const std::string& flags, FstabEntry* entry) {
150     for (const auto& flag : Split(flags, ",")) {
151         if (flag.empty() || flag == "defaults") continue;
152         std::string arg;
153         if (auto equal_sign = flag.find('='); equal_sign != std::string::npos) {
154             arg = flag.substr(equal_sign + 1);
155         }
156 
157         // First handle flags that simply set a boolean.
158 #define CheckFlag(flag_name, value)       \
159     if (flag == flag_name) {              \
160         entry->fs_mgr_flags.value = true; \
161         continue;                         \
162     }
163 
164         CheckFlag("wait", wait);
165         CheckFlag("check", check);
166         CheckFlag("nonremovable", nonremovable);
167         CheckFlag("recoveryonly", recovery_only);
168         CheckFlag("noemulatedsd", no_emulated_sd);
169         CheckFlag("notrim", no_trim);
170         CheckFlag("formattable", formattable);
171         CheckFlag("slotselect", slot_select);
172         CheckFlag("latemount", late_mount);
173         CheckFlag("nofail", no_fail);
174         CheckFlag("quota", quota);
175         CheckFlag("avb", avb);
176         CheckFlag("logical", logical);
177         CheckFlag("checkpoint=block", checkpoint_blk);
178         CheckFlag("checkpoint=fs", checkpoint_fs);
179         CheckFlag("first_stage_mount", first_stage_mount);
180         CheckFlag("slotselect_other", slot_select_other);
181         CheckFlag("fsverity", fs_verity);
182         CheckFlag("metadata_csum", ext_meta_csum);
183         CheckFlag("fscompress", fs_compress);
184         CheckFlag("overlayfs_remove_missing_lowerdir", overlayfs_remove_missing_lowerdir);
185 
186 #undef CheckFlag
187 
188         // Then handle flags that take an argument.
189         if (StartsWith(flag, "encryptable=")) {
190             // The "encryptable" flag identifies adoptable storage volumes.  The
191             // argument to this flag is ignored, but it should be "userdata".
192             //
193             // Historical note: this flag was originally meant just for /data,
194             // to indicate that FDE (full disk encryption) can be enabled.
195             // Unfortunately, it was also overloaded to identify adoptable
196             // storage volumes.  Today, FDE is no longer supported, leaving only
197             // the adoptable storage volume meaning for this flag.
198             entry->fs_mgr_flags.crypt = true;
199         } else if (StartsWith(flag, "forceencrypt=") || StartsWith(flag, "forcefdeorfbe=")) {
200             LERROR << "flag no longer supported: " << flag;
201             return false;
202         } else if (StartsWith(flag, "voldmanaged=")) {
203             // The voldmanaged flag is followed by an = and the label, a colon and the partition
204             // number or the word "auto", e.g. voldmanaged=sdcard:3
205             entry->fs_mgr_flags.vold_managed = true;
206             auto parts = Split(arg, ":");
207             if (parts.size() != 2) {
208                 LWARNING << "Warning: voldmanaged= flag malformed: " << arg;
209                 continue;
210             }
211 
212             entry->label = std::move(parts[0]);
213             if (parts[1] == "auto") {
214                 entry->partnum = -1;
215             } else {
216                 if (!ParseInt(parts[1], &entry->partnum)) {
217                     entry->partnum = -1;
218                     LWARNING << "Warning: voldmanaged= flag malformed: " << arg;
219                     continue;
220                 }
221             }
222         } else if (StartsWith(flag, "length=")) {
223             // The length flag is followed by an = and the size of the partition.
224             if (!ParseInt(arg, &entry->length)) {
225                 LWARNING << "Warning: length= flag malformed: " << arg;
226             }
227         } else if (StartsWith(flag, "swapprio=")) {
228             if (!ParseInt(arg, &entry->swap_prio)) {
229                 LWARNING << "Warning: swapprio= flag malformed: " << arg;
230             }
231         } else if (StartsWith(flag, "zramsize=")) {
232             if (!arg.empty() && arg.back() == '%') {
233                 arg.pop_back();
234                 int val;
235                 if (ParseInt(arg, &val, 0, 100)) {
236                     entry->zram_size = CalculateZramSize(val);
237                 } else {
238                     LWARNING << "Warning: zramsize= flag malformed: " << arg;
239                 }
240             } else {
241                 if (!ParseInt(arg, &entry->zram_size)) {
242                     LWARNING << "Warning: zramsize= flag malformed: " << arg;
243                 }
244             }
245         } else if (StartsWith(flag, "fileencryption=")) {
246             ParseFileEncryption(arg, entry);
247         } else if (StartsWith(flag, "max_comp_streams=")) {
248             if (!ParseInt(arg, &entry->max_comp_streams)) {
249                 LWARNING << "Warning: max_comp_streams= flag malformed: " << arg;
250             }
251         } else if (StartsWith(flag, "reservedsize=")) {
252             // The reserved flag is followed by an = and the reserved size of the partition.
253             uint64_t size;
254             if (!ParseByteCount(arg, &size)) {
255                 LWARNING << "Warning: reservedsize= flag malformed: " << arg;
256             } else {
257                 entry->reserved_size = static_cast<off64_t>(size);
258             }
259         } else if (StartsWith(flag, "readahead_size_kb=")) {
260             int val;
261             if (ParseInt(arg, &val, 0, 16 * 1024)) {
262                 entry->readahead_size_kb = val;
263             } else {
264                 LWARNING << "Warning: readahead_size_kb= flag malformed (0 ~ 16MB): " << arg;
265             }
266         } else if (StartsWith(flag, "eraseblk=")) {
267             // The erase block size flag is followed by an = and the flash erase block size. Get it,
268             // check that it is a power of 2 and at least 4096, and return it.
269             off64_t val;
270             if (!ParseInt(arg, &val) || val < 4096 || (val & (val - 1)) != 0) {
271                 LWARNING << "Warning: eraseblk= flag malformed: " << arg;
272             } else {
273                 entry->erase_blk_size = val;
274             }
275         } else if (StartsWith(flag, "logicalblk=")) {
276             // The logical block size flag is followed by an = and the flash logical block size. Get
277             // it, check that it is a power of 2 and at least 4096, and return it.
278             off64_t val;
279             if (!ParseInt(arg, &val) || val < 4096 || (val & (val - 1)) != 0) {
280                 LWARNING << "Warning: logicalblk= flag malformed: " << arg;
281             } else {
282                 entry->logical_blk_size = val;
283             }
284         } else if (StartsWith(flag, "avb_keys=")) {  // must before the following "avb"
285             entry->avb_keys = arg;
286         } else if (StartsWith(flag, "avb")) {
287             entry->fs_mgr_flags.avb = true;
288             entry->vbmeta_partition = arg;
289         } else if (StartsWith(flag, "keydirectory=")) {
290             // The keydirectory flag enables metadata encryption.  It is
291             // followed by an = and the directory containing the metadata
292             // encryption key.
293             entry->metadata_key_dir = arg;
294         } else if (StartsWith(flag, "metadata_encryption=")) {
295             // The metadata_encryption flag specifies the cipher and flags to
296             // use for metadata encryption, if the defaults aren't sufficient.
297             // It doesn't actually enable metadata encryption; that is done by
298             // "keydirectory".
299             entry->metadata_encryption_options = arg;
300         } else if (StartsWith(flag, "sysfs_path=")) {
301             // The path to trigger device gc by idle-maint of vold.
302             entry->sysfs_path = arg;
303         } else if (StartsWith(flag, "zram_backingdev_size=")) {
304             if (!ParseByteCount(arg, &entry->zram_backingdev_size)) {
305                 LWARNING << "Warning: zram_backingdev_size= flag malformed: " << arg;
306             }
307         } else if (flag == "zoned_device") {
308             if (access("/dev/block/by-name/zoned_device", F_OK) == 0) {
309                 entry->zoned_device = "/dev/block/by-name/zoned_device";
310 
311                 // atgc in f2fs does not support a zoned device
312                 auto options = Split(entry->fs_options, ",");
313                 options.erase(std::remove(options.begin(), options.end(), "atgc"), options.end());
314                 entry->fs_options = android::base::Join(options, ",");
315                 LINFO << "Removed ATGC in fs_options as " << entry->fs_options
316                       << " for zoned device=" << entry->zoned_device;
317             }
318         } else {
319             LWARNING << "Warning: unknown flag: " << flag;
320         }
321     }
322 
323     // FDE is no longer supported, so reject "encryptable" when used without
324     // "vold_managed".  For now skip this check when in recovery mode, since
325     // some recovery fstabs still contain the FDE options since they didn't do
326     // anything in recovery mode anyway (except possibly to cause the
327     // reservation of a crypto footer) and thus never got removed.
328     if (entry->fs_mgr_flags.crypt && !entry->fs_mgr_flags.vold_managed &&
329         access("/system/bin/recovery", F_OK) != 0) {
330         LERROR << "FDE is no longer supported; 'encryptable' can only be used for adoptable "
331                   "storage";
332         return false;
333     }
334     return true;
335 }
336 
InitAndroidDtDir()337 std::string InitAndroidDtDir() {
338     std::string android_dt_dir;
339     // The platform may specify a custom Android DT path in kernel cmdline
340     if (!fs_mgr_get_boot_config_from_bootconfig_source("android_dt_dir", &android_dt_dir) &&
341         !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 /* Extracts <device>s from the by-name symlinks specified in a fstab:
446  *   /dev/block/<type>/<device>/by-name/<partition>
447  *
448  * <type> can be: platform, pci or vbd.
449  *
450  * For example, given the following entries in the input fstab:
451  *   /dev/block/platform/soc/1da4000.ufshc/by-name/system
452  *   /dev/block/pci/soc.0/f9824900.sdhci/by-name/vendor
453  * it returns a set { "soc/1da4000.ufshc", "soc.0/f9824900.sdhci" }.
454  */
ExtraBootDevices(const Fstab & fstab)455 std::set<std::string> ExtraBootDevices(const Fstab& fstab) {
456     std::set<std::string> boot_devices;
457 
458     for (const auto& entry : fstab) {
459         std::string blk_device = entry.blk_device;
460         // Skips blk_device that doesn't conform to the format.
461         if (!android::base::StartsWith(blk_device, "/dev/block") ||
462             android::base::StartsWith(blk_device, "/dev/block/by-name") ||
463             android::base::StartsWith(blk_device, "/dev/block/bootdevice/by-name")) {
464             continue;
465         }
466         // Skips non-by_name blk_device.
467         // /dev/block/<type>/<device>/by-name/<partition>
468         //                           ^ slash_by_name
469         auto slash_by_name = blk_device.find("/by-name");
470         if (slash_by_name == std::string::npos) continue;
471         blk_device.erase(slash_by_name);  // erases /by-name/<partition>
472 
473         // Erases /dev/block/, now we have <type>/<device>
474         blk_device.erase(0, std::string("/dev/block/").size());
475 
476         // <type>/<device>
477         //       ^ first_slash
478         auto first_slash = blk_device.find('/');
479         if (first_slash == std::string::npos) continue;
480 
481         auto boot_device = blk_device.substr(first_slash + 1);
482         if (!boot_device.empty()) boot_devices.insert(std::move(boot_device));
483     }
484 
485     return boot_devices;
486 }
487 
488 // Helper class that maps Fstab* -> FstabEntry; const Fstab* -> const FstabEntry.
489 template <typename FstabPtr>
490 struct FstabPtrEntry {
491     using is_const_fstab = std::is_const<std::remove_pointer_t<FstabPtr>>;
492     using type = std::conditional_t<is_const_fstab::value, const FstabEntry, FstabEntry>;
493 };
494 
495 template <typename FstabPtr, typename FstabPtrEntryType = typename FstabPtrEntry<FstabPtr>::type,
496           typename Pred>
GetEntriesByPred(FstabPtr fstab,const Pred & pred)497 std::vector<FstabPtrEntryType*> GetEntriesByPred(FstabPtr fstab, const Pred& pred) {
498     if (fstab == nullptr) {
499         return {};
500     }
501     std::vector<FstabPtrEntryType*> entries;
502     for (FstabPtrEntryType& entry : *fstab) {
503         if (pred(entry)) {
504             entries.push_back(&entry);
505         }
506     }
507     return entries;
508 }
509 
510 }  // namespace
511 
512 // Return the path to the fstab file.  There may be multiple fstab files; the
513 // one that is returned will be the first that exists of fstab.<fstab_suffix>,
514 // fstab.<hardware>, and fstab.<hardware.platform>.  The fstab is searched for
515 // in /odm/etc/ and /vendor/etc/, as well as in the locations where it may be in
516 // the first stage ramdisk during early boot.  Previously, the first stage
517 // ramdisk's copy of the fstab had to be located in the root directory, but now
518 // the system/etc directory is supported too and is the preferred location.
GetFstabPath()519 std::string GetFstabPath() {
520     for (const char* prop : {"fstab_suffix", "hardware", "hardware.platform"}) {
521         std::string suffix;
522 
523         if (!fs_mgr_get_boot_config(prop, &suffix)) continue;
524 
525         for (const char* prefix : {// late-boot/post-boot locations
526                                    "/odm/etc/fstab.", "/vendor/etc/fstab.",
527                                    // early boot locations
528                                    "/system/etc/fstab.", "/first_stage_ramdisk/system/etc/fstab.",
529                                    "/fstab.", "/first_stage_ramdisk/fstab."}) {
530             std::string fstab_path = prefix + suffix;
531             if (access(fstab_path.c_str(), F_OK) == 0) {
532                 return fstab_path;
533             }
534         }
535     }
536 
537     return "";
538 }
539 
ParseFstabFromString(const std::string & fstab_str,bool proc_mounts,Fstab * fstab_out)540 bool ParseFstabFromString(const std::string& fstab_str, bool proc_mounts, Fstab* fstab_out) {
541     const int expected_fields = proc_mounts ? 4 : 5;
542 
543     Fstab fstab;
544 
545     for (const auto& line : android::base::Split(fstab_str, "\n")) {
546         auto fields = android::base::Tokenize(line, " \t");
547 
548         // Ignore empty lines and comments.
549         if (fields.empty() || android::base::StartsWith(fields.front(), '#')) {
550             continue;
551         }
552 
553         if (fields.size() < expected_fields) {
554             LERROR << "Error parsing fstab: expected " << expected_fields << " fields, got "
555                    << fields.size();
556             return false;
557         }
558 
559         FstabEntry entry;
560         auto it = fields.begin();
561 
562         entry.blk_device = std::move(*it++);
563         entry.mount_point = std::move(*it++);
564         entry.fs_type = std::move(*it++);
565         ParseMountFlags(std::move(*it++), &entry);
566 
567         // For /proc/mounts, ignore everything after mnt_freq and mnt_passno
568         if (!proc_mounts && !ParseFsMgrFlags(std::move(*it++), &entry)) {
569             LERROR << "Error parsing fs_mgr_flags";
570             return false;
571         }
572 
573         if (entry.fs_mgr_flags.logical) {
574             entry.logical_partition_name = entry.blk_device;
575         }
576 
577         fstab.emplace_back(std::move(entry));
578     }
579 
580     if (fstab.empty()) {
581         LERROR << "No entries found in fstab";
582         return false;
583     }
584 
585     /* If an A/B partition, modify block device to be the real block device */
586     if (!fs_mgr_update_for_slotselect(&fstab)) {
587         LERROR << "Error updating for slotselect";
588         return false;
589     }
590 
591     *fstab_out = std::move(fstab);
592     return true;
593 }
594 
TransformFstabForDsu(Fstab * fstab,const std::string & dsu_slot,const std::vector<std::string> & dsu_partitions)595 void TransformFstabForDsu(Fstab* fstab, const std::string& dsu_slot,
596                           const std::vector<std::string>& dsu_partitions) {
597     static constexpr char kDsuKeysDir[] = "/avb";
598     for (auto&& partition : dsu_partitions) {
599         if (!EndsWith(partition, gsi::kDsuPostfix)) {
600             continue;
601         }
602         // scratch is handled by fs_mgr_overlayfs
603         if (partition == android::gsi::kDsuScratch) {
604             continue;
605         }
606         // Convert userdata partition.
607         if (partition == android::gsi::kDsuUserdata) {
608             for (auto&& entry : GetEntriesForMountPoint(fstab, "/data")) {
609                 entry->blk_device = android::gsi::kDsuUserdata;
610                 entry->fs_mgr_flags.logical = true;
611                 entry->fs_mgr_flags.formattable = true;
612                 if (!entry->metadata_key_dir.empty()) {
613                     entry->metadata_key_dir = android::gsi::GetDsuMetadataKeyDir(dsu_slot);
614                 }
615             }
616             continue;
617         }
618         // Convert RO partitions.
619         //
620         // dsu_partition_name = corresponding_partition_name + kDsuPostfix
621         // e.g.
622         //    system_gsi for system
623         //    product_gsi for product
624         //    vendor_gsi for vendor
625         std::string lp_name = partition.substr(0, partition.length() - strlen(gsi::kDsuPostfix));
626         std::string mount_point = "/" + lp_name;
627 
628         // List of fs_type entries we're lacking, need to synthesis these later.
629         std::vector<std::string> lack_fs_list = {"ext4", "erofs"};
630 
631         // Only support early mount (first_stage_mount) partitions.
632         auto pred = [&mount_point](const FstabEntry& entry) {
633             return entry.fs_mgr_flags.first_stage_mount && entry.mount_point == mount_point;
634         };
635 
636         // Transform all matching entries and assume they are all adjacent for simplicity.
637         for (auto&& entry : GetEntriesByPred(fstab, pred)) {
638             // .blk_device is replaced with the DSU partition.
639             entry->blk_device = partition;
640             // .avb_keys hints first_stage_mount to load the chained-vbmeta image from partition
641             // footer. See aosp/932779 for more details.
642             entry->avb_keys = kDsuKeysDir;
643             // .logical_partition_name is required to look up AVB Hashtree descriptors.
644             entry->logical_partition_name = lp_name;
645             entry->fs_mgr_flags.logical = true;
646             entry->fs_mgr_flags.slot_select = false;
647             entry->fs_mgr_flags.slot_select_other = false;
648 
649             if (auto it = std::find(lack_fs_list.begin(), lack_fs_list.end(), entry->fs_type);
650                 it != lack_fs_list.end()) {
651                 lack_fs_list.erase(it);
652             }
653         }
654 
655         if (!lack_fs_list.empty()) {
656             // Insert at the end of the existing mountpoint group, or at the end of fstab.
657             // We assume there is at most one matching mountpoint group, which is the common case.
658             auto it = std::find_if_not(std::find_if(fstab->begin(), fstab->end(), pred),
659                                        fstab->end(), pred);
660             for (const auto& fs_type : lack_fs_list) {
661                 it = std::next(fstab->insert(it, {.blk_device = partition,
662                                                   .logical_partition_name = lp_name,
663                                                   .mount_point = mount_point,
664                                                   .fs_type = fs_type,
665                                                   .flags = MS_RDONLY,
666                                                   .avb_keys = kDsuKeysDir,
667                                                   .fs_mgr_flags{
668                                                           .wait = true,
669                                                           .logical = true,
670                                                           .first_stage_mount = true,
671                                                   }}));
672             }
673         }
674     }
675 }
676 
EnableMandatoryFlags(Fstab * fstab)677 void EnableMandatoryFlags(Fstab* fstab) {
678     // Devices launched in R and after must support fs_verity. Set flag to cause tune2fs
679     // to enable the feature on userdata and metadata partitions.
680     if (android::base::GetIntProperty("ro.product.first_api_level", 0) >= 30) {
681         // Devices launched in R and after should enable fs_verity on userdata.
682         // A better alternative would be to enable on mkfs at the beginning.
683         std::vector<FstabEntry*> data_entries = GetEntriesForMountPoint(fstab, "/data");
684         for (auto&& entry : data_entries) {
685             // Besides ext4, f2fs is also supported. But the image is already created with verity
686             // turned on when it was first introduced.
687             if (entry->fs_type == "ext4") {
688                 entry->fs_mgr_flags.fs_verity = true;
689             }
690         }
691         // Devices shipping with S and earlier likely do not already have fs_verity enabled via
692         // mkfs, so enable it here.
693         std::vector<FstabEntry*> metadata_entries = GetEntriesForMountPoint(fstab, "/metadata");
694         for (auto&& entry : metadata_entries) {
695             entry->fs_mgr_flags.fs_verity = true;
696         }
697     }
698 }
699 
ReadFstabFromFile(const std::string & path,Fstab * fstab_out)700 bool ReadFstabFromFile(const std::string& path, Fstab* fstab_out) {
701     const bool is_proc_mounts = (path == "/proc/mounts");
702 
703     std::string fstab_str;
704     if (!android::base::ReadFileToString(path, &fstab_str, /* follow_symlinks = */ true)) {
705         PERROR << __FUNCTION__ << "(): failed to read file: '" << path << "'";
706         return false;
707     }
708 
709     Fstab fstab;
710     if (!ParseFstabFromString(fstab_str, is_proc_mounts, &fstab)) {
711         LERROR << __FUNCTION__ << "(): failed to load fstab from : '" << path << "'";
712         return false;
713     }
714     if (!is_proc_mounts) {
715         if (!access(android::gsi::kGsiBootedIndicatorFile, F_OK)) {
716             std::string dsu_slot;
717             if (!android::gsi::GetActiveDsu(&dsu_slot)) {
718                 PERROR << __FUNCTION__ << "(): failed to get active DSU slot";
719                 return false;
720             }
721             std::string lp_names;
722             if (!ReadFileToString(gsi::kGsiLpNamesFile, &lp_names)) {
723                 PERROR << __FUNCTION__ << "(): failed to read DSU LP names";
724                 return false;
725             }
726             TransformFstabForDsu(&fstab, dsu_slot, Split(lp_names, ","));
727         } else if (errno != ENOENT) {
728             PERROR << __FUNCTION__ << "(): failed to access() DSU booted indicator";
729             return false;
730         }
731     }
732 
733     SkipMountingPartitions(&fstab, false /* verbose */);
734     EnableMandatoryFlags(&fstab);
735 
736     *fstab_out = std::move(fstab);
737     return true;
738 }
739 
740 // Returns fstab entries parsed from the device tree if they exist
ReadFstabFromDt(Fstab * fstab,bool verbose)741 bool ReadFstabFromDt(Fstab* fstab, bool verbose) {
742     std::string fstab_buf = ReadFstabFromDt();
743     if (fstab_buf.empty()) {
744         if (verbose) LINFO << __FUNCTION__ << "(): failed to read fstab from dt";
745         return false;
746     }
747 
748     if (!ParseFstabFromString(fstab_buf, /* proc_mounts = */ false, fstab)) {
749         if (verbose) {
750             LERROR << __FUNCTION__ << "(): failed to load fstab from kernel:" << std::endl
751                    << fstab_buf;
752         }
753         return false;
754     }
755 
756     SkipMountingPartitions(fstab, verbose);
757 
758     return true;
759 }
760 
761 #ifdef NO_SKIP_MOUNT
762 static constexpr bool kNoSkipMount = true;
763 #else
764 static constexpr bool kNoSkipMount = false;
765 #endif
766 
767 // For GSI to skip mounting /product and /system_ext, until there are well-defined interfaces
768 // between them and /system. Otherwise, the GSI flashed on /system might not be able to work with
769 // device-specific /product and /system_ext. skip_mount.cfg belongs to system_ext partition because
770 // only common files for all targets can be put into system partition. It is under
771 // /system/system_ext because GSI is a single system.img that includes the contents of system_ext
772 // partition and product partition under /system/system_ext and /system/product, respectively.
SkipMountingPartitions(Fstab * fstab,bool verbose)773 bool SkipMountingPartitions(Fstab* fstab, bool verbose) {
774     if (kNoSkipMount) {
775         return true;
776     }
777 
778     static constexpr char kSkipMountConfig[] = "/system/system_ext/etc/init/config/skip_mount.cfg";
779 
780     std::string skip_mount_config;
781     auto save_errno = errno;
782     if (!ReadFileToString(kSkipMountConfig, &skip_mount_config)) {
783         errno = save_errno;  // missing file is expected
784         return true;
785     }
786     return SkipMountWithConfig(skip_mount_config, fstab, verbose);
787 }
788 
SkipMountWithConfig(const std::string & skip_mount_config,Fstab * fstab,bool verbose)789 bool SkipMountWithConfig(const std::string& skip_mount_config, Fstab* fstab, bool verbose) {
790     std::vector<std::string> skip_mount_patterns;
791     for (const auto& line : Split(skip_mount_config, "\n")) {
792         if (line.empty() || StartsWith(line, "#")) {
793             continue;
794         }
795         skip_mount_patterns.push_back(line);
796     }
797 
798     // Returns false if mount_point matches any of the skip mount patterns, so that the FstabEntry
799     // would be partitioned to the second group.
800     auto glob_pattern_mismatch = [&skip_mount_patterns](const FstabEntry& entry) -> bool {
801         for (const auto& pattern : skip_mount_patterns) {
802             if (!fnmatch(pattern.c_str(), entry.mount_point.c_str(), 0 /* flags */)) {
803                 return false;
804             }
805         }
806         return true;
807     };
808     auto remove_from = std::stable_partition(fstab->begin(), fstab->end(), glob_pattern_mismatch);
809     if (verbose) {
810         for (auto it = remove_from; it != fstab->end(); ++it) {
811             LINFO << "Skip mounting mountpoint: " << it->mount_point;
812         }
813     }
814     fstab->erase(remove_from, fstab->end());
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->clear();
821     ReadFstabFromDt(fstab, false /* verbose */);
822 
823     std::string default_fstab_path;
824     // Use different fstab paths for normal boot and recovery boot, respectively
825     if ((access("/sbin/recovery", F_OK) == 0) || (access("/system/bin/recovery", F_OK) == 0)) {
826         default_fstab_path = "/etc/recovery.fstab";
827     } else {  // normal boot
828         default_fstab_path = GetFstabPath();
829     }
830 
831     Fstab default_fstab;
832     if (!default_fstab_path.empty() && ReadFstabFromFile(default_fstab_path, &default_fstab)) {
833         for (auto&& entry : default_fstab) {
834             fstab->emplace_back(std::move(entry));
835         }
836     } else {
837         LINFO << __FUNCTION__ << "(): failed to find device default fstab";
838     }
839 
840     return !fstab->empty();
841 }
842 
GetEntriesForMountPoint(Fstab * fstab,const std::string & path)843 std::vector<FstabEntry*> GetEntriesForMountPoint(Fstab* fstab, const std::string& path) {
844     return GetEntriesByPred(fstab,
845                             [&path](const FstabEntry& entry) { return entry.mount_point == path; });
846 }
847 
GetEntriesForMountPoint(const Fstab * fstab,const std::string & path)848 std::vector<const FstabEntry*> GetEntriesForMountPoint(const Fstab* fstab,
849                                                        const std::string& path) {
850     return GetEntriesByPred(fstab,
851                             [&path](const FstabEntry& entry) { return entry.mount_point == path; });
852 }
853 
GetEntryForMountPoint(Fstab * fstab,const std::string & path)854 FstabEntry* GetEntryForMountPoint(Fstab* fstab, const std::string& path) {
855     std::vector<FstabEntry*> entries = GetEntriesForMountPoint(fstab, path);
856     return entries.empty() ? nullptr : entries.front();
857 }
858 
GetEntryForMountPoint(const Fstab * fstab,const std::string & path)859 const FstabEntry* GetEntryForMountPoint(const Fstab* fstab, const std::string& path) {
860     std::vector<const FstabEntry*> entries = GetEntriesForMountPoint(fstab, path);
861     return entries.empty() ? nullptr : entries.front();
862 }
863 
GetBootDevices()864 std::set<std::string> GetBootDevices() {
865     // First check bootconfig, then kernel commandline, then the device tree
866     std::string dt_file_name = get_android_dt_dir() + "/boot_devices";
867     std::string value;
868     if (fs_mgr_get_boot_config_from_bootconfig_source("boot_devices", &value) ||
869         fs_mgr_get_boot_config_from_bootconfig_source("boot_device", &value)) {
870         std::set<std::string> boot_devices;
871         // remove quotes and split by spaces
872         auto boot_device_strings = base::Split(base::StringReplace(value, "\"", "", true), " ");
873         for (std::string_view device : boot_device_strings) {
874             // trim the trailing comma, keep the rest.
875             base::ConsumeSuffix(&device, ",");
876             boot_devices.emplace(device);
877         }
878         return boot_devices;
879     }
880 
881     if (fs_mgr_get_boot_config_from_kernel_cmdline("boot_devices", &value) ||
882         ReadDtFile(dt_file_name, &value)) {
883         auto boot_devices = Split(value, ",");
884         return std::set<std::string>(boot_devices.begin(), boot_devices.end());
885     }
886 
887     std::string cmdline;
888     if (android::base::ReadFileToString("/proc/cmdline", &cmdline)) {
889         std::set<std::string> boot_devices;
890         const std::string cmdline_key = "androidboot.boot_device";
891         for (const auto& [key, value] : fs_mgr_parse_cmdline(cmdline)) {
892             if (key == cmdline_key) {
893                 boot_devices.emplace(value);
894             }
895         }
896         if (!boot_devices.empty()) {
897             return boot_devices;
898         }
899     }
900 
901     // Fallback to extract boot devices from fstab.
902     Fstab fstab;
903     if (!ReadDefaultFstab(&fstab)) {
904         return {};
905     }
906 
907     return ExtraBootDevices(fstab);
908 }
909 
GetVerityDeviceName(const FstabEntry & entry)910 std::string GetVerityDeviceName(const FstabEntry& entry) {
911     std::string base_device;
912     if (entry.mount_point == "/") {
913         // When using system-as-root, the device name is fixed as "vroot".
914         if (entry.fs_mgr_flags.avb) {
915             return "vroot";
916         }
917         base_device = "system";
918     } else {
919         base_device = android::base::Basename(entry.mount_point);
920     }
921     return base_device + "-verity";
922 }
923 
924 }  // namespace fs_mgr
925 }  // namespace android
926 
927 // FIXME: The same logic is duplicated in system/core/init/
get_android_dt_dir()928 const std::string& get_android_dt_dir() {
929     // Set once and saves time for subsequent calls to this function
930     static const std::string kAndroidDtDir = android::fs_mgr::InitAndroidDtDir();
931     return kAndroidDtDir;
932 }
933 
is_dt_compatible()934 bool is_dt_compatible() {
935     std::string file_name = get_android_dt_dir() + "/compatible";
936     std::string dt_value;
937     if (android::fs_mgr::ReadDtFile(file_name, &dt_value)) {
938         if (dt_value == "android,firmware") {
939             return true;
940         }
941     }
942 
943     return false;
944 }
945