source: vendor/current/ctdb/tools/ltdbtool.c

Last change on this file was 988, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.3

File size: 9.7 KB
Line 
1/*
2 * ctdb local tdb tool
3 *
4 * Copyright (C) Gregor Beck 2011
5 * Copyright (C) Michael Adam 2011
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include "replace.h"
22#include "system/filesys.h"
23#include "system/network.h"
24#include "system/locale.h"
25
26#include <tdb.h>
27
28#include "protocol/protocol.h"
29
30enum {
31 MAX_HEADER_SIZE=24,
32 OUT_MODE = S_IRUSR | S_IWUSR,
33 OUT_FLAGS = O_EXCL|O_CREAT|O_RDWR,
34};
35
36union ltdb_header {
37 struct ctdb_ltdb_header hdr;
38 uint32_t uints[MAX_HEADER_SIZE/4];
39};
40
41static const union ltdb_header DEFAULT_HDR = {
42 .hdr.dmaster = -1,
43};
44
45static int help(const char* cmd)
46{
47 fprintf(stdout, ""
48"Usage: %s [options] <command>\n"
49"\n"
50"Options:\n"
51" -s {0|32|64} specify how to determine the ctdb record header size\n"
52" for the input database:\n"
53" 0: no ctdb header\n"
54" 32: ctdb header size of a 32 bit system (20 bytes)\n"
55" 64: ctdb header size of a 64 bit system (24 bytes)\n"
56" default: 32 or 64 depending on the system architecture\n"
57"\n"
58" -S <num> the number of bytes to interpret as ctdb record header\n"
59" for the input database (beware!)\n"
60"\n"
61" -o {0|32|64} specify how to determine the ctdb record header size\n"
62" for the output database\n"
63" 0: no ctdb header\n"
64" 32: ctdb header size of a 32 bit system (20 bytes)\n"
65" 64: ctdb header size of a 64 bit system (24 bytes)\n"
66" default: 32 or 64 depending on the system architecture\n"
67"\n"
68" -O <num> the number of bytes to interpret as ctdb record header\n"
69" for the output database (beware!)\n"
70"\n"
71" -e Include empty records, defaults to off\n"
72"\n"
73" -p print header (for the dump command), defaults to off\n"
74"\n"
75" -h print this help\n"
76"\n"
77"Commands:\n"
78" help print this help\n"
79" dump <db> dump the db to stdout\n"
80" convert <in_db> <out_db> convert the db\n\n", cmd);
81 return 0;
82}
83
84static int usage(const char* cmd)
85{
86 fprintf(stderr,
87 "Usage: %s dump [-e] [-p] [-s{0|32|64}] <idb>\n"
88 " %s convert [-e] [-s{0|32|64}] [-o{0|32|64}] <idb> <odb>\n"
89 " %s {help|-h}\n"
90 , cmd, cmd, cmd);
91 return -1;
92}
93
94static int
95ltdb_traverse(TDB_CONTEXT *tdb, int (*fn)(TDB_CONTEXT*, TDB_DATA, TDB_DATA,
96 struct ctdb_ltdb_header*, void *),
97 void *state, int hsize, bool skip_empty);
98
99struct write_record_ctx {
100 TDB_CONTEXT* tdb;
101 size_t hsize;
102 int tdb_store_flags;
103};
104
105static int
106write_record(TDB_CONTEXT* tdb, TDB_DATA key, TDB_DATA val,
107 struct ctdb_ltdb_header* hdr,
108 void* write_record_ctx);
109
110
111struct dump_record_ctx {
112 FILE* file;
113 void (*print_data)(FILE*, TDB_DATA);
114 void (*dump_header)(struct dump_record_ctx*, struct ctdb_ltdb_header*);
115};
116
117static int dump_record(TDB_CONTEXT* tdb, TDB_DATA key, TDB_DATA val,
118 struct ctdb_ltdb_header* hdr,
119 void* dump_record_ctx);
120static void print_data_tdbdump(FILE* file, TDB_DATA data);
121static void dump_header_full(struct dump_record_ctx*, struct ctdb_ltdb_header*);
122static void dump_header_nop(struct dump_record_ctx* c,
123 struct ctdb_ltdb_header* h)
124{}
125
126static int dump_db(const char* iname, FILE* ofile, int hsize, bool dump_header,
127 bool empty)
128{
129 int ret = -1;
130 TDB_CONTEXT* idb = tdb_open(iname, 0, TDB_DEFAULT, O_RDONLY, 0);
131 if (!idb) {
132 perror("tdbopen in");
133 } else {
134 struct dump_record_ctx dump_ctx = {
135 .file = ofile,
136 .print_data = &print_data_tdbdump,
137 .dump_header = dump_header ? &dump_header_full
138 : &dump_header_nop,
139 };
140 ret = ltdb_traverse(idb, &dump_record, &dump_ctx, hsize, !empty);
141 tdb_close(idb);
142 }
143 return ret;
144}
145
146static int conv_db(const char* iname, const char* oname, size_t isize,
147 size_t osize, bool keep_empty)
148{
149 int ret = -1;
150 TDB_CONTEXT* idb = tdb_open(iname, 0, TDB_DEFAULT, O_RDONLY, 0);
151 if (!idb) {
152 perror("tdbopen in");
153 } else {
154 TDB_CONTEXT* odb = tdb_open(oname, 0, TDB_DEFAULT, OUT_FLAGS, OUT_MODE);
155 if (!odb) {
156 perror("tdbopen out");
157 } else {
158 struct write_record_ctx ctx = {
159 .tdb = odb,
160 .hsize = osize,
161 .tdb_store_flags = TDB_REPLACE,
162 };
163 ret = ltdb_traverse(idb, &write_record, &ctx, isize, !keep_empty);
164 tdb_close(odb);
165 }
166 tdb_close(idb);
167 }
168 return ret;
169}
170
171static bool parse_size(size_t* size, const char* arg, bool raw) {
172 long val;
173 errno = 0;
174 val = strtol(arg, (char **) NULL, 10);
175 if (errno != 0) {
176 return false;
177 }
178 if (!raw) {
179 switch(val) {
180 case 0:
181 break;
182 case 32:
183 val = 20;
184 break;
185 case 64:
186 val = 24;
187 break;
188 default:
189 return false;
190 }
191 }
192 *size = MIN(val, MAX_HEADER_SIZE);
193 return true;
194}
195
196
197int main(int argc, char* argv[])
198{
199 size_t isize = sizeof(struct ctdb_ltdb_header);
200 size_t osize = sizeof(struct ctdb_ltdb_header);
201 bool print_header = false;
202 bool keep_empty = false;
203 int opt;
204 const char *cmd, *idb, *odb;
205
206 while ((opt = getopt(argc, argv, "s:o:S:O:phe")) != -1) {
207 switch (opt) {
208 case 's':
209 case 'S':
210 if (!parse_size(&isize, optarg, isupper(opt))) {
211 return usage(argv[0]);
212 }
213 break;
214 case 'o':
215 case 'O':
216 if (!parse_size(&osize, optarg, isupper(opt))) {
217 return usage(argv[0]);
218 }
219 break;
220 case 'p':
221 print_header = true;
222 break;
223 case 'e':
224 keep_empty = true;
225 break;
226 case 'h':
227 return help(argv[0]);
228 default:
229 return usage(argv[0]);
230 }
231 }
232
233 if (argc - optind < 1) {
234 return usage(argv[0]);
235 }
236
237 cmd = argv[optind];
238
239 if (strcmp(cmd, "help") == 0) {
240 return help(argv[0]);
241 }
242 else if (strcmp(cmd, "dump") == 0) {
243 int ret;
244 if (argc - optind != 2) {
245 return usage(argv[0]);
246 }
247 idb = argv[optind+1];
248 ret = dump_db(idb, stdout, isize, print_header, keep_empty);
249 return (ret >= 0) ? 0 : ret;
250 }
251 else if (strcmp(cmd, "convert") == 0) {
252 int ret;
253 if (argc - optind != 3) {
254 return usage(argv[0]);
255 }
256 idb = argv[optind+1];
257 odb = argv[optind+2];
258 ret = conv_db(idb, odb, isize, osize, keep_empty);
259 return (ret >= 0) ? 0 : ret;
260 }
261
262 return usage(argv[0]);
263}
264
265struct ltdb_traverse_ctx {
266 int (*fn)(TDB_CONTEXT*,TDB_DATA,TDB_DATA,struct ctdb_ltdb_header*,void *);
267 void* state;
268 size_t hsize;
269 bool skip_empty;
270 unsigned nempty;
271};
272
273static int
274ltdb_traverse_fn(TDB_CONTEXT* tdb, TDB_DATA key, TDB_DATA val,
275 void* ltdb_traverse_ctx)
276{
277 struct ltdb_traverse_ctx* ctx =
278 (struct ltdb_traverse_ctx*)ltdb_traverse_ctx;
279 union ltdb_header hdr = DEFAULT_HDR;
280
281 const size_t hsize = MIN(sizeof(hdr), ctx->hsize);
282 if (val.dsize < hsize) {
283 fprintf(stderr, "Value too short to contain a ctdb header: ");
284 print_data_tdbdump(stderr, key);
285 fprintf(stderr, " = ");
286 print_data_tdbdump(stderr, val);
287 fputc('\n', stderr);
288 return -1;
289 }
290 if (val.dsize == hsize && ctx->skip_empty) {
291 ctx->nempty++;
292 return 0;
293 }
294
295 memcpy(&hdr, val.dptr, hsize);
296
297 if (hdr.uints[5] != 0) {
298 fprintf(stderr, "Warning: header padding isn't zero! Wrong header size?\n");
299 }
300 val.dptr += ctx->hsize;
301 val.dsize -= ctx->hsize;
302 return ctx->fn(tdb, key, val, &hdr.hdr, ctx->state);
303}
304
305int ltdb_traverse(TDB_CONTEXT *tdb,
306 int (*fn)(TDB_CONTEXT *,TDB_DATA,TDB_DATA,struct ctdb_ltdb_header*,void *),
307 void *state, int hsize, bool skip_empty)
308{
309 struct ltdb_traverse_ctx ctx = {
310 .fn = fn,
311 .state = state,
312 .hsize = hsize < 0 ? sizeof(struct ctdb_ltdb_header) : hsize,
313 .skip_empty = skip_empty,
314 .nempty = 0,
315 };
316 int ret = tdb_traverse(tdb, &ltdb_traverse_fn, &ctx);
317
318 return (ret < 0) ? ret : (ret - ctx.nempty);
319}
320
321int write_record(TDB_CONTEXT* tdb, TDB_DATA key, TDB_DATA val,
322 struct ctdb_ltdb_header* hdr,
323 void* write_record_ctx)
324{
325 struct write_record_ctx* ctx
326 = (struct write_record_ctx*)write_record_ctx;
327
328 if (ctx->hsize == 0) {
329 if (tdb_store(ctx->tdb, key, val, ctx->tdb_store_flags) == -1) {
330 fprintf(stderr, "tdb_store: %s\n", tdb_errorstr(ctx->tdb));
331 return -1;
332 }
333 } else {
334 TDB_DATA h = {
335 .dptr = (void*)hdr,
336 .dsize = ctx->hsize,
337 };
338 if(tdb_store(ctx->tdb, key, h, ctx->tdb_store_flags) == -1) {
339 fprintf(stderr, "tdb_store: %s\n", tdb_errorstr(ctx->tdb));
340 return -1;
341 }
342 if(tdb_append(ctx->tdb, key, val) == -1) {
343 fprintf(stderr, "tdb_append: %s\n", tdb_errorstr(ctx->tdb));
344 return -1;
345 }
346 }
347 return 0;
348}
349
350int dump_record(TDB_CONTEXT* tdb, TDB_DATA key, TDB_DATA val,
351 struct ctdb_ltdb_header* hdr,
352 void* dump_record_ctx)
353{
354 struct dump_record_ctx* ctx = (struct dump_record_ctx*)dump_record_ctx;
355
356 fprintf(ctx->file, "{\nkey(%d) = ", (int)key.dsize);
357 ctx->print_data(ctx->file, key);
358 fputc('\n', ctx->file);
359 ctx->dump_header(ctx, hdr);
360 fprintf(ctx->file, "data(%d) = ", (int)val.dsize);
361 ctx->print_data(ctx->file, val);
362 fprintf(ctx->file, "\n}\n");
363 return 0;
364}
365
366void dump_header_full(struct dump_record_ctx* c, struct ctdb_ltdb_header* h)
367{
368 fprintf(c->file, "dmaster: %d\nrsn: %llu\nflags: 0x%X\n",
369 (int)h->dmaster,
370 (unsigned long long)h->rsn, h->flags);
371}
372
373void print_data_tdbdump(FILE* file, TDB_DATA data) {
374 unsigned char *ptr = data.dptr;
375 fputc('"', file);
376 while (data.dsize--) {
377 if (isprint(*ptr) && !strchr("\"\\", *ptr)) {
378 fputc(*ptr, file);
379 } else {
380 fprintf(file, "\\%02X", *ptr);
381 }
382 ptr++;
383 }
384 fputc('"',file);
385}
386
Note: See TracBrowser for help on using the repository browser.