xref: /freebsd/sys/sys/inotify.h (revision 3965de642c29d831649c8307203303de560d721a)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2025 Klara, Inc.
5  */
6 
7 #ifndef _INOTIFY_H_
8 #define _INOTIFY_H_
9 
10 #include <sys/_types.h>
11 
12 /* Flags for inotify_init1(). */
13 #define	IN_NONBLOCK	0x00000004	/* O_NONBLOCK */
14 #define	IN_CLOEXEC	0x00100000	/* O_CLOEXEC */
15 
16 struct inotify_event {
17 	int		wd;
18 	__uint32_t	mask;
19 	__uint32_t	cookie;
20 	__uint32_t	len;
21 	char		name[0];
22 };
23 
24 /* Events, set in the mask field. */
25 #define	IN_ACCESS		0x00000001
26 #define	IN_MODIFY		0x00000002
27 #define	IN_ATTRIB		0x00000004
28 #define	IN_CLOSE_WRITE		0x00000008
29 #define	IN_CLOSE_NOWRITE	0x00000010
30 #define	IN_CLOSE		(IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)
31 #define	IN_OPEN			0x00000020
32 #define	IN_MOVED_FROM		0x00000040
33 #define	IN_MOVED_TO		0x00000080
34 #define	IN_MOVE			(IN_MOVED_FROM | IN_MOVED_TO)
35 #define	IN_CREATE		0x00000100
36 #define	IN_DELETE		0x00000200
37 #define	IN_DELETE_SELF		0x00000400
38 #define	IN_MOVE_SELF		0x00000800
39 #define	IN_ALL_EVENTS		0x00000fff
40 
41 /* Events report only for entries in a watched dir, not the dir itself. */
42 #define	_IN_DIR_EVENTS		(IN_CLOSE_WRITE | IN_DELETE | IN_MODIFY | \
43 				 IN_MOVED_FROM | IN_MOVED_TO)
44 
45 #ifdef _KERNEL
46 /*
47  * An unlink that's done as part of a rename only records IN_DELETE if the
48  * unlinked vnode itself is watched, and not when the containing directory is
49  * watched.
50  */
51 #define	_IN_MOVE_DELETE		0x40000000
52 /*
53  * Inode link count changes only trigger IN_ATTRIB events if the inode itself is
54  * watched, and not when the containing directory is watched.
55  */
56 #define	_IN_ATTRIB_LINKCOUNT	0x80000000
57 #endif
58 
59 /* Flags, set in the mask field. */
60 #define	IN_ONLYDIR		0x01000000
61 #define	IN_DONT_FOLLOW		0x02000000
62 #define	IN_EXCL_UNLINK		0x04000000
63 #define	IN_MASK_CREATE		0x10000000
64 #define	IN_MASK_ADD		0x20000000
65 #define	IN_ONESHOT		0x80000000
66 #define	_IN_ALL_FLAGS		(IN_ONLYDIR | IN_DONT_FOLLOW |		\
67 				 IN_EXCL_UNLINK | IN_MASK_CREATE |	\
68 				 IN_MASK_ADD | IN_ONESHOT)
69 
70 /* Flags returned by the kernel. */
71 #define	IN_UNMOUNT		0x00002000
72 #define	IN_Q_OVERFLOW		0x00004000
73 #define	IN_IGNORED		0x00008000
74 #define	IN_ISDIR		0x40000000
75 #define	_IN_ALL_RETFLAGS	(IN_Q_OVERFLOW | IN_UNMOUNT | IN_IGNORED | \
76 				 IN_ISDIR)
77 
78 #define	_IN_ALIGN		_Alignof(struct inotify_event)
79 #define	_IN_NAMESIZE(namelen)	\
80 	((namelen) == 0 ? 0 : __align_up((namelen) + 1, _IN_ALIGN))
81 
82 #ifdef _KERNEL
83 struct componentname;
84 struct file;
85 struct inotify_softc;
86 struct thread;
87 struct vnode;
88 
89 int	inotify_create_file(struct thread *, struct file *, int, int *);
90 void	inotify_log(struct vnode *, const char *, size_t, int, __uint32_t);
91 
92 int	kern_inotify_rm_watch(int, uint32_t, struct thread *);
93 int	kern_inotify_add_watch(int, int, const char *, uint32_t,
94 	    struct thread *);
95 
96 void	vn_inotify(struct vnode *, struct vnode *, struct componentname *, int,
97 	    uint32_t);
98 int	vn_inotify_add_watch(struct vnode *, struct inotify_softc *,
99 	    __uint32_t, __uint32_t *, struct thread *);
100 void	vn_inotify_revoke(struct vnode *);
101 
102 /* Log an inotify event. */
103 #define	INOTIFY(vp, ev) do {						\
104 	if (__predict_false((vn_irflag_read(vp) & (VIRF_INOTIFY |	\
105 	    VIRF_INOTIFY_PARENT)) != 0))				\
106 		VOP_INOTIFY((vp), NULL, NULL, (ev), 0);			\
107 } while (0)
108 
109 /* Log an inotify event using a specific name for the vnode. */
110 #define	INOTIFY_NAME(vp, dvp, cnp, ev) do {				\
111 	if (__predict_false((vn_irflag_read(vp) & VIRF_INOTIFY) != 0 ||	\
112 	    (vn_irflag_read(dvp) & VIRF_INOTIFY) != 0)) 		\
113 		VOP_INOTIFY((vp), (dvp), (cnp), (ev), 0);		\
114 } while (0)
115 
116 extern __uint32_t inotify_rename_cookie;
117 
118 #define	INOTIFY_MOVE(vp, fdvp, fcnp, tvp, tdvp, tcnp) do {		\
119 	if (__predict_false((vn_irflag_read(fdvp) & VIRF_INOTIFY) != 0 || \
120 	    (vn_irflag_read(tdvp) & VIRF_INOTIFY) != 0 ||		\
121 	    (vn_irflag_read(vp) & VIRF_INOTIFY) != 0)) {		\
122 		__uint32_t cookie;					\
123 									\
124 		cookie = atomic_fetchadd_32(&inotify_rename_cookie, 1);	\
125 		VOP_INOTIFY((vp), (fdvp), (fcnp), IN_MOVED_FROM, cookie); \
126 		VOP_INOTIFY((vp), (tdvp), (tcnp), IN_MOVED_TO, cookie);	\
127 	}								\
128 	if ((tvp) != NULL)						\
129 		INOTIFY_NAME((tvp), (tdvp), (tcnp), _IN_MOVE_DELETE);	\
130 } while (0)
131 
132 #define	INOTIFY_REVOKE(vp) do {						\
133 	if (__predict_false((vn_irflag_read(vp) & VIRF_INOTIFY) != 0))	\
134 		vn_inotify_revoke((vp));				\
135 } while (0)
136 
137 #else
138 #include <sys/cdefs.h>
139 
140 __BEGIN_DECLS
141 int	inotify_init(void);
142 int	inotify_init1(int flags);
143 int	inotify_add_watch(int fd, const char *pathname, __uint32_t mask);
144 int	inotify_add_watch_at(int fd, int dfd, const char *pathname,
145 	    __uint32_t mask);
146 int	inotify_rm_watch(int fd, int wd);
147 __END_DECLS
148 #endif /* !_KERNEL */
149 
150 #endif /* !_INOTIFY_H_ */
151