fs_config_generate: add -P <partitionlist> option

Add a -P option to fs_config_generate that allows us to filter on
a comma separated partition whitelist or minus prefixed -blacklist.
A partition is defined as accessible as <partition>/ or
system/<partition>/.

No change for legacy, where no -P flag is specified.

For system.img, but not vendor, oem or odm file references:
fs_config_generate -P -vendor,-oem,-odm

For vendor.img file references:
fs_config_generate -P vendor

For oem.img file references:
fs_config_generate -P oem

For odm.img file references:
fs_config_generate -P odm

Add and fortify tests for each of these cases.

SideEffects: none
Test: gTest host fs_config-unit-test
Bug: 36071012
Change-Id: I0537453bb289d41ef98ad76e69f78ae49358a1b3
This commit is contained in:
Mark Salyzyn 2017-03-22 08:46:55 -07:00
parent 5649b31a17
commit 256d339413
4 changed files with 284 additions and 20 deletions

View File

@ -156,9 +156,28 @@ properties are preserved during runtime operations. The host files in the
${OUT} directory are used in the final stages when building the filesystem
images to set the file and directory properties.
For systems with separate partition images, such as vendor or oem,
fs_config_generate can be instructed to filter the specific file references
to land in each partition's etc/fs_config_dirs or etc/fs_config_files
locations. The filter can be instructed to blacklist a partition's data by
providing the comma separated minus sign prefixed partition names. The filter
can be instructed to whitelist partition data by providing the partition name.
For example:
- For system.img, but not vendor, oem or odm file references:
-P -vendor,-oem,-odm
This makes sure the results only contain content associated with the
system, and not vendor, oem or odm, blacklisting their content.
- For vendor.img file references: -P vendor
- For oem.img file references: -P oem
- For odm.img file references: -P odm
fs_config_generate --help reports:
Generate binary content for fs_config_dirs (-D) and fs_config_files (-F)
from device-specific android_filesystem_config.h override
from device-specific android_filesystem_config.h override. Filter based
on a comma separated partition list (-P) whitelist or prefixed by a
minus blacklist. Partitions are identified as path references to
<partition>/ or system/<partition>
Usage: fs_config_generate -D|-F [-o output-file]
Usage: fs_config_generate -D|-F [-P list] [-o output-file]

View File

