Coverage Report

Created: 2025-11-16 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source3/lib/cleanupdb.c
Line
Count
Source
1
/*
2
   Unix SMB/CIFS implementation.
3
   Implementation of reliable cleanup events
4
   Copyright (C) Ralph Boehme 2016
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 "replace.h"
21
#include "system/filesys.h"
22
#include "lib/tdb_wrap/tdb_wrap.h"
23
#include "lib/util/talloc_stack.h"
24
#include "lib/util/debug.h"
25
#include "source3/lib/cleanupdb.h"
26
#include "source3/lib/util_path.h"
27
28
struct cleanup_key {
29
  pid_t pid;
30
};
31
32
struct cleanup_rec {
33
  bool unclean;
34
};
35
36
static struct tdb_wrap *cleanup_db(void)
37
0
{
38
0
  static struct tdb_wrap *db;
39
0
  char *db_path = NULL;
40
0
  int tdbflags = TDB_INCOMPATIBLE_HASH | TDB_CLEAR_IF_FIRST |
41
0
    TDB_MUTEX_LOCKING;
42
43
0
  if (db != NULL) {
44
0
    return db;
45
0
  }
46
47
0
  db_path = lock_path(talloc_tos(), "smbd_cleanupd.tdb");
48
0
  if (db_path == NULL) {
49
0
    return NULL;
50
0
  }
51
52
0
  db = tdb_wrap_open(NULL, db_path, 0, tdbflags,
53
0
         O_CREAT | O_RDWR, 0644);
54
0
  if (db == NULL) {
55
0
    DBG_ERR("Failed to open smbd_cleanupd.tdb\n");
56
0
  }
57
58
0
  TALLOC_FREE(db_path);
59
0
  return db;
60
0
}
61
62
bool cleanupdb_store_child(const pid_t pid, const bool unclean)
63
0
{
64
0
  struct tdb_wrap *db;
65
0
  struct cleanup_key key = { .pid = pid };
66
0
  struct cleanup_rec rec = { .unclean = unclean };
67
0
  TDB_DATA tdbkey = { .dptr = (uint8_t *)&key, .dsize = sizeof(key) };
68
0
  TDB_DATA tdbdata = { .dptr = (uint8_t *)&rec, .dsize = sizeof(rec) };
69
0
  int result;
70
71
0
  db = cleanup_db();
72
0
  if (db == NULL) {
73
0
    return false;
74
0
  }
75
76
0
  result = tdb_store(db->tdb, tdbkey, tdbdata, TDB_REPLACE);
77
0
  if (result != 0) {
78
0
    DBG_ERR("tdb_store failed for pid %d\n", (int)pid);
79
0
    return false;
80
0
  }
81
82
0
  return true;
83
0
}
84
85
bool cleanupdb_delete_child(const pid_t pid)
86
0
{
87
0
  struct tdb_wrap *db;
88
0
  struct cleanup_key key = { .pid = pid };
89
0
  TDB_DATA tdbkey = { .dptr = (uint8_t *)&key, .dsize = sizeof(key) };
90
0
  int result;
91
92
0
  db = cleanup_db();
93
0
  if (db == NULL) {
94
0
    return false;
95
0
  }
96
97
0
  result = tdb_delete(db->tdb, tdbkey);
98
0
  if (result != 0) {
99
0
    DBG_ERR("tdb_delete failed for pid %d\n", (int)pid);
100
0
    return false;
101
0
  }
102
103
0
  return true;
104
0
}
105
106
struct cleanup_read_state {
107
  int (*fn)(const pid_t pid, const bool cleanup, void *private_data);
108
  void *private_data;
109
};
110
111
static int cleanup_traverse_fn(struct tdb_context *tdb,
112
             TDB_DATA key, TDB_DATA value,
113
             void *private_data)
114
0
{
115
0
  struct cleanup_read_state *state =
116
0
    (struct cleanup_read_state *)private_data;
117
0
  struct cleanup_key ckey;
118
0
  struct cleanup_rec rec;
119
0
  int result;
120
121
0
  if (key.dsize != sizeof(struct cleanup_key)) {
122
0
    DBG_ERR("Found invalid key length %zu in cleanup.tdb\n",
123
0
      key.dsize);
124
0
    return -1;
125
0
  }
126
0
  memcpy(&ckey, key.dptr, sizeof(struct cleanup_key));
127
128
0
  if (value.dsize != sizeof(struct cleanup_rec)) {
129
0
    DBG_ERR("Found invalid value length %zu in cleanup.tdb\n",
130
0
      value.dsize);
131
0
    return -1;
132
0
  }
133
0
  memcpy(&rec, value.dptr, sizeof(struct cleanup_rec));
134
135
0
  result = state->fn(ckey.pid, rec.unclean, state->private_data);
136
0
  if (result != 0) {
137
0
    return -1;
138
0
  }
139
140
0
  return 0;
141
0
}
142
143
int cleanupdb_traverse_read(int (*fn)(const pid_t pid,
144
              const bool cleanup,
145
              void *private_data),
146
          void *private_data)
147
0
{
148
0
  struct tdb_wrap *db;
149
0
  struct cleanup_read_state state;
150
0
  int result;
151
152
0
  db = cleanup_db();
153
0
  if (db == NULL) {
154
0
    return -1;
155
0
  }
156
157
0
  state = (struct cleanup_read_state) {
158
0
    .fn = fn,
159
0
    .private_data = private_data
160
0
  };
161
162
0
  result = tdb_traverse_read(db->tdb, cleanup_traverse_fn, &state);
163
0
  if (result < 0) {
164
0
    DBG_ERR("tdb_traverse_read failed\n");
165
0
    return -1;
166
0
  }
167
168
0
  return result;
169
0
}