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