init: use Result<T> for builtin functions

We currently throw out the return values from builtin functions and
occasionally log errors with no supporting context.  This change uses
the newly introduced Result<T> class to communicate a successful result
or an error back to callers in order to print an error with clear
context when a builtin fails.

Example:

init: Command 'write /sys/class/leds/vibrator/trigger transient' action=init (/init.rc:245) took 0ms and failed: Unable to write to file '/sys/class/leds/vibrator/trigger': open() failed: No such file or directory

Test: boot bullhead
Merged-In: Idc18f331d2d646629c6093c1e0f2996cf9b42aec
Change-Id: Idc18f331d2d646629c6093c1e0f2996cf9b42aec
This commit is contained in:
Tom Cherry 2017-08-01 13:50:23 -07:00
parent 11a3aeeae3
commit 557946e57c
11 changed files with 323 additions and 319 deletions

View file

@ -31,14 +31,13 @@ namespace init {
Command::Command(BuiltinFunction f, const std::vector<std::string>& args, int line)
: func_(f), args_(args), line_(line) {}
int Command::InvokeFunc() const {
Result<Success> Command::InvokeFunc() const {
std::vector<std::string> expanded_args;
expanded_args.resize(args_.size());
expanded_args[0] = args_[0];
for (std::size_t i = 1; i < args_.size(); ++i) {
if (!expand_props(args_[i], &expanded_args[i])) {
LOG(ERROR) << args_[0] << ": cannot expand '" << args_[i] << "'";
return -EINVAL;
return Error() << "cannot expand '" << args_[i] << "'";
}
}
@ -92,17 +91,17 @@ void Action::ExecuteAllCommands() const {
void Action::ExecuteCommand(const Command& command) const {
android::base::Timer t;
int result = command.InvokeFunc();
auto result = command.InvokeFunc();
auto duration = t.duration();
// Any action longer than 50ms will be warned to user as slow operation
if (duration > 50ms || android::base::GetMinimumLogSeverity() <= android::base::DEBUG) {
std::string trigger_name = BuildTriggersString();
std::string cmd_str = command.BuildCommandString();
LOG(INFO) << "Command '" << cmd_str << "' action=" << trigger_name << " (" << filename_
<< ":" << command.line() << ") returned " << result << " took "
<< duration.count() << "ms.";
<< ":" << command.line() << ") took " << duration.count() << "ms and "
<< (result ? "succeeded" : "failed: " + result.error());
}
}

View file

@ -26,6 +26,7 @@
#include "builtins.h"
#include "keyword_map.h"
#include "parser.h"
#include "result.h"
namespace android {
namespace init {
@ -34,7 +35,7 @@ class Command {
public:
Command(BuiltinFunction f, const std::vector<std::string>& args, int line);
int InvokeFunc() const;
Result<Success> InvokeFunc() const;
std::string BuildCommandString() const;
int line() const { return line_; }

View file

@ -163,37 +163,37 @@ static void bootchart_thread_main() {
LOG(INFO) << "Bootcharting finished";
}
static int do_bootchart_start() {
// We don't care about the content, but we do care that /data/bootchart/enabled actually exists.
std::string start;
if (!android::base::ReadFileToString("/data/bootchart/enabled", &start)) {
LOG(VERBOSE) << "Not bootcharting";
return 0;
}
static Result<Success> do_bootchart_start() {
// We don't care about the content, but we do care that /data/bootchart/enabled actually exists.
std::string start;
if (!android::base::ReadFileToString("/data/bootchart/enabled", &start)) {
LOG(VERBOSE) << "Not bootcharting";
return Success();
}
g_bootcharting_thread = new std::thread(bootchart_thread_main);
return 0;
g_bootcharting_thread = new std::thread(bootchart_thread_main);
return Success();
}
static int do_bootchart_stop() {
if (!g_bootcharting_thread) return 0;
static Result<Success> do_bootchart_stop() {
if (!g_bootcharting_thread) return Success();
// Tell the worker thread it's time to quit.
{
std::lock_guard<std::mutex> lock(g_bootcharting_finished_mutex);
g_bootcharting_finished = true;
g_bootcharting_finished_cv.notify_one();
}
// Tell the worker thread it's time to quit.
{
std::lock_guard<std::mutex> lock(g_bootcharting_finished_mutex);
g_bootcharting_finished = true;
g_bootcharting_finished_cv.notify_one();
}
g_bootcharting_thread->join();
delete g_bootcharting_thread;
g_bootcharting_thread = nullptr;
return 0;
g_bootcharting_thread->join();
delete g_bootcharting_thread;
g_bootcharting_thread = nullptr;
return Success();
}
int do_bootchart(const std::vector<std::string>& args) {
if (args[1] == "start") return do_bootchart_start();
return do_bootchart_stop();
Result<Success> do_bootchart(const std::vector<std::string>& args) {
if (args[1] == "start") return do_bootchart_start();
return do_bootchart_stop();
}
} // namespace init

View file

@ -20,10 +20,12 @@
#include <string>
#include <vector>
#include "result.h"
namespace android {
namespace init {
int do_bootchart(const std::vector<std::string>& args);
Result<Success> do_bootchart(const std::vector<std::string>& args);
} // namespace init
} // namespace android

View file

@ -78,47 +78,13 @@ namespace init {
static constexpr std::chrono::nanoseconds kCommandRetryTimeout = 5s;
static int insmod(const char *filename, const char *options, int flags) {
unique_fd fd(TEMP_FAILURE_RETRY(open(filename, O_RDONLY | O_NOFOLLOW | O_CLOEXEC)));
if (fd == -1) {
PLOG(ERROR) << "insmod: open(\"" << filename << "\") failed";
return -1;
}
int rc = syscall(__NR_finit_module, fd.get(), options, flags);
if (rc == -1) {
PLOG(ERROR) << "finit_module for \"" << filename << "\" failed";
}
return rc;
}
static int __ifupdown(const char *interface, int up) {
struct ifreq ifr;
strlcpy(ifr.ifr_name, interface, IFNAMSIZ);
unique_fd s(TEMP_FAILURE_RETRY(socket(AF_INET, SOCK_DGRAM, 0)));
if (s < 0) return -1;
int ret = ioctl(s, SIOCGIFFLAGS, &ifr);
if (ret < 0) return ret;
if (up) {
ifr.ifr_flags |= IFF_UP;
} else {
ifr.ifr_flags &= ~IFF_UP;
}
return ioctl(s, SIOCSIFFLAGS, &ifr);
}
static int reboot_into_recovery(const std::vector<std::string>& options) {
static Result<Success> reboot_into_recovery(const std::vector<std::string>& options) {
std::string err;
if (!write_bootloader_message(options, &err)) {
LOG(ERROR) << "failed to set bootloader message: " << err;
return -1;
return Error() << "Failed to set bootloader message: " << err;
}
property_set("sys.powerctl", "reboot,recovery");
return 0;
return Success();
}
template <typename F>
@ -128,88 +94,106 @@ static void ForEachServiceInClass(const std::string& classname, F function) {
}
}
static int do_class_start(const std::vector<std::string>& args) {
static Result<Success> do_class_start(const std::vector<std::string>& args) {
// Starting a class does not start services which are explicitly disabled.
// They must be started individually.
ForEachServiceInClass(args[1], &Service::StartIfNotDisabled);
return 0;
return Success();
}
static int do_class_stop(const std::vector<std::string>& args) {
static Result<Success> do_class_stop(const std::vector<std::string>& args) {
ForEachServiceInClass(args[1], &Service::Stop);
return 0;
return Success();
}
static int do_class_reset(const std::vector<std::string>& args) {
static Result<Success> do_class_reset(const std::vector<std::string>& args) {
ForEachServiceInClass(args[1], &Service::Reset);
return 0;
return Success();
}
static int do_class_restart(const std::vector<std::string>& args) {
static Result<Success> do_class_restart(const std::vector<std::string>& args) {
ForEachServiceInClass(args[1], &Service::Restart);
return 0;
return Success();
}
static int do_domainname(const std::vector<std::string>& args) {
static Result<Success> do_domainname(const std::vector<std::string>& args) {
if (auto result = WriteFile("/proc/sys/kernel/domainname", args[1]); !result) {
LOG(ERROR) << "Unable to write to /proc/sys/kernel/domainname: " << result.error();
return -1;
return Error() << "Unable to write to /proc/sys/kernel/domainname: " << result.error();
}
return 0;
return Success();
}
static int do_enable(const std::vector<std::string>& args) {
static Result<Success> do_enable(const std::vector<std::string>& args) {
Service* svc = ServiceList::GetInstance().FindService(args[1]);
if (!svc) {
return -1;
}
return svc->Enable();
if (!svc) return Error() << "Could not find service";
if (!svc->Enable()) return Error() << "Could not enable service";
return Success();
}
static int do_exec(const std::vector<std::string>& args) {
static Result<Success> do_exec(const std::vector<std::string>& args) {
auto service = Service::MakeTemporaryOneshotService(args);
if (!service) {
LOG(ERROR) << "Failed to create exec service: " << android::base::Join(args, " ");
return -1;
return Error() << "Could not create exec service";
}
if (!service->ExecStart()) {
LOG(ERROR) << "Failed to Start exec service";
return -1;
return Error() << "Could not start exec service";
}
ServiceList::GetInstance().AddService(std::move(service));
return 0;
return Success();
}
static int do_exec_start(const std::vector<std::string>& args) {
static Result<Success> do_exec_start(const std::vector<std::string>& args) {
Service* service = ServiceList::GetInstance().FindService(args[1]);
if (!service) {
LOG(ERROR) << "ExecStart(" << args[1] << "): Service not found";
return -1;
return Error() << "Service not found";
}
if (!service->ExecStart()) {
LOG(ERROR) << "ExecStart(" << args[1] << "): Could not start Service";
return -1;
return Error() << "Could not start Service";
}
return 0;
return Success();
}
static int do_export(const std::vector<std::string>& args) {
return add_environment(args[1].c_str(), args[2].c_str());
static Result<Success> do_export(const std::vector<std::string>& args) {
if (!add_environment(args[1].c_str(), args[2].c_str())) {
return Error();
}
return Success();
}
static int do_hostname(const std::vector<std::string>& args) {
static Result<Success> do_hostname(const std::vector<std::string>& args) {
if (auto result = WriteFile("/proc/sys/kernel/hostname", args[1]); !result) {
LOG(ERROR) << "Unable to write to /proc/sys/kernel/hostname: " << result.error();
return -1;
return Error() << "Unable to write to /proc/sys/kernel/hostname: " << result.error();
}
return 0;
return Success();
}
static int do_ifup(const std::vector<std::string>& args) {
return __ifupdown(args[1].c_str(), 1);
static Result<Success> do_ifup(const std::vector<std::string>& args) {
struct ifreq ifr;
strlcpy(ifr.ifr_name, args[1].c_str(), IFNAMSIZ);
unique_fd s(TEMP_FAILURE_RETRY(socket(AF_INET, SOCK_DGRAM, 0)));
if (s < 0) return ErrnoError() << "opening socket failed";
if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) {
return ErrnoError() << "ioctl(..., SIOCGIFFLAGS, ...) failed";
}
ifr.ifr_flags |= IFF_UP;
if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0) {
return ErrnoError() << "ioctl(..., SIOCSIFFLAGS, ...) failed";
}
return Success();
}
static int do_insmod(const std::vector<std::string>& args) {
static Result<Success> do_insmod(const std::vector<std::string>& args) {
int flags = 0;
auto it = args.begin() + 1;
@ -220,11 +204,18 @@ static int do_insmod(const std::vector<std::string>& args) {
std::string filename = *it++;
std::string options = android::base::Join(std::vector<std::string>(it, args.end()), ' ');
return insmod(filename.c_str(), options.c_str(), flags);
unique_fd fd(TEMP_FAILURE_RETRY(open(filename.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC)));
if (fd == -1) return ErrnoError() << "open(\"" << filename << "\") failed";
int rc = syscall(__NR_finit_module, fd.get(), options.c_str(), flags);
if (rc == -1) return ErrnoError() << "finit_module for \"" << filename << "\" failed";
return Success();
}
// mkdir <path> [mode] [owner] [group]
static int do_mkdir(const std::vector<std::string>& args) {
static Result<Success> do_mkdir(const std::vector<std::string>& args) {
mode_t mode = 0755;
if (args.size() >= 3) {
mode = std::strtoul(args[2].c_str(), 0, 8);
@ -234,37 +225,35 @@ static int do_mkdir(const std::vector<std::string>& args) {
/* chmod in case the directory already exists */
if (errno == EEXIST) {
if (fchmodat(AT_FDCWD, args[1].c_str(), mode, AT_SYMLINK_NOFOLLOW) == -1) {
return -errno;
return ErrnoError() << "fchmodat() failed";
}
} else {
return -errno;
return ErrnoError() << "mkdir() failed";
}
}
if (args.size() >= 4) {
auto uid = DecodeUid(args[3]);
if (!uid) {
LOG(ERROR) << "Unable to decode UID for '" << args[3] << "': " << uid.error();
return -1;
return Error() << "Unable to decode UID for '" << args[3] << "': " << uid.error();
}
Result<gid_t> gid = -1;
if (args.size() == 5) {
gid = DecodeUid(args[4]);
if (!gid) {
LOG(ERROR) << "Unable to decode GID for '" << args[3] << "': " << gid.error();
return -1;
return Error() << "Unable to decode GID for '" << args[3] << "': " << gid.error();
}
}
if (lchown(args[1].c_str(), *uid, *gid) == -1) {
return -errno;
return ErrnoError() << "lchown failed";
}
/* chown may have cleared S_ISUID and S_ISGID, chmod again */
if (mode & (S_ISUID | S_ISGID)) {
if (fchmodat(AT_FDCWD, args[1].c_str(), mode, AT_SYMLINK_NOFOLLOW) == -1) {
return -errno;
return ErrnoError() << "fchmodat failed";
}
}
}
@ -275,15 +264,18 @@ static int do_mkdir(const std::vector<std::string>& args) {
"--prompt_and_wipe_data",
"--reason=set_policy_failed:"s + args[1]};
reboot_into_recovery(options);
return -1;
return Error() << "reboot into recovery failed";
}
}
return 0;
return Success();
}
/* umount <path> */
static int do_umount(const std::vector<std::string>& args) {
return umount(args[1].c_str());
static Result<Success> do_umount(const std::vector<std::string>& args) {
if (umount(args[1].c_str()) < 0) {
return ErrnoError() << "umount() failed";
}
return Success();
}
static struct {
@ -311,7 +303,7 @@ static struct {
#define DATA_MNT_POINT "/data"
/* mount <type> <device> <path> <flags ...> <options> */
static int do_mount(const std::vector<std::string>& args) {
static Result<Success> do_mount(const std::vector<std::string>& args) {
const char* options = nullptr;
unsigned flags = 0;
bool wait = false;
@ -342,12 +334,12 @@ static int do_mount(const std::vector<std::string>& args) {
if (android::base::StartsWith(source, "loop@")) {
int mode = (flags & MS_RDONLY) ? O_RDONLY : O_RDWR;
unique_fd fd(TEMP_FAILURE_RETRY(open(source + 5, mode | O_CLOEXEC)));
if (fd < 0) return -1;
if (fd < 0) return ErrnoError() << "open(" << source + 5 << ", " << mode << ") failed";
for (size_t n = 0;; n++) {
std::string tmp = android::base::StringPrintf("/dev/block/loop%zu", n);
unique_fd loop(TEMP_FAILURE_RETRY(open(tmp.c_str(), mode | O_CLOEXEC)));
if (loop < 0) return -1;
if (loop < 0) return ErrnoError() << "open(" << tmp << ", " << mode << ") failed";
loop_info info;
/* if it is a blank loop device */
@ -356,26 +348,24 @@ static int do_mount(const std::vector<std::string>& args) {
if (ioctl(loop, LOOP_SET_FD, fd.get()) >= 0) {
if (mount(tmp.c_str(), target, system, flags, options) < 0) {
ioctl(loop, LOOP_CLR_FD, 0);
return -1;
return ErrnoError() << "mount() failed";
}
return 0;
return Success();
}
}
}
LOG(ERROR) << "out of loopback devices";
return -1;
return Error() << "out of loopback devices";
} else {
if (wait)
wait_for_file(source, kCommandRetryTimeout);
if (mount(source, target, system, flags, options) < 0) {
return -1;
return ErrnoError() << "mount() failed";
}
}
return 0;
return Success();
}
/* Imports .rc files from the specified paths. Default ones are applied if none is given.
@ -407,9 +397,7 @@ static void import_late(const std::vector<std::string>& args, size_t start_index
*
* Call fs_mgr_mount_all() to mount the given fstab
*/
static int mount_fstab(const char* fstabfile, int mount_mode) {
int ret = -1;
static Result<int> mount_fstab(const char* fstabfile, int mount_mode) {
/*
* Call fs_mgr_mount_all() to mount all filesystems. We fork(2) and
* do the call in the child to provide protection to the main init
@ -427,9 +415,9 @@ static int mount_fstab(const char* fstabfile, int mount_mode) {
}
if (WIFEXITED(status)) {
ret = WEXITSTATUS(status);
return WEXITSTATUS(status);
} else {
ret = -1;
return Error() << "child aborted";
}
} else if (pid == 0) {
/* child, call fs_mgr_mount_all() */
@ -446,10 +434,8 @@ static int mount_fstab(const char* fstabfile, int mount_mode) {
}
_exit(child_ret);
} else {
/* fork failed, return an error */
return -1;
return Error() << "fork() failed";
}
return ret;
}
/* Queue event based on fs_mgr return code.
@ -461,29 +447,33 @@ static int mount_fstab(const char* fstabfile, int mount_mode) {
*
* return code is processed based on input code
*/
static int queue_fs_event(int code) {
int ret = code;
static Result<Success> queue_fs_event(int code) {
if (code == FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION) {
ActionManager::GetInstance().QueueEventTrigger("encrypt");
return Success();
} else if (code == FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED) {
property_set("ro.crypto.state", "encrypted");
property_set("ro.crypto.type", "block");
ActionManager::GetInstance().QueueEventTrigger("defaultcrypto");
return Success();
} else if (code == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
property_set("ro.crypto.state", "unencrypted");
ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
return Success();
} else if (code == FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE) {
property_set("ro.crypto.state", "unsupported");
ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
return Success();
} else if (code == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) {
/* Setup a wipe via recovery, and reboot into recovery */
PLOG(ERROR) << "fs_mgr_mount_all suggested recovery, so wiping data via recovery.";
const std::vector<std::string> options = {"--wipe_data", "--reason=fs_mgr_mount_all" };
ret = reboot_into_recovery(options);
reboot_into_recovery(options);
return Error() << "reboot_into_recovery() failed";
/* If reboot worked, there is no return. */
} else if (code == FS_MGR_MNTALL_DEV_FILE_ENCRYPTED) {
if (e4crypt_install_keyring()) {
return -1;
return Error() << "e4crypt_install_keyring() failed";
}
property_set("ro.crypto.state", "encrypted");
property_set("ro.crypto.type", "file");
@ -491,12 +481,13 @@ static int queue_fs_event(int code) {
// Although encrypted, we have device key, so we do not need to
// do anything different from the nonencrypted case.
ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
return Success();
} else if (code > 0) {
PLOG(ERROR) << "fs_mgr_mount_all returned unexpected error " << code;
Error() << "fs_mgr_mount_all() returned unexpected error " << code;
}
/* else ... < 0: error */
return ret;
return Error() << "Invalid code: " << code;
}
/* mount_all <fstab> [ <path> ]* [--<options>]*
@ -504,7 +495,7 @@ static int queue_fs_event(int code) {
* This function might request a reboot, in which case it will
* not return.
*/
static int do_mount_all(const std::vector<std::string>& args) {
static Result<Success> do_mount_all(const std::vector<std::string>& args) {
std::size_t na = 0;
bool import_rc = true;
bool queue_event = true;
@ -529,7 +520,10 @@ static int do_mount_all(const std::vector<std::string>& args) {
std::string prop_name = "ro.boottime.init.mount_all."s + prop_post_fix;
android::base::Timer t;
int ret = mount_fstab(fstabfile, mount_mode);
auto mount_fstab_return_code = mount_fstab(fstabfile, mount_mode);
if (!mount_fstab_return_code) {
return Error() << "mount_fstab() failed " << mount_fstab_return_code.error();
}
property_set(prop_name, std::to_string(t.duration().count()));
if (import_rc) {
@ -540,13 +534,16 @@ static int do_mount_all(const std::vector<std::string>& args) {
if (queue_event) {
/* queue_fs_event will queue event based on mount_fstab return code
* and return processed return code*/
ret = queue_fs_event(ret);
auto queue_fs_result = queue_fs_event(*mount_fstab_return_code);
if (!queue_fs_result) {
return Error() << "queue_fs_event() failed: " << queue_fs_result.error();
}
}
return ret;
return Success();
}
static int do_swapon_all(const std::vector<std::string>& args) {
static Result<Success> do_swapon_all(const std::vector<std::string>& args) {
struct fstab *fstab;
int ret;
@ -554,89 +551,103 @@ static int do_swapon_all(const std::vector<std::string>& args) {
ret = fs_mgr_swapon_all(fstab);
fs_mgr_free_fstab(fstab);
return ret;
if (ret != 0) return Error() << "fs_mgr_swapon_all() failed";
return Success();
}
static int do_setprop(const std::vector<std::string>& args) {
static Result<Success> do_setprop(const std::vector<std::string>& args) {
property_set(args[1], args[2]);
return 0;
return Success();
}
static int do_setrlimit(const std::vector<std::string>& args) {
struct rlimit limit;
static Result<Success> do_setrlimit(const std::vector<std::string>& args) {
int resource;
if (android::base::ParseInt(args[1], &resource) &&
android::base::ParseUint(args[2], &limit.rlim_cur) &&
android::base::ParseUint(args[3], &limit.rlim_max)) {
return setrlimit(resource, &limit);
if (!android::base::ParseInt(args[1], &resource)) {
return Error() << "unable to parse resource, " << args[1];
}
LOG(WARNING) << "ignoring setrlimit " << args[1] << " " << args[2] << " " << args[3];
return -1;
struct rlimit limit;
if (!android::base::ParseUint(args[2], &limit.rlim_cur)) {
return Error() << "unable to parse rlim_cur, " << args[2];
}
if (!android::base::ParseUint(args[3], &limit.rlim_max)) {
return Error() << "unable to parse rlim_max, " << args[3];
}
if (setrlimit(resource, &limit) == -1) {
return ErrnoError() << "setrlimit failed";
}
return Success();
}
static int do_start(const std::vector<std::string>& args) {
static Result<Success> do_start(const std::vector<std::string>& args) {
Service* svc = ServiceList::GetInstance().FindService(args[1]);
if (!svc) {
LOG(ERROR) << "do_start: Service " << args[1] << " not found";
return -1;
}
if (!svc->Start())
return -1;
return 0;
if (!svc) return Error() << "service " << args[1] << " not found";
if (!svc->Start()) return Error() << "failed to start service";
return Success();
}
static int do_stop(const std::vector<std::string>& args) {
static Result<Success> do_stop(const std::vector<std::string>& args) {
Service* svc = ServiceList::GetInstance().FindService(args[1]);
if (!svc) {
LOG(ERROR) << "do_stop: Service " << args[1] << " not found";
return -1;
}
if (!svc) return Error() << "service " << args[1] << " not found";
svc->Stop();
return 0;
return Success();
}
static int do_restart(const std::vector<std::string>& args) {
static Result<Success> do_restart(const std::vector<std::string>& args) {
Service* svc = ServiceList::GetInstance().FindService(args[1]);
if (!svc) {
LOG(ERROR) << "do_restart: Service " << args[1] << " not found";
return -1;
}
if (!svc) return Error() << "service " << args[1] << " not found";
svc->Restart();
return 0;
return Success();
}
static int do_trigger(const std::vector<std::string>& args) {
static Result<Success> do_trigger(const std::vector<std::string>& args) {
ActionManager::GetInstance().QueueEventTrigger(args[1]);
return 0;
return Success();
}
static int do_symlink(const std::vector<std::string>& args) {
return symlink(args[1].c_str(), args[2].c_str());
}
static int do_rm(const std::vector<std::string>& args) {
return unlink(args[1].c_str());
}
static int do_rmdir(const std::vector<std::string>& args) {
return rmdir(args[1].c_str());
}
static int do_sysclktz(const std::vector<std::string>& args) {
struct timezone tz = {};
if (android::base::ParseInt(args[1], &tz.tz_minuteswest) && settimeofday(nullptr, &tz) != -1) {
return 0;
static Result<Success> do_symlink(const std::vector<std::string>& args) {
if (symlink(args[1].c_str(), args[2].c_str()) < 0) {
return ErrnoError() << "symlink() failed";
}
return -1;
return Success();
}
static int do_verity_load_state(const std::vector<std::string>& args) {
static Result<Success> do_rm(const std::vector<std::string>& args) {
if (unlink(args[1].c_str()) < 0) {
return ErrnoError() << "unlink() failed";
}
return Success();
}
static Result<Success> do_rmdir(const std::vector<std::string>& args) {
if (rmdir(args[1].c_str()) < 0) {
return ErrnoError() << "rmdir() failed";
}
return Success();
}
static Result<Success> do_sysclktz(const std::vector<std::string>& args) {
struct timezone tz = {};
if (!android::base::ParseInt(args[1], &tz.tz_minuteswest)) {
return Error() << "Unable to parse mins_west_of_gmt";
}
if (settimeofday(nullptr, &tz) == -1) {
return ErrnoError() << "settimeofday() failed";
}
return Success();
}
static Result<Success> do_verity_load_state(const std::vector<std::string>& args) {
int mode = -1;
bool loaded = fs_mgr_load_verity_state(&mode);
if (loaded && mode != VERITY_MODE_DEFAULT) {
ActionManager::GetInstance().QueueEventTrigger("verity-logging");
}
return loaded ? 0 : 1;
if (!loaded) return Error() << "Could not load verity state";
return Success();
}
static void verity_update_property(fstab_rec *fstab, const char *mount_point,
@ -644,24 +655,26 @@ static void verity_update_property(fstab_rec *fstab, const char *mount_point,
property_set("partition."s + mount_point + ".verified", std::to_string(mode));
}
static int do_verity_update_state(const std::vector<std::string>& args) {
return fs_mgr_update_verity_state(verity_update_property) ? 0 : 1;
}
static int do_write(const std::vector<std::string>& args) {
if (auto result = WriteFile(args[1], args[2]); !result) {
LOG(ERROR) << "Unable to write to file '" << args[1] << "': " << result.error();
return -1;
static Result<Success> do_verity_update_state(const std::vector<std::string>& args) {
if (!fs_mgr_update_verity_state(verity_update_property)) {
return Error() << "fs_mgr_update_verity_state() failed";
}
return 0;
return Success();
}
static int do_readahead(const std::vector<std::string>& args) {
static Result<Success> do_write(const std::vector<std::string>& args) {
if (auto result = WriteFile(args[1], args[2]); !result) {
return Error() << "Unable to write to file '" << args[1] << "': " << result.error();
}
return Success();
}
static Result<Success> do_readahead(const std::vector<std::string>& args) {
struct stat sb;
if (stat(args[1].c_str(), &sb)) {
PLOG(ERROR) << "Error opening " << args[1];
return -1;
return ErrnoError() << "Error opening " << args[1];
}
// We will do readahead in a forked process in order not to block init
@ -710,30 +723,27 @@ static int do_readahead(const std::vector<std::string>& args) {
LOG(INFO) << "Readahead " << args[1] << " took " << t;
_exit(0);
} else if (pid < 0) {
PLOG(ERROR) << "Fork failed";
return -1;
return ErrnoError() << "Fork failed";
}
return 0;
return Success();
}
static int do_copy(const std::vector<std::string>& args) {
static Result<Success> do_copy(const std::vector<std::string>& args) {
auto file_contents = ReadFile(args[1]);
if (!file_contents) {
LOG(ERROR) << "Could not read input file '" << args[1] << "': " << file_contents.error();
return -1;
return Error() << "Could not read input file '" << args[1] << "': " << file_contents.error();
}
if (auto result = WriteFile(args[2], *file_contents); !result) {
LOG(ERROR) << "Could not write to output file '" << args[2] << "': " << result.error();
return -1;
return Error() << "Could not write to output file '" << args[2] << "': " << result.error();
}
return 0;
return Success();
}
static int do_chown(const std::vector<std::string>& args) {
static Result<Success> do_chown(const std::vector<std::string>& args) {
auto uid = DecodeUid(args[1]);
if (!uid) {
LOG(ERROR) << "Unable to decode UID for '" << args[1] << "': " << uid.error();
return -1;
return Error() << "Unable to decode UID for '" << args[1] << "': " << uid.error();
}
// GID is optional and pushes the index of path out by one if specified.
@ -743,14 +753,15 @@ static int do_chown(const std::vector<std::string>& args) {
if (args.size() == 4) {
gid = DecodeUid(args[2]);
if (!gid) {
LOG(ERROR) << "Unable to decode GID for '" << args[2] << "': " << gid.error();
return -1;
return Error() << "Unable to decode GID for '" << args[2] << "': " << gid.error();
}
}
if (lchown(path.c_str(), *uid, *gid) == -1) return -errno;
if (lchown(path.c_str(), *uid, *gid) == -1) {
return ErrnoError() << "lchown() failed";
}
return 0;
return Success();
}
static mode_t get_mode(const char *s) {
@ -766,15 +777,15 @@ static mode_t get_mode(const char *s) {
return mode;
}
static int do_chmod(const std::vector<std::string>& args) {
static Result<Success> do_chmod(const std::vector<std::string>& args) {
mode_t mode = get_mode(args[1].c_str());
if (fchmodat(AT_FDCWD, args[2].c_str(), mode, AT_SYMLINK_NOFOLLOW) < 0) {
return -errno;
return ErrnoError() << "fchmodat() failed";
}
return 0;
return Success();
}
static int do_restorecon(const std::vector<std::string>& args) {
static Result<Success> do_restorecon(const std::vector<std::string>& args) {
int ret = 0;
struct flag_type {const char* name; int value;};
@ -791,8 +802,7 @@ static int do_restorecon(const std::vector<std::string>& args) {
for (size_t i = 1; i < args.size(); ++i) {
if (android::base::StartsWith(args[i], "--")) {
if (!in_flags) {
LOG(ERROR) << "restorecon - flags must precede paths";
return -1;
return Error() << "flags must precede paths";
}
bool found = false;
for (size_t j = 0; flags[j].name; ++j) {
@ -803,26 +813,27 @@ static int do_restorecon(const std::vector<std::string>& args) {
}
}
if (!found) {
LOG(ERROR) << "restorecon - bad flag " << args[i];
return -1;
return Error() << "bad flag " << args[i];
}
} else {
in_flags = false;
if (selinux_android_restorecon(args[i].c_str(), flag) < 0) {
ret = -errno;
ret = errno;
}
}
}
return ret;
if (ret) return ErrnoError() << "selinux_android_restorecon() failed";
return Success();
}
static int do_restorecon_recursive(const std::vector<std::string>& args) {
static Result<Success> do_restorecon_recursive(const std::vector<std::string>& args) {
std::vector<std::string> non_const_args(args);
non_const_args.insert(std::next(non_const_args.begin()), "--recursive");
return do_restorecon(non_const_args);
}
static int do_loglevel(const std::vector<std::string>& args) {
static Result<Success> do_loglevel(const std::vector<std::string>& args) {
// TODO: support names instead/as well?
int log_level = -1;
android::base::ParseInt(args[1], &log_level);
@ -837,77 +848,73 @@ static int do_loglevel(const std::vector<std::string>& args) {
case 1:
case 0: severity = android::base::FATAL; break;
default:
LOG(ERROR) << "loglevel: invalid log level " << log_level;
return -EINVAL;
return Error() << "invalid log level " << log_level;
}
android::base::SetMinimumLogSeverity(severity);
return 0;
return Success();
}
static int do_load_persist_props(const std::vector<std::string>& args) {
static Result<Success> do_load_persist_props(const std::vector<std::string>& args) {
load_persist_props();
return 0;
return Success();
}
static int do_load_system_props(const std::vector<std::string>& args) {
static Result<Success> do_load_system_props(const std::vector<std::string>& args) {
load_system_props();
return 0;
return Success();
}
static int do_wait(const std::vector<std::string>& args) {
if (args.size() == 2) {
return wait_for_file(args[1].c_str(), kCommandRetryTimeout);
} else if (args.size() == 3) {
int timeout;
if (android::base::ParseInt(args[2], &timeout)) {
return wait_for_file(args[1].c_str(), std::chrono::seconds(timeout));
static Result<Success> do_wait(const std::vector<std::string>& args) {
auto timeout = kCommandRetryTimeout;
if (args.size() == 3) {
int timeout_int;
if (!android::base::ParseInt(args[2], &timeout_int)) {
return Error() << "failed to parse timeout";
}
timeout = std::chrono::seconds(timeout_int);
}
return -1;
if (wait_for_file(args[1].c_str(), timeout) != 0) {
return Error() << "wait_for_file() failed";
}
return Success();
}
static int do_wait_for_prop(const std::vector<std::string>& args) {
static Result<Success> do_wait_for_prop(const std::vector<std::string>& args) {
const char* name = args[1].c_str();
const char* value = args[2].c_str();
size_t value_len = strlen(value);
if (!is_legal_property_name(name)) {
LOG(ERROR) << "do_wait_for_prop(\"" << name << "\", \"" << value
<< "\") failed: bad name";
return -1;
return Error() << "is_legal_property_name(" << name << ") failed";
}
if (value_len >= PROP_VALUE_MAX) {
LOG(ERROR) << "do_wait_for_prop(\"" << name << "\", \"" << value
<< "\") failed: value too long";
return -1;
return Error() << "value too long";
}
if (!start_waiting_for_property(name, value)) {
LOG(ERROR) << "do_wait_for_prop(\"" << name << "\", \"" << value
<< "\") failed: init already in waiting";
return -1;
return Error() << "already waiting for a property";
}
return 0;
return Success();
}
static bool is_file_crypto() {
return android::base::GetProperty("ro.crypto.type", "") == "file";
}
static int do_installkey(const std::vector<std::string>& args) {
if (!is_file_crypto()) {
return 0;
}
static Result<Success> do_installkey(const std::vector<std::string>& args) {
if (!is_file_crypto()) return Success();
auto unencrypted_dir = args[1] + e4crypt_unencrypted_folder;
if (!make_dir(unencrypted_dir, 0700) && errno != EEXIST) {
PLOG(ERROR) << "Failed to create " << unencrypted_dir;
return -1;
return ErrnoError() << "Failed to create " << unencrypted_dir;
}
std::vector<std::string> exec_args = {"exec", "/system/bin/vdc", "--wait", "cryptfs",
"enablefilecrypto"};
return do_exec(exec_args);
}
static int do_init_user0(const std::vector<std::string>& args) {
static Result<Success> do_init_user0(const std::vector<std::string>& args) {
std::vector<std::string> exec_args = {"exec", "/system/bin/vdc", "--wait", "cryptfs",
"init_user0"};
return do_exec(exec_args);

View file

@ -23,11 +23,12 @@
#include <vector>
#include "keyword_map.h"
#include "result.h"
namespace android {
namespace init {
using BuiltinFunction = std::function<int(const std::vector<std::string>&)>;
using BuiltinFunction = std::function<Result<Success>(const std::vector<std::string>&)>;
class BuiltinFunctionMap : public KeywordMap<BuiltinFunction> {
public:
BuiltinFunctionMap() {}

View file

@ -238,7 +238,7 @@ void handle_control_message(const std::string& msg, const std::string& name) {
}
}
static int wait_for_coldboot_done_action(const std::vector<std::string>& args) {
static Result<Success> wait_for_coldboot_done_action(const std::vector<std::string>& args) {
Timer t;
LOG(VERBOSE) << "Waiting for " COLDBOOT_DONE "...";
@ -257,22 +257,20 @@ static int wait_for_coldboot_done_action(const std::vector<std::string>& args) {
}
property_set("ro.boottime.init.cold_boot_wait", std::to_string(t.duration().count()));
return 0;
return Success();
}
static int keychord_init_action(const std::vector<std::string>& args)
{
static Result<Success> keychord_init_action(const std::vector<std::string>& args) {
keychord_init();
return 0;
return Success();
}
static int console_init_action(const std::vector<std::string>& args)
{
static Result<Success> console_init_action(const std::vector<std::string>& args) {
std::string console = GetProperty("ro.boot.console", "");
if (!console.empty()) {
default_console = "/dev/" + console;
}
return 0;
return Success();
}
static void import_kernel_nv(const std::string& key, const std::string& value, bool for_emulator) {
@ -354,18 +352,16 @@ static void process_kernel_cmdline() {
if (qemu[0]) import_kernel_cmdline(true, import_kernel_nv);
}
static int property_enable_triggers_action(const std::vector<std::string>& args)
{
static Result<Success> property_enable_triggers_action(const std::vector<std::string>& args) {
/* Enable property triggers. */
property_triggers_enabled = 1;
return 0;
return Success();
}
static int queue_property_triggers_action(const std::vector<std::string>& args)
{
static Result<Success> queue_property_triggers_action(const std::vector<std::string>& args) {
ActionManager::GetInstance().QueueBuiltinAction(property_enable_triggers_action, "enable_property_trigger");
ActionManager::GetInstance().QueueAllPropertyActions();
return 0;
return Success();
}
static void global_seccomp() {

View file

@ -37,7 +37,7 @@ class TestFunctionMap : public KeywordMap<BuiltinFunction> {
void Add(const std::string& name, const BuiltinFunctionNoArgs function) {
Add(name, 0, 0, [function](const std::vector<std::string>&) {
function();
return 0;
return Success();
});
}
@ -174,7 +174,7 @@ TEST(init, EventTriggerOrderMultipleFiles) {
auto execute_command = [&num_executed](const std::vector<std::string>& args) {
EXPECT_EQ(2U, args.size());
EXPECT_EQ(++num_executed, std::stoi(args[1]));
return 0;
return Success();
};
TestFunctionMap test_function_map;

View file

@ -520,7 +520,7 @@ bool HandlePowerctlMessage(const std::string& command) {
auto shutdown_handler = [cmd, command, reboot_target,
run_fsck](const std::vector<std::string>&) {
DoReboot(cmd, command, reboot_target, run_fsck);
return 0;
return Success();
};
ActionManager::GetInstance().QueueBuiltinAction(shutdown_handler, "shutdown_done");

View file

@ -45,24 +45,22 @@ namespace init {
// devices/configurations where these I/O operations are blocking for a long
// time. We do not reboot or halt on failures, as this is a best-effort
// attempt.
int MixHwrngIntoLinuxRngAction(const std::vector<std::string>& args) {
Result<Success> MixHwrngIntoLinuxRngAction(const std::vector<std::string>& args) {
unique_fd hwrandom_fd(
TEMP_FAILURE_RETRY(open("/dev/hw_random", O_RDONLY | O_NOFOLLOW | O_CLOEXEC)));
if (hwrandom_fd == -1) {
if (errno == ENOENT) {
LOG(INFO) << "/dev/hw_random not found";
// It's not an error to not have a Hardware RNG.
return 0;
return Success();
}
PLOG(ERROR) << "Failed to open /dev/hw_random";
return -1;
return ErrnoError() << "Failed to open /dev/hw_random";
}
unique_fd urandom_fd(
TEMP_FAILURE_RETRY(open("/dev/urandom", O_WRONLY | O_NOFOLLOW | O_CLOEXEC)));
if (urandom_fd == -1) {
PLOG(ERROR) << "Failed to open /dev/urandom";
return -1;
return ErrnoError() << "Failed to open /dev/urandom";
}
char buf[512];
@ -71,23 +69,20 @@ int MixHwrngIntoLinuxRngAction(const std::vector<std::string>& args) {
ssize_t chunk_size =
TEMP_FAILURE_RETRY(read(hwrandom_fd, buf, sizeof(buf) - total_bytes_written));
if (chunk_size == -1) {
PLOG(ERROR) << "Failed to read from /dev/hw_random";
return -1;
return ErrnoError() << "Failed to read from /dev/hw_random";
} else if (chunk_size == 0) {
LOG(ERROR) << "Failed to read from /dev/hw_random: EOF";
return -1;
return Error() << "Failed to read from /dev/hw_random: EOF";
}
chunk_size = TEMP_FAILURE_RETRY(write(urandom_fd, buf, chunk_size));
if (chunk_size == -1) {
PLOG(ERROR) << "Failed to write to /dev/urandom";
return -1;
return ErrnoError() << "Failed to write to /dev/urandom";
}
total_bytes_written += chunk_size;
}
LOG(INFO) << "Mixed " << total_bytes_written << " bytes from /dev/hw_random into /dev/urandom";
return 0;
return Success();
}
static bool SetHighestAvailableOptionValue(std::string path, int min, int max) {
@ -154,38 +149,38 @@ static bool __attribute__((unused)) SetMmapRndBitsMin(int start, int min, bool c
// 9e08f57d684a x86: mm: support ARCH_MMAP_RND_BITS
// ec9ee4acd97c drivers: char: random: add get_random_long()
// 5ef11c35ce86 mm: ASLR: use get_random_long()
int SetMmapRndBitsAction(const std::vector<std::string>& args) {
Result<Success> SetMmapRndBitsAction(const std::vector<std::string>& args) {
// values are arch-dependent
#if defined(USER_MODE_LINUX)
// uml does not support mmap_rnd_bits
return 0;
return Success();
#elif defined(__aarch64__)
// arm64 supports 18 - 33 bits depending on pagesize and VA_SIZE
if (SetMmapRndBitsMin(33, 24, false) && SetMmapRndBitsMin(16, 16, true)) {
return 0;
return Success();
}
#elif defined(__x86_64__)
// x86_64 supports 28 - 32 bits
if (SetMmapRndBitsMin(32, 32, false) && SetMmapRndBitsMin(16, 16, true)) {
return 0;
return Success();
}
#elif defined(__arm__) || defined(__i386__)
// check to see if we're running on 64-bit kernel
bool h64 = !access(MMAP_RND_COMPAT_PATH, F_OK);
// supported 32-bit architecture must have 16 bits set
if (SetMmapRndBitsMin(16, 16, h64)) {
return 0;
return Success();
}
#elif defined(__mips__) || defined(__mips64__)
// TODO: add mips support b/27788820
return 0;
return Success();
#else
LOG(ERROR) << "Unknown architecture";
#endif
LOG(ERROR) << "Unable to set adequate mmap entropy value!";
panic();
return -1;
return Error();
}
#define KPTR_RESTRICT_PATH "/proc/sys/kernel/kptr_restrict"
@ -195,14 +190,15 @@ int SetMmapRndBitsAction(const std::vector<std::string>& args) {
// Set kptr_restrict to the highest available level.
//
// Aborts if unable to set this to an acceptable value.
int SetKptrRestrictAction(const std::vector<std::string>& args) {
Result<Success> SetKptrRestrictAction(const std::vector<std::string>& args) {
std::string path = KPTR_RESTRICT_PATH;
if (!SetHighestAvailableOptionValue(path, KPTR_RESTRICT_MINVALUE, KPTR_RESTRICT_MAXVALUE)) {
LOG(ERROR) << "Unable to set adequate kptr_restrict value!";
panic();
return Error();
}
return 0;
return Success();
}
} // namespace init

View file

@ -20,12 +20,14 @@
#include <string>
#include <vector>
#include "result.h"
namespace android {
namespace init {
int MixHwrngIntoLinuxRngAction(const std::vector<std::string>& args);
int SetMmapRndBitsAction(const std::vector<std::string>& args);
int SetKptrRestrictAction(const std::vector<std::string>& args);
Result<Success> MixHwrngIntoLinuxRngAction(const std::vector<std::string>& args);
Result<Success> SetMmapRndBitsAction(const std::vector<std::string>& args);
Result<Success> SetKptrRestrictAction(const std::vector<std::string>& args);
} // namespace init
} // namespace android