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