summaryrefslogtreecommitdiffstats
path: root/init
diff options
context:
space:
mode:
authorSan Mehat <san@google.com>2009-05-19 13:30:46 -0700
committerSan Mehat <san@google.com>2009-05-19 13:33:07 -0700
commitf24e252903ca0f71c7fbfb135cf17e83e0c2ea90 (patch)
tree65d2499db0682ad75bbd21a365bfcfc00756d3a3 /init
parent1b154930b2c2634dce9c04d5d5cec7acb229ccb0 (diff)
downloadsystem_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.c6
-rw-r--r--init/init.c77
-rw-r--r--init/init.h4
-rw-r--r--init/parser.c6
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;