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