Use common option processing for dinit/dinitcheck service dir
authorDavin McCall <davmac@davmac.org>
Fri, 15 Nov 2019 19:39:27 +0000 (19:39 +0000)
committerDavin McCall <davmac@davmac.org>
Fri, 15 Nov 2019 19:43:38 +0000 (19:43 +0000)
src/Makefile
src/dinit.cc
src/dinitcheck.cc
src/includes/options-processing.h
src/options-processing.cc

index 4a5f07c928343b917e159e03d24ad2fb31c55cd0..8d963183c7a7efb282ac53deec3e5a3e6e5ce98b 100644 (file)
@@ -41,8 +41,8 @@ dinit: $(dinit_objects)
 dinitctl: dinitctl.o
        $(CXX) -o dinitctl dinitctl.o $(LDFLAGS)
 
-dinitcheck: dinitcheck.o
-       $(CXX) -o dinitcheck dinitcheck.o $(LDFLAGS)
+dinitcheck: dinitcheck.o options-processing.o
+       $(CXX) -o dinitcheck dinitcheck.o options-processing.o $(LDFLAGS)
 
 shutdown: shutdown.o
        $(CXX) -o shutdown shutdown.o $(LDFLAGS)
index 8fb405a5c9430f98bd68f4b55d047e1cc75e92a0..7de61560c0b0942fa26e37098595df17367f4138 100644 (file)
@@ -86,27 +86,9 @@ static const char *env_file_path = "/etc/dinit/environment";
 static const char *log_path = "/dev/log";
 static bool log_is_syslog = true; // if false, log is a file
 
-static const char *user_home_path = nullptr;
-
 // Set to true (when console_input_watcher is active) if console input becomes available
 static bool console_input_ready = false;
 
