summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--init/builtins.c44
-rwxr-xr-xinit/init.c178
-rw-r--r--init/init_parser.c177
-rw-r--r--init/init_parser.h1
-rw-r--r--init/parser.h1
-rw-r--r--init/property_service.c9
-rw-r--r--init/property_service.h3
-rw-r--r--rootdir/init.rc2
8 files changed, 297 insertions, 118 deletions
diff --git a/init/builtins.c b/init/builtins.c
index eccda3f..3781dcd 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -31,6 +31,7 @@
#include <sys/resource.h>
#include <linux/loop.h>
#include <cutils/partition_utils.h>
+#include <sys/system_properties.h>
#include "init.h"
#include "keywords.h"
@@ -448,22 +449,15 @@ int do_setprop(int nargs, char **args)
{
const char *name = args[1];
const char *value = args[2];
+ char prop_val[PROP_VALUE_MAX];
+ int ret;
- if (value[0] == '$') {
- /* Use the value of a system property if value starts with '$' */
- value++;
- if (value[0] != '$') {
- value = property_get(value);
- if (!value) {
- ERROR("property %s has no value for assigning to %s\n", value, name);
- return -EINVAL;
- }
- } /* else fall through to support double '$' prefix for setting properties
- * to string literals that start with '$'
- */
+ ret = expand_props(prop_val, value, sizeof(prop_val));
+ if (ret) {
+ ERROR("cannot expand '%s' while assigning to '%s'\n", value, name);
+ return -EINVAL;
}
-
- property_set(name, value);
+ property_set(name, prop_val);
return 0;
}
@@ -547,21 +541,15 @@ int do_write(int nargs, char **args)
{
const char *path = args[1];
const char *value = args[2];
- if (value[0] == '$') {
- /* Write the value of a system property if value starts with '$' */
- value++;
- if (value[0] != '$') {
- value = property_get(value);
- if (!value) {
- ERROR("property %s has no value for writing to %s\n", value, path);
- return -EINVAL;
- }
- } /* else fall through to support double '$' prefix for writing
- * string literals that start with '$'
- */
- }
+ char prop_val[PROP_VALUE_MAX];
+ int ret;
- return write_file(path, value);
+ ret = expand_props(prop_val, value, sizeof(prop_val));
+ if (ret) {
+ ERROR("cannot expand '%s' while writing to '%s'\n", value, path);
+ return -EINVAL;
+ }
+ return write_file(path, prop_val);
}
int do_copy(int nargs, char **args)
diff --git a/init/init.c b/init/init.c
index d10ca47..c3be93d 100755
--- a/init/init.c
+++ b/init/init.c
@@ -59,11 +59,7 @@ static int bootchart_count;
#endif
static char console[32];
-static char serialno[32];
static char bootmode[32];
-static char baseband[32];
-static char carrier[32];
-static char bootloader[32];
static char hardware[32];
static unsigned revision = 0;
static char qemu[32];
@@ -420,45 +416,6 @@ void handle_control_message(const char *msg, const char *arg)
}
}
-static void import_kernel_nv(char *name, int in_qemu)
-{
- char *value = strchr(name, '=');
-
- if (value == 0) return;
- *value++ = 0;
- if (*name == 0) return;
-
- if (!in_qemu)
- {
- /* on a real device, white-list the kernel options */
- if (!strcmp(name,"qemu")) {
- strlcpy(qemu, value, sizeof(qemu));
- } else if (!strcmp(name,"androidboot.console")) {
- strlcpy(console, value, sizeof(console));
- } else if (!strcmp(name,"androidboot.mode")) {
- strlcpy(bootmode, value, sizeof(bootmode));
- } else if (!strcmp(name,"androidboot.serialno")) {
- strlcpy(serialno, value, sizeof(serialno));
- } else if (!strcmp(name,"androidboot.baseband")) {
- strlcpy(baseband, value, sizeof(baseband));
- } else if (!strcmp(name,"androidboot.carrier")) {
- strlcpy(carrier, value, sizeof(carrier));
- } else if (!strcmp(name,"androidboot.bootloader")) {
- strlcpy(bootloader, value, sizeof(bootloader));
- } else if (!strcmp(name,"androidboot.hardware")) {
- strlcpy(hardware, value, sizeof(hardware));
- }
- } else {
- /* in the emulator, export any kernel option with the
- * ro.kernel. prefix */
- char buff[32];
- int len = snprintf( buff, sizeof(buff), "ro.kernel.%s", name );
- if (len < (int)sizeof(buff)) {
- property_set( buff, value );
- }
- }
-}
-
static struct command *get_first_command(struct action *act)
{
struct listnode *node;
@@ -518,17 +475,6 @@ static int wait_for_coldboot_done_action(int nargs, char **args)
return ret;
}
-static int property_init_action(int nargs, char **args)
-{
- bool load_defaults = true;
-
- INFO("property init\n");
- if (!strcmp(bootmode, "charger"))
- load_defaults = false;
- property_init(load_defaults);
- return 0;
-}
-
static int keychord_init_action(int nargs, char **args)
{
keychord_init();
@@ -576,30 +522,104 @@ static int console_init_action(int nargs, char **args)
return 0;
}
-static int set_init_properties_action(int nargs, char **args)
+static void import_kernel_nv(char *name, int for_emulator)
+{
+ char *value = strchr(name, '=');
+ int name_len = strlen(name);
+
+ if (value == 0) return;
+ *value++ = 0;
+ if (name_len == 0) return;
+
+ if (for_emulator) {
+ /* in the emulator, export any kernel option with the
+ * ro.kernel. prefix */
+ char buff[PROP_NAME_MAX];
+ int len = snprintf( buff, sizeof(buff), "ro.kernel.%s", name );
+
+ if (len < (int)sizeof(buff))
+ property_set( buff, value );
+ return;
+ }
+
+ if (!strcmp(name,"qemu")) {
+ strlcpy(qemu, value, sizeof(qemu));
+ } else if (!strncmp(name, "androidboot.", 12) && name_len > 12) {
+ const char *boot_prop_name = name + 12;
+ char prop[PROP_NAME_MAX];
+ int cnt;
+
+ cnt = snprintf(prop, sizeof(prop), "ro.boot.%s", boot_prop_name);
+ if (cnt < PROP_NAME_MAX)
+ property_set(prop, value);
+ }
+}
+
+static void export_kernel_boot_props(void)
{
char tmp[PROP_VALUE_MAX];
+ const char *pval;
+ unsigned i;
+ struct {
+ const char *src_prop;
+ const char *dest_prop;
+ const char *def_val;
+ } prop_map[] = {
+ { "ro.boot.serialno", "ro.serialno", "", },
+ { "ro.boot.mode", "ro.bootmode", "unknown", },
+ { "ro.boot.baseband", "ro.baseband", "unknown", },
+ { "ro.boot.carrier", "ro.carrier", "unknown", },
+ { "ro.boot.bootloader", "ro.bootloader", "unknown", },
+ };
+
+ for (i = 0; i < ARRAY_SIZE(prop_map); i++) {
+ pval = property_get(prop_map[i].src_prop);
+ property_set(prop_map[i].dest_prop, pval ?: prop_map[i].def_val);
+ }
- if (qemu[0])
- import_kernel_cmdline(1, import_kernel_nv);
+ pval = property_get("ro.boot.console");
+ if (pval)
+ strlcpy(console, pval, sizeof(console));
+
+ /* save a copy for init's usage during boot */
+ strlcpy(bootmode, property_get("ro.bootmode"), sizeof(bootmode));
+
+ /* if this was given on kernel command line, override what we read
+ * before (e.g. from /proc/cpuinfo), if anything */
+ pval = property_get("ro.boot.hardware");
+ if (pval)
+ strlcpy(hardware, pval, sizeof(hardware));
+ property_set("ro.hardware", hardware);
+
+ snprintf(tmp, PROP_VALUE_MAX, "%d", revision);
+ property_set("ro.revision", tmp);
+ /* TODO: these are obsolete. We should delete them */
if (!strcmp(bootmode,"factory"))
property_set("ro.factorytest", "1");
else if (!strcmp(bootmode,"factory2"))
property_set("ro.factorytest", "2");
else
property_set("ro.factorytest", "0");
+}
- property_set("ro.serialno", serialno[0] ? serialno : "");
- property_set("ro.bootmode", bootmode[0] ? bootmode : "unknown");
- property_set("ro.baseband", baseband[0] ? baseband : "unknown");
- property_set("ro.carrier", carrier[0] ? carrier : "unknown");
- property_set("ro.bootloader", bootloader[0] ? bootloader : "unknown");
+static void process_kernel_cmdline(void)
+{
+ /* don't expose the raw commandline to nonpriv processes */
+ chmod("/proc/cmdline", 0440);
- property_set("ro.hardware", hardware);
- snprintf(tmp, PROP_VALUE_MAX, "%d", revision);
- property_set("ro.revision", tmp);
- return 0;
+ /* first pass does the common stuff, and finds if we are in qemu.
+ * second pass is only necessary for qemu to export all kernel params
+ * as props.
+ */
+ import_kernel_cmdline(0, import_kernel_nv);
+ if (qemu[0])
+ import_kernel_cmdline(1, import_kernel_nv);
+
+ /* now propogate the info given on command line to internal variables
+ * used by init as well as the current required properties
+ */
+ export_kernel_boot_props();
}
static int property_service_init_action(int nargs, char **args)
@@ -668,6 +688,7 @@ int main(int argc, char **argv)
int property_set_fd_init = 0;
int signal_fd_init = 0;
int keychord_fd_init = 0;
+ bool is_charger = false;
if (!strcmp(basename(argv[0]), "ueventd"))
return ueventd_main(argc, argv);
@@ -701,31 +722,32 @@ int main(int argc, char **argv)
*/
open_devnull_stdio();
klog_init();
+ property_init();
+
+ get_hardware_name(hardware, &revision);
+
+ process_kernel_cmdline();
+
+ is_charger = !strcmp(bootmode, "charger");
+
+ INFO("property init\n");
+ if (!is_charger)
+ property_load_boot_defaults();
INFO("reading config file\n");
init_parse_config_file("/init.rc");
- /* pull the kernel commandline and ramdisk properties file in */
- import_kernel_cmdline(0, import_kernel_nv);
- /* don't expose the raw commandline to nonpriv processes */
- chmod("/proc/cmdline", 0440);
- get_hardware_name(hardware, &revision);
- snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);
- init_parse_config_file(tmp);
-
action_for_each_trigger("early-init", action_add_queue_tail);
queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");
- queue_builtin_action(property_init_action, "property_init");
queue_builtin_action(keychord_init_action, "keychord_init");
queue_builtin_action(console_init_action, "console_init");
- queue_builtin_action(set_init_properties_action, "set_init_properties");
/* execute all the boot actions to get us started */
action_for_each_trigger("init", action_add_queue_tail);
/* skip mounting filesystems in charger mode */
- if (strcmp(bootmode, "charger") != 0) {
+ if (!is_charger) {
action_for_each_trigger("early-fs", action_add_queue_tail);
action_for_each_trigger("fs", action_add_queue_tail);
action_for_each_trigger("post-fs", action_add_queue_tail);
@@ -736,7 +758,7 @@ int main(int argc, char **argv)
queue_builtin_action(signal_init_action, "signal_init");
queue_builtin_action(check_startup_action, "check_startup");
- if (!strcmp(bootmode, "charger")) {
+ if (is_charger) {
action_for_each_trigger("charger", action_add_queue_tail);
} else {
action_for_each_trigger("early-boot", action_add_queue_tail);
diff --git a/init/init_parser.c b/init/init_parser.c
index 13c94eb..d255db9 100644
--- a/init/init_parser.c
+++ b/init/init_parser.c
@@ -40,6 +40,11 @@ static list_declare(service_list);
static list_declare(action_list);
static list_declare(action_queue);
+struct import {
+ struct listnode list;
+ const char *filename;
+};
+
static void *parse_service(struct parse_state *state, int nargs, char **args);
static void parse_line_service(struct parse_state *state, int nargs, char **args);
@@ -159,6 +164,149 @@ 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;
+}
+
+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_import(struct parse_state *state, int nargs, char **args)
+{
+ struct listnode *import_list = state->priv;
+ struct import *import;
+ char conf_file[PATH_MAX];
+ int ret;
+
+ if (nargs != 2) {
+ ERROR("single argument needed for import\n");
+ return;
+ }
+
+ 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);
+ return;
+ }
+
+ import = calloc(1, sizeof(struct import));
+ import->filename = strdup(conf_file);
+ list_add_tail(import_list, &import->list);
+ INFO("found import '%s', adding to import list", import->filename);
+}
+
void parse_new_section(struct parse_state *state, int kw,
int nargs, char **args)
{
@@ -180,13 +328,8 @@ 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]);
- if (ret)
- ERROR("could not import file %s\n", args[1]);
- }
+ parse_import(state, nargs, args);
+ break;
}
state->parse_line = parse_line_no_op;
}
@@ -194,6 +337,8 @@ void parse_new_section(struct parse_state *state, int kw,
static void parse_config(const char *fn, char *s)
{
struct parse_state state;
+ struct listnode import_list;
+ struct listnode *node;
char *args[INIT_PARSER_MAXARGS];
int nargs;
@@ -203,11 +348,15 @@ static void parse_config(const char *fn, char *s)
state.ptr = s;
state.nexttoken = 0;
state.parse_line = parse_line_no_op;
+
+ list_init(&import_list);
+ state.priv = &import_list;
+
for (;;) {
switch (next_token(&state)) {
case T_EOF:
state.parse_line(&state, 0, 0);
- return;
+ goto parser_done;
case T_NEWLINE:
state.line++;
if (nargs) {
@@ -228,6 +377,18 @@ static void parse_config(const char *fn, char *s)
break;
}
}
+
+parser_done:
+ list_for_each(node, &import_list) {
+ struct import *import = node_to_item(node, struct import, list);
+ int ret;
+
+ INFO("importing '%s'", import->filename);
+ ret = init_parse_config_file(import->filename);
+ if (ret)
+ ERROR("could not import file '%s' from '%s'\n",
+ import->filename, fn);
+ }
}
int init_parse_config_file(const char *fn)
diff --git a/init/init_parser.h b/init/init_parser.h
index ff13b04..b078cad 100644
--- a/init/init_parser.h
+++ b/init/init_parser.h
@@ -31,5 +31,6 @@ void queue_all_property_triggers();
void queue_builtin_action(int (*func)(int nargs, char **args), char *name);
int init_parse_config_file(const char *fn);
+int expand_props(char *dst, const char *src, int len);
#endif
diff --git a/init/parser.h b/init/parser.h
index be93758..0a5802a 100644
--- a/init/parser.h
+++ b/init/parser.h
@@ -30,6 +30,7 @@ struct parse_state
void *context;
void (*parse_line)(struct parse_state *state, int nargs, char **args);
const char *filename;
+ void *priv;
};
int lookup_keyword(const char *s);
diff --git a/init/property_service.c b/init/property_service.c
index 687de6d..d06df31 100644
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -490,11 +490,14 @@ static void load_persistent_properties()
persistent_properties_loaded = 1;
}
-void property_init(bool load_defaults)
+void property_init(void)
{
init_property_area();
- if (load_defaults)
- load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT);
+}
+
+void property_load_boot_defaults(void)
+{
+ load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT);
}
int properties_inited(void)
diff --git a/init/property_service.h b/init/property_service.h
index 37c2788..b9d1bf6 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -20,7 +20,8 @@
#include <stdbool.h>
extern void handle_property_set_fd(void);
-extern void property_init(bool load_defaults);
+extern void property_init(void);
+extern void property_load_boot_defaults(void);
extern void load_persist_props(void);
extern void start_property_service(void);
void get_property_workspace(int *fd, int *sz);
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 822ae02..8041b93 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -1,3 +1,5 @@
+import /init.${ro.hardware}.rc
+
on early-init
# Set init and its forked children's oom_adj.
write /proc/1/oom_adj -16