Loading libcutils/Android.bp +2 −1 Original line number Diff line number Diff line Loading @@ -156,7 +156,6 @@ cc_library { }, srcs: [ "config_utils.cpp", "canned_fs_config.cpp", "iosched_policy.cpp", "load_file.cpp", "native_handle.cpp", Loading @@ -173,6 +172,7 @@ cc_library { not_windows: { srcs: libcutils_nonwindows_sources + [ "ashmem-host.cpp", "canned_fs_config.cpp", "fs_config.cpp", "trace-host.cpp", ], Loading @@ -193,6 +193,7 @@ cc_library { srcs: libcutils_nonwindows_sources + [ "android_reboot.cpp", "ashmem-dev.cpp", "canned_fs_config.cpp", "fs_config.cpp", "klog.cpp", "partition_utils.cpp", Loading libcutils/canned_fs_config.cpp +74 −78 Original line number Diff line number Diff line Loading @@ -18,111 +18,107 @@ #include <private/canned_fs_config.h> #include <private/fs_config.h> #include <android-base/strings.h> #include <errno.h> #include <fnmatch.h> #include <inttypes.h> #include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { const char* path; #include <algorithm> #include <fstream> #include <iostream> #include <string> #include <vector> using android::base::ConsumePrefix; using android::base::StartsWith; using android::base::Tokenize; struct Entry { std::string path; unsigned uid; unsigned gid; unsigned mode; uint64_t capabilities; } Path; }; static Path* canned_data = NULL; static int canned_alloc = 0; static int canned_used = 0; static int path_compare(const void* a, const void* b) { return strcmp(((Path*)a)->path, ((Path*)b)->path); } static std::vector<Entry> canned_data; int load_canned_fs_config(const char* fn) { char buf[PATH_MAX + 200]; FILE* f; std::ifstream input(fn); for (std::string line; std::getline(input, line);) { // Historical: the root dir can be represented as a space character. // e.g. " 1000 1000 0755" is parsed as // path = " ", uid = 1000, gid = 1000, mode = 0755. // But at the same time, we also have accepted // "/ 1000 1000 0755". if (StartsWith(line, " ")) { line.insert(line.begin(), '/'); } f = fopen(fn, "r"); if (f == NULL) { fprintf(stderr, "failed to open %s: %s\n", fn, strerror(errno)); std::vector<std::string> tokens = Tokenize(line, " "); if (tokens.size() < 4) { std::cerr << "Ill-formed line: " << line << " in " << fn << std::endl; return -1; } while (fgets(buf, sizeof(buf), f)) { Path* p; char* token; char* line = buf; bool rootdir; while (canned_used >= canned_alloc) { canned_alloc = (canned_alloc+1) * 2; canned_data = (Path*) realloc(canned_data, canned_alloc * sizeof(Path)); } p = canned_data + canned_used; if (line[0] == '/') line++; rootdir = line[0] == ' '; p->path = strdup(rootdir ? "" : strtok(line, " ")); p->uid = atoi(strtok(rootdir ? line : NULL, " ")); p->gid = atoi(strtok(NULL, " ")); p->mode = strtol(strtok(NULL, " "), NULL, 8); // mode is in octal p->capabilities = 0; do { token = strtok(NULL, " "); if (token && strncmp(token, "capabilities=", 13) == 0) { p->capabilities = strtoll(token+13, NULL, 0); // Historical: remove the leading '/' if exists. std::string path = tokens[0].front() == '/' ? std::string(tokens[0], 1) : tokens[0]; Entry e{ .path = path, .uid = static_cast<unsigned int>(atoi(tokens[1].c_str())), .gid = static_cast<unsigned int>(atoi(tokens[2].c_str())), // mode is in octal .mode = static_cast<unsigned int>(strtol(tokens[3].c_str(), nullptr, 8)), .capabilities = 0, }; for (size_t i = 4; i < tokens.size(); i++) { std::string_view sv = tokens[i]; if (ConsumePrefix(&sv, "capabilities=")) { e.capabilities = strtoll(std::string(sv).c_str(), nullptr, 0); break; } } while (token); canned_used++; // Historical: there can be tokens like "selabel=..." here. They have been ignored. // It's not an error because selabels are applied separately in e2fsdroid using the // file_contexts files set via -S option. std::cerr << "info: ignored token \"" << sv << "\" in " << fn << std::endl; } fclose(f); canned_data.emplace_back(std::move(e)); } qsort(canned_data, canned_used, sizeof(Path), path_compare); printf("loaded %d fs_config entries\n", canned_used); std::sort(canned_data.begin(), canned_data.end(), [](const Entry& a, const Entry& b) -> bool { return a.path < b.path; }); std::cout << "loaded " << canned_data.size() << " fs_config entries" << std::endl; return 0; } static const int kDebugCannedFsConfig = 0; void canned_fs_config(const char* path, [[maybe_unused]] int dir, [[maybe_unused]] const char* target_out_path, unsigned* uid, unsigned* gid, unsigned* mode, uint64_t* capabilities) { if (path != nullptr && path[0] == '/') path++; // canned paths lack the leading '/' void canned_fs_config(const char* path, int dir, const char* target_out_path, unsigned* uid, unsigned* gid, unsigned* mode, uint64_t* capabilities) { Path key, *p; const Entry* found = static_cast<Entry*>( bsearch(path, &canned_data[0], canned_data.size(), sizeof(Entry), [](const void* a, const void* b) -> int { return strcmp(static_cast<const char*>(a), static_cast<const Entry*>(b)->path.c_str()); })); key.path = path; if (path[0] == '/') key.path++; // canned paths lack the leading '/' p = (Path*) bsearch(&key, canned_data, canned_used, sizeof(Path), path_compare); if (p == NULL) { fprintf(stderr, "failed to find [%s] in canned fs_config\n", path); if (found == nullptr) { std::cerr << "failed to find " << path << " in canned fs_config" << std::endl; exit(1); } *uid = p->uid; *gid = p->gid; *mode = p->mode; *capabilities = p->capabilities; if (kDebugCannedFsConfig) { // for debugging, run the built-in fs_config and compare the results. unsigned c_uid, c_gid, c_mode; uint64_t c_capabilities; fs_config(path, dir, target_out_path, &c_uid, &c_gid, &c_mode, &c_capabilities); if (c_uid != *uid) printf("%s uid %d %d\n", path, *uid, c_uid); if (c_gid != *gid) printf("%s gid %d %d\n", path, *gid, c_gid); if (c_mode != *mode) printf("%s mode 0%o 0%o\n", path, *mode, c_mode); if (c_capabilities != *capabilities) { printf("%s capabilities %" PRIx64 " %" PRIx64 "\n", path, *capabilities, c_capabilities); } } *uid = found->uid; *gid = found->gid; *mode = found->mode; *capabilities = found->capabilities; } Loading
libcutils/Android.bp +2 −1 Original line number Diff line number Diff line Loading @@ -156,7 +156,6 @@ cc_library { }, srcs: [ "config_utils.cpp", "canned_fs_config.cpp", "iosched_policy.cpp", "load_file.cpp", "native_handle.cpp", Loading @@ -173,6 +172,7 @@ cc_library { not_windows: { srcs: libcutils_nonwindows_sources + [ "ashmem-host.cpp", "canned_fs_config.cpp", "fs_config.cpp", "trace-host.cpp", ], Loading @@ -193,6 +193,7 @@ cc_library { srcs: libcutils_nonwindows_sources + [ "android_reboot.cpp", "ashmem-dev.cpp", "canned_fs_config.cpp", "fs_config.cpp", "klog.cpp", "partition_utils.cpp", Loading
libcutils/canned_fs_config.cpp +74 −78 Original line number Diff line number Diff line Loading @@ -18,111 +18,107 @@ #include <private/canned_fs_config.h> #include <private/fs_config.h> #include <android-base/strings.h> #include <errno.h> #include <fnmatch.h> #include <inttypes.h> #include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { const char* path; #include <algorithm> #include <fstream> #include <iostream> #include <string> #include <vector> using android::base::ConsumePrefix; using android::base::StartsWith; using android::base::Tokenize; struct Entry { std::string path; unsigned uid; unsigned gid; unsigned mode; uint64_t capabilities; } Path; }; static Path* canned_data = NULL; static int canned_alloc = 0; static int canned_used = 0; static int path_compare(const void* a, const void* b) { return strcmp(((Path*)a)->path, ((Path*)b)->path); } static std::vector<Entry> canned_data; int load_canned_fs_config(const char* fn) { char buf[PATH_MAX + 200]; FILE* f; std::ifstream input(fn); for (std::string line; std::getline(input, line);) { // Historical: the root dir can be represented as a space character. // e.g. " 1000 1000 0755" is parsed as // path = " ", uid = 1000, gid = 1000, mode = 0755. // But at the same time, we also have accepted // "/ 1000 1000 0755". if (StartsWith(line, " ")) { line.insert(line.begin(), '/'); } f = fopen(fn, "r"); if (f == NULL) { fprintf(stderr, "failed to open %s: %s\n", fn, strerror(errno)); std::vector<std::string> tokens = Tokenize(line, " "); if (tokens.size() < 4) { std::cerr << "Ill-formed line: " << line << " in " << fn << std::endl; return -1; } while (fgets(buf, sizeof(buf), f)) { Path* p; char* token; char* line = buf; bool rootdir; while (canned_used >= canned_alloc) { canned_alloc = (canned_alloc+1) * 2; canned_data = (Path*) realloc(canned_data, canned_alloc * sizeof(Path)); } p = canned_data + canned_used; if (line[0] == '/') line++; rootdir = line[0] == ' '; p->path = strdup(rootdir ? "" : strtok(line, " ")); p->uid = atoi(strtok(rootdir ? line : NULL, " ")); p->gid = atoi(strtok(NULL, " ")); p->mode = strtol(strtok(NULL, " "), NULL, 8); // mode is in octal p->capabilities = 0; do { token = strtok(NULL, " "); if (token && strncmp(token, "capabilities=", 13) == 0) { p->capabilities = strtoll(token+13, NULL, 0); // Historical: remove the leading '/' if exists. std::string path = tokens[0].front() == '/' ? std::string(tokens[0], 1) : tokens[0]; Entry e{ .path = path, .uid = static_cast<unsigned int>(atoi(tokens[1].c_str())), .gid = static_cast<unsigned int>(atoi(tokens[2].c_str())), // mode is in octal .mode = static_cast<unsigned int>(strtol(tokens[3].c_str(), nullptr, 8)), .capabilities = 0, }; for (size_t i = 4; i < tokens.size(); i++) { std::string_view sv = tokens[i]; if (ConsumePrefix(&sv, "capabilities=")) { e.capabilities = strtoll(std::string(sv).c_str(), nullptr, 0); break; } } while (token); canned_used++; // Historical: there can be tokens like "selabel=..." here. They have been ignored. // It's not an error because selabels are applied separately in e2fsdroid using the // file_contexts files set via -S option. std::cerr << "info: ignored token \"" << sv << "\" in " << fn << std::endl; } fclose(f); canned_data.emplace_back(std::move(e)); } qsort(canned_data, canned_used, sizeof(Path), path_compare); printf("loaded %d fs_config entries\n", canned_used); std::sort(canned_data.begin(), canned_data.end(), [](const Entry& a, const Entry& b) -> bool { return a.path < b.path; }); std::cout << "loaded " << canned_data.size() << " fs_config entries" << std::endl; return 0; } static const int kDebugCannedFsConfig = 0; void canned_fs_config(const char* path, [[maybe_unused]] int dir, [[maybe_unused]] const char* target_out_path, unsigned* uid, unsigned* gid, unsigned* mode, uint64_t* capabilities) { if (path != nullptr && path[0] == '/') path++; // canned paths lack the leading '/' void canned_fs_config(const char* path, int dir, const char* target_out_path, unsigned* uid, unsigned* gid, unsigned* mode, uint64_t* capabilities) { Path key, *p; const Entry* found = static_cast<Entry*>( bsearch(path, &canned_data[0], canned_data.size(), sizeof(Entry), [](const void* a, const void* b) -> int { return strcmp(static_cast<const char*>(a), static_cast<const Entry*>(b)->path.c_str()); })); key.path = path; if (path[0] == '/') key.path++; // canned paths lack the leading '/' p = (Path*) bsearch(&key, canned_data, canned_used, sizeof(Path), path_compare); if (p == NULL) { fprintf(stderr, "failed to find [%s] in canned fs_config\n", path); if (found == nullptr) { std::cerr << "failed to find " << path << " in canned fs_config" << std::endl; exit(1); } *uid = p->uid; *gid = p->gid; *mode = p->mode; *capabilities = p->capabilities; if (kDebugCannedFsConfig) { // for debugging, run the built-in fs_config and compare the results. unsigned c_uid, c_gid, c_mode; uint64_t c_capabilities; fs_config(path, dir, target_out_path, &c_uid, &c_gid, &c_mode, &c_capabilities); if (c_uid != *uid) printf("%s uid %d %d\n", path, *uid, c_uid); if (c_gid != *gid) printf("%s gid %d %d\n", path, *gid, c_gid); if (c_mode != *mode) printf("%s mode 0%o 0%o\n", path, *mode, c_mode); if (c_capabilities != *capabilities) { printf("%s capabilities %" PRIx64 " %" PRIx64 "\n", path, *capabilities, c_capabilities); } } *uid = found->uid; *gid = found->gid; *mode = found->mode; *capabilities = found->capabilities; }