From 43355287e75bdd79e1719fbdd6c07df0530ab9b0 Mon Sep 17 00:00:00 2001 From: Davin McCall Date: Sat, 9 Nov 2019 17:03:15 +1000 Subject: [PATCH] Factor out service directory option processing Service directory options need to be processed/handled by dinit and by dinitcheck, so factor out the processing into a separate module. --- src/Makefile | 2 +- src/dinit.cc | 39 ++--------- src/dinitcheck.cc | 7 +- src/includes/load-service.h | 35 +--------- src/includes/options-processing.h | 108 ++++++++++++++++++++++++++++++ src/includes/service.h | 21 ++---- src/options-processing.cc | 58 ++++++++++++++++ 7 files changed, 184 insertions(+), 86 deletions(-) create mode 100644 src/includes/options-processing.h create mode 100644 src/options-processing.cc diff --git a/src/Makefile b/src/Makefile index b6dce35..4a5f07c 100644 --- a/src/Makefile +++ b/src/Makefile @@ -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 diff --git a/src/dinit.cc b/src/dinit.cc index 03afa7f..8fb405a 100644 --- a/src/dinit.cc +++ b/src/dinit.cc @@ -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 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"); diff --git a/src/dinitcheck.cc b/src/dinitcheck.cc index 9f7d761..04c9fd7 100644 --- a/src/dinitcheck.cc +++ b/src/dinitcheck.cc @@ -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; service_record *load_service(service_set_t &services, const std::string &name, - const std::vector &service_dirs); + const std::vector &service_dirs); // Add some missing standard library functionality... template bool contains(std::vector vec, const T& elem) @@ -109,7 +110,7 @@ int main(int argc, char **argv) add_all_service_dirs = true; } - std::vector service_dirs; + std::vector 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 &service_dirs) + const std::vector &service_dirs) { using namespace std; using namespace dinit_load; diff --git a/src/includes/load-service.h b/src/includes/load-service.h index fcddec0..cff1cfe 100644 --- a/src/includes/load-service.h +++ b/src/includes/load-service.h @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -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 index 0000000..dba724e --- /dev/null +++ b/src/includes/options-processing.h @@ -0,0 +1,108 @@ +#ifndef DINIT_OPTIONS_PROCESSING_H +#define DINIT_OPTIONS_PROCESSING_H 1 + +#include + +// 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 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::iterator begin() + { + return service_dirs.begin(); + } + + std::vector::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 diff --git a/src/includes/service.h b/src/includes/service.h index e46de70..35c58a4 100644 --- a/src/includes/service.h +++ b/src/includes/service.h @@ -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 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 index 0000000..c3a3d4f --- /dev/null +++ b/src/options-processing.cc @@ -0,0 +1,58 @@ +#include + +#include +#include + +#include +#include +#include + +#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); + } +} -- 2.25.1