From a8e19d5d8057e82cbda2705d755f3d4e1d3da20a Mon Sep 17 00:00:00 2001 From: Andrew Cady Date: Sun, 1 May 2016 05:25:14 -0400 Subject: remove references to files outside of this repo (commit the files into this repo) --- src/wait_for_files.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 src/wait_for_files.c (limited to 'src/wait_for_files.c') 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 @@ +// wait_for_files - Efficiently sleeps until the files specified on the +// command line exist (or have existed during execution). +// Linux 2.6.13, GNU C only. Use gcc -std=c99 +// glibc 2.4 or define PRIVATE_INOTIFY_HEADER + +// #define PRIVATE_INOTIFY_HEADER "inotifytools/inotify.h" + +#include +#include +#include +#include +#include +#ifdef PRIVATE_INOTIFY_HEADER +#include PRIVATE_INOTIFY_HEADER +#else +#include +#endif +#include +#include +#include +#include +#include +#include + +char *strdup(const char *s); // wtf? + +int main(int argc, char **argv) +{ + if (argc == 1) return 0; + --argc; ++argv; + + int notify = inotify_init(); + if (notify < 0) + error(-1, errno, "inotify_init error"); + + struct wdtab_t { + char *basename; + int wd; // set to 0 when found + } wdtab[argc]; + + bool done = true; + for (int i = 0; i < argc; ++i) { + struct wdtab_t *p = &wdtab[i]; + + char *dirname_mem; + if (!(dirname_mem = strdup(argv[i])) || + !(p->basename = strdup(argv[i]))) + error(-1, errno, "strdup error"); + char *dirname_val = dirname(dirname_mem); + p->basename = basename(p->basename); + + p->wd = inotify_add_watch(notify, dirname_val, IN_CREATE|IN_MASK_ADD); + if (p->wd < 0) + error(-1, errno, "inotify_add_watch error (file: %s)", argv[i]); + free(dirname_mem); + + struct stat dummy; + if (stat(argv[i], &dummy) == 0) + p->wd = 0; + else + done = false; + } + if (done) return 0; + + for (;;) { + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(notify, &rfds); + switch (select(notify+1, &rfds, NULL, NULL, NULL)) { + case -1: error(-1, errno, "select error"); + case 0: continue; // this should never happen + } + + // is ioctl FIONREAD even documented? + int bytes_ready = 0; + if (ioctl(notify, FIONREAD, &bytes_ready) < 0) + error(-1, errno, "ioctl FIONREAD (inotify) error"); + if (bytes_ready % sizeof(struct inotify_event) != 0) + // this should never ever ever happen, evar + error(-1, 0, "ioctl FIONREAD (inotify) returned bizarre result (%i)", + bytes_ready); + if (bytes_ready < sizeof(struct inotify_event)) + continue; // bytes_ready <= 0. this should never happen + + struct inotify_event evs[bytes_ready / sizeof(struct inotify_event)]; + + ssize_t r; + if ((r = read(notify, evs, sizeof(evs))) != sizeof(evs)) { + if (r < 0) + error(-1, errno, "read error (inotify)"); + else + error(1, 0, "short read (inotify, got %i, expected %i)", + (int) r, (int) sizeof(evs)); + } + + done = true; + for (int j = 0; j < sizeof(evs) / sizeof(evs[0]); ++j) { + struct inotify_event *ev = &evs[j]; + for (int i = 0; i < argc; ++i) { + struct wdtab_t *p = &wdtab[i]; + if (!p->wd) + continue; + else if ((ev->wd == p->wd) && + (ev->mask|IN_CREATE) && + !strcmp(ev->name, p->basename)) + { + p->wd = 0; + } else + done = false; + } + } + if (done) return 0; + } +} -- cgit v1.2.3