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