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 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 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 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 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 */ 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 */ 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 */ 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 444 int fs_mgr_is_voldmanaged(const struct fstab_rec *fstab) 445 { 446 return fstab->fs_mgr_flags & MF_VOLDMANAGED; 447 } 448 449 int fs_mgr_is_nonremovable(const struct fstab_rec *fstab) 450 { 451 return fstab->fs_mgr_flags & MF_NONREMOVABLE; 452 } 453 454 int fs_mgr_is_verified(const struct fstab_rec *fstab) 455 { 456 return fstab->fs_mgr_flags & MF_VERIFY; 457 } 458 459 int fs_mgr_is_encryptable(const struct fstab_rec *fstab) 460 { 461 return fstab->fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT); 462 } 463 464 int fs_mgr_is_file_encrypted(const struct fstab_rec *fstab) 465 { 466 return fstab->fs_mgr_flags & MF_FILEENCRYPTION; 467 } 468 469 int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab) 470 { 471 return fstab->fs_mgr_flags & MF_NOEMULATEDSD; 472 } 473 474 int fs_mgr_is_notrim(struct fstab_rec *fstab) 475 { 476 return fstab->fs_mgr_flags & MF_NOTRIM; 477 } 478 479 int fs_mgr_is_formattable(struct fstab_rec *fstab) 480 { 481 return fstab->fs_mgr_flags & (MF_FORMATTABLE); 482 } 483