init: Implement 'exec' command.

(cherry-pick of d05ab3952ec0e38f33a0e80ce6b9eb45b0064ba4.)

Change-Id: Id6d9bb32e51a0ad090ed8240cc505dc45b57b35d
This commit is contained in:
San Mehat 2014-09-23 07:48:47 -07:00 committed by Elliott Hughes
parent 46adfa69b6
commit 429721c5c4
6 changed files with 74 additions and 4 deletions

View file

@ -205,6 +205,68 @@ int do_exec(int nargs, char **args)
return -1;
}
int do_execonce(int nargs, char **args)
{
pid_t child;
int child_status = 0;
static int already_done;
if (already_done) {
return -1;
}
already_done = 1;
if (!(child = fork())) {
/*
* Child process.
*/
zap_stdio();
char *exec_args[100];
int i;
int num_process_args = nargs;
memset(exec_args, 0, sizeof(exec_args));
if (num_process_args > ARRAY_SIZE(exec_args) - 1) {
ERROR("exec called with %d args, limit is %d", num_process_args,
ARRAY_SIZE(exec_args) - 1);
_exit(1);
}
for (i = 1; i < num_process_args; i++)
exec_args[i - 1] = args[i];
if (execv(exec_args[0], exec_args) == -1) {
ERROR("Failed to execv '%s' (%s)", exec_args[0], strerror(errno));
_exit(1);
}
ERROR("Returned from execv()!");
_exit(1);
}
/*
* Parent process.
*/
if (child == -1) {
ERROR("Fork failed\n");
return -1;
}
if (TEMP_FAILURE_RETRY(waitpid(child, &child_status, 0)) == -1) {
ERROR("waitpid(): failed (%s)\n", strerror(errno));
return -1;
}
if (WIFSIGNALED(child_status)) {
INFO("Child exited due to signal %d\n", WTERMSIG(child_status));
return -1;
} else if (WIFEXITED(child_status)) {
INFO("Child exited normally (exit code %d)\n", WEXITSTATUS(child_status));
return WEXITSTATUS(child_status);
}
ERROR("Abnormal child process exit\n");
return -1;
}
int do_export(int nargs, char **args)
{
return add_environment(args[1], args[2]);

View file

@ -126,7 +126,7 @@ int add_environment(const char *key, const char *val)
return -1;
}
static void zap_stdio(void)
void zap_stdio(void)
{
int fd;
fd = open("/dev/null", O_RDWR);

View file

@ -149,5 +149,6 @@ void property_changed(const char *name, const char *value);
extern struct selabel_handle *sehandle;
extern struct selabel_handle *sehandle_prop;
extern int selinux_reload_policy(void);
void zap_stdio(void);
#endif /* _INIT_INIT_H */

View file

@ -97,6 +97,7 @@ static int lookup_keyword(const char *s)
case 'e':
if (!strcmp(s, "nable")) return K_enable;
if (!strcmp(s, "xec")) return K_exec;
if (!strcmp(s, "xeconce")) return K_execonce;
if (!strcmp(s, "xport")) return K_export;
break;
case 'g':

View file

@ -8,6 +8,7 @@ int do_class_reset(int nargs, char **args);
int do_domainname(int nargs, char **args);
int do_enable(int nargs, char **args);
int do_exec(int nargs, char **args);
int do_execonce(int nargs, char **args);
int do_export(int nargs, char **args);
int do_hostname(int nargs, char **args);
int do_ifup(int nargs, char **args);
@ -59,6 +60,7 @@ enum {
KEYWORD(domainname, COMMAND, 1, do_domainname)
KEYWORD(enable, COMMAND, 1, do_enable)
KEYWORD(exec, COMMAND, 1, do_exec)
KEYWORD(execonce, COMMAND, 1, do_execonce)
KEYWORD(export, COMMAND, 2, do_export)
KEYWORD(group, OPTION, 0, 0)
KEYWORD(hostname, COMMAND, 1, do_hostname)

View file

@ -136,10 +136,14 @@ Commands
--------
exec <path> [ <argument> ]*
This command is not implemented.
execonce <path> [ <argument> ]*
Fork and execute a program (<path>). This will block until
the program completes execution. It is best to avoid exec
as unlike the builtin commands, it runs the risk of getting
init "stuck". (??? maybe there should be a timeout?)
the program completes execution. This command can be run at most
once during init's lifetime. Subsequent invocations are ignored.
It is best to avoid exec as unlike the builtin commands, it runs
the risk of getting init "stuck".
export <name> <value>
Set the environment variable <name> equal to <value> in the