summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDima Zavin <dima@android.com>2011-12-16 14:20:12 -0800
committerJean-Baptiste Queru <jbq@google.com>2012-01-11 04:35:53 -0800
commita6235eacf4b06b14b19125618d7aca570dbc02b0 (patch)
tree148e90f51bf81d374cfab57ff79cd6972b11f14f
parentd7634c9cdad7bec39294a993b0bc898eaf709829 (diff)
downloadsystem_core-a6235eacf4b06b14b19125618d7aca570dbc02b0.zip
system_core-a6235eacf4b06b14b19125618d7aca570dbc02b0.tar.gz
system_core-a6235eacf4b06b14b19125618d7aca570dbc02b0.tar.bz2
init: allow init file imports to use properties in names
Adds new property syntax in init files during init file filename expansion during the import command: ${prop.name} So, one can do: import /init.${ro.hardware}.usb.rc Should convert other usages of property names to use the new function. Change-Id: I9205d7d7a2da620bc8e6b89ac0eb554fad53ded3 Signed-off-by: Dima Zavin <dima@android.com>
-rw-r--r--init/init_parser.c141
1 files changed, 136 insertions, 5 deletions
diff --git a/init/init_parser.c b/init/init_parser.c
index 13c94eb..5e07b34 100644
--- a/init/init_parser.c
+++ b/init/init_parser.c
@@ -159,6 +159,124 @@ void parse_line_no_op(struct parse_state *state, int nargs, char **args)
{
}
+static int push_chars(char **dst, int *len, const char *chars, int cnt)
+{
+ if (cnt > *len)
+ return -1;
+
+ memcpy(*dst, chars, cnt);
+ *dst += cnt;
+ *len -= cnt;
+
+ return 0;
+}
+
+static int expand_props(char *dst, const char *src, int dst_size)
+{
+ int cnt = 0;
+ char *dst_ptr = dst;
+ const char *src_ptr = src;
+ int src_len;
+ int idx = 0;
+ int ret = 0;
+ int left = dst_size - 1;
+
+ if (!src || !dst || dst_size == 0)
+ return -1;
+
+ src_len = strlen(src);
+
+ /* - variables can either be $x.y or ${x.y}, in case they are only part
+ * of the string.
+ * - will accept $$ as a literal $.
+ * - no nested property expansion, i.e. ${foo.${bar}} is not supported,
+ * bad things will happen
+ */
+ while (*src_ptr && left > 0) {
+ char *c;
+ char prop[PROP_NAME_MAX + 1];
+ const char *prop_val;
+ int prop_len = 0;
+
+ c = strchr(src_ptr, '$');
+ if (!c) {
+ while (left-- > 0 && *src_ptr)
+ *(dst_ptr++) = *(src_ptr++);
+ break;
+ }
+
+ memset(prop, 0, sizeof(prop));
+
+ ret = push_chars(&dst_ptr, &left, src_ptr, c - src_ptr);
+ if (ret < 0)
+ goto err_nospace;
+ c++;
+
+ if (*c == '$') {
+ *(dst_ptr++) = *(c++);
+ src_ptr = c;
+ left--;
+ continue;
+ } else if (*c == '\0') {
+ break;
+ }
+
+ if (*c == '{') {
+ c++;
+ while (*c && *c != '}' && prop_len < PROP_NAME_MAX)
+ prop[prop_len++] = *(c++);
+ if (*c != '}') {
+ /* failed to find closing brace, abort. */
+ if (prop_len == PROP_NAME_MAX)
+ ERROR("prop name too long during expansion of '%s'\n",
+ src);
+ else if (*c == '\0')
+ ERROR("unexpected end of string in '%s', looking for }\n",
+ src);
+ goto err;
+ }
+ prop[prop_len] = '\0';
+ c++;
+ } else if (*c) {
+ while (*c && prop_len < PROP_NAME_MAX)
+ prop[prop_len++] = *(c++);
+ if (prop_len == PROP_NAME_MAX && *c != '\0') {
+ ERROR("prop name too long in '%s'\n", src);
+ goto err;
+ }
+ prop[prop_len] = '\0';
+ ERROR("using deprecated syntax for specifying property '%s', use ${name} instead\n",
+ prop);
+ }
+
+ if (prop_len == 0) {
+ ERROR("invalid zero-length prop name in '%s'\n", src);
+ goto err;
+ }
+
+ prop_val = property_get(prop);
+ if (!prop_val) {
+ ERROR("property '%s' doesn't exist while expanding '%s'\n",
+ prop, src);
+ goto err;
+ }
+
+ ret = push_chars(&dst_ptr, &left, prop_val, strlen(prop_val));
+ if (ret < 0)
+ goto err_nospace;
+ src_ptr = c;
+ continue;
+ }
+
+ *dst_ptr = '\0';
+ return 0;
+
+err_nospace:
+ ERROR("destination buffer overflow while expanding '%s'\n", src);
+err:
+ return -1;
+}
+
void parse_new_section(struct parse_state *state, int kw,
int nargs, char **args)
{
@@ -180,13 +298,26 @@ void parse_new_section(struct parse_state *state, int kw,
}
break;
case K_import:
- if (nargs != 2) {
- ERROR("single argument needed for import\n");
- } else {
- int ret = init_parse_config_file(args[1]);
+ {
+ char conf_file[PATH_MAX];
+ int ret;
+
+ if (nargs != 2) {
+ ERROR("single argument needed for import\n");
+ break;
+ }
+
+ ret = expand_props(conf_file, args[1], sizeof(conf_file));
+ if (ret) {
+ ERROR("error while handling import on line '%d' in '%s'\n",
+ state->line, state->filename);
+ break;
+ }
+ ret = init_parse_config_file(conf_file);
if (ret)
- ERROR("could not import file %s\n", args[1]);
+ ERROR("could not import file '%s'\n", conf_file);
}
+ break;
}
state->parse_line = parse_line_no_op;
}