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=dcb3b1ff60a7a3d7e4f4aa9af3f62bdfd16cefd0;hb=180d6802e585e8a2826b76872438641b73e3fa6f;hpb=e0207c8d91514350c6a1bf0dda9337823004c371 diff --git a/src/core/path.c b/src/core/path.c index dcb3b1ff6..295e5cdf0 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;