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