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