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