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 <errno.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <sys/mount.h>
23 #include <unistd.h>
24
25 #include "fs_mgr_priv.h"
26
27 struct fs_mgr_flag_values {
28 char *key_loc;
29 char *verity_loc;
30 long long part_length;
31 char *label;
32 int partnum;
33 int swap_prio;
34 unsigned int zram_size;
35 };
36
37 struct flag_list {
38 const char *name;
39 unsigned flag;
40 };
41
42 static struct flag_list mount_flags[] = {
43 { "noatime", MS_NOATIME },
44 { "noexec", MS_NOEXEC },
45 { "nosuid", MS_NOSUID },
46 { "nodev", MS_NODEV },
47 { "nodiratime", MS_NODIRATIME },
48 { "ro", MS_RDONLY },
49 { "rw", 0 },
50 { "remount", MS_REMOUNT },
51 { "bind", MS_BIND },
52 { "rec", MS_REC },
53 { "unbindable", MS_UNBINDABLE },
54 { "private", MS_PRIVATE },
55 { "slave", MS_SLAVE },
56 { "shared", MS_SHARED },
57 { "defaults", 0 },
58 { 0, 0 },
59 };
60
61 static struct flag_list fs_mgr_flags[] = {
62 { "wait", MF_WAIT },
63 { "check", MF_CHECK },
64 { "encryptable=",MF_CRYPT },
65 { "forceencrypt=",MF_FORCECRYPT },
66 { "fileencryption",MF_FILEENCRYPTION },
67 { "forcefdeorfbe=",MF_FORCEFDEORFBE },
68 { "nonremovable",MF_NONREMOVABLE },
69 { "voldmanaged=",MF_VOLDMANAGED},
70 { "length=", MF_LENGTH },
71 { "recoveryonly",MF_RECOVERYONLY },
72 { "swapprio=", MF_SWAPPRIO },
73 { "zramsize=", MF_ZRAMSIZE },
74 { "verify", MF_VERIFY },
75 { "noemulatedsd", MF_NOEMULATEDSD },
76 { "notrim", MF_NOTRIM },
77 { "formattable", MF_FORMATTABLE },
78 { "slotselect", MF_SLOTSELECT },
79 { "nofail", MF_NOFAIL },
80 { "defaults", 0 },
81 { 0, 0 },
82 };
83
calculate_zram_size(unsigned int percentage)84 static uint64_t calculate_zram_size(unsigned int percentage)
85 {
86 uint64_t total;
87
88 total = sysconf(_SC_PHYS_PAGES);
89 total *= percentage;
90 total /= 100;
91
92 total *= sysconf(_SC_PAGESIZE);
93
94 return total;
95 }
96
parse_flags(char * flags,struct flag_list * fl,struct fs_mgr_flag_values * flag_vals,char * fs_options,int fs_options_len)97 static int parse_flags(char *flags, struct flag_list *fl,
98 struct fs_mgr_flag_values *flag_vals,
99 char *fs_options, int fs_options_len)
100 {
101 int f = 0;
102 int i;
103 char *p;
104 char *savep;
105
106 /* initialize flag values. If we find a relevant flag, we'll
107 * update the value */
108 if (flag_vals) {
109 memset(flag_vals, 0, sizeof(*flag_vals));
110 flag_vals->partnum = -1;
111 flag_vals->swap_prio = -1; /* negative means it wasn't specified. */
112 }
113
114 /* initialize fs_options to the null string */
115 if (fs_options && (fs_options_len > 0)) {
116 fs_options[0] = '\0';
117 }
118
119 p = strtok_r(flags, ",", &savep);
120 while (p) {
121 /* Look for the flag "p" in the flag list "fl"
122 * If not found, the loop exits with fl[i].name being null.
123 */
124 for (i = 0; fl[i].name; i++) {
125 if (!strncmp(p, fl[i].name, strlen(fl[i].name))) {
126 f |= fl[i].flag;
127 if ((fl[i].flag == MF_CRYPT) && flag_vals) {
128 /* The encryptable flag is followed by an = and the
129 * location of the keys. Get it and return it.
130 */
131 flag_vals->key_loc = strdup(strchr(p, '=') + 1);
132 } else if ((fl[i].flag == MF_VERIFY) && flag_vals) {
133 /* If the verify flag is followed by an = and the
134 * location for the verity state, get it and return it.
135 */
136 char *start = strchr(p, '=');
137 if (start) {
138 flag_vals->verity_loc = strdup(start + 1);
139 }
140 } else if ((fl[i].flag == MF_FORCECRYPT) && flag_vals) {
141 /* The forceencrypt flag is followed by an = and the
142 * location of the keys. Get it and return it.
143 */
144 flag_vals->key_loc = strdup(strchr(p, '=') + 1);
145 } else if ((fl[i].flag == MF_FORCEFDEORFBE) && flag_vals) {
146 /* The forcefdeorfbe flag is followed by an = and the
147 * location of the keys. Get it and return it.
148 */
149 flag_vals->key_loc = strdup(strchr(p, '=') + 1);
150 } else if ((fl[i].flag == MF_LENGTH) && flag_vals) {
151 /* The length flag is followed by an = and the
152 * size of the partition. Get it and return it.
153 */
154 flag_vals->part_length = strtoll(strchr(p, '=') + 1, NULL, 0);
155 } else if ((fl[i].flag == MF_VOLDMANAGED) && flag_vals) {
156 /* The voldmanaged flag is followed by an = and the
157 * label, a colon and the partition number or the
158 * word "auto", e.g.
159 * voldmanaged=sdcard:3
160 * Get and return them.
161 */
162 char *label_start;
163 char *label_end;
164 char *part_start;
165
166 label_start = strchr(p, '=') + 1;
167 label_end = strchr(p, ':');
168 if (label_end) {
169 flag_vals->label = strndup(label_start,
170 (int) (label_end - label_start));
171 part_start = strchr(p, ':') + 1;
172 if (!strcmp(part_start, "auto")) {
173 flag_vals->partnum = -1;
174 } else {
175 flag_vals->partnum = strtol(part_start, NULL, 0);
176 }
177 } else {
178 ERROR("Warning: voldmanaged= flag malformed\n");
179 }
180 } else if ((fl[i].flag == MF_SWAPPRIO) && flag_vals) {
181 flag_vals->swap_prio = strtoll(strchr(p, '=') + 1, NULL, 0);
182 } else if ((fl[i].flag == MF_ZRAMSIZE) && flag_vals) {
183 int is_percent = !!strrchr(p, '%');
184 unsigned int val = strtoll(strchr(p, '=') + 1, NULL, 0);
185 if (is_percent)
186 flag_vals->zram_size = calculate_zram_size(val);
187 else
188 flag_vals->zram_size = val;
189 }
190 break;
191 }
192 }
193
194 if (!fl[i].name) {
195 if (fs_options) {
196 /* It's not a known flag, so it must be a filesystem specific
197 * option. Add it to fs_options if it was passed in.
198 */
199 strlcat(fs_options, p, fs_options_len);
200 strlcat(fs_options, ",", fs_options_len);
201 } else {
202 /* fs_options was not passed in, so if the flag is unknown
203 * it's an error.
204 */
205 ERROR("Warning: unknown flag %s\n", p);
206 }
207 }
208 p = strtok_r(NULL, ",", &savep);
209 }
210
211 if (fs_options && fs_options[0]) {
212 /* remove the last trailing comma from the list of options */
213 fs_options[strlen(fs_options) - 1] = '\0';
214 }
215
216 return f;
217 }
218
fs_mgr_read_fstab(const char * fstab_path)219 struct fstab *fs_mgr_read_fstab(const char *fstab_path)
220 {
221 FILE *fstab_file;
222 int cnt, entries;
223 ssize_t len;
224 size_t alloc_len = 0;
225 char *line = NULL;
226 const char *delim = " \t";
227 char *save_ptr, *p;
228 struct fstab *fstab = NULL;
229 struct fs_mgr_flag_values flag_vals;
230 #define FS_OPTIONS_LEN 1024
231 char tmp_fs_options[FS_OPTIONS_LEN];
232
233 fstab_file = fopen(fstab_path, "r");
234 if (!fstab_file) {
235 ERROR("Cannot open file %s\n", fstab_path);
236 return 0;
237 }
238
239 entries = 0;
240 while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
241 /* if the last character is a newline, shorten the string by 1 byte */
242 if (line[len - 1] == '\n') {
243 line[len - 1] = '\0';
244 }
245 /* Skip any leading whitespace */
246 p = line;
247 while (isspace(*p)) {
248 p++;
249 }
250 /* ignore comments or empty lines */
251 if (*p == '#' || *p == '\0')
252 continue;
253 entries++;
254 }
255
256 if (!entries) {
257 ERROR("No entries found in fstab\n");
258 goto err;
259 }
260
261 /* Allocate and init the fstab structure */
262 fstab = calloc(1, sizeof(struct fstab));
263 fstab->num_entries = entries;
264 fstab->fstab_filename = strdup(fstab_path);
265 fstab->recs = calloc(fstab->num_entries, sizeof(struct fstab_rec));
266
267 fseek(fstab_file, 0, SEEK_SET);
268
269 cnt = 0;
270 while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
271 /* if the last character is a newline, shorten the string by 1 byte */
272 if (line[len - 1] == '\n') {
273 line[len - 1] = '\0';
274 }
275
276 /* Skip any leading whitespace */
277 p = line;
278 while (isspace(*p)) {
279 p++;
280 }
281 /* ignore comments or empty lines */
282 if (*p == '#' || *p == '\0')
283 continue;
284
285 /* If a non-comment entry is greater than the size we allocated, give an
286 * error and quit. This can happen in the unlikely case the file changes
287 * between the two reads.
288 */
289 if (cnt >= entries) {
290 ERROR("Tried to process more entries than counted\n");
291 break;
292 }
293
294 if (!(p = strtok_r(line, delim, &save_ptr))) {
295 ERROR("Error parsing mount source\n");
296 goto err;
297 }
298 fstab->recs[cnt].blk_device = strdup(p);
299
300 if (!(p = strtok_r(NULL, delim, &save_ptr))) {
301 ERROR("Error parsing mount_point\n");
302 goto err;
303 }
304 fstab->recs[cnt].mount_point = strdup(p);
305
306 if (!(p = strtok_r(NULL, delim, &save_ptr))) {
307 ERROR("Error parsing fs_type\n");
308 goto err;
309 }
310 fstab->recs[cnt].fs_type = strdup(p);
311
312 if (!(p = strtok_r(NULL, delim, &save_ptr))) {
313 ERROR("Error parsing mount_flags\n");
314 goto err;
315 }
316 tmp_fs_options[0] = '\0';
317 fstab->recs[cnt].flags = parse_flags(p, mount_flags, NULL,
318 tmp_fs_options, FS_OPTIONS_LEN);
319
320 /* fs_options are optional */
321 if (tmp_fs_options[0]) {
322 fstab->recs[cnt].fs_options = strdup(tmp_fs_options);
323 } else {
324 fstab->recs[cnt].fs_options = NULL;
325 }
326
327 if (!(p = strtok_r(NULL, delim, &save_ptr))) {
328 ERROR("Error parsing fs_mgr_options\n");
329 goto err;
330 }
331 fstab->recs[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags,
332 &flag_vals, NULL, 0);
333 fstab->recs[cnt].key_loc = flag_vals.key_loc;
334 fstab->recs[cnt].verity_loc = flag_vals.verity_loc;
335 fstab->recs[cnt].length = flag_vals.part_length;
336 fstab->recs[cnt].label = flag_vals.label;
337 fstab->recs[cnt].partnum = flag_vals.partnum;
338 fstab->recs[cnt].swap_prio = flag_vals.swap_prio;
339 fstab->recs[cnt].zram_size = flag_vals.zram_size;
340 cnt++;
341 }
342 /* If an A/B partition, modify block device to be the real block device */
343 if (fs_mgr_update_for_slotselect(fstab) != 0) {
344 ERROR("Error updating for slotselect\n");
345 goto err;
346 }
347 fclose(fstab_file);
348 free(line);
349 return fstab;
350
351 err:
352 fclose(fstab_file);
353 free(line);
354 if (fstab)
355 fs_mgr_free_fstab(fstab);
356 return NULL;
357 }
358
fs_mgr_free_fstab(struct fstab * fstab)359 void fs_mgr_free_fstab(struct fstab *fstab)
360 {
361 int i;
362
363 if (!fstab) {
364 return;
365 }
366
367 for (i = 0; i < fstab->num_entries; i++) {
368 /* Free the pointers return by strdup(3) */
369 free(fstab->recs[i].blk_device);
370 free(fstab->recs[i].mount_point);
371 free(fstab->recs[i].fs_type);
372 free(fstab->recs[i].fs_options);
373 free(fstab->recs[i].key_loc);
374 free(fstab->recs[i].label);
375 }
376
377 /* Free the fstab_recs array created by calloc(3) */
378 free(fstab->recs);
379
380 /* Free the fstab filename */
381 free(fstab->fstab_filename);
382
383 /* Free fstab */
384 free(fstab);
385 }
386
387 /* Add an entry to the fstab, and return 0 on success or -1 on error */
fs_mgr_add_entry(struct fstab * fstab,const char * mount_point,const char * fs_type,const char * blk_device)388 int fs_mgr_add_entry(struct fstab *fstab,
389 const char *mount_point, const char *fs_type,
390 const char *blk_device)
391 {
392 struct fstab_rec *new_fstab_recs;
393 int n = fstab->num_entries;
394
395 new_fstab_recs = (struct fstab_rec *)
396 realloc(fstab->recs, sizeof(struct fstab_rec) * (n + 1));
397
398 if (!new_fstab_recs) {
399 return -1;
400 }
401
402 /* A new entry was added, so initialize it */
403 memset(&new_fstab_recs[n], 0, sizeof(struct fstab_rec));
404 new_fstab_recs[n].mount_point = strdup(mount_point);
405 new_fstab_recs[n].fs_type = strdup(fs_type);
406 new_fstab_recs[n].blk_device = strdup(blk_device);
407 new_fstab_recs[n].length = 0;
408
409 /* Update the fstab struct */
410 fstab->recs = new_fstab_recs;
411 fstab->num_entries++;
412
413 return 0;
414 }
415
416 /*
417 * Returns the 1st matching fstab_rec that follows the start_rec.
418 * start_rec is the result of a previous search or NULL.
419 */
fs_mgr_get_entry_for_mount_point_after(struct fstab_rec * start_rec,struct fstab * fstab,const char * path)420 struct fstab_rec *fs_mgr_get_entry_for_mount_point_after(struct fstab_rec *start_rec, struct fstab *fstab, const char *path)
421 {
422 int i;
423 if (!fstab) {
424 return NULL;
425 }
426
427 if (start_rec) {
428 for (i = 0; i < fstab->num_entries; i++) {
429 if (&fstab->recs[i] == start_rec) {
430 i++;
431 break;
432 }
433 }
434 } else {
435 i = 0;
436 }
437 for (; i < fstab->num_entries; i++) {
438 int len = strlen(fstab->recs[i].mount_point);
439 if (strncmp(path, fstab->recs[i].mount_point, len) == 0 &&
440 (path[len] == '\0' || path[len] == '/')) {
441 return &fstab->recs[i];
442 }
443 }
444 return NULL;
445 }
446
447 /*
448 * Returns the 1st matching mount point.
449 * There might be more. To look for others, use fs_mgr_get_entry_for_mount_point_after()
450 * and give the fstab_rec from the previous search.
451 */
fs_mgr_get_entry_for_mount_point(struct fstab * fstab,const char * path)452 struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path)
453 {
454 return fs_mgr_get_entry_for_mount_point_after(NULL, fstab, path);
455 }
456
fs_mgr_is_voldmanaged(const struct fstab_rec * fstab)457 int fs_mgr_is_voldmanaged(const struct fstab_rec *fstab)
458 {
459 return fstab->fs_mgr_flags & MF_VOLDMANAGED;
460 }
461
fs_mgr_is_nonremovable(const struct fstab_rec * fstab)462 int fs_mgr_is_nonremovable(const struct fstab_rec *fstab)
463 {
464 return fstab->fs_mgr_flags & MF_NONREMOVABLE;
465 }
466
fs_mgr_is_verified(const struct fstab_rec * fstab)467 int fs_mgr_is_verified(const struct fstab_rec *fstab)
468 {
469 return fstab->fs_mgr_flags & MF_VERIFY;
470 }
471
fs_mgr_is_encryptable(const struct fstab_rec * fstab)472 int fs_mgr_is_encryptable(const struct fstab_rec *fstab)
473 {
474 return fstab->fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT | MF_FORCEFDEORFBE);
475 }
476
fs_mgr_is_file_encrypted(const struct fstab_rec * fstab)477 int fs_mgr_is_file_encrypted(const struct fstab_rec *fstab)
478 {
479 return fstab->fs_mgr_flags & MF_FILEENCRYPTION;
480 }
481
fs_mgr_is_convertible_to_fbe(const struct fstab_rec * fstab)482 int fs_mgr_is_convertible_to_fbe(const struct fstab_rec *fstab)
483 {
484 return fstab->fs_mgr_flags & MF_FORCEFDEORFBE;
485 }
486
fs_mgr_is_noemulatedsd(const struct fstab_rec * fstab)487 int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab)
488 {
489 return fstab->fs_mgr_flags & MF_NOEMULATEDSD;
490 }
491
fs_mgr_is_notrim(struct fstab_rec * fstab)492 int fs_mgr_is_notrim(struct fstab_rec *fstab)
493 {
494 return fstab->fs_mgr_flags & MF_NOTRIM;
495 }
496
fs_mgr_is_formattable(struct fstab_rec * fstab)497 int fs_mgr_is_formattable(struct fstab_rec *fstab)
498 {
499 return fstab->fs_mgr_flags & (MF_FORMATTABLE);
500 }
501
fs_mgr_is_slotselect(struct fstab_rec * fstab)502 int fs_mgr_is_slotselect(struct fstab_rec *fstab)
503 {
504 return fstab->fs_mgr_flags & MF_SLOTSELECT;
505 }
506
fs_mgr_is_nofail(struct fstab_rec * fstab)507 int fs_mgr_is_nofail(struct fstab_rec *fstab)
508 {
509 return fstab->fs_mgr_flags & MF_NOFAIL;
510 }
511