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