This commit adds implementation of fanotify_init and fanotify_mark.
Second argument for fanotify_init needs conversion because of flags
which can be FAN_NONBLOCK and FAN_CLOEXEC which rely on O_NONBLOCK
and O_CLOEXEC and those can have different values on different platforms.
For fanotify_mark argument layout is different for 32-bit and 64-bit
platforms and this implementation have support for that situation.
Also, support for writing and reading of file descriptor opened by
fanotify_init is added.
Configure file contains checks for excistence of fanotify support on
given build system.

Signed-off-by: Lena Djokic <lena.djo...@rt-rk.com>
---
 configure            |  20 ++++++++
 linux-user/syscall.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 142 insertions(+), 4 deletions(-)

diff --git a/configure b/configure
index fd6f898..56e6c98 100755
--- a/configure
+++ b/configure
@@ -3537,6 +3537,23 @@ if compile_prog "" "" ; then
   inotify1=yes
 fi
 
+# check if fanotify group of system calls is supported
+fanotify=no
+cat > $TMPC << EOF
+#include <sys/fanotify.h>
+
+int
+main(void)
+{
+    fanotify_init(0,0);
+    fanotify_mark(0,0,0,0,0);
+    return 0;
+}
+EOF
+if compile_prog "" "" ; then
+  fanotify=yes
+fi
+
 # check if utimensat and futimens are supported
 utimens=no
 cat > $TMPC << EOF
@@ -5335,6 +5352,9 @@ fi
 if test "$inotify1" = "yes" ; then
   echo "CONFIG_INOTIFY1=y" >> $config_host_mak
 fi
+if test "$fanotify" = "yes" ; then
+  echo "CONFIG_FANOTIFY=y" >> $config_host_mak
+fi
 if test "$byteswap_h" = "yes" ; then
   echo "CONFIG_BYTESWAP_H=y" >> $config_host_mak
 fi
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 7b77503..f5d9a26 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -76,6 +76,9 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
 #ifdef CONFIG_SENDFILE
 #include <sys/sendfile.h>
 #endif
+#ifdef CONFIG_FANOTIFY
+#include <sys/fanotify.h>
+#endif
 
 #define termios host_termios
 #define winsize host_winsize
@@ -499,9 +502,13 @@ enum {
     QEMU___IFLA_INET6_MAX
 };
 
