LCOV - code coverage report
Current view: top level - source3/lib/dbwrap - dbwrap_watch.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 384 529 72.6 %
Date: 2024-05-31 13:13:24 Functions: 34 44 77.3 %

          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     2147865 : 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       10811 :         size_t num_watchers;
      69             : 
      70     2147865 :         if (data.dsize == 0) {
      71             :                 /* Fresh record */
      72      473126 :                 if (pwatchers != NULL) {
      73      473126 :                         *pwatchers = NULL;
      74             :                 }
      75      473126 :                 if (pnum_watchers != NULL) {
      76      473126 :                         *pnum_watchers = 0;
      77             :                 }
      78      473126 :                 if (pdata != NULL) {
      79      473126 :                         *pdata = (TDB_DATA) { .dptr = NULL };
      80             :                 }
      81      473126 :                 return true;
      82             :         }
      83             : 
      84     1674739 :         if (data.dsize < sizeof(uint32_t)) {
      85             :                 /* Invalid record */
      86           0 :                 return false;
      87             :         }
      88             : 
      89     1674739 :         num_watchers = IVAL(data.dptr, 0);
      90             : 
      91     1674739 :         data.dptr += sizeof(uint32_t);
      92     1674739 :         data.dsize -= sizeof(uint32_t);
      93             : 
      94     1674739 :         if (num_watchers > data.dsize/DBWRAP_WATCHER_BUF_LENGTH) {
      95             :                 /* Invalid record */
      96           0 :                 return false;
      97             :         }
      98             : 
      99     1674738 :         if (pwatchers != NULL) {
     100     1392912 :                 *pwatchers = data.dptr;
     101             :         }
     102     1674738 :         if (pnum_watchers != NULL) {
     103     1392912 :                 *pnum_watchers = num_watchers;
     104             :         }
     105     1674738 :         if (pdata != NULL) {
     106     1674738 :                 size_t watchers_len = num_watchers * DBWRAP_WATCHER_BUF_LENGTH;
     107     1674738 :                 *pdata = (TDB_DATA) {
     108     1674738 :                         .dptr = data.dptr + watchers_len,
     109     1674738 :                         .dsize = data.dsize - watchers_len
     110             :                 };
     111             :         }
     112             : 
     113     1666322 :         return true;
     114             : }
     115             : 
     116        5776 : static void dbwrap_watcher_get(struct dbwrap_watcher *w,
     117             :                                const uint8_t buf[DBWRAP_WATCHER_BUF_LENGTH])
     118             : {
     119        5776 :         server_id_get(&w->pid, buf);
     120        5776 :         w->instance = BVAL(buf, SERVER_ID_BUF_LENGTH);
     121        5776 : }
     122             : 
     123        3474 : static void dbwrap_watcher_put(uint8_t buf[DBWRAP_WATCHER_BUF_LENGTH],
     124             :                                const struct dbwrap_watcher *w)
     125             : {
     126        3474 :         server_id_put(buf, w->pid);
     127        3474 :         SBVAL(buf, SERVER_ID_BUF_LENGTH, w->instance);
     128        3474 : }
     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     3913501 : 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     3913501 :         struct db_watched_record *wrec =
     201             :                 (struct db_watched_record *)rec->private_data;
     202     3913501 :         SMB_ASSERT(wrec->rec == rec);
     203     3913501 :         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     1866038 : 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        9432 :         bool ok;
     225             : 
     226     1875470 :         *rec = (struct db_record) {
     227             :                 .db = db,
     228     1866038 :                 .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     1875470 :         *wrec = (struct db_watched_record) {
     235             :                 .rec = rec,
     236     1866038 :                 .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     1866038 :         ok = dbwrap_watch_rec_parse(backend_value,
     245             :                                     &wrec->watchers.first,
     246             :                                     &wrec->watchers.count,
     247             :                                     &rec->value);
     248     1866038 :         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     1866038 : }
     254             : 
     255      249592 : static struct db_record *dbwrap_watched_fetch_locked(
     256             :         struct db_context *db, TALLOC_CTX *mem_ctx, TDB_DATA key)
     257             : {
     258      249592 :         struct db_watched_ctx *ctx = talloc_get_type_abort(
     259             :                 db->private_data, struct db_watched_ctx);
     260      249592 :         struct db_record *rec = NULL;
     261      249592 :         struct db_watched_record *wrec = NULL;
     262      249592 :         struct db_record *backend_rec = NULL;
     263      249592 :         TDB_DATA backend_value = { .dptr = NULL, };
     264             : 
     265      249592 :         rec = talloc_zero(mem_ctx, struct db_record);
     266      249592 :         if (rec == NULL) {
     267           0 :                 return NULL;
     268             :         }
     269      249592 :         wrec = talloc_zero(rec, struct db_watched_record);
     270      249592 :         if (wrec == NULL) {
     271           0 :                 TALLOC_FREE(rec);
     272           0 :                 return NULL;
     273             :         }
     274             : 
     275      249592 :         backend_rec = dbwrap_fetch_locked(ctx->backend, wrec, key);
     276      249592 :         if (backend_rec == NULL) {
     277           0 :                 TALLOC_FREE(rec);
     278           0 :                 return NULL;
     279             :         }
     280      249592 :         backend_value = dbwrap_record_get_value(backend_rec);
     281             : 
     282      249592 :         db_watched_record_init(db, ctx->msg,
     283             :                                rec, wrec,
     284             :                                backend_rec, backend_value);
     285      249592 :         rec->value_valid = true;
     286      249592 :         talloc_set_destructor(wrec, db_watched_record_destructor);
     287             : 
     288      249592 :         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     1866037 : static void db_watched_record_fini(struct db_watched_record *wrec)
     363             : {
     364     1866037 :         struct db_watched_record_fini_state state = { .wrec = wrec, };
     365     1866037 :         struct db_context *backend = dbwrap_record_get_db(wrec->backend.rec);
     366     1866037 :         struct db_record *rec = wrec->rec;
     367     1866037 :         TDB_DATA key = dbwrap_record_get_key(wrec->backend.rec);
     368        9431 :         NTSTATUS status;
     369             : 
     370     1866037 :         if (!wrec->force_fini_store) {
     371     1850885 :                 return;
     372             :         }
     373             : 
     374        5852 :         if (wrec->backend.initial_valid) {
     375        5852 :                 if (rec->value.dsize != 0) {
     376        5664 :                         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        5852 :         if (!wrec->removed_first) {
     409        2459 :                 dbwrap_watched_watch_skip_alerting(rec);
     410             :         }
     411             : 
     412        5852 :         status = dbwrap_watched_record_storev(wrec, state.dbufs, state.num_dbufs, 0);
     413        5852 :         TALLOC_FREE(state.frame);
     414        5852 :         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        5721 :         return;
     421             : }
     422             : 
     423      249591 : static int db_watched_record_destructor(struct db_watched_record *wrec)
     424             : {
     425      249591 :         struct db_record *rec = wrec->rec;
     426      249591 :         struct db_watched_ctx *ctx = talloc_get_type_abort(
     427             :                 rec->db->private_data, struct db_watched_ctx);
     428             : 
     429      249591 :         db_watched_record_fini(wrec);
     430      249591 :         TALLOC_FREE(wrec->backend.rec);
     431      249591 :         dbwrap_watched_trigger_wakeup(ctx->msg, &wrec->wakeup.watcher);
     432      249591 :         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     1616446 : static void dbwrap_watched_do_locked_fn(
     447             :         struct db_record *backend_rec,
     448             :         TDB_DATA backend_value,
     449             :         void *private_data)
     450             : {
     451     1616446 :         struct dbwrap_watched_do_locked_state *state =
     452             :                 (struct dbwrap_watched_do_locked_state *)private_data;
     453             : 
     454     1616446 :         db_watched_record_init(state->db, state->msg_ctx,
     455             :                                state->rec, state->wrec,
     456             :                                backend_rec, backend_value);
     457             : 
     458     1616446 :         state->fn(state->rec, state->rec->value, state->private_data);
     459             : 
     460     1616446 :         db_watched_record_fini(state->wrec);
     461     1616446 : }
     462             : 
     463     1616446 : 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     1616446 :         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     1616446 :         struct dbwrap_watched_do_locked_state state = {
     474     1616446 :                 .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     1616446 :         status = dbwrap_do_locked(
     481             :                 ctx->backend, key, dbwrap_watched_do_locked_fn, &state);
     482     1616446 :         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     1616446 :         DBG_DEBUG("dbwrap_watched_do_locked_fn returned\n");
     488             : 
     489     1616446 :         dbwrap_watched_trigger_wakeup(state.msg_ctx, &wrec.wakeup.watcher);
     490             : 
     491     1616446 :         return NT_STATUS_OK;
     492             : }
     493             : 
     494     2307296 : 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     2307296 :         if (wrec->watchers.alerted) {
     501             :                 /* already done */
     502     1105748 :                 return;
     503             :         }
     504     1198914 :         wrec->watchers.alerted = true;
     505             : 
     506     1198914 :         if (wrec->watchers.count == 0) {
     507     1196722 :                 DBG_DEBUG("No watchers\n");
     508     1196722 :                 return;
     509             :         }
     510             : 
     511        2192 :         while (wrec->watchers.count != 0) {
     512          11 :                 struct server_id_buf tmp;
     513          11 :                 bool exists;
     514             : 
     515        2192 :                 dbwrap_watcher_get(&wrec->wakeup.watcher, wrec->watchers.first);
     516        2192 :                 exists = serverid_exists(&wrec->wakeup.watcher.pid);
     517        2192 :                 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        2192 :                 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        2192 :                 break;
     539             :         }
     540             : }
     541             : 
     542     1866037 : static void dbwrap_watched_trigger_wakeup(struct messaging_context *msg_ctx,
     543             :                                           struct dbwrap_watcher *watcher)
     544             : {
     545        9431 :         struct server_id_buf tmp;
     546        9431 :         uint8_t instance_buf[8];
     547        9431 :         NTSTATUS status;
     548             : 
     549     1866037 :         if (watcher->instance == 0) {
     550     1863875 :                 DBG_DEBUG("No one to wakeup\n");
     551     1863875 :                 return;
     552             :         }
     553             : 
     554        2162 :         DBG_DEBUG("Alerting %s:%"PRIu64"\n",
     555             :                   server_id_str_buf(watcher->pid, &tmp),
     556             :                   watcher->instance);
     557             : 
     558        2162 :         SBVAL(instance_buf, 0, watcher->instance);
     559             : 
     560        2162 :         status = messaging_send_buf(
     561             :                 msg_ctx,
     562             :                 watcher->pid,
     563             :                 MSG_DBWRAP_MODIFIED,
     564             :                 instance_buf,
     565             :                 sizeof(instance_buf));
     566        2162 :         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     1852552 : static NTSTATUS dbwrap_watched_record_storev(
     574             :         struct db_watched_record *wrec,
     575             :         const TDB_DATA *dbufs, int num_dbufs, int flags)
     576     1852552 : {
     577     1852552 :         uint8_t num_watchers_buf[4] = { 0 };
     578        9114 :         uint8_t add_buf[DBWRAP_WATCHER_BUF_LENGTH];
     579        9114 :         size_t num_store_watchers;
     580     1852552 :         TDB_DATA my_dbufs[num_dbufs+3];
     581     1852552 :         int num_my_dbufs = 0;
     582        9114 :         NTSTATUS status;
     583     1852552 :         size_t add_count = 0;
     584             : 
     585     1852552 :         dbwrap_watched_record_prepare_wakeup(wrec);
     586             : 
     587     1852552 :         wrec->backend.initial_valid = false;
     588     1852552 :         wrec->force_fini_store = false;
     589             : 
     590     1852552 :         if (wrec->added.pid.pid != 0) {
     591        3474 :                 dbwrap_watcher_put(add_buf, &wrec->added);
     592        3474 :                 add_count = 1;
     593             :         }
     594             : 
     595     1852552 :         num_store_watchers = wrec->watchers.count + add_count;
     596     1852552 :         if (num_store_watchers == 0 && num_dbufs == 0) {
     597      471815 :                 status = dbwrap_record_delete(wrec->backend.rec);
     598      471815 :                 return status;
     599             :         }
     600     1380737 :         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     1380737 :         SIVAL(num_watchers_buf, 0, num_store_watchers);
     607             : 
     608     1380737 :         my_dbufs[num_my_dbufs++] = (TDB_DATA) {
     609             :                 .dptr = num_watchers_buf, .dsize = sizeof(num_watchers_buf),
     610             :         };
     611     1380737 :         if (wrec->watchers.count != 0) {
     612        3509 :                 my_dbufs[num_my_dbufs++] = (TDB_DATA) {
     613        3509 :                         .dptr = wrec->watchers.first, .dsize = wrec->watchers.count * DBWRAP_WATCHER_BUF_LENGTH,
     614             :                 };
     615             :         }
     616     1380737 :         if (add_count != 0) {
     617        3474 :                 my_dbufs[num_my_dbufs++] = (TDB_DATA) {
     618             :                         .dptr = add_buf,
     619             :                         .dsize = sizeof(add_buf),
     620             :                 };
     621             :         }
     622     1380737 :         if (num_dbufs != 0) {
     623     1380549 :                 memcpy(my_dbufs+num_my_dbufs, dbufs, num_dbufs * sizeof(*dbufs));
     624     1380549 :                 num_my_dbufs += num_dbufs;
     625             :         }
     626             : 
     627     1380737 :         SMB_ASSERT(num_my_dbufs <= ARRAY_SIZE(my_dbufs));
     628             : 
     629     1380737 :         status = dbwrap_record_storev(
     630             :                 wrec->backend.rec, my_dbufs, num_my_dbufs, flags);
     631     1380737 :         return status;
     632             : }
     633             : 
     634     1374885 : static NTSTATUS dbwrap_watched_storev(struct db_record *rec,
     635             :                                       const TDB_DATA *dbufs, int num_dbufs,
     636             :                                       int flags)
     637             : {
     638     1374885 :         struct db_watched_record *wrec = db_record_get_watched_record(rec);
     639             : 
     640     1374885 :         return dbwrap_watched_record_storev(wrec, dbufs, num_dbufs, flags);
     641             : }
     642             : 
     643      471815 : static NTSTATUS dbwrap_watched_delete(struct db_record *rec)
     644             : {
     645      471815 :         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      471815 :         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       18863 : static int dbwrap_watched_traverse_fn(struct db_record *rec,
     661             :                                       void *private_data)
     662             : {
     663       18863 :         struct dbwrap_watched_traverse_state *state = private_data;
     664       18863 :         struct db_record prec = *rec;
     665           0 :         bool ok;
     666             : 
     667       18863 :         ok = dbwrap_watch_rec_parse(rec->value, NULL, NULL, &prec.value);
     668       18863 :         if (!ok) {
     669           0 :                 return 0;
     670             :         }
     671       18863 :         if (prec.value.dsize == 0) {
     672           0 :                 return 0;
     673             :         }
     674       18863 :         prec.value_valid = true;
     675             : 
     676       18863 :         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        6415 : 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        6415 :         struct db_watched_ctx *ctx = talloc_get_type_abort(
     705             :                 db->private_data, struct db_watched_ctx);
     706        6415 :         struct dbwrap_watched_traverse_state state = {
     707             :                 .fn = fn, .private_data = private_data };
     708           0 :         NTSTATUS status;
     709           0 :         int ret;
     710             : 
     711        6415 :         status = dbwrap_traverse_read(
     712             :                 ctx->backend, dbwrap_watched_traverse_fn, &state, &ret);
     713        6415 :         if (!NT_STATUS_IS_OK(status)) {
     714           0 :                 return -1;
     715             :         }
     716        6415 :         return ret;
     717             : }
     718             : 
     719      193157 : static int dbwrap_watched_get_seqnum(struct db_context *db)
     720             : {
     721      193157 :         struct db_watched_ctx *ctx = talloc_get_type_abort(
     722             :                 db->private_data, struct db_watched_ctx);
     723      193157 :         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      262964 : static void dbwrap_watched_parse_record_parser(TDB_DATA key, TDB_DATA data,
     755             :                                                void *private_data)
     756             : {
     757      262964 :         struct dbwrap_watched_parse_record_state *state = private_data;
     758        1379 :         TDB_DATA userdata;
     759             : 
     760      262964 :         state->ok = dbwrap_watch_rec_parse(data, NULL, NULL, &userdata);
     761      262964 :         if (!state->ok) {
     762           1 :                 dbwrap_watch_log_invalid_record(state->db, key, data);
     763           1 :                 return;
     764             :         }
     765             : 
     766      262963 :         state->parser(key, userdata, state->private_data);
     767             : }
     768             : 
     769     1088196 : 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     1088196 :         struct db_watched_ctx *ctx = talloc_get_type_abort(
     775             :                 db->private_data, struct db_watched_ctx);
     776     1088196 :         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     1088196 :         status = dbwrap_parse_record(
     784             :                 ctx->backend, key, dbwrap_watched_parse_record_parser, &state);
     785     1088196 :         if (!NT_STATUS_IS_OK(status)) {
     786      825232 :                 return status;
     787             :         }
     788      262964 :         if (!state.ok) {
     789           1 :                 return NT_STATUS_NOT_FOUND;
     790             :         }
     791      262963 :         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         383 : 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         383 :         db = talloc_zero(mem_ctx, struct db_context);
     901         383 :         if (db == NULL) {
     902           0 :                 return NULL;
     903             :         }
     904         383 :         ctx = talloc_zero(db, struct db_watched_ctx);
     905         383 :         if (ctx == NULL) {
     906           0 :                 TALLOC_FREE(db);
     907           0 :                 return NULL;
     908             :         }
     909         383 :         db->private_data = ctx;
     910             : 
     911         383 :         ctx->msg = msg;
     912             : 
     913         383 :         ctx->backend = talloc_move(ctx, backend);
     914         383 :         db->lock_order = ctx->backend->lock_order;
     915         383 :         ctx->backend->lock_order = DBWRAP_LOCK_ORDER_NONE;
     916             : 
     917         383 :         db->fetch_locked = dbwrap_watched_fetch_locked;
     918         383 :         db->do_locked = dbwrap_watched_do_locked;
     919         383 :         db->traverse = dbwrap_watched_traverse;
     920         383 :         db->traverse_read = dbwrap_watched_traverse_read;
     921         383 :         db->get_seqnum = dbwrap_watched_get_seqnum;
     922         383 :         db->transaction_start = dbwrap_watched_transaction_start;
     923         383 :         db->transaction_commit = dbwrap_watched_transaction_commit;
     924         383 :         db->transaction_cancel = dbwrap_watched_transaction_cancel;
     925         383 :         db->parse_record = dbwrap_watched_parse_record;
     926         383 :         db->parse_record_send = dbwrap_watched_parse_record_send;
     927         383 :         db->parse_record_recv = dbwrap_watched_parse_record_recv;
     928         383 :         db->exists = dbwrap_watched_exists;
     929         383 :         db->id = dbwrap_watched_id;
     930         383 :         db->name = dbwrap_name(ctx->backend);
     931             : 
     932         383 :         return db;
     933             : }
     934             : 
     935        3475 : uint64_t dbwrap_watched_watch_add_instance(struct db_record *rec)
     936             : {
     937        3475 :         struct db_watched_record *wrec = db_record_get_watched_record(rec);
     938          71 :         static uint64_t global_instance = 1;
     939             : 
     940        3475 :         SMB_ASSERT(wrec->added.instance == 0);
     941             : 
     942        3475 :         wrec->added = (struct dbwrap_watcher) {
     943        3475 :                 .pid = wrec->self,
     944        3475 :                 .instance = global_instance++,
     945             :         };
     946             : 
     947        3475 :         wrec->force_fini_store = true;
     948             : 
     949        3475 :         return wrec->added.instance;
     950             : }
     951             : 
     952       29216 : void dbwrap_watched_watch_remove_instance(struct db_record *rec, uint64_t instance)
     953             : {
     954       29216 :         struct db_watched_record *wrec = db_record_get_watched_record(rec);
     955       29216 :         struct dbwrap_watcher clear_watcher = {
     956             :                 .pid = wrec->self,
     957             :                 .instance = instance,
     958             :         };
     959         794 :         size_t i;
     960         794 :         struct server_id_buf buf;
     961             : 
     962       29216 :         if (instance == 0) {
     963       25018 :                 return;
     964             :         }
     965             : 
     966        3473 :         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        3584 :         for (i=0; i < wrec->watchers.count; i++) {
     975          69 :                 struct dbwrap_watcher watcher;
     976        3584 :                 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        3584 :                 dbwrap_watcher_get(&watcher, wrec->watchers.first + off);
     982             : 
     983        3584 :                 if (clear_watcher.instance != watcher.instance) {
     984         111 :                         continue;
     985             :                 }
     986        3538 :                 if (!server_id_equal(&clear_watcher.pid, &watcher.pid)) {
     987          65 :                         continue;
     988             :                 }
     989             : 
     990        3473 :                 wrec->force_fini_store = true;
     991             : 
     992        3473 :                 if (i == 0) {
     993        3413 :                         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        3413 :                         wrec->watchers.first += DBWRAP_WATCHER_BUF_LENGTH;
     998        3413 :                         wrec->watchers.count -= 1;
     999        3413 :                         wrec->removed_first = true;
    1000        3473 :                         return;
    1001             :                 }
    1002          60 :                 if (i == (wrec->watchers.count-1)) {
    1003          29 :                         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          29 :                         wrec->watchers.count -= 1;
    1008          29 :                         return;
    1009             :                 }
    1010             : 
    1011          31 :                 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          31 :                 next_off = off + DBWRAP_WATCHER_BUF_LENGTH;
    1017          31 :                 full_len = wrec->watchers.count * DBWRAP_WATCHER_BUF_LENGTH;
    1018          31 :                 move_len = full_len - next_off;
    1019          31 :                 memmove(wrec->watchers.first + off,
    1020          31 :                         wrec->watchers.first + next_off,
    1021             :                         move_len);
    1022          31 :                 wrec->watchers.count -= 1;
    1023          31 :                 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     1121001 : void dbwrap_watched_watch_skip_alerting(struct db_record *rec)
    1034             : {
    1035     1121001 :         struct db_watched_record *wrec = db_record_get_watched_record(rec);
    1036             : 
    1037     1121001 :         wrec->wakeup.watcher = (struct dbwrap_watcher) { .instance = 0, };
    1038     1121001 :         wrec->watchers.alerted = true;
    1039     1121001 : }
    1040             : 
    1041      454744 : void dbwrap_watched_watch_reset_alerting(struct db_record *rec)
    1042             : {
    1043      454744 :         struct db_watched_record *wrec = db_record_get_watched_record(rec);
    1044             : 
    1045      454744 :         wrec->wakeup.watcher = (struct dbwrap_watcher) { .instance = 0, };
    1046      454744 :         wrec->watchers.alerted = false;
    1047      454744 : }
    1048             : 
    1049      454744 : void dbwrap_watched_watch_force_alerting(struct db_record *rec)
    1050             : {
    1051      454744 :         struct db_watched_record *wrec = db_record_get_watched_record(rec);
    1052             : 
    1053      454744 :         dbwrap_watched_record_prepare_wakeup(wrec);
    1054      454744 : }
    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        3621 : 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        3621 :         struct db_context *db = dbwrap_record_get_db(rec);
    1078        3621 :         struct db_watched_ctx *ctx = talloc_get_type_abort(
    1079             :                 db->private_data, struct db_watched_ctx);
    1080        3621 :         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        3621 :         req = tevent_req_create(mem_ctx, &state,
    1086             :                                 struct dbwrap_watched_watch_state);
    1087        3621 :         if (req == NULL) {
    1088           0 :                 return NULL;
    1089             :         }
    1090        3621 :         state->db = db;
    1091        3621 :         state->blocker = blocker;
    1092             : 
    1093        3621 :         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        3621 :         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        2466 :         } 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         145 :                 instance = resumed_instance;
    1109        2321 :         } 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        2255 :                 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        7240 :         state->watcher = (struct dbwrap_watcher) {
    1121        3620 :                 .pid = messaging_server_id(ctx->msg),
    1122             :                 .instance = instance,
    1123             :         };
    1124             : 
    1125        3620 :         state->key = tdb_data_talloc_copy(state, rec->key);
    1126        3620 :         if (tevent_req_nomem(state->key.dptr, req)) {
    1127           0 :                 return tevent_req_post(req, ev);
    1128             :         }
    1129             : 
    1130        3620 :         subreq = messaging_filtered_read_send(
    1131             :                 state, ev, ctx->msg, dbwrap_watched_msg_filter, state);
    1132        3620 :         if (tevent_req_nomem(subreq, req)) {
    1133           0 :                 return tevent_req_post(req, ev);
    1134             :         }
    1135        3620 :         tevent_req_set_callback(subreq, dbwrap_watched_watch_done, req);
    1136             : 
    1137        3620 :         talloc_set_destructor(state, dbwrap_watched_watch_state_destructor);
    1138             : 
    1139        3620 :         if (blocker.pid != 0) {
    1140        2788 :                 subreq = server_id_watch_send(state, ev, blocker);
    1141        2788 :                 if (tevent_req_nomem(subreq, req)) {
    1142           0 :                         return tevent_req_post(req, ev);
    1143             :                 }
    1144        2788 :                 tevent_req_set_callback(
    1145             :                         subreq, dbwrap_watched_watch_blocker_died, req);
    1146             :         }
    1147             : 
    1148        3549 :         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        2044 : static bool dbwrap_watched_msg_filter(struct messaging_rec *rec,
    1205             :                                       void *private_data)
    1206             : {
    1207        2044 :         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        2044 :         if (rec->msg_type != MSG_DBWRAP_MODIFIED) {
    1212           0 :                 return false;
    1213             :         }
    1214        2044 :         if (rec->num_fds != 0) {
    1215           0 :                 return false;
    1216             :         }
    1217             : 
    1218        2044 :         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        2044 :         instance = BVAL(rec->buf.data, 0);
    1226             : 
    1227        2044 :         if (instance != state->watcher.instance) {
    1228         218 :                 DBG_DEBUG("Got instance %"PRIu64", expected %"PRIu64"\n",
    1229             :                           instance,
    1230             :                           state->watcher.instance);
    1231         218 :                 return false;
    1232             :         }
    1233             : 
    1234        1817 :         return true;
    1235             : }
    1236             : 
    1237        1826 : static void dbwrap_watched_watch_done(struct tevent_req *subreq)
    1238             : {
    1239        1826 :         struct tevent_req *req = tevent_req_callback_data(
    1240             :                 subreq, struct tevent_req);
    1241        1826 :         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        1826 :         ret = messaging_filtered_read_recv(subreq, state, &rec);
    1247        1826 :         TALLOC_FREE(subreq);
    1248        1826 :         if (ret != 0) {
    1249           0 :                 tevent_req_nterror(req, map_nt_error_from_unix(ret));
    1250           0 :                 return;
    1251             :         }
    1252        1826 :         tevent_req_done(req);
    1253             : }
    1254             : 
    1255        1829 : NTSTATUS dbwrap_watched_watch_recv(struct tevent_req *req,
    1256             :                                    uint64_t *pkeep_instance,
    1257             :                                    bool *blockerdead,
    1258             :                                    struct server_id *blocker)
    1259             : {
    1260        1829 :         struct dbwrap_watched_watch_state *state = tevent_req_data(
    1261             :                 req, struct dbwrap_watched_watch_state);
    1262          12 :         NTSTATUS status;
    1263             : 
    1264        1829 :         if (tevent_req_is_nterror(req, &status)) {
    1265           1 :                 tevent_req_received(req);
    1266           1 :                 return status;
    1267             :         }
    1268        1828 :         if (pkeep_instance != NULL) {
    1269        1826 :                 *pkeep_instance = state->watcher.instance;
    1270             :                 /*
    1271             :                  * No need to remove ourselves anymore,
    1272             :                  * the caller will take care of removing itself.
    1273             :                  */
    1274        1826 :                 talloc_set_destructor(state, NULL);
    1275             :         }
    1276        1828 :         if (blockerdead != NULL) {
    1277        1735 :                 *blockerdead = state->blockerdead;
    1278             :         }
    1279        1828 :         if (blocker != NULL) {
    1280        1735 :                 *blocker = state->blocker;
    1281             :         }
    1282        1828 :         tevent_req_received(req);
    1283        1828 :         return NT_STATUS_OK;
    1284             : }
    1285             : 

Generated by: LCOV version 1.14