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"
25 #include "lib/util/server_id.h"
31 #include "lib/util/server_id_db.h"
32 #include "smbd/notifyd/notifyd.h"
34 struct notify_context
{
35 struct server_id notifyd
;
36 struct messaging_context
*msg_ctx
;
38 struct smbd_server_connection
*sconn
;
39 void (*callback
)(struct smbd_server_connection
*sconn
,
40 void *private_data
, struct timespec when
,
41 const struct notify_event
*ctx
);
44 static void notify_handler(struct messaging_context
*msg
, void *private_data
,
45 uint32_t msg_type
, struct server_id src
,
47 static int notify_context_destructor(struct notify_context
*ctx
);
49 struct notify_context
*notify_init(
50 TALLOC_CTX
*mem_ctx
, struct messaging_context
*msg
,
51 struct smbd_server_connection
*sconn
,
52 void (*callback
)(struct smbd_server_connection
*sconn
,
53 void *, struct timespec
,
54 const struct notify_event
*))
56 struct server_id_db
*names_db
;
57 struct notify_context
*ctx
;
60 ctx
= talloc(mem_ctx
, struct notify_context
);
67 ctx
->callback
= callback
;
69 names_db
= messaging_names_db(msg
);
70 if (!server_id_db_lookup_one(names_db
, "notify-daemon",
72 DEBUG(1, ("No notify daemon around\n"));
78 struct server_id_buf tmp
;
79 DBG_DEBUG("notifyd=%s\n",
80 server_id_str_buf(ctx
->notifyd
, &tmp
));
83 if (callback
!= NULL
) {
84 status
= messaging_register(msg
, ctx
, MSG_PVFS_NOTIFY
,
86 if (!NT_STATUS_IS_OK(status
)) {
87 DEBUG(1, ("messaging_register failed: %s\n",
94 talloc_set_destructor(ctx
, notify_context_destructor
);
99 static int notify_context_destructor(struct notify_context
*ctx
)
101 if (ctx
->callback
!= NULL
) {
102 messaging_deregister(ctx
->msg_ctx
, MSG_PVFS_NOTIFY
, ctx
);
108 static void notify_handler(struct messaging_context
*msg
, void *private_data
,
109 uint32_t msg_type
, struct server_id src
,
112 struct notify_context
*ctx
= talloc_get_type_abort(
113 private_data
, struct notify_context
);
114 struct notify_event_msg
*event_msg
;
115 struct notify_event event
;
117 if (data
->length
< offsetof(struct notify_event_msg
, path
) + 1) {
118 DEBUG(1, ("message too short: %u\n", (unsigned)data
->length
));
121 if (data
->data
[data
->length
-1] != 0) {
122 DEBUG(1, ("%s: path not 0-terminated\n", __func__
));
126 event_msg
= (struct notify_event_msg
*)data
->data
;
128 event
.action
= event_msg
->action
;
129 event
.path
= event_msg
->path
;
130 event
.private_data
= event_msg
->private_data
;
132 DEBUG(10, ("%s: Got notify_event action=%u, private_data=%p, "
133 "path=%s\n", __func__
, (unsigned)event
.action
,
134 event
.private_data
, event
.path
));
136 ctx
->callback(ctx
->sconn
, event
.private_data
, event_msg
->when
, &event
);
139 NTSTATUS
notify_add(struct notify_context
*ctx
,
140 const char *path
, uint32_t filter
, uint32_t subdir_filter
,
143 struct notify_rec_change_msg msg
= {};
149 return NT_STATUS_NOT_IMPLEMENTED
;
152 DEBUG(10, ("%s: path=[%s], filter=%u, subdir_filter=%u, "
153 "private_data=%p\n", __func__
, path
, (unsigned)filter
,
154 (unsigned)subdir_filter
, private_data
));
156 pathlen
= strlen(path
)+1;
158 clock_gettime_mono(&msg
.instance
.creation_time
);
159 msg
.instance
.filter
= filter
;
160 msg
.instance
.subdir_filter
= subdir_filter
;
161 msg
.instance
.private_data
= private_data
;
163 iov
[0].iov_base
= &msg
;
164 iov
[0].iov_len
= offsetof(struct notify_rec_change_msg
, path
);
165 iov
[1].iov_base
= discard_const_p(char, path
);
166 iov
[1].iov_len
= pathlen
;
168 status
= messaging_send_iov(
169 ctx
->msg_ctx
, ctx
->notifyd
, MSG_SMB_NOTIFY_REC_CHANGE
,
170 iov
, ARRAY_SIZE(iov
), NULL
, 0);
172 if (!NT_STATUS_IS_OK(status
)) {
173 DEBUG(10, ("messaging_send_iov returned %s\n",
181 NTSTATUS
notify_remove(struct notify_context
*ctx
, void *private_data
,
184 struct notify_rec_change_msg msg
= {};
188 /* see if change notify is enabled at all */
190 return NT_STATUS_NOT_IMPLEMENTED
;
193 msg
.instance
.private_data
= private_data
;
195 iov
[0].iov_base
= &msg
;
196 iov
[0].iov_len
= offsetof(struct notify_rec_change_msg
, path
);
197 iov
[1].iov_base
= path
;
198 iov
[1].iov_len
= strlen(path
)+1;
200 status
= messaging_send_iov(
201 ctx
->msg_ctx
, ctx
->notifyd
, MSG_SMB_NOTIFY_REC_CHANGE
,
202 iov
, ARRAY_SIZE(iov
), NULL
, 0);
207 void notify_trigger(struct notify_context
*ctx
,
208 uint32_t action
, uint32_t filter
,
209 const char *dir
, const char *name
)
211 struct notify_trigger_msg msg
;
215 DEBUG(10, ("notify_trigger called action=0x%x, filter=0x%x, "
216 "dir=%s, name=%s\n", (unsigned)action
, (unsigned)filter
,
223 msg
.when
= timespec_current();
227 iov
[0].iov_base
= &msg
;
228 iov
[0].iov_len
= offsetof(struct notify_trigger_msg
, path
);
229 iov
[1].iov_base
= discard_const_p(char, dir
);
230 iov
[1].iov_len
= strlen(dir
);
231 iov
[2].iov_base
= &slash
;
233 iov
[3].iov_base
= discard_const_p(char, name
);
234 iov
[3].iov_len
= strlen(name
)+1;
237 ctx
->msg_ctx
, ctx
->notifyd
, MSG_SMB_NOTIFY_TRIGGER
,
238 iov
, ARRAY_SIZE(iov
), NULL
, 0);
241 NTSTATUS
notify_walk(struct notify_context
*notify
,
242 bool (*fn
)(const char *path
, struct server_id server
,
243 const struct notify_instance
*instance
,
247 struct tevent_context
*ev
;
248 struct tevent_req
*req
;
249 struct messaging_rec
*rec
;
255 ev
= samba_tevent_context_init(notify
);
257 return NT_STATUS_NO_MEMORY
;
260 req
= messaging_read_send(ev
, ev
, notify
->msg_ctx
, MSG_SMB_NOTIFY_DB
);
263 return NT_STATUS_NO_MEMORY
;
266 ok
= tevent_req_set_endtime(req
, ev
, timeval_current_ofs(10, 0));
269 return NT_STATUS_NO_MEMORY
;
272 status
= messaging_send_buf(notify
->msg_ctx
, notify
->notifyd
,
273 MSG_SMB_NOTIFY_GET_DB
, NULL
, 0);
274 if (!NT_STATUS_IS_OK(status
)) {
275 DEBUG(10, ("%s: messaging_send_buf failed\n",
281 ok
= tevent_req_poll(req
, ev
);
283 DEBUG(10, ("%s: tevent_req_poll failed\n", __func__
));
285 return NT_STATUS_INTERNAL_ERROR
;
288 ret
= messaging_read_recv(req
, ev
, &rec
);
290 DEBUG(10, ("%s: messaging_read_recv failed: %s\n",
291 __func__
, strerror(ret
)));
293 return map_nt_error_from_unix(ret
);
296 ret
= notifyd_parse_db(rec
->buf
.data
, rec
->buf
.length
, &log_idx
,
299 DEBUG(10, ("%s: notifyd_parse_db failed: %s\n",
300 __func__
, strerror(ret
)));
302 return map_nt_error_from_unix(ret
);