blob: c6684b493b06746a99ea7fa262de1fb072c87ab8 [file] [log] [blame]
Mark Salyzyn0f6a2702017-05-02 08:56:15 -07001/*
2 * Copyright (C) 2017 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
Mark Salyzynfa391102017-05-03 08:54:26 -070017#include <inttypes.h>
18
Mark Salyzyn0f6a2702017-05-02 08:56:15 -070019#include <string>
20
21#include <gtest/gtest.h>
22
Mark Salyzynfa391102017-05-03 08:54:26 -070023#include <android-base/file.h>
24#include <android-base/stringprintf.h>
Mark Salyzyn0f6a2702017-05-02 08:56:15 -070025#include <android-base/strings.h>
26
27#include <private/android_filesystem_config.h>
Tom Cherry68debff2019-06-17 14:19:39 -070028
29#include "fs_config.h"
Mark Salyzyn0f6a2702017-05-02 08:56:15 -070030
Mark Salyzynfa391102017-05-03 08:54:26 -070031extern const fs_path_config* __for_testing_only__android_dirs;
32extern const fs_path_config* __for_testing_only__android_files;
Ben Fennemaacd7b7b2017-06-22 15:15:56 -070033extern bool (*__for_testing_only__fs_config_cmp)(bool, const char*, size_t, const char*, size_t);
Mark Salyzyn0f6a2702017-05-02 08:56:15 -070034
Mark Salyzynfa391102017-05-03 08:54:26 -070035// Maximum entries in system/core/libcutils/fs_config.cpp:android_* before we
36// hit a nullptr termination, before we declare the list is just too big or
37// could be missing the nullptr.
38static constexpr size_t max_idx = 4096;
39
Ben Fennemaacd7b7b2017-06-22 15:15:56 -070040static const struct fs_config_cmp_test {
41 bool dir;
42 const char* prefix;
43 const char* path;
44 bool match;
45} fs_config_cmp_tests[] = {
Jiyong Parka2159c42019-02-03 00:34:29 +090046 // clang-format off
Ben Fennemaacd7b7b2017-06-22 15:15:56 -070047 { true, "system/lib", "system/lib/hw", true },
48 { true, "vendor/lib", "system/vendor/lib/hw", true },
Tom Cherryf8baa892019-11-06 09:29:56 -080049 { true, "system/vendor/lib", "vendor/lib/hw", false },
Ben Fennemaacd7b7b2017-06-22 15:15:56 -070050 { true, "system/vendor/lib", "system/vendor/lib/hw", true },
Jiyong Parka2159c42019-02-03 00:34:29 +090051 { true, "foo/*/bar/*", "foo/1/bar/2", true },
52 { true, "foo/*/bar/*", "foo/1/bar", true },
53 { true, "foo/*/bar/*", "foo/1/bar/2/3", true },
54 { true, "foo/*/bar/*", "foo/1/bar/2/3/", true },
Ben Fennemaacd7b7b2017-06-22 15:15:56 -070055 { false, "vendor/bin/wifi", "system/vendor/bin/w", false },
56 { false, "vendor/bin/wifi", "system/vendor/bin/wifi", true },
57 { false, "vendor/bin/wifi", "system/vendor/bin/wifi2", false },
58 { false, "system/vendor/bin/wifi", "system/vendor/bin/wifi", true, },
Tom Cherryf8baa892019-11-06 09:29:56 -080059 { false, "odm/bin/wifi", "system/odm/bin/wifi", false },
60 { false, "odm/bin/wifi", "vendor/odm/bin/wifi", true },
61 { false, "oem/bin/wifi", "system/oem/bin/wifi", false },
Ben Fennemaacd7b7b2017-06-22 15:15:56 -070062 { false, "data/bin/wifi", "system/data/bin/wifi", false },
63 { false, "system/bin/*", "system/bin/wifi", true },
64 { false, "vendor/bin/*", "system/vendor/bin/wifi", true },
65 { false, "system/bin/*", "system/bin", false },
Tom Cherryf8baa892019-11-06 09:29:56 -080066 { false, "system/vendor/bin/*", "vendor/bin/wifi", false },
Jiyong Parka2159c42019-02-03 00:34:29 +090067 { false, "foo/*/bar/*", "foo/1/bar/2", true },
68 { false, "foo/*/bar/*", "foo/1/bar", false },
69 { false, "foo/*/bar/*", "foo/1/bar/2/3", true },
70 { false, "foo/*/bar/*.so", "foo/1/bar/2/3", false },
71 { false, "foo/*/bar/*.so", "foo/1/bar/2.so", true },
72 { false, "foo/*/bar/*.so", "foo/1/bar/2/3.so", true },
Ben Fennemaacd7b7b2017-06-22 15:15:56 -070073 { false, NULL, NULL, false },
Jiyong Parka2159c42019-02-03 00:34:29 +090074 // clang-format on
Ben Fennemaacd7b7b2017-06-22 15:15:56 -070075};
76
Mark Salyzynfa391102017-05-03 08:54:26 -070077static bool check_unique(std::vector<const char*>& paths, const std::string& config_name,
78 const std::string& prefix) {
79 bool retval = false;
80
81 std::string alternate = "system/" + prefix;
82
83 for (size_t idx = 0; idx < paths.size(); ++idx) {
84 size_t second;
85 std::string path(paths[idx]);
86 // check if there are multiple identical paths
87 for (second = idx + 1; second < paths.size(); ++second) {
88 if (path == paths[second]) {
89 GTEST_LOG_(ERROR) << "duplicate paths in " << config_name << ": " << paths[idx];
90 retval = true;
91 break;
Mark Salyzyn0f6a2702017-05-02 08:56:15 -070092 }
Mark Salyzynfa391102017-05-03 08:54:26 -070093 }
94
95 // check if path is <partition>/
Elliott Hughes579e6822017-12-20 09:41:00 -080096 if (android::base::StartsWith(path, prefix)) {
Mark Salyzynfa391102017-05-03 08:54:26 -070097 // rebuild path to be system/<partition>/... to check for alias
98 path = alternate + path.substr(prefix.size());
99 for (second = 0; second < paths.size(); ++second) {
100 if (path == paths[second]) {
101 GTEST_LOG_(ERROR) << "duplicate alias paths in " << config_name << ": "
102 << paths[idx] << " and " << paths[second]
103 << " (remove latter)";
104 retval = true;
105 break;
106 }
107 }
108 continue;
109 }
110
111 // check if path is system/<partition>/
Elliott Hughes579e6822017-12-20 09:41:00 -0800112 if (android::base::StartsWith(path, alternate)) {
Mark Salyzynfa391102017-05-03 08:54:26 -0700113 // rebuild path to be <partition>/... to check for alias
114 path = prefix + path.substr(alternate.size());
115 for (second = 0; second < paths.size(); ++second) {
116 if (path == paths[second]) break;
117 }
118 if (second >= paths.size()) {
119 GTEST_LOG_(ERROR) << "replace path in " << config_name << ": " << paths[idx]
120 << " with " << path;
121 retval = true;
Mark Salyzyn0f6a2702017-05-02 08:56:15 -0700122 }
123 }
124 }
Mark Salyzynfa391102017-05-03 08:54:26 -0700125 return retval;
Mark Salyzyn0f6a2702017-05-02 08:56:15 -0700126}
127
Mark Salyzynfa391102017-05-03 08:54:26 -0700128static bool check_unique(const fs_path_config* paths, const char* type_name,
129 const std::string& prefix) {
130 std::string config("system/core/libcutils/fs_config.cpp:android_");
131 config += type_name;
132 config += "[]";
133
134 bool retval = false;
135 std::vector<const char*> paths_tmp;
136 for (size_t idx = 0; paths[idx].prefix; ++idx) {
137 if (idx > max_idx) {
138 GTEST_LOG_(WARNING) << config << ": has no end (missing null prefix)";
139 retval = true;
140 break;
141 }
142 paths_tmp.push_back(paths[idx].prefix);
143 }
144
145 return check_unique(paths_tmp, config, prefix) || retval;
146}
147
Ben Fennemaacd7b7b2017-06-22 15:15:56 -0700148static bool check_fs_config_cmp(const fs_config_cmp_test* tests) {
149 bool match, retval = false;
150 for (size_t idx = 0; tests[idx].prefix; ++idx) {
151 match = __for_testing_only__fs_config_cmp(tests[idx].dir, tests[idx].prefix,
152 strlen(tests[idx].prefix), tests[idx].path,
153 strlen(tests[idx].path));
154 if (match != tests[idx].match) {
155 GTEST_LOG_(ERROR) << tests[idx].path << (match ? " matched " : " didn't match ")
156 << tests[idx].prefix;
157 retval = true;
158 break;
159 }
160 }
161 return retval;
162}
163
Mark Salyzynfa391102017-05-03 08:54:26 -0700164#define endof(pointer, field) (offsetof(typeof(*(pointer)), field) + sizeof((pointer)->field))
165
166static bool check_unique(const std::string& config, const std::string& prefix) {
167 int retval = false;
168
169 std::string data;
170 if (!android::base::ReadFileToString(config, &data)) return retval;
171
172 const fs_path_config_from_file* pc =
173 reinterpret_cast<const fs_path_config_from_file*>(data.c_str());
174 size_t len = data.size();
175
176 std::vector<const char*> paths_tmp;
177 size_t entry_number = 0;
178 while (len > 0) {
179 uint16_t host_len = (len >= endof(pc, len)) ? pc->len : INT16_MAX;
180 if (host_len > len) {
181 GTEST_LOG_(WARNING) << config << ": truncated at entry " << entry_number << " ("
182 << host_len << " > " << len << ")";
183 const std::string unknown("?");
184 GTEST_LOG_(WARNING)
185 << config << ": entry[" << entry_number << "]={ "
186 << "len=" << ((len >= endof(pc, len))
187 ? android::base::StringPrintf("%" PRIu16, pc->len)
188 : unknown)
189 << ", mode=" << ((len >= endof(pc, mode))
190 ? android::base::StringPrintf("0%" PRIo16, pc->mode)
191 : unknown)
192 << ", uid=" << ((len >= endof(pc, uid))
193 ? android::base::StringPrintf("%" PRIu16, pc->uid)
194 : unknown)
195 << ", gid=" << ((len >= endof(pc, gid))
196 ? android::base::StringPrintf("%" PRIu16, pc->gid)
197 : unknown)
198 << ", capabilities="
199 << ((len >= endof(pc, capabilities))
200 ? android::base::StringPrintf("0x%" PRIx64, pc->capabilities)
201 : unknown)
202 << ", prefix="
203 << ((len >= offsetof(fs_path_config_from_file, prefix))
204 ? android::base::StringPrintf(
205 "\"%.*s...", (int)(len - offsetof(fs_path_config_from_file, prefix)),
206 pc->prefix)
207 : unknown)
208 << " }";
209 retval = true;
210 break;
211 }
212 paths_tmp.push_back(pc->prefix);
213
214 pc = reinterpret_cast<const fs_path_config_from_file*>(reinterpret_cast<const char*>(pc) +
215 host_len);
216 len -= host_len;
217 ++entry_number;
218 }
219
220 return check_unique(paths_tmp, config, prefix) || retval;
221}
222
223void check_two(const fs_path_config* paths, const char* type_name, const char* prefix) {
Mark Salyzyn0f6a2702017-05-02 08:56:15 -0700224 ASSERT_FALSE(paths == nullptr);
Mark Salyzynfa391102017-05-03 08:54:26 -0700225 ASSERT_FALSE(type_name == nullptr);
226 ASSERT_FALSE(prefix == nullptr);
227 bool check_internal = check_unique(paths, type_name, prefix);
228 EXPECT_FALSE(check_internal);
229 bool check_overrides =
230 check_unique(std::string("/") + prefix + "etc/fs_config_" + type_name, prefix);
231 EXPECT_FALSE(check_overrides);
Mark Salyzyn0f6a2702017-05-02 08:56:15 -0700232}
233
234TEST(fs_config, vendor_dirs_alias) {
Mark Salyzynfa391102017-05-03 08:54:26 -0700235 check_two(__for_testing_only__android_dirs, "dirs", "vendor/");
Mark Salyzyn0f6a2702017-05-02 08:56:15 -0700236}
237
238TEST(fs_config, vendor_files_alias) {
Mark Salyzynfa391102017-05-03 08:54:26 -0700239 check_two(__for_testing_only__android_files, "files", "vendor/");
Mark Salyzyn0f6a2702017-05-02 08:56:15 -0700240}
241
242TEST(fs_config, oem_dirs_alias) {
Mark Salyzynfa391102017-05-03 08:54:26 -0700243 check_two(__for_testing_only__android_dirs, "dirs", "oem/");
Mark Salyzyn0f6a2702017-05-02 08:56:15 -0700244}
245
246TEST(fs_config, oem_files_alias) {
Mark Salyzynfa391102017-05-03 08:54:26 -0700247 check_two(__for_testing_only__android_files, "files", "oem/");
Mark Salyzyn0f6a2702017-05-02 08:56:15 -0700248}
249
250TEST(fs_config, odm_dirs_alias) {
Mark Salyzynfa391102017-05-03 08:54:26 -0700251 check_two(__for_testing_only__android_dirs, "dirs", "odm/");
Mark Salyzyn0f6a2702017-05-02 08:56:15 -0700252}
253
254TEST(fs_config, odm_files_alias) {
Mark Salyzynfa391102017-05-03 08:54:26 -0700255 check_two(__for_testing_only__android_files, "files", "odm/");
Mark Salyzyn0f6a2702017-05-02 08:56:15 -0700256}
Ben Fennemaacd7b7b2017-06-22 15:15:56 -0700257
258TEST(fs_config, system_alias) {
259 EXPECT_FALSE(check_fs_config_cmp(fs_config_cmp_tests));
260}