Merge "canned_fs_config.cpp is written in C++"

This commit is contained in:
Treehugger Robot 2021-12-14 03:27:56 +00:00 committed by Gerrit Code Review
commit badd64bdbd
2 changed files with 75 additions and 78 deletions

View file

@ -156,7 +156,6 @@ cc_library {
},
srcs: [
"config_utils.cpp",
"canned_fs_config.cpp",
"iosched_policy.cpp",
"load_file.cpp",
"native_handle.cpp",
@ -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",
],
@ -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",

View file

@ -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;
f = fopen(fn, "r");
if (f == NULL) {
fprintf(stderr, "failed to open %s: %s\n", fn, strerror(errno));
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));
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(), '/');
}
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);
std::vector<std::string> tokens = Tokenize(line, " ");
if (tokens.size() < 4) {
std::cerr << "Ill-formed line: " << line << " in " << fn << std::endl;
return -1;
}
// 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);
// 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;
}
canned_used++;
canned_data.emplace_back(std::move(e));
}
fclose(f);
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;
}