• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 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 <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <ctype.h>
23 #include <sys/mount.h>
24 #include <sys/stat.h>
25 #include <errno.h>
26 #include <sys/types.h>
27 #include <sys/wait.h>
28 #include <libgen.h>
29 #include <time.h>
30 
31 #include <private/android_filesystem_config.h>
32 #include <cutils/partition_utils.h>
33 #include <cutils/properties.h>
34 #include <logwrap/logwrap.h>
35 
36 #include "fs_mgr_priv.h"
37 
38 #define KEY_LOC_PROP   "ro.crypto.keyfile.userdata"
39 #define KEY_IN_FOOTER  "footer"
40 
41 #define E2FSCK_BIN      "/system/bin/e2fsck"
42 
43 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
44 
45 struct flag_list {
46     const char *name;
47     unsigned flag;
48 };
49 
50 static struct flag_list mount_flags[] = {
51     { "noatime",    MS_NOATIME },
52     { "noexec",     MS_NOEXEC },
53     { "nosuid",     MS_NOSUID },
54     { "nodev",      MS_NODEV },
55     { "nodiratime", MS_NODIRATIME },
56     { "ro",         MS_RDONLY },
57     { "rw",         0 },
58     { "remount",    MS_REMOUNT },
59     { "bind",       MS_BIND },
60     { "rec",        MS_REC },
61     { "unbindable", MS_UNBINDABLE },
62     { "private",    MS_PRIVATE },
63     { "slave",      MS_SLAVE },
64     { "shared",     MS_SHARED },
65     { "defaults",   0 },
66     { 0,            0 },
67 };
68 
69 static struct flag_list fs_mgr_flags[] = {
70     { "wait",        MF_WAIT },
71     { "check",       MF_CHECK },
72     { "encryptable=",MF_CRYPT },
73     { "nonremovable",MF_NONREMOVABLE },
74     { "voldmanaged=",MF_VOLDMANAGED},
75     { "length=",     MF_LENGTH },
76     { "recoveryonly",MF_RECOVERYONLY },
77     { "defaults",    0 },
78     { 0,             0 },
79 };
80 
81 /*
82  * gettime() - returns the time in seconds of the system's monotonic clock or
83  * zero on error.
84  */
gettime(void)85 static time_t gettime(void)
86 {
87     struct timespec ts;
88     int ret;
89 
90     ret = clock_gettime(CLOCK_MONOTONIC, &ts);
91     if (ret < 0) {
92         ERROR("clock_gettime(CLOCK_MONOTONIC) failed: %s\n", strerror(errno));
93         return 0;
94     }
95 
96     return ts.tv_sec;
97 }
98 
wait_for_file(const char * filename,int timeout)99 static int wait_for_file(const char *filename, int timeout)
100 {
101     struct stat info;
102     time_t timeout_time = gettime() + timeout;
103     int ret = -1;
104 
105     while (gettime() < timeout_time && ((ret = stat(filename, &info)) < 0))
106         usleep(10000);
107 
108     return ret;
109 }
110 
parse_flags(char * flags,struct flag_list * fl,char ** key_loc,long long * part_length,char ** label,int * partnum,char * fs_options,int fs_options_len)111 static int parse_flags(char *flags, struct flag_list *fl,
112                        char **key_loc, long long *part_length, char **label, int *partnum,
113                        char *fs_options, int fs_options_len)
114 {
115     int f = 0;
116     int i;
117     char *p;
118     char *savep;
119 
120     /* initialize key_loc to null, if we find an MF_CRYPT flag,
121      * then we'll set key_loc to the proper value */
122     if (key_loc) {
123         *key_loc = NULL;
124     }
125     /* initialize part_length to 0, if we find an MF_LENGTH flag,
126      * then we'll set part_length to the proper value */
127     if (part_length) {
128         *part_length = 0;
129     }
130     if (partnum) {
131         *partnum = -1;
132     }
133     if (label) {
134         *label = NULL;
135     }
136 
137     /* initialize fs_options to the null string */
138     if (fs_options && (fs_options_len > 0)) {
139         fs_options[0] = '\0';
140     }
141 
142     p = strtok_r(flags, ",", &savep);
143     while (p) {
144         /* Look for the flag "p" in the flag list "fl"
145          * If not found, the loop exits with fl[i].name being null.
146          */
147         for (i = 0; fl[i].name; i++) {
148             if (!strncmp(p, fl[i].name, strlen(fl[i].name))) {
149                 f |= fl[i].flag;
150                 if ((fl[i].flag == MF_CRYPT) && key_loc) {
151                     /* The encryptable flag is followed by an = and the
152                      * location of the keys.  Get it and return it.
153                      */
154                     *key_loc = strdup(strchr(p, '=') + 1);
155                 } else if ((fl[i].flag == MF_LENGTH) && part_length) {
156                     /* The length flag is followed by an = and the
157                      * size of the partition.  Get it and return it.
158                      */
159                     *part_length = strtoll(strchr(p, '=') + 1, NULL, 0);
160                 } else if ((fl[i].flag == MF_VOLDMANAGED) && label && partnum) {
161                     /* The voldmanaged flag is followed by an = and the
162                      * label, a colon and the partition number or the
163                      * word "auto", e.g.
164                      *   voldmanaged=sdcard:3
165                      * Get and return them.
166                      */
167                     char *label_start;
168                     char *label_end;
169                     char *part_start;
170 
171                     label_start = strchr(p, '=') + 1;
172                     label_end = strchr(p, ':');
173                     if (label_end) {
174                         *label = strndup(label_start,
175                                          (int) (label_end - label_start));
176                         part_start = strchr(p, ':') + 1;
177                         if (!strcmp(part_start, "auto")) {
178                             *partnum = -1;
179                         } else {
180                             *partnum = strtol(part_start, NULL, 0);
181                         }
182                     } else {
183                         ERROR("Warning: voldmanaged= flag malformed\n");
184                     }
185                 }
186                 break;
187             }
188         }
189 
190         if (!fl[i].name) {
191             if (fs_options) {
192                 /* It's not a known flag, so it must be a filesystem specific
193                  * option.  Add it to fs_options if it was passed in.
194                  */
195                 strlcat(fs_options, p, fs_options_len);
196                 strlcat(fs_options, ",", fs_options_len);
197             } else {
198                 /* fs_options was not passed in, so if the flag is unknown
199                  * it's an error.
200                  */
201                 ERROR("Warning: unknown flag %s\n", p);
202             }
203         }
204         p = strtok_r(NULL, ",", &savep);
205     }
206 
207 out:
208     if (fs_options && fs_options[0]) {
209         /* remove the last trailing comma from the list of options */
210         fs_options[strlen(fs_options) - 1] = '\0';
211     }
212 
213     return f;
214 }
215 
216 /* Read a line of text till the next newline character.
217  * If no newline is found before the buffer is full, continue reading till a new line is seen,
218  * then return an empty buffer.  This effectively ignores lines that are too long.
219  * On EOF, return null.
220  */
fs_getline(char * buf,int size,FILE * file)221 static char *fs_getline(char *buf, int size, FILE *file)
222 {
223     int cnt = 0;
224     int eof = 0;
225     int eol = 0;
226     int c;
227 
228     if (size < 1) {
229         return NULL;
230     }
231 
232     while (cnt < (size - 1)) {
233         c = getc(file);
234         if (c == EOF) {
235             eof = 1;
236             break;
237         }
238 
239         *(buf + cnt) = c;
240         cnt++;
241 
242         if (c == '\n') {
243             eol = 1;
244             break;
245         }
246     }
247 
248     /* Null terminate what we've read */
249     *(buf + cnt) = '\0';
250 
251     if (eof) {
252         if (cnt) {
253             return buf;
254         } else {
255             return NULL;
256         }
257     } else if (eol) {
258         return buf;
259     } else {
260         /* The line is too long.  Read till a newline or EOF.
261          * If EOF, return null, if newline, return an empty buffer.
262          */
263         while(1) {
264             c = getc(file);
265             if (c == EOF) {
266                 return NULL;
267             } else if (c == '\n') {
268                 *buf = '\0';
269                 return buf;
270             }
271         }
272     }
273 }
274 
fs_mgr_read_fstab(const char * fstab_path)275 struct fstab *fs_mgr_read_fstab(const char *fstab_path)
276 {
277     FILE *fstab_file;
278     int cnt, entries;
279     int len;
280     char line[256];
281     const char *delim = " \t";
282     char *save_ptr, *p;
283     struct fstab *fstab;
284     struct fstab_rec *recs;
285     char *key_loc;
286     long long part_length;
287     char *label;
288     int partnum;
289 #define FS_OPTIONS_LEN 1024
290     char tmp_fs_options[FS_OPTIONS_LEN];
291 
292     fstab_file = fopen(fstab_path, "r");
293     if (!fstab_file) {
294         ERROR("Cannot open file %s\n", fstab_path);
295         return 0;
296     }
297 
298     entries = 0;
299     while (fs_getline(line, sizeof(line), fstab_file)) {
300         /* if the last character is a newline, shorten the string by 1 byte */
301         len = strlen(line);
302         if (line[len - 1] == '\n') {
303             line[len - 1] = '\0';
304         }
305         /* Skip any leading whitespace */
306         p = line;
307         while (isspace(*p)) {
308             p++;
309         }
310         /* ignore comments or empty lines */
311         if (*p == '#' || *p == '\0')
312             continue;
313         entries++;
314     }
315 
316     if (!entries) {
317         ERROR("No entries found in fstab\n");
318         return 0;
319     }
320 
321     /* Allocate and init the fstab structure */
322     fstab = calloc(1, sizeof(struct fstab));
323     fstab->num_entries = entries;
324     fstab->fstab_filename = strdup(fstab_path);
325     fstab->recs = calloc(fstab->num_entries, sizeof(struct fstab_rec));
326 
327     fseek(fstab_file, 0, SEEK_SET);
328 
329     cnt = 0;
330     while (fs_getline(line, sizeof(line), fstab_file)) {
331         /* if the last character is a newline, shorten the string by 1 byte */
332         len = strlen(line);
333         if (line[len - 1] == '\n') {
334             line[len - 1] = '\0';
335         }
336 
337         /* Skip any leading whitespace */
338         p = line;
339         while (isspace(*p)) {
340             p++;
341         }
342         /* ignore comments or empty lines */
343         if (*p == '#' || *p == '\0')
344             continue;
345 
346         /* If a non-comment entry is greater than the size we allocated, give an
347          * error and quit.  This can happen in the unlikely case the file changes
348          * between the two reads.
349          */
350         if (cnt >= entries) {
351             ERROR("Tried to process more entries than counted\n");
352             break;
353         }
354 
355         if (!(p = strtok_r(line, delim, &save_ptr))) {
356             ERROR("Error parsing mount source\n");
357             return 0;
358         }
359         fstab->recs[cnt].blk_device = strdup(p);
360 
361         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
362             ERROR("Error parsing mount_point\n");
363             return 0;
364         }
365         fstab->recs[cnt].mount_point = strdup(p);
366 
367         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
368             ERROR("Error parsing fs_type\n");
369             return 0;
370         }
371         fstab->recs[cnt].fs_type = strdup(p);
372 
373         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
374             ERROR("Error parsing mount_flags\n");
375             return 0;
376         }
377         tmp_fs_options[0] = '\0';
378         fstab->recs[cnt].flags = parse_flags(p, mount_flags,
379                                        NULL, NULL, NULL, NULL,
380                                        tmp_fs_options, FS_OPTIONS_LEN);
381 
382         /* fs_options are optional */
383         if (tmp_fs_options[0]) {
384             fstab->recs[cnt].fs_options = strdup(tmp_fs_options);
385         } else {
386             fstab->recs[cnt].fs_options = NULL;
387         }
388 
389         if (!(p = strtok_r(NULL, delim, &save_ptr))) {
390             ERROR("Error parsing fs_mgr_options\n");
391             return 0;
392         }
393         fstab->recs[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags,
394                                               &key_loc, &part_length,
395                                               &label, &partnum,
396                                               NULL, 0);
397         fstab->recs[cnt].key_loc = key_loc;
398         fstab->recs[cnt].length = part_length;
399         fstab->recs[cnt].label = label;
400         fstab->recs[cnt].partnum = partnum;
401         cnt++;
402     }
403     fclose(fstab_file);
404 
405     return fstab;
406 }
407 
fs_mgr_free_fstab(struct fstab * fstab)408 void fs_mgr_free_fstab(struct fstab *fstab)
409 {
410     int i;
411 
412     for (i = 0; i < fstab->num_entries; i++) {
413         /* Free the pointers return by strdup(3) */
414         free(fstab->recs[i].blk_device);
415         free(fstab->recs[i].mount_point);
416         free(fstab->recs[i].fs_type);
417         free(fstab->recs[i].fs_options);
418         free(fstab->recs[i].key_loc);
419         free(fstab->recs[i].label);
420         i++;
421     }
422 
423     /* Free the fstab_recs array created by calloc(3) */
424     free(fstab->recs);
425 
426     /* Free the fstab filename */
427     free(fstab->fstab_filename);
428 
429     /* Free fstab */
430     free(fstab);
431 }
432 
check_fs(char * blk_device,char * fs_type,char * target)433 static void check_fs(char *blk_device, char *fs_type, char *target)
434 {
435     int status;
436     int ret;
437     long tmpmnt_flags = MS_NOATIME | MS_NOEXEC | MS_NOSUID;
438     char *tmpmnt_opts = "nomblk_io_submit,errors=remount-ro";
439     char *e2fsck_argv[] = {
440         E2FSCK_BIN,
441         "-y",
442         blk_device
443     };
444 
445     /* Check for the types of filesystems we know how to check */
446     if (!strcmp(fs_type, "ext2") || !strcmp(fs_type, "ext3") || !strcmp(fs_type, "ext4")) {
447         /*
448          * First try to mount and unmount the filesystem.  We do this because
449          * the kernel is more efficient than e2fsck in running the journal and
450          * processing orphaned inodes, and on at least one device with a
451          * performance issue in the emmc firmware, it can take e2fsck 2.5 minutes
452          * to do what the kernel does in about a second.
453          *
454          * After mounting and unmounting the filesystem, run e2fsck, and if an
455          * error is recorded in the filesystem superblock, e2fsck will do a full
456          * check.  Otherwise, it does nothing.  If the kernel cannot mount the
457          * filesytsem due to an error, e2fsck is still run to do a full check
458          * fix the filesystem.
459          */
460         ret = mount(blk_device, target, fs_type, tmpmnt_flags, tmpmnt_opts);
461         if (!ret) {
462             umount(target);
463         }
464 
465         INFO("Running %s on %s\n", E2FSCK_BIN, blk_device);
466 
467         ret = android_fork_execvp_ext(ARRAY_SIZE(e2fsck_argv), e2fsck_argv,
468                                       &status, true, LOG_KLOG, true);
469 
470         if (ret < 0) {
471             /* No need to check for error in fork, we can't really handle it now */
472             ERROR("Failed trying to run %s\n", E2FSCK_BIN);
473         }
474     }
475 
476     return;
477 }
478 
remove_trailing_slashes(char * n)479 static void remove_trailing_slashes(char *n)
480 {
481     int len;
482 
483     len = strlen(n) - 1;
484     while ((*(n + len) == '/') && len) {
485       *(n + len) = '\0';
486       len--;
487     }
488 }
489 
fs_match(char * in1,char * in2)490 static int fs_match(char *in1, char *in2)
491 {
492     char *n1;
493     char *n2;
494     int ret;
495 
496     n1 = strdup(in1);
497     n2 = strdup(in2);
498 
499     remove_trailing_slashes(n1);
500     remove_trailing_slashes(n2);
501 
502     ret = !strcmp(n1, n2);
503 
504     free(n1);
505     free(n2);
506 
507     return ret;
508 }
509 
fs_mgr_mount_all(struct fstab * fstab)510 int fs_mgr_mount_all(struct fstab *fstab)
511 {
512     int i = 0;
513     int encrypted = 0;
514     int ret = -1;
515     int mret;
516 
517     if (!fstab) {
518         return ret;
519     }
520 
521     for (i = 0; i < fstab->num_entries; i++) {
522         /* Don't mount entries that are managed by vold */
523         if (fstab->recs[i].fs_mgr_flags & (MF_VOLDMANAGED | MF_RECOVERYONLY)) {
524             continue;
525         }
526 
527         /* Skip raw partition entries such as boot, recovery, etc */
528         if (!strcmp(fstab->recs[i].fs_type, "emmc") ||
529             !strcmp(fstab->recs[i].fs_type, "mtd")) {
530             continue;
531         }
532 
533         if (fstab->recs[i].fs_mgr_flags & MF_WAIT) {
534             wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT);
535         }
536 
537         if (fstab->recs[i].fs_mgr_flags & MF_CHECK) {
538             check_fs(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
539                      fstab->recs[i].mount_point);
540         }
541 
542         mret = mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point,
543                      fstab->recs[i].fs_type, fstab->recs[i].flags,
544                      fstab->recs[i].fs_options);
545         if (!mret) {
546             /* Success!  Go get the next one */
547             continue;
548         }
549 
550         /* mount(2) returned an error, check if it's encrypted and deal with it */
551         if ((fstab->recs[i].fs_mgr_flags & MF_CRYPT) &&
552             !partition_wiped(fstab->recs[i].blk_device)) {
553             /* Need to mount a tmpfs at this mountpoint for now, and set
554              * properties that vold will query later for decrypting
555              */
556             if (mount("tmpfs", fstab->recs[i].mount_point, "tmpfs",
557                   MS_NOATIME | MS_NOSUID | MS_NODEV, CRYPTO_TMPFS_OPTIONS) < 0) {
558                 ERROR("Cannot mount tmpfs filesystem for encrypted fs at %s\n",
559                         fstab->recs[i].mount_point);
560                 goto out;
561             }
562             encrypted = 1;
563         } else {
564             ERROR("Cannot mount filesystem on %s at %s\n",
565                     fstab->recs[i].blk_device, fstab->recs[i].mount_point);
566             goto out;
567         }
568     }
569 
570     if (encrypted) {
571         ret = 1;
572     } else {
573         ret = 0;
574     }
575 
576 out:
577     return ret;
578 }
579 
580 /* If tmp_mount_point is non-null, mount the filesystem there.  This is for the
581  * tmp mount we do to check the user password
582  */
fs_mgr_do_mount(struct fstab * fstab,char * n_name,char * n_blk_device,char * tmp_mount_point)583 int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
584                     char *tmp_mount_point)
585 {
586     int i = 0;
587     int ret = -1;
588     char *m;
589 
590     if (!fstab) {
591         return ret;
592     }
593 
594     for (i = 0; i < fstab->num_entries; i++) {
595         if (!fs_match(fstab->recs[i].mount_point, n_name)) {
596             continue;
597         }
598 
599         /* We found our match */
600         /* If this is a raw partition, report an error */
601         if (!strcmp(fstab->recs[i].fs_type, "emmc") ||
602             !strcmp(fstab->recs[i].fs_type, "mtd")) {
603             ERROR("Cannot mount filesystem of type %s on %s\n",
604                   fstab->recs[i].fs_type, n_blk_device);
605             goto out;
606         }
607 
608         /* First check the filesystem if requested */
609         if (fstab->recs[i].fs_mgr_flags & MF_WAIT) {
610             wait_for_file(n_blk_device, WAIT_TIMEOUT);
611         }
612 
613         if (fstab->recs[i].fs_mgr_flags & MF_CHECK) {
614             check_fs(n_blk_device, fstab->recs[i].fs_type,
615                      fstab->recs[i].mount_point);
616         }
617 
618         /* Now mount it where requested */
619         if (tmp_mount_point) {
620             m = tmp_mount_point;
621         } else {
622             m = fstab->recs[i].mount_point;
623         }
624         if (mount(n_blk_device, m, fstab->recs[i].fs_type,
625                   fstab->recs[i].flags, fstab->recs[i].fs_options)) {
626             ERROR("Cannot mount filesystem on %s at %s\n",
627                     n_blk_device, m);
628             goto out;
629         } else {
630             ret = 0;
631             goto out;
632         }
633     }
634 
635     /* We didn't find a match, say so and return an error */
636     ERROR("Cannot find mount point %s in fstab\n", fstab->recs[i].mount_point);
637 
638 out:
639     return ret;
640 }
641 
642 /*
643  * mount a tmpfs filesystem at the given point.
644  * return 0 on success, non-zero on failure.
645  */
fs_mgr_do_tmpfs_mount(char * n_name)646 int fs_mgr_do_tmpfs_mount(char *n_name)
647 {
648     int ret;
649 
650     ret = mount("tmpfs", n_name, "tmpfs",
651                 MS_NOATIME | MS_NOSUID | MS_NODEV, CRYPTO_TMPFS_OPTIONS);
652     if (ret < 0) {
653         ERROR("Cannot mount tmpfs filesystem at %s\n", n_name);
654         return -1;
655     }
656 
657     /* Success */
658     return 0;
659 }
660 
fs_mgr_unmount_all(struct fstab * fstab)661 int fs_mgr_unmount_all(struct fstab *fstab)
662 {
663     int i = 0;
664     int ret = 0;
665 
666     if (!fstab) {
667         return -1;
668     }
669 
670     while (fstab->recs[i].blk_device) {
671         if (umount(fstab->recs[i].mount_point)) {
672             ERROR("Cannot unmount filesystem at %s\n", fstab->recs[i].mount_point);
673             ret = -1;
674         }
675         i++;
676     }
677 
678     return ret;
679 }
680 /*
681  * key_loc must be at least PROPERTY_VALUE_MAX bytes long
682  *
683  * real_blk_device must be at least PROPERTY_VALUE_MAX bytes long
684  */
fs_mgr_get_crypt_info(struct fstab * fstab,char * key_loc,char * real_blk_device,int size)685 int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc, char *real_blk_device, int size)
686 {
687     int i = 0;
688 
689     if (!fstab) {
690         return -1;
691     }
692     /* Initialize return values to null strings */
693     if (key_loc) {
694         *key_loc = '\0';
695     }
696     if (real_blk_device) {
697         *real_blk_device = '\0';
698     }
699 
700     /* Look for the encryptable partition to find the data */
701     for (i = 0; i < fstab->num_entries; i++) {
702         /* Don't deal with vold managed enryptable partitions here */
703         if (fstab->recs[i].fs_mgr_flags & MF_VOLDMANAGED) {
704             continue;
705         }
706         if (!(fstab->recs[i].fs_mgr_flags & MF_CRYPT)) {
707             continue;
708         }
709 
710         /* We found a match */
711         if (key_loc) {
712             strlcpy(key_loc, fstab->recs[i].key_loc, size);
713         }
714         if (real_blk_device) {
715             strlcpy(real_blk_device, fstab->recs[i].blk_device, size);
716         }
717         break;
718     }
719 
720     return 0;
721 }
722 
723 /* 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,long long length)724 int fs_mgr_add_entry(struct fstab *fstab,
725                      const char *mount_point, const char *fs_type,
726                      const char *blk_device, long long length)
727 {
728     struct fstab_rec *new_fstab_recs;
729     int n = fstab->num_entries;
730 
731     new_fstab_recs = (struct fstab_rec *)
732                      realloc(fstab->recs, sizeof(struct fstab_rec) * (n + 1));
733 
734     if (!new_fstab_recs) {
735         return -1;
736     }
737 
738     /* A new entry was added, so initialize it */
739      memset(&new_fstab_recs[n], 0, sizeof(struct fstab_rec));
740      new_fstab_recs[n].mount_point = strdup(mount_point);
741      new_fstab_recs[n].fs_type = strdup(fs_type);
742      new_fstab_recs[n].blk_device = strdup(blk_device);
743      new_fstab_recs[n].length = 0;
744 
745      /* Update the fstab struct */
746      fstab->recs = new_fstab_recs;
747      fstab->num_entries++;
748 
749      return 0;
750 }
751 
fs_mgr_get_entry_for_mount_point(struct fstab * fstab,const char * path)752 struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path)
753 {
754     int i;
755 
756     if (!fstab) {
757         return NULL;
758     }
759 
760     for (i = 0; i < fstab->num_entries; i++) {
761         int len = strlen(fstab->recs[i].mount_point);
762         if (strncmp(path, fstab->recs[i].mount_point, len) == 0 &&
763             (path[len] == '\0' || path[len] == '/')) {
764             return &fstab->recs[i];
765         }
766     }
767 
768     return NULL;
769 }
770 
fs_mgr_is_voldmanaged(struct fstab_rec * fstab)771 int fs_mgr_is_voldmanaged(struct fstab_rec *fstab)
772 {
773     return fstab->fs_mgr_flags & MF_VOLDMANAGED;
774 }
775 
fs_mgr_is_nonremovable(struct fstab_rec * fstab)776 int fs_mgr_is_nonremovable(struct fstab_rec *fstab)
777 {
778     return fstab->fs_mgr_flags & MF_NONREMOVABLE;
779 }
780 
fs_mgr_is_encryptable(struct fstab_rec * fstab)781 int fs_mgr_is_encryptable(struct fstab_rec *fstab)
782 {
783     return fstab->fs_mgr_flags & MF_CRYPT;
784 }
785 
786