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