Merge "debuggerd: prepare to abandon ship^Wgdb."
diff --git a/NOTICE b/NOTICE
deleted file mode 100644
index 8e8a91c..0000000
--- a/NOTICE
+++ /dev/null
@@ -1,16 +0,0 @@
-Copyright (C) 2017 The Android Open Source Project
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-     http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
--------------------------------------------------------------------
-
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index ae2cd0a..04e1e4e 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -153,14 +153,14 @@
   }
 
   struct timeval tv = {
-      .tv_sec = 1 * android::base::TimeoutMultiplier(),
+      .tv_sec = 1 * android::base::HwTimeoutMultiplier(),
       .tv_usec = 0,
   };
   if (setsockopt(amfd.get(), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) == -1) {
     PLOG(ERROR) << "failed to set send timeout on activity manager socket";
     return false;
   }
-  tv.tv_sec = 3 * android::base::TimeoutMultiplier();  // 3 seconds on handshake read
+  tv.tv_sec = 3 * android::base::HwTimeoutMultiplier();  // 3 seconds on handshake read
   if (setsockopt(amfd.get(), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {
     PLOG(ERROR) << "failed to set receive timeout on activity manager socket";
     return false;
@@ -448,7 +448,7 @@
   //
   // Note: processes with many threads and minidebug-info can take a bit to
   //       unwind, do not make this too small. b/62828735
-  alarm(30 * android::base::TimeoutMultiplier());
+  alarm(30 * android::base::HwTimeoutMultiplier());
 
   // Get the process name (aka cmdline).
   std::string process_name = get_process_name(g_target_thread);
diff --git a/debuggerd/crasher/Android.bp b/debuggerd/crasher/Android.bp
index 7975a3a..23b106e 100644
--- a/debuggerd/crasher/Android.bp
+++ b/debuggerd/crasher/Android.bp
@@ -13,7 +13,6 @@
         "-Werror",
         "-O0",
         "-fstack-protector-all",
-        "-Wno-free-nonheap-object",
         "-Wno-date-time",
     ],
     srcs: ["crasher.cpp"],
diff --git a/debuggerd/crasher/crasher.cpp b/debuggerd/crasher/crasher.cpp
index a2b13a3..db30b8f 100644
--- a/debuggerd/crasher/crasher.cpp
+++ b/debuggerd/crasher/crasher.cpp
@@ -134,10 +134,14 @@
     return a*2;
 }
 
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wfree-nonheap-object"
+
 noinline void abuse_heap() {
     char buf[16];
     free(buf); // GCC is smart enough to warn about this, but we're doing it deliberately.
 }
+#pragma clang diagnostic pop
 
 noinline void leak() {
     while (true) {
diff --git a/debuggerd/libdebuggerd/test/sys/system_properties.h b/debuggerd/libdebuggerd/test/sys/system_properties.h
deleted file mode 100644
index 1f4f58a..0000000
--- a/debuggerd/libdebuggerd/test/sys/system_properties.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef _DEBUGGERD_TEST_SYS_SYSTEM_PROPERTIES_H
-#define _DEBUGGERD_TEST_SYS_SYSTEM_PROPERTIES_H
-
-// This is just enough to get the property code to compile on
-// the host.
-
-#define PROP_VALUE_MAX  92
-
-#endif // _DEBUGGERD_TEST_SYS_SYSTEM_PROPERTIES_H
diff --git a/debuggerd/tombstoned/intercept_manager.cpp b/debuggerd/tombstoned/intercept_manager.cpp
index 4d4646a..613e6f5 100644
--- a/debuggerd/tombstoned/intercept_manager.cpp
+++ b/debuggerd/tombstoned/intercept_manager.cpp
@@ -163,7 +163,7 @@
     event_assign(intercept->intercept_event, intercept_manager->base, sockfd, EV_READ | EV_TIMEOUT,
                  intercept_close_cb, arg);
 
-    struct timeval timeout = {.tv_sec = 10 * android::base::TimeoutMultiplier(), .tv_usec = 0};
+    struct timeval timeout = {.tv_sec = 10 * android::base::HwTimeoutMultiplier(), .tv_usec = 0};
     event_add(intercept->intercept_event, &timeout);
   }
 
@@ -179,7 +179,7 @@
   intercept->intercept_manager = static_cast<InterceptManager*>(arg);
   intercept->sockfd.reset(sockfd);
 
-  struct timeval timeout = {1 * android::base::TimeoutMultiplier(), 0};
+  struct timeval timeout = {1 * android::base::HwTimeoutMultiplier(), 0};
   event_base* base = evconnlistener_get_base(listener);
   event* intercept_event =
     event_new(base, sockfd, EV_TIMEOUT | EV_READ, intercept_request_cb, intercept);
diff --git a/debuggerd/tombstoned/tombstoned.cpp b/debuggerd/tombstoned/tombstoned.cpp
index bc2d33d..0b87b7a 100644
--- a/debuggerd/tombstoned/tombstoned.cpp
+++ b/debuggerd/tombstoned/tombstoned.cpp
@@ -320,7 +320,7 @@
   }
 
   // TODO: Make this configurable by the interceptor?
-  struct timeval timeout = {10 * android::base::TimeoutMultiplier(), 0};
+  struct timeval timeout = {10 * android::base::HwTimeoutMultiplier(), 0};
 
   event_base* base = event_get_base(crash->crash_event);
 
@@ -340,7 +340,7 @@
 
   // TODO: Make sure that only java crashes come in on the java socket
   // and only native crashes on the native socket.
-  struct timeval timeout = {1 * android::base::TimeoutMultiplier(), 0};
+  struct timeval timeout = {1 * android::base::HwTimeoutMultiplier(), 0};
   event* crash_event = event_new(base, sockfd, EV_TIMEOUT | EV_READ, crash_request_cb, crash);
   crash->crash_socket_fd.reset(sockfd);
   crash->crash_event = crash_event;
diff --git a/libkeyutils/Android.bp b/libkeyutils/Android.bp
index 9848cd8..86f68fb 100644
--- a/libkeyutils/Android.bp
+++ b/libkeyutils/Android.bp
@@ -2,25 +2,10 @@
     default_applicable_licenses: ["system_core_libkeyutils_license"],
 }
 
