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