From a4bf2cee04cb1d06eaf302b37746bcdbefb22898 Mon Sep 17 00:00:00 2001 From: Steve Muckle Date: Fri, 1 Nov 2019 13:58:02 -0700 Subject: [PATCH] first_stage_init: add hook to exec a shell script If the first stage console is being used, attempt to run /first_stage.sh immediately before the console is created. Bug: 154126020 Change-Id: I8b7431e7b8219afea295b120d7ea91751804bda6 --- init/Android.bp | 1 + init/Android.mk | 1 + init/first_stage_console.cpp | 95 ++++++++++++++++++++++++++++++++++++ init/first_stage_console.h | 28 +++++++++++ init/first_stage_init.cpp | 46 +---------------- 5 files changed, 126 insertions(+), 45 deletions(-) create mode 100644 init/first_stage_console.cpp create mode 100644 init/first_stage_console.h diff --git a/init/Android.bp b/init/Android.bp index 1b3aa18ea..827a8293f 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -41,6 +41,7 @@ init_device_sources = [ "builtins.cpp", "devices.cpp", "firmware_handler.cpp", + "first_stage_console.cpp", "first_stage_init.cpp", "first_stage_mount.cpp", "fscrypt_init_extensions.cpp", diff --git a/init/Android.mk b/init/Android.mk index b49fb3b8b..416b732d8 100644 --- a/init/Android.mk +++ b/init/Android.mk @@ -50,6 +50,7 @@ LOCAL_CPPFLAGS := $(init_cflags) LOCAL_SRC_FILES := \ block_dev_initializer.cpp \ devices.cpp \ + first_stage_console.cpp \ first_stage_init.cpp \ first_stage_main.cpp \ first_stage_mount.cpp \ diff --git a/init/first_stage_console.cpp b/init/first_stage_console.cpp new file mode 100644 index 000000000..cae53f440 --- /dev/null +++ b/init/first_stage_console.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "first_stage_console.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +static void RunScript() { + LOG(INFO) << "Attempting to run /first_stage.sh..."; + pid_t pid = fork(); + if (pid != 0) { + int status; + waitpid(pid, &status, 0); + LOG(INFO) << "/first_stage.sh exited with status " << status; + return; + } + const char* path = "/system/bin/sh"; + const char* args[] = {path, "/first_stage.sh", nullptr}; + int rv = execv(path, const_cast(args)); + LOG(ERROR) << "unable to execv /first_stage.sh, returned " << rv << " errno " << errno; +} + +namespace android { +namespace init { + +void StartConsole() { + if (mknod("/dev/console", S_IFCHR | 0600, makedev(5, 1))) { + PLOG(ERROR) << "unable to create /dev/console"; + return; + } + pid_t pid = fork(); + if (pid != 0) { + int status; + waitpid(pid, &status, 0); + LOG(ERROR) << "console shell exited with status " << status; + return; + } + int fd = -1; + int tries = 50; // should timeout after 5s + // The device driver for console may not be ready yet so retry for a while in case of failure. + while (tries--) { + fd = open("/dev/console", O_RDWR); + if (fd != -1) { + break; + } + std::this_thread::sleep_for(100ms); + } + if (fd == -1) { + LOG(ERROR) << "Could not open /dev/console, errno = " << errno; + _exit(127); + } + ioctl(fd, TIOCSCTTY, 0); + dup2(fd, STDIN_FILENO); + dup2(fd, STDOUT_FILENO); + dup2(fd, STDERR_FILENO); + close(fd); + + RunScript(); + const char* path = "/system/bin/sh"; + const char* args[] = {path, nullptr}; + int rv = execv(path, const_cast(args)); + LOG(ERROR) << "unable to execv, returned " << rv << " errno " << errno; + _exit(127); +} + +bool FirstStageConsole(const std::string& cmdline) { + return cmdline.find("androidboot.first_stage_console=1") != std::string::npos; +} + +} // namespace init +} // namespace android diff --git a/init/first_stage_console.h b/init/first_stage_console.h new file mode 100644 index 000000000..74853399b --- /dev/null +++ b/init/first_stage_console.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace android { +namespace init { + +void StartConsole(); +bool FirstStageConsole(const std::string& cmdline); + +} // namespace init +} // namespace android diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp index ad546bf07..5eca64457 100644 --- a/init/first_stage_init.cpp +++ b/init/first_stage_init.cpp @@ -24,12 +24,10 @@ #include #include #include -#include #include #include #include -#include #include #include @@ -39,6 +37,7 @@ #include #include "debug_ramdisk.h" +#include "first_stage_console.h" #include "first_stage_mount.h" #include "reboot_utils.h" #include "switch_root.h" @@ -94,49 +93,6 @@ void FreeRamdisk(DIR* dir, dev_t dev) { } } -void StartConsole() { - if (mknod("/dev/console", S_IFCHR | 0600, makedev(5, 1))) { - PLOG(ERROR) << "unable to create /dev/console"; - return; - } - pid_t pid = fork(); - if (pid != 0) { - int status; - waitpid(pid, &status, 0); - LOG(ERROR) << "console shell exited with status " << status; - return; - } - int fd = -1; - int tries = 50; // should timeout after 5s - // The device driver for console may not be ready yet so retry for a while in case of failure. - while (tries--) { - fd = open("/dev/console", O_RDWR); - if (fd != -1) { - break; - } - std::this_thread::sleep_for(100ms); - } - if (fd == -1) { - LOG(ERROR) << "Could not open /dev/console, errno = " << errno; - _exit(127); - } - ioctl(fd, TIOCSCTTY, 0); - dup2(fd, STDIN_FILENO); - dup2(fd, STDOUT_FILENO); - dup2(fd, STDERR_FILENO); - close(fd); - - const char* path = "/system/bin/sh"; - const char* args[] = {path, nullptr}; - int rv = execv(path, const_cast(args)); - LOG(ERROR) << "unable to execv, returned " << rv << " errno " << errno; - _exit(127); -} - -bool FirstStageConsole(const std::string& cmdline) { - return cmdline.find("androidboot.first_stage_console=1") != std::string::npos; -} - bool ForceNormalBoot(const std::string& cmdline) { return cmdline.find("androidboot.force_normal_boot=1") != std::string::npos; }