blob: ab8f128ce466ea3af8ad6101f26e2c8be31b874a [file] [log] [blame]
Colin Cross5edee2a2014-01-23 14:22:48 -08001/*
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 },
Paul Lawrence2e5ae0a2014-04-04 09:34:19 -070062 { "forceencrypt=",MF_FORCECRYPT },
Colin Cross5edee2a2014-01-23 14:22:48 -080063 { "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);
Paul Lawrence2e5ae0a2014-04-04 09:34:19 -0700110 } 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);
Colin Cross5edee2a2014-01-23 14:22:48 -0800115 } 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
Colin Cross5edee2a2014-01-23 14:22:48 -0800171 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;
Colin Cross5edee2a2014-01-23 14:22:48 -0800189 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,
Sasha Levitskiycdc1cfb2014-04-10 17:10:21 -0700344 const char *blk_device)
Colin Cross5edee2a2014-01-23 14:22:48 -0800345{
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
JP Abgrall5c01dac2014-06-18 14:54:37 -0700370/*
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)
Colin Cross5edee2a2014-01-23 14:22:48 -0800375{
376 int i;
Colin Cross5edee2a2014-01-23 14:22:48 -0800377 if (!fstab) {
378 return NULL;
379 }
380
JP Abgrall5c01dac2014-06-18 14:54:37 -0700381 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++) {
Colin Cross5edee2a2014-01-23 14:22:48 -0800392 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 }
JP Abgrallf786fe52014-06-18 07:28:14 +0000398 return NULL;
JP Abgralla794f862014-06-17 16:58:46 -0700399}
400
JP Abgrall5c01dac2014-06-18 14:54:37 -0700401/*
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
Colin Cross5edee2a2014-01-23 14:22:48 -0800411int 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
Paul Lawrencebbb36312014-10-09 14:22:49 +0000421int fs_mgr_is_verified(struct fstab_rec *fstab)
422{
423 return fstab->fs_mgr_flags & MF_VERIFY;
424}
425
Colin Cross5edee2a2014-01-23 14:22:48 -0800426int fs_mgr_is_encryptable(struct fstab_rec *fstab)
427{
Paul Lawrence2e5ae0a2014-04-04 09:34:19 -0700428 return fstab->fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT);
Colin Cross5edee2a2014-01-23 14:22:48 -0800429}
430
431int fs_mgr_is_noemulatedsd(struct fstab_rec *fstab)
432{
433 return fstab->fs_mgr_flags & MF_NOEMULATEDSD;
434}