init: switch host_init_verifier to getopt()

Test: host init verifier works

Change-Id: Ia0fe5994079e6e182a64b14a15fdb36328080168
diff --git a/init/host_init_verifier.cpp b/init/host_init_verifier.cpp
index 1b4716f..9323aa0 100644
--- a/init/host_init_verifier.cpp
+++ b/init/host_init_verifier.cpp
@@ -15,11 +15,13 @@
 //
 
 #include <errno.h>
+#include <getopt.h>
 #include <pwd.h>
 #include <stdio.h>
 #include <stdlib.h>
 
 #include <iostream>
+#include <iterator>
 #include <string>
 #include <vector>
 
@@ -48,9 +50,9 @@
 using android::base::ReadFileToString;
 using android::base::Split;
 
-static std::string passwd_file;
+static std::vector<std::string> passwd_files;
 
-static std::vector<std::pair<std::string, int>> GetVendorPasswd() {
+static std::vector<std::pair<std::string, int>> GetVendorPasswd(const std::string& passwd_file) {
     std::string passwd;
     if (!ReadFileToString(passwd_file, &passwd)) {
         return {};
@@ -72,6 +74,16 @@
     return result;
 }
 
+static std::vector<std::pair<std::string, int>> GetVendorPasswd() {
+    std::vector<std::pair<std::string, int>> result;
+    for (const auto& passwd_file : passwd_files) {
+        auto individual_result = GetVendorPasswd(passwd_file);
+        std::move(individual_result.begin(), individual_result.end(),
+                  std::back_insert_iterator(result));
+    }
+    return result;
+}
+
 passwd* getpwnam(const char* login) {  // NOLINT: implementing bad function.
     // This isn't thread safe, but that's okay for our purposes.
     static char static_name[32] = "";
@@ -126,17 +138,50 @@
 
 #include "generated_stub_builtin_function_map.h"
 
+void PrintUsage() {
+    std::cout << "usage: host_init_verifier [-p FILE] <init rc file>\n"
+                 "\n"
+                 "Tests an init script for correctness\n"
+                 "\n"
+                 "-p FILE\tSearch this passwd file for users and groups\n"
+              << std::endl;
+}
+
 int main(int argc, char** argv) {
     android::base::InitLogging(argv, &android::base::StdioLogger);
     android::base::SetMinimumLogSeverity(android::base::ERROR);
 
-    if (argc != 2 && argc != 3) {
-        LOG(ERROR) << "Usage: " << argv[0] << " <init rc file> [passwd file]";
-        return EXIT_FAILURE;
+    while (true) {
+        static const struct option long_options[] = {
+                {"help", no_argument, nullptr, 'h'},
+                {nullptr, 0, nullptr, 0},
+        };
+
+        int arg = getopt_long(argc, argv, "p:", long_options, nullptr);
+
+        if (arg == -1) {
+            break;
+        }
+
+        switch (arg) {
+            case 'h':
+                PrintUsage();
+                return EXIT_FAILURE;
+            case 'p':
+                passwd_files.emplace_back(optarg);
+                break;
+            default:
+                std::cerr << "getprop: getopt returned invalid result: " << arg << std::endl;
+                return EXIT_FAILURE;
+        }
     }
 
-    if (argc == 3) {
-        passwd_file = argv[2];
+    argc -= optind;
+    argv += optind;
+
+    if (argc != 1) {
+        PrintUsage();
+        return EXIT_FAILURE;
     }
 
     const BuiltinFunctionMap function_map;
@@ -148,12 +193,12 @@
     parser.AddSectionParser("on", std::make_unique<ActionParser>(&am, nullptr));
     parser.AddSectionParser("import", std::make_unique<HostImportParser>());
 
-    if (!parser.ParseConfigFileInsecure(argv[1])) {
-        LOG(ERROR) << "Failed to open init rc script '" << argv[1] << "'";
+    if (!parser.ParseConfigFileInsecure(*argv)) {
+        LOG(ERROR) << "Failed to open init rc script '" << *argv << "'";
         return EXIT_FAILURE;
     }
     if (parser.parse_error_count() > 0) {
-        LOG(ERROR) << "Failed to parse init script '" << argv[1] << "' with "
+        LOG(ERROR) << "Failed to parse init script '" << *argv << "' with "
                    << parser.parse_error_count() << " errors";
         return EXIT_FAILURE;
     }