Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit badd64bd authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

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

parents 51f11baa d8602917
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -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",
+74 −78
Original line number Diff line number Diff line
@@ -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;
}