/* * Copyright (C) 2008,2009 Sebastian Krahmer. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Sebastian Krahmer. * 4. The name Sebastian Krahmer may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* inotify.cc simply watches files/dirs on Linux 2.6+ Kernels. * call like "inotify /tmp /var/ ..." */ #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; struct mask2string { u_int32_t mask; const char *desc; }; struct mask2string events[] = { {IN_ACCESS, "accessed"}, {IN_ATTRIB, "attributes changed"}, {IN_CLOSE_WRITE, "writable closed"}, {IN_CLOSE_NOWRITE, "non-writable closed"}, {IN_CREATE, "created"}, {IN_DELETE, "deleted"}, {IN_DELETE_SELF, "(self) deleted"}, {IN_MODIFY, "modified"}, {IN_MOVE_SELF, "(self) moved"}, {IN_MOVED_FROM, "moved out of dir"}, {IN_MOVED_TO, "moved into dir"}, {IN_OPEN, "opened"}, {-1, NULL} }; namespace global { map wd2path; bool recurse = 0; int ifd = -1; } using namespace global; void print_status(struct inotify_event *ie) { struct stat st; int i = 0; string path = wd2path[(u_int32_t)ie->wd]; if (ie->len) { path += "/"; path += string(ie->name); } printf("[%s] ", path.c_str()); if (stat(path.c_str(), &st) == 0) { printf("[ino:%08zd] [mode:%05o] [uid:%04d] [gid:%04d] [size:%08zd] ", st.st_ino, st.st_mode, st.st_uid, st.st_gid, st.st_size); } else { printf("[no stat(2) possible] "); } if (recurse && (ie->mask & IN_CREATE) && S_ISDIR(st.st_mode)) { int wfd = inotify_add_watch(ifd, path.c_str(), IN_ALL_EVENTS); if (wfd >= 0) wd2path[wfd] = path; } for (i = 0; events[i].desc != NULL; ++i) { if (ie->mask & events[i].mask) { printf("%s ", events[i].desc); } } printf("\n"); return; } int watch_path(const vector &paths) { char buf[4096]; struct inotify_event *ie = (struct inotify_event *)buf; u_int32_t wfd = 0; ifd = inotify_init(); for (vector::const_iterator j = paths.begin(); j != paths.end(); ++j) { wfd = inotify_add_watch(ifd, (*j).c_str(), IN_ALL_EVENTS); if ((int)wfd < 0) { perror("inotify_add_watch"); exit(errno); } wd2path[wfd] = *j; } for (;;) { if (read(ifd, ie, sizeof(buf)) < 0) { perror("read"); exit(errno); } print_status(ie); } return 0; } int main(int argc, char **argv) { vector pv; ++argv; for (;*argv; ++argv) { if (string(*argv) == string("-r")) { recurse = 1; continue; } pv.push_back(*argv); } watch_path(pv); return 0; }