inotifyd.c revision 6958429d84cff06fefdc898d837a71c239f1e214
16958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma/* inotifyd.c - inotify daemon. 26958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma * 36958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma * Copyright 2013 Ashwini Kumar <ak.ashwini1981@gmail.com> 46958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma * Copyright 2013 Kyungwan Han <asura321@gmail.com> 56958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma * 66958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma * No Standard. 76958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma 86958429d84cff06fefdc898d837a71c239f1e214Ashwini SharmaUSE_INOTIFYD(NEWTOY(inotifyd, "<2", TOYFLAG_USR|TOYFLAG_BIN)) 96958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma 106958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharmaconfig INOTIFYD 116958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma bool "inotifyd" 126958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma default n 136958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma help 146958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma usage: inotifyd PROG FILE[:mask] ... 156958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma 166958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma Run PROG on filesystem changes. 176958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma When a filesystem event matching MASK occurs on FILEn, 186958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma PROG ACTUAL_EVENTS FILEn [SUBFILE] is run. 196958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma If PROG is -, events are sent to stdout. 206958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma 216958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma Events: 226958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma a File is accessed 236958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma c File is modified 246958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma e Metadata changed 256958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma w Writable file is closed 266958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma 0 Unwritable file is closed 276958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma r File is opened 286958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma D File is deleted 296958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma M File is moved 306958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma u Backing fs is unmounted 316958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma o Event queue overflowed 326958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma x File can't be watched anymore 336958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma If watching a directory: 346958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma m Subfile is moved into dir 356958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma y Subfile is moved out of dir 366958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma n Subfile is created 376958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma d Subfile is deleted 386958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma 396958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma inotifyd waits for PROG to exit. 406958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma When x event happens for all FILEs, inotifyd exits. 416958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma*/ 426958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma#define FOR_inotifyd 436958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma#include "toys.h" 446958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma#include <sys/inotify.h> 456958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma 466958429d84cff06fefdc898d837a71c239f1e214Ashwini SharmaGLOBALS( 476958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma int gotsignal; 486958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma) 496958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma 506958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharmastatic void sig_handler(int sig) 516958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma{ 526958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma TT.gotsignal = sig; 536958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma} 546958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma 556958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharmastatic int exec_wait(char **args) 566958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma{ 576958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma int status = 0; 586958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma pid_t pid = fork(); 596958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma 606958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma if (!pid) xexec(args); 616958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma else if (pid > 0) waitpid(pid, &status, 0); 626958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma else perror_exit("fork"); 636958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma return WEXITSTATUS(status); 646958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma} 656958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma 666958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharmavoid inotifyd_main(void) 676958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma{ 686958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma struct pollfd fds; 696958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma char *prog_args[5], **files, **restore; 706958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma struct mask_nameval { 716958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma char name; 726958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma unsigned long val; 736958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma } mask_nv[] = { 746958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma { 'a', IN_ACCESS }, 756958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma { 'c', IN_MODIFY }, 766958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma { 'e', IN_ATTRIB }, 776958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma { 'w', IN_CLOSE_WRITE }, 786958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma { '0', IN_CLOSE_NOWRITE }, 796958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma { 'r', IN_OPEN }, 806958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma { 'm', IN_MOVED_FROM }, 816958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma { 'y', IN_MOVED_TO }, 826958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma { 'n', IN_CREATE }, 836958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma { 'd', IN_DELETE }, 846958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma { 'D', IN_DELETE_SELF }, 856958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma { 'M', IN_MOVE_SELF }, 866958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma { 'u', IN_UNMOUNT }, 876958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma { 'o', IN_Q_OVERFLOW }, 886958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma { 'x', IN_IGNORED } 896958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma }; 906958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma int mask, masks_len = ARRAY_LEN(mask_nv); 916958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma 926958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma prog_args[0] = toys.optargs[0]; 936958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma prog_args[4] = NULL; 946958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma toys.optc--; // 1st one is program, rest are files to be watched 956958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma //wd ZERO is not used, hence toys.optargs is assigned to files. 966958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma restore = files = toys.optargs; 976958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma if ((fds.fd = inotify_init()) == -1) perror_exit("initialization failed"); 986958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma 996958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma while (*++toys.optargs) { 1006958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma char *path = *toys.optargs; 1016958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma char *masks = strchr(path, ':'); 1026958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma 1036958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma mask = 0x0fff; //assuming all non-kernel events to be notified. 1046958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma if (masks) { 1056958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma *masks++ = '\0'; 1066958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma mask = 0; 1076958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma while (*masks) { 1086958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma int i = 0; 1096958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma 1106958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma for (i = 0; i < masks_len; i++) { 1116958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma if (*masks == mask_nv[i].name) { 1126958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma mask |= mask_nv[i].val; 1136958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma break; 1146958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma } 1156958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma } 1166958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma if (i == masks_len) error_exit("wrong mask '%c'", *masks); 1176958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma masks++; 1186958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma } 1196958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma } 1206958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma if (inotify_add_watch(fds.fd, path, mask) < 0) 1216958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma perror_exit("add watch '%s' failed", path); 1226958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma } 1236958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma toys.optargs = restore; 1246958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma sigatexit(sig_handler); 1256958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma fds.events = POLLIN; 1266958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma 1276958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma while (1) { 1286958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma int ret = 0, queue_len; 1296958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma void *buf = NULL; 1306958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma struct inotify_event *event; 1316958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma 1326958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharmaretry: 1336958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma if (TT.gotsignal) break; 1346958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma ret = poll(&fds, 1, -1); 1356958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma if (ret < 0 && errno == EINTR) goto retry; 1366958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma if (ret <= 0) break; 1376958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma xioctl(fds.fd, FIONREAD, &queue_len); 1386958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma event = buf = xmalloc(queue_len); 1396958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma queue_len = readall(fds.fd, buf, queue_len); 1406958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma while (queue_len > 0) { 1416958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma uint32_t m = event->mask; 1426958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma 1436958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma if (m) { 1446958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma char evts[masks_len+1], *s = evts; 1456958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma int i; 1466958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma 1476958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma for (i = 0; i < masks_len; i++) 1486958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma if (m & mask_nv[i].val) *s++ = mask_nv[i].name; 1496958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma *s = '\0'; 1506958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma 1516958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma if (prog_args[0][0] == '-' && !prog_args[0][1]) { //stdout 1526958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma printf(event->len ? "%s\t%s\t%s\n" : "%s\t%s\n", evts, 1536958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma files[event->wd], event->name); 1546958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma fflush(stdout); 1556958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma } else { 1566958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma prog_args[1] = evts; 1576958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma prog_args[2] = files[event->wd]; 1586958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma prog_args[3] = event->len ? event->name : NULL; 1596958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma exec_wait(prog_args); //exec and wait... 1606958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma } 1616958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma if (event->mask & IN_IGNORED) { 1626958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma if (--toys.optc <= 0) { 1636958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma free(buf); 1646958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma goto done; 1656958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma } 1666958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma inotify_rm_watch(fds.fd, event->wd); 1676958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma } 1686958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma } 1696958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma queue_len -= sizeof(struct inotify_event) + event->len; 1706958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma event = (void*)((char*)event + sizeof(struct inotify_event) + event->len); //next event 1716958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma } 1726958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma free(buf); 1736958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma } 1746958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharmadone: 1756958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma toys.exitval = TT.gotsignal; 1766958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma} 177