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 <private/android_filesystem_config.h> 18 #include <private/canned_fs_config.h> 19 #include <private/fs_config.h> 20 21 #include <errno.h> 22 #include <inttypes.h> 23 #include <limits.h> 24 #include <stdbool.h> 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <string.h> 28 29 typedef struct { 30 const char* path; 31 unsigned uid; 32 unsigned gid; 33 unsigned mode; 34 uint64_t capabilities; 35 } Path; 36 37 static Path* canned_data = NULL; 38 static int canned_alloc = 0; 39 static int canned_used = 0; 40 41 static int path_compare(const void* a, const void* b) { 42 return strcmp(((Path*)a)->path, ((Path*)b)->path); 43 } 44 45 int load_canned_fs_config(const char* fn) { 46 char buf[PATH_MAX + 200]; 47 FILE* f; 48 49 f = fopen(fn, "r"); 50 if (f == NULL) { 51 fprintf(stderr, "failed to open %s: %s\n", fn, strerror(errno)); 52 return -1; 53 } 54 55 while (fgets(buf, sizeof(buf), f)) { 56 Path* p; 57 char* token; 58 char* line = buf; 59 bool rootdir; 60 61 while (canned_used >= canned_alloc) { 62 canned_alloc = (canned_alloc+1) * 2; 63 canned_data = (Path*) realloc(canned_data, canned_alloc * sizeof(Path)); 64 } 65 p = canned_data + canned_used; 66 if (line[0] == '/') line++; 67 rootdir = line[0] == ' '; 68 p->path = strdup(rootdir ? "" : strtok(line, " ")); 69 p->uid = atoi(strtok(rootdir ? line : NULL, " ")); 70 p->gid = atoi(strtok(NULL, " ")); 71 p->mode = strtol(strtok(NULL, " "), NULL, 8); // mode is in octal 72 p->capabilities = 0; 73 74 do { 75 token = strtok(NULL, " "); 76 if (token && strncmp(token, "capabilities=", 13) == 0) { 77 p->capabilities = strtoll(token+13, NULL, 0); 78 break; 79 } 80 } while (token); 81 82 canned_used++; 83 } 84 85 fclose(f); 86 87 qsort(canned_data, canned_used, sizeof(Path), path_compare); 88 printf("loaded %d fs_config entries\n", canned_used); 89 90 return 0; 91 } 92 93 static const int kDebugCannedFsConfig = 0; 94 95 void canned_fs_config(const char* path, int dir, const char* target_out_path, 96 unsigned* uid, unsigned* gid, unsigned* mode, uint64_t* capabilities) { 97 Path key, *p; 98 99 key.path = path; 100 if (path[0] == '/') key.path++; // canned paths lack the leading '/' 101 p = (Path*) bsearch(&key, canned_data, canned_used, sizeof(Path), path_compare); 102 if (p == NULL) { 103 fprintf(stderr, "failed to find [%s] in canned fs_config\n", path); 104 exit(1); 105 } 106 *uid = p->uid; 107 *gid = p->gid; 108 *mode = p->mode; 109 *capabilities = p->capabilities; 110 111 if (kDebugCannedFsConfig) { 112 // for debugging, run the built-in fs_config and compare the results. 113 114 unsigned c_uid, c_gid, c_mode; 115 uint64_t c_capabilities; 116 117 fs_config(path, dir, target_out_path, &c_uid, &c_gid, &c_mode, &c_capabilities); 118 119 if (c_uid != *uid) printf("%s uid %d %d\n", path, *uid, c_uid); 120 if (c_gid != *gid) printf("%s gid %d %d\n", path, *gid, c_gid); 121 if (c_mode != *mode) printf("%s mode 0%o 0%o\n", path, *mode, c_mode); 122 if (c_capabilities != *capabilities) { 123 printf("%s capabilities %" PRIx64 " %" PRIx64 "\n", 124 path, 125 *capabilities, 126 c_capabilities); 127 } 128 } 129 } 130