Factor out service directory option processing
authorDavin McCall <davmac@davmac.org>
Sat, 9 Nov 2019 07:03:15 +0000 (17:03 +1000)
committerDavin McCall <davmac@davmac.org>
Sat, 9 Nov 2019 07:03:15 +0000 (17:03 +1000)
Service directory options need to be processed/handled by dinit and by
dinitcheck, so factor out the processing into a separate module.

src/Makefile
src/dinit.cc
src/dinitcheck.cc
src/includes/load-service.h
src/includes/options-processing.h [new file with mode: 0644]
src/includes/service.h
src/options-processing.cc [new file with mode: 0644]

index b6dce35b18c3ba044e8fb36d736cfa86263e06a4..4a5f07c928343b917e159e03d24ad2fb31c55cd0 100644 (file)
@@ -10,7 +10,7 @@ ifeq ($(BUILD_SHUTDOWN),yes)
 endif
 
 dinit_objects = dinit.o load-service.o service.o proc-service.o baseproc-service.o control.o dinit-log.o \
-               dinit-main.o run-child-proc.o
+               dinit-main.o run-child-proc.o options-processing.o
 
 objects = $(dinit_objects) dinitctl.o dinitcheck.o shutdown.o
 
index 03afa7f7e7954723a9c2b277fe50ef5ce6cd48f4..8fb405a5c9430f98bd68f4b55d047e1cc75e92a0 100644 (file)
@@ -31,6 +31,7 @@
 #include "dinit-socket.h"
 #include "static-string.h"
 #include "dinit-utmp.h"
+#include "options-processing.h"
 
 #include "mconfig.h"
 
@@ -197,13 +198,13 @@ int dinit_main(int argc, char **argv)
     
     am_pid_one = (getpid() == 1);
     am_system_init = (getuid() == 0);
-    const char * service_dir = nullptr;
-    bool service_dir_dynamic = false; // service_dir dynamically allocated?
     const char * env_file = nullptr;
     bool control_socket_path_set = false;
     bool env_file_set = false;
     bool log_specified = false;
 
+    service_dir_opt service_dir_opts;
+
     // list of services to start
     list<const char *> services_to_start;
     
@@ -227,7 +228,7 @@ int dinit_main(int argc, char **argv)
                 }
                 else if (strcmp(argv[i], "--services-dir") == 0 || strcmp(argv[i], "-d") == 0) {
                     if (++i < argc) {
-                        service_dir = argv[i];
+                        service_dir_opts.set_specified_service_dir(argv[i]);
                     }
                     else {
                         cerr << "dinit: '--services-dir' (-d) requires an argument" << endl;
@@ -351,24 +352,6 @@ int dinit_main(int argc, char **argv)
         }
     }
     
-    /* service directory name */
-    if (service_dir == nullptr && ! am_system_init) {
-        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;
-        }
-    }
-    
     if (services_to_start.empty()) {
         services_to_start.push_back("boot");
     }
@@ -419,19 +402,11 @@ int dinit_main(int argc, char **argv)
     
     log_flush_timer.add_timer(event_loop, dasynq::clock_type::MONOTONIC);
 
-    bool add_all_service_dirs = false;
-    if (service_dir == nullptr) {
-        service_dir = "/etc/dinit.d";
-        add_all_service_dirs = true;
-    }
+    service_dir_opts.build_paths();
 
     /* start requested services */
-    services = new dirload_service_set(service_dir, service_dir_dynamic);
-    if (add_all_service_dirs) {
-        services->add_service_dir("/usr/local/lib/dinit.d", false);
-        services->add_service_dir("/lib/dinit.d", false);
-    }
-    
+    services = new dirload_service_set(std::move(service_dir_opts.get_paths()));
+
     init_log(services, log_is_syslog);
     if (am_system_init) {
         log(loglevel_t::INFO, false, "starting system");
index 9f7d761d63b3bb57d060f0bd19faa4ae5dc55dfb..04c9fd70b9e745e491843a4bdc6211bb03e5368d 100644 (file)
@@ -17,6 +17,7 @@
 #include "dinit-util.h"
 #include "service-constants.h"
 #include "load-service.h"
+#include "options-processing.h"
 
 // dinitcheck:  utility to check Dinit configuration for correctness/lint
 
@@ -66,7 +67,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<dinit_load::dir_entry> &service_dirs);
+        const std::vector<dir_entry> &service_dirs);
 
 // Add some missing standard library functionality...
 template <typename T> bool contains(std::vector<T> vec, const T& elem)