-// Added automatically by a large-scale-change that took the approach of
-// 'apply every license found to every target'. While this makes sure we respect
-// every license restriction, it may not be entirely correct.
-//
-// e.g. GPL in an MIT project might only apply to the contrib/ directory.
-//
-// Please consider splitting the single license below into multiple licenses,
-// taking care not to lose any license_kind information, and overriding the
-// default license using the 'licenses: [...]' property on targets as needed.
-//
-// For unused files, consider creating a 'fileGroup' with "//visibility:private"
-// to attach the license to, and including a comment whether the files may be
-// used in the current project.
-// See: http://go/android-license-faq
 license {
     name: "system_core_libkeyutils_license",
     visibility: [":__subpackages__"],
     license_kinds: [
-        "SPDX-license-identifier-Apache-2.0",
         "SPDX-license-identifier-BSD",
     ],
     // large-scale-change unable to identify any license_text files
diff --git a/llkd/libllkd.cpp b/llkd/libllkd.cpp
index b3101f4..c4c58ee 100644
--- a/llkd/libllkd.cpp
+++ b/llkd/libllkd.cpp
@@ -962,7 +962,8 @@
     //
     // This alarm is effectively the live lock detection of llkd, as
     // we understandably can not monitor ourselves otherwise.
-    ::alarm(duration_cast<seconds>(llkTimeoutMs * 2 * android::base::TimeoutMultiplier()).count());
+    ::alarm(duration_cast<seconds>(llkTimeoutMs * 2 * android::base::HwTimeoutMultiplier())
+                    .count());
 
     // kernel jiffy precision fastest acquisition
     static timespec last;
diff --git a/libkeyutils/mini_keyctl/Android.bp b/mini_keyctl/Android.bp
similarity index 100%
rename from libkeyutils/mini_keyctl/Android.bp
rename to mini_keyctl/Android.bp
diff --git a/libkeyutils/mini_keyctl/mini_keyctl.cpp b/mini_keyctl/mini_keyctl.cpp
similarity index 100%
rename from libkeyutils/mini_keyctl/mini_keyctl.cpp
rename to mini_keyctl/mini_keyctl.cpp
diff --git a/libkeyutils/mini_keyctl/mini_keyctl_utils.cpp b/mini_keyctl/mini_keyctl_utils.cpp
similarity index 100%
rename from libkeyutils/mini_keyctl/mini_keyctl_utils.cpp
rename to mini_keyctl/mini_keyctl_utils.cpp
diff --git a/libkeyutils/mini_keyctl/mini_keyctl_utils.h b/mini_keyctl/mini_keyctl_utils.h
similarity index 100%
rename from libkeyutils/mini_keyctl/mini_keyctl_utils.h
rename to mini_keyctl/mini_keyctl_utils.h
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 58e161d..6b8868b 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -884,9 +884,12 @@
     wait_for_prop apexd.status activated
     perform_apex_config
 
-    # Export *CLASSPATH variables from /etc/classpath
-    # TODO(b/180105615): export from the generated file instead.
-    load_exports /etc/classpath
+    # Define and export *CLASSPATH variables
+    mkdir /data/system/environ 0700 system system
+    # Must start before 'odsign', as odsign depends on *CLASSPATH variables
+    exec_start derive_classpath
+    load_exports /data/system/environ/classpath
+    rm /data/system/environ/classpath
 
     # Special-case /data/media/obb per b/64566063
     mkdir /data/media 0770 media_rw media_rw encryption=None
@@ -902,6 +905,7 @@
 
     # Start the on-device signing daemon, and wait for it to finish, to ensure
     # ART artifacts are generated if needed.
+    # Must start after 'derive_classpath' to have *CLASSPATH variables set.
     exec_start odsign
 
     # After apexes are mounted, tell keymaster early boot has ended, so it will
@@ -1074,7 +1078,7 @@
     chown root radio /proc/cmdline
 
     # Define default initial receive window size in segments.
-    setprop net.tcp.default_init_rwnd 60
+    setprop net.tcp_def_init_rwnd 60
 
     # Start standard binderized HAL daemons
     class_start hal
diff --git a/trusty/utils/acvp/Android.bp b/trusty/utils/acvp/Android.bp
new file mode 100644
index 0000000..6fe193e
--- /dev/null
+++ b/trusty/utils/acvp/Android.bp
@@ -0,0 +1,36 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at //
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_binary {
+    name: "trusty_acvp_modulewrapper",
+    vendor: true,
+
+    srcs: [
+        "trusty_modulewrapper.cpp",
+    ],
+    static_libs: [
+        "libacvp_modulewrapper",
+    ],
+    shared_libs: [
+        "libbase",
+        "libc",
+        "libdmabufheap",
+        "liblog",
+        "libtrusty",
+        "libssl",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+}
diff --git a/trusty/utils/acvp/acvp_ipc.h b/trusty/utils/acvp/acvp_ipc.h
new file mode 100644
index 0000000..8b48ae3
--- /dev/null
+++ b/trusty/utils/acvp/acvp_ipc.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ACVP_PORT "com.android.trusty.acvp"
+
+/*
+ * Maximum number of arguments
+ */
+#define ACVP_MAX_NUM_ARGUMENTS 8
+
+/*
+ * Maximum length of an algorithm name
+ */
+#define ACVP_MAX_NAME_LENGTH 30
+
+/*
+ * Maximum length of an ACVP request message
+ */
+#define ACVP_MAX_MESSAGE_LENGTH sizeof(struct acvp_req)
+
+/*
+ * Minimum length of the shared memory buffer
+ *
+ * This must be at least as long as the longest reply from the ACVP service
+ * (currently the reply from getConfig()).
+ */
+#define ACVP_MIN_SHARED_MEMORY 16384
+
+/**
+ * acvp_req - Request for the Trusty ACVP app
+ * @num_args: Number of acvp_arg structures following this struct
+ * @buffer_size: Total size of shared memory buffer
+ * @lengths: Length of each argument in the shared memory buffer
+ *
+ * @num_args copies of the acvp_arg struct follow this structure.
+ */
+struct acvp_req {
+    uint32_t num_args;
+    uint32_t buffer_size;
+    uint32_t lengths[ACVP_MAX_NUM_ARGUMENTS];
+};
+
+/**
+ * acvp_resp - Response to a ACVP request
+ *
+ * @num_spans: Number of response sections
+ * @lengths: Length of each response section
+ */
+struct acvp_resp {
+    uint32_t num_spans;
+    uint32_t lengths[ACVP_MAX_NUM_ARGUMENTS];
+};
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
diff --git a/trusty/utils/acvp/trusty_modulewrapper.cpp b/trusty/utils/acvp/trusty_modulewrapper.cpp
new file mode 100644
index 0000000..70ffb52
--- /dev/null
+++ b/trusty/utils/acvp/trusty_modulewrapper.cpp
@@ -0,0 +1,235 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "TrustyAcvpModulewrapper"
+
+#include <BufferAllocator/BufferAllocator.h>
+#include <android-base/file.h>
+#include <android-base/result.h>
+#include <android-base/unique_fd.h>
+#include <errno.h>
+#include <log/log.h>
+#include <modulewrapper.h>
+#include <openssl/span.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <trusty/tipc.h>
+#include <unistd.h>
+#include <iostream>
+
+#include "acvp_ipc.h"
+
+constexpr const char kTrustyDeviceName[] = "/dev/trusty-ipc-dev0";
+
+using android::base::ErrnoError;
+using android::base::Error;
+using android::base::Result;
+using android::base::unique_fd;
+using android::base::WriteFully;
+
+static inline size_t AlignUpToPage(size_t size) {
+    return (size + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
+}
+
+namespace {
+
+class ModuleWrapper {
+  private:
+    static const char* kAcvpPort_;
+    static const char* kTrustyDeviceName_;
+
+  public:
+    ModuleWrapper();
+    ~ModuleWrapper();
+
+    Result<void> SendMessage(bssl::Span<const bssl::Span<const uint8_t>>);
+
+    Result<void> ForwardResponse();
+
+  private:
+    // Connection to the Trusty ACVP service
+    int tipc_fd_ = -1;
+
+    // Shared memory DMA buf
+    unique_fd dmabuf_fd_;
+
+    // Size of shared memory mapping
+    size_t shm_size_ = 0;
+
+    // Shared memory mapping
+    uint8_t* shm_buffer_ = nullptr;
+};
+
+}  // namespace
+
+const char* ModuleWrapper::kAcvpPort_ = ACVP_PORT;
+const char* ModuleWrapper::kTrustyDeviceName_ = kTrustyDeviceName;
+
+ModuleWrapper::ModuleWrapper() {
+    tipc_fd_ = tipc_connect(kTrustyDeviceName_, kAcvpPort_);
+    if (tipc_fd_ < 0) {
+        fprintf(stderr, "Failed to connect to Trusty ACVP test app: %s\n", strerror(-tipc_fd_));
+    }
+}
+
+ModuleWrapper::~ModuleWrapper() {
+    if (tipc_fd_ >= 0) {
+        tipc_close(tipc_fd_);
+    }
+
+    if (shm_buffer_) {
+        munmap(shm_buffer_, shm_size_);
+    }
+}
+
+Result<void> ModuleWrapper::SendMessage(bssl::Span<const bssl::Span<const uint8_t>> args) {
+    assert(args.size() < ACVP_MAX_NUM_ARGUMENTS);
+    assert(args[0].size() < ACVP_MAX_NAME_LENGTH);
+
+    struct acvp_req request;
+    request.num_args = args.size();
+
+    size_t total_args_size = 0;
+    for (auto arg : args) {
+        total_args_size += arg.size();
+    }
+
+    shm_size_ = ACVP_MIN_SHARED_MEMORY;
+    if (total_args_size > shm_size_) {
+        shm_size_ = AlignUpToPage(total_args_size);
+    }
+    request.buffer_size = shm_size_;
+
+    struct iovec iov = {
+            .iov_base = &request,
+            .iov_len = sizeof(struct acvp_req),
+    };
+
+    BufferAllocator alloc;
+    dmabuf_fd_.reset(alloc.Alloc(kDmabufSystemHeapName, shm_size_));
+    if (!dmabuf_fd_.ok()) {
+        return ErrnoError() << "Error creating dmabuf";
+    }
+
+    shm_buffer_ = (uint8_t*)mmap(0, shm_size_, PROT_READ | PROT_WRITE, MAP_SHARED, dmabuf_fd_, 0);
+    if (shm_buffer_ == MAP_FAILED) {
+        return ErrnoError() << "Failed to map shared memory dmabuf";
+    }
+
+    size_t cur_offset = 0;
+    for (int i = 0; i < args.size(); ++i) {
+        request.lengths[i] = args[i].size();
+        memcpy(shm_buffer_ + cur_offset, args[i].data(), args[i].size());
+        cur_offset += args[i].size();
+    }
+
+    struct trusty_shm shm = {
+            .fd = dmabuf_fd_.get(),
+            .transfer = TRUSTY_SHARE,
+    };
+
+    int rc = tipc_send(tipc_fd_, &iov, 1, &shm, 1);
+    if (rc != sizeof(struct acvp_req)) {
+        return ErrnoError() << "Failed to send request to Trusty ACVP service";
+    }
+
+    return {};
+}
+
+Result<void> ModuleWrapper::ForwardResponse() {
+    struct acvp_resp resp;
+    int bytes_read = read(tipc_fd_, &resp, sizeof(struct acvp_resp));
+    if (bytes_read < 0) {
+        return ErrnoError() << "Failed to read response from Trusty ACVP service";
+    }
+
+    if (bytes_read != sizeof(struct acvp_resp)) {
+        return Error() << "Trusty ACVP response overflowed expected size";
+    }
+
+    size_t total_args_size = 0;
+    for (size_t i = 0; i < resp.num_spans; i++) {
+        total_args_size += resp.lengths[i];
+    }
+
+    iovec iovs[2];
+    iovs[0].iov_base = &resp;
+    iovs[0].iov_len = sizeof(uint32_t) * (1 + resp.num_spans);
+
+    iovs[1].iov_base = shm_buffer_;
+    iovs[1].iov_len = total_args_size;
+
+    size_t iov_done = 0;
+    while (iov_done < 2) {
+        ssize_t r;
+        do {
+            r = writev(STDOUT_FILENO, &iovs[iov_done], 2 - iov_done);
+        } while (r == -1 && errno == EINTR);
+
+        if (r <= 0) {
+            return Error() << "Failed to write ACVP response to standard out";
+        }
+
+        size_t written = r;
+        for (size_t i = iov_done; i < 2 && written > 0; i++) {
+            iovec& iov = iovs[i];
+
+            size_t done = written;
+            if (done > iov.iov_len) {
+                done = iov.iov_len;
+            }
+
+            iov.iov_base = reinterpret_cast<uint8_t*>(iov.iov_base) + done;
+            iov.iov_len -= done;
+            written -= done;
+
+            if (iov.iov_len == 0) {
+                iov_done++;
+            }
+        }
+
+        assert(written == 0);
+    }
+
+    return {};
+}
+
+int main() {
+    for (;;) {
+        auto buffer = bssl::acvp::RequestBuffer::New();
+        auto args = bssl::acvp::ParseArgsFromFd(STDIN_FILENO, buffer.get());
+        if (args.empty()) {
+            ALOGE("Could not parse arguments\n");
+            return EXIT_FAILURE;
+        }
+
+        ModuleWrapper wrapper;
+        auto res = wrapper.SendMessage(args);
+        if (!res.ok()) {
+            std::cerr << res.error() << std::endl;
+            return EXIT_FAILURE;
+        }
+
+        res = wrapper.ForwardResponse();
+        if (!res.ok()) {
+            std::cerr << res.error() << std::endl;
+            return EXIT_FAILURE;
+        }
+    }
+
+    return EXIT_SUCCESS;
+};