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