2 * Unix SMB/CIFS implementation.
4 * Copyright (C) Volker Lendecke 2014
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "librpc/gen_ndr/notify.h"
22 #include "librpc/gen_ndr/messaging.h"
23 #include "lib/dbwrap/dbwrap.h"
24 #include "lib/dbwrap/dbwrap_rbt.h"
30 #include "lib/util/server_id_db.h"
31 #include "smbd/notifyd/notifyd.h"
34 struct notify_list
*next
, *prev
;
35 void (*callback
)(void *private_data
, struct timespec when
,
36 const struct notify_event
*ctx
);
41 struct notify_context
{
42 struct server_id notifyd
;
43 struct messaging_context
*msg_ctx
;
44 struct notify_list
*list
;
47 static void notify_handler(struct messaging_context
*msg
, void *private_data
,
48 uint32_t msg_type
, struct server_id src
,
51 struct notify_context
*notify_init(TALLOC_CTX
*mem_ctx
,
52 struct messaging_context
*msg
,
53 struct tevent_context
*ev
)
55 struct server_id_db
*names_db
;
56 struct notify_context
*ctx
;
59 ctx
= talloc(mem_ctx
, struct notify_context
);
66 names_db
= messaging_names_db(msg
);
67 if (!server_id_db_lookup_one(names_db
, "notify-daemon",
69 DEBUG(1, ("No notify daemon around\n"));
74 status
= messaging_register(msg
, ctx
, MSG_PVFS_NOTIFY
, notify_handler
);
75 if (!NT_STATUS_IS_OK(status
)) {
76 DEBUG(1, ("messaging_register failed: %s\n",
85 static void notify_handler(struct messaging_context
*msg
, void *private_data
,
86 uint32_t msg_type
, struct server_id src
,
89 struct notify_context
*ctx
= talloc_get_type_abort(
90 private_data
, struct notify_context
);
91 struct notify_event_msg
*event_msg
;
92 struct notify_event event
;
93 struct notify_list
*listel
;
95 if (data
->length
< offsetof(struct notify_event_msg
, path
) + 1) {
96 DEBUG(1, ("message too short: %u\n", (unsigned)data
->length
));
99 if (data
->data
[data
->length
-1] != 0) {
100 DEBUG(1, ("%s: path not 0-terminated\n", __func__
));
104 event_msg
= (struct notify_event_msg
*)data
->data
;
106 event
.action
= event_msg
->action
;
107 event
.path
= event_msg
->path
;
108 event
.private_data
= event_msg
->private_data
;
110 DEBUG(10, ("%s: Got notify_event action=%u, private_data=%p, "
111 "path=%s\n", __func__
, (unsigned)event
.action
,
112 event
.private_data
, event
.path
));
114 for (listel
= ctx
->list
; listel
!= NULL
; listel
= listel
->next
) {
115 if (listel
->private_data
== event
.private_data
) {
116 listel
->callback(listel
->private_data
, event_msg
->when
,
123 NTSTATUS
notify_add(struct notify_context
*ctx
,
124 const char *path
, uint32_t filter
, uint32_t subdir_filter
,
125 void (*callback
)(void *, struct timespec
,
126 const struct notify_event
*),
129 struct notify_list
*listel
;
130 struct notify_rec_change_msg msg
= {};
136 return NT_STATUS_NOT_IMPLEMENTED
;
139 DEBUG(10, ("%s: path=[%s], filter=%u, subdir_filter=%u, "
140 "private_data=%p\n", __func__
, path
, (unsigned)filter
,
141 (unsigned)subdir_filter
, private_data
));
143 pathlen
= strlen(path
)+1;
145 listel
= (struct notify_list
*)talloc_size(
146 ctx
, offsetof(struct notify_list
, path
) + pathlen
);
147 if (listel
== NULL
) {
148 return NT_STATUS_NO_MEMORY
;
150 listel
->callback
= callback
;
151 listel
->private_data
= private_data
;
152 memcpy(listel
->path
, path
, pathlen
);
154 clock_gettime_mono(&msg
.instance
.creation_time
);
155 msg
.instance
.filter
= filter
;
156 msg
.instance
.subdir_filter
= subdir_filter
;
157 msg
.instance
.private_data
= private_data
;
159 iov
[0].iov_base
= &msg
;
160 iov
[0].iov_len
= offsetof(struct notify_rec_change_msg
, path
);
161 iov
[1].iov_base
= discard_const_p(char, path
);
162 iov
[1].iov_len
= pathlen
;
164 status
= messaging_send_iov(
165 ctx
->msg_ctx
, ctx
->notifyd
, MSG_SMB_NOTIFY_REC_CHANGE
,
166 iov
, ARRAY_SIZE(iov
), NULL
, 0);
168 if (!NT_STATUS_IS_OK(status
)) {
170 DEBUG(10, ("messaging_send_iov returned %s\n",
175 DLIST_ADD(ctx
->list
, listel
);
179 NTSTATUS
notify_remove(struct notify_context
*ctx
, void *private_data
)
181 struct notify_list
*listel
;
182 struct notify_rec_change_msg msg
= {};
186 /* see if change notify is enabled at all */
188 return NT_STATUS_NOT_IMPLEMENTED
;
191 for (listel
= ctx
->list
; listel
!= NULL
; listel
= listel
->next
) {
192 if (listel
->private_data
== private_data
) {
193 DLIST_REMOVE(ctx
->list
, listel
);
197 if (listel
== NULL
) {
198 DEBUG(10, ("%p not found\n", private_data
));
199 return NT_STATUS_NOT_FOUND
;
202 msg
.instance
.private_data
= private_data
;
204 iov
[0].iov_base
= &msg
;
205 iov
[0].iov_len
= offsetof(struct notify_rec_change_msg
, path
);
206 iov
[1].iov_base
= discard_const_p(char, listel
->path
);
207 iov
[1].iov_len
= strlen(listel
->path
)+1;
209 status
= messaging_send_iov(
210 ctx
->msg_ctx
, ctx
->notifyd
, MSG_SMB_NOTIFY_REC_CHANGE
,
211 iov
, ARRAY_SIZE(iov
), NULL
, 0);
217 void notify_trigger(struct notify_context
*ctx
,
218 uint32_t action
, uint32_t filter
,
219 const char *dir
, const char *name
)
221 struct notify_trigger_msg msg
;
225 DEBUG(10, ("notify_trigger called action=0x%x, filter=0x%x, "
226 "dir=%s, name=%s\n", (unsigned)action
, (unsigned)filter
,
233 msg
.when
= timespec_current();
237 iov
[0].iov_base
= &msg
;
238 iov
[0].iov_len
= offsetof(struct notify_trigger_msg
, path
);
239 iov
[1].iov_base
= discard_const_p(char, dir
);
240 iov
[1].iov_len
= strlen(dir
);
241 iov
[2].iov_base
= &slash
;
243 iov
[3].iov_base
= discard_const_p(char, name
);
244 iov
[3].iov_len
= strlen(name
)+1;
247 ctx
->msg_ctx
, ctx
->notifyd
, MSG_SMB_NOTIFY_TRIGGER
,
248 iov
, ARRAY_SIZE(iov
), NULL
, 0);
251 NTSTATUS
notify_walk(struct notify_context
*notify
,
252 bool (*fn
)(const char *path
, struct server_id server
,
253 const struct notify_instance
*instance
,
257 struct tevent_context
*ev
;
258 struct tevent_req
*req
;
259 struct messaging_rec
*rec
;
265 ev
= samba_tevent_context_init(notify
);
267 return NT_STATUS_NO_MEMORY
;
270 req
= messaging_read_send(ev
, ev
, notify
->msg_ctx
, MSG_SMB_NOTIFY_DB
);
273 return NT_STATUS_NO_MEMORY
;
276 ok
= tevent_req_set_endtime(req
, ev
, timeval_current_ofs(10, 0));
279 return NT_STATUS_NO_MEMORY
;
282 status
= messaging_send_buf(notify
->msg_ctx
, notify
->notifyd
,
283 MSG_SMB_NOTIFY_GET_DB
, NULL
, 0);
284 if (!NT_STATUS_IS_OK(status
)) {
285 DEBUG(10, ("%s: messaging_send_buf failed\n",
291 ok
= tevent_req_poll(req
, ev
);
293 DEBUG(10, ("%s: tevent_req_poll failed\n", __func__
));
295 return NT_STATUS_INTERNAL_ERROR
;
298 ret
= messaging_read_recv(req
, ev
, &rec
);
300 DEBUG(10, ("%s: messaging_read_recv failed: %s\n",
301 __func__
, strerror(ret
)));
303 return map_nt_error_from_unix(ret
);
306 ret
= notifyd_parse_db(rec
->buf
.data
, rec
->buf
.length
, &log_idx
,
309 DEBUG(10, ("%s: notifyd_parse_db failed: %s\n",
310 __func__
, strerror(ret
)));
312 return map_nt_error_from_unix(ret
);