Last active
February 22, 2021 15:26
-
-
Save duangsuse/a8984950c563894eea54fc2f537b5003 to your computer and use it in GitHub Desktop.
Linux DNotify/INotify
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <fcntl.h> | |
#include <csignal> | |
#include <unistd.h> | |
#include <limits.h> | |
#include <cstdio> | |
const int sigPrior = SIGRTMIN+1; | |
#define notNeg(v) v; if (v<0) return -1 | |
static char fpDesc[PATH_MAX]; | |
void getFPath(int fd) { | |
sprintf(fpDesc, "/proc/self/fd/%d", fd); | |
size_t n = readlink(fpDesc, fpDesc, sizeof(fpDesc)); //notNeg(fcntl(o.si_fd, F_GETPATH, fpDesc)); | |
fpDesc[n] = '\0'; | |
} | |
void printFPath(int signo, siginfo_t* si, void*) { | |
auto o = *si; | |
printf("%d %d %d", signo, o.si_code, o.si_fd); | |
getFPath(o.si_fd); | |
printf(" %s\n", fpDesc); | |
} | |
int main(int argc, char** argv) { | |
auto fp = (argc>1)? argv[1] : "."; | |
int fd = notNeg(open(fp, O_RDONLY)); | |
fcntl(fd, F_SETSIG, sigPrior); | |
fcntl(fd, F_NOTIFY, DN_MULTISHOT|DN_CREATE|DN_MODIFY|DN_DELETE); | |
struct sigaction dnAct = { .sa_sigaction=printFPath, .sa_flags=SA_SIGINFO }; | |
sigemptyset(&dnAct.sa_mask); | |
sigaction(sigPrior, &dnAct, NULL); | |
while(true) pause(); | |
return 0; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <sys/inotify.h> | |
#include <unistd.h> | |
#include <cstdio> | |
#include <cstdlib> | |
#include <algorithm> | |
#include <cstring> | |
#include <limits.h> //NAME_MAX | |
typedef const char* cstr; | |
cstr evFlagNames[] = { // See /usr/include/sys/inotify.h | |
"R", "M", "attrib", "close", "close.rd", | |
"open", "move.from", "move.to", "A", "D", | |
"self.D", "self.move", "", "self.unmount", "in.queovf", "in.ignore" | |
}; | |
template<typename T> | |
void onIncTail(int fd, size_t nbuf, size_t(*op)(T*)) { | |
alignas(T) char buf[nbuf]; | |
for (int n; (n = read(fd, buf, nbuf)) != 0;) { | |
char *ptr, *ptr1; | |
for (ptr=&buf[0], ptr1=ptr+n; ptr!=ptr1;) ptr += sizeof(T)+op((T*)ptr); | |
} | |
} | |
template<typename N, size_t NUM> | |
void printFlags(N flags, cstr (&names)[NUM]) { | |
for (int i=0; i<NUM; i++) if (flags & (1<<i)) printf("%s ", names[i]); | |
} | |
int ienv(cstr name, int deft) { cstr v=getenv(name); return (v!=NULL)? atoi(v) : deft; } | |
unsigned readINMask(char*s, cstr sep) { | |
if (s==NULL) return IN_ALL_EVENTS; | |
cstr tok = strtok(s, sep); | |
int mask = 0; | |
while (tok!=NULL) { | |
using namespace std; | |
auto ary = evFlagNames, aend = ary+16; | |
auto ptr = find_if(ary, aend, [&](cstr s) { return strcmp(s, tok)==0; }); | |
if (ptr!=aend) mask|=(1<<distance(ary, ptr)); | |
tok = strtok(NULL, sep); | |
} | |
return mask; | |
} | |
template<typename N> | |
N strMask(cstr s, N(*get_bit)(char)) { | |
if (s==NULL) return 0; | |
N mask = (N)0; | |
for (int i=0; i<strlen(s); i++) mask|=get_bit(s[i]); | |
return mask; | |
} | |
#define MREL(k, v) case k: return v; | |
cstr* mainArgv; bool hasPrefix; | |
const size_t MIN_SIZE = sizeof(struct inotify_event)+NAME_MAX+1; | |
int main(int argc, cstr argv[]) { | |
size_t bufSize = std::max((size_t)ienv("bufSize", MIN_SIZE*5), MIN_SIZE); | |
mainArgv = argv; hasPrefix = argc!=2 && ienv("hasPrefix", 1)==1; | |
if (argc==1) { for(cstr name : evFlagNames) printf("%s ", name); printf("\nevNames=above evFlags=dFu1 hasPrefix=1 bufSize=%zu\n", bufSize); return -1; } | |
int fdNoti = inotify_init(); | |
auto extraMask = strMask(getenv("evFlags"), +[](char c) -> unsigned { | |
switch(c) { MREL('d', IN_ONLYDIR) MREL('F', IN_DONT_FOLLOW) MREL('u', IN_EXCL_UNLINK) MREL('1', IN_ONESHOT) } | |
return 0; | |
}); | |
for (int i=1; i<argc; i++) inotify_add_watch(fdNoti, argv[i], readINMask(getenv("evNames"), " ,")|extraMask); | |
onIncTail(fdNoti, bufSize, +[](struct inotify_event* ev) { | |
if(ev->mask&IN_ISDIR) printf("d"); | |
printFlags(ev->mask, evFlagNames); | |
if (hasPrefix) printf("%s/", mainArgv[ev->wd]); | |
printf("%s\n", ev->name); | |
return (size_t)ev->len; | |
}); | |
return 0; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <sys/inotify.h> | |
#include <unistd.h> | |
#include <cstdlib> | |
#include <cstdio> | |
#include <cerrno> | |
#define notNeg(v, ...) v; if (v<0) { fprintf(stderr, "Failed to " __VA_ARGS__); perror(" "); return -1; } | |
const char* evNames[] = { | |
"access", "M", "attrib", "close", "close.rd", | |
"open", "move.from", "move.to", "A", "D", | |
"self.D", "self.move", "", "self.unmount", "ovf", "ignore" | |
}; | |
int main(int argc, char** argv) { | |
auto fp = (argc>1)? argv[1] : "."; | |
int bufSize = (argc>2)? atoi(argv[2]) : 1024; | |
int fdNoti, idNoti; | |
char buffer[bufSize+1], *offset = NULL; | |
struct inotify_event* ev; | |
notNeg((fdNoti = inotify_init()), "initialize inotify"); | |
notNeg((idNoti = inotify_add_watch(fdNoti, fp, IN_ALL_EVENTS)), "add watch for %s", fp); | |
for (int n; (n = read(fdNoti, buffer, bufSize)) != 0;) { | |
offset = buffer; | |
ev = (typeof(ev))(offset); | |
while (((char*)ev - buffer) < n) { | |
if(ev->wd != idNoti) { continue; } | |
if(ev->mask&IN_ISDIR) printf("[d]"); | |
for (int i=0; i<sizeof(evNames)/sizeof(char*); i++) { // print flags | |
if (ev->mask & (1<<i)) printf("%s ", evNames[i]); | |
} | |
printf("%s\n", ev->name); | |
size_t nbEntry = sizeof(struct inotify_event) + ev->len; | |
offset += nbEntry; | |
ev = (typeof(ev))(offset); | |
} | |
} | |
int len, i=0; | |
if(0)while ((len = read(fdNoti, buffer, bufSize))) { // original ver. | |
offset = buffer; | |
ev = (struct inotify_event *)offset; | |
while (((char *)ev - buffer) < len) { | |
if (ev->wd != idNoti) continue; | |
printf("Object type: %s\n", ev->mask & IN_ISDIR ? "Direcotory" : "File"); | |
printf("Object name: %s\n", ev->name); | |
printf("Event mask: %08X\n", ev->mask); | |
for (i = 0; i < 16; i++) { | |
if (ev->mask & (1 << i)) { | |
printf("Event: %s\n", evNames[i]); | |
} | |
} | |
int nb = sizeof(struct inotify_event) + ev->len; | |
offset += nb; | |
ev = (struct inotify_event *)(offset); | |
} | |
} | |
return 0; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <sys/inotify.h> | |
#include <unistd.h> // fd read | |
#include <signal.h> // on_exit | |
#include <cstdlib> | |
#include <cstdio> | |
#include <cerrno> | |
#include <type_traits> | |
typedef const char* cstr; | |
cstr evFlagNames[] = { | |
"access", "M", "attrib", "close", "close.rd", | |
"open", "move.from", "move.to", "A", "D", | |
"self.D", "self.move", "", "self.unmount", "ovf", "ignore" | |
}; | |
template<typename N> | |
bool setsNeg(N& n, N v, cstr msg) { | |
if (n>=0) { n = v; return false; } | |
else { fprintf(stderr, "Failed to %s", msg); perror(" "); return true; } | |
} | |
template<typename T> | |
void onIncBufferedTail(int fd, size_t nbuf, size_t(*op)(T*)) { | |
char buf[nbuf], *ptr; | |
for (int n; (n = read(fd, buf, nbuf)) != 0;) { | |
ptr = &buf[0]; | |
while (ptr - buf < n) { | |
ptr += sizeof(T)+op((T*)ptr); | |
} | |
} | |
} | |
template<typename N, size_t NUM> | |
void printFlags(N flags, cstr (&names)[NUM]) { | |
for (int i=0; i<NUM; i++) if (flags & (1<<i)) printf("%s ", names[i]); | |
} | |
template<typename T> | |
T env(cstr name, T deft) { auto v=getenv(name); return (v==NULL)? deft : (std::is_integral<T>::value)? (T)atol(v) : (T)(size_t)v; } | |
int main(int argc, char** argv) { | |
int fdNoti, idNoti[1+argc-1]; | |
if (setsNeg(fdNoti, inotify_init(), "initialize inotify")) return 1; | |
for (int i=1; i<argc; i++) { | |
auto fp = argv[i]; | |
if (setsNeg(idNoti[i], inotify_add_watch(fdNoti, fp, IN_ALL_EVENTS), "add watch")) | |
{ fprintf(stderr, " for %s\n", fp); return 2; } | |
} | |
for(int no=2; no<=3; no++) signal(no/*INT,QUIT*/, +[](int) { exit(0); }); | |
idNoti[0] = fdNoti; | |
on_exit(+[](int n, void* v) { printf("--\n"); auto vs = (int*)v; for (int i=1; i<n; i++) inotify_rm_watch(vs[0], vs[i]); }, idNoti); | |
onIncBufferedTail(fdNoti, env("BUFSIZE", 1024), +[](struct inotify_event* ev) { | |
if(ev->mask&IN_ISDIR) printf("[d]"); | |
printFlags(ev->mask, evFlagNames); | |
printf("%s\n", ev->name); | |
return (size_t)ev->len; | |
}); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
See: https://blog.csdn.net/xiejinfeng850414/article/details/8252770
https://stackoverflow.com/questions/4062806/what-is-the-proper-way-to-use-inotify