Merge changes I3c284860,I06dc35ff,Iedda6c90,I933e5bba,I9205d7d7,Iae9ed109
* changes: init: use init's property expansion code for setprop/write init: delay importing files until after parsing the current file init: export all androidboot cmd line values as ro.boot.xx props init: import the hardware specific init file in init.rc init: allow init file imports to use properties in names init: initialize property area early at boot
This commit is contained in:
commit
829c0b8d9e
|
@ -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)
|
||||
|
|
178
init/init.c
178
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", },
|
||||
};
|
||||
|
||||
if (qemu[0])
|
||||
import_kernel_cmdline(1, import_kernel_nv);
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue