diff options
author | San Mehat <san@google.com> | 2009-05-19 13:30:46 -0700 |
---|---|---|
committer | San Mehat <san@google.com> | 2009-05-19 13:33:07 -0700 |
commit | f24e252903ca0f71c7fbfb135cf17e83e0c2ea90 (patch) | |
tree | 65d2499db0682ad75bbd21a365bfcfc00756d3a3 /init | |
parent | 1b154930b2c2634dce9c04d5d5cec7acb229ccb0 (diff) | |
download | system_core-f24e252903ca0f71c7fbfb135cf17e83e0c2ea90.zip system_core-f24e252903ca0f71c7fbfb135cf17e83e0c2ea90.tar.gz system_core-f24e252903ca0f71c7fbfb135cf17e83e0c2ea90.tar.bz2 |
init: Add the ability to start services with dynamic arguments.
To add arguments dynamically to a service, start the service like so:
setprop ctl.start service_to_run:arg1 arg2 arg3...
To start a service with *no* dynamic arguments, start the service normally:
setprop ctl.start service_to_run
Dynamic arguments are only supported on 'oneshot' services
Signed-off-by: San Mehat <san@google.com>
Diffstat (limited to 'init')
-rw-r--r-- | init/builtins.c | 6 | ||||
-rw-r--r-- | init/init.c | 77 | ||||
-rw-r--r-- | init/init.h | 4 | ||||
-rw-r--r-- | init/parser.c | 6 |
4 files changed, 79 insertions, 14 deletions
diff --git a/init/builtins.c b/init/builtins.c index 95fb223..17df0af 100644 --- a/init/builtins.c +++ b/init/builtins.c @@ -126,7 +126,7 @@ done: static void service_start_if_not_disabled(struct service *svc) { if (!(svc->flags & SVC_DISABLED)) { - service_start(svc); + service_start(svc, NULL); } } @@ -316,7 +316,7 @@ int do_start(int nargs, char **args) struct service *svc; svc = service_find_by_name(args[1]); if (svc) { - service_start(svc); + service_start(svc, NULL); } return 0; } @@ -337,7 +337,7 @@ int do_restart(int nargs, char **args) svc = service_find_by_name(args[1]); if (svc) { service_stop(svc); - service_start(svc); + service_start(svc, NULL); } return 0; } diff --git a/init/init.c b/init/init.c index a748ec3..b350569 100644 --- a/init/init.c +++ b/init/init.c @@ -156,7 +156,7 @@ static void publish_socket(const char *name, int fd) fcntl(fd, F_SETFD, 0); } -void service_start(struct service *svc) +void service_start(struct service *svc, const char *dynamic_args) { struct stat s; pid_t pid; @@ -192,6 +192,12 @@ void service_start(struct service *svc) return; } + if ((!(svc->flags & SVC_ONESHOT)) && dynamic_args) { + ERROR("service '%s' must be one-shot to use dynamic args, disabling\n", svc->args[0]); + svc->flags |= SVC_DISABLED; + return; + } + NOTICE("starting '%s'\n", svc->name); pid = fork(); @@ -248,7 +254,50 @@ void service_start(struct service *svc) setuid(svc->uid); } - execve(svc->args[0], (char**) svc->args, (char**) ENV); + if (!dynamic_args) + execve(svc->args[0], (char**) svc->args, (char**) ENV); + else { + char *arg_ptrs[SVC_MAXARGS+1]; + int arg_idx; + char *tmp = strdup(dynamic_args); + char *p = tmp; + + /* Copy the static arguments */ + for (arg_idx = 0; arg_idx < svc->nargs; arg_idx++) { + arg_ptrs[arg_idx] = svc->args[arg_idx]; + } + + int done = 0; + while(!done) { + + if (arg_idx == SVC_MAXARGS) + break; + + /* Advance over any leading whitespace */ + if (*p == ' ') { + for (p; *p != ' '; p++); + p++; + } + /* Locate next argument */ + char *q = p; + while(1) { + if (*q == ' ') { + *q = '\0'; + break; + } else if (*q == '\0') { + done = 1; + break; + } + q++; + } + arg_ptrs[arg_idx++] = p; + + q++; // Advance q to the next string + p = q; + } + arg_ptrs[arg_idx] = '\0'; + execve(svc->args[0], (char**) arg_ptrs, (char**) ENV); + } _exit(127); } @@ -379,7 +428,7 @@ static void restart_service_if_needed(struct service *svc) if (next_start_time <= gettime()) { svc->flags &= (~SVC_RESTARTING); - service_start(svc); + service_start(svc, NULL); return; } @@ -405,13 +454,29 @@ static void sigchld_handler(int s) static void msg_start(const char *name) { - struct service *svc = service_find_by_name(name); + struct service *svc; + char *tmp = NULL; + char *args = NULL; + + if (!strchr(name, ':')) + svc = service_find_by_name(name); + else { + tmp = strdup(name); + strcpy(tmp, name); + args = strchr(tmp, ':'); + *args = '\0'; + args++; + + svc = service_find_by_name(tmp); + } if (svc) { - service_start(svc); + service_start(svc, args); } else { ERROR("no such service '%s'\n", name); } + if (tmp) + free(tmp); } static void msg_stop(const char *name) @@ -737,7 +802,7 @@ void handle_keychord(int fd) svc = service_find_by_keychord(id); if (svc) { INFO("starting service %s from keychord\n", svc->name); - service_start(svc); + service_start(svc, NULL); } else { ERROR("service for keychord %d not found\n", id); } diff --git a/init/init.h b/init/init.h index b93eb50..f306b7b 100644 --- a/init/init.h +++ b/init/init.h @@ -116,6 +116,8 @@ struct svcenvinfo { #define NR_SVC_SUPP_GIDS 6 /* six supplementary groups */ +#define SVC_MAXARGS 64 + struct service { /* list of all services */ struct listnode slist; @@ -160,7 +162,7 @@ void service_for_each_class(const char *classname, void service_for_each_flags(unsigned matchflags, void (*func)(struct service *svc)); void service_stop(struct service *svc); -void service_start(struct service *svc); +void service_start(struct service *svc, const char *dynamic_args); void property_changed(const char *name, const char *value); struct action *action_remove_queue_head(void); diff --git a/init/parser.c b/init/parser.c index 30fa3de..33c1a68 100644 --- a/init/parser.c +++ b/init/parser.c @@ -60,8 +60,6 @@ void DUMP(void) #endif } -#define MAXARGS 64 - #define T_EOF 0 #define T_TEXT 1 #define T_NEWLINE 2 @@ -357,7 +355,7 @@ void parse_new_section(struct parse_state *state, int kw, static void parse_config(const char *fn, char *s) { struct parse_state state; - char *args[MAXARGS]; + char *args[SVC_MAXARGS]; int nargs; nargs = 0; @@ -384,7 +382,7 @@ static void parse_config(const char *fn, char *s) } break; case T_TEXT: - if (nargs < MAXARGS) { + if (nargs < SVC_MAXARGS) { args[nargs++] = state.text; } break; |