Factor out service parameter processing
authorDavin McCall <davmac@davmac.org>
Thu, 21 Nov 2019 10:41:34 +0000 (10:41 +0000)
committerDavin McCall <davmac@davmac.org>
Thu, 21 Nov 2019 10:41:34 +0000 (10:41 +0000)
Factor service parameter processing into a template method, to enable
sharing (later) between load_service in dinit and dinitcheck.

src/includes/dinit-utmp.h
src/includes/load-service.h
src/includes/service.h
src/load-service.cc
src/mconfig-gen.cc

index f02eca242f90e63657b0aea2923b17892ddaf186..eb32e4fe60506ed7b1c6c5f35a2519bc04eb9156 100644 (file)
@@ -3,6 +3,8 @@
 #ifndef DINIT_UTMP_H_INCLUDED
 #define DINIT_UTMP_H_INCLUDED
 
+#include "mconfig.h"  // pull in any explicit configuration
+
 // Configuration:
 // USE_UTMPX - whether to update the utmp[x] database. If 0, no-op stubs are defined.
 // USE_UPDWTMPX - whether to use the updwtmpx function to log boot (contingent on USE_UTMPX).
index d19bac16ebdcbf4f3afa1dabf28cd9cdb319a98b..a00a0813188fd13d5239f6b5855526c876eee2c6 100644 (file)
@@ -3,6 +3,7 @@
 #include <limits>
 #include <csignal>
 #include <cstring>
+#include <utility>
 
 #include <sys/types.h>
 #include <sys/time.h>
@@ -10,6 +11,9 @@
 #include <grp.h>
 #include <pwd.h>
 
+#include "dinit-utmp.h"
+#include "dinit-util.h"
+
 struct service_flags_t
 {
     // on-start flags:
@@ -555,6 +559,343 @@ void process_service_file(string name, std::istream &service_file, T func)
     }
 }
 
