X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fcore%2Fpath.c;h=295e5cdf0e83096e73898a5051eaab783b5c290b;hp=767620ba754bb2f42184c0acd42fe0a4e083cbf8;hb=fea7838e7e0b2724f5e0bc028121a08b42995045;hpb=f274ece0f76b5709408821e317e87aef76123db6 diff --git a/src/core/path.c b/src/core/path.c index 767620ba7..295e5cdf0 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -33,6 +33,7 @@ #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, @@ -52,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); @@ -60,47 +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; - } - s->primary_wd = inotify_add_watch(s->inotify_fd, k, flags_table[s->type]); - if (s->primary_wd >= 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()! */ - slash = strrchr(k, '/'); - if (!slash) - 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'; - /* Trim the path at the last slash. Keep the slash if it's the root dir. */ - slash[slash == k] = 0; + inotify_add_watch(s->inotify_fd, s->path, IN_MOVE_SELF); + /* Error is ignored, the worst can happen is + we get spurious events. */ - flags = IN_MOVE_SELF; - if (!exists) - flags |= IN_DELETE_SELF | IN_ATTRIB | IN_CREATE | IN_MOVED_TO; + *cut2 = tmp2; + } + } - if (inotify_add_watch(s->inotify_fd, k, flags) >= 0) - exists = true; - } while (slash != k); + if (cut) + *cut = tmp; + + 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; } @@ -117,7 +156,7 @@ 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; @@ -125,30 +164,24 @@ int path_spec_fd_event(PathSpec *s, uint32_t events) { if (events != EPOLLIN) { log_error("Got invalid poll event on inotify."); - r = -EINVAL; - goto out; + return -EINVAL; } if (ioctl(s->inotify_fd, FIONREAD, &l) < 0) { log_error("FIONREAD failed: %m"); - r = -errno; - goto out; + return -errno; } assert(l > 0); buf = malloc(l); - if (!buf) { - log_error("Failed to allocate buffer: %m"); - r = -errno; - goto out; - } + if (!buf) + return log_oom(); 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; @@ -166,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; } @@ -248,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; @@ -276,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; } @@ -293,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; } @@ -321,14 +362,19 @@ static int path_add_default_dependencies(Path *p) { assert(p); if (UNIT(p)->manager->running_as == SYSTEMD_SYSTEM) { - if ((r = unit_add_dependency_by_name(UNIT(p), UNIT_BEFORE, SPECIAL_BASIC_TARGET, NULL, true)) < 0) + 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) { @@ -338,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) { @@ -353,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); @@ -406,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; } @@ -473,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); @@ -517,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 @@ -535,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); } @@ -602,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; @@ -696,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