service description: make waits-for.d path relative to service file.
authorDavin McCall <davmac@davmac.org>
Fri, 19 Oct 2018 22:00:41 +0000 (23:00 +0100)
committerDavin McCall <davmac@davmac.org>
Fri, 19 Oct 2018 22:00:41 +0000 (23:00 +0100)
If the path specified by waits-for.d is not absolute, it will be
interpreted as relative to the directory containing the service
description file.

doc/manpages/dinit-service.5
src/dinitctl.cc
src/includes/dinit-util.h
src/load-service.cc

index 38f5847adfffb6cf674b8fdfae527d02a47c603d..c853a1361724f17d1b966f8ee4187b47b1632425 100644 (file)
@@ -172,7 +172,10 @@ add a \fBwaits-for\fR dependency to the service with the same name. Note that
 contents of files in the specified directory are not significant; expected
 usage is to have symbolic links to the associated service description files,
 but this is not required. Failure to read the directory contents, or to find
-any of the services named within, is not considered fatal. 
+any of the services named within, is not considered fatal.
+
+The directory path, if not absolute, is relative to the directory containing
+the service description file.
 .TP
 \fBsocket\-listen\fR = \fIsocket-path\fR
 Pre-open a socket for the service and pass it to the service using the
index 43808d21c8eadb108b165ae7208d9da052e5d091..fadc2fb055bd3ce99bd7b40e2521266e0a65fe37 100644 (file)
@@ -22,6 +22,7 @@
 #include "cpbuffer.h"
 #include "dinit-client.h"
 #include "load-service.h"
+#include "dinit-util.h"
 
 // dinitctl:  utility to control the Dinit daemon, including starting and stopping of services.
 
@@ -855,16 +856,6 @@ static int shutdown_dinit(int socknum, cpbuffer_t &rbuffer)
     return 0;
 }
 
-// Join two paths; the 2nd must be relative
-static std::string join_paths(std::string p1, std::string p2)
-{
-    std::string r = p1;
-    if (*(r.rbegin()) != '/') {
-        r += '/';
-    }
-    return r + p2;
-}
-
 // exception for cancelling a service operation
 class service_op_cancel { };
 
@@ -936,7 +927,7 @@ static int enable_disable_service(int socknum, cpbuffer_t &rbuffer, const char *
     string service_file_path;
 
     for (std::string path : paths) {
-        string test_path = join_paths(dinit_cwd + '/' + path, from);
+        string test_path = combine_paths(dinit_cwd + '/' + path, from);
 
         service_file.open(test_path.c_str(), ios::in);
         if (service_file) {
@@ -988,8 +979,11 @@ static int enable_disable_service(int socknum, cpbuffer_t &rbuffer, const char *
         return 1;
     }
 
+    // The waits-for.d path is relative to the service file path, combine:
+    string waits_for_d_full = combine_paths(parent_path(service_file_path), waits_for_d.c_str());
+
     // check if dependency already exists
-    string dep_link_path = join_paths(waits_for_d, to);
+    string dep_link_path = combine_paths(waits_for_d_full, to);
     struct stat stat_buf;
     if (lstat(dep_link_path.c_str(), &stat_buf) == -1) {
         if (errno != ENOENT) {
index 77170f443fa75354888ba3e8d0c880002ae8ec27..caedbdd2c0d77dff4785dd213099f8afa111bdd8 100644 (file)
@@ -36,4 +36,29 @@ inline ssize_t ss_read(int fd, void * buf, size_t n)
     return n;
 }
 
+// Combine two paths to produce a path. If the second path is absolute, it is returned unmodified;
+// otherwise, it is appended to the first path (with a slash separator added if needed).
+inline std::string combine_paths(const std::string &p1, const char * p2)
+{
+    if (*p2 == 0) return p1;
+    if (p1.empty()) return std::string(p2);
+
+    if (p2[0] == '/') return p2;
+
+    if (*(p1.rbegin()) == '/') return p1 + p2;
+    return p1 + '/' + p2;
+}
+
+// Find the parent path of a given path, which should refer to a named file or directory (not . or ..).
+// If the path contains no directory, returns the empty string.
+inline std::string parent_path(const std::string &p)
+{
+    auto spos = p.rfind('/');
+    if (spos == std::string::npos) {
+        return std::string {};
+    }
+
+    return p.substr(0, spos + 1);
+}
+
 #endif
index 1aeddb858cfd93e9db0a245e76a24dcd4b444764..37c00bccb8b161c2e378367e97bcaee175925e3e 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "proc-service.h"
 #include "dinit-log.h"
+#include "dinit-util.h"
 
 using string = std::string;
 using string_iterator = std::string::iterator;
@@ -243,12 +244,15 @@ static void do_env_subst(std::string &line, std::list<std::pair<unsigned,unsigne
 // a fatal error.
 static void process_dep_dir(dirload_service_set &sset,
         const char *servicename,
+        string service_filename,
         std::list<prelim_dep> &deplist, const std::string &depdirpath,
         dependency_type dep_type)
 {
-    DIR *depdir = opendir(depdirpath.c_str());
+    std::string depdir_fname = combine_paths(parent_path(service_filename), depdirpath.c_str());
+
+    DIR *depdir = opendir(depdir_fname.c_str());
     if (depdir == nullptr) {
-        log(loglevel_t::WARN, "Could not open dependency directory '", depdirpath,
+        log(loglevel_t::WARN, "Could not open dependency directory '", depdir_fname,
                 "' for ", servicename, " service.");
         return;
     }
@@ -308,10 +312,11 @@ service_record * dirload_service_set::load_service(const char * name)
     }
 
     ifstream service_file;
+    string service_filename;
 
     // Couldn't find one. Have to load it.
     for (auto &service_dir : service_dirs) {
-        string service_filename = service_dir.get_dir();
+        service_filename = service_dir.get_dir();
         if (*(service_filename.rbegin()) != '/') {
             service_filename += '/';
         }
@@ -422,7 +427,8 @@ service_record * dirload_service_set::load_service(const char * name)
             }
             else if (setting == "waits-for.d") {
                 string waitsford = read_setting_value(i, end);
-                process_dep_dir(*this, name, depends, waitsford, dependency_type::WAITS_FOR);
+                process_dep_dir(*this, name, service_filename, depends, waitsford,
+                        dependency_type::WAITS_FOR);
             }
             else if (setting == "logfile") {
                 logfile = read_setting_value(i, end);