+typedef abi_long (*TargetFdReadFunc)(void *, size_t);
+typedef abi_long (*TargetFdWriteFunc)(void *, size_t);
 typedef abi_long (*TargetFdDataFunc)(void *, size_t);
 typedef abi_long (*TargetFdAddrFunc)(void *, abi_ulong, socklen_t);
 typedef struct TargetFdTrans {
+    TargetFdReadFunc read_op;
+    TargetFdWriteFunc write_op;
     TargetFdDataFunc host_to_target_data;
     TargetFdDataFunc target_to_host_data;
     TargetFdAddrFunc target_to_host_addr;
@@ -511,6 +518,22 @@ static TargetFdTrans **target_fd_trans;
 
 static unsigned int target_fd_max;
 
+static TargetFdReadFunc fd_trans_read_op(int fd)
+{
+    if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
+        return target_fd_trans[fd]->read_op;
+    }
+    return NULL;
+}
+
+static TargetFdWriteFunc fd_trans_write_op(int fd)
+{
+    if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
+        return target_fd_trans[fd]->write_op;
+    }
+    return NULL;
+}
+
 static TargetFdDataFunc fd_trans_target_to_host_data(int fd)
 {
     if (fd >= 0 && fd < target_fd_max && target_fd_trans[fd]) {
@@ -7527,6 +7550,47 @@ static target_timer_t get_timer_id(abi_long arg)
     return timerid;
 }
 
+#if defined(CONFIG_FANOTIFY)
+static inline abi_long fanotify_fd_read_op(void *buf, size_t len)
+{
+    struct fanotify_event_metadata *fem;
+    int num;
+
+    /* Read buffer for fanotify file descriptor contains one or more
+     * of fanotify_event_metadata structures.
+     */
+    fem = (struct fanotify_event_metadata *)buf;
+    num = len / sizeof(struct fanotify_event_metadata);
+    for (int i = 0; i < num; i++) {
+        (fem + i)->event_len = tswap32((fem + i)->event_len);
+        /* Fields (fem+i)->vers and (fem+i)->reserved are single byte,
+         * so swapping is not needed for them.
+         */
+        (fem + i)->metadata_len = tswap16((fem + i)->metadata_len);
+        (fem + i)->mask = tswap64((fem + i)->mask);
+        (fem + i)->fd = tswap32((fem + i)->fd);
+        (fem + i)->pid = tswap32((fem + i)->pid);
+    }
+
+    return len;
+}
+
+static inline abi_long fanotify_fd_write_op(void *buf, size_t len)
+{
+    struct fanotify_response *fr = (struct fanotify_response *)buf;
+
+    fr->fd = tswap32(fr->fd);
+    fr->response = tswap32(fr->response);
+
+    return len;
+}
+
+static TargetFdTrans fanotify_trans = {
+    .read_op = fanotify_fd_read_op,
+    .write_op = fanotify_fd_write_op,
+};
+#endif
+
 /* do_syscall() should always have a single exit point at the end so
    that actions, such as logging of syscall results, can be performed.
    All errnos that do_syscall() returns must be -TARGET_<errcode>. */
@@ -7613,16 +7677,27 @@ abi_long do_syscall(void *cpu_env, int num, abi_long 
arg1,
             if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
                 goto efault;
             ret = get_errno(safe_read(arg1, p, arg3));
-            if (ret >= 0 &&
-                fd_trans_host_to_target_data(arg1)) {
-                ret = fd_trans_host_to_target_data(arg1)(p, ret);
-            }
+            if (ret >= 0) {
+                if (fd_trans_read_op(arg1)) {
+                    ret = fd_trans_read_op(arg1)(p, ret);
+                }
+                if (fd_trans_host_to_target_data(arg1)) {
+                    ret = fd_trans_host_to_target_data(arg1)(p, ret);
+                }
+             }
             unlock_user(p, arg2, ret);
         }
         break;
     case TARGET_NR_write:
         if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1)))
             goto efault;
+        if (fd_trans_write_op(arg1)) {
+            ret = fd_trans_write_op(arg1)(p, arg3);
+            if (is_error(ret)) {
+                unlock_user(p, arg2, 0);
+                break;
+            }
+        }
         ret = get_errno(safe_write(arg1, p, arg3));
         unlock_user(p, arg2, 0);
         break;
@@ -11567,6 +11642,49 @@ abi_long do_syscall(void *cpu_env, int num, abi_long 
arg1,
         break;
 #endif
 
+#if defined(TARGET_NR_fanotify_init) && defined(CONFIG_FANOTIFY)
+    case TARGET_NR_fanotify_init:
+        {
+            ret = get_errno(fanotify_init(arg1, target_to_host_bitmask(arg2,
+                                                fcntl_flags_tbl)));
+            if (ret >= 0) {
+                fd_trans_register(ret, &fanotify_trans);
+            }
+        }
+        break;
+#endif
+#if defined(TARGET_NR_fanotify_mark) && defined(CONFIG_FANOTIFY)
+    case TARGET_NR_fanotify_mark:
+        {
+            p = NULL;
+#if (TARGET_ABI_BITS == 32)
+            if (arg6) {
+                p = lock_user_string(arg6);
+                if (!p) {
+                    goto efault;
+                }
+            }
+            ret = get_errno(fanotify_mark(arg1, arg2,
+                                target_offset64(arg3, arg4), arg5 , p));
+            if (arg6) {
+                unlock_user(p, arg6, 0);
+            }
+#else
+            if (arg5) {
+                p = lock_user_string(arg5);
+                if (!p) {
+                    goto efault;
+                }
+            }
+            ret = get_errno(fanotify_mark(arg1, arg2, arg3, arg4 , p));
+            if (arg5) {
+                unlock_user(p, arg5, 0);
+            }
+#endif
+        }
+        break;
+#endif
+
 #if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
     case TARGET_NR_mq_open:
         {
-- 
2.7.4


Reply via email to