[systemd-commits] 11 commits - src/core src/nss-myhostname src/shared src/systemctl src/test TODO

Zbigniew Jędrzejewski-Szmek zbyszek at kemper.freedesktop.org
Mon Dec 15 21:30:54 PST 2014


 TODO                                |    5 
 src/core/load-dropin.c              |  138 +--------
 src/core/load-dropin.h              |    9 
 src/core/unit.c                     |    2 
 src/nss-myhostname/nss-myhostname.c |    4 
 src/shared/dropin.c                 |  136 +++++++++
 src/shared/dropin.h                 |   29 ++
 src/shared/path-util.c              |    6 
 src/shared/utf8.c                   |    1 
 src/systemctl/systemctl.c           |  504 +++++++++++++++++-------------------
 src/test/test-path-util.c           |    4 
 11 files changed, 439 insertions(+), 399 deletions(-)

New commits:
commit b0ceb53a7ddb94269f70b2769bbc72870e574111
Author: Susant Sahani <susant at redhat.com>
Date:   Tue Dec 16 08:48:34 2014 +0530

    fix compiler warning
    
    src/shared/utf8.c:268:13: warning: unused variable 'd'
    [-Wunused-variable]
             int d;

diff --git a/src/shared/utf8.c b/src/shared/utf8.c
index 67f6285..03a0abe 100644
--- a/src/shared/utf8.c
+++ b/src/shared/utf8.c
@@ -265,7 +265,6 @@ char *ascii_is_valid(const char *str) {
 
 int utf8_encode_unichar(uint16_t c, char *p) {
         uint8_t *t = (uint8_t*) p;
-        int d;
 
         if (c < 0x80) {
                 t[0] = (uint8_t) c;

commit 75836b9d2071aab978ee78d7d797126a18a32052
Author: Jan Synacek <jsynacek at redhat.com>
Date:   Mon Dec 15 10:39:00 2014 +0100

    systemctl: fix argument handling when invoked as "shutdown"

diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 649fb5c..4c4648f 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -6926,7 +6926,7 @@ static int shutdown_parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "HPrhkt:afFc", options, NULL)) >= 0)
+        while ((c = getopt_long(argc, argv, "HPrhkKt:afFc", options, NULL)) >= 0)
                 switch (c) {
 
                 case ARG_HELP:
@@ -6967,6 +6967,8 @@ static int shutdown_parse_argv(int argc, char *argv[]) {
 
                 case 't':
                 case 'a':
+                case 'f':
+                case 'F':
                         /* Compatibility nops */
                         break;
 

commit df17ddee0853482bfaefc36b9bd3424a64621915
Author: Harald Hoyer <harald at redhat.com>
Date:   Mon Dec 15 11:34:24 2014 +0100

    nss-myhostname: also recognize "gateway."
    
    "gateway." skips adding the domain search path and saves some queries to
    the nameserver.

diff --git a/src/nss-myhostname/nss-myhostname.c b/src/nss-myhostname/nss-myhostname.c
index aa92cc9..2f76860 100644
--- a/src/nss-myhostname/nss-myhostname.c
+++ b/src/nss-myhostname/nss-myhostname.c
@@ -78,7 +78,7 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
                 canonical = "localhost";
                 local_address_ipv4 = htonl(INADDR_LOOPBACK);
 
-        } else if (streq(name, "gateway")) {
+        } else if (streq(name, "gateway") || streq(name, "gateway.")) {
 
                 n_addresses = local_gateways(NULL, 0, AF_UNSPEC, &addresses);
                 if (n_addresses <= 0) {
@@ -348,7 +348,7 @@ enum nss_status _nss_myhostname_gethostbyname3_r(
                 canonical = "localhost";
                 local_address_ipv4 = htonl(INADDR_LOOPBACK);
 
-        } else if (streq(name, "gateway")) {
+        } else if (streq(name, "gateway") || streq(name, "gateway.")) {
 
                 n_addresses = local_gateways(NULL, 0, af, &addresses);
                 if (n_addresses <= 0) {

commit b42de08aa4c97636e42c28c7bce08f0d7c2a719a
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Tue Dec 16 00:22:58 2014 -0500

    Update TODO

diff --git a/TODO b/TODO
index c0da5c8..393ee5e 100644
--- a/TODO
+++ b/TODO
@@ -123,7 +123,10 @@ Features:
 
 * systemctl: if some operation fails, show log output?
 
-* systemctl edit: add commented help text to the end, like git commit
+* systemctl edit:
+- allow creation of units from scratch
+- use equvalent of cat() to insert existing config as a comment, prepended with #.
+  Upon editor exit, lines with one # are removed, lines with two # are left with one #, etc.
 
 * refcounting in sd-resolve is borked
 

commit bc854dc7cd051e1e5a6ebcca8084b07168051c6c
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Mon Dec 15 23:01:05 2014 -0500

    systemctl: refuse to edit runtime dropins when they already exist in /etc
    
    The check for existing unit files and dropins is unified.
    
    path_join() is updated to not insert duplicate separators.

diff --git a/src/shared/path-util.c b/src/shared/path-util.c
index b3fe0b8..dcc8321 100644
--- a/src/shared/path-util.c
+++ b/src/shared/path-util.c
@@ -439,14 +439,14 @@ char* path_join(const char *root, const char *path, const char *rest) {
         assert(path);
 
         if (!isempty(root))
-                return strjoin(root, "/",
+                return strjoin(root, endswith(root, "/") ? "" : "/",
                                path[0] == '/' ? path+1 : path,
-                               rest ? "/" : NULL,
+                               rest ? (endswith(path, "/") ? "" : "/") : NULL,
                                rest && rest[0] == '/' ? rest+1 : rest,
                                NULL);
         else
                 return strjoin(path,
-                               rest ? "/" : NULL,
+                               rest ? (endswith(path, "/") ? "" : "/") : NULL,
                                rest && rest[0] == '/' ? rest+1 : rest,
                                NULL);
 }
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 51ba330..649fb5c 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -5902,41 +5902,58 @@ static int create_edit_temp_file(const char *new_path, const char *original_path
         return 0;
 }
 
-static int get_drop_in_to_edit(const char *unit_name, const char *user_home, const char *user_runtime, char **ret_path) {
-        char *tmp_new_path;
-        char *tmp;
-
-        assert(unit_name);
-        assert(ret_path);
+static int get_file_to_edit(const char *name, const char *user_home, const char *user_runtime, char **ret_path) {
+        _cleanup_free_ char *path = NULL, *path2 = NULL, *run = NULL;
 
         switch (arg_scope) {
                 case UNIT_FILE_SYSTEM:
-                        tmp = strappenda(arg_runtime ? "/run/systemd/system/" : SYSTEM_CONFIG_UNIT_PATH "/", unit_name, ".d/override.conf");
+                        path = path_join(arg_root, SYSTEM_CONFIG_UNIT_PATH, name);
+                        if (arg_runtime)
+                                run = path_join(arg_root, "/run/systemd/system/", name);
                         break;
                 case UNIT_FILE_GLOBAL:
-                        tmp = strappenda(arg_runtime ? "/run/systemd/user/" : USER_CONFIG_UNIT_PATH "/", unit_name, ".d/override.conf");
+                        path = path_join(arg_root, USER_CONFIG_UNIT_PATH, name);
+                        if (arg_runtime)
+                                run = path_join(arg_root, "/run/systemd/user/", name);
                         break;
                 case UNIT_FILE_USER:
                         assert(user_home);
                         assert(user_runtime);
 
-                        tmp = strappenda(arg_runtime ? user_runtime : user_home, "/", unit_name, ".d/override.conf");
+                        path = path_join(arg_root, user_home, name);
+                        if (arg_runtime) {
+                                path2 = path_join(arg_root, USER_CONFIG_UNIT_PATH, name);
+                                if (!path2)
+                                        return log_oom();
+                                run = path_join(arg_root, user_runtime, name);
+                        }
                         break;
                 default:
                         assert_not_reached("Invalid scope");
         }
-
-        tmp_new_path = path_join(arg_root, tmp, NULL);
-        if (!tmp_new_path)
+        if (!path || (arg_runtime && !run))
                 return log_oom();
 
-        *ret_path = tmp_new_path;
+        if (arg_runtime) {
+                if (access(path, F_OK) >= 0)
+                        return log_error_errno(EEXIST, "Refusing to create \"%s\" because it would be overriden by \"%s\" anyway.",
+                                               run, path);
+                if (path2 && access(path2, F_OK) >= 0)
+                        return log_error_errno(EEXIST, "Refusing to create \"%s\" because it would be overriden by \"%s\" anyway.",
+                                               run, path2);
+                *ret_path = run;
+                run = NULL;
+        } else {
+                *ret_path = path;
+                path = NULL;
+        }
 
         return 0;
 }
 
-static int unit_file_create_drop_in(const char *unit_name, const char *user_home, const char *user_runtime, char **ret_new_path, char **ret_tmp_path) {
-        char *tmp_new_path;
+
+static int unit_file_create_dropin(const char *unit_name, const char *user_home, const char *user_runtime, char **ret_new_path, char **ret_tmp_path) {
+        char *tmp_new_path, *ending;
         char *tmp_tmp_path;
         int r;
 
@@ -5944,7 +5961,8 @@ static int unit_file_create_drop_in(const char *unit_name, const char *user_home
         assert(ret_new_path);
         assert(ret_tmp_path);
 
-        r = get_drop_in_to_edit(unit_name, user_home, user_runtime, &tmp_new_path);
+        ending = strappenda(unit_name, ".d/override.conf");
+        r = get_file_to_edit(ending, user_home, user_runtime, &tmp_new_path);
         if (r < 0)
                 return r;
 
@@ -5960,91 +5978,6 @@ static int unit_file_create_drop_in(const char *unit_name, const char *user_home
         return 0;
 }
 
-static bool unit_is_editable(const char *unit_name, const char *fragment_path, const char *user_home) {
-        bool editable = true;
-        const char *invalid_path;
-
-        assert(unit_name);
-
-        if (!arg_runtime)
-                return true;
-
-        switch (arg_scope) {
-                case UNIT_FILE_SYSTEM:
-                        if (path_startswith(fragment_path, "/etc/systemd/system")) {
-                                editable = false;
-                                invalid_path = "/etc/systemd/system";
-                        } else if (path_startswith(fragment_path, SYSTEM_CONFIG_UNIT_PATH)) {
-                                editable = false;
-                                invalid_path = SYSTEM_CONFIG_UNIT_PATH;
-                        }
-                        break;
-                case UNIT_FILE_GLOBAL:
-                        if (path_startswith(fragment_path, "/etc/systemd/user")) {
-                                editable = false;
-                                invalid_path = "/etc/systemd/user";
-                        } else if (path_startswith(fragment_path, USER_CONFIG_UNIT_PATH)) {
-                                editable = false;
-                                invalid_path = USER_CONFIG_UNIT_PATH;
-                        }
-                        break;
-                case UNIT_FILE_USER:
-                        assert(user_home);
-
-                        if (path_startswith(fragment_path, "/etc/systemd/user")) {
-                                editable = false;
-                                invalid_path = "/etc/systemd/user";
-                        } else if (path_startswith(fragment_path, USER_CONFIG_UNIT_PATH)) {
-                                editable = false;
-                                invalid_path = USER_CONFIG_UNIT_PATH;
-                        } else if (path_startswith(fragment_path, user_home)) {
-                                editable = false;
-                                invalid_path = user_home;
-                        }
-                        break;
-                default:
-                        assert_not_reached("Invalid scope");
-        }
-
-        if (!editable)
-                log_error("%s ignored: cannot temporarily edit units from %s", unit_name, invalid_path);
-
-        return editable;
-}
-
-static int get_copy_to_edit(const char *unit_name, const char *fragment_path, const char *user_home, const char *user_runtime, char **ret_path) {
-        char *tmp_new_path;
-
-        assert(unit_name);
-        assert(ret_path);
-
-        if (!unit_is_editable(unit_name, fragment_path, user_home))
-                return -EINVAL;
-
-        switch (arg_scope) {
-                case UNIT_FILE_SYSTEM:
-                        tmp_new_path = path_join(arg_root, arg_runtime ? "/run/systemd/system/" : SYSTEM_CONFIG_UNIT_PATH, unit_name);
-                        break;
-                case UNIT_FILE_GLOBAL:
-                        tmp_new_path = path_join(arg_root, arg_runtime ? "/run/systemd/user/" : USER_CONFIG_UNIT_PATH, unit_name);
-                        break;
-                case UNIT_FILE_USER:
-                        assert(user_home);
-                        assert(user_runtime);
-
-                        tmp_new_path = path_join(arg_root, arg_runtime ? user_runtime : user_home, unit_name);
-                        break;
-                default:
-                        assert_not_reached("Invalid scope");
-        }
-        if (!tmp_new_path)
-                return log_oom();
-
-        *ret_path = tmp_new_path;
-
-        return 0;
-}
-
 static int unit_file_create_copy(const char *unit_name,
                                  const char *fragment_path,
                                  const char *user_home,
@@ -6060,7 +5993,7 @@ static int unit_file_create_copy(const char *unit_name,
         assert(ret_new_path);
         assert(ret_tmp_path);
 
-        r = get_copy_to_edit(unit_name, fragment_path, user_home, user_runtime, &tmp_new_path);
+        r = get_file_to_edit(unit_name, user_home, user_runtime, &tmp_new_path);
         if (r < 0)
                 return r;
 
@@ -6192,7 +6125,7 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
                 if (arg_full)
                         r = unit_file_create_copy(*name, path, user_home, user_runtime, &new_path, &tmp_path);
                 else
-                        r = unit_file_create_drop_in(*name, user_home, user_runtime, &new_path, &tmp_path);
+                        r = unit_file_create_dropin(*name, user_home, user_runtime, &new_path, &tmp_path);
                 if (r < 0)
                         return r;
 
diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c
index 58b456a..11aa52a 100644
--- a/src/test/test-path-util.c
+++ b/src/test/test-path-util.c
@@ -176,13 +176,13 @@ static void test_path_join(void) {
         test_join("/root", "/a/b", "/c", "/root/a/b/c");
         test_join("/root", "a/b", "c", "/root/a/b/c");
         test_join("/root", "/a/b", "c", "/root/a/b/c");
-        test_join("/root", "/", "c", "/root//c");
+        test_join("/root", "/", "c", "/root/c");
         test_join("/root", "/", NULL, "/root/");
 
         test_join(NULL, "/a/b", "/c", "/a/b/c");
         test_join(NULL, "a/b", "c", "a/b/c");
         test_join(NULL, "/a/b", "c", "/a/b/c");
-        test_join(NULL, "/", "c", "//c");
+        test_join(NULL, "/", "c", "/c");
         test_join(NULL, "/", NULL, "/");
 }
 

commit ad2a035820e0fca29e49816f735bec1fcdabf82a
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Sat Dec 13 16:38:35 2014 -0500

    systemctl: share path lookup between 'cat' and 'edit'
    
    'systemctl cat' now works for templates too.
    
    'systemctl edit' does not refuse to edit units that have changed on
    disk. That restriction didn't seem useful, actually editing units that
    have changed on disk before they are started is very reasonable.
    
    'edit' with instances and templates works again:
    
    Now:
    
    $ build/systemctl edit getty@
    Failed to copy /etc/systemd/system/getty at .service.d/override.conf to /etc/systemd/system/getty at .service.d/.override.confdff6290408c86369: Permission denied
    $ build/systemctl edit getty at tty3
    Failed to create directories for /etc/systemd/system/getty at tty3.service.d/override.conf: Permission denied
    $ build/systemctl edit --full getty at tty3
    Failed to copy /usr/lib/systemd/system/getty at .service to /etc/systemd/system/.getty at tty3.serviced3d175087e7e439b: Permission denied
    Failed to create temporary file for /etc/systemd/system/getty at tty3.service: Permission denied
    $ build/systemctl edit --full getty@
    Failed to copy /usr/lib/systemd/system/getty at .service to /etc/systemd/system/.getty at .servicea3caad491c0f2f3d: Permission denied
    Failed to create temporary file for /etc/systemd/system/getty at .service: Permission denied

diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 68cb71c..51ba330 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -74,6 +74,7 @@
 #include "bus-error.h"
 #include "bus-common-errors.h"
 #include "mkdir.h"
+#include "dropin.h"
 
 static char **arg_types = NULL;
 static char **arg_states = NULL;
@@ -2286,7 +2287,7 @@ static int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **un
         assert(unit_path);
 
         STRV_FOREACH(p, lp->unit_path) {
-                char *path;
+                _cleanup_free_ char *path;
 
                 path = path_join(arg_root, *p, unit_name);
                 if (!path)
@@ -2294,35 +2295,46 @@ static int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **un
 
                 if (access(path, F_OK) == 0) {
                         *unit_path = path;
+                        path = NULL;
                         return 1;
                 }
-
-                free(path);
         }
 
         return 0;
 }
 
-static int unit_find_path(sd_bus *bus, const char *unit_name, const char *template, bool avoid_bus_cache, LookupPaths *lp, char **path) {
+static int unit_find_paths(sd_bus *bus,
+                           const char *unit_name,
+                           bool avoid_bus_cache,
+                           LookupPaths *lp,
+                           char **fragment_path,
+                           char ***dropin_paths) {
         int r;
 
+        /**
+         * Finds where the unit is defined on disk. Returns 0 if the unit
+         * is not found. Returns 1 if it is found, and sets
+         * - the path to the unit in *path, if it exists on disk,
+         * - and a strv of existing drop-ins in *dropins,
+         *   if the arg is not NULL and any dropins were found.
+         */
+
         assert(unit_name);
-        assert(path);
+        assert(fragment_path);
         assert(lp);
 
         if (!avoid_bus_cache && !unit_name_is_template(unit_name)) {
                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
                 _cleanup_free_ char *unit = NULL;
-                _cleanup_free_ char *tmp_path = NULL;
+                _cleanup_free_ char *path = NULL;
+                _cleanup_strv_free_ char **dropins = NULL;
 
                 unit = unit_dbus_path_from_name(unit_name);
                 if (!unit)
                         return log_oom();
 
-                if (need_daemon_reload(bus, unit_name) > 0) {
+                if (need_daemon_reload(bus, unit_name) > 0)
                         warn_unit_file_changed(unit_name);
-                        return 0;
-                }
 
                 r = sd_bus_get_property_string(
                                 bus,
@@ -2331,29 +2343,67 @@ static int unit_find_path(sd_bus *bus, const char *unit_name, const char *templa
                                 "org.freedesktop.systemd1.Unit",
                                 "FragmentPath",
                                 &error,
-                                &tmp_path);
-                if (r < 0) {
-                        log_warning("Failed to get FragmentPath: %s", bus_error_message(&error, r));
-                        return 0;
+                                &path);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to get FragmentPath: %s", bus_error_message(&error, r));
+
+                r = sd_bus_get_property_strv(
+                                bus,
+                                "org.freedesktop.systemd1",
+                                unit,
+                                "org.freedesktop.systemd1.Unit",
+                                "DropInPaths",
+                                &error,
+                                &dropins);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to get DropInPaths: %s", bus_error_message(&error, r));
+
+                r = 0;
+                if (!isempty(path)) {
+                        *fragment_path = path;
+                        path = NULL;
+                        r = 1;
                 }
 
-                if (isempty(tmp_path)) {
-                        log_warning("%s ignored: not found", template);
-                        return 0;
+                if (dropin_paths && !strv_isempty(dropins)) {
+                        *dropin_paths = dropins;
+                        dropins = NULL;
+                        r = 1;
                 }
+        } else {
+                _cleanup_set_free_ Set *names;
 
-                *path = tmp_path;
-                tmp_path = NULL;
+                names = set_new(NULL);
+                if (!names)
+                        return -ENOMEM;
 
-                return 1;
-        } else {
-                r = unit_file_find_path(lp, template, path);
-                if (r == 0)
-                        log_warning("%s ignored: not found", template);
-                return r;
+                r = set_put(names, unit_name);
+                if (r < 0)
+                        return r;
+
+                r = unit_file_find_path(lp, unit_name, fragment_path);
+                if (r < 0)
+                        return r;
+
+                if (r == 0) {
+                        _cleanup_free_ char *template;
+
+                        template = unit_name_template(unit_name);
+                        if (!template)
+                                return log_oom();
+
+                        if (!streq(template, unit_name)) {
+                                r = unit_file_find_path(lp, template, fragment_path);
+                                if (r < 0)
+                                        return r;
+                        }
+                }
+
+                if (dropin_paths)
+                        r = unit_file_find_dropin_paths(lp->unit_path, NULL, names, dropin_paths);
         }
 
-        return 0;
+        return r;
 }
 
 typedef struct WaitData {
@@ -2810,6 +2860,9 @@ static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***r
                 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
                 _cleanup_free_ UnitInfo *unit_infos = NULL;
 
+                if (!bus)
+                        return log_error_errno(ENOTSUP, "Unit name globbing without bus is not implemented.");
+
                 r = get_unit_list(bus, NULL, globs, &unit_infos, 0, &reply);
                 if (r < 0)
                         return r;
@@ -4701,56 +4754,38 @@ static int init_home_and_lookup_paths(char **user_home, char **user_runtime, Loo
 }
 
 static int cat(sd_bus *bus, char **args) {
+        _cleanup_free_ char *user_home = NULL;
+        _cleanup_free_ char *user_runtime = NULL;
+        _cleanup_lookup_paths_free_ LookupPaths lp = {};
         _cleanup_strv_free_ char **names = NULL;
         char **name;
-        bool first = true;
+        bool first = true, avoid_bus_cache;
         int r = 0;
 
-        assert(bus);
         assert(args);
 
+        r = init_home_and_lookup_paths(&user_home, &user_runtime, &lp);
+        if (r < 0)
+                return r;
+
         r = expand_names(bus, args + 1, NULL, &names);
         if (r < 0)
                 log_error_errno(r, "Failed to expand names: %m");
 
+        avoid_bus_cache = !bus || avoid_bus();
+
         pager_open_if_enabled();
 
         STRV_FOREACH(name, names) {
-                _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+                _cleanup_free_ char *fragment_path = NULL;
                 _cleanup_strv_free_ char **dropin_paths = NULL;
-                _cleanup_free_ char *fragment_path = NULL, *unit = NULL;
                 char **path;
 
-                unit = unit_dbus_path_from_name(*name);
-                if (!unit)
-                        return log_oom();
-
-                if (need_daemon_reload(bus, *name) > 0)
-                        warn_unit_file_changed(*name);
-
-                r = sd_bus_get_property_string(
-                                bus,
-                                "org.freedesktop.systemd1",
-                                unit,
-                                "org.freedesktop.systemd1.Unit",
-                                "FragmentPath",
-                                &error,
-                                &fragment_path);
-                if (r < 0) {
-                        log_warning("Failed to get FragmentPath: %s", bus_error_message(&error, r));
-                        continue;
-                }
-
-                r = sd_bus_get_property_strv(
-                                bus,
-                                "org.freedesktop.systemd1",
-                                unit,
-                                "org.freedesktop.systemd1.Unit",
-                                "DropInPaths",
-                                &error,
-                                &dropin_paths);
-                if (r < 0) {
-                        log_warning("Failed to get DropInPaths: %s", bus_error_message(&error, r));
+                r = unit_find_paths(bus, *name, avoid_bus_cache, &lp, &fragment_path, &dropin_paths);
+                if (r < 0)
+                        return r;
+                else if (r == 0) {
+                        log_warning("Unit %s does not have any files on disk", *name);
                         continue;
                 }
 
@@ -4759,7 +4794,7 @@ static int cat(sd_bus *bus, char **args) {
                 else
                         puts("");
 
-                if (!isempty(fragment_path)) {
+                if (fragment_path) {
                         printf("%s# %s%s\n",
                                ansi_highlight_blue(),
                                fragment_path,
@@ -6115,7 +6150,7 @@ static int run_editor(char **paths) {
                         }
                 }
 
-                log_error("Cannot edit unit(s): No editor available. Please set either SYSTEMD_EDITOR or EDITOR or VISUAL environment variable");
+                log_error("Cannot edit unit(s), no editor available. Please set either $SYSTEMD_EDITOR or $EDITOR or $VISUAL.");
                 _exit(EXIT_FAILURE);
         }
 
@@ -6145,27 +6180,21 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
 
         STRV_FOREACH(name, names) {
                 _cleanup_free_ char *path = NULL;
-                _cleanup_free_ char *template = NULL;
                 char *new_path, *tmp_path;
 
-                template = unit_name_template(*name);
-                if (!template)
-                        return log_oom();
-
-                r = unit_find_path(bus, *name, template, avoid_bus_cache, &lp, &path);
+                r = unit_find_paths(bus, *name, avoid_bus_cache, &lp, &path, NULL);
                 if (r < 0)
                         return r;
-                else if (r == 0) {
-                        continue;
-                }
+                else if (r == 0 || !path)
+                        // FIXME: support units with path==NULL (no FragmentPath)
+                        return log_error_errno(ENOENT, "Unit %s not found, cannot edit.", *name);
 
                 if (arg_full)
-                        r = unit_file_create_copy(template, path, user_home, user_runtime, &new_path, &tmp_path);
+                        r = unit_file_create_copy(*name, path, user_home, user_runtime, &new_path, &tmp_path);
                 else
-                        r = unit_file_create_drop_in(template, user_home, user_runtime, &new_path, &tmp_path);
-
+                        r = unit_file_create_drop_in(*name, user_home, user_runtime, &new_path, &tmp_path);
                 if (r < 0)
-                        continue;
+                        return r;
 
                 r = strv_push_pair(paths, new_path, tmp_path);
                 if (r < 0)
@@ -7307,7 +7336,7 @@ static int systemctl_main(sd_bus *bus, int argc, char *argv[], int bus_error) {
                 { "check",                 MORE,  2, check_unit_active },
                 { "is-failed",             MORE,  2, check_unit_failed },
                 { "show",                  MORE,  1, show              },
-                { "cat",                   MORE,  2, cat               },
+                { "cat",                   MORE,  2, cat,              NOBUS },
                 { "status",                MORE,  1, show              },
                 { "help",                  MORE,  2, show              },
                 { "snapshot",              LESS,  2, snapshot          },

commit 8df1850740f2b78407b856e32ba649a7037227d4
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Tue Dec 16 00:28:43 2014 -0500

    systemctl: split out LookupPaths initialization

diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index d16c673..68cb71c 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -4668,6 +4668,38 @@ static int show(sd_bus *bus, char **args) {
         return ret;
 }
 
+static int init_home_and_lookup_paths(char **user_home, char **user_runtime, LookupPaths *lp) {
+        int r;
+
+        assert(user_home);
+        assert(user_runtime);
+        assert(lp);
+
+        if (arg_scope == UNIT_FILE_USER) {
+                r = user_config_home(user_home);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to query XDG_CONFIG_HOME: %m");
+                else if (r == 0)
+                        return log_error_errno(ENOTDIR, "Cannot find units: $XDG_CONFIG_HOME and $HOME are not set.");
+
+                r = user_runtime_dir(user_runtime);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to query XDG_CONFIG_HOME: %m");
+                else if (r == 0)
+                        return log_error_errno(ENOTDIR, "Cannot find units: $XDG_RUNTIME_DIR is not set.");
+        }
+
+        r = lookup_paths_init(lp,
+                              arg_scope == UNIT_FILE_SYSTEM ? SYSTEMD_SYSTEM : SYSTEMD_USER,
+                              arg_scope == UNIT_FILE_USER,
+                              arg_root,
+                              NULL, NULL, NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to lookup unit lookup paths: %m");
+
+        return 0;
+}
+
 static int cat(sd_bus *bus, char **args) {
         _cleanup_strv_free_ char **names = NULL;
         char **name;
@@ -6105,27 +6137,9 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
         assert(names);
         assert(paths);
 
-        if (arg_scope == UNIT_FILE_USER) {
-                r = user_config_home(&user_home);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to query XDG_CONFIG_HOME: %m");
-                else if (r == 0)
-                        return log_error_errno(ENOTDIR, "Cannot edit units: $XDG_CONFIG_HOME and $HOME are not set.");
-
-                r = user_runtime_dir(&user_runtime);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to query XDG_CONFIG_HOME: %m");
-                else if (r == 0)
-                        return log_error_errno(ENOTDIR, "Cannot edit units: $XDG_RUNTIME_DIR is not set.");
-        }
-
-        r = lookup_paths_init(&lp,
-                              arg_scope == UNIT_FILE_SYSTEM ? SYSTEMD_SYSTEM : SYSTEMD_USER,
-                              arg_scope == UNIT_FILE_USER,
-                              arg_root,
-                              NULL, NULL, NULL);
+        r = init_home_and_lookup_paths(&user_home, &user_runtime, &lp);
         if (r < 0)
-                return log_error_errno(r, "Failed get lookup paths: %m");
+                return r;
 
         avoid_bus_cache = !bus || avoid_bus();
 

commit 33f6c497f3f2da15b94da9140f77aefac92e2866
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Tue Dec 16 00:28:41 2014 -0500

    systemctl: move two functions up
    
    No functional change.

diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 20bc3bd..d16c673 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -2278,6 +2278,84 @@ static void warn_unit_file_changed(const char *name) {
                     arg_scope == UNIT_FILE_SYSTEM ? "" : " --user");
 }
 
+static int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **unit_path) {
+        char **p;
+
+        assert(lp);
+        assert(unit_name);
+        assert(unit_path);
+
+        STRV_FOREACH(p, lp->unit_path) {
+                char *path;
+
+                path = path_join(arg_root, *p, unit_name);
+                if (!path)
+                        return log_oom();
+
+                if (access(path, F_OK) == 0) {
+                        *unit_path = path;
+                        return 1;
+                }
+
+                free(path);
+        }
+
+        return 0;
+}
+
+static int unit_find_path(sd_bus *bus, const char *unit_name, const char *template, bool avoid_bus_cache, LookupPaths *lp, char **path) {
+        int r;
+
+        assert(unit_name);
+        assert(path);
+        assert(lp);
+
+        if (!avoid_bus_cache && !unit_name_is_template(unit_name)) {
+                _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+                _cleanup_free_ char *unit = NULL;
+                _cleanup_free_ char *tmp_path = NULL;
+
+                unit = unit_dbus_path_from_name(unit_name);
+                if (!unit)
+                        return log_oom();
+
+                if (need_daemon_reload(bus, unit_name) > 0) {
+                        warn_unit_file_changed(unit_name);
+                        return 0;
+                }
+
+                r = sd_bus_get_property_string(
+                                bus,
+                                "org.freedesktop.systemd1",
+                                unit,
+                                "org.freedesktop.systemd1.Unit",
+                                "FragmentPath",
+                                &error,
+                                &tmp_path);
+                if (r < 0) {
+                        log_warning("Failed to get FragmentPath: %s", bus_error_message(&error, r));
+                        return 0;
+                }
+
+                if (isempty(tmp_path)) {
+                        log_warning("%s ignored: not found", template);
+                        return 0;
+                }
+
+                *path = tmp_path;
+                tmp_path = NULL;
+
+                return 1;
+        } else {
+                r = unit_file_find_path(lp, template, path);
+                if (r == 0)
+                        log_warning("%s ignored: not found", template);
+                return r;
+        }
+
+        return 0;
+}
+
 typedef struct WaitData {
         Set *set;
 
@@ -5719,31 +5797,6 @@ static int is_system_running(sd_bus *bus, char **args) {
         return streq(state, "running") ? EXIT_SUCCESS : EXIT_FAILURE;
 }
 
-static int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **unit_path) {
-        char **p;
-
-        assert(lp);
-        assert(unit_name);
-        assert(unit_path);
-
-        STRV_FOREACH(p, lp->unit_path) {
-                char *path;
-
-                path = path_join(arg_root, *p, unit_name);
-                if (!path)
-                        return log_oom();
-
-                if (access(path, F_OK) == 0) {
-                        *unit_path = path;
-                        return 1;
-                }
-
-                free(path);
-        }
-
-        return 0;
-}
-
 static int create_edit_temp_file(const char *new_path, const char *original_path, char **ret_tmp_fn) {
         char *t;
         int r;
@@ -6041,59 +6094,6 @@ static int run_editor(char **paths) {
         return r;
 }
 
-static int unit_find_path(sd_bus *bus, const char *unit_name, const char *template, bool avoid_bus_cache, LookupPaths *lp, char **path) {
-        int r;
-
-        assert(unit_name);
-        assert(path);
-        assert(lp);
-
-        if (!avoid_bus_cache && !unit_name_is_template(unit_name)) {
-                _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-                _cleanup_free_ char *unit = NULL;
-                _cleanup_free_ char *tmp_path = NULL;
-
-                unit = unit_dbus_path_from_name(unit_name);
-                if (!unit)
-                        return log_oom();
-
-                if (need_daemon_reload(bus, unit_name) > 0) {
-                        warn_unit_file_changed(unit_name);
-                        return 0;
-                }
-
-                r = sd_bus_get_property_string(
-                                bus,
-                                "org.freedesktop.systemd1",
-                                unit,
-                                "org.freedesktop.systemd1.Unit",
-                                "FragmentPath",
-                                &error,
-                                &tmp_path);
-                if (r < 0) {
-                        log_warning("Failed to get FragmentPath: %s", bus_error_message(&error, r));
-                        return 0;
-                }
-
-                if (isempty(tmp_path)) {
-                        log_warning("%s ignored: not found", template);
-                        return 0;
-                }
-
-                *path = tmp_path;
-                tmp_path = NULL;
-
-                return 1;
-        } else {
-                r = unit_file_find_path(lp, template, path);
-                if (r == 0)
-                        log_warning("%s ignored: not found", template);
-                return r;
-        }
-
-        return 0;
-}
-
 static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
         _cleanup_free_ char *user_home = NULL;
         _cleanup_free_ char *user_runtime = NULL;

commit 3f36991e00634026db3c603a10dfcb3af2c5b7b2
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Mon Dec 15 23:28:38 2014 -0500

    systemctl: unify warning about unit files changed on disk

diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 324d9b6..20bc3bd 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -2270,6 +2270,14 @@ static int need_daemon_reload(sd_bus *bus, const char *unit) {
         return b;
 }
 
+static void warn_unit_file_changed(const char *name) {
+        log_warning("%sWarning:%s %s changed on disk. Run 'systemctl%s daemon-reload' to reload units.",
+                    ansi_highlight_red(),
+                    ansi_highlight_off(),
+                    name,
+                    arg_scope == UNIT_FILE_SYSTEM ? "" : " --user");
+}
+
 typedef struct WaitData {
         Set *set;
 
@@ -2676,8 +2684,7 @@ static int start_unit_one(
                 return bus_log_parse_error(r);
 
         if (need_daemon_reload(bus, name) > 0)
-                log_warning("Warning: Unit file of %s changed on disk, 'systemctl%s daemon-reload' recommended.",
-                            name, arg_scope == UNIT_FILE_SYSTEM ? "" : " --user");
+                warn_unit_file_changed(name);
 
         if (s) {
                 char *p;
@@ -3606,10 +3613,7 @@ static void print_status_info(
         }
 
         if (i->need_daemon_reload)
-                printf("\n%sWarning:%s Unit file changed on disk, 'systemctl %sdaemon-reload' recommended.\n",
-                       ansi_highlight_red(),
-                       ansi_highlight_off(),
-                       arg_scope == UNIT_FILE_SYSTEM ? "" : "--user ");
+                warn_unit_file_changed(i->id);
 }
 
 static void show_unit_help(UnitStatusInfo *i) {
@@ -4612,8 +4616,7 @@ static int cat(sd_bus *bus, char **args) {
                         return log_oom();
 
                 if (need_daemon_reload(bus, *name) > 0)
-                        log_warning("Unit file of %s changed on disk. Run 'systemctl%s daemon-reload'.",
-                                    *name, arg_scope == UNIT_FILE_SYSTEM ? "" : " --user");
+                        warn_unit_file_changed(*name);
 
                 r = sd_bus_get_property_string(
                                 bus,
@@ -6055,8 +6058,7 @@ static int unit_find_path(sd_bus *bus, const char *unit_name, const char *templa
                         return log_oom();
 
                 if (need_daemon_reload(bus, unit_name) > 0) {
-                        log_warning("%s ignored: unit file changed on disk. Run 'systemctl%s daemon-reload'.",
-                                    unit_name, arg_scope == UNIT_FILE_SYSTEM ? "" : " --user");
+                        warn_unit_file_changed(unit_name);
                         return 0;
                 }
 

commit 5b013a2f67a5914d6e86e3914f40cf44a03da091
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Sat Dec 13 12:43:07 2014 -0500

    systemctl: do not use -1 for return code
    
    Also make the error messages more specific to give a hint to the user
    how to solve the problem.

diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 8a1b481..324d9b6 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -6106,19 +6106,15 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
         if (arg_scope == UNIT_FILE_USER) {
                 r = user_config_home(&user_home);
                 if (r < 0)
-                        return log_oom();
-                else if (r == 0) {
-                        log_error("Cannot edit units for the user instance: home directory unknown");
-                        return -1;
-                }
+                        return log_error_errno(r, "Failed to query XDG_CONFIG_HOME: %m");
+                else if (r == 0)
+                        return log_error_errno(ENOTDIR, "Cannot edit units: $XDG_CONFIG_HOME and $HOME are not set.");
 
                 r = user_runtime_dir(&user_runtime);
                 if (r < 0)
-                        return log_oom();
-                else if (r == 0) {
-                        log_error("Cannot edit units for the user instance: runtime directory unknown");
-                        return -1;
-                }
+                        return log_error_errno(r, "Failed to query XDG_CONFIG_HOME: %m");
+                else if (r == 0)
+                        return log_error_errno(ENOTDIR, "Cannot edit units: $XDG_RUNTIME_DIR is not set.");
         }
 
         r = lookup_paths_init(&lp,
@@ -6126,10 +6122,8 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
                               arg_scope == UNIT_FILE_USER,
                               arg_root,
                               NULL, NULL, NULL);
-        if (r < 0) {
-                log_error_errno(r, "Failed get lookup paths: %m");
-                return r;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Failed get lookup paths: %m");
 
         avoid_bus_cache = !bus || avoid_bus();
 

commit 1a7f1b385cd9de8a0da934fadc379860f914ef33
Author: Zbigniew Jędrzejewski-Szmek <zbyszek at in.waw.pl>
Date:   Sun Dec 14 23:12:40 2014 -0500

    Move dropin listing to shared
    
    No functional change. This is in preparation for using this in
    systemctl in the future.

diff --git a/src/core/load-dropin.c b/src/core/load-dropin.c
index 8afaf45..8be1900 100644
--- a/src/core/load-dropin.c
+++ b/src/core/load-dropin.c
@@ -31,137 +31,27 @@
 #include "load-fragment.h"
 #include "conf-files.h"
 
-static int iterate_dir(
-                Unit *u,
-                const char *path,
+static int add_dependency_consumer(
                 UnitDependency dependency,
-                char ***strv) {
-
-        _cleanup_closedir_ DIR *d = NULL;
+                const char *entry,
+                const char* filepath,
+                void *arg) {
+        Unit *u = arg;
         int r;
 
         assert(u);
-        assert(path);
-
-        /* The config directories are special, since the order of the
-         * drop-ins matters */
-        if (dependency < 0)  {
-                r = strv_extend(strv, path);
-                if (r < 0)
-                        return log_oom();
-
-                return 0;
-        }
-
-        d = opendir(path);
-        if (!d) {
-                if (errno == ENOENT)
-                        return 0;
-
-                log_error_errno(errno, "Failed to open directory %s: %m", path);
-                return -errno;
-        }
-
-        for (;;) {
-                struct dirent *de;
-                _cleanup_free_ char *f = NULL;
-
-                errno = 0;
-                de = readdir(d);
-                if (!de && errno != 0)
-                        return log_error_errno(errno, "Failed to read directory %s: %m", path);
-
-                if (!de)
-                        break;
-
-                if (ignore_file(de->d_name))
-                        continue;
 
-                f = strjoin(path, "/", de->d_name, NULL);
-                if (!f)
-                        return log_oom();
-
-                r = unit_add_dependency_by_name(u, dependency, de->d_name, f, true);
-                if (r < 0)
-                        log_error_errno(r, "Cannot add dependency %s to %s, ignoring: %m", de->d_name, u->id);
-        }
+        r = unit_add_dependency_by_name(u, dependency, entry, filepath, true);
+        if (r < 0)
+                log_error_errno(r, "Cannot add dependency %s to %s, ignoring: %m", entry, u->id);
 
         return 0;
 }
 
-static int process_dir(
-                Unit *u,
-                const char *unit_path,
-                const char *name,
-                const char *suffix,
-                UnitDependency dependency,
-                char ***strv) {
-
-        _cleanup_free_ char *path = NULL;
-
-        assert(u);
-        assert(unit_path);
-        assert(name);
-        assert(suffix);
-
-        path = strjoin(unit_path, "/", name, suffix, NULL);
-        if (!path)
-                return log_oom();
-
-        if (!u->manager->unit_path_cache || set_get(u->manager->unit_path_cache, path))
-                iterate_dir(u, path, dependency, strv);
-
-        if (u->instance) {
-                _cleanup_free_ char *template = NULL, *p = NULL;
-                /* Also try the template dir */
-
-                template = unit_name_template(name);
-                if (!template)
-                        return log_oom();
-
-                p = strjoin(unit_path, "/", template, suffix, NULL);
-                if (!p)
-                        return log_oom();
-
-                if (!u->manager->unit_path_cache || set_get(u->manager->unit_path_cache, p))
-                        iterate_dir(u, p, dependency, strv);
-        }
-
-        return 0;
-}
-
-char **unit_find_dropin_paths(Unit *u) {
-        _cleanup_strv_free_ char **strv = NULL;
-        char **configs = NULL;
-        Iterator i;
-        char *t;
-        int r;
-
-        assert(u);
-
-        SET_FOREACH(t, u->names, i) {
-                char **p;
-
-                STRV_FOREACH(p, u->manager->lookup_paths.unit_path)
-                        process_dir(u, *p, t, ".d", _UNIT_DEPENDENCY_INVALID, &strv);
-        }
-
-        if (strv_isempty(strv))
-                return NULL;
-
-        r = conf_files_list_strv(&configs, ".conf", NULL, (const char**) strv);
-        if (r < 0) {
-                log_error_errno(r, "Failed to get list of configuration files: %m");
-                strv_free(configs);
-                return NULL;
-        }
-
-        return configs;
-}
-
 int unit_load_dropin(Unit *u) {
         Iterator i;
         char *t, **f;
+        int r;
 
         assert(u);
 
@@ -171,13 +61,15 @@ int unit_load_dropin(Unit *u) {
                 char **p;
 
                 STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
-                        process_dir(u, *p, t, ".wants", UNIT_WANTS, NULL);
-                        process_dir(u, *p, t, ".requires", UNIT_REQUIRES, NULL);
+                        unit_file_process_dir(u->manager->unit_path_cache, *p, t, ".wants", UNIT_WANTS,
+                                              add_dependency_consumer, u, NULL);
+                        unit_file_process_dir(u->manager->unit_path_cache, *p, t, ".requires", UNIT_REQUIRES,
+                                              add_dependency_consumer, u, NULL);
                 }
         }
 
-        u->dropin_paths = unit_find_dropin_paths(u);
-        if (!u->dropin_paths)
+        r = unit_find_dropin_paths(u, &u->dropin_paths);
+        if (r <= 0)
                 return 0;
 
         STRV_FOREACH(f, u->dropin_paths) {
diff --git a/src/core/load-dropin.h b/src/core/load-dropin.h
index fd55117..1e018c4 100644
--- a/src/core/load-dropin.h
+++ b/src/core/load-dropin.h
@@ -22,8 +22,15 @@
 ***/
 
 #include "unit.h"
+#include "dropin.h"
 
 /* Read service data supplementary drop-in directories */
 
-char **unit_find_dropin_paths(Unit *u);
+static inline int unit_find_dropin_paths(Unit *u, char ***paths) {
+        return unit_file_find_dropin_paths(u->manager->lookup_paths.unit_path,
+                                           u->manager->unit_path_cache,
+                                           u->names,
+                                           paths);
+}
+
 int unit_load_dropin(Unit *u);
diff --git a/src/core/unit.c b/src/core/unit.c
index 8cec0e7..a2f3728 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -2894,7 +2894,7 @@ bool unit_need_daemon_reload(Unit *u) {
                         return true;
         }
 
-        t = unit_find_dropin_paths(u);
+        (void) unit_find_dropin_paths(u, &t);
         loaded_cnt = strv_length(t);
         current_cnt = strv_length(u->dropin_paths);
 
diff --git a/src/shared/dropin.c b/src/shared/dropin.c
index c5c4f95..40e6fee 100644
--- a/src/shared/dropin.c
+++ b/src/shared/dropin.c
@@ -21,8 +21,10 @@
 
 #include "dropin.h"
 #include "util.h"
+#include "strv.h"
 #include "mkdir.h"
 #include "fileio-label.h"
+#include "conf-files.h"
 
 int drop_in_file(const char *dir, const char *unit, unsigned level,
                  const char *name, char **_p, char **_q) {
@@ -100,3 +102,137 @@ int write_drop_in_format(const char *dir, const char *unit, unsigned level,
 
         return write_drop_in(dir, unit, level, name, p);
 }
+
+static int iterate_dir(
+                const char *path,
+                UnitDependency dependency,
+                dependency_consumer_t consumer,
+                void *arg,
+                char ***strv) {
+
+        _cleanup_closedir_ DIR *d = NULL;
+        int r;
+
+        assert(path);
+
+        /* The config directories are special, since the order of the
+         * drop-ins matters */
+        if (dependency < 0)  {
+                r = strv_extend(strv, path);
+                if (r < 0)
+                        return log_oom();
+
+                return 0;
+        }
+
+        assert(consumer);
+
+        d = opendir(path);
+        if (!d) {
+                if (errno == ENOENT)
+                        return 0;
+
+                log_error_errno(errno, "Failed to open directory %s: %m", path);
+                return -errno;
+        }
+
+        for (;;) {
+                struct dirent *de;
+                _cleanup_free_ char *f = NULL;
+
+                errno = 0;
+                de = readdir(d);
+                if (!de && errno != 0)
+                        return log_error_errno(errno, "Failed to read directory %s: %m", path);
+
+                if (!de)
+                        break;
+
+                if (ignore_file(de->d_name))
+                        continue;
+
+                f = strjoin(path, "/", de->d_name, NULL);
+                if (!f)
+                        return log_oom();
+
+                r = consumer(dependency, de->d_name, f, arg);
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
+int unit_file_process_dir(
+                Set * unit_path_cache,
+                const char *unit_path,
+                const char *name,
+                const char *suffix,
+                UnitDependency dependency,
+                dependency_consumer_t consumer,
+                void *arg,
+                char ***strv) {
+
+        _cleanup_free_ char *path = NULL;
+
+        assert(unit_path);
+        assert(name);
+        assert(suffix);
+
+        path = strjoin(unit_path, "/", name, suffix, NULL);
+        if (!path)
+                return log_oom();
+
+        if (!unit_path_cache || set_get(unit_path_cache, path))
+                iterate_dir(path, dependency, consumer, arg, strv);
+
+        if (unit_name_is_instance(name)) {
+                _cleanup_free_ char *template = NULL, *p = NULL;
+                /* Also try the template dir */
+
+                template = unit_name_template(name);
+                if (!template)
+                        return log_oom();
+
+                p = strjoin(unit_path, "/", template, suffix, NULL);
+                if (!p)
+                        return log_oom();
+
+                if (!unit_path_cache || set_get(unit_path_cache, p))
+                        iterate_dir(p, dependency, consumer, arg, strv);
+        }
+
+        return 0;
+}
+
+int unit_file_find_dropin_paths(
+                char **lookup_path,
+                Set *unit_path_cache,
+                Set *names,
+                char ***paths) {
+
+        _cleanup_strv_free_ char **strv = NULL, **ans = NULL;
+        Iterator i;
+        char *t;
+        int r;
+
+        assert(paths);
+
+        SET_FOREACH(t, names, i) {
+                char **p;
+
+                STRV_FOREACH(p, lookup_path)
+                        unit_file_process_dir(unit_path_cache, *p, t, ".d", _UNIT_DEPENDENCY_INVALID, NULL, NULL, &strv);
+        }
+
+        if (strv_isempty(strv))
+                return 0;
+
+        r = conf_files_list_strv(&ans, ".conf", NULL, (const char**) strv);
+        if (r < 0)
+                return log_warning_errno(r, "Failed to get list of configuration files: %m");
+
+        *paths = ans;
+        ans = NULL;
+        return 1;
+}
diff --git a/src/shared/dropin.h b/src/shared/dropin.h
index 9c9742d..d4531fc 100644
--- a/src/shared/dropin.h
+++ b/src/shared/dropin.h
@@ -22,6 +22,8 @@
 ***/
 
 #include "macro.h"
+#include "set.h"
+#include "unit-name.h"
 
 int drop_in_file(const char *dir, const char *unit, unsigned level,
                  const char *name, char **_p, char **_q);
@@ -31,3 +33,30 @@ int write_drop_in(const char *dir, const char *unit, unsigned level,
 
 int write_drop_in_format(const char *dir, const char *unit, unsigned level,
                          const char *name, const char *format, ...) _printf_(5, 6);
+
+/**
+ * This callback will be called for each directory entry @entry,
+ * with @filepath being the full path to the entry.
+ *
+ * If return value is negative, loop will be aborted.
+ */
+typedef int (*dependency_consumer_t)(UnitDependency dependency,
+                                     const char *entry,
+                                     const char* filepath,
+                                     void *arg);
+
+int unit_file_process_dir(
+                Set * unit_path_cache,
+                const char *unit_path,
+                const char *name,
+                const char *suffix,
+                UnitDependency dependency,
+                dependency_consumer_t consumer,
+                void *arg,
+                char ***strv);
+
+int unit_file_find_dropin_paths(
+                char **lookup_path,
+                Set *unit_path_cache,
+                Set *names,
+                char ***paths);



More information about the systemd-commits mailing list