summaryrefslogtreecommitdiff
path: root/src/wait_for_files.c
diff options
context:
space:
mode:
authorAndrew Cady <d@jerkface.net>2016-05-01 05:25:14 -0400
committerAndrew Cady <d@jerkface.net>2016-05-01 05:28:22 -0400
commita8e19d5d8057e82cbda2705d755f3d4e1d3da20a (patch)
tree84449f8ac6e45a5727b0abbb64eeb578c20628fd /src/wait_for_files.c
parent4854ffec94f70705dc95c5657e43c5f69c270a1a (diff)
remove references to files outside of this repo
(commit the files into this repo)
Diffstat (limited to 'src/wait_for_files.c')
-rw-r--r--src/wait_for_files.c114
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
25char *strdup(const char *s); // wtf?
26
27int 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}