@@ -109,7 +110,7 @@ int main(int argc, char **argv)
         add_all_service_dirs = true;
     }
 
-    std::vector<dinit_load::dir_entry> service_dirs;
+    std::vector<dir_entry> service_dirs;
 
     service_dirs.emplace_back(service_dir, service_dir_dynamic);
     if (add_all_service_dirs) {
@@ -201,7 +202,7 @@ static void process_dep_dir(const char *servicename,
 }
 
 service_record *load_service(service_set_t &services, const std::string &name,
-        const std::vector<dinit_load::dir_entry> &service_dirs)
+        const std::vector<dir_entry> &service_dirs)
 {
     using namespace std;
     using namespace dinit_load;
index fcddec0d9ce815d66393942033058c66b6e321b8..cff1cfe32c1cdffccf97edb40938bf0c8ab5a6c2 100644 (file)
@@ -2,6 +2,7 @@
 #include <list>
 #include <limits>
 #include <csignal>
+#include <cstring>
 
 #include <sys/types.h>
 #include <sys/time.h>
@@ -89,40 +90,6 @@ namespace dinit_load {
 using string = std::string;
 using string_iterator = std::string::iterator;
 
-// A service directory entry, tracking the directory as a nul-terminated string, which may either
-// be static or dynamically allocated (via new char[...]).
-class dir_entry
-{
-    const char *dir;
-    bool dir_dyn_allocd;  // dynamically allocated?
-
-    public:
-    dir_entry(const char *dir_p, bool dir_dyn_allocd_p) :
-        dir(dir_p), dir_dyn_allocd(dir_dyn_allocd_p)
-    { }
-
-    dir_entry(dir_entry &&other)
-    {
-        dir = other.dir;
-        dir_dyn_allocd = other.dir_dyn_allocd;
-        other.dir_dyn_allocd = false;
-    }
-
-    dir_entry(const dir_entry &other) = delete;
-
-    ~dir_entry()
-    {
-        if (dir_dyn_allocd) {
-            delete[] dir;
-        }
-    }
-
-    const char *get_dir() const
-    {
-        return dir;
-    }
-};
-
 // exception thrown when encountering a syntax issue when reading a setting value
 class setting_exception
 {
diff --git a/src/includes/options-processing.h b/src/includes/options-processing.h
new file mode 100644 (file)
index 0000000..dba724e
--- /dev/null
@@ -0,0 +1,108 @@
+#ifndef DINIT_OPTIONS_PROCESSING_H
+#define DINIT_OPTIONS_PROCESSING_H 1
+
+#include <vector>
+
+// A service directory entry, tracking the directory as a nul-terminated string, which may either
+// be static or dynamically allocated (via new char[...]).
+class dir_entry
+{
+    const char *dir;
+    bool dir_dyn_allocd;  // dynamically allocated?
+
+    public:
+    dir_entry(const char *dir_p, bool dir_dyn_allocd_p) :
+        dir(dir_p), dir_dyn_allocd(dir_dyn_allocd_p)
+    { }
+
+    dir_entry(dir_entry &&other)
+    {
+        dir = other.dir;
+        dir_dyn_allocd = other.dir_dyn_allocd;
+        other.dir_dyn_allocd = false;
+    }
+
+    dir_entry(const dir_entry &other) = delete;
+
+    ~dir_entry()
+    {
+        if (dir_dyn_allocd) {
+            delete[] dir;
+        }
+    }
+
+    const char *get_dir() const
+    {
+        return dir;
+    }
+};
+
+// TODO this is close to just being a vector; make it so?
+class service_dir_pathlist
+{
+    std::vector<dir_entry> service_dirs; // directories containing service descriptions
+
+public:
+    service_dir_pathlist() { }
+
+    service_dir_pathlist(const char *service_dir_p, bool dyn_allocd = false)
+    {
+        service_dirs.emplace_back(service_dir_p, dyn_allocd);
+    }
+
+    void add_dir(const char *service_dir_p, bool dyn_allocd = false)
+    {
+        service_dirs.emplace_back(service_dir_p, dyn_allocd);
+    }
+
+    size_t size()
+    {
+        return service_dirs.size();
+    }
+
+    dir_entry &operator[](size_t index)
+    {
+        return service_dirs[index];
+    }
+
+    std::vector<dir_entry>::iterator begin()
+    {
+        return service_dirs.begin();
+    }
+
+    std::vector<dir_entry>::iterator end()
+    {
+        return service_dirs.end();
+    }
+};
+
+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;
+
+public:
+    // 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();
+
+    void set_specified_service_dir(const char *specified_dir)
+    {
+        service_dir = specified_dir;
+    }
+
+    void build_paths();
+
+    service_dir_pathlist &get_paths()
+    {
+        return service_dir_paths;
+    }
+};
+
+#endif
index e46de700762f73e54ec95851dd89b6e3b51297e8..35c58a4703933aac058917ff17b87d254e47aa2c 100644 (file)
@@ -17,6 +17,7 @@
 #include "load-service.h"
 #include "dinit-ll.h"
 #include "dinit-log.h"
+#include "options-processing.h" // TODO maybe remove, service_dir_pathlist can be moved?
 
 /*
  * This header defines service_record, a data record maintaining information about a service,
@@ -907,9 +908,7 @@ class service_set
 // A service set which loads services from one of several service directories.
 class dirload_service_set : public service_set
 {
-    using dir_entry = dinit_load::dir_entry;
-
-    std::vector<dir_entry> service_dirs; // directories containing service descriptions
+    service_dir_pathlist service_dirs;
 
     public:
     dirload_service_set() : service_set()
@@ -917,22 +916,12 @@ class dirload_service_set : public service_set
         // nothing to do.
     }
 
-    dirload_service_set(const dirload_service_set &) = delete;
-
-    // Construct a dirload_service_set which loads services from the specified directory. The
-    // directory specified can be dynamically allocated via "new char[...]" (dyn_allocd == true)
-    // or statically allocated.
-    dirload_service_set(const char *service_dir_p, bool dyn_allocd = false) : service_set()
+    dirload_service_set(service_dir_pathlist &&pathlist) : service_set(), service_dirs(std::move(pathlist))
     {
-        service_dirs.emplace_back(service_dir_p, dyn_allocd);
+        // nothing to do.
     }
 
-    // Append a directory to the list of service directories, so that it is searched last for
-    // service description files.
-    void add_service_dir(const char *service_dir_p, bool dyn_allocd = true)
-    {
-        service_dirs.emplace_back(service_dir_p, dyn_allocd);
-    }
+    dirload_service_set(const dirload_service_set &) = delete;
 
     int get_service_dir_count()
     {
diff --git a/src/options-processing.cc b/src/options-processing.cc
new file mode 100644 (file)
index 0000000..c3a3d4f
--- /dev/null
@@ -0,0 +1,58 @@
+#include <vector>
+
+#include <cstring>
+#include <cstdlib>
+
+#include <sys/types.h>
+#include <pwd.h>
+#include <unistd.h>
+
+#include "options-processing.h"
+
+const char *service_dir_opt::user_home_path = nullptr;
+
+const char * service_dir_opt::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;
+}
+
+void service_dir_opt::build_paths()
+{
+    /* service directory name */
+    if (service_dir == nullptr && ! am_system_init) {
+        const char * user_home = get_user_home();
+        if (user_home != nullptr) {
+            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;
+        }
+    }
+
+    bool add_all_service_dirs = false;
+    if (service_dir == nullptr) {
+        service_dir = "/etc/dinit.d";
+        add_all_service_dirs = true;
+    }
+
+    service_dir_paths.add_dir(service_dir, service_dir_dynamic);
+    if (add_all_service_dirs) {
+        service_dir_paths.add_dir("/usr/local/lib/dinit.d", false);
+        service_dir_paths.add_dir("/lib/dinit.d", false);
+    }
+}