diff options
Diffstat (limited to 'fs/notify/fanotify/fanotify_user.c')
-rw-r--r-- | fs/notify/fanotify/fanotify_user.c | 61 |
1 files changed, 60 insertions, 1 deletions
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index cf176fc7086b..67c0b5e4a488 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c | |||
@@ -1,13 +1,72 @@ | |||
1 | #include <linux/fcntl.h> | 1 | #include <linux/fcntl.h> |
2 | #include <linux/fs.h> | 2 | #include <linux/fs.h> |
3 | #include <linux/anon_inodes.h> | ||
3 | #include <linux/fsnotify_backend.h> | 4 | #include <linux/fsnotify_backend.h> |
4 | #include <linux/security.h> | 5 | #include <linux/security.h> |
5 | #include <linux/syscalls.h> | 6 | #include <linux/syscalls.h> |
6 | 7 | ||
7 | #include "fanotify.h" | 8 | #include "fanotify.h" |
8 | 9 | ||
10 | static int fanotify_release(struct inode *ignored, struct file *file) | ||
11 | { | ||
12 | struct fsnotify_group *group = file->private_data; | ||
13 | |||
14 | pr_debug("%s: file=%p group=%p\n", __func__, file, group); | ||
15 | |||
16 | /* matches the fanotify_init->fsnotify_alloc_group */ | ||
17 | fsnotify_put_group(group); | ||
18 | |||
19 | return 0; | ||
20 | } | ||
21 | |||
22 | static const struct file_operations fanotify_fops = { | ||
23 | .poll = NULL, | ||
24 | .read = NULL, | ||
25 | .fasync = NULL, | ||
26 | .release = fanotify_release, | ||
27 | .unlocked_ioctl = NULL, | ||
28 | .compat_ioctl = NULL, | ||
29 | }; | ||
30 | |||
31 | /* fanotify syscalls */ | ||
9 | SYSCALL_DEFINE3(fanotify_init, unsigned int, flags, unsigned int, event_f_flags, | 32 | SYSCALL_DEFINE3(fanotify_init, unsigned int, flags, unsigned int, event_f_flags, |
10 | unsigned int, priority) | 33 | unsigned int, priority) |
11 | { | 34 | { |
12 | return -ENOSYS; | 35 | struct fsnotify_group *group; |
36 | int f_flags, fd; | ||
37 | |||
38 | pr_debug("%s: flags=%d event_f_flags=%d priority=%d\n", | ||
39 | __func__, flags, event_f_flags, priority); | ||
40 | |||
41 | if (event_f_flags) | ||
42 | return -EINVAL; | ||
43 | if (priority) | ||
44 | return -EINVAL; | ||
45 | |||
46 | if (!capable(CAP_SYS_ADMIN)) | ||
47 | return -EACCES; | ||
48 | |||
49 | if (flags & ~FAN_ALL_INIT_FLAGS) | ||
50 | return -EINVAL; | ||
51 | |||
52 | f_flags = (O_RDONLY | FMODE_NONOTIFY); | ||
53 | if (flags & FAN_CLOEXEC) | ||
54 | f_flags |= O_CLOEXEC; | ||
55 | if (flags & FAN_NONBLOCK) | ||
56 | f_flags |= O_NONBLOCK; | ||
57 | |||
58 | /* fsnotify_alloc_group takes a ref. Dropped in fanotify_release */ | ||
59 | group = fsnotify_alloc_group(&fanotify_fsnotify_ops); | ||
60 | if (IS_ERR(group)) | ||
61 | return PTR_ERR(group); | ||
62 | |||
63 | fd = anon_inode_getfd("[fanotify]", &fanotify_fops, group, f_flags); | ||
64 | if (fd < 0) | ||
65 | goto out_put_group; | ||
66 | |||
67 | return fd; | ||
68 | |||
69 | out_put_group: | ||
70 | fsnotify_put_group(group); | ||
71 | return fd; | ||
13 | } | 72 | } |