2 Unix SMB/CIFS implementation.
3 cleanup connections tdb
4 Copyright (C) Gregor Beck 2012
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "popt_common.h"
23 #include "dbwrap/dbwrap.h"
26 #include "system/filesys.h"
28 #include "lib/conn_tdb.h"
30 static bool verbose = false;
31 static bool dry_run = false;
32 static bool automatic = false;
35 struct server_id *ids;
45 static char *serverid_str(const struct server_id id)
47 return talloc_asprintf(talloc_tos(), "pid %u, vnn %u, uid %lu",
48 (unsigned)id.pid, (unsigned)id.vnn, id.unique_id);
51 static void print_record(const char *msg,
52 const struct connections_key *k,
53 const struct connections_data *d)
55 char *idstr = serverid_str(k->pid);
56 d_printf("%s: connection %d (%s) to \"%s\" from %u:%u@%s[%s] %s\n", msg,
57 k->cnum, idstr, d->servicename, (unsigned)d->uid,
58 (unsigned)d->gid, d->machine, d->addr, time_to_asc(d->start));
62 static int read_connections_fn(const struct connections_key *key,
63 const struct connections_data *data,
66 struct cclean_ctx *ctx = (struct cclean_ctx *)cclean_ctx;
67 unsigned length = talloc_array_length(ctx->cnums);
68 if (length <= ctx->num) {
69 int n = MAX(2*length, 16);
72 tmp = talloc_realloc(ctx, ctx->ids, struct server_id, n);
76 ctx->ids = (struct server_id *)tmp;
78 tmp = talloc_realloc(ctx, ctx->cnums, int, n);
82 ctx->cnums = (int *)tmp;
84 tmp = talloc_realloc(ctx, ctx->names, const char *, n);
88 ctx->names = (const char **)tmp;
92 print_record("Read", key, data);
95 ctx->ids[ctx->num] = key->pid;
96 ctx->cnums[ctx->num] = key->cnum;
97 ctx->names[ctx->num] = talloc_strndup(ctx, key->name, FSTRING_LEN);
98 if (ctx->names[ctx->num] == NULL) {
106 DEBUG(0, ("Out of memory\n"));
110 static int read_connections(struct cclean_ctx *ctx)
112 int ret = connections_forall_read(
113 &read_connections_fn,
118 if (ret != ctx->num) {
119 DEBUG(0, ("Skipped %d invalid entries\n", ret - ctx->num));
124 static int check_connections(struct cclean_ctx *ctx)
128 ctx->exists = talloc_realloc(ctx, ctx->exists, bool, MAX(1, ctx->num));
129 if (ctx->exists == NULL) {
130 DEBUG(0, ("Out of memory\n"));
134 if (!serverids_exist(ctx->ids, ctx->num, ctx->exists)) {
135 DEBUG(0, ("serverids_exist() failed\n"));
139 ctx->num_orphans = 0;
140 for (i=0; i<ctx->num; i++) {
141 if (!ctx->exists[i]) {
142 char *idstr = serverid_str(ctx->ids[i]);
143 d_printf("Orphaned entry: %s\n", idstr);
153 static int delete_orphans(struct cclean_ctx *ctx)
156 struct db_record *conn;
159 for (i=0; i<ctx->num; i++) {
160 if (!ctx->exists[i]) {
162 conn = connections_fetch_entry_ext(NULL,
167 key = dbwrap_record_get_key(conn);
168 value = dbwrap_record_get_value(conn);
170 print_record("Delete record",
171 (struct connections_key *)key.dptr,
172 (struct connections_data *)value.dptr);
175 status = dbwrap_record_delete(conn);
176 if (!NT_STATUS_IS_OK(status)) {
177 DEBUG(0, ("Failed to delete record: %s\n",
188 static int cclean(void)
191 struct cclean_ctx *ctx = talloc_zero(talloc_tos(), struct cclean_ctx);
193 ret = read_connections(ctx);
195 d_printf("Failed to read connections\n");
198 d_printf("Read %u connections\n", ctx->num);
200 ret = check_connections(ctx);
202 d_printf("Failed to check connections\n");
205 d_printf("Found %u orphans\n", ctx->num_orphans);
207 if (ctx->num_orphans == 0) {
212 int act = interact_prompt("Delete ([y]es/[n]o)", "yn", 'n');
213 if (tolower(act) != 'y') {
218 ret = delete_orphans(ctx);
220 d_printf("Failed to delete all orphans\n");
227 int main(int argc, const char *argv[])
230 TALLOC_CTX *frame = talloc_stackframe();
233 struct poptOption long_options[] = {
235 {"verbose", 'v', POPT_ARG_NONE, NULL, 'v', "Be verbose" },
236 {"auto", 'a', POPT_ARG_NONE, NULL, 'a', "Don't ask" },
237 {"test", 'T', POPT_ARG_NONE, NULL, 'T', "Dry run" },
241 struct tevent_context *evt_ctx = NULL;
242 struct messaging_context *msg_ctx = NULL;
245 setup_logging(argv[0], DEBUG_STDERR);
247 pc = poptGetContext(NULL, argc, (const char **) argv, long_options,
248 POPT_CONTEXT_KEEP_FIRST);
249 while ((opt = poptGetNextOpt(pc)) != -1) {
263 DEBUG(1, ("using configfile = %s\n", get_dyn_CONFIGFILE()));
265 if (!lp_load_initial_only(get_dyn_CONFIGFILE())) {
266 DEBUG(0, ("Can't load %s - run testparm to debug it\n",
267 get_dyn_CONFIGFILE()));
271 if (lp_clustering()) {
272 evt_ctx = event_context_init(frame);
273 if (evt_ctx == NULL) {
274 DEBUG(0, ("tevent_context_init failed\n"));
278 msg_ctx = messaging_init(frame, evt_ctx);
279 if (msg_ctx == NULL) {
280 DEBUG(0, ("messaging_init failed\n"));
285 if (!lp_load_global(get_dyn_CONFIGFILE())) {
286 DEBUG(0, ("Can't load %s - run testparm to debug it\n",
287 get_dyn_CONFIGFILE()));
291 if (!connections_init(!dry_run)) {
292 DEBUG(0, ("Failed to open connections tdb\n"));