diff options
Diffstat (limited to 'src/wait_for_files.c')
-rw-r--r-- | src/wait_for_files.c | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/src/wait_for_files.c b/src/wait_for_files.c new file mode 100644 index 0000000..3a7f6b5 --- /dev/null +++ b/src/wait_for_files.c | |||
@@ -0,0 +1,114 @@ | |||
1 | // wait_for_files - Efficiently sleeps until the files specified on the | ||
2 | // command line exist (or have existed during execution). | ||
3 | // Linux 2.6.13, GNU C only. Use gcc -std=c99 | ||
4 | // glibc 2.4 or define PRIVATE_INOTIFY_HEADER | ||
5 | |||
6 | // #define PRIVATE_INOTIFY_HEADER "inotifytools/inotify.h" | ||
7 | |||
8 | #include <errno.h> | ||
9 | #include <error.h> | ||
10 | #include <libgen.h> | ||
11 | #include <stdbool.h> | ||
12 | #include <string.h> | ||
13 | #ifdef PRIVATE_INOTIFY_HEADER | ||
14 | #include PRIVATE_INOTIFY_HEADER | ||
15 | #else | ||
16 | #include <sys/inotify.h> | ||
17 | #endif | ||
18 | #include <sys/ioctl.h> | ||
19 | #include <sys/select.h> | ||
20 | #include <sys/stat.h> | ||
21 | #include <sys/types.h> | ||
22 | #include <unistd.h> | ||
23 | #include <stdlib.h> | ||
24 | |||
25 | char *strdup(const char *s); // wtf? | ||
26 | |||
27 | int main(int argc, char **argv) | ||
28 | { | ||
29 | if (argc == 1) return 0; | ||
30 | --argc; ++argv; | ||
31 | |||
32 | int notify = inotify_init(); | ||
33 | if (notify < 0) | ||
34 | error(-1, errno, "inotify_init error"); | ||
35 | |||
36 | struct wdtab_t { | ||
37 | char *basename; | ||
38 | int wd; // set to 0 when found | ||
39 | } wdtab[argc]; | ||
40 | |||
41 | bool done = true; | ||
42 | for (int i = 0; i < argc; ++i) { | ||
43 | struct wdtab_t *p = &wdtab[i]; | ||
44 | |||
45 | char *dirname_mem; | ||
46 | if (!(dirname_mem = strdup(argv[i])) || | ||
47 | !(p->basename = strdup(argv[i]))) | ||
48 | error(-1, errno, "strdup error"); | ||
49 | char *dirname_val = dirname(dirname_mem); | ||
50 | p->basename = basename(p->basename); | ||
51 | |||
52 | p->wd = inotify_add_watch(notify, dirname_val, IN_CREATE|IN_MASK_ADD); | ||
53 | if (p->wd < 0) | ||
54 | error(-1, errno, "inotify_add_watch error (file: %s)", argv[i]); | ||
55 | free(dirname_mem); | ||
56 | |||
57 | struct stat dummy; | ||
58 | if (stat(argv[i], &dummy) == 0) | ||
59 | p->wd = 0; | ||
60 | else | ||
61 | done = false; | ||
62 | } | ||
63 | if (done) return 0; | ||
64 | |||
65 | for (;;) { | ||
66 | fd_set rfds; | ||
67 | FD_ZERO(&rfds); | ||
68 | FD_SET(notify, &rfds); | ||
69 | switch (select(notify+1, &rfds, NULL, NULL, NULL)) { | ||
70 | case -1: error(-1, errno, "select error"); | ||
71 | case 0: continue; // this should never happen | ||
72 | } | ||
73 | |||
74 | // is ioctl FIONREAD even documented? | ||
75 | int bytes_ready = 0; | ||
76 | if (ioctl(notify, FIONREAD, &bytes_ready) < 0) | ||
77 | error(-1, errno, "ioctl FIONREAD (inotify) error"); | ||
78 | if (bytes_ready % sizeof(struct inotify_event) != 0) | ||
79 | // this should never ever ever happen, evar | ||
80 | error(-1, 0, "ioctl FIONREAD (inotify) returned bizarre result (%i)", | ||
81 | bytes_ready); | ||
82 | if (bytes_ready < sizeof(struct inotify_event)) | ||
83 | continue; // bytes_ready <= 0. this should never happen | ||
84 | |||
85 | struct inotify_event evs[bytes_ready / sizeof(struct inotify_event)]; | ||
86 | |||
87 | ssize_t r; | ||
88 | if ((r = read(notify, evs, sizeof(evs))) != sizeof(evs)) { | ||
89 | if (r < 0) | ||
90 | error(-1, errno, "read error (inotify)"); | ||
91 | else | ||
92 | error(1, 0, "short read (inotify, got %i, expected %i)", | ||
93 | (int) r, (int) sizeof(evs)); | ||
94 | } | ||
95 | |||
96 | done = true; | ||
97 | for (int j = 0; j < sizeof(evs) / sizeof(evs[0]); ++j) { | ||
98 | struct inotify_event *ev = &evs[j]; | ||
99 | for (int i = 0; i < argc; ++i) { | ||
100 | struct wdtab_t *p = &wdtab[i]; | ||
101 | if (!p->wd) | ||
102 | continue; | ||
103 | else if ((ev->wd == p->wd) && | ||
104 | (ev->mask|IN_CREATE) && | ||
105 | !strcmp(ev->name, p->basename)) | ||
106 | { | ||
107 | p->wd = 0; | ||
108 | } else | ||
109 | done = false; | ||
110 | } | ||
111 | } | ||
112 | if (done) return 0; | ||
113 | } | ||
114 | } | ||