blob: dddd331741037deb960cf0a047b3d0dc7606aa59 [file] [log] [blame]
Mark Salyzyn06b91b92015-04-01 14:41:29 -07001/*
2 * Copyright (C) 2015 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 Salyzyn256d3392017-03-22 08:46:55 -070017#include <ctype.h>
Mark Salyzyn06b91b92015-04-01 14:41:29 -070018#include <stdbool.h>
19#include <stdio.h>
20#include <stdlib.h>
Mark Salyzyn256d3392017-03-22 08:46:55 -070021#include <string.h>
Mark Salyzyn06b91b92015-04-01 14:41:29 -070022#include <unistd.h>
23
24#include <private/android_filesystem_config.h>
25
26/*
27 * This program expects android_device_dirs and android_device_files
28 * to be defined in the supplied android_filesystem_config.h file in
29 * the device/<vendor>/<product> $(TARGET_DEVICE_DIR). Then generates
30 * the binary format used in the /system/etc/fs_config_dirs and
31 * the /system/etc/fs_config_files to be used by the runtimes.
32 */
Mark Salyzyn5649b312017-03-22 08:46:55 -070033#ifdef ANDROID_FILESYSTEM_CONFIG
34#include ANDROID_FILESYSTEM_CONFIG
35#else
Mark Salyzyn06b91b92015-04-01 14:41:29 -070036#include "android_filesystem_config.h"
Mark Salyzyn5649b312017-03-22 08:46:55 -070037#endif
Mark Salyzyn06b91b92015-04-01 14:41:29 -070038
39#ifdef NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRS
Mark Salyzyn256d3392017-03-22 08:46:55 -070040static const struct fs_path_config android_device_dirs[] = { };
Mark Salyzyn06b91b92015-04-01 14:41:29 -070041#endif
42
43#ifdef NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_FILES
Mark Salyzyn640816e2018-12-11 09:38:17 -080044static const struct fs_path_config android_device_files[] = { };
Mark Salyzyn06b91b92015-04-01 14:41:29 -070045#endif
46
47static void usage() {
48 fprintf(stderr,
49 "Generate binary content for fs_config_dirs (-D) and fs_config_files (-F)\n"
Mark Salyzyn256d3392017-03-22 08:46:55 -070050 "from device-specific android_filesystem_config.h override. Filter based\n"
51 "on a comma separated partition list (-P) whitelist or prefixed by a\n"
52 "minus blacklist. Partitions are identified as path references to\n"
53 "<partition>/ or system/<partition>/\n\n"
54 "Usage: fs_config_generate -D|-F [-P list] [-o output-file]\n");
Mark Salyzyn06b91b92015-04-01 14:41:29 -070055}
56
Mark Salyzyn256d3392017-03-22 08:46:55 -070057/* If tool switches to C++, use android-base/macros.h array_size() */
58#ifndef ARRAY_SIZE /* popular macro */
59#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
60#endif
Mark Salyzyn06b91b92015-04-01 14:41:29 -070061
Mark Salyzyn256d3392017-03-22 08:46:55 -070062int main(int argc, char** argv) {
63 const struct fs_path_config* pc;
64 const struct fs_path_config* end;
65 bool dir = false, file = false;
66 const char* partitions = NULL;
67 FILE* fp = stdout;
68 int opt;
69 static const char optstring[] = "DFP:ho:";
70
71 while ((opt = getopt(argc, argv, optstring)) != -1) {
72 switch (opt) {
Mark Salyzyn06b91b92015-04-01 14:41:29 -070073 case 'D':
74 if (file) {
75 fprintf(stderr, "Must specify only -D or -F\n");
76 usage();
77 exit(EXIT_FAILURE);
78 }
79 dir = true;
80 break;
81 case 'F':
82 if (dir) {
83 fprintf(stderr, "Must specify only -F or -D\n");
84 usage();
85 exit(EXIT_FAILURE);
86 }
87 file = true;
88 break;
Mark Salyzyn256d3392017-03-22 08:46:55 -070089 case 'P':
90 if (partitions) {
91 fprintf(stderr, "Specify only one partition list\n");
92 usage();
93 exit(EXIT_FAILURE);
94 }
95 while (*optarg && isspace(*optarg)) ++optarg;
96 if (!optarg[0]) {
97 fprintf(stderr, "Partition list empty\n");
98 usage();
99 exit(EXIT_FAILURE);
100 }
101 if (!optarg[1]) {
102 fprintf(stderr, "Partition list too short \"%s\"\n", optarg);
103 usage();
104 exit(EXIT_FAILURE);
105 }
106 if ((optarg[0] == '-') && strchr(optstring, optarg[1]) && !optarg[2]) {
107 fprintf(stderr, "Partition list is a flag \"%s\"\n", optarg);
108 usage();
109 exit(EXIT_FAILURE);
110 }
111 partitions = optarg;
112 break;
Mark Salyzyn06b91b92015-04-01 14:41:29 -0700113 case 'o':
114 if (fp != stdout) {
115 fprintf(stderr, "Specify only one output file\n");
116 usage();
117 exit(EXIT_FAILURE);
118 }
Mark Salyzyn60240692015-04-16 08:42:19 -0700119 fp = fopen(optarg, "wb");
Mark Salyzyn06b91b92015-04-01 14:41:29 -0700120 if (fp == NULL) {
121 fprintf(stderr, "Can not open \"%s\"\n", optarg);
122 exit(EXIT_FAILURE);
123 }
124 break;
125 case 'h':
126 usage();
127 exit(EXIT_SUCCESS);
128 default:
129 usage();
130 exit(EXIT_FAILURE);
131 }
132 }
133
Mark Salyzyn256d3392017-03-22 08:46:55 -0700134 if (optind < argc) {
135 fprintf(stderr, "Unknown non-argument \"%s\"\n", argv[optind]);
136 usage();
137 exit(EXIT_FAILURE);
138 }
139
Mark Salyzyn06b91b92015-04-01 14:41:29 -0700140 if (!file && !dir) {
141 fprintf(stderr, "Must specify either -F or -D\n");
142 usage();
143 exit(EXIT_FAILURE);
144 }
145
146 if (dir) {
147 pc = android_device_dirs;
Mark Salyzyn256d3392017-03-22 08:46:55 -0700148 end = &android_device_dirs[ARRAY_SIZE(android_device_dirs)];
Mark Salyzyn06b91b92015-04-01 14:41:29 -0700149 } else {
150 pc = android_device_files;
Mark Salyzyn256d3392017-03-22 08:46:55 -0700151 end = &android_device_files[ARRAY_SIZE(android_device_files)];
Mark Salyzyn06b91b92015-04-01 14:41:29 -0700152 }
Mark Salyzyn256d3392017-03-22 08:46:55 -0700153 for (; (pc < end) && pc->prefix; pc++) {
154 bool submit;
Mark Salyzyn06b91b92015-04-01 14:41:29 -0700155 char buffer[512];
156 ssize_t len = fs_config_generate(buffer, sizeof(buffer), pc);
157 if (len < 0) {
158 fprintf(stderr, "Entry too large\n");
159 exit(EXIT_FAILURE);
160 }
Mark Salyzyn256d3392017-03-22 08:46:55 -0700161 submit = true;
162 if (partitions) {
163 char* partitions_copy = strdup(partitions);
164 char* arg = partitions_copy;
165 char* sv = NULL; /* Do not leave uninitialized, NULL is known safe. */
166 /* Deal with case all iterated partitions are blacklists with no match */
167 bool all_blacklist_but_no_match = true;
168 submit = false;
169
170 if (!partitions_copy) {
171 fprintf(stderr, "Failed to allocate a copy of %s\n", partitions);
172 exit(EXIT_FAILURE);
173 }
174 /* iterate through (officially) comma separated list of partitions */
175 while (!!(arg = strtok_r(arg, ",:; \t\n\r\f", &sv))) {
176 static const char system[] = "system/";
177 size_t plen;
178 bool blacklist = false;
179 if (*arg == '-') {
180 blacklist = true;
181 ++arg;
182 } else {
183 all_blacklist_but_no_match = false;
184 }
185 plen = strlen(arg);
186 /* deal with evil callers */
187 while (arg[plen - 1] == '/') {
188 --plen;
189 }
190 /* check if we have <partition>/ or /system/<partition>/ */
191 if ((!strncmp(pc->prefix, arg, plen) && (pc->prefix[plen] == '/')) ||
192 (!strncmp(pc->prefix, system, strlen(system)) &&
193 !strncmp(pc->prefix + strlen(system), arg, plen) &&
194 (pc->prefix[strlen(system) + plen] == '/'))) {
195 all_blacklist_but_no_match = false;
196 /* we have a match !!! */
197 if (!blacklist) submit = true;
198 break;
199 }
200 arg = NULL;
201 }
202 free(partitions_copy);
203 if (all_blacklist_but_no_match) submit = true;
204 }
205 if (submit && (fwrite(buffer, 1, len, fp) != (size_t)len)) {
Mark Salyzyn06b91b92015-04-01 14:41:29 -0700206 fprintf(stderr, "Write failure\n");
207 exit(EXIT_FAILURE);
208 }
209 }
210 fclose(fp);
211
212 return 0;
213}