init: introduce Result<T> for return values and error handling

init tries to propagate error information up to build context before
logging errors.  This is a good thing, however too often init has the
overly verbose paradigm for error handling, below:

bool CalculateResult(const T& input, U* output, std::string* err)

bool CalculateAndUseResult(const T& input, std::string* err) {
  U output;
  std::string calculate_result_err;
  if (!CalculateResult(input, &output, &calculate_result_err)) {
    *err = "CalculateResult " + input + " failed: " +
      calculate_result_err;
      return false;
  }
  UseResult(output);
  return true;
}

Even more common are functions that return only true/false but also
require passing a std::string* err in order to see the error message.

This change introduces a Result<T> that is use to either hold a
successful return value of type T or to hold an error message as a
std::string.  If the functional only returns success or a failure with
an error message, Result<Success> may be used.  The classes Error and
ErrnoError are used to indicate a failed Result<T>.

A successful Result<T> is constructed implicitly from any type that
can be implicitly converted to T or from the constructor arguments for
T.  This allows you to return a type T directly from a function that
returns Result<T>.

Error and ErrnoError are used to construct a Result<T> has
failed. Each of these classes take an ostream as an input and are
implicitly cast to a Result<T> containing that failure.  ErrnoError()
additionally appends ": " + strerror(errno) to the end of  the failure
string to aid in interacting with C APIs.

The end result is that the above code snippet is turned into the much
clearer example below:

Result<U> CalculateResult(const T& input);

Result<Success> CalculateAndUseResult(const T& input) {
  auto output = CalculateResult(input);
  if (!output) {
    return Error() << "CalculateResult " << input << " failed: "
                   << output.error();
  }
  UseResult(*output);
  return Success();
}

This change also makes this conversion for some of the util.cpp
functions that used the old paradigm.

Test: boot bullhead, init unit tests
Merged-In: I1e7d3a8820a79362245041251057fbeed2f7979b
Change-Id: I1e7d3a8820a79362245041251057fbeed2f7979b
diff --git a/init/util.cpp b/init/util.cpp
index e037987..fcf7ca8 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -57,30 +57,20 @@
 const std::string kDefaultAndroidDtDir("/proc/device-tree/firmware/android/");
 
 // DecodeUid() - decodes and returns the given string, which can be either the
-// numeric or name representation, into the integer uid or gid. Returns
-// UINT_MAX on error.
-bool DecodeUid(const std::string& name, uid_t* uid, std::string* err) {
-    *uid = UINT_MAX;
-    *err = "";
-
+// numeric or name representation, into the integer uid or gid.
+Result<uid_t> DecodeUid(const std::string& name) {
     if (isalpha(name[0])) {
         passwd* pwd = getpwnam(name.c_str());
-        if (!pwd) {
-            *err = "getpwnam failed: "s + strerror(errno);
-            return false;
-        }
-        *uid = pwd->pw_uid;
-        return true;
+        if (!pwd) return ErrnoError() << "getpwnam failed";
+
+        return pwd->pw_uid;
     }
 
     errno = 0;
     uid_t result = static_cast<uid_t>(strtoul(name.c_str(), 0, 0));
-    if (errno) {
-        *err = "strtoul failed: "s + strerror(errno);
-        return false;
-    }
-    *uid = result;
-    return true;
+    if (errno) return ErrnoError() << "strtoul failed";
+
+    return result;
 }
 
 /*
@@ -164,50 +154,40 @@
     return -1;
 }
 
-bool ReadFile(const std::string& path, std::string* content, std::string* err) {
-    content->clear();
-    *err = "";
-
+Result<std::string> ReadFile(const std::string& path) {
     android::base::unique_fd fd(
         TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC)));
     if (fd == -1) {
-        *err = "Unable to open '" + path + "': " + strerror(errno);
-        return false;
+        return ErrnoError() << "open() failed";
     }
 
     // For security reasons, disallow world-writable
     // or group-writable files.
     struct stat sb;
     if (fstat(fd, &sb) == -1) {
-        *err = "fstat failed for '" + path + "': " + strerror(errno);
-        return false;
+        return ErrnoError() << "fstat failed()";
     }
     if ((sb.st_mode & (S_IWGRP | S_IWOTH)) != 0) {
-        *err = "Skipping insecure file '" + path + "'";
-        return false;
+        return Error() << "Skipping insecure file";
     }
 
-    if (!android::base::ReadFdToString(fd, content)) {
-        *err = "Unable to read '" + path + "': " + strerror(errno);
-        return false;
+    std::string content;
+    if (!android::base::ReadFdToString(fd, &content)) {
+        return ErrnoError() << "Unable to read file contents";
     }
-    return true;
+    return content;
 }
 
-bool WriteFile(const std::string& path, const std::string& content, std::string* err) {
-    *err = "";
-
+Result<Success> WriteFile(const std::string& path, const std::string& content) {
     android::base::unique_fd fd(TEMP_FAILURE_RETRY(
         open(path.c_str(), O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC | O_CLOEXEC, 0600)));
     if (fd == -1) {
-        *err = "Unable to open '" + path + "': " + strerror(errno);
-        return false;
+        return ErrnoError() << "open() failed";
     }
     if (!android::base::WriteStringToFd(content, fd)) {
-        *err = "Unable to write to '" + path + "': " + strerror(errno);
-        return false;
+        return ErrnoError() << "Unable to write file contents";
     }
-    return true;
+    return Success();
 }
 
 bool mkdir_recursive(const std::string& path, mode_t mode) {