X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fcore%2Fpath.c;h=ff49c069eebc96084d9b53b35c8aa12aa007e9f3;hb=ee531d949c2f62374fc109252f8cbe61c2b8ee39;hp=65913f87591cb41848c08381313fb6ec905f00a5;hpb=a163db44190dea7c34112f28f32cdff664d79b06;p=elogind.git diff --git a/src/core/path.c b/src/core/path.c index 65913f875..ff49c069e 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -53,8 +53,7 @@ int path_spec_watch(PathSpec *s, Unit *u) { }; bool exists = false; - char _cleanup_free_ *k = NULL; - char *slash; + char *slash, *oldslash = NULL; int r; assert(u); @@ -62,10 +61,6 @@ int path_spec_watch(PathSpec *s, Unit *u) { path_spec_unwatch(s, u); - k = strdup(s->path); - if (!k) - return -ENOMEM; - s->inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC); if (s->inotify_fd < 0) { r = -errno; @@ -76,28 +71,71 @@ int path_spec_watch(PathSpec *s, Unit *u) { 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; @@ -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; } @@ -320,15 +361,20 @@ 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) - return r; + r = unit_add_dependency_by_name(UNIT(p), UNIT_BEFORE, + SPECIAL_PATHS_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) + if (UNIT(p)->manager->running_as == SYSTEMD_SYSTEM) { + 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