LCOV - code coverage report
Current view: top level - source3/lib/dbwrap - dbwrap_watch.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 326 463 70.4 %
Date: 2021-09-23 10:06:22 Functions: 31 42 73.8 %

          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 "server_id_watch.h"
      29             : #include "lib/dbwrap/dbwrap_private.h"
      30             : 
      31             : struct dbwrap_watcher {
      32             :         /*
      33             :          * Process watching this record
      34             :          */
      35             :         struct server_id pid;
      36             :         /*
      37             :          * Individual instance inside the waiter, incremented each
      38             :          * time a watcher is created
      39             :          */
      40             :         uint64_t instance;
      41             : };
      42             : 
      43             : #define DBWRAP_WATCHER_BUF_LENGTH (SERVER_ID_BUF_LENGTH + sizeof(uint64_t))
      44             : 
      45             : /*
      46             :  * Watched records contain a header of:
      47             :  *
      48             :  * [uint32] num_records
      49             :  * 0 [DBWRAP_WATCHER_BUF_LENGTH]              \
      50             :  * 1 [DBWRAP_WATCHER_BUF_LENGTH]              |
      51             :  * ..                                         |- Array of watchers
      52             :  * (num_records-1)[DBWRAP_WATCHER_BUF_LENGTH] /
      53             :  *
      54             :  * [Remainder of record....]
      55             :  *
      56             :  * If this header is absent then this is a
      57             :  * fresh record of length zero (no watchers).
      58             :  */
      59             : 
      60    12893698 : static bool dbwrap_watch_rec_parse(
      61             :         TDB_DATA data,
      62             :         uint8_t **pwatchers,
      63             :         size_t *pnum_watchers,
      64             :         TDB_DATA *pdata)
      65             : {
      66             :         size_t num_watchers;
      67             : 
      68    12893698 :         if (data.dsize == 0) {
      69             :                 /* Fresh record */
      70      950410 :                 if (pwatchers != NULL) {
      71      475145 :                         *pwatchers = NULL;
      72             :                 }
      73      950410 :                 if (pnum_watchers != NULL) {
      74      475145 :                         *pnum_watchers = 0;
      75             :                 }
      76      950410 :                 if (pdata != NULL) {
      77      475303 :                         *pdata = (TDB_DATA) { .dptr = NULL };
      78             :                 }
      79      947125 :                 return true;
      80             :         }
      81             : 
      82    11943288 :         if (data.dsize < sizeof(uint32_t)) {
      83             :                 /* Invalid record */
      84           0 :                 return false;
      85             :         }
      86             : 
      87    11943288 :         num_watchers = IVAL(data.dptr, 0);
      88             : 
      89    11943288 :         data.dptr += sizeof(uint32_t);
      90    11943288 :         data.dsize -= sizeof(uint32_t);
      91             : 
      92    11943288 :         if (num_watchers > data.dsize/DBWRAP_WATCHER_BUF_LENGTH) {
      93             :                 /* Invalid record */
      94           0 :                 return false;
      95             :         }
      96             : 
      97    11943287 :         if (pwatchers != NULL) {
      98     3706889 :                 *pwatchers = data.dptr;
      99             :         }
     100    11943287 :         if (pnum_watchers != NULL) {
     101     3706889 :                 *pnum_watchers = num_watchers;
     102             :         }
     103    11943287 :         if (pdata != NULL) {
     104     8241831 :                 size_t watchers_len = num_watchers * DBWRAP_WATCHER_BUF_LENGTH;
     105     8241831 :                 *pdata = (TDB_DATA) {
     106     8241831 :                         .dptr = data.dptr + watchers_len,
     107     8241831 :                         .dsize = data.dsize - watchers_len
     108             :                 };
     109             :         }
     110             : 
     111    11917981 :         return true;
     112             : }
     113             : 
     114        3900 : static void dbwrap_watcher_get(struct dbwrap_watcher *w,
     115             :                                const uint8_t buf[DBWRAP_WATCHER_BUF_LENGTH])
     116             : {
     117        3900 :         server_id_get(&w->pid, buf);
     118        3900 :         w->instance = BVAL(buf, SERVER_ID_BUF_LENGTH);
     119        3900 : }
     120             : 
     121        3857 : static void dbwrap_watcher_put(uint8_t buf[DBWRAP_WATCHER_BUF_LENGTH],
     122             :                                const struct dbwrap_watcher *w)
     123             : {
     124        3857 :         server_id_put(buf, w->pid);
     125        3857 :         SBVAL(buf, SERVER_ID_BUF_LENGTH, w->instance);
     126        3857 : }
     127             : 
     128           1 : static void dbwrap_watch_log_invalid_record(
     129             :         struct db_context *db, TDB_DATA key, TDB_DATA value)
     130             : {
     131           1 :         DBG_ERR("Found invalid record in %s\n", dbwrap_name(db));
     132           1 :         dump_data(1, key.dptr, key.dsize);
     133           1 :         dump_data(1, value.dptr, value.dsize);
     134           1 : }
     135             : 
     136             : struct db_watched_ctx {
     137             :         struct db_context *backend;
     138             :         struct messaging_context *msg;
     139             : };
     140             : 
     141             : struct db_watched_subrec {
     142             :         struct db_record *subrec;
     143             :         struct dbwrap_watcher added;
     144             : };
     145             : 
     146             : static NTSTATUS dbwrap_watched_subrec_storev(
     147             :         struct db_record *rec, struct db_watched_subrec *subrec,
     148             :         const TDB_DATA *dbufs, int num_dbufs, int flags);
     149             : static NTSTATUS dbwrap_watched_subrec_delete(
     150             :         struct db_record *rec, struct db_watched_subrec *subrec);
     151             : static NTSTATUS dbwrap_watched_storev(struct db_record *rec,
     152             :                                       const TDB_DATA *dbufs, int num_dbufs,
     153             :                                       int flags);
     154             : static NTSTATUS dbwrap_watched_delete(struct db_record *rec);
     155             : static void dbwrap_watched_subrec_wakeup(
     156             :         struct db_record *rec, struct db_watched_subrec *subrec);
     157             : static int db_watched_subrec_destructor(struct db_watched_subrec *s);
     158             : 
     159      210625 : static struct db_record *dbwrap_watched_fetch_locked(
     160             :         struct db_context *db, TALLOC_CTX *mem_ctx, TDB_DATA key)
     161             : {
     162      210625 :         struct db_watched_ctx *ctx = talloc_get_type_abort(
     163             :                 db->private_data, struct db_watched_ctx);
     164             :         struct db_record *rec;
     165             :         struct db_watched_subrec *subrec;
     166             :         TDB_DATA subrec_value;
     167             :         bool ok;
     168             : 
     169      210625 :         rec = talloc_zero(mem_ctx, struct db_record);
     170      210625 :         if (rec == NULL) {
     171           0 :                 return NULL;
     172             :         }
     173      210625 :         subrec = talloc_zero(rec, struct db_watched_subrec);
     174      210625 :         if (subrec == NULL) {
     175           0 :                 TALLOC_FREE(rec);
     176           0 :                 return NULL;
     177             :         }
     178      210625 :         talloc_set_destructor(subrec, db_watched_subrec_destructor);
     179      210625 :         rec->private_data = subrec;
     180             : 
     181      210625 :         subrec->subrec = dbwrap_fetch_locked(ctx->backend, subrec, key);
     182      210625 :         if (subrec->subrec == NULL) {
     183           0 :                 TALLOC_FREE(rec);
     184           0 :                 return NULL;
     185             :         }
     186             : 
     187      210625 :         rec->db = db;
     188      210625 :         rec->key = dbwrap_record_get_key(subrec->subrec);
     189      210625 :         rec->storev = dbwrap_watched_storev;
     190      210625 :         rec->delete_rec = dbwrap_watched_delete;
     191             : 
     192      210625 :         subrec_value = dbwrap_record_get_value(subrec->subrec);
     193             : 
     194      210625 :         ok = dbwrap_watch_rec_parse(subrec_value, NULL, NULL, &rec->value);
     195      210625 :         if (!ok) {
     196           0 :                 dbwrap_watch_log_invalid_record(db, rec->key, subrec_value);
     197             :                 /* wipe invalid data */
     198           0 :                 rec->value = (TDB_DATA) { .dptr = NULL, .dsize = 0 };
     199             :         }
     200      210625 :         rec->value_valid = true;
     201             : 
     202      210625 :         return rec;
     203             : }
     204             : 
     205             : struct dbwrap_watched_add_watcher_state {
     206             :         struct dbwrap_watcher w;
     207             :         NTSTATUS status;
     208             : };
     209             : 
     210        3857 : static void dbwrap_watched_add_watcher(
     211             :         struct db_record *rec,
     212             :         TDB_DATA value,
     213             :         void *private_data)
     214             : {
     215        3857 :         struct dbwrap_watched_add_watcher_state *state = private_data;
     216        3857 :         size_t num_watchers = 0;
     217             :         bool ok;
     218             : 
     219             :         uint8_t num_watchers_buf[4];
     220             :         uint8_t add_buf[DBWRAP_WATCHER_BUF_LENGTH];
     221             : 
     222        3857 :         TDB_DATA dbufs[4] = {
     223             :                 {
     224             :                         .dptr = num_watchers_buf,
     225             :                         .dsize = sizeof(num_watchers_buf),
     226             :                 },
     227             :                 { 0 },          /* filled in with existing watchers */
     228             :                 {
     229             :                         .dptr = add_buf,
     230             :                         .dsize = sizeof(add_buf),
     231             :                 },
     232             :                 { 0 },          /* filled in with existing data */
     233             :         };
     234             : 
     235        3857 :         dbwrap_watcher_put(add_buf, &state->w);
     236             : 
     237        3857 :         ok = dbwrap_watch_rec_parse(
     238             :                 value, &dbufs[1].dptr, &num_watchers, &dbufs[3]);
     239        3857 :         if (!ok) {
     240           0 :                 struct db_context *db = dbwrap_record_get_db(rec);
     241           0 :                 TDB_DATA key = dbwrap_record_get_key(rec);
     242             : 
     243           0 :                 dbwrap_watch_log_invalid_record(db, key, value);
     244             : 
     245             :                 /* wipe invalid data */
     246           0 :                 num_watchers = 0;
     247           0 :                 dbufs[3] = (TDB_DATA) { .dptr = NULL, .dsize = 0 };
     248             :         }
     249             : 
     250        3857 :         dbufs[1].dsize = num_watchers * DBWRAP_WATCHER_BUF_LENGTH;
     251             : 
     252        3857 :         if (num_watchers >= UINT32_MAX) {
     253           0 :                 DBG_DEBUG("Can't handle %zu watchers\n",
     254             :                           num_watchers+1);
     255           0 :                 state->status = NT_STATUS_INSUFFICIENT_RESOURCES;
     256           0 :                 return;
     257             :         }
     258             : 
     259        3857 :         num_watchers += 1;
     260        3857 :         SIVAL(num_watchers_buf, 0, num_watchers);
     261             : 
     262        3857 :         state->status = dbwrap_record_storev(rec, dbufs, ARRAY_SIZE(dbufs), 0);
     263             : }
     264             : 
     265     4182150 : static int db_watched_subrec_destructor(struct db_watched_subrec *s)
     266             : {
     267     4182150 :         struct dbwrap_watched_add_watcher_state state = { .w = s->added };
     268     4182150 :         struct db_context *backend = dbwrap_record_get_db(s->subrec);
     269             :         NTSTATUS status;
     270             : 
     271     4182150 :         if (s->added.pid.pid == 0) {
     272     4167945 :                 return 0;
     273             :         }
     274             : 
     275        3857 :         status = dbwrap_do_locked(
     276        3857 :                 backend, s->subrec->key, dbwrap_watched_add_watcher, &state);
     277        3857 :         if (!NT_STATUS_IS_OK(status)) {
     278           0 :                 DBG_WARNING("dbwrap_do_locked failed: %s\n",
     279             :                             nt_errstr(status));
     280           0 :                 return 0;
     281             :         }
     282        3857 :         if (!NT_STATUS_IS_OK(state.status)) {
     283           0 :                 DBG_WARNING("dbwrap_watched_add_watcher failed: %s\n",
     284             :                             nt_errstr(state.status));
     285           0 :                 return 0;
     286             :         }
     287        3841 :         return 0;
     288             : }
     289             : 
     290             : struct dbwrap_watched_subrec_wakeup_state {
     291             :         struct messaging_context *msg_ctx;
     292             : };
     293             : static void dbwrap_watched_subrec_wakeup_fn(
     294             :         struct db_record *rec,
     295             :         TDB_DATA value,
     296             :         void *private_data);
     297             : 
     298             : struct dbwrap_watched_do_locked_state {
     299             :         struct db_context *db;
     300             :         void (*fn)(struct db_record *rec,
     301             :                    TDB_DATA value,
     302             :                    void *private_data);
     303             :         void *private_data;
     304             : 
     305             :         struct db_watched_subrec subrec;
     306             : 
     307             :         /*
     308             :          * This contains the initial value we got
     309             :          * passed to dbwrap_watched_do_locked_fn()
     310             :          *
     311             :          * It's only used in order to pass it
     312             :          * to dbwrap_watched_subrec_wakeup_fn()
     313             :          * in dbwrap_watched_do_locked_{storev,delete}()
     314             :          *
     315             :          * It gets cleared after the first call to
     316             :          * dbwrap_watched_subrec_wakeup_fn() as we
     317             :          * only need to wakeup once per dbwrap_do_locked().
     318             :          */
     319             :         TDB_DATA wakeup_value;
     320             : 
     321             :         NTSTATUS status;
     322             : };
     323             : 
     324     3540992 : static NTSTATUS dbwrap_watched_do_locked_storev(
     325             :         struct db_record *rec, const TDB_DATA *dbufs, int num_dbufs,
     326             :         int flags)
     327             : {
     328     3540992 :         struct dbwrap_watched_do_locked_state *state = rec->private_data;
     329     3540992 :         struct db_watched_subrec *subrec = &state->subrec;
     330     3540992 :         struct db_watched_ctx *ctx = talloc_get_type_abort(
     331             :                 state->db->private_data, struct db_watched_ctx);
     332     3540992 :         struct dbwrap_watched_subrec_wakeup_state wakeup_state = {
     333     3540992 :                 .msg_ctx = ctx->msg,
     334             :         };
     335             :         NTSTATUS status;
     336             : 
     337             :         /*
     338             :          * Wakeup only needs to happen once.
     339             :          * so we clear state->wakeup_value after the first run
     340             :          */
     341     3540992 :         dbwrap_watched_subrec_wakeup_fn(rec, state->wakeup_value, &wakeup_state);
     342     3540992 :         state->wakeup_value = (TDB_DATA) { .dsize = 0, };
     343             : 
     344     3540992 :         status = dbwrap_watched_subrec_storev(rec, subrec, dbufs, num_dbufs,
     345             :                                               flags);
     346     3540992 :         return status;
     347             : }
     348             : 
     349      426950 : static NTSTATUS dbwrap_watched_do_locked_delete(struct db_record *rec)
     350             : {
     351      426950 :         struct dbwrap_watched_do_locked_state *state = rec->private_data;
     352      426950 :         struct db_watched_subrec *subrec = &state->subrec;
     353      426950 :         struct db_watched_ctx *ctx = talloc_get_type_abort(
     354             :                 state->db->private_data, struct db_watched_ctx);
     355      426950 :         struct dbwrap_watched_subrec_wakeup_state wakeup_state = {
     356      426950 :                 .msg_ctx = ctx->msg,
     357             :         };
     358             :         NTSTATUS status;
     359             : 
     360             :         /*
     361             :          * Wakeup only needs to happen once.
     362             :          * so we clear state->wakeup_value after the first run
     363             :          */
     364      426950 :         dbwrap_watched_subrec_wakeup_fn(rec, state->wakeup_value, &wakeup_state);
     365      426950 :         state->wakeup_value = (TDB_DATA) { .dsize = 0, };
     366             : 
     367      426950 :         status = dbwrap_watched_subrec_delete(rec, subrec);
     368      426950 :         return status;
     369             : }
     370             : 
     371     3971526 : static void dbwrap_watched_do_locked_fn(
     372             :         struct db_record *subrec,
     373             :         TDB_DATA subrec_value,
     374             :         void *private_data)
     375             : {
     376     3971526 :         struct dbwrap_watched_do_locked_state *state =
     377             :                 (struct dbwrap_watched_do_locked_state *)private_data;
     378     3971526 :         TDB_DATA value = {0};
     379     7943052 :         struct db_record rec = {
     380     3971526 :                 .db = state->db,
     381      529638 :                 .key = dbwrap_record_get_key(subrec),
     382             :                 .value_valid = true,
     383             :                 .storev = dbwrap_watched_do_locked_storev,
     384             :                 .delete_rec = dbwrap_watched_do_locked_delete,
     385             :                 .private_data = state
     386             :         };
     387             :         bool ok;
     388             : 
     389     3971526 :         state->subrec = (struct db_watched_subrec) {
     390             :                 .subrec = subrec
     391             :         };
     392     3971526 :         state->wakeup_value = subrec_value;
     393             : 
     394     3971526 :         ok = dbwrap_watch_rec_parse(subrec_value, NULL, NULL, &value);
     395     3971526 :         if (!ok) {
     396           0 :                 dbwrap_watch_log_invalid_record(rec.db, rec.key, subrec_value);
     397             :                 /* wipe invalid data */
     398           0 :                 value = (TDB_DATA) { .dptr = NULL, .dsize = 0 };
     399             :         }
     400             : 
     401     3971526 :         state->fn(&rec, value, state->private_data);
     402             : 
     403     3971526 :         db_watched_subrec_destructor(&state->subrec);
     404     3971526 : }
     405             : 
     406     3971526 : static NTSTATUS dbwrap_watched_do_locked(struct db_context *db, TDB_DATA key,
     407             :                                          void (*fn)(struct db_record *rec,
     408             :                                                     TDB_DATA value,
     409             :                                                     void *private_data),
     410             :                                          void *private_data)
     411             : {
     412     3971526 :         struct db_watched_ctx *ctx = talloc_get_type_abort(
     413             :                 db->private_data, struct db_watched_ctx);
     414     3971526 :         struct dbwrap_watched_do_locked_state state = {
     415             :                 .db = db, .fn = fn, .private_data = private_data
     416             :         };
     417             :         NTSTATUS status;
     418             : 
     419     3971526 :         status = dbwrap_do_locked(
     420             :                 ctx->backend, key, dbwrap_watched_do_locked_fn, &state);
     421     3971526 :         if (!NT_STATUS_IS_OK(status)) {
     422           0 :                 DBG_DEBUG("dbwrap_do_locked returned %s\n", nt_errstr(status));
     423           0 :                 return status;
     424             :         }
     425             : 
     426     3971526 :         DBG_DEBUG("dbwrap_watched_do_locked_fn returned %s\n",
     427             :                   nt_errstr(state.status));
     428             : 
     429     3971526 :         return state.status;
     430             : }
     431             : 
     432     4176563 : static void dbwrap_watched_subrec_wakeup_fn(
     433             :         struct db_record *rec,
     434             :         TDB_DATA value,
     435             :         void *private_data)
     436             : {
     437     4176563 :         struct dbwrap_watched_subrec_wakeup_state *state = private_data;
     438             :         uint8_t *watchers;
     439     4176563 :         size_t num_watchers = 0;
     440             :         size_t i;
     441             :         bool ok;
     442             : 
     443     4176563 :         ok = dbwrap_watch_rec_parse(value, &watchers, &num_watchers, NULL);
     444     4176563 :         if (!ok) {
     445           0 :                 struct db_context *db = dbwrap_record_get_db(rec);
     446           0 :                 TDB_DATA key = dbwrap_record_get_key(rec);
     447           0 :                 dbwrap_watch_log_invalid_record(db, key, value);
     448           0 :                 return;
     449             :         }
     450             : 
     451     4176563 :         if (num_watchers == 0) {
     452     4174403 :                 DBG_DEBUG("No watchers\n");
     453     4164065 :                 return;
     454             :         }
     455             : 
     456        4443 :         for (i=0; i<num_watchers; i++) {
     457             :                 struct dbwrap_watcher watcher;
     458             :                 struct server_id_buf tmp;
     459             :                 uint8_t instance_buf[8];
     460             :                 NTSTATUS status;
     461             : 
     462        4468 :                 dbwrap_watcher_get(
     463        2290 :                         &watcher, watchers + i*DBWRAP_WATCHER_BUF_LENGTH);
     464             : 
     465        2290 :                 DBG_DEBUG("Alerting %s:%"PRIu64"\n",
     466             :                           server_id_str_buf(watcher.pid, &tmp),
     467             :                           watcher.instance);
     468             : 
     469        2290 :                 SBVAL(instance_buf, 0, watcher.instance);
     470             : 
     471        2290 :                 status = messaging_send_buf(
     472             :                         state->msg_ctx,
     473             :                         watcher.pid,
     474             :                         MSG_DBWRAP_MODIFIED,
     475             :                         instance_buf,
     476             :                         sizeof(instance_buf));
     477        2290 :                 if (!NT_STATUS_IS_OK(status)) {
     478           0 :                         DBG_DEBUG("messaging_send_buf to %s failed: %s\n",
     479             :                                   server_id_str_buf(watcher.pid, &tmp),
     480             :                                   nt_errstr(status));
     481             :                 }
     482             :         }
     483             : }
     484             : 
     485     4176563 : static void dbwrap_watched_subrec_wakeup(
     486             :         struct db_record *rec, struct db_watched_subrec *subrec)
     487             : {
     488     4176563 :         struct db_context *backend = dbwrap_record_get_db(subrec->subrec);
     489     4176563 :         struct db_context *db = dbwrap_record_get_db(rec);
     490     4176563 :         struct db_watched_ctx *ctx = talloc_get_type_abort(
     491             :                 db->private_data, struct db_watched_ctx);
     492     4176563 :         struct dbwrap_watched_subrec_wakeup_state state = {
     493     4176563 :                 .msg_ctx = ctx->msg,
     494             :         };
     495             :         NTSTATUS status;
     496             : 
     497     4176563 :         if (rec->storev == dbwrap_watched_do_locked_storev) {
     498             :                 /*
     499             :                  * This is handled in the caller,
     500             :                  * as we need to avoid recursion
     501             :                  * into dbwrap_do_locked().
     502             :                  */
     503     3967942 :                 return;
     504             :         }
     505             : 
     506      208621 :         status = dbwrap_do_locked(
     507             :                 backend,
     508      208621 :                 subrec->subrec->key,
     509             :                 dbwrap_watched_subrec_wakeup_fn,
     510             :                 &state);
     511      208621 :         if (!NT_STATUS_IS_OK(status)) {
     512           0 :                 DBG_DEBUG("dbwrap_record_modify failed: %s\n",
     513             :                           nt_errstr(status));
     514             :         }
     515             : }
     516             : 
     517     3701500 : static NTSTATUS dbwrap_watched_subrec_storev(
     518             :         struct db_record *rec, struct db_watched_subrec *subrec,
     519             :         const TDB_DATA *dbufs, int num_dbufs, int flags)
     520     3701500 : {
     521     3701500 :         uint8_t num_watchers_buf[4] = { 0 };
     522     3701500 :         TDB_DATA my_dbufs[num_dbufs+1];
     523             :         NTSTATUS status;
     524             : 
     525     3701500 :         dbwrap_watched_subrec_wakeup(rec, subrec);
     526             : 
     527             :         /*
     528             :          * Watchers only informed once, set num_watchers to 0
     529             :          */
     530     3701500 :         my_dbufs[0] = (TDB_DATA) {
     531             :                 .dptr = num_watchers_buf, .dsize = sizeof(num_watchers_buf),
     532             :         };
     533     3701500 :         if (num_dbufs != 0) {
     534     3701500 :                 memcpy(my_dbufs+1, dbufs, num_dbufs * sizeof(*dbufs));
     535             :         }
     536             : 
     537     3701500 :         status = dbwrap_record_storev(
     538     3701500 :                 subrec->subrec, my_dbufs, ARRAY_SIZE(my_dbufs), flags);
     539     3701500 :         return status;
     540             : }
     541             : 
     542      160508 : static NTSTATUS dbwrap_watched_storev(struct db_record *rec,
     543             :                                       const TDB_DATA *dbufs, int num_dbufs,
     544             :                                       int flags)
     545             : {
     546      160508 :         struct db_watched_subrec *subrec = talloc_get_type_abort(
     547             :                 rec->private_data, struct db_watched_subrec);
     548             :         NTSTATUS status;
     549             : 
     550      160508 :         status = dbwrap_watched_subrec_storev(rec, subrec, dbufs, num_dbufs,
     551             :                                               flags);
     552      160508 :         return status;
     553             : }
     554             : 
     555      475063 : static NTSTATUS dbwrap_watched_subrec_delete(
     556             :         struct db_record *rec, struct db_watched_subrec *subrec)
     557             : {
     558             :         NTSTATUS status;
     559             : 
     560      475063 :         dbwrap_watched_subrec_wakeup(rec, subrec);
     561             : 
     562             :         /*
     563             :          * Watchers were informed, we can throw away the record now
     564             :          */
     565      475063 :         status = dbwrap_record_delete(subrec->subrec);
     566      475063 :         return status;
     567             : }
     568             : 
     569       48113 : static NTSTATUS dbwrap_watched_delete(struct db_record *rec)
     570             : {
     571       48113 :         struct db_watched_subrec *subrec = talloc_get_type_abort(
     572             :                 rec->private_data, struct db_watched_subrec);
     573             :         NTSTATUS status;
     574             : 
     575       48113 :         status = dbwrap_watched_subrec_delete(rec, subrec);
     576       48113 :         return status;
     577             : }
     578             : 
     579             : struct dbwrap_watched_traverse_state {
     580             :         int (*fn)(struct db_record *rec, void *private_data);
     581             :         void *private_data;
     582             : };
     583             : 
     584       17885 : static int dbwrap_watched_traverse_fn(struct db_record *rec,
     585             :                                       void *private_data)
     586             : {
     587       17885 :         struct dbwrap_watched_traverse_state *state = private_data;
     588       17885 :         struct db_record prec = *rec;
     589             :         bool ok;
     590             : 
     591       17885 :         ok = dbwrap_watch_rec_parse(rec->value, NULL, NULL, &prec.value);
     592       17885 :         if (!ok) {
     593           0 :                 return 0;
     594             :         }
     595       17885 :         prec.value_valid = true;
     596             : 
     597       17885 :         return state->fn(&prec, state->private_data);
     598             : }
     599             : 
     600           0 : static int dbwrap_watched_traverse(struct db_context *db,
     601             :                                    int (*fn)(struct db_record *rec,
     602             :                                              void *private_data),
     603             :                                    void *private_data)
     604             : {
     605           0 :         struct db_watched_ctx *ctx = talloc_get_type_abort(
     606             :                 db->private_data, struct db_watched_ctx);
     607           0 :         struct dbwrap_watched_traverse_state state = {
     608             :                 .fn = fn, .private_data = private_data };
     609             :         NTSTATUS status;
     610             :         int ret;
     611             : 
     612           0 :         status = dbwrap_traverse(
     613             :                 ctx->backend, dbwrap_watched_traverse_fn, &state, &ret);
     614           0 :         if (!NT_STATUS_IS_OK(status)) {
     615           0 :                 return -1;
     616             :         }
     617           0 :         return ret;
     618             : }
     619             : 
     620        5972 : static int dbwrap_watched_traverse_read(struct db_context *db,
     621             :                                         int (*fn)(struct db_record *rec,
     622             :                                                   void *private_data),
     623             :                                         void *private_data)
     624             : {
     625        5972 :         struct db_watched_ctx *ctx = talloc_get_type_abort(
     626             :                 db->private_data, struct db_watched_ctx);
     627        5972 :         struct dbwrap_watched_traverse_state state = {
     628             :                 .fn = fn, .private_data = private_data };
     629             :         NTSTATUS status;
     630             :         int ret;
     631             : 
     632        5972 :         status = dbwrap_traverse_read(
     633             :                 ctx->backend, dbwrap_watched_traverse_fn, &state, &ret);
     634        5972 :         if (!NT_STATUS_IS_OK(status)) {
     635           0 :                 return -1;
     636             :         }
     637        5972 :         return ret;
     638             : }
     639             : 
     640      175807 : static int dbwrap_watched_get_seqnum(struct db_context *db)
     641             : {
     642      175807 :         struct db_watched_ctx *ctx = talloc_get_type_abort(
     643             :                 db->private_data, struct db_watched_ctx);
     644      175807 :         return dbwrap_get_seqnum(ctx->backend);
     645             : }
     646             : 
     647           0 : static int dbwrap_watched_transaction_start(struct db_context *db)
     648             : {
     649           0 :         struct db_watched_ctx *ctx = talloc_get_type_abort(
     650             :                 db->private_data, struct db_watched_ctx);
     651           0 :         return dbwrap_transaction_start(ctx->backend);
     652             : }
     653             : 
     654           0 : static int dbwrap_watched_transaction_commit(struct db_context *db)
     655             : {
     656           0 :         struct db_watched_ctx *ctx = talloc_get_type_abort(
     657             :                 db->private_data, struct db_watched_ctx);
     658           0 :         return dbwrap_transaction_commit(ctx->backend);
     659             : }
     660             : 
     661           0 : static int dbwrap_watched_transaction_cancel(struct db_context *db)
     662             : {
     663           0 :         struct db_watched_ctx *ctx = talloc_get_type_abort(
     664             :                 db->private_data, struct db_watched_ctx);
     665           0 :         return dbwrap_transaction_cancel(ctx->backend);
     666             : }
     667             : 
     668             : struct dbwrap_watched_parse_record_state {
     669             :         struct db_context *db;
     670             :         void (*parser)(TDB_DATA key, TDB_DATA data, void *private_data);
     671             :         void *private_data;
     672             :         bool ok;
     673             : };
     674             : 
     675     4511628 : static void dbwrap_watched_parse_record_parser(TDB_DATA key, TDB_DATA data,
     676             :                                                void *private_data)
     677             : {
     678     4511628 :         struct dbwrap_watched_parse_record_state *state = private_data;
     679             :         TDB_DATA userdata;
     680             : 
     681     4511628 :         state->ok = dbwrap_watch_rec_parse(data, NULL, NULL, &userdata);
     682     4511628 :         if (!state->ok) {
     683           1 :                 dbwrap_watch_log_invalid_record(state->db, key, data);
     684           1 :                 return;
     685             :         }
     686             : 
     687     4511627 :         state->parser(key, userdata, state->private_data);
     688             : }
     689             : 
     690     4933937 : static NTSTATUS dbwrap_watched_parse_record(
     691             :         struct db_context *db, TDB_DATA key,
     692             :         void (*parser)(TDB_DATA key, TDB_DATA data, void *private_data),
     693             :         void *private_data)
     694             : {
     695     4933937 :         struct db_watched_ctx *ctx = talloc_get_type_abort(
     696             :                 db->private_data, struct db_watched_ctx);
     697     4933937 :         struct dbwrap_watched_parse_record_state state = {
     698             :                 .db = db,
     699             :                 .parser = parser,
     700             :                 .private_data = private_data,
     701             :         };
     702             :         NTSTATUS status;
     703             : 
     704     4933937 :         status = dbwrap_parse_record(
     705             :                 ctx->backend, key, dbwrap_watched_parse_record_parser, &state);
     706     4933937 :         if (!NT_STATUS_IS_OK(status)) {
     707      422309 :                 return status;
     708             :         }
     709     4511628 :         if (!state.ok) {
     710           1 :                 return NT_STATUS_NOT_FOUND;
     711             :         }
     712     4511627 :         return NT_STATUS_OK;
     713             : }
     714             : 
     715             : static void dbwrap_watched_parse_record_done(struct tevent_req *subreq);
     716             : 
     717           0 : static struct tevent_req *dbwrap_watched_parse_record_send(
     718             :         TALLOC_CTX *mem_ctx,
     719             :         struct tevent_context *ev,
     720             :         struct db_context *db,
     721             :         TDB_DATA key,
     722             :         void (*parser)(TDB_DATA key, TDB_DATA data, void *private_data),
     723             :         void *private_data,
     724             :         enum dbwrap_req_state *req_state)
     725             : {
     726           0 :         struct db_watched_ctx *ctx = talloc_get_type_abort(
     727             :                 db->private_data, struct db_watched_ctx);
     728           0 :         struct tevent_req *req = NULL;
     729           0 :         struct tevent_req *subreq = NULL;
     730           0 :         struct dbwrap_watched_parse_record_state *state = NULL;
     731             : 
     732           0 :         req = tevent_req_create(mem_ctx, &state,
     733             :                                 struct dbwrap_watched_parse_record_state);
     734           0 :         if (req == NULL) {
     735           0 :                 *req_state = DBWRAP_REQ_ERROR;
     736           0 :                 return NULL;
     737             :         }
     738             : 
     739           0 :         *state = (struct dbwrap_watched_parse_record_state) {
     740             :                 .parser = parser,
     741             :                 .private_data = private_data,
     742             :                 .ok = true,
     743             :         };
     744             : 
     745           0 :         subreq = dbwrap_parse_record_send(state,
     746             :                                           ev,
     747             :                                           ctx->backend,
     748             :                                           key,
     749             :                                           dbwrap_watched_parse_record_parser,
     750             :                                           state,
     751             :                                           req_state);
     752           0 :         if (tevent_req_nomem(subreq, req)) {
     753           0 :                 *req_state = DBWRAP_REQ_ERROR;
     754           0 :                 return tevent_req_post(req, ev);
     755             :         }
     756             : 
     757           0 :         tevent_req_set_callback(subreq, dbwrap_watched_parse_record_done, req);
     758           0 :         return req;
     759             : }
     760             : 
     761           0 : static void dbwrap_watched_parse_record_done(struct tevent_req *subreq)
     762             : {
     763           0 :         struct tevent_req *req = tevent_req_callback_data(
     764             :                 subreq, struct tevent_req);
     765           0 :         struct dbwrap_watched_parse_record_state *state = tevent_req_data(
     766             :                 req, struct dbwrap_watched_parse_record_state);
     767             :         NTSTATUS status;
     768             : 
     769           0 :         status = dbwrap_parse_record_recv(subreq);
     770           0 :         TALLOC_FREE(subreq);
     771           0 :         if (tevent_req_nterror(req, status)) {
     772           0 :                 return;
     773             :         }
     774             : 
     775           0 :         if (!state->ok) {
     776           0 :                 tevent_req_nterror(req, NT_STATUS_NOT_FOUND);
     777           0 :                 return;
     778             :         }
     779             : 
     780           0 :         tevent_req_done(req);
     781           0 :         return;
     782             : }
     783             : 
     784           0 : static NTSTATUS dbwrap_watched_parse_record_recv(struct tevent_req *req)
     785             : {
     786             :         NTSTATUS status;
     787             : 
     788           0 :         if (tevent_req_is_nterror(req, &status)) {
     789           0 :                 tevent_req_received(req);
     790           0 :                 return status;
     791             :         }
     792             : 
     793           0 :         tevent_req_received(req);
     794           0 :         return NT_STATUS_OK;
     795             : }
     796             : 
     797           0 : static int dbwrap_watched_exists(struct db_context *db, TDB_DATA key)
     798             : {
     799           0 :         struct db_watched_ctx *ctx = talloc_get_type_abort(
     800             :                 db->private_data, struct db_watched_ctx);
     801             : 
     802           0 :         return dbwrap_exists(ctx->backend, key);
     803             : }
     804             : 
     805           0 : static size_t dbwrap_watched_id(struct db_context *db, uint8_t *id,
     806             :                                 size_t idlen)
     807             : {
     808           0 :         struct db_watched_ctx *ctx = talloc_get_type_abort(
     809             :                 db->private_data, struct db_watched_ctx);
     810             : 
     811           0 :         return dbwrap_db_id(ctx->backend, id, idlen);
     812             : }
     813             : 
     814           0 : static void dbwrap_watched_wakeup_fn(
     815             :         struct db_record *rec,
     816             :         TDB_DATA value,
     817             :         void *private_data)
     818             : {
     819           0 :         uint8_t num_watchers_buf[4] = { 0 };
     820           0 :         TDB_DATA dbufs[2] = {
     821             :                 {
     822             :                         .dptr = num_watchers_buf,
     823             :                         .dsize = sizeof(num_watchers_buf),
     824             :                 },
     825             :                 { 0 },          /* filled in with existing data */
     826             :         };
     827             :         NTSTATUS status;
     828             :         bool ok;
     829             : 
     830           0 :         dbwrap_watched_subrec_wakeup_fn(rec, value, private_data);
     831             : 
     832             :         /*
     833             :          * Watchers are informed only once: Store the existing data
     834             :          * without any watchers
     835             :          */
     836             : 
     837           0 :         ok = dbwrap_watch_rec_parse(value, NULL, NULL, &dbufs[1]);
     838           0 :         if (!ok) {
     839           0 :                 DBG_DEBUG("dbwrap_watch_rec_parse failed\n");
     840           0 :                 return;
     841             :         }
     842             : 
     843           0 :         status = dbwrap_record_storev(rec, dbufs, ARRAY_SIZE(dbufs), 0);
     844           0 :         if (!NT_STATUS_IS_OK(status)) {
     845           0 :                 DBG_DEBUG("dbwrap_record_storev() failed: %s\n",
     846             :                           nt_errstr(status));
     847             :         }
     848             : }
     849             : 
     850           0 : void dbwrap_watched_wakeup(struct db_record *rec)
     851             : {
     852           0 :         struct db_context *db = dbwrap_record_get_db(rec);
     853           0 :         struct db_watched_ctx *ctx = talloc_get_type_abort(
     854             :                 db->private_data, struct db_watched_ctx);
     855           0 :         struct dbwrap_watched_subrec_wakeup_state state = {
     856           0 :                 .msg_ctx = ctx->msg,
     857             :         };
     858             :         NTSTATUS status;
     859             : 
     860           0 :         status = dbwrap_do_locked(
     861             :                 ctx->backend, rec->key, dbwrap_watched_wakeup_fn, &state);
     862           0 :         if (!NT_STATUS_IS_OK(status)) {
     863           0 :                 DBG_DEBUG("dbwrap_do_locked failed: %s\n",
     864             :                           nt_errstr(status));
     865             :         }
     866           0 : }
     867             : 
     868         434 : struct db_context *db_open_watched(TALLOC_CTX *mem_ctx,
     869             :                                    struct db_context **backend,
     870             :                                    struct messaging_context *msg)
     871             : {
     872             :         struct db_context *db;
     873             :         struct db_watched_ctx *ctx;
     874             : 
     875         434 :         db = talloc_zero(mem_ctx, struct db_context);
     876         434 :         if (db == NULL) {
     877           0 :                 return NULL;
     878             :         }
     879         434 :         ctx = talloc_zero(db, struct db_watched_ctx);
     880         434 :         if (ctx == NULL) {
     881           0 :                 TALLOC_FREE(db);
     882           0 :                 return NULL;
     883             :         }
     884         434 :         db->private_data = ctx;
     885             : 
     886         434 :         ctx->msg = msg;
     887             : 
     888         434 :         ctx->backend = talloc_move(ctx, backend);
     889         434 :         db->lock_order = ctx->backend->lock_order;
     890         434 :         ctx->backend->lock_order = DBWRAP_LOCK_ORDER_NONE;
     891             : 
     892         434 :         db->fetch_locked = dbwrap_watched_fetch_locked;
     893         434 :         db->do_locked = dbwrap_watched_do_locked;
     894         434 :         db->traverse = dbwrap_watched_traverse;
     895         434 :         db->traverse_read = dbwrap_watched_traverse_read;
     896         434 :         db->get_seqnum = dbwrap_watched_get_seqnum;
     897         434 :         db->transaction_start = dbwrap_watched_transaction_start;
     898         434 :         db->transaction_commit = dbwrap_watched_transaction_commit;
     899         434 :         db->transaction_cancel = dbwrap_watched_transaction_cancel;
     900         434 :         db->parse_record = dbwrap_watched_parse_record;
     901         434 :         db->parse_record_send = dbwrap_watched_parse_record_send;
     902         434 :         db->parse_record_recv = dbwrap_watched_parse_record_recv;
     903         434 :         db->exists = dbwrap_watched_exists;
     904         434 :         db->id = dbwrap_watched_id;
     905         434 :         db->name = dbwrap_name(ctx->backend);
     906             : 
     907         434 :         return db;
     908             : }
     909             : 
     910             : struct dbwrap_watched_watch_state {
     911             :         struct db_context *db;
     912             :         TDB_DATA key;
     913             :         struct dbwrap_watcher watcher;
     914             :         struct server_id blocker;
     915             :         bool blockerdead;
     916             : };
     917             : 
     918             : static bool dbwrap_watched_msg_filter(struct messaging_rec *rec,
     919             :                                       void *private_data);
     920             : static void dbwrap_watched_watch_done(struct tevent_req *subreq);
     921             : static void dbwrap_watched_watch_blocker_died(struct tevent_req *subreq);
     922             : static int dbwrap_watched_watch_state_destructor(
     923             :         struct dbwrap_watched_watch_state *state);
     924             : 
     925        3859 : struct tevent_req *dbwrap_watched_watch_send(TALLOC_CTX *mem_ctx,
     926             :                                              struct tevent_context *ev,
     927             :                                              struct db_record *rec,
     928             :                                              struct server_id blocker)
     929             : {
     930        3859 :         struct db_context *db = dbwrap_record_get_db(rec);
     931        3859 :         struct db_watched_ctx *ctx = talloc_get_type_abort(
     932             :                 db->private_data, struct db_watched_ctx);
     933        3859 :         struct db_watched_subrec *subrec = NULL;
     934             :         struct tevent_req *req, *subreq;
     935             :         struct dbwrap_watched_watch_state *state;
     936             : 
     937             :         static uint64_t instance = 1;
     938             : 
     939        3859 :         req = tevent_req_create(mem_ctx, &state,
     940             :                                 struct dbwrap_watched_watch_state);
     941        3859 :         if (req == NULL) {
     942           0 :                 return NULL;
     943             :         }
     944        3859 :         state->db = db;
     945        3859 :         state->blocker = blocker;
     946             : 
     947        3859 :         if (ctx->msg == NULL) {
     948           0 :                 tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED);
     949           0 :                 return tevent_req_post(req, ev);
     950             :         }
     951             : 
     952             :         /*
     953             :          * Figure out whether we're called as part of do_locked. If
     954             :          * so, we can't use talloc_get_type_abort, the
     955             :          * db_watched_subrec is stack-allocated in that case.
     956             :          */
     957             : 
     958        3859 :         if (rec->storev == dbwrap_watched_storev) {
     959        1046 :                 subrec = talloc_get_type_abort(rec->private_data,
     960             :                                                struct db_watched_subrec);
     961             :         }
     962        3859 :         if (rec->storev == dbwrap_watched_do_locked_storev) {
     963             :                 struct dbwrap_watched_do_locked_state *do_locked_state;
     964        2813 :                 do_locked_state = rec->private_data;
     965        2813 :                 subrec = &do_locked_state->subrec;
     966             :         }
     967        3859 :         if (subrec == NULL) {
     968           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
     969           0 :                 return tevent_req_post(req, ev);
     970             :         }
     971        3859 :         if (subrec->added.pid.pid != 0) {
     972           1 :                 tevent_req_nterror(req, NT_STATUS_REQUEST_NOT_ACCEPTED);
     973           1 :                 return tevent_req_post(req, ev);
     974             :         }
     975             : 
     976        7716 :         state->watcher = (struct dbwrap_watcher) {
     977        3858 :                 .pid = messaging_server_id(ctx->msg),
     978        3858 :                 .instance = instance++,
     979             :         };
     980        3858 :         subrec->added = state->watcher;
     981             : 
     982        3858 :         state->key = tdb_data_talloc_copy(state, rec->key);
     983        3858 :         if (tevent_req_nomem(state->key.dptr, req)) {
     984           0 :                 return tevent_req_post(req, ev);
     985             :         }
     986             : 
     987        3858 :         subreq = messaging_filtered_read_send(
     988             :                 state, ev, ctx->msg, dbwrap_watched_msg_filter, state);
     989        3858 :         if (tevent_req_nomem(subreq, req)) {
     990           0 :                 return tevent_req_post(req, ev);
     991             :         }
     992        3858 :         tevent_req_set_callback(subreq, dbwrap_watched_watch_done, req);
     993             : 
     994        3858 :         talloc_set_destructor(state, dbwrap_watched_watch_state_destructor);
     995             : 
     996        3858 :         if (blocker.pid != 0) {
     997        2623 :                 subreq = server_id_watch_send(state, ev, blocker);
     998        2623 :                 if (tevent_req_nomem(subreq, req)) {
     999           0 :                         return tevent_req_post(req, ev);
    1000             :                 }
    1001        2623 :                 tevent_req_set_callback(
    1002             :                         subreq, dbwrap_watched_watch_blocker_died, req);
    1003             :         }
    1004             : 
    1005        3841 :         return req;
    1006             : }
    1007             : 
    1008           4 : static void dbwrap_watched_watch_blocker_died(struct tevent_req *subreq)
    1009             : {
    1010           4 :         struct tevent_req *req = tevent_req_callback_data(
    1011             :                 subreq, struct tevent_req);
    1012           4 :         struct dbwrap_watched_watch_state *state = tevent_req_data(
    1013             :                 req, struct dbwrap_watched_watch_state);
    1014             :         int ret;
    1015             : 
    1016           4 :         ret = server_id_watch_recv(subreq, NULL);
    1017           4 :         TALLOC_FREE(subreq);
    1018           4 :         if (ret != 0) {
    1019           0 :                 tevent_req_nterror(req, map_nt_error_from_unix(ret));
    1020           0 :                 return;
    1021             :         }
    1022           4 :         state->blockerdead = true;
    1023           4 :         tevent_req_done(req);
    1024             : }
    1025             : 
    1026        1614 : static void dbwrap_watched_watch_state_destructor_fn(
    1027             :         struct db_record *rec,
    1028             :         TDB_DATA value,
    1029             :         void *private_data)
    1030             : {
    1031        1614 :         struct dbwrap_watched_watch_state *state = talloc_get_type_abort(
    1032             :                 private_data, struct dbwrap_watched_watch_state);
    1033             :         uint8_t *watchers;
    1034        1614 :         size_t num_watchers = 0;
    1035             :         size_t i;
    1036             :         bool ok;
    1037             :         NTSTATUS status;
    1038             : 
    1039             :         uint8_t num_watchers_buf[4];
    1040             : 
    1041        1614 :         TDB_DATA dbufs[4] = {
    1042             :                 {
    1043             :                         .dptr = num_watchers_buf,
    1044             :                         .dsize = sizeof(num_watchers_buf),
    1045             :                 },
    1046             :                 { 0 },          /* watchers "before" state->w */
    1047             :                 { 0 },          /* watchers "behind" state->w */
    1048             :                 { 0 },          /* filled in with data */
    1049             :         };
    1050             : 
    1051        1614 :         ok = dbwrap_watch_rec_parse(
    1052             :                 value, &watchers, &num_watchers, &dbufs[3]);
    1053        1614 :         if (!ok) {
    1054           0 :                 status = dbwrap_record_delete(rec);
    1055           0 :                 if (!NT_STATUS_IS_OK(status)) {
    1056           0 :                         DBG_DEBUG("dbwrap_record_delete failed: %s\n",
    1057             :                                   nt_errstr(status));
    1058             :                 }
    1059          50 :                 return;
    1060             :         }
    1061             : 
    1062        1650 :         for (i=0; i<num_watchers; i++) {
    1063             :                 struct dbwrap_watcher watcher;
    1064             : 
    1065        2968 :                 dbwrap_watcher_get(
    1066        1610 :                         &watcher, watchers + i*DBWRAP_WATCHER_BUF_LENGTH);
    1067             : 
    1068        3174 :                 if ((state->watcher.instance == watcher.instance) &&
    1069        1564 :                     server_id_equal(&state->watcher.pid, &watcher.pid)) {
    1070        1556 :                         break;
    1071             :                 }
    1072             :         }
    1073             : 
    1074        1614 :         if (i == num_watchers) {
    1075             :                 struct server_id_buf buf;
    1076          50 :                 DBG_DEBUG("Watcher %s:%"PRIu64" not found\n",
    1077             :                           server_id_str_buf(state->watcher.pid, &buf),
    1078             :                           state->watcher.instance);
    1079          48 :                 return;
    1080             :         }
    1081             : 
    1082        1564 :         if (i > 0) {
    1083          64 :                 dbufs[1] = (TDB_DATA) {
    1084             :                         .dptr = watchers,
    1085          32 :                         .dsize = i * DBWRAP_WATCHER_BUF_LENGTH,
    1086             :                 };
    1087             :         }
    1088             : 
    1089        1564 :         if (i < (num_watchers - 1)) {
    1090           8 :                 size_t behind = (num_watchers - 1 - i);
    1091             : 
    1092           8 :                 dbufs[2] = (TDB_DATA) {
    1093           8 :                         .dptr = watchers + (i+1) * DBWRAP_WATCHER_BUF_LENGTH,
    1094           8 :                         .dsize = behind * DBWRAP_WATCHER_BUF_LENGTH,
    1095             :                 };
    1096             :         }
    1097             : 
    1098        1564 :         num_watchers -= 1;
    1099             : 
    1100        1564 :         if ((num_watchers == 0) && (dbufs[3].dsize == 0)) {
    1101           0 :                 status = dbwrap_record_delete(rec);
    1102           0 :                 if (!NT_STATUS_IS_OK(status)) {
    1103           0 :                         DBG_DEBUG("dbwrap_record_delete() failed: %s\n",
    1104             :                                   nt_errstr(status));
    1105             :                 }
    1106           0 :                 return;
    1107             :         }
    1108             : 
    1109        1564 :         SIVAL(num_watchers_buf, 0, num_watchers);
    1110             : 
    1111        1564 :         status = dbwrap_record_storev(rec, dbufs, ARRAY_SIZE(dbufs), 0);
    1112        1564 :         if (!NT_STATUS_IS_OK(status)) {
    1113           0 :                 DBG_DEBUG("dbwrap_record_storev() failed: %s\n",
    1114             :                           nt_errstr(status));
    1115             :         }
    1116             : }
    1117             : 
    1118        1614 : static int dbwrap_watched_watch_state_destructor(
    1119             :         struct dbwrap_watched_watch_state *state)
    1120             : {
    1121        1614 :         struct db_watched_ctx *ctx = talloc_get_type_abort(
    1122             :                 state->db->private_data, struct db_watched_ctx);
    1123             :         NTSTATUS status;
    1124             : 
    1125        1614 :         status = dbwrap_do_locked(
    1126             :                 ctx->backend,
    1127             :                 state->key,
    1128             :                 dbwrap_watched_watch_state_destructor_fn,
    1129             :                 state);
    1130        1614 :         if (!NT_STATUS_IS_OK(status)) {
    1131           0 :                 DBG_DEBUG("dbwrap_do_locked failed: %s\n",
    1132             :                           nt_errstr(status));
    1133             :         }
    1134        1614 :         return 0;
    1135             : }
    1136             : 
    1137        2244 : static bool dbwrap_watched_msg_filter(struct messaging_rec *rec,
    1138             :                                       void *private_data)
    1139             : {
    1140        2244 :         struct dbwrap_watched_watch_state *state = talloc_get_type_abort(
    1141             :                 private_data, struct dbwrap_watched_watch_state);
    1142             :         uint64_t instance;
    1143             : 
    1144        2244 :         if (rec->msg_type != MSG_DBWRAP_MODIFIED) {
    1145           1 :                 return false;
    1146             :         }
    1147        2243 :         if (rec->num_fds != 0) {
    1148           0 :                 return false;
    1149             :         }
    1150             : 
    1151        2243 :         if (rec->buf.length != sizeof(instance)) {
    1152           0 :                 DBG_DEBUG("Got size %zu, expected %zu\n",
    1153             :                           rec->buf.length,
    1154             :                           sizeof(instance));
    1155           0 :                 return false;
    1156             :         }
    1157             : 
    1158        2243 :         instance = BVAL(rec->buf.data, 0);
    1159             : 
    1160        2243 :         if (instance != state->watcher.instance) {
    1161           1 :                 DBG_DEBUG("Got instance %"PRIu64", expected %"PRIu64"\n",
    1162             :                           instance,
    1163             :                           state->watcher.instance);
    1164           0 :                 return false;
    1165             :         }
    1166             : 
    1167        2237 :         return true;
    1168             : }
    1169             : 
    1170        2242 : static void dbwrap_watched_watch_done(struct tevent_req *subreq)
    1171             : {
    1172        2242 :         struct tevent_req *req = tevent_req_callback_data(
    1173             :                 subreq, struct tevent_req);
    1174        2242 :         struct dbwrap_watched_watch_state *state = tevent_req_data(
    1175             :                 req, struct dbwrap_watched_watch_state);
    1176             :         struct messaging_rec *rec;
    1177             :         int ret;
    1178             : 
    1179        2242 :         ret = messaging_filtered_read_recv(subreq, talloc_tos(), &rec);
    1180        2242 :         TALLOC_FREE(subreq);
    1181        2242 :         if (ret != 0) {
    1182           0 :                 tevent_req_nterror(req, map_nt_error_from_unix(ret));
    1183           0 :                 return;
    1184             :         }
    1185             :         /*
    1186             :          * No need to remove ourselves anymore, we've been removed by
    1187             :          * dbwrap_watched_subrec_wakeup().
    1188             :          */
    1189        2242 :         talloc_set_destructor(state, NULL);
    1190        2242 :         tevent_req_done(req);
    1191             : }
    1192             : 
    1193        2247 : NTSTATUS dbwrap_watched_watch_recv(struct tevent_req *req,
    1194             :                                    bool *blockerdead,
    1195             :                                    struct server_id *blocker)
    1196             : {
    1197        2247 :         struct dbwrap_watched_watch_state *state = tevent_req_data(
    1198             :                 req, struct dbwrap_watched_watch_state);
    1199             :         NTSTATUS status;
    1200             : 
    1201        2247 :         if (tevent_req_is_nterror(req, &status)) {
    1202           1 :                 return status;
    1203             :         }
    1204        2246 :         if (blockerdead != NULL) {
    1205        2192 :                 *blockerdead = state->blockerdead;
    1206             :         }
    1207        2246 :         if (blocker != NULL) {
    1208        2192 :                 *blocker = state->blocker;
    1209             :         }
    1210        2246 :         return NT_STATUS_OK;
    1211             : }
    1212             : 

Generated by: LCOV version 1.13