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 %llu",
48 (unsigned)id
.pid
, (unsigned)id
.vnn
, (unsigned long long)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) ", msg
, k
->cnum
, idstr
);
58 d_printf("<no data>\n");
60 d_printf("to \"%s\" from %u:%u@%s[%s] %s\n", d
->servicename
,
61 (unsigned)d
->uid
, (unsigned)d
->gid
, d
->machine
,
62 d
->addr
, time_to_asc(d
->start
));
67 static int read_connections_fn(const struct connections_key
*key
,
68 const struct connections_data
*data
,
71 struct cclean_ctx
*ctx
= (struct cclean_ctx
*)cclean_ctx
;
72 unsigned length
= talloc_array_length(ctx
->cnums
);
73 if (length
<= ctx
->num
) {
74 int n
= MAX(2*length
, 16);
77 tmp
= talloc_realloc(ctx
, ctx
->ids
, struct server_id
, n
);
81 ctx
->ids
= (struct server_id
*)tmp
;
83 tmp
= talloc_realloc(ctx
, ctx
->cnums
, int, n
);
87 ctx
->cnums
= (int *)tmp
;
89 tmp
= talloc_realloc(ctx
, ctx
->names
, const char *, n
);
93 ctx
->names
= (const char **)tmp
;
97 print_record("Read", key
, data
);
100 ctx
->ids
[ctx
->num
] = key
->pid
;
101 ctx
->cnums
[ctx
->num
] = key
->cnum
;
102 ctx
->names
[ctx
->num
] = talloc_strndup(ctx
, key
->name
, FSTRING_LEN
);
103 if (ctx
->names
[ctx
->num
] == NULL
) {
111 DEBUG(0, ("Out of memory\n"));
115 static int read_connections(struct cclean_ctx
*ctx
)
117 int ret
= connections_forall_read(
118 &read_connections_fn
,
123 if (ret
!= ctx
->num
) {
124 DEBUG(0, ("Skipped %d invalid entries\n", ret
- ctx
->num
));
129 static int check_connections(struct cclean_ctx
*ctx
)
133 ctx
->exists
= talloc_realloc(ctx
, ctx
->exists
, bool, MAX(1, ctx
->num
));
134 if (ctx
->exists
== NULL
) {
135 DEBUG(0, ("Out of memory\n"));
139 if (!serverids_exist(ctx
->ids
, ctx
->num
, ctx
->exists
)) {
140 DEBUG(0, ("serverids_exist() failed\n"));
144 ctx
->num_orphans
= 0;
145 for (i
=0; i
<ctx
->num
; i
++) {
146 if (!ctx
->exists
[i
]) {
147 char *idstr
= serverid_str(ctx
->ids
[i
]);
148 d_printf("Orphaned entry: %s\n", idstr
);
158 static int delete_orphans(struct cclean_ctx
*ctx
)
161 struct db_record
*conn
;
164 for (i
=0; i
<ctx
->num
; i
++) {
165 if (!ctx
->exists
[i
]) {
167 conn
= connections_fetch_entry_ext(NULL
,
172 key
= dbwrap_record_get_key(conn
);
173 value
= dbwrap_record_get_value(conn
);
175 print_record("Delete record",
176 (struct connections_key
*)key
.dptr
,
177 (struct connections_data
*)value
.dptr
);
180 status
= dbwrap_record_delete(conn
);
181 if (!NT_STATUS_IS_OK(status
)) {
182 DEBUG(0, ("Failed to delete record: %s\n",
193 static int cclean(void)
196 struct cclean_ctx
*ctx
= talloc_zero(talloc_tos(), struct cclean_ctx
);
198 ret
= read_connections(ctx
);
200 d_printf("Failed to read connections\n");
203 d_printf("Read %u connections\n", ctx
->num
);
205 ret
= check_connections(ctx
);
207 d_printf("Failed to check connections\n");
210 d_printf("Found %u orphans\n", ctx
->num_orphans
);
212 if (ctx
->num_orphans
== 0) {
217 int act
= interact_prompt("Delete ([y]es/[n]o)", "yn", 'n');
218 if (tolower(act
) != 'y') {
223 ret
= delete_orphans(ctx
);
225 d_printf("Failed to delete all orphans\n");
232 int main(int argc
, const char *argv
[])
235 TALLOC_CTX
*frame
= talloc_stackframe();
238 struct poptOption long_options
[] = {
240 {"verbose", 'v', POPT_ARG_NONE
, NULL
, 'v', "Be verbose" },
241 {"auto", 'a', POPT_ARG_NONE
, NULL
, 'a', "Don't ask" },
242 {"test", 'T', POPT_ARG_NONE
, NULL
, 'T', "Dry run" },
246 struct tevent_context
*evt_ctx
= NULL
;
247 struct messaging_context
*msg_ctx
= NULL
;
250 setup_logging(argv
[0], DEBUG_STDERR
);
252 pc
= poptGetContext(NULL
, argc
, (const char **) argv
, long_options
,
253 POPT_CONTEXT_KEEP_FIRST
);
254 while ((opt
= poptGetNextOpt(pc
)) != -1) {
268 DEBUG(1, ("using configfile = %s\n", get_dyn_CONFIGFILE()));
270 if (!lp_load_initial_only(get_dyn_CONFIGFILE())) {
271 DEBUG(0, ("Can't load %s - run testparm to debug it\n",
272 get_dyn_CONFIGFILE()));
276 if (lp_clustering()) {
277 evt_ctx
= event_context_init(frame
);
278 if (evt_ctx
== NULL
) {
279 DEBUG(0, ("tevent_context_init failed\n"));
283 msg_ctx
= messaging_init(frame
, evt_ctx
);
284 if (msg_ctx
== NULL
) {
285 DEBUG(0, ("messaging_init failed\n"));
290 if (!lp_load_global(get_dyn_CONFIGFILE())) {
291 DEBUG(0, ("Can't load %s - run testparm to debug it\n",
292 get_dyn_CONFIGFILE()));
296 if (!connections_init(!dry_run
)) {
297 DEBUG(0, ("Failed to open connections tdb\n"));