+// A wrapper type for service parameters. It is parameterised by dependency type.
+template <class dep_type>
+class service_settings_wrapper
+{
+    template <typename A, typename B> using pair = std::pair<A,B>;
+    template <typename A> using list = std::list<A>;
+
+    public:
+
+    string command;
+    list<pair<unsigned,unsigned>> command_offsets;
+    string stop_command;
+    list<pair<unsigned,unsigned>> stop_command_offsets;
+    string working_dir;
+    string pid_file;
+    string env_file;
+
+    bool do_sub_vars = false;
+
+    service_type_t service_type = service_type_t::PROCESS;
+    std::list<dep_type> depends;
+    string logfile;
+    service_flags_t onstart_flags;
+    int term_signal = -1;  // additional termination signal
+    bool auto_restart = false;
+    bool smooth_recovery = false;
+    string socket_path;
+    int socket_perms = 0666;
+    // Note: Posix allows that uid_t and gid_t may be unsigned types, but eg chown uses -1 as an
+    // invalid value, so it's safe to assume that we can do the same:
+    uid_t socket_uid = -1;
+    gid_t socket_gid = -1;
+    // Restart limit interval / count; default is 10 seconds, 3 restarts:
+    timespec restart_interval = { .tv_sec = 10, .tv_nsec = 0 };
+    int max_restarts = 3;
+    timespec restart_delay = { .tv_sec = 0, .tv_nsec = 200000000 };
+    timespec stop_timeout = { .tv_sec = 10, .tv_nsec = 0 };
+    timespec start_timeout = { .tv_sec = 60, .tv_nsec = 0 };
+    std::vector<service_rlimits> rlimits;
+
+    int readiness_fd = -1;      // readiness fd in service process
+    std::string readiness_var;  // environment var to hold readiness fd
+
+    uid_t run_as_uid = -1;
+    gid_t run_as_gid = -1;
+
+    string chain_to_name;
+
+    #if USE_UTMPX
+    char inittab_id[sizeof(utmpx().ut_id)] = {0};
+    char inittab_line[sizeof(utmpx().ut_line)] = {0};
+    #endif
+};
+
+// Process a service description line. In general, parse the setting value and record the parsed value
+// in a service settings wrapper object. Errors will be reported via service_description_exc exception.
+//
+// type parameters:
+//     settings_wrapper : wrapper for service settings
+//     load_service_t   : type of load service function/lambda (see below)
+//     process_dep_dir_t : type of process_dep_dir funciton/lambda (see below)
+//
+// parameters:
+//     settings     : wrapper object for service settings
+//     name         : name of the service being processed
+//     line         : the current line of the service description file
+//     setting      : the name of the setting (from the beginning of line)
+//     i            : iterator at beginning of setting value (including whitespace)
+//     end          : iterator at end of line
+//     load_service : function to load a service
+//                      arguments:  const char *service_name
+//                      return: a value that can be used (with a dependency type) to construct a dependency
+//                              in the 'depends' vector within the 'settings' object
+//     process_dep_dir : function to process a dependency directory
+//                      arguments: decltype(settings.depends) &dependencies
+//                                 const string &waitsford - directory as specified in parameter
+//                                 dependency_type dep_type - type of dependency to add
+template <typename settings_wrapper,
+    typename load_service_t,
+    typename process_dep_dir_t>
+void process_service_line(settings_wrapper &settings, const char *name, string &line, string &setting,
+        string::iterator &i, string::iterator &end, load_service_t load_service,
+        process_dep_dir_t process_dep_dir)
+{
+    if (setting == "command") {
+        settings.command = read_setting_value(i, end, &settings.command_offsets);
+    }
+    else if (setting == "working-dir") {
+        settings.working_dir = read_setting_value(i, end, nullptr);
+    }
+    else if (setting == "env-file") {
+        settings.env_file = read_setting_value(i, end, nullptr);
+    }
+    else if (setting == "socket-listen") {
+        settings.socket_path = read_setting_value(i, end, nullptr);
+    }
+    else if (setting == "socket-permissions") {
+        string sock_perm_str = read_setting_value(i, end, nullptr);
+        std::size_t ind = 0;
+        try {
+            settings.socket_perms = std::stoi(sock_perm_str, &ind, 8);
+            if (ind != sock_perm_str.length()) {
+                throw std::logic_error("");
+            }
+        }
+        catch (std::logic_error &exc) {
+            throw service_description_exc(name, "socket-permissions: Badly-formed or "
+                    "out-of-range numeric value");
+        }
+    }
+    else if (setting == "socket-uid") {
+        string sock_uid_s = read_setting_value(i, end, nullptr);
+        settings.socket_uid = parse_uid_param(sock_uid_s, name, "socket-uid", &settings.socket_gid);
+    }
+    else if (setting == "socket-gid") {
+        string sock_gid_s = read_setting_value(i, end, nullptr);
+        settings.socket_gid = parse_gid_param(sock_gid_s, "socket-gid", name);
+    }
+    else if (setting == "stop-command") {
+        settings.stop_command = read_setting_value(i, end, &settings.stop_command_offsets);
+    }
+    else if (setting == "pid-file") {
+        settings.pid_file = read_setting_value(i, end);
+    }
+    else if (setting == "depends-on") {
+        string dependency_name = read_setting_value(i, end);
+        settings.depends.emplace_back(load_service(dependency_name.c_str()), dependency_type::REGULAR);
+    }
+    else if (setting == "depends-ms") {
+        string dependency_name = read_setting_value(i, end);
+        settings.depends.emplace_back(load_service(dependency_name.c_str()), dependency_type::MILESTONE);
+    }
+    else if (setting == "waits-for") {
+        string dependency_name = read_setting_value(i, end);
+        settings.depends.emplace_back(load_service(dependency_name.c_str()), dependency_type::WAITS_FOR);
+    }
+    else if (setting == "waits-for.d") {
+        string waitsford = read_setting_value(i, end);
+        process_dep_dir(settings.depends, waitsford, dependency_type::WAITS_FOR);
+    }
+    else if (setting == "logfile") {
+        settings.logfile = read_setting_value(i, end);
+    }
+    else if (setting == "restart") {
+        string restart = read_setting_value(i, end);
+        settings.auto_restart = (restart == "yes" || restart == "true");
+    }
+    else if (setting == "smooth-recovery") {
+        string recovery = read_setting_value(i, end);
+        settings.smooth_recovery = (recovery == "yes" || recovery == "true");
+    }
+    else if (setting == "type") {
+        string type_str = read_setting_value(i, end);
+        if (type_str == "scripted") {
+            settings.service_type = service_type_t::SCRIPTED;
+        }
+        else if (type_str == "process") {
+            settings.service_type = service_type_t::PROCESS;
+        }
+        else if (type_str == "bgprocess") {
+            settings.service_type = service_type_t::BGPROCESS;
+        }
+        else if (type_str == "internal") {
+            settings.service_type = service_type_t::INTERNAL;
+        }
+        else {
+            throw service_description_exc(name, "Service type must be one of: \"scripted\","
+                " \"process\", \"bgprocess\" or \"internal\"");
+        }
+    }
+    else if (setting == "options") {
+        std::list<std::pair<unsigned,unsigned>> indices;
+        string onstart_cmds = read_setting_value(i, end, &indices);
+        for (auto indexpair : indices) {
+            string option_txt = onstart_cmds.substr(indexpair.first,
+                    indexpair.second - indexpair.first);
+            if (option_txt == "starts-rwfs") {
+                settings.onstart_flags.rw_ready = true;
+            }
+            else if (option_txt == "starts-log") {
+                settings.onstart_flags.log_ready = true;
+            }
+            else if (option_txt == "no-sigterm") {
+                settings.onstart_flags.no_sigterm = true;
+            }
+            else if (option_txt == "runs-on-console") {
+                settings.onstart_flags.runs_on_console = true;
+                // A service that runs on the console necessarily starts on console:
+                settings.onstart_flags.starts_on_console = true;
+                settings.onstart_flags.shares_console = false;
+            }
+            else if (option_txt == "starts-on-console") {
+                settings.onstart_flags.starts_on_console = true;
+                settings.onstart_flags.shares_console = false;
+            }
+            else if (option_txt == "shares-console") {
+                settings.onstart_flags.shares_console = true;
+                settings.onstart_flags.runs_on_console = false;
+                settings.onstart_flags.starts_on_console = false;
+            }
+            else if (option_txt == "pass-cs-fd") {
+                settings.onstart_flags.pass_cs_fd = true;
+            }
+            else if (option_txt == "start-interruptible") {
+                settings.onstart_flags.start_interruptible = true;
+            }
+            else if (option_txt == "skippable") {
+                settings.onstart_flags.skippable = true;
+            }
+            else if (option_txt == "signal-process-only") {
+                settings.onstart_flags.signal_process_only = true;
+            }
+            else {
+                throw service_description_exc(name, "Unknown option: " + option_txt);
+            }
+        }
+    }
+    else if (setting == "load-options") {
+        std::list<std::pair<unsigned,unsigned>> indices;
+        string load_opts = read_setting_value(i, end, &indices);
+        for (auto indexpair : indices) {
+            string option_txt = load_opts.substr(indexpair.first,
+                    indexpair.second - indexpair.first);
+            if (option_txt == "sub-vars") {
+                // substitute environment variables in command line
+                settings.do_sub_vars = true;
+            }
+            else if (option_txt == "no-sub-vars") {
+                settings.do_sub_vars = false;
+            }
+            else {
+                throw service_description_exc(name, "Unknown load option: " + option_txt);
+            }
+        }
+    }
+    else if (setting == "term-signal" || setting == "termsignal") {
+        // Note: "termsignal" supported for legacy reasons.
+        string signame = read_setting_value(i, end, nullptr);
+        int signo = signal_name_to_number(signame);
+        if (signo == -1) {
+            throw service_description_exc(name, "Unknown/unsupported termination signal: "
+                    + signame);
+        }
+        else {
+            settings.term_signal = signo;
+        }
+    }
+    else if (setting == "restart-limit-interval") {
+        string interval_str = read_setting_value(i, end, nullptr);
+        parse_timespec(interval_str, name, "restart-limit-interval", settings.restart_interval);
+    }
+    else if (setting == "restart-delay") {
+        string rsdelay_str = read_setting_value(i, end, nullptr);
+        parse_timespec(rsdelay_str, name, "restart-delay", settings.restart_delay);
+    }
+    else if (setting == "restart-limit-count") {
+        string limit_str = read_setting_value(i, end, nullptr);
+        settings.max_restarts = parse_unum_param(limit_str, name, std::numeric_limits<int>::max());
+    }
+    else if (setting == "stop-timeout") {
+        string stoptimeout_str = read_setting_value(i, end, nullptr);
+        parse_timespec(stoptimeout_str, name, "stop-timeout", settings.stop_timeout);
+    }
+    else if (setting == "start-timeout") {
+        string starttimeout_str = read_setting_value(i, end, nullptr);
+        parse_timespec(starttimeout_str, name, "start-timeout", settings.start_timeout);
+    }
+    else if (setting == "run-as") {
+        string run_as_str = read_setting_value(i, end, nullptr);
+        settings.run_as_uid = parse_uid_param(run_as_str, name, "run-as", &settings.run_as_gid);
+    }
+    else if (setting == "chain-to") {
+        settings.chain_to_name = read_setting_value(i, end, nullptr);
+    }
+    else if (setting == "ready-notification") {
+        string notify_setting = read_setting_value(i, end, nullptr);
+        if (starts_with(notify_setting, "pipefd:")) {
+            settings.readiness_fd = parse_unum_param(notify_setting.substr(7 /* len 'pipefd:' */),
+                    name, std::numeric_limits<int>::max());
+        }
+        else if (starts_with(notify_setting, "pipevar:")) {
+            settings.readiness_var = notify_setting.substr(8 /* len 'pipevar:' */);
+            if (settings.readiness_var.empty()) {
+                throw service_description_exc(name, "Invalid pipevar variable name "
+                        "in ready-notification");
+            }
+        }
+        else {
+            throw service_description_exc(name, "Unknown ready-notification setting: "
+                    + notify_setting);
+        }
+    }
+    else if (setting == "inittab-id") {
+        string inittab_setting = read_setting_value(i, end, nullptr);
+        #if USE_UTMPX
+        if (inittab_setting.length() > sizeof(settings.inittab_id)) {
+            throw service_description_exc(name, "inittab-id setting is too long");
+        }
+        strncpy(settings.inittab_id, inittab_setting.c_str(), sizeof(settings.inittab_id));
+        #endif
+    }
+    else if (setting == "inittab-line") {
+        string inittab_setting = read_setting_value(i, end, nullptr);
+        #if USE_UTMPX
+        if (inittab_setting.length() > sizeof(settings.inittab_line)) {
+            throw service_description_exc(name, "inittab-line setting is too long");
+        }
+        strncpy(settings.inittab_line, inittab_setting.c_str(), sizeof(settings.inittab_line));
+        #endif
+    }
+    else if (setting == "rlimit-nofile") {
+        string nofile_setting = read_setting_value(i, end, nullptr);
+        service_rlimits &nofile_limits = find_rlimits(settings.rlimits, RLIMIT_NOFILE);
+        parse_rlimit(line, name, "rlimit-nofile", nofile_limits);
+    }
+    else if (setting == "rlimit-core") {
+        string nofile_setting = read_setting_value(i, end, nullptr);
+        service_rlimits &nofile_limits = find_rlimits(settings.rlimits, RLIMIT_CORE);
+        parse_rlimit(line, name, "rlimit-core", nofile_limits);
+    }
+    else if (setting == "rlimit-data") {
+        string nofile_setting = read_setting_value(i, end, nullptr);
+        service_rlimits &nofile_limits = find_rlimits(settings.rlimits, RLIMIT_DATA);
+        parse_rlimit(line, name, "rlimit-data", nofile_limits);
+    }
+    else if (setting == "rlimit-addrspace") {
+        #if defined(RLIMIT_AS)
+            string nofile_setting = read_setting_value(i, end, nullptr);
+            service_rlimits &nofile_limits = find_rlimits(settings.rlimits, RLIMIT_AS);
+            parse_rlimit(line, name, "rlimit-addrspace", nofile_limits);
+        #endif
+    }
+    else {
+        throw service_description_exc(name, "Unknown setting: " + setting);
+    }
+}
+
 } // namespace dinit_load
 
 using dinit_load::process_service_file;
