blob: 92c6ee8c04ee8725c72b51949181add477c177e2 [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>
Colin Cross5edee2a2014-01-23 14:22:48 -080020#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <sys/mount.h>
Iliyan Malchev3ea902f2015-05-01 14:05:04 -070024#include <unistd.h>
Colin Cross5edee2a2014-01-23 14:22:48 -080025
Sandeep Patilc20c0c22017-02-23 16:09:34 -080026#include <android-base/file.h>
27#include <android-base/stringprintf.h>
28#include <android-base/strings.h>
29
Colin Cross5edee2a2014-01-23 14:22:48 -080030#include "fs_mgr_priv.h"
31
Yu Ningc01022a2017-07-26 17:54:08 +080032const std::string kDefaultAndroidDtDir("/proc/device-tree/firmware/android");
33
Colin Cross5edee2a2014-01-23 14:22:48 -080034struct fs_mgr_flag_values {
35 char *key_loc;
Paul Lawrence9dbe97b2017-04-21 12:41:48 -070036 char* key_dir;
Sami Tolvanen946a0f32015-03-22 12:40:05 +000037 char *verity_loc;
Colin Cross5edee2a2014-01-23 14:22:48 -080038 long long part_length;
39 char *label;
40 int partnum;
41 int swap_prio;
Peter Enderborg4d217f02016-08-26 15:09:35 +020042 int max_comp_streams;
Colin Cross5edee2a2014-01-23 14:22:48 -080043 unsigned int zram_size;
liminghao9a0fd1d2016-07-22 11:48:14 +080044 uint64_t reserved_size;
Eric Biggersb478f702017-02-02 14:46:24 -080045 unsigned int file_contents_mode;
46 unsigned int file_names_mode;
Connor O'Brien46fec482017-01-24 17:50:39 -080047 unsigned int erase_blk_size;
48 unsigned int logical_blk_size;
Colin Cross5edee2a2014-01-23 14:22:48 -080049};
50
51struct flag_list {
52 const char *name;
Paul Lawrence4e898a02016-05-24 04:56:37 -070053 unsigned int flag;
Colin Cross5edee2a2014-01-23 14:22:48 -080054};
55
56static struct flag_list mount_flags[] = {
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 { "remount", MS_REMOUNT },
65 { "bind", MS_BIND },
66 { "rec", MS_REC },
67 { "unbindable", MS_UNBINDABLE },
68 { "private", MS_PRIVATE },
69 { "slave", MS_SLAVE },
70 { "shared", MS_SHARED },
71 { "defaults", 0 },
72 { 0, 0 },
73};
74
75static struct flag_list fs_mgr_flags[] = {
Paul Lawrence9dbe97b2017-04-21 12:41:48 -070076 {"wait", MF_WAIT},
77 {"check", MF_CHECK},
78 {"encryptable=", MF_CRYPT},
79 {"forceencrypt=", MF_FORCECRYPT},
80 {"fileencryption=", MF_FILEENCRYPTION},
81 {"forcefdeorfbe=", MF_FORCEFDEORFBE},
82 {"keydirectory=", MF_KEYDIRECTORY},
83 {"nonremovable", MF_NONREMOVABLE},
84 {"voldmanaged=", MF_VOLDMANAGED},
85 {"length=", MF_LENGTH},
86 {"recoveryonly", MF_RECOVERYONLY},
87 {"swapprio=", MF_SWAPPRIO},
88 {"zramsize=", MF_ZRAMSIZE},
89 {"max_comp_streams=", MF_MAX_COMP_STREAMS},
90 {"verifyatboot", MF_VERIFYATBOOT},
91 {"verify", MF_VERIFY},
92 {"avb", MF_AVB},
93 {"noemulatedsd", MF_NOEMULATEDSD},
94 {"notrim", MF_NOTRIM},
95 {"formattable", MF_FORMATTABLE},
96 {"slotselect", MF_SLOTSELECT},
97 {"nofail", MF_NOFAIL},
98 {"latemount", MF_LATEMOUNT},
99 {"reservedsize=", MF_RESERVEDSIZE},
100 {"quota", MF_QUOTA},
101 {"eraseblk=", MF_ERASEBLKSIZE},
102 {"logicalblk=", MF_LOGICALBLKSIZE},
103 {"defaults", 0},
104 {0, 0},
Colin Cross5edee2a2014-01-23 14:22:48 -0800105};
106
Eric Biggersb478f702017-02-02 14:46:24 -0800107#define EM_AES_256_XTS 1
108#define EM_ICE 2
109#define EM_AES_256_CTS 3
110#define EM_AES_256_HEH 4
Paul Lawrence4e898a02016-05-24 04:56:37 -0700111
Eric Biggersb478f702017-02-02 14:46:24 -0800112static const struct flag_list file_contents_encryption_modes[] = {
113 {"aes-256-xts", EM_AES_256_XTS},
114 {"software", EM_AES_256_XTS}, /* alias for backwards compatibility */
115 {"ice", EM_ICE}, /* hardware-specific inline cryptographic engine */
116 {0, 0},
Paul Lawrence5b8a1082016-05-05 11:00:44 -0700117};
118
Eric Biggersb478f702017-02-02 14:46:24 -0800119static const struct flag_list file_names_encryption_modes[] = {
120 {"aes-256-cts", EM_AES_256_CTS},
121 {"aes-256-heh", EM_AES_256_HEH},
122 {0, 0},
123};
124
125static unsigned int encryption_mode_to_flag(const struct flag_list *list,
126 const char *mode, const char *type)
127{
128 const struct flag_list *j;
129
130 for (j = list; j->name; ++j) {
131 if (!strcmp(mode, j->name)) {
132 return j->flag;
133 }
134 }
135 LERROR << "Unknown " << type << " encryption mode: " << mode;
136 return 0;
137}
138
139static const char *flag_to_encryption_mode(const struct flag_list *list,
140 unsigned int flag)
141{
142 const struct flag_list *j;
143
144 for (j = list; j->name; ++j) {
145 if (flag == j->flag) {
146 return j->name;
147 }
148 }
149 return nullptr;
150}
151
Iliyan Malchev3ea902f2015-05-01 14:05:04 -0700152static uint64_t calculate_zram_size(unsigned int percentage)
153{
154 uint64_t total;
155
156 total = sysconf(_SC_PHYS_PAGES);
157 total *= percentage;
158 total /= 100;
159
160 total *= sysconf(_SC_PAGESIZE);
161
162 return total;
163}
164
liminghao9a0fd1d2016-07-22 11:48:14 +0800165static uint64_t parse_size(const char *arg)
166{
167 char *endptr;
168 uint64_t size = strtoull(arg, &endptr, 10);
169 if (*endptr == 'k' || *endptr == 'K')
170 size *= 1024LL;
171 else if (*endptr == 'm' || *endptr == 'M')
172 size *= 1024LL * 1024LL;
173 else if (*endptr == 'g' || *endptr == 'G')
174 size *= 1024LL * 1024LL * 1024LL;
175
176 return size;
177}
178
Sandeep Patil4cd9a462017-02-24 13:03:39 -0800179/* fills 'dt_value' with the underlying device tree value string without
180 * the trailing '\0'. Returns true if 'dt_value' has a valid string, 'false'
181 * otherwise.
182 */
183static bool read_dt_file(const std::string& file_name, std::string* dt_value)
184{
185 if (android::base::ReadFileToString(file_name, dt_value)) {
186 if (!dt_value->empty()) {
187 // trim the trailing '\0' out, otherwise the comparison
188 // will produce false-negatives.
189 dt_value->resize(dt_value->size() - 1);
190 return true;
191 }
192 }
193
194 return false;
195}
196
Colin Cross5edee2a2014-01-23 14:22:48 -0800197static int parse_flags(char *flags, struct flag_list *fl,
198 struct fs_mgr_flag_values *flag_vals,
199 char *fs_options, int fs_options_len)
200{
201 int f = 0;
202 int i;
203 char *p;
204 char *savep;
205
206 /* initialize flag values. If we find a relevant flag, we'll
207 * update the value */
208 if (flag_vals) {
209 memset(flag_vals, 0, sizeof(*flag_vals));
210 flag_vals->partnum = -1;
211 flag_vals->swap_prio = -1; /* negative means it wasn't specified. */
212 }
213
214 /* initialize fs_options to the null string */
215 if (fs_options && (fs_options_len > 0)) {
216 fs_options[0] = '\0';
217 }
218
219 p = strtok_r(flags, ",", &savep);
220 while (p) {
221 /* Look for the flag "p" in the flag list "fl"
222 * If not found, the loop exits with fl[i].name being null.
223 */
224 for (i = 0; fl[i].name; i++) {
225 if (!strncmp(p, fl[i].name, strlen(fl[i].name))) {
226 f |= fl[i].flag;
227 if ((fl[i].flag == MF_CRYPT) && flag_vals) {
228 /* The encryptable flag is followed by an = and the
229 * location of the keys. Get it and return it.
230 */
231 flag_vals->key_loc = strdup(strchr(p, '=') + 1);
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000232 } else if ((fl[i].flag == MF_VERIFY) && flag_vals) {
233 /* If the verify flag is followed by an = and the
234 * location for the verity state, get it and return it.
235 */
236 char *start = strchr(p, '=');
237 if (start) {
238 flag_vals->verity_loc = strdup(start + 1);
239 }
Paul Lawrence2e5ae0a2014-04-04 09:34:19 -0700240 } else if ((fl[i].flag == MF_FORCECRYPT) && flag_vals) {
241 /* The forceencrypt flag is followed by an = and the
242 * location of the keys. Get it and return it.
243 */
244 flag_vals->key_loc = strdup(strchr(p, '=') + 1);
Paul Lawrenceb262d682015-10-29 10:31:02 -0700245 } else if ((fl[i].flag == MF_FORCEFDEORFBE) && flag_vals) {
246 /* The forcefdeorfbe flag is followed by an = and the
247 * location of the keys. Get it and return it.
248 */
249 flag_vals->key_loc = strdup(strchr(p, '=') + 1);
Eric Biggersb478f702017-02-02 14:46:24 -0800250 flag_vals->file_contents_mode = EM_AES_256_XTS;
251 flag_vals->file_names_mode = EM_AES_256_CTS;
Paul Lawrence5b8a1082016-05-05 11:00:44 -0700252 } else if ((fl[i].flag == MF_FILEENCRYPTION) && flag_vals) {
Eric Biggersb478f702017-02-02 14:46:24 -0800253 /* The fileencryption flag is followed by an = and
254 * the mode of contents encryption, then optionally a
255 * : and the mode of filenames encryption (defaults
256 * to aes-256-cts). Get it and return it.
Paul Lawrence5b8a1082016-05-05 11:00:44 -0700257 */
Eric Biggersb478f702017-02-02 14:46:24 -0800258 char *mode = strchr(p, '=') + 1;
259 char *colon = strchr(mode, ':');
260 if (colon) {
261 *colon = '\0';
Paul Lawrence5b8a1082016-05-05 11:00:44 -0700262 }
Eric Biggersb478f702017-02-02 14:46:24 -0800263 flag_vals->file_contents_mode =
264 encryption_mode_to_flag(file_contents_encryption_modes,
265 mode, "file contents");
266 if (colon) {
267 flag_vals->file_names_mode =
268 encryption_mode_to_flag(file_names_encryption_modes,
269 colon + 1, "file names");
270 } else {
271 flag_vals->file_names_mode = EM_AES_256_CTS;
Paul Lawrence5b8a1082016-05-05 11:00:44 -0700272 }
Paul Lawrence9dbe97b2017-04-21 12:41:48 -0700273 } else if ((fl[i].flag == MF_KEYDIRECTORY) && flag_vals) {
274 /* The metadata flag is followed by an = and the
275 * directory for the keys. Get it and return it.
276 */
277 flag_vals->key_dir = strdup(strchr(p, '=') + 1);
Colin Cross5edee2a2014-01-23 14:22:48 -0800278 } else if ((fl[i].flag == MF_LENGTH) && flag_vals) {
279 /* The length flag is followed by an = and the
280 * size of the partition. Get it and return it.
281 */
282 flag_vals->part_length = strtoll(strchr(p, '=') + 1, NULL, 0);
283 } else if ((fl[i].flag == MF_VOLDMANAGED) && flag_vals) {
284 /* The voldmanaged flag is followed by an = and the
285 * label, a colon and the partition number or the
286 * word "auto", e.g.
287 * voldmanaged=sdcard:3
288 * Get and return them.
289 */
290 char *label_start;
291 char *label_end;
292 char *part_start;
293
294 label_start = strchr(p, '=') + 1;
295 label_end = strchr(p, ':');
296 if (label_end) {
297 flag_vals->label = strndup(label_start,
298 (int) (label_end - label_start));
299 part_start = strchr(p, ':') + 1;
300 if (!strcmp(part_start, "auto")) {
301 flag_vals->partnum = -1;
302 } else {
303 flag_vals->partnum = strtol(part_start, NULL, 0);
304 }
305 } else {
bowgotsai47878de2017-01-23 14:04:34 +0800306 LERROR << "Warning: voldmanaged= flag malformed";
Colin Cross5edee2a2014-01-23 14:22:48 -0800307 }
308 } else if ((fl[i].flag == MF_SWAPPRIO) && flag_vals) {
309 flag_vals->swap_prio = strtoll(strchr(p, '=') + 1, NULL, 0);
Peter Enderborg4d217f02016-08-26 15:09:35 +0200310 } else if ((fl[i].flag == MF_MAX_COMP_STREAMS) && flag_vals) {
311 flag_vals->max_comp_streams = strtoll(strchr(p, '=') + 1, NULL, 0);
Colin Cross5edee2a2014-01-23 14:22:48 -0800312 } else if ((fl[i].flag == MF_ZRAMSIZE) && flag_vals) {
Iliyan Malchev3ea902f2015-05-01 14:05:04 -0700313 int is_percent = !!strrchr(p, '%');
314 unsigned int val = strtoll(strchr(p, '=') + 1, NULL, 0);
315 if (is_percent)
316 flag_vals->zram_size = calculate_zram_size(val);
317 else
318 flag_vals->zram_size = val;
liminghao9a0fd1d2016-07-22 11:48:14 +0800319 } else if ((fl[i].flag == MF_RESERVEDSIZE) && flag_vals) {
320 /* The reserved flag is followed by an = and the
321 * reserved size of the partition. Get it and return it.
322 */
323 flag_vals->reserved_size = parse_size(strchr(p, '=') + 1);
Connor O'Brien46fec482017-01-24 17:50:39 -0800324 } else if ((fl[i].flag == MF_ERASEBLKSIZE) && flag_vals) {
325 /* The erase block size flag is followed by an = and the flash
326 * erase block size. Get it, check that it is a power of 2 and
327 * at least 4096, and return it.
328 */
329 unsigned int val = strtoul(strchr(p, '=') + 1, NULL, 0);
330 if (val >= 4096 && (val & (val - 1)) == 0)
331 flag_vals->erase_blk_size = val;
332 } else if ((fl[i].flag == MF_LOGICALBLKSIZE) && flag_vals) {
333 /* The logical block size flag is followed by an = and the flash
334 * logical block size. Get it, check that it is a power of 2 and
335 * at least 4096, and return it.
336 */
337 unsigned int val = strtoul(strchr(p, '=') + 1, NULL, 0);
338 if (val >= 4096 && (val & (val - 1)) == 0)
339 flag_vals->logical_blk_size = val;
Colin Cross5edee2a2014-01-23 14:22:48 -0800340 }
341 break;
342 }
343 }
344
345 if (!fl[i].name) {
346 if (fs_options) {
347 /* It's not a known flag, so it must be a filesystem specific
348 * option. Add it to fs_options if it was passed in.
349 */
350 strlcat(fs_options, p, fs_options_len);
351 strlcat(fs_options, ",", fs_options_len);
352 } else {
353 /* fs_options was not passed in, so if the flag is unknown
354 * it's an error.
355 */
bowgotsai47878de2017-01-23 14:04:34 +0800356 LERROR << "Warning: unknown flag " << p;
Colin Cross5edee2a2014-01-23 14:22:48 -0800357 }
358 }
359 p = strtok_r(NULL, ",", &savep);
360 }
361
Colin Cross5edee2a2014-01-23 14:22:48 -0800362 if (fs_options && fs_options[0]) {
363 /* remove the last trailing comma from the list of options */
364 fs_options[strlen(fs_options) - 1] = '\0';
365 }
366
367 return f;
368}
369
Yu Ningc01022a2017-07-26 17:54:08 +0800370static std::string init_android_dt_dir() {
371 std::string android_dt_dir;
372 // The platform may specify a custom Android DT path in kernel cmdline
373 if (!fs_mgr_get_boot_config_from_kernel_cmdline("android_dt_dir", &android_dt_dir)) {
374 // Fall back to the standard procfs-based path
375 android_dt_dir = kDefaultAndroidDtDir;
376 }
377 return android_dt_dir;
378}
379
380// FIXME: The same logic is duplicated in system/core/init/
381const std::string& get_android_dt_dir() {
382 // Set once and saves time for subsequent calls to this function
383 static const std::string kAndroidDtDir = init_android_dt_dir();
384 return kAndroidDtDir;
385}
386
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800387static bool is_dt_fstab_compatible() {
388 std::string dt_value;
Yu Ningc01022a2017-07-26 17:54:08 +0800389 std::string file_name = get_android_dt_dir() + "/fstab/compatible";
Sandeep Patil4cd9a462017-02-24 13:03:39 -0800390 if (read_dt_file(file_name, &dt_value)) {
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800391 if (dt_value == "android,fstab") {
392 return true;
393 }
394 }
395
396 return false;
397}
398
399static std::string read_fstab_from_dt() {
400 std::string fstab;
401 if (!is_dt_compatible() || !is_dt_fstab_compatible()) {
402 return fstab;
403 }
404
Yu Ningc01022a2017-07-26 17:54:08 +0800405 std::string fstabdir_name = get_android_dt_dir() + "/fstab";
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800406 std::unique_ptr<DIR, int (*)(DIR*)> fstabdir(opendir(fstabdir_name.c_str()), closedir);
407 if (!fstabdir) return fstab;
408
409 dirent* dp;
410 while ((dp = readdir(fstabdir.get())) != NULL) {
Bowgo Tsai06ed6132017-06-08 10:43:41 +0800411 // skip over name, compatible and .
412 if (dp->d_type != DT_DIR || dp->d_name[0] == '.') continue;
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800413
414 // create <dev> <mnt_point> <type> <mnt_flags> <fsmgr_flags>\n
415 std::vector<std::string> fstab_entry;
416 std::string file_name;
417 std::string value;
Sandeep Patilbe4302b2017-05-26 18:09:06 -0700418 // skip a partition entry if the status property is present and not set to ok
419 file_name = android::base::StringPrintf("%s/%s/status", fstabdir_name.c_str(), dp->d_name);
420 if (read_dt_file(file_name, &value)) {
421 if (value != "okay" && value != "ok") {
422 LINFO << "dt_fstab: Skip disabled entry for partition " << dp->d_name;
423 continue;
424 }
425 }
426
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800427 file_name = android::base::StringPrintf("%s/%s/dev", fstabdir_name.c_str(), dp->d_name);
Sandeep Patil4cd9a462017-02-24 13:03:39 -0800428 if (!read_dt_file(file_name, &value)) {
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800429 LERROR << "dt_fstab: Failed to find device for partition " << dp->d_name;
430 fstab.clear();
431 break;
432 }
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800433 fstab_entry.push_back(value);
434 fstab_entry.push_back(android::base::StringPrintf("/%s", dp->d_name));
435
436 file_name = android::base::StringPrintf("%s/%s/type", fstabdir_name.c_str(), dp->d_name);
Sandeep Patil4cd9a462017-02-24 13:03:39 -0800437 if (!read_dt_file(file_name, &value)) {
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800438 LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
439 fstab.clear();
440 break;
441 }
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800442 fstab_entry.push_back(value);
443
444 file_name = android::base::StringPrintf("%s/%s/mnt_flags", fstabdir_name.c_str(), dp->d_name);
Sandeep Patil4cd9a462017-02-24 13:03:39 -0800445 if (!read_dt_file(file_name, &value)) {
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800446 LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
447 fstab.clear();
448 break;
449 }
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800450 fstab_entry.push_back(value);
451
452 file_name = android::base::StringPrintf("%s/%s/fsmgr_flags", fstabdir_name.c_str(), dp->d_name);
Sandeep Patil4cd9a462017-02-24 13:03:39 -0800453 if (!read_dt_file(file_name, &value)) {
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800454 LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
455 fstab.clear();
456 break;
457 }
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800458 fstab_entry.push_back(value);
459
460 fstab += android::base::Join(fstab_entry, " ");
461 fstab += '\n';
462 }
463
464 return fstab;
465}
466
Sandeep Patile396c602017-02-24 11:04:49 -0800467bool is_dt_compatible() {
Yu Ningc01022a2017-07-26 17:54:08 +0800468 std::string file_name = get_android_dt_dir() + "/compatible";
Sandeep Patile396c602017-02-24 11:04:49 -0800469 std::string dt_value;
Sandeep Patil4cd9a462017-02-24 13:03:39 -0800470 if (read_dt_file(file_name, &dt_value)) {
471 if (dt_value == "android,firmware") {
472 return true;
Sandeep Patile396c602017-02-24 11:04:49 -0800473 }
474 }
475
476 return false;
477}
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800478
Bowgo Tsai47d34272017-03-06 22:22:07 +0800479static struct fstab *fs_mgr_read_fstab_file(FILE *fstab_file)
Colin Cross5edee2a2014-01-23 14:22:48 -0800480{
Colin Cross5edee2a2014-01-23 14:22:48 -0800481 int cnt, entries;
482 ssize_t len;
483 size_t alloc_len = 0;
484 char *line = NULL;
485 const char *delim = " \t";
486 char *save_ptr, *p;
487 struct fstab *fstab = NULL;
Colin Cross5edee2a2014-01-23 14:22:48 -0800488 struct fs_mgr_flag_values flag_vals;
489#define FS_OPTIONS_LEN 1024
490 char tmp_fs_options[FS_OPTIONS_LEN];
491
Colin Cross5edee2a2014-01-23 14:22:48 -0800492 entries = 0;
493 while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
494 /* if the last character is a newline, shorten the string by 1 byte */
495 if (line[len - 1] == '\n') {
496 line[len - 1] = '\0';
497 }
498 /* Skip any leading whitespace */
499 p = line;
500 while (isspace(*p)) {
501 p++;
502 }
503 /* ignore comments or empty lines */
504 if (*p == '#' || *p == '\0')
505 continue;
506 entries++;
507 }
508
509 if (!entries) {
bowgotsai47878de2017-01-23 14:04:34 +0800510 LERROR << "No entries found in fstab";
Colin Cross5edee2a2014-01-23 14:22:48 -0800511 goto err;
512 }
513
514 /* Allocate and init the fstab structure */
bowgotsaicea7ea72017-01-16 21:49:49 +0800515 fstab = static_cast<struct fstab *>(calloc(1, sizeof(struct fstab)));
Colin Cross5edee2a2014-01-23 14:22:48 -0800516 fstab->num_entries = entries;
bowgotsaicea7ea72017-01-16 21:49:49 +0800517 fstab->recs = static_cast<struct fstab_rec *>(
518 calloc(fstab->num_entries, sizeof(struct fstab_rec)));
Colin Cross5edee2a2014-01-23 14:22:48 -0800519
520 fseek(fstab_file, 0, SEEK_SET);
521
522 cnt = 0;
523 while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
524 /* if the last character is a newline, shorten the string by 1 byte */
525 if (line[len - 1] == '\n') {
526 line[len - 1] = '\0';
527 }
528
529 /* Skip any leading whitespace */
530 p = line;
531 while (isspace(*p)) {
532 p++;
533 }
534 /* ignore comments or empty lines */
535 if (*p == '#' || *p == '\0')
536 continue;
537
538 /* If a non-comment entry is greater than the size we allocated, give an
539 * error and quit. This can happen in the unlikely case the file changes
540 * between the two reads.
541 */
542 if (cnt >= entries) {
bowgotsai47878de2017-01-23 14:04:34 +0800543 LERROR << "Tried to process more entries than counted";
Colin Cross5edee2a2014-01-23 14:22:48 -0800544 break;
545 }
546
547 if (!(p = strtok_r(line, delim, &save_ptr))) {
bowgotsai47878de2017-01-23 14:04:34 +0800548 LERROR << "Error parsing mount source";
Colin Cross5edee2a2014-01-23 14:22:48 -0800549 goto err;
550 }
551 fstab->recs[cnt].blk_device = strdup(p);
552
553 if (!(p = strtok_r(NULL, delim, &save_ptr))) {
bowgotsai47878de2017-01-23 14:04:34 +0800554 LERROR << "Error parsing mount_point";
Colin Cross5edee2a2014-01-23 14:22:48 -0800555 goto err;
556 }
557 fstab->recs[cnt].mount_point = strdup(p);
558
559 if (!(p = strtok_r(NULL, delim, &save_ptr))) {
bowgotsai47878de2017-01-23 14:04:34 +0800560 LERROR << "Error parsing fs_type";
Colin Cross5edee2a2014-01-23 14:22:48 -0800561 goto err;
562 }
563 fstab->recs[cnt].fs_type = strdup(p);
564
565 if (!(p = strtok_r(NULL, delim, &save_ptr))) {
bowgotsai47878de2017-01-23 14:04:34 +0800566 LERROR << "Error parsing mount_flags";
Colin Cross5edee2a2014-01-23 14:22:48 -0800567 goto err;
568 }
569 tmp_fs_options[0] = '\0';
570 fstab->recs[cnt].flags = parse_flags(p, mount_flags, NULL,
571 tmp_fs_options, FS_OPTIONS_LEN);
572
573 /* fs_options are optional */
574 if (tmp_fs_options[0]) {
575 fstab->recs[cnt].fs_options = strdup(tmp_fs_options);
576 } else {
577 fstab->recs[cnt].fs_options = NULL;
578 }
579
580 if (!(p = strtok_r(NULL, delim, &save_ptr))) {
bowgotsai47878de2017-01-23 14:04:34 +0800581 LERROR << "Error parsing fs_mgr_options";
Colin Cross5edee2a2014-01-23 14:22:48 -0800582 goto err;
583 }
584 fstab->recs[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags,
585 &flag_vals, NULL, 0);
586 fstab->recs[cnt].key_loc = flag_vals.key_loc;
Paul Lawrence9dbe97b2017-04-21 12:41:48 -0700587 fstab->recs[cnt].key_dir = flag_vals.key_dir;
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000588 fstab->recs[cnt].verity_loc = flag_vals.verity_loc;
Colin Cross5edee2a2014-01-23 14:22:48 -0800589 fstab->recs[cnt].length = flag_vals.part_length;
590 fstab->recs[cnt].label = flag_vals.label;
591 fstab->recs[cnt].partnum = flag_vals.partnum;
592 fstab->recs[cnt].swap_prio = flag_vals.swap_prio;
Peter Enderborg4d217f02016-08-26 15:09:35 +0200593 fstab->recs[cnt].max_comp_streams = flag_vals.max_comp_streams;
Colin Cross5edee2a2014-01-23 14:22:48 -0800594 fstab->recs[cnt].zram_size = flag_vals.zram_size;
liminghao9a0fd1d2016-07-22 11:48:14 +0800595 fstab->recs[cnt].reserved_size = flag_vals.reserved_size;
Eric Biggersb478f702017-02-02 14:46:24 -0800596 fstab->recs[cnt].file_contents_mode = flag_vals.file_contents_mode;
597 fstab->recs[cnt].file_names_mode = flag_vals.file_names_mode;
Connor O'Brien46fec482017-01-24 17:50:39 -0800598 fstab->recs[cnt].erase_blk_size = flag_vals.erase_blk_size;
599 fstab->recs[cnt].logical_blk_size = flag_vals.logical_blk_size;
Colin Cross5edee2a2014-01-23 14:22:48 -0800600 cnt++;
601 }
David Zeuthen227ef3c2015-09-03 12:23:12 -0400602 /* If an A/B partition, modify block device to be the real block device */
Bowgo Tsai87d08362017-04-05 00:02:33 +0800603 if (!fs_mgr_update_for_slotselect(fstab)) {
bowgotsai47878de2017-01-23 14:04:34 +0800604 LERROR << "Error updating for slotselect";
David Zeuthen744a8f82015-09-09 18:03:13 -0400605 goto err;
David Zeuthen227ef3c2015-09-03 12:23:12 -0400606 }
Colin Cross5edee2a2014-01-23 14:22:48 -0800607 free(line);
608 return fstab;
609
610err:
Colin Cross5edee2a2014-01-23 14:22:48 -0800611 free(line);
612 if (fstab)
613 fs_mgr_free_fstab(fstab);
614 return NULL;
615}
616
Bowgo Tsai47d34272017-03-06 22:22:07 +0800617/* merges fstab entries from both a and b, then returns the merged result.
618 * note that the caller should only manage the return pointer without
619 * doing further memory management for the two inputs, i.e. only need to
620 * frees up memory of the return value without touching a and b. */
621static struct fstab *in_place_merge(struct fstab *a, struct fstab *b)
622{
623 if (!a) return b;
624 if (!b) return a;
625
626 int total_entries = a->num_entries + b->num_entries;
627 a->recs = static_cast<struct fstab_rec *>(realloc(
628 a->recs, total_entries * (sizeof(struct fstab_rec))));
629 if (!a->recs) {
630 LERROR << __FUNCTION__ << "(): failed to allocate fstab recs";
631 // If realloc() fails the original block is left untouched;
632 // it is not freed or moved. So we have to free both a and b here.
633 fs_mgr_free_fstab(a);
634 fs_mgr_free_fstab(b);
635 return nullptr;
636 }
637
638 for (int i = a->num_entries, j = 0; i < total_entries; i++, j++) {
639 // copy the pointer directly *without* malloc and memcpy
640 a->recs[i] = b->recs[j];
641 }
642
643 // Frees up b, but don't free b->recs[X] to make sure they are
644 // accessible through a->recs[X].
645 free(b->fstab_filename);
646 free(b);
647
648 a->num_entries = total_entries;
649 return a;
650}
651
Hung-ying Tyan99c4a8a2016-02-01 15:07:40 +0800652struct fstab *fs_mgr_read_fstab(const char *fstab_path)
653{
654 FILE *fstab_file;
655 struct fstab *fstab;
656
657 fstab_file = fopen(fstab_path, "r");
658 if (!fstab_file) {
Bowgo Tsai47d34272017-03-06 22:22:07 +0800659 PERROR << __FUNCTION__<< "(): cannot open file: '" << fstab_path << "'";
660 return nullptr;
Hung-ying Tyan99c4a8a2016-02-01 15:07:40 +0800661 }
Bowgo Tsai47d34272017-03-06 22:22:07 +0800662
Hung-ying Tyan99c4a8a2016-02-01 15:07:40 +0800663 fstab = fs_mgr_read_fstab_file(fstab_file);
664 if (fstab) {
665 fstab->fstab_filename = strdup(fstab_path);
Bowgo Tsai47d34272017-03-06 22:22:07 +0800666 } else {
667 LERROR << __FUNCTION__ << "(): failed to load fstab from : '" << fstab_path << "'";
Hung-ying Tyan99c4a8a2016-02-01 15:07:40 +0800668 }
Bowgo Tsai47d34272017-03-06 22:22:07 +0800669
Hung-ying Tyan99c4a8a2016-02-01 15:07:40 +0800670 fclose(fstab_file);
671 return fstab;
672}
673
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800674/* Returns fstab entries parsed from the device tree if they
675 * exist
676 */
677struct fstab *fs_mgr_read_fstab_dt()
678{
679 std::string fstab_buf = read_fstab_from_dt();
680 if (fstab_buf.empty()) {
bowgotsai172c1d82017-03-16 10:25:39 +0900681 LINFO << __FUNCTION__ << "(): failed to read fstab from dt";
Bowgo Tsai47d34272017-03-06 22:22:07 +0800682 return nullptr;
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800683 }
684
685 std::unique_ptr<FILE, decltype(&fclose)> fstab_file(
686 fmemopen(static_cast<void*>(const_cast<char*>(fstab_buf.c_str())),
687 fstab_buf.length(), "r"), fclose);
688 if (!fstab_file) {
Bowgo Tsai47d34272017-03-06 22:22:07 +0800689 PERROR << __FUNCTION__ << "(): failed to create a file stream for fstab dt";
690 return nullptr;
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800691 }
692
693 struct fstab *fstab = fs_mgr_read_fstab_file(fstab_file.get());
694 if (!fstab) {
Bowgo Tsai47d34272017-03-06 22:22:07 +0800695 LERROR << __FUNCTION__ << "(): failed to load fstab from kernel:"
696 << std::endl << fstab_buf;
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800697 }
698
699 return fstab;
700}
701
Bowgo Tsai46c6dc12017-03-07 18:52:03 +0800702/*
703 * tries to load default fstab.<hardware> file from /odm/etc, /vendor/etc
704 * or /. loads the first one found and also combines fstab entries passed
705 * in from device tree.
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800706 */
707struct fstab *fs_mgr_read_fstab_default()
708{
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800709 std::string hw;
Bowgo Tsai47d34272017-03-06 22:22:07 +0800710 std::string default_fstab;
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800711
Bowgo Tsaid05a2f72017-03-28 01:28:29 +0800712 // Use different fstab paths for normal boot and recovery boot, respectively
713 if (access("/sbin/recovery", F_OK) == 0) {
714 default_fstab = "/etc/recovery.fstab";
715 } else if (fs_mgr_get_boot_config("hardware", &hw)) { // normal boot
Bowgo Tsai46c6dc12017-03-07 18:52:03 +0800716 for (const char *prefix : {"/odm/etc/fstab.","/vendor/etc/fstab.", "/fstab."}) {
717 default_fstab = prefix + hw;
718 if (access(default_fstab.c_str(), F_OK) == 0) break;
719 }
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800720 } else {
Bowgo Tsai47d34272017-03-06 22:22:07 +0800721 LWARNING << __FUNCTION__ << "(): failed to find device hardware name";
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800722 }
723
Bowgo Tsaiacc1c3c2017-03-29 16:19:45 +0800724 // combines fstab entries passed in from device tree with
725 // the ones found from default_fstab file
726 struct fstab *fstab_dt = fs_mgr_read_fstab_dt();
727 struct fstab *fstab = fs_mgr_read_fstab(default_fstab.c_str());
728
729 return in_place_merge(fstab_dt, fstab);
Sandeep Patilc20c0c22017-02-23 16:09:34 -0800730}
731
Colin Cross5edee2a2014-01-23 14:22:48 -0800732void fs_mgr_free_fstab(struct fstab *fstab)
733{
734 int i;
735
736 if (!fstab) {
737 return;
738 }
739
740 for (i = 0; i < fstab->num_entries; i++) {
741 /* Free the pointers return by strdup(3) */
742 free(fstab->recs[i].blk_device);
743 free(fstab->recs[i].mount_point);
744 free(fstab->recs[i].fs_type);
745 free(fstab->recs[i].fs_options);
746 free(fstab->recs[i].key_loc);
Paul Lawrence9dbe97b2017-04-21 12:41:48 -0700747 free(fstab->recs[i].key_dir);
Colin Cross5edee2a2014-01-23 14:22:48 -0800748 free(fstab->recs[i].label);
749 }
750
751 /* Free the fstab_recs array created by calloc(3) */
752 free(fstab->recs);
753
754 /* Free the fstab filename */
755 free(fstab->fstab_filename);
756
757 /* Free fstab */
758 free(fstab);
759}
760
761/* Add an entry to the fstab, and return 0 on success or -1 on error */
762int fs_mgr_add_entry(struct fstab *fstab,
763 const char *mount_point, const char *fs_type,
Sasha Levitskiycdc1cfb2014-04-10 17:10:21 -0700764 const char *blk_device)
Colin Cross5edee2a2014-01-23 14:22:48 -0800765{
766 struct fstab_rec *new_fstab_recs;
767 int n = fstab->num_entries;
768
769 new_fstab_recs = (struct fstab_rec *)
770 realloc(fstab->recs, sizeof(struct fstab_rec) * (n + 1));
771
772 if (!new_fstab_recs) {
773 return -1;
774 }
775
776 /* A new entry was added, so initialize it */
777 memset(&new_fstab_recs[n], 0, sizeof(struct fstab_rec));
778 new_fstab_recs[n].mount_point = strdup(mount_point);
779 new_fstab_recs[n].fs_type = strdup(fs_type);
780 new_fstab_recs[n].blk_device = strdup(blk_device);
781 new_fstab_recs[n].length = 0;
782
783 /* Update the fstab struct */
784 fstab->recs = new_fstab_recs;
785 fstab->num_entries++;
786
787 return 0;
788}
789
JP Abgrall5c01dac2014-06-18 14:54:37 -0700790/*
Bowgo Tsaic55f1882017-09-27 18:00:10 +0800791 * Returns the fstab_rec* whose mount_point is path.
792 * Returns nullptr if not found.
JP Abgrall5c01dac2014-06-18 14:54:37 -0700793 */
Bowgo Tsaic55f1882017-09-27 18:00:10 +0800794struct fstab_rec* fs_mgr_get_entry_for_mount_point(struct fstab* fstab, const std::string& path) {
Colin Cross5edee2a2014-01-23 14:22:48 -0800795 if (!fstab) {
Bowgo Tsaicc323952017-09-26 18:03:23 +0800796 return nullptr;
Colin Cross5edee2a2014-01-23 14:22:48 -0800797 }
Bowgo Tsaic55f1882017-09-27 18:00:10 +0800798 for (int i = 0; i < fstab->num_entries; i++) {
Bowgo Tsaicc323952017-09-26 18:03:23 +0800799 if (fstab->recs[i].mount_point && path == fstab->recs[i].mount_point) {
Colin Cross5edee2a2014-01-23 14:22:48 -0800800 return &fstab->recs[i];
801 }
802 }
Bowgo Tsaicc323952017-09-26 18:03:23 +0800803 return nullptr;
JP Abgralla794f862014-06-17 16:58:46 -0700804}
805
Paul Lawrencec410b3b2015-03-26 15:49:42 +0000806int fs_mgr_is_voldmanaged(const struct fstab_rec *fstab)
Colin Cross5edee2a2014-01-23 14:22:48 -0800807{
808 return fstab->fs_mgr_flags & MF_VOLDMANAGED;
809}
810
Paul Lawrencec410b3b2015-03-26 15:49:42 +0000811int fs_mgr_is_nonremovable(const struct fstab_rec *fstab)
Colin Cross5edee2a2014-01-23 14:22:48 -0800812{
813 return fstab->fs_mgr_flags & MF_NONREMOVABLE;
814}
815
Paul Lawrencec410b3b2015-03-26 15:49:42 +0000816int fs_mgr_is_verified(const struct fstab_rec *fstab)
Paul Lawrencebbb36312014-10-09 14:22:49 +0000817{
818 return fstab->fs_mgr_flags & MF_VERIFY;
819}
820
Bowgo Tsai80d1ad12017-04-13 13:05:42 +0800821int fs_mgr_is_avb(const struct fstab_rec *fstab)
822{
823 return fstab->fs_mgr_flags & MF_AVB;
824}
825
Sandeep Patil05ff38b2017-02-16 17:04:11 -0800826int fs_mgr_is_verifyatboot(const struct fstab_rec *fstab)
827{
828 return fstab->fs_mgr_flags & MF_VERIFYATBOOT;
829}
830
Paul Lawrencec410b3b2015-03-26 15:49:42 +0000831int fs_mgr_is_encryptable(const struct fstab_rec *fstab)
Colin Cross5edee2a2014-01-23 14:22:48 -0800832{
Paul Lawrenceb262d682015-10-29 10:31:02 -0700833 return fstab->fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT | MF_FORCEFDEORFBE);
Colin Cross5edee2a2014-01-23 14:22:48 -0800834}
835
Paul Lawrencec410b3b2015-03-26 15:49:42 +0000836int fs_mgr_is_file_encrypted(const struct fstab_rec *fstab)
837{
838 return fstab->fs_mgr_flags & MF_FILEENCRYPTION;
839}
840
Eric Biggersb478f702017-02-02 14:46:24 -0800841void fs_mgr_get_file_encryption_modes(const struct fstab_rec *fstab,
842 const char **contents_mode_ret,
843 const char **filenames_mode_ret)
Paul Lawrence4e898a02016-05-24 04:56:37 -0700844{
Eric Biggersb478f702017-02-02 14:46:24 -0800845 *contents_mode_ret = flag_to_encryption_mode(file_contents_encryption_modes,
846 fstab->file_contents_mode);
847 *filenames_mode_ret = flag_to_encryption_mode(file_names_encryption_modes,
848 fstab->file_names_mode);
Paul Lawrence4e898a02016-05-24 04:56:37 -0700849}
850
Paul Lawrenceb262d682015-10-29 10:31:02 -0700851int fs_mgr_is_convertible_to_fbe(const struct fstab_rec *fstab)
852{
853 return fstab->fs_mgr_flags & MF_FORCEFDEORFBE;
854}
855
Paul Lawrencec410b3b2015-03-26 15:49:42 +0000856int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab)
Colin Cross5edee2a2014-01-23 14:22:48 -0800857{
858 return fstab->fs_mgr_flags & MF_NOEMULATEDSD;
859}
JP Abgrallfe6fcc42015-03-05 17:30:53 -0800860
Eric Biggers8d3bcd42017-07-05 12:21:15 -0700861int fs_mgr_is_notrim(const struct fstab_rec* fstab) {
JP Abgrallfe6fcc42015-03-05 17:30:53 -0800862 return fstab->fs_mgr_flags & MF_NOTRIM;
863}
Ed Tame498c7c2015-04-13 18:01:33 -0700864
Eric Biggers8d3bcd42017-07-05 12:21:15 -0700865int fs_mgr_is_formattable(const struct fstab_rec* fstab) {
Chris Fries79f33842013-09-05 13:19:21 -0500866 return fstab->fs_mgr_flags & (MF_FORMATTABLE);
867}
Daniel Rosenbergeb65ce02015-09-01 12:41:18 -0700868
Eric Biggers8d3bcd42017-07-05 12:21:15 -0700869int fs_mgr_is_slotselect(const struct fstab_rec* fstab) {
Daniel Rosenberg8bb2f362015-08-27 13:42:20 -0700870 return fstab->fs_mgr_flags & MF_SLOTSELECT;
871}
Daniel Rosenberge3a32882016-04-12 14:28:09 -0700872
Eric Biggers8d3bcd42017-07-05 12:21:15 -0700873int fs_mgr_is_nofail(const struct fstab_rec* fstab) {
Daniel Rosenbergd38e3c52016-04-07 20:10:25 -0700874 return fstab->fs_mgr_flags & MF_NOFAIL;
875}
Wei Wangd61a7e22016-08-23 11:58:09 -0700876
Eric Biggers8d3bcd42017-07-05 12:21:15 -0700877int fs_mgr_is_latemount(const struct fstab_rec* fstab) {
Wei Wangd61a7e22016-08-23 11:58:09 -0700878 return fstab->fs_mgr_flags & MF_LATEMOUNT;
879}
Jeff Sharkey6d896102016-12-14 12:00:51 -0700880
Eric Biggers8d3bcd42017-07-05 12:21:15 -0700881int fs_mgr_is_quota(const struct fstab_rec* fstab) {
Jeff Sharkey6d896102016-12-14 12:00:51 -0700882 return fstab->fs_mgr_flags & MF_QUOTA;
883}