diff --git a/TODO b/TODO index 6d905dc68c4..c1008ab525d 100644 --- a/TODO +++ b/TODO @@ -68,8 +68,6 @@ * ask-password tty timeout -* properly handle multiple inotify events per read() in path.c and util.c - * readahead: btrfs/LVM SSD detection * document locale.conf, vconsole.conf and possibly the tempfiles.d and modules-load.d mechanism. diff --git a/src/path.c b/src/path.c index 92f99381e85..b3bc8a5a0d7 100644 --- a/src/path.c +++ b/src/path.c @@ -453,7 +453,8 @@ static void path_fd_event(Unit *u, int fd, uint32_t events, Watch *w) { Path *p = PATH(u); int l; ssize_t k; - struct inotify_event *buf = NULL; + uint8_t *buf = NULL; + struct inotify_event *e; PathSpec *s; assert(p); @@ -493,16 +494,22 @@ static void path_fd_event(Unit *u, int fd, uint32_t events, Watch *w) { goto fail; } - if ((size_t) k < sizeof(struct inotify_event) || - (size_t) k < sizeof(struct inotify_event) + buf->len) { - log_error("inotify event too small."); - goto fail; - } + e = (struct inotify_event*) buf; - if (s->type == PATH_CHANGED && s->primary_wd == buf->wd) - path_enter_running(p); - else - path_enter_waiting(p, false); + while (k > 0) { + size_t step; + + if (s->type == PATH_CHANGED && s->primary_wd == e->wd) + path_enter_running(p); + else + path_enter_waiting(p, false); + + step = sizeof(struct inotify_event) + e->len; + assert(step <= (size_t) k); + + e = (struct inotify_event*) ((uint8_t*) e + step); + k -= step; + } free(buf); diff --git a/src/util.c b/src/util.c index d09e4477767..434f311e71f 100644 --- a/src/util.c +++ b/src/util.c @@ -2247,26 +2247,34 @@ int acquire_terminal(const char *name, bool fail, bool force, bool ignore_tiocst assert(notify >= 0); for (;;) { - struct inotify_event e; + uint8_t inotify_buffer[sizeof(struct inotify_event) + FILENAME_MAX]; ssize_t l; + struct inotify_event *e; - if ((l = read(notify, &e, sizeof(e))) != sizeof(e)) { + if ((l = read(notify, &inotify_buffer, sizeof(inotify_buffer))) < 0) { - if (l < 0) { - - if (errno == EINTR) - continue; - - r = -errno; - } else - r = -EIO; + if (errno == EINTR) + continue; + r = -errno; goto fail; } - if (e.wd != wd || !(e.mask & IN_CLOSE)) { - r = -EIO; - goto fail; + e = (struct inotify_event*) inotify_buffer; + + while (l > 0) { + size_t step; + + if (e->wd != wd || !(e->mask & IN_CLOSE)) { + r = -EIO; + goto fail; + } + + step = sizeof(struct inotify_event) + e->len; + assert(step <= (size_t) l); + + e = (struct inotify_event*) ((uint8_t*) e + step); + l -= step; } break;