inotifyd.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. /* inotifyd.c - inotify daemon.
  2. *
  3. * Copyright 2013 Ashwini Kumar <ak.ashwini1981@gmail.com>
  4. * Copyright 2013 Kyungwan Han <asura321@gmail.com>
  5. *
  6. * No Standard.
  7. USE_INOTIFYD(NEWTOY(inotifyd, "<2", TOYFLAG_USR|TOYFLAG_BIN))
  8. config INOTIFYD
  9. bool "inotifyd"
  10. default y
  11. help
  12. usage: inotifyd PROG FILE[:MASK] ...
  13. When a filesystem event matching MASK occurs to a FILE, run PROG as:
  14. PROG EVENTS FILE [DIRFILE]
  15. If PROG is "-" events are sent to stdout.
  16. This file is:
  17. a accessed c modified e metadata change w closed (writable)
  18. r opened D deleted M moved 0 closed (unwritable)
  19. u unmounted o overflow x unwatchable
  20. A file in this directory is:
  21. m moved in y moved out n created d deleted
  22. When x event happens for all FILEs, inotifyd exits (after waiting for PROG).
  23. */
  24. #define FOR_inotifyd
  25. #include "toys.h"
  26. #include <sys/inotify.h>
  27. void inotifyd_main(void)
  28. {
  29. struct pollfd fds;
  30. char *prog_args[5], **ss = toys.optargs;
  31. char *masklist ="acew0rmyndDM uox";
  32. fds.events = POLLIN;
  33. *prog_args = *toys.optargs;
  34. prog_args[4] = 0;
  35. if ((fds.fd = inotify_init()) == -1) perror_exit(0);
  36. // Track number of watched files. First one was program to run.
  37. toys.optc--;
  38. while (*++ss) {
  39. char *path = *ss, *masks = strchr(*ss, ':');
  40. int i, mask = 0;
  41. if (!masks) mask = 0xfff; // default to all
  42. else{
  43. *masks++ = 0;
  44. for (*masks++ = 0; *masks; masks++) {
  45. i = stridx(masklist, *masks);;
  46. if (i == -1) error_exit("bad mask '%c'", *masks);
  47. mask |= 1<<i;
  48. }
  49. }
  50. // This returns increasing numbers starting from 1, which coincidentally
  51. // is the toys.optargs position of the file. (0 is program to run.)
  52. if (inotify_add_watch(fds.fd, path, mask) < 0) perror_exit_raw(path);
  53. }
  54. for (;;) {
  55. int ret = 0, len;
  56. void *buf = 0;
  57. struct inotify_event *event;
  58. // Read next event(s)
  59. ret = poll(&fds, 1, -1);
  60. if (ret < 0 && errno == EINTR) continue;
  61. if (ret <= 0) break;
  62. xioctl(fds.fd, FIONREAD, &len);
  63. event = buf = xmalloc(len);
  64. len = readall(fds.fd, buf, len);
  65. // Loop through set of events.
  66. for (;;) {
  67. int left = len - (((char *)event)-(char *)buf),
  68. size = sizeof(struct inotify_event);
  69. // Don't dereference event if ->len is off end of bufer
  70. if (left >= size) size += event->len;
  71. if (left < size) break;
  72. if (event->mask) {
  73. char *s = toybuf, *m;
  74. for (m = masklist; *m; m++)
  75. if (event->mask & (1<<(m-masklist))) *s++ = *m;
  76. *s = 0;
  77. if (**prog_args == '-' && !prog_args[0][1]) {
  78. xprintf("%s\t%s\t%s\n" + 3*!event->len, toybuf,
  79. toys.optargs[event->wd], event->name);
  80. } else {
  81. prog_args[1] = toybuf;
  82. prog_args[2] = toys.optargs[event->wd];
  83. prog_args[3] = event->len ? event->name : 0;
  84. xrun(prog_args);
  85. }
  86. if (event->mask & IN_IGNORED) {
  87. if (--toys.optc <= 0) {
  88. free(buf);
  89. goto done;
  90. }
  91. inotify_rm_watch(fds.fd, event->wd);
  92. }
  93. }
  94. event = (void*)(size + (char*)event);
  95. }
  96. free(buf);
  97. }
  98. done:
  99. toys.exitval = !!toys.signal;
  100. }