Skip to content

Instantly share code, notes, and snippets.

@duangsuse
Last active February 22, 2021 15:26
Show Gist options
  • Save duangsuse/a8984950c563894eea54fc2f537b5003 to your computer and use it in GitHub Desktop.
Save duangsuse/a8984950c563894eea54fc2f537b5003 to your computer and use it in GitHub Desktop.
Linux DNotify/INotify
#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;
}
#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;
}
#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;
}
#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