2 * Samba Unix/Linux SMB client library
3 * Distributed SMB/CIFS Server Management Utility
4 * fiddle with connections tdb
6 * Copyright (C) Gregor Beck 2012
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "popt_common.h"
26 #include "dbwrap/dbwrap.h"
29 #include "system/filesys.h"
31 #include "lib/conn_tdb.h"
34 struct server_id
*ids
;
47 static char *serverid_str(const struct server_id id
)
49 return talloc_asprintf(talloc_tos(), "pid %u, vnn %u, uid %llu",
50 (unsigned)id
.pid
, (unsigned)id
.vnn
, (unsigned long long)id
.unique_id
);
53 static void print_record(const char *msg
,
54 const struct connections_key
*k
,
55 const struct connections_data
*d
)
57 char *idstr
= serverid_str(k
->pid
);
58 d_printf("%s: connection %d (%s) ", msg
, k
->cnum
, idstr
);
60 d_printf("<no data>\n");
62 d_printf("to \"%s\" from %u:%u@%s[%s] %s\n", d
->servicename
,
63 (unsigned)d
->uid
, (unsigned)d
->gid
, d
->machine
,
64 d
->addr
, time_to_asc(d
->start
));
69 static int read_connections_fn(const struct connections_key
*key
,
70 const struct connections_data
*data
,
73 struct cclean_ctx
*ctx
= (struct cclean_ctx
*)cclean_ctx
;
74 unsigned length
= talloc_array_length(ctx
->cnums
);
75 if (length
<= ctx
->num
) {
76 int n
= MAX(2*length
, 16);
79 tmp
= talloc_realloc(ctx
, ctx
->ids
, struct server_id
, n
);
83 ctx
->ids
= (struct server_id
*)tmp
;
85 tmp
= talloc_realloc(ctx
, ctx
->cnums
, int, n
);
89 ctx
->cnums
= (int *)tmp
;
91 tmp
= talloc_realloc(ctx
, ctx
->names
, const char *, n
);
95 ctx
->names
= (const char **)tmp
;
99 print_record("Read", key
, data
);
102 ctx
->ids
[ctx
->num
] = key
->pid
;
103 ctx
->cnums
[ctx
->num
] = key
->cnum
;
104 ctx
->names
[ctx
->num
] = talloc_strndup(ctx
, key
->name
, FSTRING_LEN
);
105 if (ctx
->names
[ctx
->num
] == NULL
) {
113 DEBUG(0, ("Out of memory\n"));
117 static int read_connections(struct cclean_ctx
*ctx
)
119 int ret
= connections_forall_read(
120 &read_connections_fn
,
125 if (ret
!= ctx
->num
) {
126 DEBUG(0, ("Skipped %d invalid entries\n", ret
- ctx
->num
));
131 static int check_connections(struct cclean_ctx
*ctx
)
135 ctx
->exists
= talloc_realloc(ctx
, ctx
->exists
, bool, MAX(1, ctx
->num
));
136 if (ctx
->exists
== NULL
) {
137 DEBUG(0, ("Out of memory\n"));
141 if (!serverids_exist(ctx
->ids
, ctx
->num
, ctx
->exists
)) {
142 DEBUG(0, ("serverids_exist() failed\n"));
146 ctx
->num_orphans
= 0;
147 for (i
=0; i
<ctx
->num
; i
++) {
148 if (!ctx
->exists
[i
]) {
149 char *idstr
= serverid_str(ctx
->ids
[i
]);
150 d_printf("Orphaned entry: %s\n", idstr
);
160 static int delete_orphans(struct cclean_ctx
*ctx
)
163 struct db_record
*conn
;
166 for (i
=0; i
<ctx
->num
; i
++) {
167 if (!ctx
->exists
[i
]) {
169 conn
= connections_fetch_entry_ext(NULL
,
174 key
= dbwrap_record_get_key(conn
);
175 value
= dbwrap_record_get_value(conn
);
177 print_record("Delete record",
178 (struct connections_key
*)key
.dptr
,
179 (struct connections_data
*)value
.dptr
);
182 status
= dbwrap_record_delete(conn
);
183 if (!NT_STATUS_IS_OK(status
)) {
184 DEBUG(0, ("Failed to delete record: %s\n",
195 static int cclean(bool verbose
, bool dry_run
, bool automatic
)
198 struct cclean_ctx
*ctx
= talloc_zero(talloc_tos(), struct cclean_ctx
);
200 d_printf("Out of memory\n");
204 ctx
->verbose
= verbose
;
205 ctx
->dry_run
= dry_run
;
207 ret
= read_connections(ctx
);
209 d_printf("Failed to read connections\n");
212 d_printf("Read %u connections\n", ctx
->num
);
214 ret
= check_connections(ctx
);
216 d_printf("Failed to check connections\n");
219 d_printf("Found %u orphans\n", ctx
->num_orphans
);
221 if (ctx
->num_orphans
== 0) {
226 int act
= interact_prompt("Delete ([y]es/[n]o)", "yn", 'n');
227 if (tolower(act
) != 'y') {
232 ret
= delete_orphans(ctx
);
234 d_printf("Failed to delete all orphans\n");
241 static int net_connections_cleanup(struct net_context
*c
,
242 int argc
, const char **argv
)
244 return cclean(c
->opt_verbose
, c
->opt_testmode
, c
->opt_auto
);
247 int net_connections(struct net_context
*c
, int argc
, const char **argv
)
251 struct functable func
[] = {
254 net_connections_cleanup
,
256 N_("Remove orphaned entries from connections.tdb"),
257 N_("net connections cleanup\n"
258 " Remove orphaned entries from connections.tdb")
260 { NULL
, NULL
, 0, NULL
, NULL
}
263 if (!c
->display_usage
) {
264 if (!connections_init(!c
->opt_testmode
)) {
265 DEBUG(0, ("Failed to open connections tdb\n"));
270 ret
= net_run_function(c
, argc
, argv
, "net connections", func
);