2 Unix SMB/Netbios implementation.
4 change notify handling - linux kernel based implementation
5 Copyright (C) Andrew Tridgell 2000
6 Copyright (C) Volker Lendecke 2007
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #if HAVE_KERNEL_CHANGE_NOTIFY
28 #define DN_ACCESS 0x00000001 /* File accessed in directory */
29 #define DN_MODIFY 0x00000002 /* File modified in directory */
30 #define DN_CREATE 0x00000004 /* File created in directory */
31 #define DN_DELETE 0x00000008 /* File removed from directory */
32 #define DN_RENAME 0x00000010 /* File renamed in directory */
33 #define DN_ATTRIB 0x00000020 /* File changed attribute */
34 #define DN_MULTISHOT 0x80000000 /* Don't remove notifier */
38 #ifndef RT_SIGNAL_NOTIFY
39 #define RT_SIGNAL_NOTIFY (SIGRTMIN+2)
50 /****************************************************************************
51 This is the structure to keep the information needed to
52 determine if a directory has changed.
53 *****************************************************************************/
56 struct dnotify_ctx *prev, *next;
62 static struct dnotify_ctx *dnotify_list;
63 static int dnotify_signal_pipe[2];
65 /****************************************************************************
66 The signal handler for change notify.
67 The Linux kernel has a bug in that we should be able to block any
68 further delivery of RT signals until the kernel_check_notify() function
69 unblocks them, but it seems that any signal mask we're setting here is
70 being overwritten on exit from this handler. I should create a standalone
71 test case for the kernel hackers. JRA.
72 *****************************************************************************/
74 static void dnotify_signal_handler(int sig, siginfo_t *info, void *unused)
79 * According to http://www.opengroup.org/onlinepubs/009695399/ write
80 * to a pipe either writes all or nothing, so we can safely write a
81 * full sizeof(int) and not risk the pipe to become out of sync with
84 * We don't care about the result of the write() call. If the pipe is
85 * full, then this signal is lost, we can't do anything about it.
89 write(dnotify_signal_pipe[1], (const void *)&info->si_fd, sizeof(int));
92 sys_select_signal(RT_SIGNAL_NOTIFY);
95 /****************************************************************************
96 The upper level handler informed when the pipe is ready for reading
97 *****************************************************************************/
99 static void dnotify_pipe_handler(struct event_context *event_ctx,
100 struct fd_event *event,
105 struct dnotify_ctx *ctx;
107 res = read(dnotify_signal_pipe[0], (void *)&fd, sizeof(int));
110 DEBUG(0, ("Read from the dnotify pipe failed: %s\n",
112 TALLOC_FREE(event); /* Don't try again */
116 if (res != sizeof(int)) {
117 smb_panic("read from dnotify pipe gave wrong number of "
121 for (ctx = dnotify_list; ctx; ctx = ctx->next) {
123 notify_fsp(ctx->fsp, 0, NULL);
128 /****************************************************************************
129 Register a change notify request.
130 *****************************************************************************/
132 static int kernel_register_notify(connection_struct *conn, char *path,
136 unsigned long kernel_flags;
138 fd = sys_open(path,O_RDONLY, 0);
141 DEBUG(3,("Failed to open directory %s for change notify\n",
146 if (sys_fcntl_long(fd, F_SETSIG, RT_SIGNAL_NOTIFY) == -1) {
147 DEBUG(3,("Failed to set signal handler for change notify\n"));
152 kernel_flags = DN_CREATE|DN_DELETE|DN_RENAME; /* creation/deletion
155 if (flags & FILE_NOTIFY_CHANGE_FILE_NAME) kernel_flags |= DN_MODIFY;
156 if (flags & FILE_NOTIFY_CHANGE_DIR_NAME) kernel_flags
159 if (flags & FILE_NOTIFY_CHANGE_ATTRIBUTES) kernel_flags |= DN_ATTRIB;
160 if (flags & FILE_NOTIFY_CHANGE_SIZE) kernel_flags |= DN_MODIFY;
161 if (flags & FILE_NOTIFY_CHANGE_LAST_WRITE) kernel_flags |= DN_MODIFY;
162 if (flags & FILE_NOTIFY_CHANGE_LAST_ACCESS) kernel_flags |= DN_ACCESS;
163 if (flags & FILE_NOTIFY_CHANGE_CREATION) kernel_flags |= DN_CREATE;
164 if (flags & FILE_NOTIFY_CHANGE_SECURITY) kernel_flags |= DN_ATTRIB;
165 if (flags & FILE_NOTIFY_CHANGE_EA) kernel_flags |= DN_ATTRIB;
166 if (flags & FILE_NOTIFY_CHANGE_FILE_NAME) kernel_flags
170 if (sys_fcntl_long(fd, F_NOTIFY, kernel_flags) == -1) {
171 DEBUG(3,("Failed to set async flag for change notify\n"));
176 DEBUG(3,("kernel change notify on %s (ntflags=0x%x flags=0x%x) "
177 "fd=%d\n", path, (int)flags, (int)kernel_flags, fd));
182 /****************************************************************************
183 See if the kernel supports change notify.
184 ****************************************************************************/
186 static BOOL kernel_notify_available(void)
189 fd = open("/tmp", O_RDONLY);
191 return False; /* uggh! */
192 ret = sys_fcntl_long(fd, F_NOTIFY, 0);
197 static int dnotify_ctx_destructor(struct dnotify_ctx *ctx)
200 DLIST_REMOVE(dnotify_list, ctx);
204 static void *kernel_notify_add(TALLOC_CTX *mem_ctx,
205 struct event_context *event_ctx,
209 struct dnotify_ctx *ctx;
211 if (!(ctx = TALLOC_P(mem_ctx, struct dnotify_ctx))) {
212 DEBUG(0, ("talloc failed\n"));
217 ctx->fd = kernel_register_notify(fsp->conn, fsp->fsp_name, *filter);
224 DLIST_ADD(dnotify_list, ctx);
225 talloc_set_destructor(ctx, dnotify_ctx_destructor);
230 /****************************************************************************
231 Setup kernel based change notify.
232 ****************************************************************************/
234 struct cnotify_fns *kernel_notify_init(struct event_context *event_ctx)
236 static struct cnotify_fns cnotify;
237 struct sigaction act;
239 if (pipe(dnotify_signal_pipe) == -1) {
240 DEBUG(0, ("Failed to create signal pipe: %s\n",
245 if ((set_blocking(dnotify_signal_pipe[0], False) == -1)
246 || (set_blocking(dnotify_signal_pipe[1], False) == -1)) {
247 DEBUG(0, ("Failed to set signal pipe to non-blocking: %s\n",
249 close(dnotify_signal_pipe[0]);
250 close(dnotify_signal_pipe[1]);
254 if (event_add_fd(event_ctx, NULL, dnotify_signal_pipe[0],
255 EVENT_FD_READ, dnotify_pipe_handler, NULL) == NULL) {
256 DEBUG(0, ("Failed to set signal event handler\n"));
257 close(dnotify_signal_pipe[0]);
258 close(dnotify_signal_pipe[1]);
264 act.sa_sigaction = dnotify_signal_handler;
265 act.sa_flags = SA_SIGINFO;
266 sigemptyset( &act.sa_mask );
267 if (sigaction(RT_SIGNAL_NOTIFY, &act, NULL) != 0) {
268 DEBUG(0,("Failed to setup RT_SIGNAL_NOTIFY handler\n"));
272 if (!kernel_notify_available())
275 cnotify.notify_add = kernel_notify_add;
277 /* the signal can start off blocked due to a bug in bash */
278 BlockSignals(False, RT_SIGNAL_NOTIFY);
284 void notify_kernel_dummy(void);
286 void notify_kernel_dummy(void) {}
287 #endif /* HAVE_KERNEL_CHANGE_NOTIFY */