docs: Add very basic samba manpage.
[Samba/gebeck_regimport.git] / source3 / utils / net_connections.c
bloba74d53f63af178106612385861a1bae7cec2f6c0
1 /*
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/>.
22 #include "includes.h"
23 #include "net.h"
24 #include "serverid.h"
25 #include "popt_common.h"
26 #include "dbwrap/dbwrap.h"
27 #include "util_tdb.h"
28 #include "messages.h"
29 #include "system/filesys.h"
30 #include "interact.h"
31 #include "lib/conn_tdb.h"
33 struct cclean_ctx {
34 struct server_id *ids;
35 int *cnums;
36 const char **names;
37 unsigned num;
39 bool *exists;
40 unsigned num_orphans;
42 bool verbose;
43 bool dry_run;
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);
59 if (d == NULL) {
60 d_printf("<no data>\n");
61 } else {
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));
66 talloc_free(idstr);
69 static int read_connections_fn(const struct connections_key *key,
70 const struct connections_data *data,
71 void *cclean_ctx)
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);
77 void *tmp;
79 tmp = talloc_realloc(ctx, ctx->ids, struct server_id, n);
80 if (tmp == NULL) {
81 goto talloc_failed;
83 ctx->ids = (struct server_id *)tmp;
85 tmp = talloc_realloc(ctx, ctx->cnums, int, n);
86 if (tmp == NULL) {
87 goto talloc_failed;
89 ctx->cnums = (int *)tmp;
91 tmp = talloc_realloc(ctx, ctx->names, const char *, n);
92 if (tmp == NULL) {
93 goto talloc_failed;
95 ctx->names = (const char **)tmp;
98 if (ctx->verbose) {
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) {
106 goto talloc_failed;
108 ctx->num++;
110 return 0;
112 talloc_failed:
113 DEBUG(0, ("Out of memory\n"));
114 return -1;
117 static int read_connections(struct cclean_ctx *ctx)
119 int ret = connections_forall_read(
120 &read_connections_fn,
121 ctx);
122 if (ret < 0) {
123 return ret;
125 if (ret != ctx->num) {
126 DEBUG(0, ("Skipped %d invalid entries\n", ret - ctx->num));
128 return 0;
131 static int check_connections(struct cclean_ctx *ctx)
133 int i, ret = -1;
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"));
138 goto done;
141 if (!serverids_exist(ctx->ids, ctx->num, ctx->exists)) {
142 DEBUG(0, ("serverids_exist() failed\n"));
143 goto done;
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);
151 talloc_free(idstr);
152 ctx->num_orphans++;
155 ret = 0;
156 done:
157 return ret;
160 static int delete_orphans(struct cclean_ctx *ctx)
162 NTSTATUS status;
163 struct db_record *conn;
164 int i, ret = 0;
166 for (i=0; i<ctx->num; i++) {
167 if (!ctx->exists[i]) {
168 TDB_DATA key, value;
169 conn = connections_fetch_entry_ext(NULL,
170 ctx->ids[i],
171 ctx->cnums[i],
172 ctx->names[i]);
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);
181 if (!ctx->dry_run) {
182 status = dbwrap_record_delete(conn);
183 if (!NT_STATUS_IS_OK(status)) {
184 DEBUG(0, ("Failed to delete record: %s\n",
185 nt_errstr(status)));
186 ret = -2;
189 TALLOC_FREE(conn);
192 return ret;
195 static int cclean(bool verbose, bool dry_run, bool automatic)
197 int ret = -1;
198 struct cclean_ctx *ctx = talloc_zero(talloc_tos(), struct cclean_ctx);
199 if (ctx == NULL) {
200 d_printf("Out of memory\n");
201 goto done;
204 ctx->verbose = verbose;
205 ctx->dry_run = dry_run;
207 ret = read_connections(ctx);
208 if (ret != 0) {
209 d_printf("Failed to read connections\n");
210 goto done;
212 d_printf("Read %u connections\n", ctx->num);
214 ret = check_connections(ctx);
215 if (ret != 0) {
216 d_printf("Failed to check connections\n");
217 goto done;
219 d_printf("Found %u orphans\n", ctx->num_orphans);
221 if (ctx->num_orphans == 0) {
222 goto done;
225 if (!automatic) {
226 int act = interact_prompt("Delete ([y]es/[n]o)", "yn", 'n');
227 if (tolower(act) != 'y') {
228 ret = 0;
229 goto done;
232 ret = delete_orphans(ctx);
233 if (ret != 0) {
234 d_printf("Failed to delete all orphans\n");
236 done:
237 talloc_free(ctx);
238 return ret;
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)
249 int ret = -1;
251 struct functable func[] = {
253 "cleanup",
254 net_connections_cleanup,
255 NET_TRANSPORT_LOCAL,
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"));
266 return -1;
270 ret = net_run_function(c, argc, argv, "net connections", func);
272 return ret;