chiark / gitweb /
core/smack: downgrade info to debug
[elogind.git] / src / core / path.c
index 0f23f1494d1a859dec6a47536b216128c4c06de6..295e5cdf0e83096e73898a5051eaab783b5c290b 100644 (file)
@@ -32,6 +32,8 @@
 #include "dbus-path.h"
 #include "special.h"
 #include "bus-errors.h"
+#include "path-util.h"
+#include "macro.h"
 
 static const UnitActiveState state_translation_table[_PATH_STATE_MAX] = {
         [PATH_DEAD] = UNIT_INACTIVE,
@@ -51,7 +53,7 @@ int path_spec_watch(PathSpec *s, Unit *u) {
         };
 
         bool exists = false;
-        char *k, *slash;
+        char *slash, *oldslash = NULL;
         int r;
 
         assert(u);
@@ -59,45 +61,85 @@ int path_spec_watch(PathSpec *s, Unit *u) {
 
         path_spec_unwatch(s, u);
 
-        if (!(k = strdup(s->path)))
-                return -ENOMEM;
-
-        if ((s->inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC)) < 0) {
+        s->inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
+        if (s->inotify_fd < 0) {
                 r = -errno;
                 goto fail;
         }
 
-        if (unit_watch_fd(u, s->inotify_fd, EPOLLIN, &s->watch) < 0) {
-                r = -errno;
+        r = unit_watch_fd(u, s->inotify_fd, EPOLLIN, &s->watch);
+        if (r < 0)
                 goto fail;
-        }
 
-        if ((s->primary_wd = inotify_add_watch(s->inotify_fd, k, flags_table[s->type])) >= 0)
-                exists = true;
+        /* This assumes the path was passed through path_kill_slashes()! */
 
-        do {
+        for (slash = strchr(s->path, '/'); ; slash = strchr(slash+1, '/')) {
+                char *cut = NULL;
                 int flags;
+                char tmp;
+
+                if (slash) {
+                        cut = slash + (slash == s->path);
+                        tmp = *cut;
+                        *cut = '\0';
+
+                        flags = IN_MOVE_SELF | IN_DELETE_SELF | IN_ATTRIB | IN_CREATE | IN_MOVED_TO;
+                } else
+                        flags = flags_table[s->type];
+
+                r = inotify_add_watch(s->inotify_fd, s->path, flags);
+                if (r < 0) {
+                        if (errno == EACCES || errno == ENOENT) {
+                                if (cut)
+                                        *cut = tmp;
+                                break;
+                        }
+
+                        log_warning("Failed to add watch on %s: %m", s->path);
+                        r = -errno;
+                        if (cut)
+                                *cut = tmp;
+                        goto fail;
+                } else {
+                        exists = true;
 
-                /* This assumes the path was passed through path_kill_slashes()! */
-                if (!(slash = strrchr(k, '/')))
-                        break;
+                        /* Path exists, we don't need to watch parent
+                           too closely. */
+                        if (oldslash) {
+                                char *cut2 = oldslash + (oldslash == s->path);
+                                char tmp2 = *cut2;
+                                *cut2 = '\0';
+
+                                inotify_add_watch(s->inotify_fd, s->path, IN_MOVE_SELF);
+                                /* Error is ignored, the worst can happen is
+                                   we get spurious events. */
 
-                /* Trim the path at the last slash. Keep the slash if it's the root dir. */
-                slash[slash == k] = 0;
+                                *cut2 = tmp2;
+                        }
+                }
 
-                flags = IN_MOVE_SELF;
-                if (!exists)
-                        flags |= IN_DELETE_SELF | IN_ATTRIB | IN_CREATE | IN_MOVED_TO;
+                if (cut)
+                        *cut = tmp;
 
-                if (inotify_add_watch(s->inotify_fd, k, flags) >= 0)
-                        exists = true;
-        } while (slash != k);
+                if (slash)
+                        oldslash = slash;
+                else {
+                        /* whole path has been iterated over */
+                        s->primary_wd = r;
+                        break;
+                }
+        }
+
+        if (!exists) {
+                log_error("Failed to add watch on any of the components of %s: %m",
+                          s->path);
+                r = -errno; /* either EACCESS or ENOENT */
+                goto fail;
+        }
 
         return 0;
 
 fail:
-        free(k);
-
         path_spec_unwatch(s, u);
         return r;
 }
@@ -114,36 +156,32 @@ void path_spec_unwatch(PathSpec *s, Unit *u) {
 }
 
 int path_spec_fd_event(PathSpec *s, uint32_t events) {
-        uint8_t *buf = NULL;
+        uint8_t _cleanup_free_ *buf = NULL;
         struct inotify_event *e;
         ssize_t k;
         int l;
         int r = 0;
 
         if (events != EPOLLIN) {
-                log_error("Got Invalid poll event on inotify.");
-                r = -EINVAL;
-                goto out;
+                log_error("Got invalid poll event on inotify.");
+                return -EINVAL;
         }
 
         if (ioctl(s->inotify_fd, FIONREAD, &l) < 0) {
                 log_error("FIONREAD failed: %m");
-                r = -errno;
-                goto out;
+                return -errno;
         }
 
         assert(l > 0);
 
-        if (!(buf = malloc(l))) {
-                log_error("Failed to allocate buffer: %m");
-                r = -errno;
-                goto out;
-        }
+        buf = malloc(l);
+        if (!buf)
+                return log_oom();
 
-        if ((k = read(s->inotify_fd, buf, l)) < 0) {
+        k = read(s->inotify_fd, buf, l);
+        if (k < 0) {
                 log_error("Failed to read inotify event: %m");
-                r = -errno;
-                goto out;
+                return -errno;
         }
 
         e = (struct inotify_event*) buf;
@@ -161,8 +199,7 @@ int path_spec_fd_event(PathSpec *s, uint32_t events) {
                 e = (struct inotify_event*) ((uint8_t*) e + step);
                 k -= step;
         }
-out:
-        free(buf);
+
         return r;
 }
 
@@ -214,7 +251,8 @@ static void path_spec_mkdir(PathSpec *s, mode_t mode) {
         if (s->type == PATH_EXISTS || s->type == PATH_EXISTS_GLOB)
                 return;
 
-        if ((r = mkdir_p(s->path, mode)) < 0)
+        r = mkdir_p_label(s->path, mode);
+        if (r < 0)
                 log_warning("mkdir(%s) failed: %s", s->path, strerror(-r));
 }
 
@@ -242,22 +280,28 @@ static void path_init(Unit *u) {
         p->directory_mode = 0755;
 }
 
-static void path_done(Unit *u) {
-        Path *p = PATH(u);
+void path_free_specs(Path *p) {
         PathSpec *s;
 
         assert(p);
 
-        unit_ref_unset(&p->unit);
-
         while ((s = p->specs)) {
-                path_spec_unwatch(s, u);
+                path_spec_unwatch(s, UNIT(p));
                 LIST_REMOVE(PathSpec, spec, p->specs, s);
                 path_spec_done(s);
                 free(s);
         }
 }
 
+static void path_done(Unit *u) {
+        Path *p = PATH(u);
+
+        assert(p);
+
+        unit_ref_unset(&p->unit);
+        path_free_specs(p);
+}
+
 int path_add_one_mount_link(Path *p, Mount *m) {
         PathSpec *s;
         int r;
@@ -270,11 +314,12 @@ int path_add_one_mount_link(Path *p, Mount *m) {
                 return 0;
 
         LIST_FOREACH(spec, s, p->specs) {
-
                 if (!path_spec_startswith(s, m->where))
                         continue;
 
-                if ((r = unit_add_two_dependencies(UNIT(p), UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true)) < 0)
+                r = unit_add_two_dependencies(UNIT(p), UNIT_AFTER, UNIT_REQUIRES,
+                                              UNIT(m), true);
+                if (r < 0)
                         return r;
         }
 
@@ -287,9 +332,11 @@ static int path_add_mount_links(Path *p) {
 
         assert(p);
 
-        LIST_FOREACH(units_by_type, other, UNIT(p)->manager->units_by_type[UNIT_MOUNT])
-                if ((r = path_add_one_mount_link(p, MOUNT(other))) < 0)
+        LIST_FOREACH(units_by_type, other, UNIT(p)->manager->units_by_type[UNIT_MOUNT]) {
+                r = path_add_one_mount_link(p, MOUNT(other));
+                if (r < 0)
                         return r;
+        }
 
         return 0;
 }
@@ -301,7 +348,8 @@ static int path_verify(Path *p) {
                 return 0;
 
         if (!p->specs) {
-                log_error("%s lacks path setting. Refusing.", UNIT(p)->id);
+                log_error_unit(UNIT(p)->id,
+                               "%s lacks path setting. Refusing.", UNIT(p)->id);
                 return -EINVAL;
         }
 
@@ -313,15 +361,20 @@ static int path_add_default_dependencies(Path *p) {
 
         assert(p);
 
-        if (UNIT(p)->manager->running_as == MANAGER_SYSTEM) {
-                if ((r = unit_add_dependency_by_name(UNIT(p), UNIT_BEFORE, SPECIAL_BASIC_TARGET, NULL, true)) < 0)
+        if (UNIT(p)->manager->running_as == SYSTEMD_SYSTEM) {
+                r = unit_add_dependency_by_name(UNIT(p), UNIT_BEFORE,
+                                                SPECIAL_BASIC_TARGET, NULL, true);
+                if (r < 0)
                         return r;
 
-                if ((r = unit_add_two_dependencies_by_name(UNIT(p), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true)) < 0)
+                r = unit_add_two_dependencies_by_name(UNIT(p), UNIT_AFTER, UNIT_REQUIRES,
+                                                      SPECIAL_SYSINIT_TARGET, NULL, true);
+                if (r < 0)
                         return r;
         }
 
-        return unit_add_two_dependencies_by_name(UNIT(p), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
+        return unit_add_two_dependencies_by_name(UNIT(p), UNIT_BEFORE, UNIT_CONFLICTS,
+                                                 SPECIAL_SHUTDOWN_TARGET, NULL, true);
 }
 
 static int path_load(Unit *u) {
@@ -331,7 +384,8 @@ static int path_load(Unit *u) {
         assert(u);
         assert(u->load_state == UNIT_STUB);
 
-        if ((r = unit_load_fragment_and_dropin(u)) < 0)
+        r = unit_load_fragment_and_dropin(u);
+        if (r < 0)
                 return r;
 
         if (u->load_state == UNIT_LOADED) {
@@ -346,16 +400,20 @@ static int path_load(Unit *u) {
                         unit_ref_set(&p->unit, x);
                 }
 
-                r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(p->unit), true);
+                r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS,
+                                              UNIT_DEREF(p->unit), true);
                 if (r < 0)
                         return r;
 
-                if ((r = path_add_mount_links(p)) < 0)
+                r = path_add_mount_links(p);
+                if (r < 0)
                         return r;
 
-                if (UNIT(p)->default_dependencies)
-                        if ((r = path_add_default_dependencies(p)) < 0)
+                if (UNIT(p)->default_dependencies) {
+                        r = path_add_default_dependencies(p);
+                        if (r < 0)
                                 return r;
+                }
         }
 
         return path_verify(p);
@@ -399,9 +457,11 @@ static int path_watch(Path *p) {
 
         assert(p);
 
-        LIST_FOREACH(spec, s, p->specs)
-                if ((r = path_spec_watch(s, UNIT(p))) < 0)
+        LIST_FOREACH(spec, s, p->specs) {
+                r = path_spec_watch(s, UNIT(p));
+                if (r < 0)
                         return r;
+        }
 
         return 0;
 }
@@ -466,19 +526,23 @@ static void path_enter_running(Path *p) {
         if (UNIT(p)->job && UNIT(p)->job->type == JOB_STOP)
                 return;
 
-        if ((r = manager_add_job(UNIT(p)->manager, JOB_START, UNIT_DEREF(p->unit), JOB_REPLACE, true, &error, NULL)) < 0)
+        r = manager_add_job(UNIT(p)->manager, JOB_START, UNIT_DEREF(p->unit),
+                            JOB_REPLACE, true, &error, NULL);
+        if (r < 0)
                 goto fail;
 
         p->inotify_triggered = false;
 
-        if ((r = path_watch(p)) < 0)
+        r = path_watch(p);
+        if (r < 0)
                 goto fail;
 
         path_set_state(p, PATH_RUNNING);
         return;
 
 fail:
-        log_warning("%s failed to queue unit startup job: %s", UNIT(p)->id, bus_error(&error, r));
+        log_warning("%s failed to queue unit startup job: %s",
+                    UNIT(p)->id, bus_error(&error, r));
         path_enter_dead(p, PATH_FAILURE_RESOURCES);
 
         dbus_error_free(&error);
@@ -510,7 +574,8 @@ static void path_enter_waiting(Path *p, bool initial, bool recheck) {
                         return;
                 }
 
-        if ((r = path_watch(p)) < 0)
+        r = path_watch(p);
+        if (r < 0)
                 goto fail;
 
         /* Hmm, so now we have created inotify watches, but the file
@@ -528,7 +593,8 @@ static void path_enter_waiting(Path *p, bool initial, bool recheck) {
         return;
 
 fail:
-        log_warning("%s failed to enter waiting state: %s", UNIT(p)->id, strerror(-r));
+        log_warning("%s failed to enter waiting state: %s",
+                    UNIT(p)->id, strerror(-r));
         path_enter_dead(p, PATH_FAILURE_RESOURCES);
 }
 
@@ -595,7 +661,8 @@ static int path_deserialize_item(Unit *u, const char *key, const char *value, FD
         if (streq(key, "state")) {
                 PathState state;
 
-                if ((state = path_state_from_string(value)) < 0)
+                state = path_state_from_string(value);
+                if (state < 0)
                         log_debug("Failed to parse state value %s", value);
                 else
                         p->deserialized_state = state;
@@ -689,7 +756,8 @@ void path_unit_notify(Unit *u, UnitActiveState new_state) {
                 p = PATH(k);
 
                 if (p->state == PATH_RUNNING && new_state == UNIT_INACTIVE) {
-                        log_debug("%s got notified about unit deactivation.", UNIT(p)->id);
+                        log_debug("%s got notified about unit deactivation.",
+                                  UNIT(p)->id);
 
                         /* Hmm, so inotify was triggered since the
                          * last activation, so I guess we need to
@@ -737,7 +805,6 @@ static const char* const path_result_table[_PATH_RESULT_MAX] = {
 DEFINE_STRING_TABLE_LOOKUP(path_result, PathResult);
 
 const UnitVTable path_vtable = {
-        .suffix = ".path",
         .object_size = sizeof(Path),
         .sections =
                 "Unit\0"