RPM Package Manager, CVS Repository http://rpm5.org/cvs/ ____________________________________________________________________________
Server: rpm5.org Name: Jeff Johnson Root: /v/rpm/cvs Email: j...@rpm5.org Module: rpm Date: 23-May-2017 06:53:56 Branch: rpm-5_4 Handle: 2017052304535600 Modified files: (Branch: rpm-5_4) rpm/rpmio fanotify.c Log: - Odd C dialect ... let's go shopping. Summary: Revision Changes Path 1.1.2.2 +203 -169 rpm/rpmio/fanotify.c ____________________________________________________________________________ patch -p0 <<'@@ .' Index: rpm/rpmio/fanotify.c ============================================================================ $ cvs diff -u -r1.1.2.1 -r1.1.2.2 fanotify.c --- rpm/rpmio/fanotify.c 23 May 2017 02:58:11 -0000 1.1.2.1 +++ rpm/rpmio/fanotify.c 23 May 2017 04:53:56 -0000 1.1.2.2 @@ -13,15 +13,15 @@ * limitations under the License. */ -#include <errno.h> -#include <fcntl.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> +#include "system.h" + +#if defined(HAVE_SYS_FANOTIFY_H) #include <sys/fanotify.h> +#endif + +#include "debug.h" -char const USAGE[] = +const char USAGE[] = "Usage: fanotify [FLAGS PATH]... [FLAGS]\n" "Watch a directory or filesytem using fanotify\n\n" "If no path is supplied then watch the current directory\n\n" @@ -35,197 +35,231 @@ struct flag { uint64_t mask; - const char * name; + const char *name; }; -static unsigned const MASK_COUNT = 8; - -static struct flag const MASKS[8] = { - {FAN_OPEN, "OPEN"}, - {FAN_ACCESS, "ACCESS"}, - {FAN_MODIFY, "MODIFY"}, - {FAN_CLOSE, "CLOSE"}, - {FAN_CLOSE_WRITE, "CLOSE_WRITE"}, - {FAN_CLOSE_NOWRITE, "CLOSE_NOWRITE"}, - {FAN_ONDIR, "ONDIR"}, - {FAN_EVENT_ON_CHILD, "EVENT_ON_CHILD"}, +static const struct flag MASKS[8] = { +#define _ENTRY(_v) { FAN_##_v, #_v, } + _ENTRY(OPEN), + _ENTRY(ACCESS), + _ENTRY(MODIFY), + _ENTRY(CLOSE), + _ENTRY(CLOSE_WRITE), + _ENTRY(CLOSE_NOWRITE), + _ENTRY(ONDIR), + _ENTRY(EVENT_ON_CHILD), +#undef _ENTRY }; +static const unsigned int MASK_COUNT = sizeof(MASKS)/sizeof(MASKS[0]); -static const unsigned int FLAG_COUNT = 4; - -static struct flag const FLAGS[4] = { - {FAN_MARK_DONT_FOLLOW, "DONT_FOLLOW"}, - {FAN_MARK_ONLYDIR, "ONLYDIR"}, - {FAN_MARK_MOUNT, "MOUNT"}, - {FAN_MARK_IGNORED_MASK, "IGNORE"}, +static const struct flag FLAGS[] = { +#define _ENTRY(_v) { FAN_MARK_##_v, #_v, } + _ENTRY(DONT_FOLLOW), + _ENTRY(ONLYDIR), + _ENTRY(MOUNT), + _ENTRY(IGNORED_MASK), +#undef _ENTRY }; +static const unsigned int FLAG_COUNT = sizeof(FLAGS)/sizeof(FLAGS[0]); - -char PROC_SELF_FD[32] = "/proc/self/fd/"; -char INPUT_BUFFER[4096]; -char OUTPUT_BUFFER[4096]; - - -uint64_t parse_flags( - struct flag const * flags, unsigned flag_count, char const * pos -) { +uint64_t parse_flags(const struct flag *flags, unsigned flag_count, + const char *pos) +{ uint64_t mask = 0; unsigned j; - char const * next = pos; + char const *next = pos; + while (*next) { - /* Scan through the ',' separated list of flags */ - next = strchr(pos, ','); - if (!next) { next = pos + strlen(pos); } - for (j = 0; j < flag_count; ++j) { - if ((strlen(flags[j].name) == (next - pos)) - && (strncmp(flags[j].name, pos, next - pos) == 0)) { - /* If the flag has a name we know then add it to the mask */ - mask |= flags[j].mask; - break; - } - } - if (j == flag_count) { - /* If we don't know what the flag is then exit */ - write(2, OUTPUT_BUFFER, snprintf( - OUTPUT_BUFFER, sizeof(OUTPUT_BUFFER), - "Unknown value: \"%*s\"\nPossible values are:\n", - (int)(next - pos), pos - )); - for (j = 0; j < flag_count; ++j) { - write(2, OUTPUT_BUFFER, snprintf( - OUTPUT_BUFFER, sizeof(OUTPUT_BUFFER), - " %s\n", flags[j].name - )); - } - exit(1); - } - pos = next + 1; + /* Scan through the ',' separated list of flags */ + next = strchr(pos, ','); + if (!next) + next = pos + strlen(pos); + + for (j = 0; j < flag_count; ++j) { + const struct flag *fp = flags + j; + if (((int) strlen(fp->name) == (next - pos)) + && (strncmp(fp->name, pos, (next - pos)) == 0)) { + /* If the flag has a name we know then add it to the mask */ + mask |= fp->mask; + break; + } + } + if (j == flag_count) { + /* If we don't know what the flag is then exit */ + fprintf(stderr, "Unknown value: \"%*s\"\nPossible values are:\n", + (int) (next - pos), pos); + for (j = 0; j < flag_count; ++j) + fprintf(stderr, " %s\n", flags[j].name); + exit(1); + } + pos = next + 1; } return mask; } -char * print_flags( - char * output, char * output_end, - struct flag const * flags, unsigned flag_count, uint64_t mask -) { - unsigned j; +char *print_flags(char *te, char *tend, + const struct flag *flags, unsigned flag_count, + uint64_t mask) +{ /* If the mask is empty then we don't print anything. */ - if (!mask) return output; - for (j = 0; j < flag_count; ++j) { - if ((flags[j].mask & mask) == flags[j].mask ) { - /* Print the name of the bits */ - size_t length = strlen(flags[j].name); - if (output_end - output < length) length = output_end - output; - memcpy(output, flags[j].name, length); - output += length; - if (output != output_end) { *(output++) = '|'; } - /* Remove the bits from the mask. */ - mask &= ~flags[j].mask; - } + if (!mask) + goto exit; + + for (unsigned j = 0; j < flag_count; ++j) { + const struct flag *fp = flags + j; + if ((fp->mask & mask) != fp->mask) + continue; + /* Print the name of the bits */ + size_t length = strlen(fp->name); + if ((tend - te) < (int) length) + length = (tend - te); + memcpy(te, fp->name, length); + te += length; + if (te < tend) + *te++ = '|'; + /* Remove the bits from the mask. */ + mask &= ~fp->mask; } + if (mask) { - /* The mask contained some bits we don't know about. Print it as hex */ - output += snprintf( - output, output_end - output, "0x%llx", (long long) mask - ); + /* The mask contained some bits we don't know about. Print it as hex */ + te += snprintf(te, (tend - te), "0x%llx", (long long) mask); } else { - /* We have written a trailing '|' character since the mask is set and - * we known what all the bits mean. So we can safely move output one - * character back to remove the trailing '|' */ - --output; + /* We have written a trailing '|' character since the mask is set and + * we known what all the bits mean. So we can safely move te one + * character back to remove the trailing '|' */ + --te; } - return output; + +exit: + return te; } +int main(int argc, char const *argv[]) +{ + int ec = 1; /* assume failure */ + int rc; -int main(int argc, char const * argv[]) { - int fanfd, i, result, cwdfd; if (argc == 1) { - write(2, USAGE, sizeof(USAGE) - 1); exit(1); + fprintf(stdout, "%s", USAGE); + goto exit; } - /* Create a fanotify_fd. We only need to be notified about events, and - * we only want to read the files. */ - fanfd = fanotify_init(FAN_CLASS_NOTIF, O_RDONLY); + + /* + * Create a fanotify_fd. We only need to be notified about events, and + * we only want to read the files. + */ + int fanfd = fanotify_init(FAN_CLASS_NOTIF, O_RDONLY); if (fanfd < 0) { - perror("fanotify_init"); - /* The most likely reason to fail here is that we don't have - * the CAP_SYS_ADMIN cabability needed by fanotify_init */ - if (errno == EPERM) { - write(2, OUTPUT_BUFFER, snprintf( - OUTPUT_BUFFER, sizeof(OUTPUT_BUFFER), - "fanotify needs to be run as root\n" - )); - } - exit(1); + /* + * The most likely reason to fail here is that we don't have + * the CAP_SYS_ADMIN cabability needed by fanotify_init + */ + if (errno == EPERM) + fprintf(stderr, "fanotify needs to be run as root\n"); + else + perror("fanotify_init"); + goto exit; } - /* In theory fanotify_mark should be able to take AT_FDCWD for the dirfd. + + /* + * In theory fanotify_mark should be able to take AT_FDCWD for the dirfd. * However it seems to complain if we pass AT_FDCWD to it. So instead we - * open the current working directory and pass the resulting fd. */ - cwdfd = openat(AT_FDCWD, ".", O_RDONLY | O_DIRECTORY); - if (cwdfd < 0) { perror("open"); exit(1); } - for(i = 1; i < argc; ++i) { - /* Parse the mask bits from the first argument */ - uint64_t mask = parse_flags(MASKS, MASK_COUNT, argv[i]); - unsigned int flags = FAN_MARK_ADD; - char const * path = "."; - /* Then parse the flags bits from the second argument */ - if ((++i) < argc) flags |= parse_flags(FLAGS, FLAG_COUNT, argv[i]); - /* Then optionally set path using the third argument */ - if ((++i) < argc) path = argv[i]; - result = fanotify_mark(fanfd, flags, mask, cwdfd, path); - if (result < 0) { perror("fanotify_mark"); exit(1); } + * open the current working directory and pass the resulting fd. + */ + int cwdfd = openat(AT_FDCWD, ".", O_RDONLY | O_DIRECTORY); + if (cwdfd < 0) { + perror("openat"); + goto exit; + } + + for (int i = 1; i < argc; ++i) { + /* Parse the mask bits from the first argument */ + uint64_t mask = parse_flags(MASKS, MASK_COUNT, argv[i]); + unsigned int flags = FAN_MARK_ADD; + char const *path = "."; + /* Then parse the flags bits from the second argument */ + if (++i < argc) + flags |= parse_flags(FLAGS, FLAG_COUNT, argv[i]); + /* Then optionally set path using the third argument */ + if (++i < argc) + path = argv[i]; + rc = fanotify_mark(fanfd, flags, mask, cwdfd, path); + if (rc < 0) { + perror("fanotify_mark"); + goto exit; + } } + close(cwdfd); for (;;) { - ssize_t count = read(fanfd, INPUT_BUFFER, sizeof(INPUT_BUFFER)); - if (count < 0) { perror("read"); exit(1); } - char * input = INPUT_BUFFER; - char * input_end = input + count; - struct fanotify_event_metadata * event; - while (input != input_end) { - char * output = OUTPUT_BUFFER; - /* Leave space at the end of the output buffer for a '\n' */ - char * output_end = output + sizeof(OUTPUT_BUFFER) - 1; - unsigned j; - /* Check that we have enough input read an event structure. */ - if (input_end - input < sizeof(struct fanotify_event_metadata)) { - perror("Invalid fanotify_event_meta"); exit(1); - } - event = (struct fanotify_event_metadata *) input; - /* Check that we have all of the event structure and that it's - * a version that we understand */ - if (input_end - input < event->event_len || - event->vers != FANOTIFY_METADATA_VERSION) { - perror("Invalid fanotify_event_meta"); exit(1); - } - /* Print the event mask. Each bit will be separated by '|' - * characters. */ - output = print_flags( - output, output_end, MASKS, MASK_COUNT, event->mask - ); - /* Print the pid of the process that this is event is from */ - output += snprintf( - output, output_end - output, " %d ", event->pid - ); - /* We aren't told the path of the event directly. But we can read - * the /proc/self/fd/%d symlink to see what path the file - * descriptor was opened with */ - snprintf( - PROC_SELF_FD, sizeof(PROC_SELF_FD), - "/proc/self/fd/%d", event->fd - ); - count = readlink(PROC_SELF_FD, output, output_end - output); - if (count < 0) { perror("readlink"); exit(1); } - output += count; - /* Add a newline to the end. This is always safe because we left - * ourselves a byte of space when picking output_end */ - *(output++) = '\n'; - write(1, OUTPUT_BUFFER, output - OUTPUT_BUFFER); - /* Close the event's file descriptor. */ - close(event->fd); - /* Advance to the next event in the input buffer */ - input += event->event_len; - } + char s[BUFSIZ]; + size_t ns = sizeof(s); + char *se = s; + + ssize_t nr = read(fanfd, s, ns); + if (nr < 0) { + perror("read"); + exit(1); + } + char *send = s + nr; + + while (se < send) { + struct fanotify_event_metadata * event + = (struct fanotify_event_metadata *) se; + char t[BUFSIZ]; + size_t nt = sizeof(t); + char *te = t; + /* Leave space at the end of the output buffer for a '\n' */ + char *tend = t + nt - 1; + + /* Check that we have enough input read an event structure. */ + if ((send - se) < (int) sizeof(*event)) { + perror("Invalid fanotify_event_meta"); + goto exit; + } + + /* Check that we have all of the event structure and that it's + * a version that we understand */ + if ((send - s) < event->event_len + || event->vers != FANOTIFY_METADATA_VERSION) + { + perror("Invalid fanotify_event_meta"); + goto exit; + } + + /* Print the event mask. Each bit will be separated by '|' + * characters. */ + te = print_flags(te, tend, MASKS, MASK_COUNT, event->mask); + + /* Print the pid of the process that this is event is from */ + te += snprintf(te, (tend - te), " %d ", event->pid); + + /* We aren't told the path of the event directly. But we can read + * the /proc/self/fd/%d symlink to see what path the file + * descriptor was opened with */ + char fn[32]; + snprintf(fn, sizeof(fn), "/proc/self/fd/%d", event->fd); + nr = readlink(fn, te, (tend - te)); + if (nr < 0) { + perror("readlink"); + goto exit; + } + te += nr; + *te = '\0'; + + fprintf(stdout, "%s\n", t); + + /* Close the event's file descriptor. */ + close(event->fd); + + /* Advance to the next event in the input buffer */ + se += event->event_len; + } } + ec = 0; + +exit: + return ec; } @@ . ______________________________________________________________________ RPM Package Manager http://rpm5.org CVS Sources Repository rpm-cvs@rpm5.org