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