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

Reply via email to