From 557946e57c375b05deb5ba07b739f27abc70697e Mon Sep 17 00:00:00 2001 From: Tom Cherry Date: Tue, 1 Aug 2017 13:50:23 -0700 Subject: [PATCH] init: use Result 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 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 --- init/action.cpp | 13 +- init/action.h | 3 +- init/bootchart.cpp | 48 ++--- init/bootchart.h | 4 +- init/builtins.cpp | 493 +++++++++++++++++++++++---------------------- init/builtins.h | 3 +- init/init.cpp | 24 +-- init/init_test.cpp | 4 +- init/reboot.cpp | 2 +- init/security.cpp | 40 ++-- init/security.h | 8 +- 11 files changed, 323 insertions(+), 319 deletions(-) diff --git a/init/action.cpp b/init/action.cpp index 4ec5f1739..671e285e1 100644 --- a/init/action.cpp +++ b/init/action.cpp @@ -31,14 +31,13 @@ namespace init { Command::Command(BuiltinFunction f, const std::vector& args, int line) : func_(f), args_(args), line_(line) {} -int Command::InvokeFunc() const { +Result Command::InvokeFunc() const { std::vector 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()); } } diff --git a/init/action.h b/init/action.h index 50cae7171..44ecd237b 100644 --- a/init/action.h +++ b/init/action.h @@ -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& args, int line); - int InvokeFunc() const; + Result InvokeFunc() const; std::string BuildCommandString() const; int line() const { return line_; } diff --git a/init/bootchart.cpp b/init/bootchart.cpp index 4727f92e9..ec84317c3 100644 --- a/init/bootchart.cpp +++ b/init/bootchart.cpp @@ -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 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 do_bootchart_stop() { + if (!g_bootcharting_thread) return Success(); - // Tell the worker thread it's time to quit. - { - std::lock_guard 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 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& args) { - if (args[1] == "start") return do_bootchart_start(); - return do_bootchart_stop(); +Result do_bootchart(const std::vector& args) { + if (args[1] == "start") return do_bootchart_start(); + return do_bootchart_stop(); } } // namespace init diff --git a/init/bootchart.h b/init/bootchart.h index e4f7b59b2..f614f712f 100644 --- a/init/bootchart.h +++ b/init/bootchart.h @@ -20,10 +20,12 @@ #include #include +#include "result.h" + namespace android { namespace init { -int do_bootchart(const std::vector& args); +Result do_bootchart(const std::vector& args); } // namespace init } // namespace android diff --git a/init/builtins.cpp b/init/builtins.cpp index 28f60e6ac..f807343ab 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -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& options) { +static Result reboot_into_recovery(const std::vector& 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 @@ -128,88 +94,106 @@ static void ForEachServiceInClass(const std::string& classname, F function) { } } -static int do_class_start(const std::vector& args) { +static Result do_class_start(const std::vector& 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& args) { +static Result do_class_stop(const std::vector& args) { ForEachServiceInClass(args[1], &Service::Stop); - return 0; + return Success(); } -static int do_class_reset(const std::vector& args) { +static Result do_class_reset(const std::vector& args) { ForEachServiceInClass(args[1], &Service::Reset); - return 0; + return Success(); } -static int do_class_restart(const std::vector& args) { +static Result do_class_restart(const std::vector& args) { ForEachServiceInClass(args[1], &Service::Restart); - return 0; + return Success(); } -static int do_domainname(const std::vector& args) { +static Result do_domainname(const std::vector& 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& args) { +static Result do_enable(const std::vector& 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& args) { +static Result do_exec(const std::vector& 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& args) { +static Result do_exec_start(const std::vector& 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& args) { - return add_environment(args[1].c_str(), args[2].c_str()); +static Result do_export(const std::vector& args) { + if (!add_environment(args[1].c_str(), args[2].c_str())) { + return Error(); + } + return Success(); } -static int do_hostname(const std::vector& args) { +static Result do_hostname(const std::vector& 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& args) { - return __ifupdown(args[1].c_str(), 1); +static Result do_ifup(const std::vector& 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& args) { +static Result do_insmod(const std::vector& args) { int flags = 0; auto it = args.begin() + 1; @@ -220,11 +204,18 @@ static int do_insmod(const std::vector& args) { std::string filename = *it++; std::string options = android::base::Join(std::vector(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 [mode] [owner] [group] -static int do_mkdir(const std::vector& args) { +static Result do_mkdir(const std::vector& 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& 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 = -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& 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 */ -static int do_umount(const std::vector& args) { - return umount(args[1].c_str()); +static Result do_umount(const std::vector& 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 */ -static int do_mount(const std::vector& args) { +static Result do_mount(const std::vector& args) { const char* options = nullptr; unsigned flags = 0; bool wait = false; @@ -342,12 +334,12 @@ static int do_mount(const std::vector& 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& 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& 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 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 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 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 [ ]* [--]* @@ -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& args) { +static Result do_mount_all(const std::vector& 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& 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& 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& args) { +static Result do_swapon_all(const std::vector& args) { struct fstab *fstab; int ret; @@ -554,89 +551,103 @@ static int do_swapon_all(const std::vector& 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& args) { +static Result do_setprop(const std::vector& args) { property_set(args[1], args[2]); - return 0; + return Success(); } -static int do_setrlimit(const std::vector& args) { - struct rlimit limit; +static Result do_setrlimit(const std::vector& 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& args) { +static Result do_start(const std::vector& 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& args) { +static Result do_stop(const std::vector& 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& args) { +static Result do_restart(const std::vector& 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& args) { +static Result do_trigger(const std::vector& args) { ActionManager::GetInstance().QueueEventTrigger(args[1]); - return 0; + return Success(); } -static int do_symlink(const std::vector& args) { - return symlink(args[1].c_str(), args[2].c_str()); -} - -static int do_rm(const std::vector& args) { - return unlink(args[1].c_str()); -} - -static int do_rmdir(const std::vector& args) { - return rmdir(args[1].c_str()); -} - -static int do_sysclktz(const std::vector& args) { - struct timezone tz = {}; - if (android::base::ParseInt(args[1], &tz.tz_minuteswest) && settimeofday(nullptr, &tz) != -1) { - return 0; +static Result do_symlink(const std::vector& 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& args) { +static Result do_rm(const std::vector& args) { + if (unlink(args[1].c_str()) < 0) { + return ErrnoError() << "unlink() failed"; + } + return Success(); +} + +static Result do_rmdir(const std::vector& args) { + if (rmdir(args[1].c_str()) < 0) { + return ErrnoError() << "rmdir() failed"; + } + return Success(); +} + +static Result do_sysclktz(const std::vector& 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 do_verity_load_state(const std::vector& 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& args) { - return fs_mgr_update_verity_state(verity_update_property) ? 0 : 1; -} - -static int do_write(const std::vector& 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 do_verity_update_state(const std::vector& 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& args) { +static Result do_write(const std::vector& 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 do_readahead(const std::vector& 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& 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& args) { +static Result do_copy(const std::vector& 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& args) { +static Result do_chown(const std::vector& 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& 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& args) { +static Result do_chmod(const std::vector& 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& args) { +static Result do_restorecon(const std::vector& args) { int ret = 0; struct flag_type {const char* name; int value;}; @@ -791,8 +802,7 @@ static int do_restorecon(const std::vector& 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& 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& args) { +static Result do_restorecon_recursive(const std::vector& args) { std::vector 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& args) { +static Result do_loglevel(const std::vector& 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& 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& args) { +static Result do_load_persist_props(const std::vector& args) { load_persist_props(); - return 0; + return Success(); } -static int do_load_system_props(const std::vector& args) { +static Result do_load_system_props(const std::vector& args) { load_system_props(); - return 0; + return Success(); } -static int do_wait(const std::vector& 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 do_wait(const std::vector& 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& args) { +static Result do_wait_for_prop(const std::vector& 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& args) { - if (!is_file_crypto()) { - return 0; - } +static Result do_installkey(const std::vector& 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 exec_args = {"exec", "/system/bin/vdc", "--wait", "cryptfs", "enablefilecrypto"}; return do_exec(exec_args); } -static int do_init_user0(const std::vector& args) { +static Result do_init_user0(const std::vector& args) { std::vector exec_args = {"exec", "/system/bin/vdc", "--wait", "cryptfs", "init_user0"}; return do_exec(exec_args); diff --git a/init/builtins.h b/init/builtins.h index b110f619f..f66ae1940 100644 --- a/init/builtins.h +++ b/init/builtins.h @@ -23,11 +23,12 @@ #include #include "keyword_map.h" +#include "result.h" namespace android { namespace init { -using BuiltinFunction = std::function&)>; +using BuiltinFunction = std::function(const std::vector&)>; class BuiltinFunctionMap : public KeywordMap { public: BuiltinFunctionMap() {} diff --git a/init/init.cpp b/init/init.cpp index ee3a84c29..c65d8460b 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -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& args) { +static Result wait_for_coldboot_done_action(const std::vector& args) { Timer t; LOG(VERBOSE) << "Waiting for " COLDBOOT_DONE "..."; @@ -257,22 +257,20 @@ static int wait_for_coldboot_done_action(const std::vector& 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& args) -{ +static Result keychord_init_action(const std::vector& args) { keychord_init(); - return 0; + return Success(); } -static int console_init_action(const std::vector& args) -{ +static Result console_init_action(const std::vector& 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& args) -{ +static Result property_enable_triggers_action(const std::vector& args) { /* Enable property triggers. */ property_triggers_enabled = 1; - return 0; + return Success(); } -static int queue_property_triggers_action(const std::vector& args) -{ +static Result queue_property_triggers_action(const std::vector& args) { ActionManager::GetInstance().QueueBuiltinAction(property_enable_triggers_action, "enable_property_trigger"); ActionManager::GetInstance().QueueAllPropertyActions(); - return 0; + return Success(); } static void global_seccomp() { diff --git a/init/init_test.cpp b/init/init_test.cpp index 58e3d758e..27659f917 100644 --- a/init/init_test.cpp +++ b/init/init_test.cpp @@ -37,7 +37,7 @@ class TestFunctionMap : public KeywordMap { void Add(const std::string& name, const BuiltinFunctionNoArgs function) { Add(name, 0, 0, [function](const std::vector&) { function(); - return 0; + return Success(); }); } @@ -174,7 +174,7 @@ TEST(init, EventTriggerOrderMultipleFiles) { auto execute_command = [&num_executed](const std::vector& args) { EXPECT_EQ(2U, args.size()); EXPECT_EQ(++num_executed, std::stoi(args[1])); - return 0; + return Success(); }; TestFunctionMap test_function_map; diff --git a/init/reboot.cpp b/init/reboot.cpp index 32816fe40..24ccdfc6a 100644 --- a/init/reboot.cpp +++ b/init/reboot.cpp @@ -520,7 +520,7 @@ bool HandlePowerctlMessage(const std::string& command) { auto shutdown_handler = [cmd, command, reboot_target, run_fsck](const std::vector&) { DoReboot(cmd, command, reboot_target, run_fsck); - return 0; + return Success(); }; ActionManager::GetInstance().QueueBuiltinAction(shutdown_handler, "shutdown_done"); diff --git a/init/security.cpp b/init/security.cpp index 45a5412bf..f8976dec2 100644 --- a/init/security.cpp +++ b/init/security.cpp @@ -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& args) { +Result MixHwrngIntoLinuxRngAction(const std::vector& 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& 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& args) { +Result SetMmapRndBitsAction(const std::vector& 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& args) { // Set kptr_restrict to the highest available level. // // Aborts if unable to set this to an acceptable value. -int SetKptrRestrictAction(const std::vector& args) { +Result SetKptrRestrictAction(const std::vector& 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 diff --git a/init/security.h b/init/security.h index c489de143..31e5790f0 100644 --- a/init/security.h +++ b/init/security.h @@ -20,12 +20,14 @@ #include #include +#include "result.h" + namespace android { namespace init { -int MixHwrngIntoLinuxRngAction(const std::vector& args); -int SetMmapRndBitsAction(const std::vector& args); -int SetKptrRestrictAction(const std::vector& args); +Result MixHwrngIntoLinuxRngAction(const std::vector& args); +Result SetMmapRndBitsAction(const std::vector& args); +Result SetKptrRestrictAction(const std::vector& args); } // namespace init } // namespace android