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>
This commit is contained in:
parent
1b154930b2
commit
f24e252903
4 changed files with 79 additions and 14 deletions
|
@ -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;
|
||||
}
|
||||
|
|
77
init/init.c
77
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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue