Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Watch dbwrap record changes
4 : Copyright (C) Volker Lendecke 2012
5 :
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.
10 :
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.
15 :
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/>.
18 : */
19 :
20 : #include "includes.h"
21 : #include "system/filesys.h"
22 : #include "lib/util/server_id.h"
23 : #include "dbwrap/dbwrap.h"
24 : #include "dbwrap_watch.h"
25 : #include "dbwrap_open.h"
26 : #include "lib/util/util_tdb.h"
27 : #include "lib/util/tevent_ntstatus.h"
28 : #include "serverid.h"
29 : #include "server_id_watch.h"
30 : #include "lib/dbwrap/dbwrap_private.h"
31 :
32 : struct dbwrap_watcher {
33 : /*
34 : * Process watching this record
35 : */
36 : struct server_id pid;
37 : /*
38 : * Individual instance inside the waiter, incremented each
39 : * time a watcher is created
40 : */
41 : uint64_t instance;
42 : };
43 :
44 : #define DBWRAP_WATCHER_BUF_LENGTH (SERVER_ID_BUF_LENGTH + sizeof(uint64_t))
45 : #define DBWRAP_MAX_WATCHERS (INT32_MAX/DBWRAP_WATCHER_BUF_LENGTH)
46 :
47 : /*
48 : * Watched records contain a header of:
49 : *
50 : * [uint32] num_records
51 : * 0 [DBWRAP_WATCHER_BUF_LENGTH] \
52 : * 1 [DBWRAP_WATCHER_BUF_LENGTH] |
53 : * .. |- Array of watchers
54 : * (num_records-1)[DBWRAP_WATCHER_BUF_LENGTH] /
55 : *
56 : * [Remainder of record....]
57 : *
58 : * If this header is absent then this is a
59 : * fresh record of length zero (no watchers).
60 : */
61 :
62 2146489 : static bool dbwrap_watch_rec_parse(
63 : TDB_DATA data,
64 : uint8_t **pwatchers,
65 : size_t *pnum_watchers,
66 : TDB_DATA *pdata)
67 : {
68 10621 : size_t num_watchers;
69 :
70 2146489 : if (data.dsize == 0) {
71 : /* Fresh record */
72 471854 : if (pwatchers != NULL) {
73 471854 : *pwatchers = NULL;
74 : }
75 471854 : if (pnum_watchers != NULL) {
76 471854 : *pnum_watchers = 0;
77 : }
78 471854 : if (pdata != NULL) {
79 471854 : *pdata = (TDB_DATA) { .dptr = NULL };
80 : }
81 471854 : return true;
82 : }
83 :
84 1674635 : if (data.dsize < sizeof(uint32_t)) {
85 : /* Invalid record */
86 0 : return false;
87 : }
88 :
89 1674635 : num_watchers = IVAL(data.dptr, 0);
90 :
91 1674635 : data.dptr += sizeof(uint32_t);
92 1674635 : data.dsize -= sizeof(uint32_t);
93 :
94 1674635 : if (num_watchers > data.dsize/DBWRAP_WATCHER_BUF_LENGTH) {
95 : /* Invalid record */
96 0 : return false;
97 : }
98 :
99 1674634 : if (pwatchers != NULL) {
100 1392995 : *pwatchers = data.dptr;
101 : }
102 1674634 : if (pnum_watchers != NULL) {
103 1392995 : *pnum_watchers = num_watchers;
104 : }
105 1674634 : if (pdata != NULL) {
106 1674634 : size_t watchers_len = num_watchers * DBWRAP_WATCHER_BUF_LENGTH;
107 1674634 : *pdata = (TDB_DATA) {
108 1674634 : .dptr = data.dptr + watchers_len,
109 1674634 : .dsize = data.dsize - watchers_len
110 : };
111 : }
112 :
113 1666364 : return true;
114 : }
115 :
116 5757 : static void dbwrap_watcher_get(struct dbwrap_watcher *w,
117 : const uint8_t buf[DBWRAP_WATCHER_BUF_LENGTH])
118 : {
119 5757 : server_id_get(&w->pid, buf);
120 5757 : w->instance = BVAL(buf, SERVER_ID_BUF_LENGTH);
121 5757 : }
122 :
123 3471 : static void dbwrap_watcher_put(uint8_t buf[DBWRAP_WATCHER_BUF_LENGTH],
124 : const struct dbwrap_watcher *w)
125 : {
126 3471 : server_id_put(buf, w->pid);
127 3471 : SBVAL(buf, SERVER_ID_BUF_LENGTH, w->instance);
128 3471 : }
129 :
130 1 : static void dbwrap_watch_log_invalid_record(
131 : struct db_context *db, TDB_DATA key, TDB_DATA value)
132 : {
133 1 : DBG_ERR("Found invalid record in %s\n", dbwrap_name(db));
134 1 : dump_data(1, key.dptr, key.dsize);
135 1 : dump_data(1, value.dptr, value.dsize);
136 1 : }
137 :
138 : struct db_watched_ctx {
139 : struct db_context *backend;
140 : struct messaging_context *msg;
141 : };
142 :
143 : struct db_watched_record {
144 : struct db_record *rec;
145 : struct server_id self;
146 : struct {
147 : struct db_record *rec;
148 : TDB_DATA initial_value;
149 : bool initial_valid;
150 : } backend;
151 : bool force_fini_store;
152 : struct dbwrap_watcher added;
153 : bool removed_first;
154 : struct {
155 : /*
156 : * The is the number of watcher records
157 : * parsed from backend.initial_value
158 : */
159 : size_t count;
160 : /*
161 : * This is the pointer to
162 : * the optentially first watcher record
163 : * parsed from backend.initial_value
164 : *
165 : * The pointer actually points to memory
166 : * in backend.initial_value.
167 : *
168 : * Note it might be NULL, if count is 0.
169 : */
170 : uint8_t *first;
171 : /*
172 : * This remembers if we already
173 : * notified the watchers.
174 : *
175 : * As we only need to do that once during:
176 : * do_locked
177 : * or:
178 : * between rec = fetch_locked
179 : * and
180 : * TALLOC_FREE(rec)
181 : */
182 : bool alerted;
183 : } watchers;
184 : struct {
185 : struct dbwrap_watcher watcher;
186 : } wakeup;
187 : };
188 :
189 3920464 : static struct db_watched_record *db_record_get_watched_record(struct db_record *rec)
190 : {
191 : /*
192 : * we can't use wrec = talloc_get_type_abort() here!
193 : * because wrec is likely a stack variable in
194 : * dbwrap_watched_do_locked_fn()
195 : *
196 : * In order to have a least some protection
197 : * we verify the cross reference pointers
198 : * between rec and wrec
199 : */
200 3920464 : struct db_watched_record *wrec =
201 : (struct db_watched_record *)rec->private_data;
202 3920464 : SMB_ASSERT(wrec->rec == rec);
203 3920464 : return wrec;
204 : }
205 :
206 : static NTSTATUS dbwrap_watched_record_storev(
207 : struct db_watched_record *wrec,
208 : const TDB_DATA *dbufs, int num_dbufs, int flags);
209 : static NTSTATUS dbwrap_watched_storev(struct db_record *rec,
210 : const TDB_DATA *dbufs, int num_dbufs,
211 : int flags);
212 : static NTSTATUS dbwrap_watched_delete(struct db_record *rec);
213 : static void dbwrap_watched_trigger_wakeup(struct messaging_context *msg_ctx,
214 : struct dbwrap_watcher *watcher);
215 : static int db_watched_record_destructor(struct db_watched_record *wrec);
216 :
217 1864849 : static void db_watched_record_init(struct db_context *db,
218 : struct messaging_context *msg_ctx,
219 : struct db_record *rec,
220 : struct db_watched_record *wrec,
221 : struct db_record *backend_rec,
222 : TDB_DATA backend_value)
223 : {
224 9242 : bool ok;
225 :
226 1874091 : *rec = (struct db_record) {
227 : .db = db,
228 1864849 : .key = dbwrap_record_get_key(backend_rec),
229 : .storev = dbwrap_watched_storev,
230 : .delete_rec = dbwrap_watched_delete,
231 : .private_data = wrec,
232 : };
233 :
234 1874091 : *wrec = (struct db_watched_record) {
235 : .rec = rec,
236 1864849 : .self = messaging_server_id(msg_ctx),
237 : .backend = {
238 : .rec = backend_rec,
239 : .initial_value = backend_value,
240 : .initial_valid = true,
241 : },
242 : };
243 :
244 1864849 : ok = dbwrap_watch_rec_parse(backend_value,
245 : &wrec->watchers.first,
246 : &wrec->watchers.count,
247 : &rec->value);
248 1864849 : if (!ok) {
249 0 : dbwrap_watch_log_invalid_record(rec->db, rec->key, backend_value);
250 : /* wipe invalid data */
251 0 : rec->value = (TDB_DATA) { .dptr = NULL, .dsize = 0 };
252 : }
253 1864849 : }
254 :
255 246067 : static struct db_record *dbwrap_watched_fetch_locked(
256 : struct db_context *db, TALLOC_CTX *mem_ctx, TDB_DATA key)
257 : {
258 246067 : struct db_watched_ctx *ctx = talloc_get_type_abort(
259 : db->private_data, struct db_watched_ctx);
260 246067 : struct db_record *rec = NULL;
261 246067 : struct db_watched_record *wrec = NULL;
262 246067 : struct db_record *backend_rec = NULL;
263 246067 : TDB_DATA backend_value = { .dptr = NULL, };
264 :
265 246067 : rec = talloc_zero(mem_ctx, struct db_record);
266 246067 : if (rec == NULL) {
267 0 : return NULL;
268 : }
269 246067 : wrec = talloc_zero(rec, struct db_watched_record);
270 246067 : if (wrec == NULL) {
271 0 : TALLOC_FREE(rec);
272 0 : return NULL;
273 : }
274 :
275 246067 : backend_rec = dbwrap_fetch_locked(ctx->backend, wrec, key);
276 246067 : if (backend_rec == NULL) {
277 0 : TALLOC_FREE(rec);
278 0 : return NULL;
279 : }
280 246067 : backend_value = dbwrap_record_get_value(backend_rec);
281 :
282 246067 : db_watched_record_init(db, ctx->msg,
283 : rec, wrec,
284 : backend_rec, backend_value);
285 246067 : rec->value_valid = true;
286 246067 : talloc_set_destructor(wrec, db_watched_record_destructor);
287 :
288 246067 : return rec;
289 : }
290 :
291 : struct db_watched_record_fini_state {
292 : struct db_watched_record *wrec;
293 : TALLOC_CTX *frame;
294 : TDB_DATA dbufs[2];
295 : int num_dbufs;
296 : bool ok;
297 : };
298 :
299 0 : static void db_watched_record_fini_fetcher(TDB_DATA key,
300 : TDB_DATA backend_value,
301 : void *private_data)
302 : {
303 0 : struct db_watched_record_fini_state *state =
304 : (struct db_watched_record_fini_state *)private_data;
305 0 : struct db_watched_record *wrec = state->wrec;
306 0 : struct db_record *rec = wrec->rec;
307 0 : TDB_DATA value = {};
308 0 : bool ok;
309 0 : size_t copy_size;
310 :
311 : /*
312 : * We're within dbwrap_parse_record()
313 : * and backend_value directly points into
314 : * the mmap'ed tdb, so we need to copy the
315 : * parts we require.
316 : */
317 :
318 0 : ok = dbwrap_watch_rec_parse(backend_value, NULL, NULL, &value);
319 0 : if (!ok) {
320 0 : struct db_context *db = dbwrap_record_get_db(rec);
321 :
322 0 : dbwrap_watch_log_invalid_record(db, key, backend_value);
323 :
324 : /* wipe invalid data */
325 0 : value = (TDB_DATA) { .dptr = NULL, .dsize = 0 };
326 : }
327 :
328 0 : copy_size = MIN(rec->value.dsize, value.dsize);
329 0 : if (copy_size != 0) {
330 : /*
331 : * First reuse the buffer we already had
332 : * as much as we can.
333 : */
334 0 : memcpy(rec->value.dptr, value.dptr, copy_size);
335 0 : state->dbufs[state->num_dbufs++] = rec->value;
336 0 : value.dsize -= copy_size;
337 0 : value.dptr += copy_size;
338 : }
339 :
340 0 : if (value.dsize != 0) {
341 0 : uint8_t *p = NULL;
342 :
343 : /*
344 : * There's still new data left
345 : * allocate it on callers stackframe
346 : */
347 0 : p = talloc_memdup(state->frame, value.dptr, value.dsize);
348 0 : if (p == NULL) {
349 0 : DBG_WARNING("failed to allocate %zu bytes\n",
350 : value.dsize);
351 0 : return;
352 : }
353 :
354 0 : state->dbufs[state->num_dbufs++] = (TDB_DATA) {
355 0 : .dptr = p, .dsize = value.dsize,
356 : };
357 : }
358 :
359 0 : state->ok = true;
360 : }
361 :
362 1864848 : static void db_watched_record_fini(struct db_watched_record *wrec)
363 : {
364 1864848 : struct db_watched_record_fini_state state = { .wrec = wrec, };
365 1864848 : struct db_context *backend = dbwrap_record_get_db(wrec->backend.rec);
366 1864848 : struct db_record *rec = wrec->rec;
367 1864848 : TDB_DATA key = dbwrap_record_get_key(wrec->backend.rec);
368 9241 : NTSTATUS status;
369 :
370 1864848 : if (!wrec->force_fini_store) {
371 1849888 : return;
372 : }
373 :
374 5850 : if (wrec->backend.initial_valid) {
375 5850 : if (rec->value.dsize != 0) {
376 5662 : state.dbufs[state.num_dbufs++] = rec->value;
377 : }
378 : } else {
379 : /*
380 : * We need to fetch the current
381 : * value from the backend again,
382 : * which may need to allocate memory
383 : * on the provided stackframe.
384 : */
385 :
386 0 : state.frame = talloc_stackframe();
387 :
388 0 : status = dbwrap_parse_record(backend, key,
389 : db_watched_record_fini_fetcher, &state);
390 0 : if (!NT_STATUS_IS_OK(status)) {
391 0 : DBG_WARNING("dbwrap_parse_record failed: %s\n",
392 : nt_errstr(status));
393 0 : TALLOC_FREE(state.frame);
394 0 : return;
395 : }
396 0 : if (!state.ok) {
397 0 : TALLOC_FREE(state.frame);
398 0 : return;
399 : }
400 : }
401 :
402 : /*
403 : * We don't want to wake up others just because
404 : * we added ourself as new watcher. But if we
405 : * removed outself from the first position
406 : * we need to alert the next one.
407 : */
408 5850 : if (!wrec->removed_first) {
409 2460 : dbwrap_watched_watch_skip_alerting(rec);
410 : }
411 :
412 5850 : status = dbwrap_watched_record_storev(wrec, state.dbufs, state.num_dbufs, 0);
413 5850 : TALLOC_FREE(state.frame);
414 5850 : if (!NT_STATUS_IS_OK(status)) {
415 0 : DBG_WARNING("dbwrap_watched_record_storev failed: %s\n",
416 : nt_errstr(status));
417 0 : return;
418 : }
419 :
420 5719 : return;
421 : }
422 :
423 246066 : static int db_watched_record_destructor(struct db_watched_record *wrec)
424 : {
425 246066 : struct db_record *rec = wrec->rec;
426 246066 : struct db_watched_ctx *ctx = talloc_get_type_abort(
427 : rec->db->private_data, struct db_watched_ctx);
428 :
429 246066 : db_watched_record_fini(wrec);
430 246066 : TALLOC_FREE(wrec->backend.rec);
431 246066 : dbwrap_watched_trigger_wakeup(ctx->msg, &wrec->wakeup.watcher);
432 246066 : return 0;
433 : }
434 :
435 : struct dbwrap_watched_do_locked_state {
436 : struct db_context *db;
437 : struct messaging_context *msg_ctx;
438 : struct db_watched_record *wrec;
439 : struct db_record *rec;
440 : void (*fn)(struct db_record *rec,
441 : TDB_DATA value,
442 : void *private_data);
443 : void *private_data;
444 : };
445 :
446 1618782 : static void dbwrap_watched_do_locked_fn(
447 : struct db_record *backend_rec,
448 : TDB_DATA backend_value,
449 : void *private_data)
450 : {
451 1618782 : struct dbwrap_watched_do_locked_state *state =
452 : (struct dbwrap_watched_do_locked_state *)private_data;
453 :
454 1618782 : db_watched_record_init(state->db, state->msg_ctx,
455 : state->rec, state->wrec,
456 : backend_rec, backend_value);
457 :
458 1618782 : state->fn(state->rec, state->rec->value, state->private_data);
459 :
460 1618782 : db_watched_record_fini(state->wrec);
461 1618782 : }
462 :
463 1618782 : static NTSTATUS dbwrap_watched_do_locked(struct db_context *db, TDB_DATA key,
464 : void (*fn)(struct db_record *rec,
465 : TDB_DATA value,
466 : void *private_data),
467 : void *private_data)
468 : {
469 1618782 : struct db_watched_ctx *ctx = talloc_get_type_abort(
470 : db->private_data, struct db_watched_ctx);
471 3598 : struct db_watched_record wrec;
472 3598 : struct db_record rec;
473 1618782 : struct dbwrap_watched_do_locked_state state = {
474 1618782 : .db = db, .msg_ctx = ctx->msg,
475 : .rec = &rec, .wrec = &wrec,
476 : .fn = fn, .private_data = private_data,
477 : };
478 3598 : NTSTATUS status;
479 :
480 1618782 : status = dbwrap_do_locked(
481 : ctx->backend, key, dbwrap_watched_do_locked_fn, &state);
482 1618782 : if (!NT_STATUS_IS_OK(status)) {
483 0 : DBG_DEBUG("dbwrap_do_locked returned %s\n", nt_errstr(status));
484 0 : return status;
485 : }
486 :
487 1618782 : DBG_DEBUG("dbwrap_watched_do_locked_fn returned\n");
488 :
489 1618782 : dbwrap_watched_trigger_wakeup(state.msg_ctx, &wrec.wakeup.watcher);
490 :
491 1618782 : return NT_STATUS_OK;
492 : }
493 :
494 2309077 : static void dbwrap_watched_record_prepare_wakeup(
495 : struct db_watched_record *wrec)
496 : {
497 : /*
498 : * Wakeup only needs to happen once (if at all)
499 : */
500 2309077 : if (wrec->watchers.alerted) {
501 : /* already done */
502 1108373 : return;
503 : }
504 1198070 : wrec->watchers.alerted = true;
505 :
506 1198070 : if (wrec->watchers.count == 0) {
507 1195881 : DBG_DEBUG("No watchers\n");
508 1195881 : return;
509 : }
510 :
511 2189 : while (wrec->watchers.count != 0) {
512 11 : struct server_id_buf tmp;
513 11 : bool exists;
514 :
515 2189 : dbwrap_watcher_get(&wrec->wakeup.watcher, wrec->watchers.first);
516 2189 : exists = serverid_exists(&wrec->wakeup.watcher.pid);
517 2189 : if (!exists) {
518 0 : DBG_DEBUG("Discard non-existing waiter %s:%"PRIu64"\n",
519 : server_id_str_buf(wrec->wakeup.watcher.pid, &tmp),
520 : wrec->wakeup.watcher.instance);
521 0 : wrec->watchers.first += DBWRAP_WATCHER_BUF_LENGTH;
522 0 : wrec->watchers.count -= 1;
523 0 : continue;
524 : }
525 :
526 : /*
527 : * We will only wakeup the first waiter, via
528 : * dbwrap_watched_trigger_wakeup(), but keep
529 : * all (including the first one) in the list that
530 : * will be flushed back to the backend record
531 : * again. Waiters are removing their entries
532 : * via dbwrap_watched_watch_remove_instance()
533 : * when they no longer want to monitor the record.
534 : */
535 2189 : DBG_DEBUG("Will alert first waiter %s:%"PRIu64"\n",
536 : server_id_str_buf(wrec->wakeup.watcher.pid, &tmp),
537 : wrec->wakeup.watcher.instance);
538 2189 : break;
539 : }
540 : }
541 :
542 1864848 : static void dbwrap_watched_trigger_wakeup(struct messaging_context *msg_ctx,
543 : struct dbwrap_watcher *watcher)
544 : {
545 9241 : struct server_id_buf tmp;
546 9241 : uint8_t instance_buf[8];
547 9241 : NTSTATUS status;
548 :
549 1864848 : if (watcher->instance == 0) {
550 1862689 : DBG_DEBUG("No one to wakeup\n");
551 1862689 : return;
552 : }
553 :
554 2159 : DBG_DEBUG("Alerting %s:%"PRIu64"\n",
555 : server_id_str_buf(watcher->pid, &tmp),
556 : watcher->instance);
557 :
558 2159 : SBVAL(instance_buf, 0, watcher->instance);
559 :
560 2159 : status = messaging_send_buf(
561 : msg_ctx,
562 : watcher->pid,
563 : MSG_DBWRAP_MODIFIED,
564 : instance_buf,
565 : sizeof(instance_buf));
566 2159 : if (!NT_STATUS_IS_OK(status)) {
567 0 : DBG_WARNING("messaging_send_buf to %s failed: %s - ignoring...\n",
568 : server_id_str_buf(watcher->pid, &tmp),
569 : nt_errstr(status));
570 : }
571 : }
572 :
573 1851391 : static NTSTATUS dbwrap_watched_record_storev(
574 : struct db_watched_record *wrec,
575 : const TDB_DATA *dbufs, int num_dbufs, int flags)
576 1851391 : {
577 1851391 : uint8_t num_watchers_buf[4] = { 0 };
578 8924 : uint8_t add_buf[DBWRAP_WATCHER_BUF_LENGTH];
579 8924 : size_t num_store_watchers;
580 1851391 : TDB_DATA my_dbufs[num_dbufs+3];
581 1851391 : int num_my_dbufs = 0;
582 8924 : NTSTATUS status;
583 1851391 : size_t add_count = 0;
584 :
585 1851391 : dbwrap_watched_record_prepare_wakeup(wrec);
586 :
587 1851391 : wrec->backend.initial_valid = false;
588 1851391 : wrec->force_fini_store = false;
589 :
590 1851391 : if (wrec->added.pid.pid != 0) {
591 3471 : dbwrap_watcher_put(add_buf, &wrec->added);
592 3471 : add_count = 1;
593 : }
594 :
595 1851391 : num_store_watchers = wrec->watchers.count + add_count;
596 1851391 : if (num_store_watchers == 0 && num_dbufs == 0) {
597 470544 : status = dbwrap_record_delete(wrec->backend.rec);
598 470544 : return status;
599 : }
600 1380847 : if (num_store_watchers >= DBWRAP_MAX_WATCHERS) {
601 0 : DBG_WARNING("Can't handle %zu watchers\n",
602 : num_store_watchers);
603 0 : return NT_STATUS_INSUFFICIENT_RESOURCES;
604 : }
605 :
606 1380847 : SIVAL(num_watchers_buf, 0, num_store_watchers);
607 :
608 1380847 : my_dbufs[num_my_dbufs++] = (TDB_DATA) {
609 : .dptr = num_watchers_buf, .dsize = sizeof(num_watchers_buf),
610 : };
611 1380847 : if (wrec->watchers.count != 0) {
612 3514 : my_dbufs[num_my_dbufs++] = (TDB_DATA) {
613 3514 : .dptr = wrec->watchers.first, .dsize = wrec->watchers.count * DBWRAP_WATCHER_BUF_LENGTH,
614 : };
615 : }
616 1380847 : if (add_count != 0) {
617 3471 : my_dbufs[num_my_dbufs++] = (TDB_DATA) {
618 : .dptr = add_buf,
619 : .dsize = sizeof(add_buf),
620 : };
621 : }
622 1380847 : if (num_dbufs != 0) {
623 1380659 : memcpy(my_dbufs+num_my_dbufs, dbufs, num_dbufs * sizeof(*dbufs));
624 1380659 : num_my_dbufs += num_dbufs;
625 : }
626 :
627 1380847 : SMB_ASSERT(num_my_dbufs <= ARRAY_SIZE(my_dbufs));
628 :
629 1380847 : status = dbwrap_record_storev(
630 : wrec->backend.rec, my_dbufs, num_my_dbufs, flags);
631 1380847 : return status;
632 : }
633 :
634 1374997 : static NTSTATUS dbwrap_watched_storev(struct db_record *rec,
635 : const TDB_DATA *dbufs, int num_dbufs,
636 : int flags)
637 : {
638 1374997 : struct db_watched_record *wrec = db_record_get_watched_record(rec);
639 :
640 1374997 : return dbwrap_watched_record_storev(wrec, dbufs, num_dbufs, flags);
641 : }
642 :
643 470544 : static NTSTATUS dbwrap_watched_delete(struct db_record *rec)
644 : {
645 470544 : struct db_watched_record *wrec = db_record_get_watched_record(rec);
646 :
647 : /*
648 : * dbwrap_watched_record_storev() will figure out
649 : * if the record should be deleted or if there are still
650 : * watchers to be stored.
651 : */
652 470544 : return dbwrap_watched_record_storev(wrec, NULL, 0, 0);
653 : }
654 :
655 : struct dbwrap_watched_traverse_state {
656 : int (*fn)(struct db_record *rec, void *private_data);
657 : void *private_data;
658 : };
659 :
660 18823 : static int dbwrap_watched_traverse_fn(struct db_record *rec,
661 : void *private_data)
662 : {
663 18823 : struct dbwrap_watched_traverse_state *state = private_data;
664 18823 : struct db_record prec = *rec;
665 0 : bool ok;
666 :
667 18823 : ok = dbwrap_watch_rec_parse(rec->value, NULL, NULL, &prec.value);
668 18823 : if (!ok) {
669 0 : return 0;
670 : }
671 18823 : if (prec.value.dsize == 0) {
672 0 : return 0;
673 : }
674 18823 : prec.value_valid = true;
675 :
676 18823 : return state->fn(&prec, state->private_data);
677 : }
678 :
679 0 : static int dbwrap_watched_traverse(struct db_context *db,
680 : int (*fn)(struct db_record *rec,
681 : void *private_data),
682 : void *private_data)
683 : {
684 0 : struct db_watched_ctx *ctx = talloc_get_type_abort(
685 : db->private_data, struct db_watched_ctx);
686 0 : struct dbwrap_watched_traverse_state state = {
687 : .fn = fn, .private_data = private_data };
688 0 : NTSTATUS status;
689 0 : int ret;
690 :
691 0 : status = dbwrap_traverse(
692 : ctx->backend, dbwrap_watched_traverse_fn, &state, &ret);
693 0 : if (!NT_STATUS_IS_OK(status)) {
694 0 : return -1;
695 : }
696 0 : return ret;
697 : }
698 :
699 6375 : static int dbwrap_watched_traverse_read(struct db_context *db,
700 : int (*fn)(struct db_record *rec,
701 : void *private_data),
702 : void *private_data)
703 : {
704 6375 : struct db_watched_ctx *ctx = talloc_get_type_abort(
705 : db->private_data, struct db_watched_ctx);
706 6375 : struct dbwrap_watched_traverse_state state = {
707 : .fn = fn, .private_data = private_data };
708 0 : NTSTATUS status;
709 0 : int ret;
710 :
711 6375 : status = dbwrap_traverse_read(
712 : ctx->backend, dbwrap_watched_traverse_fn, &state, &ret);
713 6375 : if (!NT_STATUS_IS_OK(status)) {
714 0 : return -1;
715 : }
716 6375 : return ret;
717 : }
718 :
719 193204 : static int dbwrap_watched_get_seqnum(struct db_context *db)
720 : {
721 193204 : struct db_watched_ctx *ctx = talloc_get_type_abort(
722 : db->private_data, struct db_watched_ctx);
723 193204 : return dbwrap_get_seqnum(ctx->backend);
724 : }
725 :
726 0 : static int dbwrap_watched_transaction_start(struct db_context *db)
727 : {
728 0 : struct db_watched_ctx *ctx = talloc_get_type_abort(
729 : db->private_data, struct db_watched_ctx);
730 0 : return dbwrap_transaction_start(ctx->backend);
731 : }
732 :
733 0 : static int dbwrap_watched_transaction_commit(struct db_context *db)
734 : {
735 0 : struct db_watched_ctx *ctx = talloc_get_type_abort(
736 : db->private_data, struct db_watched_ctx);
737 0 : return dbwrap_transaction_commit(ctx->backend);
738 : }
739 :
740 0 : static int dbwrap_watched_transaction_cancel(struct db_context *db)
741 : {
742 0 : struct db_watched_ctx *ctx = talloc_get_type_abort(
743 : db->private_data, struct db_watched_ctx);
744 0 : return dbwrap_transaction_cancel(ctx->backend);
745 : }
746 :
747 : struct dbwrap_watched_parse_record_state {
748 : struct db_context *db;
749 : void (*parser)(TDB_DATA key, TDB_DATA data, void *private_data);
750 : void *private_data;
751 : bool ok;
752 : };
753 :
754 262817 : static void dbwrap_watched_parse_record_parser(TDB_DATA key, TDB_DATA data,
755 : void *private_data)
756 : {
757 262817 : struct dbwrap_watched_parse_record_state *state = private_data;
758 1379 : TDB_DATA userdata;
759 :
760 262817 : state->ok = dbwrap_watch_rec_parse(data, NULL, NULL, &userdata);
761 262817 : if (!state->ok) {
762 1 : dbwrap_watch_log_invalid_record(state->db, key, data);
763 1 : return;
764 : }
765 :
766 262816 : state->parser(key, userdata, state->private_data);
767 : }
768 :
769 1087768 : static NTSTATUS dbwrap_watched_parse_record(
770 : struct db_context *db, TDB_DATA key,
771 : void (*parser)(TDB_DATA key, TDB_DATA data, void *private_data),
772 : void *private_data)
773 : {
774 1087768 : struct db_watched_ctx *ctx = talloc_get_type_abort(
775 : db->private_data, struct db_watched_ctx);
776 1087768 : struct dbwrap_watched_parse_record_state state = {
777 : .db = db,
778 : .parser = parser,
779 : .private_data = private_data,
780 : };
781 1815 : NTSTATUS status;
782 :
783 1087768 : status = dbwrap_parse_record(
784 : ctx->backend, key, dbwrap_watched_parse_record_parser, &state);
785 1087768 : if (!NT_STATUS_IS_OK(status)) {
786 824951 : return status;
787 : }
788 262817 : if (!state.ok) {
789 1 : return NT_STATUS_NOT_FOUND;
790 : }
791 262816 : return NT_STATUS_OK;
792 : }
793 :
794 : static void dbwrap_watched_parse_record_done(struct tevent_req *subreq);
795 :
796 0 : static struct tevent_req *dbwrap_watched_parse_record_send(
797 : TALLOC_CTX *mem_ctx,
798 : struct tevent_context *ev,
799 : struct db_context *db,
800 : TDB_DATA key,
801 : void (*parser)(TDB_DATA key, TDB_DATA data, void *private_data),
802 : void *private_data,
803 : enum dbwrap_req_state *req_state)
804 : {
805 0 : struct db_watched_ctx *ctx = talloc_get_type_abort(
806 : db->private_data, struct db_watched_ctx);
807 0 : struct tevent_req *req = NULL;
808 0 : struct tevent_req *subreq = NULL;
809 0 : struct dbwrap_watched_parse_record_state *state = NULL;
810 :
811 0 : req = tevent_req_create(mem_ctx, &state,
812 : struct dbwrap_watched_parse_record_state);
813 0 : if (req == NULL) {
814 0 : *req_state = DBWRAP_REQ_ERROR;
815 0 : return NULL;
816 : }
817 :
818 0 : *state = (struct dbwrap_watched_parse_record_state) {
819 : .parser = parser,
820 : .private_data = private_data,
821 : .ok = true,
822 : };
823 :
824 0 : subreq = dbwrap_parse_record_send(state,
825 : ev,
826 : ctx->backend,
827 : key,
828 : dbwrap_watched_parse_record_parser,
829 : state,
830 : req_state);
831 0 : if (tevent_req_nomem(subreq, req)) {
832 0 : *req_state = DBWRAP_REQ_ERROR;
833 0 : return tevent_req_post(req, ev);
834 : }
835 :
836 0 : tevent_req_set_callback(subreq, dbwrap_watched_parse_record_done, req);
837 0 : return req;
838 : }
839 :
840 0 : static void dbwrap_watched_parse_record_done(struct tevent_req *subreq)
841 : {
842 0 : struct tevent_req *req = tevent_req_callback_data(
843 : subreq, struct tevent_req);
844 0 : struct dbwrap_watched_parse_record_state *state = tevent_req_data(
845 : req, struct dbwrap_watched_parse_record_state);
846 0 : NTSTATUS status;
847 :
848 0 : status = dbwrap_parse_record_recv(subreq);
849 0 : TALLOC_FREE(subreq);
850 0 : if (tevent_req_nterror(req, status)) {
851 0 : return;
852 : }
853 :
854 0 : if (!state->ok) {
855 0 : tevent_req_nterror(req, NT_STATUS_NOT_FOUND);
856 0 : return;
857 : }
858 :
859 0 : tevent_req_done(req);
860 0 : return;
861 : }
862 :
863 0 : static NTSTATUS dbwrap_watched_parse_record_recv(struct tevent_req *req)
864 : {
865 0 : NTSTATUS status;
866 :
867 0 : if (tevent_req_is_nterror(req, &status)) {
868 0 : tevent_req_received(req);
869 0 : return status;
870 : }
871 :
872 0 : tevent_req_received(req);
873 0 : return NT_STATUS_OK;
874 : }
875 :
876 0 : static int dbwrap_watched_exists(struct db_context *db, TDB_DATA key)
877 : {
878 0 : struct db_watched_ctx *ctx = talloc_get_type_abort(
879 : db->private_data, struct db_watched_ctx);
880 :
881 0 : return dbwrap_exists(ctx->backend, key);
882 : }
883 :
884 0 : static size_t dbwrap_watched_id(struct db_context *db, uint8_t *id,
885 : size_t idlen)
886 : {
887 0 : struct db_watched_ctx *ctx = talloc_get_type_abort(
888 : db->private_data, struct db_watched_ctx);
889 :
890 0 : return dbwrap_db_id(ctx->backend, id, idlen);
891 : }
892 :
893 382 : struct db_context *db_open_watched(TALLOC_CTX *mem_ctx,
894 : struct db_context **backend,
895 : struct messaging_context *msg)
896 : {
897 27 : struct db_context *db;
898 27 : struct db_watched_ctx *ctx;
899 :
900 382 : db = talloc_zero(mem_ctx, struct db_context);
901 382 : if (db == NULL) {
902 0 : return NULL;
903 : }
904 382 : ctx = talloc_zero(db, struct db_watched_ctx);
905 382 : if (ctx == NULL) {
906 0 : TALLOC_FREE(db);
907 0 : return NULL;
908 : }
909 382 : db->private_data = ctx;
910 :
911 382 : ctx->msg = msg;
912 :
913 382 : ctx->backend = talloc_move(ctx, backend);
914 382 : db->lock_order = ctx->backend->lock_order;
915 382 : ctx->backend->lock_order = DBWRAP_LOCK_ORDER_NONE;
916 :
917 382 : db->fetch_locked = dbwrap_watched_fetch_locked;
918 382 : db->do_locked = dbwrap_watched_do_locked;
919 382 : db->traverse = dbwrap_watched_traverse;
920 382 : db->traverse_read = dbwrap_watched_traverse_read;
921 382 : db->get_seqnum = dbwrap_watched_get_seqnum;
922 382 : db->transaction_start = dbwrap_watched_transaction_start;
923 382 : db->transaction_commit = dbwrap_watched_transaction_commit;
924 382 : db->transaction_cancel = dbwrap_watched_transaction_cancel;
925 382 : db->parse_record = dbwrap_watched_parse_record;
926 382 : db->parse_record_send = dbwrap_watched_parse_record_send;
927 382 : db->parse_record_recv = dbwrap_watched_parse_record_recv;
928 382 : db->exists = dbwrap_watched_exists;
929 382 : db->id = dbwrap_watched_id;
930 382 : db->name = dbwrap_name(ctx->backend);
931 :
932 382 : return db;
933 : }
934 :
935 3472 : uint64_t dbwrap_watched_watch_add_instance(struct db_record *rec)
936 : {
937 3472 : struct db_watched_record *wrec = db_record_get_watched_record(rec);
938 71 : static uint64_t global_instance = 1;
939 :
940 3472 : SMB_ASSERT(wrec->added.instance == 0);
941 :
942 3472 : wrec->added = (struct dbwrap_watcher) {
943 3472 : .pid = wrec->self,
944 3472 : .instance = global_instance++,
945 : };
946 :
947 3472 : wrec->force_fini_store = true;
948 :
949 3472 : return wrec->added.instance;
950 : }
951 :
952 28860 : void dbwrap_watched_watch_remove_instance(struct db_record *rec, uint64_t instance)
953 : {
954 28860 : struct db_watched_record *wrec = db_record_get_watched_record(rec);
955 28860 : struct dbwrap_watcher clear_watcher = {
956 : .pid = wrec->self,
957 : .instance = instance,
958 : };
959 774 : size_t i;
960 774 : struct server_id_buf buf;
961 :
962 28860 : if (instance == 0) {
963 24685 : return;
964 : }
965 :
966 3470 : if (wrec->added.instance == instance) {
967 0 : SMB_ASSERT(server_id_equal(&wrec->added.pid, &wrec->self));
968 0 : DBG_DEBUG("Watcher %s:%"PRIu64" reverted from adding\n",
969 : server_id_str_buf(clear_watcher.pid, &buf),
970 : clear_watcher.instance);
971 0 : ZERO_STRUCT(wrec->added);
972 : }
973 :
974 3568 : for (i=0; i < wrec->watchers.count; i++) {
975 69 : struct dbwrap_watcher watcher;
976 3568 : size_t off = i*DBWRAP_WATCHER_BUF_LENGTH;
977 69 : size_t next_off;
978 69 : size_t full_len;
979 69 : size_t move_len;
980 :
981 3568 : dbwrap_watcher_get(&watcher, wrec->watchers.first + off);
982 :
983 3568 : if (clear_watcher.instance != watcher.instance) {
984 98 : continue;
985 : }
986 3522 : if (!server_id_equal(&clear_watcher.pid, &watcher.pid)) {
987 52 : continue;
988 : }
989 :
990 3470 : wrec->force_fini_store = true;
991 :
992 3470 : if (i == 0) {
993 3405 : DBG_DEBUG("Watcher %s:%"PRIu64" removed from first position of %zu\n",
994 : server_id_str_buf(clear_watcher.pid, &buf),
995 : clear_watcher.instance,
996 : wrec->watchers.count);
997 3405 : wrec->watchers.first += DBWRAP_WATCHER_BUF_LENGTH;
998 3405 : wrec->watchers.count -= 1;
999 3405 : wrec->removed_first = true;
1000 3470 : return;
1001 : }
1002 65 : if (i == (wrec->watchers.count-1)) {
1003 36 : DBG_DEBUG("Watcher %s:%"PRIu64" removed from last position of %zu\n",
1004 : server_id_str_buf(clear_watcher.pid, &buf),
1005 : clear_watcher.instance,
1006 : wrec->watchers.count);
1007 36 : wrec->watchers.count -= 1;
1008 36 : return;
1009 : }
1010 :
1011 29 : DBG_DEBUG("Watcher %s:%"PRIu64" cleared at position %zu from %zu\n",
1012 : server_id_str_buf(clear_watcher.pid, &buf),
1013 : clear_watcher.instance, i+1,
1014 : wrec->watchers.count);
1015 :
1016 29 : next_off = off + DBWRAP_WATCHER_BUF_LENGTH;
1017 29 : full_len = wrec->watchers.count * DBWRAP_WATCHER_BUF_LENGTH;
1018 29 : move_len = full_len - next_off;
1019 29 : memmove(wrec->watchers.first + off,
1020 29 : wrec->watchers.first + next_off,
1021 : move_len);
1022 29 : wrec->watchers.count -= 1;
1023 29 : return;
1024 : }
1025 :
1026 0 : DBG_DEBUG("Watcher %s:%"PRIu64" not found in %zu watchers\n",
1027 : server_id_str_buf(clear_watcher.pid, &buf),
1028 : clear_watcher.instance,
1029 : wrec->watchers.count);
1030 0 : return;
1031 : }
1032 :
1033 1123595 : void dbwrap_watched_watch_skip_alerting(struct db_record *rec)
1034 : {
1035 1123595 : struct db_watched_record *wrec = db_record_get_watched_record(rec);
1036 :
1037 1123595 : wrec->wakeup.watcher = (struct dbwrap_watcher) { .instance = 0, };
1038 1123595 : wrec->watchers.alerted = true;
1039 1123595 : }
1040 :
1041 457686 : void dbwrap_watched_watch_reset_alerting(struct db_record *rec)
1042 : {
1043 457686 : struct db_watched_record *wrec = db_record_get_watched_record(rec);
1044 :
1045 457686 : wrec->wakeup.watcher = (struct dbwrap_watcher) { .instance = 0, };
1046 457686 : wrec->watchers.alerted = false;
1047 457686 : }
1048 :
1049 457686 : void dbwrap_watched_watch_force_alerting(struct db_record *rec)
1050 : {
1051 457686 : struct db_watched_record *wrec = db_record_get_watched_record(rec);
1052 :
1053 457686 : dbwrap_watched_record_prepare_wakeup(wrec);
1054 457686 : }
1055 :
1056 : struct dbwrap_watched_watch_state {
1057 : struct db_context *db;
1058 : TDB_DATA key;
1059 : struct dbwrap_watcher watcher;
1060 : struct server_id blocker;
1061 : bool blockerdead;
1062 : };
1063 :
1064 : static bool dbwrap_watched_msg_filter(struct messaging_rec *rec,
1065 : void *private_data);
1066 : static void dbwrap_watched_watch_done(struct tevent_req *subreq);
1067 : static void dbwrap_watched_watch_blocker_died(struct tevent_req *subreq);
1068 : static int dbwrap_watched_watch_state_destructor(
1069 : struct dbwrap_watched_watch_state *state);
1070 :
1071 3624 : struct tevent_req *dbwrap_watched_watch_send(TALLOC_CTX *mem_ctx,
1072 : struct tevent_context *ev,
1073 : struct db_record *rec,
1074 : uint64_t resumed_instance,
1075 : struct server_id blocker)
1076 : {
1077 3624 : struct db_context *db = dbwrap_record_get_db(rec);
1078 3624 : struct db_watched_ctx *ctx = talloc_get_type_abort(
1079 : db->private_data, struct db_watched_ctx);
1080 3624 : struct db_watched_record *wrec = db_record_get_watched_record(rec);
1081 72 : struct tevent_req *req, *subreq;
1082 72 : struct dbwrap_watched_watch_state *state;
1083 72 : uint64_t instance;
1084 :
1085 3624 : req = tevent_req_create(mem_ctx, &state,
1086 : struct dbwrap_watched_watch_state);
1087 3624 : if (req == NULL) {
1088 0 : return NULL;
1089 : }
1090 3624 : state->db = db;
1091 3624 : state->blocker = blocker;
1092 :
1093 3624 : if (ctx->msg == NULL) {
1094 0 : tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED);
1095 0 : return tevent_req_post(req, ev);
1096 : }
1097 :
1098 3624 : if (resumed_instance == 0 && wrec->added.instance == 0) {
1099 : /*
1100 : * Adding a new instance
1101 : */
1102 1155 : instance = dbwrap_watched_watch_add_instance(rec);
1103 2469 : } else if (resumed_instance != 0 && wrec->added.instance == 0) {
1104 : /*
1105 : * Resuming an existing instance that was
1106 : * already present before do_locked started
1107 : */
1108 151 : instance = resumed_instance;
1109 2318 : } else if (resumed_instance == wrec->added.instance) {
1110 : /*
1111 : * The caller used dbwrap_watched_watch_add_instance()
1112 : * already during this do_locked() invocation.
1113 : */
1114 2252 : instance = resumed_instance;
1115 : } else {
1116 1 : tevent_req_nterror(req, NT_STATUS_REQUEST_NOT_ACCEPTED);
1117 1 : return tevent_req_post(req, ev);
1118 : }
1119 :
1120 7246 : state->watcher = (struct dbwrap_watcher) {
1121 3623 : .pid = messaging_server_id(ctx->msg),
1122 : .instance = instance,
1123 : };
1124 :
1125 3623 : state->key = tdb_data_talloc_copy(state, rec->key);
1126 3623 : if (tevent_req_nomem(state->key.dptr, req)) {
1127 0 : return tevent_req_post(req, ev);
1128 : }
1129 :
1130 3623 : subreq = messaging_filtered_read_send(
1131 : state, ev, ctx->msg, dbwrap_watched_msg_filter, state);
1132 3623 : if (tevent_req_nomem(subreq, req)) {
1133 0 : return tevent_req_post(req, ev);
1134 : }
1135 3623 : tevent_req_set_callback(subreq, dbwrap_watched_watch_done, req);
1136 :
1137 3623 : talloc_set_destructor(state, dbwrap_watched_watch_state_destructor);
1138 :
1139 3623 : if (blocker.pid != 0) {
1140 2790 : subreq = server_id_watch_send(state, ev, blocker);
1141 2790 : if (tevent_req_nomem(subreq, req)) {
1142 0 : return tevent_req_post(req, ev);
1143 : }
1144 2790 : tevent_req_set_callback(
1145 : subreq, dbwrap_watched_watch_blocker_died, req);
1146 : }
1147 :
1148 3552 : return req;
1149 : }
1150 :
1151 2 : static void dbwrap_watched_watch_blocker_died(struct tevent_req *subreq)
1152 : {
1153 2 : struct tevent_req *req = tevent_req_callback_data(
1154 : subreq, struct tevent_req);
1155 2 : struct dbwrap_watched_watch_state *state = tevent_req_data(
1156 : req, struct dbwrap_watched_watch_state);
1157 2 : int ret;
1158 :
1159 2 : ret = server_id_watch_recv(subreq, NULL);
1160 2 : TALLOC_FREE(subreq);
1161 2 : if (ret != 0) {
1162 0 : tevent_req_nterror(req, map_nt_error_from_unix(ret));
1163 0 : return;
1164 : }
1165 2 : state->blockerdead = true;
1166 2 : tevent_req_done(req);
1167 : }
1168 :
1169 1792 : static void dbwrap_watched_watch_state_destructor_fn(
1170 : struct db_record *rec,
1171 : TDB_DATA value,
1172 : void *private_data)
1173 : {
1174 1792 : struct dbwrap_watched_watch_state *state = talloc_get_type_abort(
1175 : private_data, struct dbwrap_watched_watch_state);
1176 :
1177 : /*
1178 : * Here we just remove ourself from the in memory
1179 : * watchers array and let db_watched_record_fini()
1180 : * call dbwrap_watched_record_storev() to do the magic
1181 : * of writing back the modified in memory copy.
1182 : */
1183 1792 : dbwrap_watched_watch_remove_instance(rec, state->watcher.instance);
1184 1792 : return;
1185 : }
1186 :
1187 1792 : static int dbwrap_watched_watch_state_destructor(
1188 : struct dbwrap_watched_watch_state *state)
1189 : {
1190 60 : NTSTATUS status;
1191 :
1192 1792 : status = dbwrap_do_locked(
1193 : state->db,
1194 : state->key,
1195 : dbwrap_watched_watch_state_destructor_fn,
1196 : state);
1197 1792 : if (!NT_STATUS_IS_OK(status)) {
1198 0 : DBG_WARNING("dbwrap_do_locked failed: %s\n",
1199 : nt_errstr(status));
1200 : }
1201 1792 : return 0;
1202 : }
1203 :
1204 2048 : static bool dbwrap_watched_msg_filter(struct messaging_rec *rec,
1205 : void *private_data)
1206 : {
1207 2048 : struct dbwrap_watched_watch_state *state = talloc_get_type_abort(
1208 : private_data, struct dbwrap_watched_watch_state);
1209 10 : uint64_t instance;
1210 :
1211 2048 : if (rec->msg_type != MSG_DBWRAP_MODIFIED) {
1212 2 : return false;
1213 : }
1214 2046 : if (rec->num_fds != 0) {
1215 0 : return false;
1216 : }
1217 :
1218 2046 : if (rec->buf.length != sizeof(instance)) {
1219 0 : DBG_DEBUG("Got size %zu, expected %zu\n",
1220 : rec->buf.length,
1221 : sizeof(instance));
1222 0 : return false;
1223 : }
1224 :
1225 2046 : instance = BVAL(rec->buf.data, 0);
1226 :
1227 2046 : if (instance != state->watcher.instance) {
1228 217 : DBG_DEBUG("Got instance %"PRIu64", expected %"PRIu64"\n",
1229 : instance,
1230 : state->watcher.instance);
1231 217 : return false;
1232 : }
1233 :
1234 1820 : return true;
1235 : }
1236 :
1237 1829 : static void dbwrap_watched_watch_done(struct tevent_req *subreq)
1238 : {
1239 1829 : struct tevent_req *req = tevent_req_callback_data(
1240 : subreq, struct tevent_req);
1241 1829 : struct dbwrap_watched_watch_state *state = tevent_req_data(
1242 : req, struct dbwrap_watched_watch_state);
1243 9 : struct messaging_rec *rec;
1244 9 : int ret;
1245 :
1246 1829 : ret = messaging_filtered_read_recv(subreq, state, &rec);
1247 1829 : TALLOC_FREE(subreq);
1248 1829 : if (ret != 0) {
1249 0 : tevent_req_nterror(req, map_nt_error_from_unix(ret));
1250 0 : return;
1251 : }
1252 1829 : tevent_req_done(req);
1253 : }
1254 :
1255 1832 : NTSTATUS dbwrap_watched_watch_recv(struct tevent_req *req,
1256 : uint64_t *pkeep_instance,
1257 : bool *blockerdead,
1258 : struct server_id *blocker)
1259 : {
1260 1832 : struct dbwrap_watched_watch_state *state = tevent_req_data(
1261 : req, struct dbwrap_watched_watch_state);
1262 12 : NTSTATUS status;
1263 :
1264 1832 : if (tevent_req_is_nterror(req, &status)) {
1265 1 : tevent_req_received(req);
1266 1 : return status;
1267 : }
1268 1831 : if (pkeep_instance != NULL) {
1269 1829 : *pkeep_instance = state->watcher.instance;
1270 : /*
1271 : * No need to remove ourselves anymore,
1272 : * the caller will take care of removing itself.
1273 : */
1274 1829 : talloc_set_destructor(state, NULL);
1275 : }
1276 1831 : if (blockerdead != NULL) {
1277 1734 : *blockerdead = state->blockerdead;
1278 : }
1279 1831 : if (blocker != NULL) {
1280 1734 : *blocker = state->blocker;
1281 : }
1282 1831 : tevent_req_received(req);
1283 1831 : return NT_STATUS_OK;
1284 : }
1285 :
|