#include #include #include #include #include #include #include struct index { struct index *next; struct index *prev; const char *line; }; struct state { size_t bufsize; char *buf; size_t index_size; struct index *index; struct index head; }; static void read_mountinfo(struct pollfd *pfd, char *buf, size_t bufsize) { int readcnt, backoff = 0, retry = 0; size_t len; ssize_t res; retry: if (lseek(pfd->fd, 0, SEEK_SET) == (off_t) -1) err(1, "lseek"); len = 0; readcnt = 0; do { if (len >= bufsize - 4096) errx(1, "buffer overrun"); res = read(pfd->fd, buf + len, bufsize - len); if (res == -1) err(1, "read"); len += res; if (!res || !(++readcnt % 16)) { if (poll(pfd, 1, 0) == -1) err(1, "poll/0"); if (pfd->revents & POLLPRI) { if (!backoff) { backoff++; goto retry; } if (!retry) { fprintf(stderr, "retry."); retry = 1; } do { usleep(backoff * 1000); if (backoff < 128) backoff *= 2; if (poll(pfd, 1, 0) == -1) err(1, "poll/0"); } while (pfd->revents & POLLPRI); goto retry; } } } while (res); buf[len] = '\0'; if (retry) { fprintf(stderr, "..\n"); retry = 0; } } static void add_index(struct state *s, struct index *this, const char *line) { struct index *prev = s->head.prev, *next = &s->head; if (this->line) errx(1, "index corruption"); this->line = line; this->next = next; this->prev = prev; prev->next = next->prev = this; } static void del_index(struct index *this) { struct index *prev = this->prev, *next = this->next; this->line = NULL; prev->next = next; next->prev = prev; } static void diff_mountinfo(struct state *old, struct state *cur) { char *line, *end; struct index *this; int mntid; cur->head.next = cur->head.prev = &cur->head; for (line = cur->buf; line[0]; line = end + 1) { end = strchr(line, '\n'); if (!end) errx(1, "parsing (1)"); *end = '\0'; if (sscanf(line, "%i", &mntid) != 1) errx(1, "parsing (2)"); if (mntid < 0 || (size_t) mntid >= cur->index_size) errx(1, "index overflow"); add_index(cur, &cur->index[mntid], line); this = &old->index[mntid]; if (this->line) { if (strcmp(this->line, line)) printf("* %s\n", line); del_index(this); } else { printf("+ %s\n", line); } } while (old->head.next != &old->head) { this = old->head.next; printf("- %s\n", this->line); del_index(this); } fflush(stdout); } int main(void) { struct state state[2], *old = &state[0], *cur = &state[1], *tmp; struct pollfd pfd = { .events = POLLPRI }; old->index_size = cur->index_size = 131072; old->bufsize = cur->bufsize = cur->index_size * 128; old->index = calloc(old->index_size, sizeof(struct index)); cur->index = calloc(cur->index_size, sizeof(struct index)); old->buf = malloc(old->bufsize); cur->buf = malloc(cur->bufsize); if (!old->index || !cur->index || !old->buf || !cur->buf) err(1, "allocating buffers"); old->buf[0] = '\0'; old->head.prev = old->head.next = &old->head; pfd.fd = open("/proc/self/mountinfo", O_RDONLY); if (pfd.fd == -1) err(1, "open"); while (1) { read_mountinfo(&pfd, cur->buf, cur->bufsize); diff_mountinfo(old, cur); tmp = old; old = cur; cur = tmp; if (poll(&pfd, 1, -1) == -1) err(1, "poll/inf"); } }