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