init: ignore ENOENT from fewer builtins

Previously we were ignoring ENOENT from all builtins as
rootdir/init.rc has many legacy commands that we need to keep for
backwards compatibility, but are otherwise no longer relevant.

However, this wasn't catching actual issues, for example chown failing
due to not finding the user or group name.  This change therefore
reduces the scope of ignoring ENOENT to the only the extraneous errors
in builtins.

Test: boot CF and walleye without seeing errors from init.rc
Test: see errors from invalid users/groups in chown
Change-Id: Ia8e14fa2591e083cb1736c313a3e55515bc5d15e
This commit is contained in:
Tom Cherry 2019-07-30 10:51:59 -07:00
parent 244d9b8fb9
commit d17c37952d
2 changed files with 47 additions and 22 deletions

View file

@ -123,18 +123,8 @@ void Action::ExecuteCommand(const Command& command) const {
auto result = command.InvokeFunc(subcontext_);
auto duration = t.duration();
// There are many legacy paths in rootdir/init.rc that will virtually never exist on a new
// device, such as '/sys/class/leds/jogball-backlight/brightness'. As of this writing, there
// are 198 such failures on bullhead. Instead of spamming the log reporting them, we do not
// report such failures unless we're running at the DEBUG log level.
bool report_failure = !result.has_value();
if (report_failure && android::base::GetMinimumLogSeverity() > android::base::DEBUG &&
result.error().code() == ENOENT) {
report_failure = false;
}
// Any action longer than 50ms will be warned to user as slow operation
if (report_failure || duration > 50ms ||
if (!result.has_value() || duration > 50ms ||
android::base::GetMinimumLogSeverity() <= android::base::DEBUG) {
std::string trigger_name = BuildTriggersString();
std::string cmd_str = command.BuildCommandString();

View file

@ -89,6 +89,43 @@ using android::fs_mgr::ReadFstabFromFile;
namespace android {
namespace init {
// There are many legacy paths in rootdir/init.rc that will virtually never exist on a new
// device, such as '/sys/class/leds/jogball-backlight/brightness'. As of this writing, there
// are 81 such failures on cuttlefish. Instead of spamming the log reporting them, we do not
// report such failures unless we're running at the DEBUG log level.
class ErrorIgnoreEnoent {
public:
ErrorIgnoreEnoent()
: ignore_error_(errno == ENOENT &&
android::base::GetMinimumLogSeverity() > android::base::DEBUG) {}
explicit ErrorIgnoreEnoent(int errno_to_append)
: error_(errno_to_append),
ignore_error_(errno_to_append == ENOENT &&
android::base::GetMinimumLogSeverity() > android::base::DEBUG) {}
template <typename T>
operator android::base::expected<T, ResultError>() {
if (ignore_error_) {
return {};
}
return error_;
}
template <typename T>
ErrorIgnoreEnoent& operator<<(T&& t) {
error_ << t;
return *this;
}
private:
Error error_;
bool ignore_error_;
};
inline ErrorIgnoreEnoent ErrnoErrorIgnoreEnoent() {
return ErrorIgnoreEnoent(errno);
}
std::vector<std::string> late_import_paths;
static constexpr std::chrono::nanoseconds kCommandRetryTimeout = 5s;
@ -330,7 +367,7 @@ static Result<void> do_mkdir(const BuiltinArguments& args) {
return ErrnoError() << "fchmodat() failed";
}
} else {
return ErrnoError() << "mkdir() failed";
return ErrnoErrorIgnoreEnoent() << "mkdir() failed";
}
}
@ -459,7 +496,7 @@ static Result<void> do_mount(const BuiltinArguments& args) {
if (wait)
wait_for_file(source, kCommandRetryTimeout);
if (mount(source, target, system, flags, options) < 0) {
return ErrnoError() << "mount() failed";
return ErrnoErrorIgnoreEnoent() << "mount() failed";
}
}
@ -683,7 +720,7 @@ static Result<void> do_start(const BuiltinArguments& args) {
Service* svc = ServiceList::GetInstance().FindService(args[1]);
if (!svc) return Error() << "service " << args[1] << " not found";
if (auto result = svc->Start(); !result) {
return Error() << "Could not start service: " << result.error();
return ErrorIgnoreEnoent() << "Could not start service: " << result.error();
}
return {};
}
@ -729,10 +766,7 @@ static Result<void> do_symlink(const BuiltinArguments& args) {
if (MakeSymlink(args[1], args[2]) < 0) {
// The symlink builtin is often used to create symlinks for older devices to be backwards
// compatible with new paths, therefore we skip reporting this error.
if (errno == EEXIST && android::base::GetMinimumLogSeverity() > android::base::DEBUG) {
return {};
}
return ErrnoError() << "symlink() failed";
return ErrnoErrorIgnoreEnoent() << "symlink() failed";
}
return {};
}
@ -790,7 +824,8 @@ static Result<void> do_verity_update_state(const BuiltinArguments& args) {
static Result<void> do_write(const BuiltinArguments& args) {
if (auto result = WriteFile(args[1], args[2]); !result) {
return Error() << "Unable to write to file '" << args[1] << "': " << result.error();
return ErrorIgnoreEnoent()
<< "Unable to write to file '" << args[1] << "': " << result.error();
}
return {};
@ -908,7 +943,7 @@ static Result<void> do_chown(const BuiltinArguments& args) {
}
if (lchown(path.c_str(), *uid, *gid) == -1) {
return ErrnoError() << "lchown() failed";
return ErrnoErrorIgnoreEnoent() << "lchown() failed";
}
return {};
@ -930,7 +965,7 @@ static mode_t get_mode(const char *s) {
static Result<void> do_chmod(const BuiltinArguments& args) {
mode_t mode = get_mode(args[1].c_str());
if (fchmodat(AT_FDCWD, args[2].c_str(), mode, AT_SYMLINK_NOFOLLOW) < 0) {
return ErrnoError() << "fchmodat() failed";
return ErrnoErrorIgnoreEnoent() << "fchmodat() failed";
}
return {};
}
@ -973,7 +1008,7 @@ static Result<void> do_restorecon(const BuiltinArguments& args) {
}
}
if (ret) return ErrnoError() << "selinux_android_restorecon() failed";
if (ret) return ErrnoErrorIgnoreEnoent() << "selinux_android_restorecon() failed";
return {};
}