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