// 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; } }