aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/notify.c87
-rw-r--r--lib/portability.c94
-rw-r--r--lib/portability.h12
-rw-r--r--toys/posix/tail.c7
4 files changed, 107 insertions, 93 deletions
diff --git a/lib/notify.c b/lib/notify.c
deleted file mode 100644
index a7993e2a..00000000
--- a/lib/notify.c
+++ /dev/null
@@ -1,87 +0,0 @@
-#include "toys.h"
-
-static char **paths;
-static int *fds;
-static int count;
-
-#ifdef __APPLE__
-
-#include <sys/event.h>
-
-static int kq = -1;
-
-void notify_init(int max)
-{
- if ((kq = kqueue()) == -1) perror_exit("kqueue");
- paths = xmalloc(max * sizeof(char *));
- fds = xmalloc(max * sizeof(int));
-}
-
-int notify_add(int fd, char *path)
-{
- struct kevent event;
-
- EV_SET(&event, fd, EVFILT_VNODE, EV_ADD|EV_CLEAR, NOTE_WRITE, 0, NULL);
- if (kevent(kq, &event, 1, NULL, 0, NULL) == -1 || event.flags & EV_ERROR)
- return -1;
- paths[count] = path;
- fds[count++] = fd;
- return 0;
-}
-
-int notify_wait(char **path)
-{
- struct kevent event;
- int i;
-
- for (;;) {
- if (kevent(kq, NULL, 0, &event, 1, NULL) != -1) {
- // We get the fd for free, but still have to search for the path.
- for (i=0; i<count; i++) if (fds[i]==event.ident) {
- *path = paths[i];
- return event.ident;
- }
- }
- }
-}
-
-#else
-
-#include <sys/inotify.h>
-
-static int ffd = -1;
-static int *ids;
-
-void notify_init(int max)
-{
- if ((ffd = inotify_init()) < 0) perror_exit("inotify_init");
- fds = xmalloc(max * sizeof(int));
- ids = xmalloc(max * sizeof(int));
- paths = xmalloc(max * sizeof(char *));
-}
-
-int notify_add(int fd, char *path)
-{
- ids[count] = inotify_add_watch(ffd, path, IN_MODIFY);
- if (ids[count] == -1) return -1;
- paths[count] = path;
- fds[count++] = fd;
- return 0;
-}
-
-int notify_wait(char **path)
-{
- struct inotify_event ev;
- int i;
-
- for (;;) {
- if (sizeof(ev)!=read(ffd, &ev, sizeof(ev))) perror_exit("inotify");
-
- for (i=0; i<count; i++) if (ev.wd==ids[i]) {
- *path = paths[i];
- return fds[i];
- }
- }
-}
-
-#endif
diff --git a/lib/portability.c b/lib/portability.c
index c75e8ba5..726e42a9 100644
--- a/lib/portability.c
+++ b/lib/portability.c
@@ -153,3 +153,97 @@ struct mtab_list *xgetmountlist(char *path)
}
#endif
+
+#ifdef __APPLE__
+
+#include <sys/event.h>
+
+struct xnotify *xnotify_init(int max)
+{
+ struct xnotify *not = xzalloc(sizeof(struct xnotify));
+
+ not->max = max;
+ if ((not->kq = kqueue()) == -1) perror_exit("kqueue");
+ not->paths = xmalloc(max * sizeof(char *));
+ not->fds = xmalloc(max * sizeof(int));
+
+ return not;
+}
+
+int xnotify_add(struct xnotify *not, int fd, char *path)
+{
+ struct kevent event;
+
+ if (not->count == not->max) error_exit("xnotify_add overflow");
+ EV_SET(&event, fd, EVFILT_VNODE, EV_ADD|EV_CLEAR, NOTE_WRITE, 0, NULL);
+ if (kevent(not->kq, &event, 1, NULL, 0, NULL) == -1 || event.flags & EV_ERROR)
+ return -1;
+ not->paths[not->count] = path;
+ not->fds[not->count++] = fd;
+
+ return 0;
+}
+
+int xnotify_wait(struct xnotify *not, char **path)
+{
+ struct kevent event;
+ int i;
+
+ for (;;) {
+ if (kevent(not->kq, NULL, 0, &event, 1, NULL) != -1) {
+ // We get the fd for free, but still have to search for the path.
+ for (i = 0; i<not->count; i++) if (not->fds[i]==event.ident) {
+ *path = paths[i];
+
+ return event.ident;
+ }
+ }
+ }
+}
+
+#else
+
+#include <sys/inotify.h>
+
+struct xnotify *xnotify_init(int max)
+{
+ struct xnotify *not = xzalloc(sizeof(struct xnotify));
+
+ not->max = max;
+ if ((not->kq = inotify_init()) < 0) perror_exit("inotify_init");
+ not->paths = xmalloc(max * sizeof(char *));
+ not->fds = xmalloc(max * 2 * sizeof(int));
+
+ return not;
+}
+
+int xnotify_add(struct xnotify *not, int fd, char *path)
+{
+ int i = 2*not->count;
+
+ if (not->max == not->count) error_exit("xnotify_add overflow");
+ if ((not->fds[i] = inotify_add_watch(not->kq, path, IN_MODIFY))==-1)
+ return -1;
+ not->fds[i+1] = fd;
+ not->paths[not->count++] = path;
+
+ return 0;
+}
+
+int xnotify_wait(struct xnotify *not, char **path)
+{
+ struct inotify_event ev;
+ int i;
+
+ for (;;) {
+ if (sizeof(ev)!=read(not->kq, &ev, sizeof(ev))) perror_exit("inotify");
+
+ for (i = 0; i<not->count; i++) if (ev.wd==not->fds[2*i]) {
+ *path = not->paths[i];
+
+ return not->fds[2*i+1];
+ }
+ }
+}
+
+#endif
diff --git a/lib/portability.h b/lib/portability.h
index f4a2b327..f5f8352a 100644
--- a/lib/portability.h
+++ b/lib/portability.h
@@ -309,6 +309,12 @@ static inline void confstr(int a, char *b, int c) {strcpy(b, a ? "POSIXLY_CORREC
#endif
// Paper over the differences between BSD kqueue and Linux inotify for tail.
-void notify_init(int max);
-int notify_add(int fd, char *path);
-int notify_wait(char **path);
+
+struct xnotify {
+ char **paths;
+ int max, *fds, count, kq;
+};
+
+struct xnotify *xnotify_init(int max);
+int xnotify_add(struct xnotify *not, int fd, char *path);
+int xnotify_wait(struct xnotify *not, char **path);
diff --git a/toys/posix/tail.c b/toys/posix/tail.c
index 49a7f69b..d49a70c2 100644
--- a/toys/posix/tail.c
+++ b/toys/posix/tail.c
@@ -36,6 +36,7 @@ GLOBALS(
long n, c;
int file_no, last_fd;
+ struct xnotify *not;
)
struct line_list {
@@ -139,7 +140,7 @@ static void do_tail(int fd, char *name)
char *s = name;
if (!fd) sprintf(s = toybuf, "/proc/self/fd/%d", fd);
- if (notify_add(fd, s) == -1) perror_exit("-f on '%s' failed", s);
+ if (xnotify_add(TT.not, fd, s)) perror_exit("-f on '%s' failed", s);
}
if (TT.file_no++) xputc('\n');
@@ -233,13 +234,13 @@ void tail_main(void)
}
}
- if (FLAG(f)) notify_init(toys.optc);
+ if (FLAG(f)) TT.not = xnotify_init(toys.optc);
loopfiles_rw(args, O_RDONLY|WARN_ONLY|(O_CLOEXEC*!FLAG(f)), 0, do_tail);
if (FLAG(f) && TT.file_no) {
for (;;) {
char *path;
- int fd = notify_wait(&path), len;
+ int fd = xnotify_wait(TT.not, &path), len;
// Read new data.
while ((len = read(fd, toybuf, sizeof(toybuf)))>0) {