Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 829c0b8d authored by Dima Zavin's avatar Dima Zavin Committed by Android (Google) Code Review
Browse files

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
parents ae8b56c0 ebe2cb31
Loading
Loading
Loading
Loading
+16 −28
Original line number Diff line number Diff line
@@ -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);
    ret = expand_props(prop_val, value, sizeof(prop_val));
    if (ret) {
        ERROR("cannot expand '%s' while assigning to '%s'\n", value, name);
        return -EINVAL;
    }
        } /* else fall through to support double '$' prefix for setting properties
           * to string literals that start with '$'
           */
    }

    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);
    char prop_val[PROP_VALUE_MAX];
    int ret;

    ret = expand_props(prop_val, value, sizeof(prop_val));
    if (ret) {
        ERROR("cannot expand '%s' while writing to '%s'\n", value, path);
        return -EINVAL;
    }
        } /* else fall through to support double '$' prefix for writing
           * string literals that start with '$'
           */
    }

    return write_file(path, value);
    return write_file(path, prop_val);
}

int do_copy(int nargs, char **args)
+100 −78
Original line number Diff line number Diff line
@@ -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);
    }

    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);

    if (qemu[0])
        import_kernel_cmdline(1, import_kernel_nv);
    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);
+169 −8
Original line number Diff line number Diff line
@@ -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)
+1 −0
Original line number Diff line number Diff line
@@ -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
+1 −0
Original line number Diff line number Diff line
@@ -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);
Loading