init: Implement 'exec' command.
(cherry-pick of d05ab3952ec0e38f33a0e80ce6b9eb45b0064ba4.)
Change-Id: Id6d9bb32e51a0ad090ed8240cc505dc45b57b35d
diff --git a/init/builtins.c b/init/builtins.c
index b9b5029..303a8ca 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -205,6 +205,68 @@
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]);