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