1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <private/android_filesystem_config.h>
#include <private/canned_fs_config.h>
#include <private/fs_config.h>
#include <android-base/strings.h>
#include <errno.h>
#include <inttypes.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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;
};
static std::vector<Entry> canned_data;
int load_canned_fs_config(const char* fn) {
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(), '/');
}
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 = std::move(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;
}
// 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_data.emplace_back(std::move(e));
}
// Note: we used to sort the entries by path names. This was to improve the lookup performance
// by doing binary search. However, this is no longer the case. The lookup performance is not
// critical because this tool runs on the host, not on the device. Now, there can be multiple
// entries for the same path. Then the one that comes the last wins. This is to allow overriding
// platform provided fs_config with a user provided fs_config by appending the latter to the
// former.
//
// To implement the strategy, reverse the entries order, and search from the top.
std::reverse(canned_data.begin(), canned_data.end());
std::cout << "loaded " << canned_data.size() << " fs_config entries" << std::endl;
return 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 '/'
const Entry* found = nullptr;
// canned_data is already reversed. First match wins.
for (const auto& entry : canned_data) {
if (path == entry.path) {
found = &entry;
break;
}
continue;
}
if (found == nullptr) {
std::cerr << "failed to find " << path << " in canned fs_config" << std::endl;
exit(1);
}
*uid = found->uid;
*gid = found->gid;
*mode = found->mode;
*capabilities = found->capabilities;
}
|