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

Commit 132ac31b authored by Wei Wang's avatar Wei Wang
Browse files

init: add wait_for_prop builtin command

There are many use cases from vendors to exec service in background and then
use a shell scriprt to wait for the command done.

This CL is to add a wait_for_prop command to suppor those use cases.

Bug: 34746108
Test: on marlin
Change-Id: Ia81290b0928f9d375710d2daa546714f0cd65b72
parent afe25958
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -298,7 +298,8 @@ Commands
> Fork and execute command with the given arguments. The command starts
  after "--" so that an optional security context, user, and supplementary
  groups can be provided. No other commands will be run until this one
  finishes. _seclabel_ can be a - to denote default.
  finishes. _seclabel_ can be a - to denote default. Properties are expanded
  within _argument_.

`export <name> <value>`
> Set the environment variable _name_ equal to _value_ in the
@@ -412,6 +413,11 @@ Commands
  or the timeout has been reached. If timeout is not specified it
  currently defaults to five seconds.

`wait_for_prop <name> <value>`
> Wait for system property _name_ to be _value_. Properties are expanded
  within _value_. If property _name_ is already set to _value_, continue
  immediately.

`write <path> <content>`
> Open the file at _path_ and write a string to it with write(2).
  If the file does not exist, it will be created. If it does exist,
+24 −0
Original line number Diff line number Diff line
@@ -1003,6 +1003,29 @@ static int do_wait(const std::vector<std::string>& args) {
    return -1;
}

static int do_wait_for_prop(const std::vector<std::string>& args) {
    const char* name = args[1].c_str();
    const char* value = args[2].c_str();
    size_t value_len = strlen(value);

    if (!is_legal_property_name(name)) {
        LOG(ERROR) << "do_wait_for_prop(\"" << name << "\", \"" << value
                   << "\") failed: bad name";
        return -1;
    }
    if (value_len >= PROP_VALUE_MAX) {
        LOG(ERROR) << "do_wait_for_prop(\"" << name << "\", \"" << value
                   << "\") failed: value too long";
        return -1;
    }
    if (!wait_property(name, value)) {
        LOG(ERROR) << "do_wait_for_prop(\"" << name << "\", \"" << value
                   << "\") failed: init already in waiting";
        return -1;
    }
    return 0;
}

/*
 * Callback to make a directory from the ext4 code
 */
@@ -1074,6 +1097,7 @@ BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
        {"verity_load_state",       {0,     0,    do_verity_load_state}},
        {"verity_update_state",     {0,     0,    do_verity_update_state}},
        {"wait",                    {1,     2,    do_wait}},
        {"wait_for_prop",           {2,     2,    do_wait_for_prop}},
        {"write",                   {2,     2,    do_write}},
    };
    return builtin_functions;
+29 −1
Original line number Diff line number Diff line
@@ -87,6 +87,10 @@ bool waiting_for_exec = false;

static int epoll_fd = -1;

static std::unique_ptr<Timer> waiting_for_prop(nullptr);
static std::string wait_prop_name;
static std::string wait_prop_value;

void register_epoll_handler(int fd, void (*fn)()) {
    epoll_event ev;
    ev.events = EPOLLIN;
@@ -128,10 +132,34 @@ int add_environment(const char *key, const char *val)
    return -1;
}

bool wait_property(const char *name, const char *value)
{
    if (waiting_for_prop) {
        return false;
    }
    if (property_get(name) != value) {
        // Current property value is not equal to expected value
        wait_prop_name = name;
        wait_prop_value = value;
        waiting_for_prop.reset(new Timer());
    } else {
        LOG(INFO) << "wait_property(\"" << name << "\", \"" << value << "\"): already set";
    }
    return true;
}

void property_changed(const char *name, const char *value)
{
    if (property_triggers_enabled)
        ActionManager::GetInstance().QueuePropertyTrigger(name, value);
    if (waiting_for_prop) {
        if (wait_prop_name == name && wait_prop_value == value) {
            wait_prop_name.clear();
            wait_prop_value.clear();
            LOG(INFO) << "Wait for property took " << *waiting_for_prop;
            waiting_for_prop.reset();
        }
    }
}

static void restart_processes()
@@ -876,7 +904,7 @@ int main(int argc, char** argv) {
    am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");

    while (true) {
        if (!waiting_for_exec) {
        if (!(waiting_for_exec || waiting_for_prop)) {
            am.ExecuteOneCommand();
            restart_processes();
        }
+2 −0
Original line number Diff line number Diff line
@@ -36,4 +36,6 @@ void register_epoll_handler(int fd, void (*fn)());

int add_environment(const char* key, const char* val);

bool wait_property(const char *name, const char *value);

#endif  /* _INIT_INIT_H */