index 35c58a4703933aac058917ff17b87d254e47aa2c..ef1b6a67651fbc0eb27534e7920f4abbd7e4eac3 100644 (file)
@@ -164,7 +164,7 @@ class prelim_dep
 
     prelim_dep(service_record *to_p, dependency_type dep_type_p) : to(to_p), dep_type(dep_type_p)
     {
-        //
+        // (constructor)
     }
 };
 
index 791f05b23c0624240da87102b6a4101bce24d4e7..35de6519331f88435bfab1cb669abd7f6b4889a1 100644 (file)
@@ -160,49 +160,7 @@ service_record * dirload_service_set::load_service(const char * name)
         throw service_not_found(string(name));
     }
 
-    string command;
-    list<pair<unsigned,unsigned>> command_offsets;
-    string stop_command;
-    list<pair<unsigned,unsigned>> stop_command_offsets;
-    string working_dir;
-    string pid_file;
-    string env_file;
-
-    bool do_sub_vars = false;
-
-    service_type_t service_type = service_type_t::PROCESS;
-    std::list<prelim_dep> depends;
-    string logfile;
-    service_flags_t onstart_flags;
-    int term_signal = -1;  // additional termination signal
-    bool auto_restart = false;
-    bool smooth_recovery = false;
-    string socket_path;
-    int socket_perms = 0666;
-    // Note: Posix allows that uid_t and gid_t may be unsigned types, but eg chown uses -1 as an
-    // invalid value, so it's safe to assume that we can do the same:
-    uid_t socket_uid = -1;
-    gid_t socket_gid = -1;
-    // Restart limit interval / count; default is 10 seconds, 3 restarts:
-    timespec restart_interval = { .tv_sec = 10, .tv_nsec = 0 };
-    int max_restarts = 3;
-    timespec restart_delay = { .tv_sec = 0, .tv_nsec = 200000000 };
-    timespec stop_timeout = { .tv_sec = 10, .tv_nsec = 0 };
-    timespec start_timeout = { .tv_sec = 60, .tv_nsec = 0 };
-    std::vector<service_rlimits> rlimits;
-    
-    int readiness_fd = -1;      // readiness fd in service process
-    std::string readiness_var;  // environment var to hold readiness fd
-
-    uid_t run_as_uid = -1;
-    gid_t run_as_gid = -1;
-
-    string chain_to_name;
-
-    #if USE_UTMPX
-    char inittab_id[sizeof(utmpx().ut_id)] = {0};
-    char inittab_line[sizeof(utmpx().ut_line)] = {0};
-    #endif
+    service_settings_wrapper<prelim_dep> settings;
 
     string line;
     // getline can set failbit if it reaches end-of-file, we don't want an exception in that case. There's