@ -26,6 +26,14 @@ static const struct fs_path_config android_device_dirs[] = {
{00555, AID_ROOT, AID_SYSTEM, 0, "vendor/etc"},
{00555, AID_ROOT, AID_SYSTEM, 0, "oem/etc"},
{00555, AID_ROOT, AID_SYSTEM, 0, "odm/etc"},
{00755, AID_SYSTEM, AID_ROOT, 0, "system/oem/etc"},
{00755, AID_SYSTEM, AID_ROOT, 0, "system/odm/etc"},
{00755, AID_SYSTEM, AID_ROOT, 0, "system/vendor/etc"},
{00755, AID_SYSTEM, AID_ROOT, 0, "data/misc"},
{00755, AID_SYSTEM, AID_ROOT, 0, "oem/data/misc"},
{00755, AID_SYSTEM, AID_ROOT, 0, "odm/data/misc"},
{00755, AID_SYSTEM, AID_ROOT, 0, "vendor/data/misc"},
{00555, AID_SYSTEM, AID_ROOT, 0, "etc"},
};
static const struct fs_path_config android_device_files[] = {
@ -37,4 +45,12 @@ static const struct fs_path_config android_device_files[] = {
{00444, AID_ROOT, AID_SYSTEM, 0, "vendor/etc/fs_config_files"},
{00444, AID_ROOT, AID_SYSTEM, 0, "oem/etc/fs_config_files"},
{00444, AID_ROOT, AID_SYSTEM, 0, "odm/etc/fs_config_files"},
{00644, AID_SYSTEM, AID_ROOT, 0, "system/vendor/etc/fs_config_dirs"},
{00644, AID_SYSTEM, AID_ROOT, 0, "system/oem/etc/fs_config_dirs"},
{00644, AID_SYSTEM, AID_ROOT, 0, "system/odm/etc/fs_config_dirs"},
{00644, AID_SYSTEM, AID_ROOT, 0, "system/vendor/etc/fs_config_files"},
{00644, AID_SYSTEM, AID_ROOT, 0, "system/oem/etc/fs_config_files"},
{00644, AID_SYSTEM, AID_ROOT, 0, "system/odm/etc/fs_config_files"},
{00644, AID_SYSTEM, AID_ROOT, 0, "etc/fs_config_files"},
{00666, AID_ROOT, AID_SYSTEM, 0, "data/misc/oem"},
};

View File

@ -14,9 +14,11 @@
* limitations under the License.
*/
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <private/android_filesystem_config.h>
@ -35,35 +37,50 @@
#endif
#ifdef NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRS
static const struct fs_path_config android_device_dirs[] = {
};
static const struct fs_path_config android_device_dirs[] = { };
#endif
#ifdef NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_FILES
static const struct fs_path_config android_device_files[] = {
#ifdef NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRS
{ 0, AID_ROOT, AID_ROOT, 0, "system/etc/fs_config_dirs" },
{0000, AID_ROOT, AID_ROOT, 0, "system/etc/fs_config_dirs"},
{0000, AID_ROOT, AID_ROOT, 0, "vendor/etc/fs_config_dirs"},
{0000, AID_ROOT, AID_ROOT, 0, "oem/etc/fs_config_dirs"},
{0000, AID_ROOT, AID_ROOT, 0, "odm/etc/fs_config_dirs"},
#endif
{ 0, AID_ROOT, AID_ROOT, 0, "system/etc/fs_config_files" },
{0000, AID_ROOT, AID_ROOT, 0, "system/etc/fs_config_files"},
{0000, AID_ROOT, AID_ROOT, 0, "vendor/etc/fs_config_files"},
{0000, AID_ROOT, AID_ROOT, 0, "oem/etc/fs_config_files"},
{0000, AID_ROOT, AID_ROOT, 0, "odm/etc/fs_config_files"},
};
#endif
static void usage() {
fprintf(stderr,
"Generate binary content for fs_config_dirs (-D) and fs_config_files (-F)\n"
"from device-specific android_filesystem_config.h override\n\n"
"Usage: fs_config_generate -D|-F [-o output-file]\n");
"from device-specific android_filesystem_config.h override. Filter based\n"
"on a comma separated partition list (-P) whitelist or prefixed by a\n"
"minus blacklist. Partitions are identified as path references to\n"
"<partition>/ or system/<partition>/\n\n"
"Usage: fs_config_generate -D|-F [-P list] [-o output-file]\n");
}
int main(int argc, char** argv) {
const struct fs_path_config *pc;
const struct fs_path_config *end;
bool dir = false, file = false;
FILE *fp = stdout;
int opt;
/* If tool switches to C++, use android-base/macros.h array_size() */
#ifndef ARRAY_SIZE /* popular macro */
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#endif
while((opt = getopt(argc, argv, "DFho:")) != -1) {
switch(opt) {
int main(int argc, char** argv) {
const struct fs_path_config* pc;
const struct fs_path_config* end;
bool dir = false, file = false;
const char* partitions = NULL;
FILE* fp = stdout;
int opt;
static const char optstring[] = "DFP:ho:";
while ((opt = getopt(argc, argv, optstring)) != -1) {
switch (opt) {
case 'D':
if (file) {
fprintf(stderr, "Must specify only -D or -F\n");
@ -80,6 +97,30 @@ int main(int argc, char** argv) {
}
file = true;
break;
case 'P':
if (partitions) {
fprintf(stderr, "Specify only one partition list\n");
usage();
exit(EXIT_FAILURE);
}
while (*optarg && isspace(*optarg)) ++optarg;
if (!optarg[0]) {
fprintf(stderr, "Partition list empty\n");
usage();
exit(EXIT_FAILURE);
}
if (!optarg[1]) {
fprintf(stderr, "Partition list too short \"%s\"\n", optarg);
usage();
exit(EXIT_FAILURE);
}
if ((optarg[0] == '-') && strchr(optstring, optarg[1]) && !optarg[2]) {
fprintf(stderr, "Partition list is a flag \"%s\"\n", optarg);
usage();
exit(EXIT_FAILURE);
}
partitions = optarg;
break;
case 'o':
if (fp != stdout) {
fprintf(stderr, "Specify only one output file\n");
@ -101,6 +142,12 @@ int main(int argc, char** argv) {
}
}
if (optind < argc) {
fprintf(stderr, "Unknown non-argument \"%s\"\n", argv[optind]);
usage();
exit(EXIT_FAILURE);
}
if (!file && !dir) {
fprintf(stderr, "Must specify either -F or -D\n");
usage();
@ -109,19 +156,64 @@ int main(int argc, char** argv) {
if (dir) {
pc = android_device_dirs;
end = &android_device_dirs[sizeof(android_device_dirs) / sizeof(android_device_dirs[0])];
end = &android_device_dirs[ARRAY_SIZE(android_device_dirs)];
} else {
pc = android_device_files;
end = &android_device_files[sizeof(android_device_files) / sizeof(android_device_files[0])];
end = &android_device_files[ARRAY_SIZE(android_device_files)];
}
for(; (pc < end) && pc->prefix; pc++) {
for (; (pc < end) && pc->prefix; pc++) {
bool submit;
char buffer[512];
ssize_t len = fs_config_generate(buffer, sizeof(buffer), pc);
if (len < 0) {
fprintf(stderr, "Entry too large\n");
exit(EXIT_FAILURE);
}
if (fwrite(buffer, 1, len, fp) != (size_t)len) {
submit = true;
if (partitions) {
char* partitions_copy = strdup(partitions);
char* arg = partitions_copy;
char* sv = NULL; /* Do not leave uninitialized, NULL is known safe. */
/* Deal with case all iterated partitions are blacklists with no match */
bool all_blacklist_but_no_match = true;
submit = false;
if (!partitions_copy) {
fprintf(stderr, "Failed to allocate a copy of %s\n", partitions);
exit(EXIT_FAILURE);
}
/* iterate through (officially) comma separated list of partitions */
while (!!(arg = strtok_r(arg, ",:; \t\n\r\f", &sv))) {
static const char system[] = "system/";
size_t plen;
bool blacklist = false;
if (*arg == '-') {
blacklist = true;
++arg;
} else {
all_blacklist_but_no_match = false;
}
plen = strlen(arg);
/* deal with evil callers */
while (arg[plen - 1] == '/') {
--plen;
}
/* check if we have <partition>/ or /system/<partition>/ */
if ((!strncmp(pc->prefix, arg, plen) && (pc->prefix[plen] == '/')) ||
(!strncmp(pc->prefix, system, strlen(system)) &&
!strncmp(pc->prefix + strlen(system), arg, plen) &&
(pc->prefix[strlen(system) + plen] == '/'))) {
all_blacklist_but_no_match = false;
/* we have a match !!! */
if (!blacklist) submit = true;
break;
}
arg = NULL;
}
free(partitions_copy);
if (all_blacklist_but_no_match) submit = true;
}
if (submit && (fwrite(buffer, 1, len, fp) != (size_t)len)) {
fprintf(stderr, "Write failure\n");
exit(EXIT_FAILURE);
}

View File

@ -18,9 +18,11 @@
#include <sys/cdefs.h>
#include <string>
#include <vector>
#include <android-base/file.h>
#include <android-base/macros.h>
#include <android-base/strings.h>
#include <android-base/stringprintf.h>
#include <gtest/gtest.h>
#include <private/android_filesystem_config.h>
@ -84,3 +86,138 @@ TEST(fs_conf_test, files) {
android::base::StringPrintf("%s -F", fs_config_generate_command)),
android_device_files, arraysize(android_device_files));
}
static const char vendor_str[] = "vendor/";
static const char vendor_alt_str[] = "system/vendor/";
static const char oem_str[] = "oem/";
static const char oem_alt_str[] = "system/oem/";
static const char odm_str[] = "odm/";
static const char odm_alt_str[] = "system/odm/";
TEST(fs_conf_test, system_dirs) {
std::vector<fs_path_config> dirs;
const fs_path_config* config = android_device_dirs;
for (size_t num = arraysize(android_device_dirs); num; --num) {
if (!android::base::StartsWith(config->prefix, vendor_str) &&
!android::base::StartsWith(config->prefix, vendor_alt_str) &&
!android::base::StartsWith(config->prefix, oem_str) &&
!android::base::StartsWith(config->prefix, oem_alt_str) &&
!android::base::StartsWith(config->prefix, odm_str) &&
!android::base::StartsWith(config->prefix, odm_alt_str)) {
dirs.emplace_back(*config);
}
++config;
}
confirm(popenToString(android::base::StringPrintf(
"%s -D -P -vendor,-oem,-odm", fs_config_generate_command)),
&dirs[0], dirs.size());
}
TEST(fs_conf_test, vendor_dirs) {
std::vector<fs_path_config> dirs;
const fs_path_config* config = android_device_dirs;
for (size_t num = arraysize(android_device_dirs); num; --num) {
if (android::base::StartsWith(config->prefix, vendor_str) ||
android::base::StartsWith(config->prefix, vendor_alt_str)) {
dirs.emplace_back(*config);
}
++config;
}
confirm(popenToString(android::base::StringPrintf(
"%s -D -P vendor", fs_config_generate_command)),
&dirs[0], dirs.size());
}
TEST(fs_conf_test, oem_dirs) {
std::vector<fs_path_config> dirs;
const fs_path_config* config = android_device_dirs;
for (size_t num = arraysize(android_device_dirs); num; --num) {
if (android::base::StartsWith(config->prefix, oem_str) ||
android::base::StartsWith(config->prefix, oem_alt_str)) {
dirs.emplace_back(*config);
}
++config;
}
confirm(popenToString(android::base::StringPrintf(
"%s -D -P oem", fs_config_generate_command)),
&dirs[0], dirs.size());
}
TEST(fs_conf_test, odm_dirs) {
std::vector<fs_path_config> dirs;
const fs_path_config* config = android_device_dirs;
for (size_t num = arraysize(android_device_dirs); num; --num) {
if (android::base::StartsWith(config->prefix, odm_str) ||
android::base::StartsWith(config->prefix, odm_alt_str)) {
dirs.emplace_back(*config);
}
++config;
}
confirm(popenToString(android::base::StringPrintf(
"%s -D -P odm", fs_config_generate_command)),
&dirs[0], dirs.size());
}
TEST(fs_conf_test, system_files) {
std::vector<fs_path_config> files;
const fs_path_config* config = android_device_files;
for (size_t num = arraysize(android_device_files); num; --num) {
if (!android::base::StartsWith(config->prefix, vendor_str) &&
!android::base::StartsWith(config->prefix, vendor_alt_str) &&
!android::base::StartsWith(config->prefix, oem_str) &&
!android::base::StartsWith(config->prefix, oem_alt_str) &&
!android::base::StartsWith(config->prefix, odm_str) &&
!android::base::StartsWith(config->prefix, odm_alt_str)) {
files.emplace_back(*config);
}
++config;
}
confirm(popenToString(android::base::StringPrintf(
"%s -F -P -vendor,-oem,-odm", fs_config_generate_command)),
&files[0], files.size());
}
TEST(fs_conf_test, vendor_files) {
std::vector<fs_path_config> files;
const fs_path_config* config = android_device_files;
for (size_t num = arraysize(android_device_files); num; --num) {
if (android::base::StartsWith(config->prefix, vendor_str) ||
android::base::StartsWith(config->prefix, vendor_alt_str)) {
files.emplace_back(*config);
}
++config;
}
confirm(popenToString(android::base::StringPrintf(
"%s -F -P vendor", fs_config_generate_command)),
&files[0], files.size());
}
TEST(fs_conf_test, oem_files) {
std::vector<fs_path_config> files;
const fs_path_config* config = android_device_files;
for (size_t num = arraysize(android_device_files); num; --num) {
if (android::base::StartsWith(config->prefix, oem_str) ||
android::base::StartsWith(config->prefix, oem_alt_str)) {
files.emplace_back(*config);
}
++config;
}
confirm(popenToString(android::base::StringPrintf(
"%s -F -P oem", fs_config_generate_command)),
&files[0], files.size());
}
TEST(fs_conf_test, odm_files) {
std::vector<fs_path_config> files;
const fs_path_config* config = android_device_files;
for (size_t num = arraysize(android_device_files); num; --num) {
if (android::base::StartsWith(config->prefix, odm_str) ||
android::base::StartsWith(config->prefix, odm_alt_str)) {
files.emplace_back(*config);
}
++config;
}
confirm(popenToString(android::base::StringPrintf(
"%s -F -P odm", fs_config_generate_command)),
&files[0], files.size());
}