blob: 8c719c868252dc498d012c10912984157e2dcec2 [file] [log] [blame]
Colin Cross5edee2a2014-01-23 14:22:48 -08001/*
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>
Sandeep Patilc20c0c22017-02-23 16:09:34 -080018#include <dirent.h>
Iliyan Malchev3ea902f2015-05-01 14:05:04 -070019#include <errno.h>
Yi-Yo Chiang2f2fe4a2021-03-31 20:39:22 +080020#include <fnmatch.h>
Colin Cross5edee2a2014-01-23 14:22:48 -080021#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <sys/mount.h>
Iliyan Malchev3ea902f2015-05-01 14:05:04 -070025#include <unistd.h>
Colin Cross5edee2a2014-01-23 14:22:48 -080026
Bowgo Tsai80281892017-12-12 00:47:43 +080027#include <algorithm>
Tom Cherry7e34f752019-01-22 15:37:08 -080028#include <array>
Bowgo Tsai80281892017-12-12 00:47:43 +080029#include <utility>
30#include <vector>
31
Sandeep Patilc20c0c22017-02-23 16:09:34 -080032#include <android-base/file.h>
Jaegeuk Kim2aedc822018-11-20 13:27:06 -080033#include <android-base/parseint.h>
Victor Hsieh98296fc2020-02-24 16:02:32 -080034#include <android-base/properties.h>
Sandeep Patilc20c0c22017-02-23 16:09:34 -080035#include <android-base/stringprintf.h>
36#include <android-base/strings.h>
David Anderson0e330f12019-01-03 18:16:56 -080037#include <libgsi/libgsi.h>
Sandeep Patilc20c0c22017-02-23 16:09:34 -080038
Colin Cross5edee2a2014-01-23 14:22:48 -080039#include "fs_mgr_priv.h"
40
Howard Chen1b094932019-09-11 18:22:01 +080041using android::base::EndsWith;
Tom Cherry151a17f2019-01-21 16:49:13 -080042using android::base::ParseByteCount;
43using android::base::ParseInt;
SzuWei Lin77c28472019-04-22 17:27:52 +080044using android::base::ReadFileToString;
Nikita Ioffe51106282019-11-21 21:40:03 +000045using android::base::Readlink;
Tom Cherry6bbe9472018-12-13 10:58:37 -080046using android::base::Split;
Tom Marshall66f6a6d2018-03-06 16:19:18 +010047using android::base::StartsWith;
48
Tom Cherrya3530e62019-01-30 13:25:35 -080049namespace android {
50namespace fs_mgr {
51namespace {
52
Vic Yang5caa3e92019-08-06 14:15:33 -070053constexpr char kDefaultAndroidDtDir[] = "/proc/device-tree/firmware/android";
Yu Ningc01022a2017-07-26 17:54:08 +080054
Tom Cherrya3530e62019-01-30 13:25:35 -080055struct FlagList {
Colin Cross5edee2a2014-01-23 14:22:48 -080056 const char *name;
Bowgo Tsai4c80edf2018-12-12 23:21:13 +080057 uint64_t flag;
Colin Cross5edee2a2014-01-23 14:22:48 -080058};
59
Tom Cherrya3530e62019-01-30 13:25:35 -080060FlagList kMountFlagsList[] = {
Tom Cherry151a17f2019-01-21 16:49:13 -080061 {"noatime", MS_NOATIME},
62 {"noexec", MS_NOEXEC},
63 {"nosuid", MS_NOSUID},
64 {"nodev", MS_NODEV},
65 {"nodiratime", MS_NODIRATIME},
66 {"ro", MS_RDONLY},
67 {"rw", 0},
Jaegeuk Kim5ffa9702019-06-05 17:43:47 -070068 {"sync", MS_SYNCHRONOUS},
Tom Cherry151a17f2019-01-21 16:49:13 -080069 {"remount", MS_REMOUNT},
70 {"bind", MS_BIND},
71 {"rec", MS_REC},
72 {"unbindable", MS_UNBINDABLE},
73 {"private", MS_PRIVATE},
74 {"slave", MS_SLAVE},
75 {"shared", MS_SHARED},
Daniel Rosenberg4c93b252018-08-28 01:41:18 -070076 {"defaults", 0},
Colin Cross5edee2a2014-01-23 14:22:48 -080077};
78
Tom Cherrya3530e62019-01-30 13:25:35 -080079off64_t CalculateZramSize(int percentage) {
Tom Cherryfafbb642018-11-29 13:24:09 -080080 off64_t total;
Iliyan Malchev3ea902f2015-05-01 14:05:04 -070081
82 total = sysconf(_SC_PHYS_PAGES);
83 total *= percentage;
84 total /= 100;
85
86 total *= sysconf(_SC_PAGESIZE);
87
88 return total;
89}
90
Tom Cherrya3530e62019-01-30 13:25:35 -080091// Fills 'dt_value' with the underlying device tree value string without the trailing '\0'.
92// Returns true if 'dt_value' has a valid string, 'false' otherwise.
93bool ReadDtFile(const std::string& file_name, std::string* dt_value) {
Sandeep Patil4cd9a462017-02-24 13:03:39 -080094 if (android::base::ReadFileToString(file_name, dt_value)) {
95 if (!dt_value->empty()) {
Tom Cherrya3530e62019-01-30 13:25:35 -080096 // Trim the trailing '\0' out, otherwise the comparison will produce false-negatives.
Sandeep Patil4cd9a462017-02-24 13:03:39 -080097 dt_value->resize(dt_value->size() - 1);
98 return true;
99 }
100 }
101
102 return false;
103}
104
Tom Cherrya3530e62019-01-30 13:25:35 -0800105void ParseFileEncryption(const std::string& arg, FstabEntry* entry) {
Tom Cherry151a17f2019-01-21 16:49:13 -0800106 entry->fs_mgr_flags.file_encryption = true;
Paul Crowley4fa84132019-10-24 23:33:12 -0700107 entry->encryption_options = arg;
Tom Cherry7e34f752019-01-22 15:37:08 -0800108}
109
Tom Cherrya3530e62019-01-30 13:25:35 -0800110bool SetMountFlag(const std::string& flag, FstabEntry* entry) {
111 for (const auto& [name, value] : kMountFlagsList) {
Tom Cherry151a17f2019-01-21 16:49:13 -0800112 if (flag == name) {
113 entry->flags |= value;
114 return true;
115 }
116 }
117 return false;
118}
Colin Cross5edee2a2014-01-23 14:22:48 -0800119
Tom Cherrya3530e62019-01-30 13:25:35 -0800120void ParseMountFlags(const std::string& flags, FstabEntry* entry) {
Tom Cherry151a17f2019-01-21 16:49:13 -0800121 std::string fs_options;
122 for (const auto& flag : Split(flags, ",")) {
123 if (!SetMountFlag(flag, entry)) {
124 // Unknown flag, so it must be a filesystem specific option.
125 if (!fs_options.empty()) {
126 fs_options.append(","); // appends a comma if not the first
Colin Cross5edee2a2014-01-23 14:22:48 -0800127 }
Tom Cherry151a17f2019-01-21 16:49:13 -0800128 fs_options.append(flag);
Jaegeuk Kimf07d07b2019-06-13 17:37:01 -0700129
Yi-Yo Chiang7b810232021-05-22 00:35:09 +0800130 if (auto equal_sign = flag.find('='); equal_sign != std::string::npos) {
131 const auto arg = flag.substr(equal_sign + 1);
132 if (entry->fs_type == "f2fs" && StartsWith(flag, "reserve_root=")) {
Yi-Yo Chiangfb62a712021-10-25 21:47:57 +0800133 off64_t size_in_4k_blocks;
134 if (!ParseInt(arg, &size_in_4k_blocks, static_cast<off64_t>(0),
135 std::numeric_limits<off64_t>::max() >> 12)) {
Yi-Yo Chiang7b810232021-05-22 00:35:09 +0800136 LWARNING << "Warning: reserve_root= flag malformed: " << arg;
137 } else {
Yi-Yo Chiangfb62a712021-10-25 21:47:57 +0800138 entry->reserved_size = size_in_4k_blocks << 12;
Yi-Yo Chiang7b810232021-05-22 00:35:09 +0800139 }
140 } else if (StartsWith(flag, "lowerdir=")) {
Yi-Yo Chiangeee9fe42021-11-12 21:45:24 +0800141 entry->lowerdir = arg;
Jaegeuk Kimf07d07b2019-06-13 17:37:01 -0700142 }
143 }
Tom Cherry151a17f2019-01-21 16:49:13 -0800144 }
145 }
146 entry->fs_options = std::move(fs_options);
147}
148
Eric Biggersb6625302021-11-08 16:38:52 -0800149bool ParseFsMgrFlags(const std::string& flags, FstabEntry* entry) {
Tom Cherry151a17f2019-01-21 16:49:13 -0800150 for (const auto& flag : Split(flags, ",")) {
Mark Salyzync0d09a22019-02-05 07:30:23 -0800151 if (flag.empty() || flag == "defaults") continue;
Tom Cherry151a17f2019-01-21 16:49:13 -0800152 std::string arg;
153 if (auto equal_sign = flag.find('='); equal_sign != std::string::npos) {
154 arg = flag.substr(equal_sign + 1);
Colin Cross5edee2a2014-01-23 14:22:48 -0800155 }
156
Tom Cherry151a17f2019-01-21 16:49:13 -0800157 // First handle flags that simply set a boolean.
158#define CheckFlag(flag_name, value) \
159 if (flag == flag_name) { \
160 entry->fs_mgr_flags.value = true; \
161 continue; \
Colin Cross5edee2a2014-01-23 14:22:48 -0800162 }
163
Tom Cherry151a17f2019-01-21 16:49:13 -0800164 CheckFlag("wait", wait);
165 CheckFlag("check", check);
166 CheckFlag("nonremovable", nonremovable);
167 CheckFlag("recoveryonly", recovery_only);
168 CheckFlag("noemulatedsd", no_emulated_sd);
169 CheckFlag("notrim", no_trim);
Tom Cherry151a17f2019-01-21 16:49:13 -0800170 CheckFlag("formattable", formattable);
171 CheckFlag("slotselect", slot_select);
172 CheckFlag("latemount", late_mount);
173 CheckFlag("nofail", no_fail);
Tom Cherry151a17f2019-01-21 16:49:13 -0800174 CheckFlag("quota", quota);
175 CheckFlag("avb", avb);
176 CheckFlag("logical", logical);
177 CheckFlag("checkpoint=block", checkpoint_blk);
178 CheckFlag("checkpoint=fs", checkpoint_fs);
179 CheckFlag("first_stage_mount", first_stage_mount);
180 CheckFlag("slotselect_other", slot_select_other);
181 CheckFlag("fsverity", fs_verity);
Jaegeuk Kim78f040c2020-02-11 15:22:46 -0800182 CheckFlag("metadata_csum", ext_meta_csum);
Jaegeuk Kim4076dc92020-01-13 11:02:28 -0800183 CheckFlag("fscompress", fs_compress);
Yi-Yo Chiange7783a92021-08-03 01:02:31 +0800184 CheckFlag("overlayfs_remove_missing_lowerdir", overlayfs_remove_missing_lowerdir);
Tom Cherry151a17f2019-01-21 16:49:13 -0800185
186#undef CheckFlag
187
188 // Then handle flags that take an argument.
Eric Biggers9e217002021-11-12 12:13:30 -0800189 if (StartsWith(flag, "encryptable=")) {
Eric Biggersb6625302021-11-08 16:38:52 -0800190 // The "encryptable" flag identifies adoptable storage volumes. The
Eric Biggers9e217002021-11-12 12:13:30 -0800191 // argument to this flag is ignored, but it should be "userdata".
Eric Biggersb6625302021-11-08 16:38:52 -0800192 //
193 // Historical note: this flag was originally meant just for /data,
194 // to indicate that FDE (full disk encryption) can be enabled.
195 // Unfortunately, it was also overloaded to identify adoptable
196 // storage volumes. Today, FDE is no longer supported, leaving only
197 // the adoptable storage volume meaning for this flag.
Tom Cherry151a17f2019-01-21 16:49:13 -0800198 entry->fs_mgr_flags.crypt = true;
Eric Biggers9e217002021-11-12 12:13:30 -0800199 } else if (StartsWith(flag, "forceencrypt=") || StartsWith(flag, "forcefdeorfbe=")) {
Eric Biggersb6625302021-11-08 16:38:52 -0800200 LERROR << "flag no longer supported: " << flag;
201 return false;
Tom Cherry151a17f2019-01-21 16:49:13 -0800202 } else if (StartsWith(flag, "voldmanaged=")) {
203 // The voldmanaged flag is followed by an = and the label, a colon and the partition
204 // number or the word "auto", e.g. voldmanaged=sdcard:3
205 entry->fs_mgr_flags.vold_managed = true;
206 auto parts = Split(arg, ":");
207 if (parts.size() != 2) {
208 LWARNING << "Warning: voldmanaged= flag malformed: " << arg;
209 continue;
210 }
211
212 entry->label = std::move(parts[0]);
213 if (parts[1] == "auto") {
214 entry->partnum = -1;
215 } else {
216 if (!ParseInt(parts[1], &entry->partnum)) {
217 entry->partnum = -1;
218 LWARNING << "Warning: voldmanaged= flag malformed: " << arg;
219 continue;
220 }
221 }
222 } else if (StartsWith(flag, "length=")) {
223 // The length flag is followed by an = and the size of the partition.
Tom Cherry151a17f2019-01-21 16:49:13 -0800224 if (!ParseInt(arg, &entry->length)) {
225 LWARNING << "Warning: length= flag malformed: " << arg;
226 }
227 } else if (StartsWith(flag, "swapprio=")) {
Tom Cherry151a17f2019-01-21 16:49:13 -0800228 if (!ParseInt(arg, &entry->swap_prio)) {
Felix92ed4232020-02-12 17:29:54 +0100229 LWARNING << "Warning: swapprio= flag malformed: " << arg;
Tom Cherry151a17f2019-01-21 16:49:13 -0800230 }
231 } else if (StartsWith(flag, "zramsize=")) {
Tom Cherry151a17f2019-01-21 16:49:13 -0800232 if (!arg.empty() && arg.back() == '%') {
233 arg.pop_back();
234 int val;
235 if (ParseInt(arg, &val, 0, 100)) {
Tom Cherrya3530e62019-01-30 13:25:35 -0800236 entry->zram_size = CalculateZramSize(val);
Tom Cherry151a17f2019-01-21 16:49:13 -0800237 } else {
238 LWARNING << "Warning: zramsize= flag malformed: " << arg;
239 }
240 } else {
241 if (!ParseInt(arg, &entry->zram_size)) {
242 LWARNING << "Warning: zramsize= flag malformed: " << arg;
243 }
244 }
Tom Cherry151a17f2019-01-21 16:49:13 -0800245 } else if (StartsWith(flag, "fileencryption=")) {
246 ParseFileEncryption(arg, entry);
Tom Cherry151a17f2019-01-21 16:49:13 -0800247 } else if (StartsWith(flag, "max_comp_streams=")) {
Tom Cherry151a17f2019-01-21 16:49:13 -0800248 if (!ParseInt(arg, &entry->max_comp_streams)) {
249 LWARNING << "Warning: max_comp_streams= flag malformed: " << arg;
250 }
251 } else if (StartsWith(flag, "reservedsize=")) {
252 // The reserved flag is followed by an = and the reserved size of the partition.
Tom Cherry151a17f2019-01-21 16:49:13 -0800253 uint64_t size;
254 if (!ParseByteCount(arg, &size)) {
255 LWARNING << "Warning: reservedsize= flag malformed: " << arg;
256 } else {
257 entry->reserved_size = static_cast<off64_t>(size);
258 }
Jaegeuk Kim05ca9152021-04-02 21:28:51 -0700259 } else if (StartsWith(flag, "readahead_size_kb=")) {
260 int val;
261 if (ParseInt(arg, &val, 0, 16 * 1024)) {
262 entry->readahead_size_kb = val;
263 } else {
264 LWARNING << "Warning: readahead_size_kb= flag malformed (0 ~ 16MB): " << arg;
265 }
Tom Cherry151a17f2019-01-21 16:49:13 -0800266 } else if (StartsWith(flag, "eraseblk=")) {
267 // The erase block size flag is followed by an = and the flash erase block size. Get it,
268 // check that it is a power of 2 and at least 4096, and return it.
Tom Cherry151a17f2019-01-21 16:49:13 -0800269 off64_t val;
270 if (!ParseInt(arg, &val) || val < 4096 || (val & (val - 1)) != 0) {
271 LWARNING << "Warning: eraseblk= flag malformed: " << arg;
272 } else {
273 entry->erase_blk_size = val;
274 }
275 } else if (StartsWith(flag, "logicalblk=")) {
276 // The logical block size flag is followed by an = and the flash logical block size. Get
277 // it, check that it is a power of 2 and at least 4096, and return it.
Tom Cherry151a17f2019-01-21 16:49:13 -0800278 off64_t val;
279 if (!ParseInt(arg, &val) || val < 4096 || (val & (val - 1)) != 0) {
280 LWARNING << "Warning: logicalblk= flag malformed: " << arg;
281 } else {
282 entry->logical_blk_size = val;
283 }
Bowgo Tsaid214b402019-02-27 22:56:56 +0800284 } else if (StartsWith(flag, "avb_keys=")) { // must before the following "avb"
285 entry->avb_keys = arg;
Tom Cherry151a17f2019-01-21 16:49:13 -0800286 } else if (StartsWith(flag, "avb")) {
287 entry->fs_mgr_flags.avb = true;
288 entry->vbmeta_partition = arg;
289 } else if (StartsWith(flag, "keydirectory=")) {
Eric Biggers20a5f922022-03-17 23:09:52 +0000290 // The keydirectory flag enables metadata encryption. It is
291 // followed by an = and the directory containing the metadata
292 // encryption key.
Paul Crowley7823e322020-01-30 16:03:45 -0800293 entry->metadata_key_dir = arg;
Barani Muthukumaran2ca1d832020-02-06 23:46:37 -0800294 } else if (StartsWith(flag, "metadata_encryption=")) {
Eric Biggers20a5f922022-03-17 23:09:52 +0000295 // The metadata_encryption flag specifies the cipher and flags to
296 // use for metadata encryption, if the defaults aren't sufficient.
297 // It doesn't actually enable metadata encryption; that is done by
298 // "keydirectory".
299 entry->metadata_encryption_options = arg;
Tom Cherry151a17f2019-01-21 16:49:13 -0800300 } else if (StartsWith(flag, "sysfs_path=")) {
301 // The path to trigger device gc by idle-maint of vold.
Tom Cherry151a17f2019-01-21 16:49:13 -0800302 entry->sysfs_path = arg;
Minchan Kim12e96152019-10-15 14:41:18 -0700303 } else if (StartsWith(flag, "zram_backingdev_size=")) {
304 if (!ParseByteCount(arg, &entry->zram_backingdev_size)) {
305 LWARNING << "Warning: zram_backingdev_size= flag malformed: " << arg;
Tom Cherry151a17f2019-01-21 16:49:13 -0800306 }
Tom Cherry151a17f2019-01-21 16:49:13 -0800307 } else {
308 LWARNING << "Warning: unknown flag: " << flag;
309 }
310 }
Eric Biggersb6625302021-11-08 16:38:52 -0800311
Eric Biggersefe20932021-11-12 13:07:04 -0800312 // FDE is no longer supported, so reject "encryptable" when used without
313 // "vold_managed". For now skip this check when in recovery mode, since
314 // some recovery fstabs still contain the FDE options since they didn't do
315 // anything in recovery mode anyway (except possibly to cause the
316 // reservation of a crypto footer) and thus never got removed.
317 if (entry->fs_mgr_flags.crypt && !entry->fs_mgr_flags.vold_managed &&
318 access("/system/bin/recovery", F_OK) != 0) {
Eric Biggersb6625302021-11-08 16:38:52 -0800319 LERROR << "FDE is no longer supported; 'encryptable' can only be used for adoptable "
320 "storage";
321 return false;
322 }
323 return true;
Colin Cross5edee2a2014-01-23 14:22:48 -0800324}
325
Tom Cherrya3530e62019-01-30 13:25:35 -0800326std::string InitAndroidDtDir() {
Yu Ningc01022a2017-07-26 17:54:08 +0800327 std::string android_dt_dir;
328 // The platform may specify a custom Android DT path in kernel cmdline
Devin Moore20b74252021-03-04 08:23:31 -0800329 if (!fs_mgr_get_boot_config_from_bootconfig_source("android_dt_dir", &android_dt_dir) &&
330 !fs_mgr_get_boot_config_from_kernel_cmdline("android_dt_dir", &android_dt_dir)) {
Yu Ningc01022a2017-07-26 17:54:08 +0800331 // Fall back to the standard procfs-based path
332 android_dt_dir = kDefaultAndroidDtDir;
333 }
334 return android_dt_dir;
335}
336
Tom Cherrya3530e62019-01-30 13:25:35 -0800337bool IsDtFstabCompatible() {
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800338 std::string dt_value;
Yu Ningc01022a2017-07-26 17:54:08 +0800339 std::string file_name = get_android_dt_dir() + "/fstab/compatible";
Tom Cherry1eb04562018-11-06 10:42:09 -0800340
Tom Cherrya3530e62019-01-30 13:25:35 -0800341 if (ReadDtFile(file_name, &dt_value) && dt_value == "android,fstab") {
Tom Cherry1eb04562018-11-06 10:42:09 -0800342 // If there's no status property or its set to "ok" or "okay", then we use the DT fstab.
343 std::string status_value;
344 std::string status_file_name = get_android_dt_dir() + "/fstab/status";
Tom Cherrya3530e62019-01-30 13:25:35 -0800345 return !ReadDtFile(status_file_name, &status_value) || status_value == "ok" ||
Tom Cherry1eb04562018-11-06 10:42:09 -0800346 status_value == "okay";
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800347 }
348
349 return false;
350}
351
Tom Cherrya3530e62019-01-30 13:25:35 -0800352std::string ReadFstabFromDt() {
353 if (!is_dt_compatible() || !IsDtFstabCompatible()) {
Bowgo Tsai80281892017-12-12 00:47:43 +0800354 return {};
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800355 }
356
Yu Ningc01022a2017-07-26 17:54:08 +0800357 std::string fstabdir_name = get_android_dt_dir() + "/fstab";
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800358 std::unique_ptr<DIR, int (*)(DIR*)> fstabdir(opendir(fstabdir_name.c_str()), closedir);
Bowgo Tsai80281892017-12-12 00:47:43 +0800359 if (!fstabdir) return {};
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800360
361 dirent* dp;
Bowgo Tsai80281892017-12-12 00:47:43 +0800362 // Each element in fstab_dt_entries is <mount point, the line format in fstab file>.
363 std::vector<std::pair<std::string, std::string>> fstab_dt_entries;
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800364 while ((dp = readdir(fstabdir.get())) != NULL) {
Bowgo Tsai06ed6132017-06-08 10:43:41 +0800365 // skip over name, compatible and .
366 if (dp->d_type != DT_DIR || dp->d_name[0] == '.') continue;
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800367
368 // create <dev> <mnt_point> <type> <mnt_flags> <fsmgr_flags>\n
369 std::vector<std::string> fstab_entry;
370 std::string file_name;
371 std::string value;
Sandeep Patilbe4302b2017-05-26 18:09:06 -0700372 // skip a partition entry if the status property is present and not set to ok
373 file_name = android::base::StringPrintf("%s/%s/status", fstabdir_name.c_str(), dp->d_name);
Tom Cherrya3530e62019-01-30 13:25:35 -0800374 if (ReadDtFile(file_name, &value)) {
Sandeep Patilbe4302b2017-05-26 18:09:06 -0700375 if (value != "okay" && value != "ok") {
376 LINFO << "dt_fstab: Skip disabled entry for partition " << dp->d_name;
377 continue;
378 }
379 }
380
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800381 file_name = android::base::StringPrintf("%s/%s/dev", fstabdir_name.c_str(), dp->d_name);
Tom Cherrya3530e62019-01-30 13:25:35 -0800382 if (!ReadDtFile(file_name, &value)) {
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800383 LERROR << "dt_fstab: Failed to find device for partition " << dp->d_name;
Bowgo Tsai80281892017-12-12 00:47:43 +0800384 return {};
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800385 }
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800386 fstab_entry.push_back(value);
Bowgo Tsai80281892017-12-12 00:47:43 +0800387
388 std::string mount_point;
389 file_name =
390 android::base::StringPrintf("%s/%s/mnt_point", fstabdir_name.c_str(), dp->d_name);
Tom Cherrya3530e62019-01-30 13:25:35 -0800391 if (ReadDtFile(file_name, &value)) {
Bowgo Tsai80281892017-12-12 00:47:43 +0800392 LINFO << "dt_fstab: Using a specified mount point " << value << " for " << dp->d_name;
393 mount_point = value;
394 } else {
395 mount_point = android::base::StringPrintf("/%s", dp->d_name);
396 }
397 fstab_entry.push_back(mount_point);
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800398
399 file_name = android::base::StringPrintf("%s/%s/type", fstabdir_name.c_str(), dp->d_name);
Tom Cherrya3530e62019-01-30 13:25:35 -0800400 if (!ReadDtFile(file_name, &value)) {
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800401 LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
Bowgo Tsai80281892017-12-12 00:47:43 +0800402 return {};
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800403 }
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800404 fstab_entry.push_back(value);
405
406 file_name = android::base::StringPrintf("%s/%s/mnt_flags", fstabdir_name.c_str(), dp->d_name);
Tom Cherrya3530e62019-01-30 13:25:35 -0800407 if (!ReadDtFile(file_name, &value)) {
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800408 LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
Bowgo Tsai80281892017-12-12 00:47:43 +0800409 return {};
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800410 }
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800411 fstab_entry.push_back(value);
412
413 file_name = android::base::StringPrintf("%s/%s/fsmgr_flags", fstabdir_name.c_str(), dp->d_name);
Tom Cherrya3530e62019-01-30 13:25:35 -0800414 if (!ReadDtFile(file_name, &value)) {
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800415 LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
Bowgo Tsai80281892017-12-12 00:47:43 +0800416 return {};
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800417 }
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800418 fstab_entry.push_back(value);
Bowgo Tsai80281892017-12-12 00:47:43 +0800419 // Adds a fstab_entry to fstab_dt_entries, to be sorted by mount_point later.
420 fstab_dt_entries.emplace_back(mount_point, android::base::Join(fstab_entry, " "));
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800421 }
422
Bowgo Tsai80281892017-12-12 00:47:43 +0800423 // Sort fstab_dt entries, to ensure /vendor is mounted before /vendor/abc is attempted.
424 std::sort(fstab_dt_entries.begin(), fstab_dt_entries.end(),
425 [](const auto& a, const auto& b) { return a.first < b.first; });
426
427 std::string fstab_result;
428 for (const auto& [_, dt_entry] : fstab_dt_entries) {
429 fstab_result += dt_entry + "\n";
430 }
431 return fstab_result;
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800432}
433
Eric Biggerse98afa22021-07-29 19:04:41 -0700434// Return the path to the fstab file. There may be multiple fstab files; the
435// one that is returned will be the first that exists of fstab.<fstab_suffix>,
436// fstab.<hardware>, and fstab.<hardware.platform>. The fstab is searched for
437// in /odm/etc/ and /vendor/etc/, as well as in the locations where it may be in
438// the first stage ramdisk during early boot. Previously, the first stage
439// ramdisk's copy of the fstab had to be located in the root directory, but now
440// the system/etc directory is supported too and is the preferred location.
Tom Cherrya3530e62019-01-30 13:25:35 -0800441std::string GetFstabPath() {
Alistair Delvaa2cc1eb2020-05-20 16:24:00 -0700442 for (const char* prop : {"fstab_suffix", "hardware", "hardware.platform"}) {
443 std::string suffix;
Tom Cherrya3530e62019-01-30 13:25:35 -0800444
Alistair Delvaa2cc1eb2020-05-20 16:24:00 -0700445 if (!fs_mgr_get_boot_config(prop, &suffix)) continue;
Tom Cherrya3530e62019-01-30 13:25:35 -0800446
Eric Biggerse98afa22021-07-29 19:04:41 -0700447 for (const char* prefix : {// late-boot/post-boot locations
448 "/odm/etc/fstab.", "/vendor/etc/fstab.",
449 // early boot locations
450 "/system/etc/fstab.", "/first_stage_ramdisk/system/etc/fstab.",
451 "/fstab.", "/first_stage_ramdisk/fstab."}) {
Alistair Delvaa2cc1eb2020-05-20 16:24:00 -0700452 std::string fstab_path = prefix + suffix;
Tom Cherrya3530e62019-01-30 13:25:35 -0800453 if (access(fstab_path.c_str(), F_OK) == 0) {
454 return fstab_path;
455 }
Sandeep Patile396c602017-02-24 11:04:49 -0800456 }
457 }
458
Tom Cherrya3530e62019-01-30 13:25:35 -0800459 return "";
Sandeep Patile396c602017-02-24 11:04:49 -0800460}
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800461
Yi-Yo Chiangb398a0b2021-10-25 21:34:05 +0800462/* Extracts <device>s from the by-name symlinks specified in a fstab:
463 * /dev/block/<type>/<device>/by-name/<partition>
464 *
465 * <type> can be: platform, pci or vbd.
466 *
467 * For example, given the following entries in the input fstab:
468 * /dev/block/platform/soc/1da4000.ufshc/by-name/system
469 * /dev/block/pci/soc.0/f9824900.sdhci/by-name/vendor
470 * it returns a set { "soc/1da4000.ufshc", "soc.0/f9824900.sdhci" }.
471 */
472std::set<std::string> ExtraBootDevices(const Fstab& fstab) {
473 std::set<std::string> boot_devices;
474
475 for (const auto& entry : fstab) {
476 std::string blk_device = entry.blk_device;
477 // Skips blk_device that doesn't conform to the format.
478 if (!android::base::StartsWith(blk_device, "/dev/block") ||
479 android::base::StartsWith(blk_device, "/dev/block/by-name") ||
480 android::base::StartsWith(blk_device, "/dev/block/bootdevice/by-name")) {
481 continue;
482 }
483 // Skips non-by_name blk_device.
484 // /dev/block/<type>/<device>/by-name/<partition>
485 // ^ slash_by_name
486 auto slash_by_name = blk_device.find("/by-name");
487 if (slash_by_name == std::string::npos) continue;
488 blk_device.erase(slash_by_name); // erases /by-name/<partition>
489
490 // Erases /dev/block/, now we have <type>/<device>
491 blk_device.erase(0, std::string("/dev/block/").size());
492
493 // <type>/<device>
494 // ^ first_slash
495 auto first_slash = blk_device.find('/');
496 if (first_slash == std::string::npos) continue;
497
498 auto boot_device = blk_device.substr(first_slash + 1);
499 if (!boot_device.empty()) boot_devices.insert(std::move(boot_device));
500 }
501
502 return boot_devices;
503}
504
505FstabEntry BuildDsuUserdataFstabEntry() {
506 constexpr uint32_t kFlags = MS_NOATIME | MS_NOSUID | MS_NODEV;
507
508 FstabEntry userdata = {
509 .blk_device = "userdata_gsi",
510 .mount_point = "/data",
511 .fs_type = "ext4",
512 .flags = kFlags,
513 .reserved_size = 128 * 1024 * 1024,
514 };
515 userdata.fs_mgr_flags.wait = true;
516 userdata.fs_mgr_flags.check = true;
517 userdata.fs_mgr_flags.logical = true;
518 userdata.fs_mgr_flags.quota = true;
519 userdata.fs_mgr_flags.late_mount = true;
520 userdata.fs_mgr_flags.formattable = true;
521 return userdata;
522}
523
524bool EraseFstabEntry(Fstab* fstab, const std::string& mount_point) {
525 auto iter = std::remove_if(fstab->begin(), fstab->end(),
526 [&](const auto& entry) { return entry.mount_point == mount_point; });
527 if (iter != fstab->end()) {
528 fstab->erase(iter, fstab->end());
529 return true;
530 }
531 return false;
532}
533
534} // namespace
535
Yi-Yo Chiang97f2fdf2021-11-12 19:19:29 +0800536bool ParseFstabFromString(const std::string& fstab_str, bool proc_mounts, Fstab* fstab_out) {
Yi-Yo Chiangb8837392021-11-11 22:17:35 +0800537 const int expected_fields = proc_mounts ? 4 : 5;
Yi-Yo Chiang97f2fdf2021-11-12 19:19:29 +0800538
Tom Cherryd0be7a52018-11-29 13:04:52 -0800539 Fstab fstab;
Colin Cross5edee2a2014-01-23 14:22:48 -0800540
Yi-Yo Chiang97f2fdf2021-11-12 19:19:29 +0800541 for (const auto& line : android::base::Split(fstab_str, "\n")) {
Yi-Yo Chiangb8837392021-11-11 22:17:35 +0800542 auto fields = android::base::Tokenize(line, " \t");
Yi-Yo Chiang97f2fdf2021-11-12 19:19:29 +0800543
544 // Ignore empty lines and comments.
545 if (fields.empty() || android::base::StartsWith(fields.front(), '#')) {
546 continue;
547 }
548
Yi-Yo Chiangb8837392021-11-11 22:17:35 +0800549 if (fields.size() < expected_fields) {
550 LERROR << "Error parsing fstab: expected " << expected_fields << " fields, got "
551 << fields.size();
Yi-Yo Chiang97f2fdf2021-11-12 19:19:29 +0800552 return false;
Yi-Yo Chiangb8837392021-11-11 22:17:35 +0800553 }
554
Tom Cherryd0be7a52018-11-29 13:04:52 -0800555 FstabEntry entry;
Yi-Yo Chiangb8837392021-11-11 22:17:35 +0800556 auto it = fields.begin();
Colin Cross5edee2a2014-01-23 14:22:48 -0800557
Yi-Yo Chiangb8837392021-11-11 22:17:35 +0800558 entry.blk_device = std::move(*it++);
559 entry.mount_point = std::move(*it++);
560 entry.fs_type = std::move(*it++);
561 ParseMountFlags(std::move(*it++), &entry);
Colin Cross5edee2a2014-01-23 14:22:48 -0800562
Mark Salyzyneba47062018-06-20 13:07:28 -0700563 // For /proc/mounts, ignore everything after mnt_freq and mnt_passno
Yi-Yo Chiangb8837392021-11-11 22:17:35 +0800564 if (!proc_mounts && !ParseFsMgrFlags(std::move(*it++), &entry)) {
Eric Biggersb6625302021-11-08 16:38:52 -0800565 LERROR << "Error parsing fs_mgr_flags";
Yi-Yo Chiang97f2fdf2021-11-12 19:19:29 +0800566 return false;
Eric Biggersb6625302021-11-08 16:38:52 -0800567 }
Tom Cherry151a17f2019-01-21 16:49:13 -0800568
Tom Cherryd0be7a52018-11-29 13:04:52 -0800569 if (entry.fs_mgr_flags.logical) {
570 entry.logical_partition_name = entry.blk_device;
David Anderson62e5b202018-05-01 17:09:17 -0700571 }
572
Tom Cherryd0be7a52018-11-29 13:04:52 -0800573 fstab.emplace_back(std::move(entry));
Colin Cross5edee2a2014-01-23 14:22:48 -0800574 }
Tom Cherryd0be7a52018-11-29 13:04:52 -0800575
576 if (fstab.empty()) {
577 LERROR << "No entries found in fstab";
Yi-Yo Chiang97f2fdf2021-11-12 19:19:29 +0800578 return false;
Tom Cherryd0be7a52018-11-29 13:04:52 -0800579 }
580
David Zeuthen227ef3c2015-09-03 12:23:12 -0400581 /* If an A/B partition, modify block device to be the real block device */
Tom Cherryd0be7a52018-11-29 13:04:52 -0800582 if (!fs_mgr_update_for_slotselect(&fstab)) {
bowgotsai47878de2017-01-23 14:04:34 +0800583 LERROR << "Error updating for slotselect";
Yi-Yo Chiang97f2fdf2021-11-12 19:19:29 +0800584 return false;
David Zeuthen227ef3c2015-09-03 12:23:12 -0400585 }
Yi-Yo Chiang97f2fdf2021-11-12 19:19:29 +0800586
Tom Cherryd0be7a52018-11-29 13:04:52 -0800587 *fstab_out = std::move(fstab);
588 return true;
Bowgo Tsai47d34272017-03-06 22:22:07 +0800589}
590
Yo Chiang165d9ae2020-09-23 19:48:05 +0800591void TransformFstabForDsu(Fstab* fstab, const std::string& dsu_slot,
592 const std::vector<std::string>& dsu_partitions) {
Bowgo Tsaia2ac8462019-12-11 15:03:00 +0800593 static constexpr char kDsuKeysDir[] = "/avb";
Howard Chen1b094932019-09-11 18:22:01 +0800594 // Convert userdata
David Anderson88045ae2019-02-04 19:02:19 -0800595 // Inherit fstab properties for userdata.
596 FstabEntry userdata;
597 if (FstabEntry* entry = GetEntryForMountPoint(fstab, "/data")) {
598 userdata = *entry;
Yo Chiang62c75b12020-10-21 21:43:13 +0800599 userdata.blk_device = android::gsi::kDsuUserdata;
David Anderson88045ae2019-02-04 19:02:19 -0800600 userdata.fs_mgr_flags.logical = true;
601 userdata.fs_mgr_flags.formattable = true;
Paul Crowley7823e322020-01-30 16:03:45 -0800602 if (!userdata.metadata_key_dir.empty()) {
Yo Chiang165d9ae2020-09-23 19:48:05 +0800603 userdata.metadata_key_dir = android::gsi::GetDsuMetadataKeyDir(dsu_slot);
David Anderson88045ae2019-02-04 19:02:19 -0800604 }
605 } else {
Howard Chen1b094932019-09-11 18:22:01 +0800606 userdata = BuildDsuUserdataFstabEntry();
Bowgo Tsai9bbaa7b2019-02-18 17:56:58 +0800607 }
David Anderson88045ae2019-02-04 19:02:19 -0800608
Bowgo Tsai9bbaa7b2019-02-18 17:56:58 +0800609 if (EraseFstabEntry(fstab, "/data")) {
610 fstab->emplace_back(userdata);
611 }
David Anderson0e330f12019-01-03 18:16:56 -0800612
Howard Chen1b094932019-09-11 18:22:01 +0800613 // Convert others
614 for (auto&& partition : dsu_partitions) {
615 if (!EndsWith(partition, gsi::kDsuPostfix)) {
616 continue;
617 }
618 // userdata has been handled
Yo Chiang62c75b12020-10-21 21:43:13 +0800619 if (partition == android::gsi::kDsuUserdata) {
620 continue;
621 }
622 // scratch is handled by fs_mgr_overlayfs
623 if (partition == android::gsi::kDsuScratch) {
Howard Chen1b094932019-09-11 18:22:01 +0800624 continue;
625 }
626 // dsu_partition_name = corresponding_partition_name + kDsuPostfix
627 // e.g.
628 // system_gsi for system
629 // product_gsi for product
630 // vendor_gsi for vendor
631 std::string lp_name = partition.substr(0, partition.length() - strlen(gsi::kDsuPostfix));
632 std::string mount_point = "/" + lp_name;
633 std::vector<FstabEntry*> entries = GetEntriesForMountPoint(fstab, mount_point);
634 if (entries.empty()) {
635 FstabEntry entry = {
636 .blk_device = partition,
Nick Desaulniers8e048442019-10-11 10:52:16 -0700637 // .logical_partition_name is required to look up AVB Hashtree descriptors.
638 .logical_partition_name = "system",
Howard Chen1b094932019-09-11 18:22:01 +0800639 .mount_point = mount_point,
640 .fs_type = "ext4",
641 .flags = MS_RDONLY,
642 .fs_options = "barrier=1",
Bowgo Tsaia2ac8462019-12-11 15:03:00 +0800643 .avb_keys = kDsuKeysDir,
Nick Desaulniers8e048442019-10-11 10:52:16 -0700644 };
Howard Chen1b094932019-09-11 18:22:01 +0800645 entry.fs_mgr_flags.wait = true;
646 entry.fs_mgr_flags.logical = true;
647 entry.fs_mgr_flags.first_stage_mount = true;
Yo Chiange48dbc22020-08-19 14:17:37 +0800648 fstab->emplace_back(entry);
Howard Chen1b094932019-09-11 18:22:01 +0800649 } else {
650 // If the corresponding partition exists, transform all its Fstab
651 // by pointing .blk_device to the DSU partition.
652 for (auto&& entry : entries) {
653 entry->blk_device = partition;
Bowgo Tsaia2ac8462019-12-11 15:03:00 +0800654 // AVB keys for DSU should always be under kDsuKeysDir.
Yo Chiange48dbc22020-08-19 14:17:37 +0800655 entry->avb_keys = kDsuKeysDir;
Tim Zimmermann496132b2022-04-16 22:37:08 +0200656 entry->fs_mgr_flags.logical = true;
Howard Chen1b094932019-09-11 18:22:01 +0800657 }
658 // Make sure the ext4 is included to support GSI.
659 auto partition_ext4 =
660 std::find_if(fstab->begin(), fstab->end(), [&](const auto& entry) {
661 return entry.mount_point == mount_point && entry.fs_type == "ext4";
662 });
663 if (partition_ext4 == fstab->end()) {
664 auto new_entry = *GetEntryForMountPoint(fstab, mount_point);
665 new_entry.fs_type = "ext4";
Yi-Yo Chiang6bcabc02022-02-18 22:54:50 +0800666 auto it = std::find_if(fstab->rbegin(), fstab->rend(),
667 [&mount_point](const auto& entry) {
668 return entry.mount_point == mount_point;
669 });
670 auto end_of_mount_point_group = fstab->begin() + std::distance(it, fstab->rend());
671 fstab->insert(end_of_mount_point_group, new_entry);
Howard Chen1b094932019-09-11 18:22:01 +0800672 }
673 }
674 }
675}
Tom Cherrya3530e62019-01-30 13:25:35 -0800676
Victor Hsieh98296fc2020-02-24 16:02:32 -0800677void EnableMandatoryFlags(Fstab* fstab) {
Jeff Vander Stoepeb749382021-11-22 10:22:09 +0100678 // Devices launched in R and after must support fs_verity. Set flag to cause tune2fs
679 // to enable the feature on userdata and metadata partitions.
Victor Hsieh98296fc2020-02-24 16:02:32 -0800680 if (android::base::GetIntProperty("ro.product.first_api_level", 0) >= 30) {
Jeff Vander Stoepeb749382021-11-22 10:22:09 +0100681 // Devices launched in R and after should enable fs_verity on userdata.
682 // A better alternative would be to enable on mkfs at the beginning.
Victor Hsieh98296fc2020-02-24 16:02:32 -0800683 std::vector<FstabEntry*> data_entries = GetEntriesForMountPoint(fstab, "/data");
684 for (auto&& entry : data_entries) {
685 // Besides ext4, f2fs is also supported. But the image is already created with verity
686 // turned on when it was first introduced.
687 if (entry->fs_type == "ext4") {
688 entry->fs_mgr_flags.fs_verity = true;
689 }
690 }
Jeff Vander Stoepeb749382021-11-22 10:22:09 +0100691 // Devices shipping with S and earlier likely do not already have fs_verity enabled via
692 // mkfs, so enable it here.
693 std::vector<FstabEntry*> metadata_entries = GetEntriesForMountPoint(fstab, "/metadata");
694 for (auto&& entry : metadata_entries) {
695 entry->fs_mgr_flags.fs_verity = true;
696 }
Victor Hsieh98296fc2020-02-24 16:02:32 -0800697 }
698}
699
Yi-Yo Chiang1a3c0502021-03-30 20:28:21 +0800700bool ReadFstabFromFile(const std::string& path, Fstab* fstab_out) {
Yi-Yo Chiang97f2fdf2021-11-12 19:19:29 +0800701 const bool is_proc_mounts = (path == "/proc/mounts");
702
703 std::string fstab_str;
704 if (!android::base::ReadFileToString(path, &fstab_str, /* follow_symlinks = */ true)) {
705 PERROR << __FUNCTION__ << "(): failed to read file: '" << path << "'";
Tom Cherryd0be7a52018-11-29 13:04:52 -0800706 return false;
707 }
708
Yi-Yo Chiang1a3c0502021-03-30 20:28:21 +0800709 Fstab fstab;
Yi-Yo Chiang97f2fdf2021-11-12 19:19:29 +0800710 if (!ParseFstabFromString(fstab_str, is_proc_mounts, &fstab)) {
Tom Cherryd0be7a52018-11-29 13:04:52 -0800711 LERROR << __FUNCTION__ << "(): failed to load fstab from : '" << path << "'";
712 return false;
713 }
Yi-Yo Chiangea4369d2021-03-22 13:45:09 +0800714 if (!is_proc_mounts) {
715 if (!access(android::gsi::kGsiBootedIndicatorFile, F_OK)) {
716 // This is expected to fail if host is android Q, since Q doesn't
717 // support DSU slotting. The DSU "active" indicator file would be
718 // non-existent or empty if DSU is enabled within the guest system.
719 // In that case, just use the default slot name "dsu".
720 std::string dsu_slot;
721 if (!android::gsi::GetActiveDsu(&dsu_slot) && errno != ENOENT) {
722 PERROR << __FUNCTION__ << "(): failed to get active DSU slot";
723 return false;
724 }
725 if (dsu_slot.empty()) {
726 dsu_slot = "dsu";
727 LWARNING << __FUNCTION__ << "(): assuming default DSU slot: " << dsu_slot;
728 }
729 // This file is non-existent on Q vendor.
730 std::string lp_names;
731 if (!ReadFileToString(gsi::kGsiLpNamesFile, &lp_names) && errno != ENOENT) {
732 PERROR << __FUNCTION__ << "(): failed to read DSU LP names";
733 return false;
734 }
Yi-Yo Chiang1a3c0502021-03-30 20:28:21 +0800735 TransformFstabForDsu(&fstab, dsu_slot, Split(lp_names, ","));
Yi-Yo Chiangea4369d2021-03-22 13:45:09 +0800736 } else if (errno != ENOENT) {
737 PERROR << __FUNCTION__ << "(): failed to access() DSU booted indicator";
738 return false;
Yo Chiangcb1d0d92020-11-09 17:45:35 +0800739 }
David Anderson0e330f12019-01-03 18:16:56 -0800740 }
Tom Cherryd0be7a52018-11-29 13:04:52 -0800741
Yi-Yo Chiang1a3c0502021-03-30 20:28:21 +0800742 SkipMountingPartitions(&fstab, false /* verbose */);
743 EnableMandatoryFlags(&fstab);
SzuWei Lin77c28472019-04-22 17:27:52 +0800744
Yi-Yo Chiang1a3c0502021-03-30 20:28:21 +0800745 *fstab_out = std::move(fstab);
Tom Cherryd0be7a52018-11-29 13:04:52 -0800746 return true;
747}
748
Tom Cherryd0be7a52018-11-29 13:04:52 -0800749// Returns fstab entries parsed from the device tree if they exist
Yi-Yo Chiang20579012021-04-01 20:14:54 +0800750bool ReadFstabFromDt(Fstab* fstab, bool verbose) {
Tom Cherrya3530e62019-01-30 13:25:35 -0800751 std::string fstab_buf = ReadFstabFromDt();
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800752 if (fstab_buf.empty()) {
Yi-Yo Chiang20579012021-04-01 20:14:54 +0800753 if (verbose) LINFO << __FUNCTION__ << "(): failed to read fstab from dt";
Tom Cherryd0be7a52018-11-29 13:04:52 -0800754 return false;
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800755 }
756
Yi-Yo Chiang97f2fdf2021-11-12 19:19:29 +0800757 if (!ParseFstabFromString(fstab_buf, /* proc_mounts = */ false, fstab)) {
Yi-Yo Chiang20579012021-04-01 20:14:54 +0800758 if (verbose) {
Mark Salyzynf98d6c42019-01-25 09:08:42 -0800759 LERROR << __FUNCTION__ << "(): failed to load fstab from kernel:" << std::endl
760 << fstab_buf;
761 }
Tom Cherryd0be7a52018-11-29 13:04:52 -0800762 return false;
763 }
764
Yi-Yo Chiang20579012021-04-01 20:14:54 +0800765 SkipMountingPartitions(fstab, verbose);
SzuWei Lin77c28472019-04-22 17:27:52 +0800766
767 return true;
768}
769
Yi-Yo Chiang20579012021-04-01 20:14:54 +0800770#ifdef NO_SKIP_MOUNT
771bool SkipMountingPartitions(Fstab*, bool) {
772 return true;
773}
774#else
Justin Yun7eaf9b52019-06-28 14:28:00 +0900775// For GSI to skip mounting /product and /system_ext, until there are well-defined interfaces
776// between them and /system. Otherwise, the GSI flashed on /system might not be able to work with
Bowgo Tsai79f875f2019-09-04 22:20:01 +0800777// device-specific /product and /system_ext. skip_mount.cfg belongs to system_ext partition because
778// only common files for all targets can be put into system partition. It is under
779// /system/system_ext because GSI is a single system.img that includes the contents of system_ext
780// partition and product partition under /system/system_ext and /system/product, respectively.
Yi-Yo Chiang20579012021-04-01 20:14:54 +0800781bool SkipMountingPartitions(Fstab* fstab, bool verbose) {
782 static constexpr char kSkipMountConfig[] = "/system/system_ext/etc/init/config/skip_mount.cfg";
SzuWei Lin77c28472019-04-22 17:27:52 +0800783
784 std::string skip_config;
Mark Salyzyn98a01282019-05-13 09:14:55 -0700785 auto save_errno = errno;
SzuWei Lin77c28472019-04-22 17:27:52 +0800786 if (!ReadFileToString(kSkipMountConfig, &skip_config)) {
Mark Salyzyn98a01282019-05-13 09:14:55 -0700787 errno = save_errno; // missing file is expected
SzuWei Lin77c28472019-04-22 17:27:52 +0800788 return true;
789 }
790
Yi-Yo Chiang2f2fe4a2021-03-31 20:39:22 +0800791 std::vector<std::string> skip_mount_patterns;
792 for (const auto& line : Split(skip_config, "\n")) {
793 if (line.empty() || StartsWith(line, "#")) {
SzuWei Lin77c28472019-04-22 17:27:52 +0800794 continue;
795 }
Yi-Yo Chiang2f2fe4a2021-03-31 20:39:22 +0800796 skip_mount_patterns.push_back(line);
SzuWei Lin77c28472019-04-22 17:27:52 +0800797 }
798
Yi-Yo Chiang2f2fe4a2021-03-31 20:39:22 +0800799 // Returns false if mount_point matches any of the skip mount patterns, so that the FstabEntry
800 // would be partitioned to the second group.
801 auto glob_pattern_mismatch = [&skip_mount_patterns](const FstabEntry& entry) -> bool {
802 for (const auto& pattern : skip_mount_patterns) {
803 if (!fnmatch(pattern.c_str(), entry.mount_point.c_str(), 0 /* flags */)) {
804 return false;
805 }
806 }
807 return true;
808 };
809 auto remove_from = std::stable_partition(fstab->begin(), fstab->end(), glob_pattern_mismatch);
810 if (verbose) {
811 for (auto it = remove_from; it != fstab->end(); ++it) {
812 LINFO << "Skip mounting mountpoint: " << it->mount_point;
813 }
814 }
815 fstab->erase(remove_from, fstab->end());
Tom Cherryd0be7a52018-11-29 13:04:52 -0800816 return true;
817}
Hung-ying Tyane7cb09d2020-07-03 14:26:59 +0800818#endif
Tom Cherryd0be7a52018-11-29 13:04:52 -0800819
Tom Cherryd0be7a52018-11-29 13:04:52 -0800820// Loads the fstab file and combines with fstab entries passed in from device tree.
821bool ReadDefaultFstab(Fstab* fstab) {
Yi-Yo Chiang1a3c0502021-03-30 20:28:21 +0800822 fstab->clear();
823 ReadFstabFromDt(fstab, false /* verbose */);
Tom Cherryd0be7a52018-11-29 13:04:52 -0800824
825 std::string default_fstab_path;
Bowgo Tsaid05a2f72017-03-28 01:28:29 +0800826 // Use different fstab paths for normal boot and recovery boot, respectively
Jerry Zhang5de2be52018-07-03 16:03:28 -0700827 if (access("/system/bin/recovery", F_OK) == 0) {
Tom Cherryd0be7a52018-11-29 13:04:52 -0800828 default_fstab_path = "/etc/recovery.fstab";
Oleg Matcovschi018d7f62017-10-30 19:26:32 -0700829 } else { // normal boot
Tom Cherrya3530e62019-01-30 13:25:35 -0800830 default_fstab_path = GetFstabPath();
Oleg Matcovschi018d7f62017-10-30 19:26:32 -0700831 }
832
Tom Cherryd0be7a52018-11-29 13:04:52 -0800833 Fstab default_fstab;
Yi-Yo Chiangea4369d2021-03-22 13:45:09 +0800834 if (!default_fstab_path.empty() && ReadFstabFromFile(default_fstab_path, &default_fstab)) {
835 for (auto&& entry : default_fstab) {
836 fstab->emplace_back(std::move(entry));
837 }
Chris Morinb183e052018-01-04 17:59:45 -0800838 } else {
839 LINFO << __FUNCTION__ << "(): failed to find device default fstab";
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800840 }
841
Tom Cherryd0be7a52018-11-29 13:04:52 -0800842 return !fstab->empty();
843}
844
Tom Cherrya3530e62019-01-30 13:25:35 -0800845FstabEntry* GetEntryForMountPoint(Fstab* fstab, const std::string& path) {
846 if (fstab == nullptr) {
847 return nullptr;
848 }
849
850 for (auto& entry : *fstab) {
851 if (entry.mount_point == path) {
852 return &entry;
853 }
854 }
855
856 return nullptr;
857}
858
Howard Chen1b094932019-09-11 18:22:01 +0800859std::vector<FstabEntry*> GetEntriesForMountPoint(Fstab* fstab, const std::string& path) {
860 std::vector<FstabEntry*> entries;
861 if (fstab == nullptr) {
862 return entries;
863 }
864
865 for (auto& entry : *fstab) {
866 if (entry.mount_point == path) {
867 entries.emplace_back(&entry);
868 }
869 }
870
871 return entries;
872}
873
Tom Cherrya3530e62019-01-30 13:25:35 -0800874std::set<std::string> GetBootDevices() {
Devin Moore20b74252021-03-04 08:23:31 -0800875 // First check bootconfig, then kernel commandline, then the device tree
Tom Cherrya3530e62019-01-30 13:25:35 -0800876 std::string dt_file_name = get_android_dt_dir() + "/boot_devices";
877 std::string value;
Devin Moore20b74252021-03-04 08:23:31 -0800878 if (fs_mgr_get_boot_config_from_bootconfig_source("boot_devices", &value) ||
879 fs_mgr_get_boot_config_from_bootconfig_source("boot_device", &value)) {
880 std::set<std::string> boot_devices;
881 // remove quotes and split by spaces
882 auto boot_device_strings = base::Split(base::StringReplace(value, "\"", "", true), " ");
883 for (std::string_view device : boot_device_strings) {
884 // trim the trailing comma, keep the rest.
885 base::ConsumeSuffix(&device, ",");
886 boot_devices.emplace(device);
887 }
888 return boot_devices;
889 }
890
Tom Cherrya3530e62019-01-30 13:25:35 -0800891 if (fs_mgr_get_boot_config_from_kernel_cmdline("boot_devices", &value) ||
892 ReadDtFile(dt_file_name, &value)) {
893 auto boot_devices = Split(value, ",");
894 return std::set<std::string>(boot_devices.begin(), boot_devices.end());
895 }
896
David Andersonfabc3642020-04-01 19:46:42 -0700897 std::string cmdline;
898 if (android::base::ReadFileToString("/proc/cmdline", &cmdline)) {
899 std::set<std::string> boot_devices;
900 const std::string cmdline_key = "androidboot.boot_device";
Devin Moorea4ef15b2020-12-15 16:14:37 -0800901 for (const auto& [key, value] : fs_mgr_parse_cmdline(cmdline)) {
David Andersonfabc3642020-04-01 19:46:42 -0700902 if (key == cmdline_key) {
903 boot_devices.emplace(value);
904 }
905 }
906 if (!boot_devices.empty()) {
907 return boot_devices;
908 }
909 }
910
Tom Cherrya3530e62019-01-30 13:25:35 -0800911 // Fallback to extract boot devices from fstab.
912 Fstab fstab;
913 if (!ReadDefaultFstab(&fstab)) {
914 return {};
915 }
916
917 return ExtraBootDevices(fstab);
918}
919
David Anderson7082f682019-03-18 19:17:11 -0700920std::string GetVerityDeviceName(const FstabEntry& entry) {
921 std::string base_device;
922 if (entry.mount_point == "/") {
David Anderson9655c7b2019-05-09 17:55:18 -0700923 // When using system-as-root, the device name is fixed as "vroot".
924 if (entry.fs_mgr_flags.avb) {
925 return "vroot";
926 }
927 base_device = "system";
David Anderson7082f682019-03-18 19:17:11 -0700928 } else {
929 base_device = android::base::Basename(entry.mount_point);
930 }
931 return base_device + "-verity";
932}
933
Tom Cherrya3530e62019-01-30 13:25:35 -0800934} // namespace fs_mgr
935} // namespace android
936
937// FIXME: The same logic is duplicated in system/core/init/
938const std::string& get_android_dt_dir() {
939 // Set once and saves time for subsequent calls to this function
940 static const std::string kAndroidDtDir = android::fs_mgr::InitAndroidDtDir();
941 return kAndroidDtDir;
942}
943
944bool is_dt_compatible() {
945 std::string file_name = get_android_dt_dir() + "/compatible";
946 std::string dt_value;
947 if (android::fs_mgr::ReadDtFile(file_name, &dt_value)) {
948 if (dt_value == "android,firmware") {
949 return true;
950 }
951 }
952
953 return false;
954}