@@ -217,265 +175,26 @@ service_record * dirload_service_set::load_service(const char * name)
     try {
         process_service_file(name, service_file,
                 [&](string &line, string &setting, string_iterator &i, string_iterator &end) -> void {
-            if (setting == "command") {
-                command = read_setting_value(i, end, &command_offsets);
-            }
-            else if (setting == "working-dir") {
-                working_dir = read_setting_value(i, end, nullptr);
-            }
-            else if (setting == "env-file") {
-                env_file = read_setting_value(i, end, nullptr);
-            }
-            else if (setting == "socket-listen") {
-                socket_path = read_setting_value(i, end, nullptr);
-            }
-            else if (setting == "socket-permissions") {
-                string sock_perm_str = read_setting_value(i, end, nullptr);
-                std::size_t ind = 0;
-                try {
-                    socket_perms = std::stoi(sock_perm_str, &ind, 8);
-                    if (ind != sock_perm_str.length()) {
-                        throw std::logic_error("");
-                    }
-                }
-                catch (std::logic_error &exc) {
-                    throw service_description_exc(name, "socket-permissions: Badly-formed or "
-                            "out-of-range numeric value");
-                }
-            }
-            else if (setting == "socket-uid") {
-                string sock_uid_s = read_setting_value(i, end, nullptr);
-                socket_uid = parse_uid_param(sock_uid_s, name, "socket-uid", &socket_gid);
-            }
-            else if (setting == "socket-gid") {
-                string sock_gid_s = read_setting_value(i, end, nullptr);
-                socket_gid = parse_gid_param(sock_gid_s, "socket-gid", name);
-            }
-            else if (setting == "stop-command") {
-                stop_command = read_setting_value(i, end, &stop_command_offsets);
-            }
-            else if (setting == "pid-file") {
-                pid_file = read_setting_value(i, end);
-            }
-            else if (setting == "depends-on") {
-                string dependency_name = read_setting_value(i, end);
-                depends.emplace_back(load_service(dependency_name.c_str()), dependency_type::REGULAR);
-            }
-            else if (setting == "depends-ms") {
-                string dependency_name = read_setting_value(i, end);
-                depends.emplace_back(load_service(dependency_name.c_str()), dependency_type::MILESTONE);
-            }
-            else if (setting == "waits-for") {
-                string dependency_name = read_setting_value(i, end);
-                depends.emplace_back(load_service(dependency_name.c_str()), dependency_type::WAITS_FOR);
-            }
-            else if (setting == "waits-for.d") {
-                string waitsford = read_setting_value(i, end);
-                process_dep_dir(*this, name, service_filename, depends, waitsford,
-                        dependency_type::WAITS_FOR);
-            }
-            else if (setting == "logfile") {
-                logfile = read_setting_value(i, end);
-            }
-            else if (setting == "restart") {
-                string restart = read_setting_value(i, end);
-                auto_restart = (restart == "yes" || restart == "true");
-            }
-            else if (setting == "smooth-recovery") {
-                string recovery = read_setting_value(i, end);
-                smooth_recovery = (recovery == "yes" || recovery == "true");
-            }
-            else if (setting == "type") {
-                string type_str = read_setting_value(i, end);
-                if (type_str == "scripted") {
-                    service_type = service_type_t::SCRIPTED;
-                }
-                else if (type_str == "process") {
-                    service_type = service_type_t::PROCESS;
-                }
-                else if (type_str == "bgprocess") {
-                    service_type = service_type_t::BGPROCESS;
-                }
-                else if (type_str == "internal") {
-                    service_type = service_type_t::INTERNAL;
-                }
-                else {
-                    throw service_description_exc(name, "Service type must be one of: \"scripted\","
-                        " \"process\", \"bgprocess\" or \"internal\"");
-                }
-            }
-            else if (setting == "options") {
-                std::list<std::pair<unsigned,unsigned>> indices;
-                string onstart_cmds = read_setting_value(i, end, &indices);
-                for (auto indexpair : indices) {
-                    string option_txt = onstart_cmds.substr(indexpair.first,
-                            indexpair.second - indexpair.first);
-                    if (option_txt == "starts-rwfs") {
-                        onstart_flags.rw_ready = true;
-                    }
-                    else if (option_txt == "starts-log") {
-                        onstart_flags.log_ready = true;
-                    }
-                    else if (option_txt == "no-sigterm") {
-                        onstart_flags.no_sigterm = true;
-                    }
-                    else if (option_txt == "runs-on-console") {
-                        onstart_flags.runs_on_console = true;
-                        // A service that runs on the console necessarily starts on console:
-                        onstart_flags.starts_on_console = true;
-                        onstart_flags.shares_console = false;
-                    }
-                    else if (option_txt == "starts-on-console") {
-                        onstart_flags.starts_on_console = true;
-                        onstart_flags.shares_console = false;
-                    }
-                    else if (option_txt == "shares-console") {
-                        onstart_flags.shares_console = true;
-                        onstart_flags.runs_on_console = false;
-                        onstart_flags.starts_on_console = false;
-                    }
-                    else if (option_txt == "pass-cs-fd") {
-                        onstart_flags.pass_cs_fd = true;
-                    }
-                    else if (option_txt == "start-interruptible") {
-                        onstart_flags.start_interruptible = true;
-                    }
-                    else if (option_txt == "skippable") {
-                        onstart_flags.skippable = true;
-                    }
-                    else if (option_txt == "signal-process-only") {
-                        onstart_flags.signal_process_only = true;
-                    }
-                    else {
-                        throw service_description_exc(name, "Unknown option: " + option_txt);
-                    }
-                }
-            }
-            else if (setting == "load-options") {
-                std::list<std::pair<unsigned,unsigned>> indices;
-                string load_opts = read_setting_value(i, end, &indices);
-                for (auto indexpair : indices) {
-                    string option_txt = load_opts.substr(indexpair.first,
-                            indexpair.second - indexpair.first);
-                    if (option_txt == "sub-vars") {
-                        // substitute environment variables in command line
-                        do_sub_vars = true;
-                    }
-                    else if (option_txt == "no-sub-vars") {
-                        do_sub_vars = false;
-                    }
-                    else {
-                        throw service_description_exc(name, "Unknown load option: " + option_txt);
-                    }
-                }
-            }
-            else if (setting == "term-signal" || setting == "termsignal") {
-                // Note: "termsignal" supported for legacy reasons.
-                string signame = read_setting_value(i, end, nullptr);
-                int signo = signal_name_to_number(signame);
-                if (signo == -1) {
-                    throw service_description_exc(name, "Unknown/unsupported termination signal: "
-                            + signame);
-                }
-                else {
-                    term_signal = signo;
-                }
-            }
-            else if (setting == "restart-limit-interval") {
-                string interval_str = read_setting_value(i, end, nullptr);
-                parse_timespec(interval_str, name, "restart-limit-interval", restart_interval);
-            }
-            else if (setting == "restart-delay") {
-                string rsdelay_str = read_setting_value(i, end, nullptr);
-                parse_timespec(rsdelay_str, name, "restart-delay", restart_delay);
-            }
-            else if (setting == "restart-limit-count") {
-                string limit_str = read_setting_value(i, end, nullptr);
-                max_restarts = parse_unum_param(limit_str, name, std::numeric_limits<int>::max());
-            }
-            else if (setting == "stop-timeout") {
-                string stoptimeout_str = read_setting_value(i, end, nullptr);
-                parse_timespec(stoptimeout_str, name, "stop-timeout", stop_timeout);
-            }
-            else if (setting == "start-timeout") {
-                string starttimeout_str = read_setting_value(i, end, nullptr);
-                parse_timespec(starttimeout_str, name, "start-timeout", start_timeout);
-            }
-            else if (setting == "run-as") {
-                string run_as_str = read_setting_value(i, end, nullptr);
-                run_as_uid = parse_uid_param(run_as_str, name, "run-as", &run_as_gid);
-            }
-            else if (setting == "chain-to") {
-                chain_to_name = read_setting_value(i, end, nullptr);
-            }
-            else if (setting == "ready-notification") {
-                string notify_setting = read_setting_value(i, end, nullptr);
-                if (starts_with(notify_setting, "pipefd:")) {
-                    readiness_fd = parse_unum_param(notify_setting.substr(7 /* len 'pipefd:' */),
-                            name, std::numeric_limits<int>::max());
-                }
-                else if (starts_with(notify_setting, "pipevar:")) {
-                    readiness_var = notify_setting.substr(8 /* len 'pipevar:' */);
-                    if (readiness_var.empty()) {
-                        throw service_description_exc(name, "Invalid pipevar variable name "
-                                "in ready-notification");
-                    }
-                }
-                else {
-                    throw service_description_exc(name, "Unknown ready-notification setting: "
-                            + notify_setting);
-                }
-            }
-            else if (setting == "inittab-id") {
-                string inittab_setting = read_setting_value(i, end, nullptr);
-                #if USE_UTMPX
-                if (inittab_setting.length() > sizeof(inittab_id)) {
-                    throw service_description_exc(name, "inittab-id setting is too long");
-                }
-                strncpy(inittab_id, inittab_setting.c_str(), sizeof(inittab_id));
-                #endif
-            }
-            else if (setting == "inittab-line") {
-                string inittab_setting = read_setting_value(i, end, nullptr);
-                #if USE_UTMPX
-                if (inittab_setting.length() > sizeof(inittab_line)) {
-                    throw service_description_exc(name, "inittab-line setting is too long");
-                }
-                strncpy(inittab_line, inittab_setting.c_str(), sizeof(inittab_line));
-                #endif
-            }
-            else if (setting == "rlimit-nofile") {
-                string nofile_setting = read_setting_value(i, end, nullptr);
-                service_rlimits &nofile_limits = find_rlimits(rlimits, RLIMIT_NOFILE);
-                parse_rlimit(line, name, "rlimit-nofile", nofile_limits);
-            }
-            else if (setting == "rlimit-core") {
-                string nofile_setting = read_setting_value(i, end, nullptr);
-                service_rlimits &nofile_limits = find_rlimits(rlimits, RLIMIT_CORE);
-                parse_rlimit(line, name, "rlimit-core", nofile_limits);
-            }
-            else if (setting == "rlimit-data") {
-                string nofile_setting = read_setting_value(i, end, nullptr);
-                service_rlimits &nofile_limits = find_rlimits(rlimits, RLIMIT_DATA);
-                parse_rlimit(line, name, "rlimit-data", nofile_limits);
-            }
-            else if (setting == "rlimit-addrspace") {
-                #if defined(RLIMIT_AS)
-                    string nofile_setting = read_setting_value(i, end, nullptr);
-                    service_rlimits &nofile_limits = find_rlimits(rlimits, RLIMIT_AS);
-                    parse_rlimit(line, name, "rlimit-addrspace", nofile_limits);
-                #endif
-            }
-            else {
-                throw service_description_exc(name, "Unknown setting: " + setting);
-            }
+
+            auto process_dep_dir_n = [&](std::list<prelim_dep> &deplist, const std::string &waitsford,
+                    dependency_type dep_type) -> void {
+                process_dep_dir(*this, name, service_filename, deplist, waitsford, dep_type);
+            };
+
+            auto load_service_n = [&](const string &dep_name) -> service_record * {
+                return load_service(dep_name.c_str());
+            };
+
+            process_service_line(settings, name, line, setting, i, end, load_service_n, process_dep_dir_n);
         });
 
         service_file.close();
         
+        auto service_type = settings.service_type;
+
         if (service_type == service_type_t::PROCESS || service_type == service_type_t::BGPROCESS
                 || service_type == service_type_t::SCRIPTED) {
-            if (command.length() == 0) {
+            if (settings.command.length() == 0) {
                 throw service_description_exc(name, "Service command not specified");
             }
         }
@@ -486,66 +205,67 @@ service_record * dirload_service_set::load_service(const char * name)
                 // We've found the dummy record
                 delete rval;
                 if (service_type == service_type_t::PROCESS) {
-                    do_env_subst(command, command_offsets, do_sub_vars);
-                    auto rvalps = new process_service(this, string(name), std::move(command),
-                            command_offsets, depends);
-                    rvalps->set_working_dir(working_dir);
-                    rvalps->set_env_file(env_file);
-                    rvalps->set_rlimits(std::move(rlimits));
-                    rvalps->set_restart_interval(restart_interval, max_restarts);
-                    rvalps->set_restart_delay(restart_delay);
-                    rvalps->set_stop_timeout(stop_timeout);
-                    rvalps->set_start_timeout(start_timeout);
-                    rvalps->set_extra_termination_signal(term_signal);
-                    rvalps->set_run_as_uid_gid(run_as_uid, run_as_gid);
-                    rvalps->set_notification_fd(readiness_fd);
-                    rvalps->set_notification_var(std::move(readiness_var));
+                    do_env_subst(settings.command, settings.command_offsets, settings.do_sub_vars);
+                    auto rvalps = new process_service(this, string(name), std::move(settings.command),
+                            settings.command_offsets, settings.depends);
+                    rvalps->set_working_dir(settings.working_dir);
+                    rvalps->set_env_file(settings.env_file);
+                    rvalps->set_rlimits(std::move(settings.rlimits));
+                    rvalps->set_restart_interval(settings.restart_interval, settings.max_restarts);
+                    rvalps->set_restart_delay(settings.restart_delay);
+                    rvalps->set_stop_timeout(settings.stop_timeout);
+                    rvalps->set_start_timeout(settings.start_timeout);
+                    rvalps->set_extra_termination_signal(settings.term_signal);
+                    rvalps->set_run_as_uid_gid(settings.run_as_uid, settings.run_as_gid);
+                    rvalps->set_notification_fd(settings.readiness_fd);
+                    rvalps->set_notification_var(std::move(settings.readiness_var));
                     #if USE_UTMPX
-                    rvalps->set_utmp_id(inittab_id);
-                    rvalps->set_utmp_line(inittab_line);
+                    rvalps->set_utmp_id(settings.inittab_id);
+                    rvalps->set_utmp_line(settings.inittab_line);
                     #endif
                     rval = rvalps;
                 }
                 else if (service_type == service_type_t::BGPROCESS) {
-                    do_env_subst(command, command_offsets, do_sub_vars);
-                    auto rvalps = new bgproc_service(this, string(name), std::move(command),
-                            command_offsets, depends);
-                    rvalps->set_working_dir(working_dir);
-                    rvalps->set_env_file(env_file);
-                    rvalps->set_rlimits(std::move(rlimits));
-                    rvalps->set_pid_file(std::move(pid_file));
-                    rvalps->set_restart_interval(restart_interval, max_restarts);
-                    rvalps->set_restart_delay(restart_delay);
-                    rvalps->set_stop_timeout(stop_timeout);
-                    rvalps->set_start_timeout(start_timeout);
-                    rvalps->set_extra_termination_signal(term_signal);
-                    rvalps->set_run_as_uid_gid(run_as_uid, run_as_gid);
-                    onstart_flags.runs_on_console = false;
+                    do_env_subst(settings.command, settings.command_offsets, settings.do_sub_vars);
+                    auto rvalps = new bgproc_service(this, string(name), std::move(settings.command),
+                            settings.command_offsets, settings.depends);
+                    rvalps->set_working_dir(settings.working_dir);
+                    rvalps->set_env_file(settings.env_file);
+                    rvalps->set_rlimits(std::move(settings.rlimits));
+                    rvalps->set_pid_file(std::move(settings.pid_file));
+                    rvalps->set_restart_interval(settings.restart_interval, settings.max_restarts);
+                    rvalps->set_restart_delay(settings.restart_delay);
+                    rvalps->set_stop_timeout(settings.stop_timeout);
+                    rvalps->set_start_timeout(settings.start_timeout);
+                    rvalps->set_extra_termination_signal(settings.term_signal);
+                    rvalps->set_run_as_uid_gid(settings.run_as_uid, settings.run_as_gid);
+                    settings.onstart_flags.runs_on_console = false;
                     rval = rvalps;
                 }
                 else if (service_type == service_type_t::SCRIPTED) {
-                    do_env_subst(command, command_offsets, do_sub_vars);
-                    auto rvalps = new scripted_service(this, string(name), std::move(command),
-                            command_offsets, depends);
-                    rvalps->set_stop_command(stop_command, stop_command_offsets);
-                    rvalps->set_working_dir(working_dir);
-                    rvalps->set_env_file(env_file);
-                    rvalps->set_rlimits(std::move(rlimits));
-                    rvalps->set_stop_timeout(stop_timeout);
-                    rvalps->set_start_timeout(start_timeout);
-                    rvalps->set_extra_termination_signal(term_signal);
-                    rvalps->set_run_as_uid_gid(run_as_uid, run_as_gid);
+                    do_env_subst(settings.command, settings.command_offsets, settings.do_sub_vars);
+                    auto rvalps = new scripted_service(this, string(name), std::move(settings.command),
+                            settings.command_offsets, settings.depends);
+                    rvalps->set_stop_command(settings.stop_command, settings.stop_command_offsets);
+                    rvalps->set_working_dir(settings.working_dir);
+                    rvalps->set_env_file(settings.env_file);
+                    rvalps->set_rlimits(std::move(settings.rlimits));
+                    rvalps->set_stop_timeout(settings.stop_timeout);
+                    rvalps->set_start_timeout(settings.start_timeout);
+                    rvalps->set_extra_termination_signal(settings.term_signal);
+                    rvalps->set_run_as_uid_gid(settings.run_as_uid, settings.run_as_gid);
                     rval = rvalps;
                 }
                 else {
-                    rval = new service_record(this, string(name), service_type, depends);
+                    rval = new service_record(this, string(name), service_type, settings.depends);
                 }
-                rval->set_log_file(logfile);
-                rval->set_auto_restart(auto_restart);
-                rval->set_smooth_recovery(smooth_recovery);
-                rval->set_flags(onstart_flags);
-                rval->set_socket_details(std::move(socket_path), socket_perms, socket_uid, socket_gid);
-                rval->set_chain_to(std::move(chain_to_name));
+                rval->set_log_file(settings.logfile);
+                rval->set_auto_restart(settings.auto_restart);
+                rval->set_smooth_recovery(settings.smooth_recovery);
+                rval->set_flags(settings.onstart_flags);
+                rval->set_socket_details(std::move(settings.socket_path), settings.socket_perms,
+                        settings.socket_uid, settings.socket_gid);
+                rval->set_chain_to(std::move(settings.chain_to_name));
                 *iter = rval;
                 break;
             }
index 5864bdd5dae44623669521370ce55631abf6b92e..4ab7075cbae61c8063d998bc9c42a99adb72f64d 100644 (file)
@@ -59,13 +59,19 @@ int main(int argc, char **argv)
     }
 
     using namespace std;
-    cout << "// This file is auto-generated by mconfig-gen.cc." << endl;
+    cout << "// This file is auto-generated by mconfig-gen.cc.\n";
+    cout << "#ifndef DINIT_MCONFIG_H\n";
+    cout << "#define DINIT_MCONFIG_H 1\n";
+
     cout << "\n// Defines\n";
     if (vars.find("USE_UTMPX") != vars.end()) {
         cout << "#define USE_UTMPX " << vars["USE_UTMPX"] << "\n";
     }
+
     cout << "\n// Constants\n";
     cout << "constexpr static char SYSCONTROLSOCKET[] = " << stringify(vars["SYSCONTROLSOCKET"]) << ";\n";
     cout << "constexpr static char SBINDIR[] = " << stringify(vars["SBINDIR"]) << ";\n";
+
+    cout << "\n#endif\n";
     return 0;
 }