-// Get user home (and set user_home_path). (The return may become invalid after
-// changing the environment (HOME variable) or using the getpwuid() function).
-static const char * get_user_home()
-{
-    if (user_home_path == nullptr) {
-        user_home_path = getenv("HOME");
-        if (user_home_path == nullptr) {
-            struct passwd * pwuid_p = getpwuid(getuid());
-            if (pwuid_p != nullptr) {
-                user_home_path = pwuid_p->pw_dir;
-            }
-        }
-    }
-    return user_home_path;
-}
-
 
 namespace {
     // Event-loop handler for a signal, which just delegates to a function (pointer).
@@ -192,6 +174,7 @@ namespace {
     log_flush_timer_t log_flush_timer;
 }
 
+// Main entry point
 int dinit_main(int argc, char **argv)
 {
     using namespace std;
@@ -344,7 +327,7 @@ int dinit_main(int argc, char **argv)
     signal(SIGPIPE, SIG_IGN);
     
     if (! am_system_init && ! control_socket_path_set) {
-        const char * userhome = get_user_home();
+        const char * userhome = service_dir_opt::get_user_home();
         if (userhome != nullptr) {
             control_socket_str = userhome;
             control_socket_str += "/.dinitctl";
@@ -402,7 +385,7 @@ int dinit_main(int argc, char **argv)
     
     log_flush_timer.add_timer(event_loop, dasynq::clock_type::MONOTONIC);
 
-    service_dir_opts.build_paths();
+    service_dir_opts.build_paths(am_system_init);
 
     /* start requested services */
     services = new dirload_service_set(std::move(service_dir_opts.get_paths()));
index 04c9fd70b9e745e491843a4bdc6211bb03e5368d..7fb74f73fbca78f5410efac4b4dcbb9aff699907 100644 (file)
 using string = std::string;
 using string_iterator = std::string::iterator;
 
-static const char *user_home_path = nullptr;
-
-// Get user home (and set user_home_path). (The return may become invalid after
-// changing the environment (HOME variable) or using the getpwuid() function).
-static const char * get_user_home()
-{
-    if (user_home_path == nullptr) {
-        user_home_path = getenv("HOME");
-        if (user_home_path == nullptr) {
-            struct passwd * pwuid_p = getpwuid(getuid());
-            if (pwuid_p != nullptr) {
-                user_home_path = pwuid_p->pw_dir;
-            }
-        }
-    }
-    return user_home_path;
-}
-
+// prelim_dep: A preliminary (unresolved) service dependency
 class prelim_dep
 {
     public:
@@ -67,7 +50,7 @@ public:
 using service_set_t = std::map<std::string, service_record *>;
 
 service_record *load_service(service_set_t &services, const std::string &name,
-        const std::vector<dir_entry> &service_dirs);
+        const service_dir_pathlist &service_dirs);
 
 // Add some missing standard library functionality...
 template <typename T> bool contains(std::vector<T> vec, const T& elem)
@@ -79,44 +62,33 @@ int main(int argc, char **argv)
 {
     using namespace std;
 
-    bool add_all_service_dirs = false;
-    bool for_system = false;
-    const char * service_dir = nullptr;
-    bool service_dir_dynamic = false; // service_dir dynamically allocated?
+    service_dir_opt service_dir_opts;
+    bool am_system_init = (getuid() == 0);
 
     std::vector<std::string> services_to_check;
 
-    // Figure out service dirs
-    /* service directory name */
-    if (service_dir == nullptr && ! for_system) {
-        const char * userhome = get_user_home();
-        if (userhome != nullptr) {
-            const char * user_home = get_user_home();
-            size_t user_home_len = strlen(user_home);
-            size_t dinit_d_len = strlen("/dinit.d");
-            size_t full_len = user_home_len + dinit_d_len + 1;
-            char *service_dir_w = new char[full_len];
-            std::memcpy(service_dir_w, user_home, user_home_len);
-            std::memcpy(service_dir_w + user_home_len, "/dinit.d", dinit_d_len);
-            service_dir_w[full_len - 1] = 0;
-
-            service_dir = service_dir_w;
-            service_dir_dynamic = true;
+    // Process command line
+    if (argc > 1) {
+        for (int i = 1; i < argc; i++) {
+            if (argv[i][0] == '-') {
+                if (argv[i][0] == '-') {
+                    // An option...
+                    if (strcmp(argv[i], "--services-dir") == 0 || strcmp(argv[i], "-d") == 0) {
+                        if (++i < argc) {
+                            service_dir_opts.set_specified_service_dir(argv[i]);
+                        }
+                        else {
+                            cerr << "dinitcheck: '--services-dir' (-d) requires an argument" << endl;
+                            return 1;
+                        }
+                    }
+                }
+                // TODO handle other options, err if unrecognized
+            }
         }
     }
 
-    if (service_dir == nullptr) {
-        service_dir = "/etc/dinit.d";
-        add_all_service_dirs = true;
-    }
-
-    std::vector<dir_entry> service_dirs;
-
-    service_dirs.emplace_back(service_dir, service_dir_dynamic);
-    if (add_all_service_dirs) {
-        service_dirs.emplace_back("/usr/local/lib/dinit.d", false);
-        service_dirs.emplace_back("/lib/dinit.d", false);
-    }
+    service_dir_opts.build_paths(am_system_init);
 
     // Temporary, for testing:
     services_to_check.push_back("boot");
@@ -127,11 +99,11 @@ int main(int argc, char **argv)
     // - load the service, store dependencies as strings
     // - recurse
 
-    // additional: check chain-to, other lint
+    // TODO additional: check chain-to, other lint
 
     for (const auto &name : services_to_check) {
         try {
-            service_record *sr = load_service(service_set, name, service_dirs);
+            service_record *sr = load_service(service_set, name, service_dir_opts.get_paths());
             service_set[name] = sr;
             // add dependencies to services_to_check
             for (auto &dep : sr->dependencies) {
@@ -145,7 +117,7 @@ int main(int argc, char **argv)
         }
     }
 
-    // check for circular dependencies
+    // TODO check for circular dependencies
 
     return 0;
 }
@@ -201,8 +173,9 @@ static void process_dep_dir(const char *servicename,
     closedir(depdir);
 }
 
+// TODO: this is pretty much copy-paste from load_service.cc. Need to factor out common structure.
 service_record *load_service(service_set_t &services, const std::string &name,
-        const std::vector<dir_entry> &service_dirs)
+        const service_dir_pathlist &service_dirs)
 {
     using namespace std;
     using namespace dinit_load;
index dba724e1fa90f6764afec32965ff5749c9564a6b..e591dca9a7625a86439fcbea92ac09e431d35cd3 100644 (file)
@@ -55,7 +55,7 @@ public:
         service_dirs.emplace_back(service_dir_p, dyn_allocd);
     }
 
-    size_t size()
+    size_t size() const
     {
         return service_dirs.size();
     }
@@ -65,12 +65,12 @@ public:
         return service_dirs[index];
     }
 
-    std::vector<dir_entry>::iterator begin()
+    std::vector<dir_entry>::const_iterator begin() const
     {
         return service_dirs.begin();
     }
 
-    std::vector<dir_entry>::iterator end()
+    std::vector<dir_entry>::const_iterator end() const
     {
         return service_dirs.end();
     }
@@ -81,8 +81,6 @@ class service_dir_opt
     const char *service_dir = nullptr;;
     bool service_dir_dynamic = false;
 
-    bool am_system_init;
-
     static const char *user_home_path;
 
     service_dir_pathlist service_dir_paths;
@@ -97,8 +95,11 @@ public:
         service_dir = specified_dir;
     }
 
-    void build_paths();
+    // Build the set of service directory paths, as per configuration specified thus far. This might be a
+    // single specified path, or a set of default paths.
+    void build_paths(bool am_system_init);
 
+    // Get the service directory paths as a (mutable) collection. Call only after calling build_paths().
     service_dir_pathlist &get_paths()
     {
         return service_dir_paths;
index c3a3d4f30d011fc285864e527ffa4132f6376dea..3365b7dfe995484def6d2cc72352db7f14293a51 100644 (file)
@@ -25,7 +25,7 @@ const char * service_dir_opt::get_user_home()
     return user_home_path;
 }
 
-void service_dir_opt::build_paths()
+void service_dir_opt::build_paths(bool am_system_init)
 {
     /* service directory name */
     if (service_dir == nullptr && ! am_system_init) {