buildtools: Rename perl vendorarch configure option.
[Samba.git] / ctdb / tools / ltdbtool.c
blob13fd7f98d7d5d445a4b9f7f520e66fccb6fd9f4e
1 /*
2 * ctdb local tdb tool
4 * Copyright (C) Gregor Beck 2011
5 * Copyright (C) Michael Adam 2011
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.
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.
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/>.
21 #include <stdio.h>
22 #include <stdbool.h>
23 #include <stddef.h>
24 #include <stdlib.h>
25 #include <ctype.h> /* isprint */
26 #include <string.h> /* strstr */
27 #include <fcntl.h> /* mode_t */
28 #include <sys/stat.h> /* S_IRUSR */
29 #include <stdint.h> /* uint32_t */
30 #include <netinet/in.h> /* struct sockaddr_in */
31 #include <sys/socket.h> /* struct sockaddr */
32 #include <sys/param.h> /* MIN */
33 #include <tdb.h>
34 #include <unistd.h> /* getopt */
35 #include <errno.h>
37 #include "ctdb_protocol.h"
39 enum {
40 MAX_HEADER_SIZE=24,
41 OUT_MODE = S_IRUSR | S_IWUSR,
42 OUT_FLAGS = O_EXCL|O_CREAT|O_RDWR,
45 union ltdb_header {
46 struct ctdb_ltdb_header hdr;
47 uint32_t uints[MAX_HEADER_SIZE/4];
50 static const union ltdb_header DEFAULT_HDR = {
51 .hdr.dmaster = -1,
54 static int help(const char* cmd)
56 fprintf(stdout, ""
57 "Usage: %s [options] <command>\n"
58 "\n"
59 "Options:\n"
60 " -s {0|32|64} specify how to determine the ctdb record header size\n"
61 " for the input database:\n"
62 " 0: no ctdb header\n"
63 " 32: ctdb header size of a 32 bit system (20 bytes)\n"
64 " 64: ctdb header size of a 64 bit system (24 bytes)\n"
65 " default: 32 or 64 depending on the system architecture\n"
66 "\n"
67 " -S <num> the number of bytes to interpret as ctdb record header\n"
68 " for the input database (beware!)\n"
69 "\n"
70 " -o {0|32|64} specify how to determine the ctdb record header size\n"
71 " for the output database\n"
72 " 0: no ctdb header\n"
73 " 32: ctdb header size of a 32 bit system (20 bytes)\n"
74 " 64: ctdb header size of a 64 bit system (24 bytes)\n"
75 " default: 32 or 64 depending on the system architecture\n"
76 "\n"
77 " -O <num> the number of bytes to interpret as ctdb record header\n"
78 " for the output database (beware!)\n"
79 "\n"
80 " -e Include empty records, defaults to off\n"
81 "\n"
82 " -p print header (for the dump command), defaults to off\n"
83 "\n"
84 " -h print this help\n"
85 "\n"
86 "Commands:\n"
87 " help print this help\n"
88 " dump <db> dump the db to stdout\n"
89 " convert <in_db> <out_db> convert the db\n\n", cmd);
90 return 0;
93 static int usage(const char* cmd)
95 fprintf(stderr,
96 "Usage: %s dump [-e] [-p] [-s{0|32|64}] <idb>\n"
97 " %s convert [-e] [-s{0|32|64}] [-o{0|32|64}] <idb> <odb>\n"
98 " %s {help|-h}\n"
99 , cmd, cmd, cmd);
100 return -1;
103 static int
104 ltdb_traverse(TDB_CONTEXT *tdb, int (*fn)(TDB_CONTEXT*, TDB_DATA, TDB_DATA,
105 struct ctdb_ltdb_header*, void *),
106 void *state, int hsize, bool skip_empty);
108 struct write_record_ctx {
109 TDB_CONTEXT* tdb;
110 size_t hsize;
111 int tdb_store_flags;
114 static int
115 write_record(TDB_CONTEXT* tdb, TDB_DATA key, TDB_DATA val,
116 struct ctdb_ltdb_header* hdr,
117 void* write_record_ctx);
120 struct dump_record_ctx {
121 FILE* file;
122 void (*print_data)(FILE*, TDB_DATA);
123 void (*dump_header)(struct dump_record_ctx*, struct ctdb_ltdb_header*);
126 static int dump_record(TDB_CONTEXT* tdb, TDB_DATA key, TDB_DATA val,
127 struct ctdb_ltdb_header* hdr,
128 void* dump_record_ctx);
129 static void print_data_tdbdump(FILE* file, TDB_DATA data);
130 static void dump_header_full(struct dump_record_ctx*, struct ctdb_ltdb_header*);
131 static void dump_header_nop(struct dump_record_ctx* c,
132 struct ctdb_ltdb_header* h)
135 static int dump_db(const char* iname, FILE* ofile, int hsize, bool dump_header,
136 bool empty)
138 int ret = -1;
139 TDB_CONTEXT* idb = tdb_open(iname, 0, TDB_DEFAULT, O_RDONLY, 0);
140 if (!idb) {
141 perror("tdbopen in");
142 } else {
143 struct dump_record_ctx dump_ctx = {
144 .file = ofile,
145 .print_data = &print_data_tdbdump,
146 .dump_header = dump_header ? &dump_header_full
147 : &dump_header_nop,
149 ret = ltdb_traverse(idb, &dump_record, &dump_ctx, hsize, !empty);
150 tdb_close(idb);
152 return ret;
155 static int conv_db(const char* iname, const char* oname, size_t isize,
156 size_t osize, bool keep_empty)
158 int ret = -1;
159 TDB_CONTEXT* idb = tdb_open(iname, 0, TDB_DEFAULT, O_RDONLY, 0);
160 if (!idb) {
161 perror("tdbopen in");
162 } else {
163 TDB_CONTEXT* odb = tdb_open(oname, 0, TDB_DEFAULT, OUT_FLAGS, OUT_MODE);
164 if (!odb) {
165 perror("tdbopen out");
166 } else {
167 struct write_record_ctx ctx = {
168 .tdb = odb,
169 .hsize = osize,
170 .tdb_store_flags = TDB_REPLACE,
172 ret = ltdb_traverse(idb, &write_record, &ctx, isize, !keep_empty);
173 tdb_close(odb);
175 tdb_close(idb);
177 return ret;
180 static bool parse_size(size_t* size, const char* arg, bool raw) {
181 long val;
182 errno = 0;
183 val = strtol(arg, (char **) NULL, 10);
184 if (errno != 0) {
185 return false;
187 if (!raw) {
188 switch(val) {
189 case 0:
190 break;
191 case 32:
192 val = 20;
193 break;
194 case 64:
195 val = 24;
196 break;
197 default:
198 return false;
201 *size = MIN(val, MAX_HEADER_SIZE);
202 return true;
206 int main(int argc, char* argv[])
208 size_t isize = sizeof(struct ctdb_ltdb_header);
209 size_t osize = sizeof(struct ctdb_ltdb_header);
210 bool print_header = false;
211 bool keep_empty = false;
212 int opt;
213 const char *cmd, *idb, *odb;
215 while ((opt = getopt(argc, argv, "s:o:S:O:phe")) != -1) {
216 switch (opt) {
217 case 's':
218 case 'S':
219 if (!parse_size(&isize, optarg, isupper(opt))) {
220 return usage(argv[0]);
222 break;
223 case 'o':
224 case 'O':
225 if (!parse_size(&osize, optarg, isupper(opt))) {
226 return usage(argv[0]);
228 break;
229 case 'p':
230 print_header = true;
231 break;
232 case 'e':
233 keep_empty = true;
234 break;
235 case 'h':
236 return help(argv[0]);
237 default:
238 return usage(argv[0]);
242 if (argc - optind < 1) {
243 return usage(argv[0]);
246 cmd = argv[optind];
248 if (strcmp(cmd, "help") == 0) {
249 return help(argv[0]);
251 else if (strcmp(cmd, "dump") == 0) {
252 int ret;
253 if (argc - optind != 2) {
254 return usage(argv[0]);
256 idb = argv[optind+1];
257 ret = dump_db(idb, stdout, isize, print_header, keep_empty);
258 return (ret >= 0) ? 0 : ret;
260 else if (strcmp(cmd, "convert") == 0) {
261 int ret;
262 if (argc - optind != 3) {
263 return usage(argv[0]);
265 idb = argv[optind+1];
266 odb = argv[optind+2];
267 ret = conv_db(idb, odb, isize, osize, keep_empty);
268 return (ret >= 0) ? 0 : ret;
271 return usage(argv[0]);
274 struct ltdb_traverse_ctx {
275 int (*fn)(TDB_CONTEXT*,TDB_DATA,TDB_DATA,struct ctdb_ltdb_header*,void *);
276 void* state;
277 size_t hsize;
278 bool skip_empty;
279 unsigned nempty;
282 static int
283 ltdb_traverse_fn(TDB_CONTEXT* tdb, TDB_DATA key, TDB_DATA val,
284 void* ltdb_traverse_ctx)
286 struct ltdb_traverse_ctx* ctx =
287 (struct ltdb_traverse_ctx*)ltdb_traverse_ctx;
288 union ltdb_header hdr = DEFAULT_HDR;
290 const size_t hsize = MIN(sizeof(hdr), ctx->hsize);
291 if (val.dsize < hsize) {
292 fprintf(stderr, "Value too short to contain a ctdb header: ");
293 print_data_tdbdump(stderr, key);
294 fprintf(stderr, " = ");
295 print_data_tdbdump(stderr, val);
296 fputc('\n', stderr);
297 return -1;
299 if (val.dsize == hsize && ctx->skip_empty) {
300 ctx->nempty++;
301 return 0;
304 memcpy(&hdr, val.dptr, hsize);
306 if (hdr.uints[5] != 0) {
307 fprintf(stderr, "Warning: header padding isn't zero! Wrong header size?\n");
309 val.dptr += ctx->hsize;
310 val.dsize -= ctx->hsize;
311 return ctx->fn(tdb, key, val, &hdr.hdr, ctx->state);
314 int ltdb_traverse(TDB_CONTEXT *tdb,
315 int (*fn)(TDB_CONTEXT *,TDB_DATA,TDB_DATA,struct ctdb_ltdb_header*,void *),
316 void *state, int hsize, bool skip_empty)
318 struct ltdb_traverse_ctx ctx = {
319 .fn = fn,
320 .state = state,
321 .hsize = hsize < 0 ? sizeof(struct ctdb_ltdb_header) : hsize,
322 .skip_empty = skip_empty,
323 .nempty = 0,
325 int ret = tdb_traverse(tdb, &ltdb_traverse_fn, &ctx);
327 return (ret < 0) ? ret : (ret - ctx.nempty);
330 int write_record(TDB_CONTEXT* tdb, TDB_DATA key, TDB_DATA val,
331 struct ctdb_ltdb_header* hdr,
332 void* write_record_ctx)
334 struct write_record_ctx* ctx
335 = (struct write_record_ctx*)write_record_ctx;
337 if (ctx->hsize == 0) {
338 if (tdb_store(ctx->tdb, key, val, ctx->tdb_store_flags) == -1) {
339 fprintf(stderr, "tdb_store: %s\n", tdb_errorstr(ctx->tdb));
340 return -1;
342 } else {
343 TDB_DATA h = {
344 .dptr = (void*)hdr,
345 .dsize = ctx->hsize,
347 if(tdb_store(ctx->tdb, key, h, ctx->tdb_store_flags) == -1) {
348 fprintf(stderr, "tdb_store: %s\n", tdb_errorstr(ctx->tdb));
349 return -1;
351 if(tdb_append(ctx->tdb, key, val) == -1) {
352 fprintf(stderr, "tdb_append: %s\n", tdb_errorstr(ctx->tdb));
353 return -1;
356 return 0;
359 int dump_record(TDB_CONTEXT* tdb, TDB_DATA key, TDB_DATA val,
360 struct ctdb_ltdb_header* hdr,
361 void* dump_record_ctx)
363 struct dump_record_ctx* ctx = (struct dump_record_ctx*)dump_record_ctx;
365 fprintf(ctx->file, "{\nkey(%d) = ", (int)key.dsize);
366 ctx->print_data(ctx->file, key);
367 fputc('\n', ctx->file);
368 ctx->dump_header(ctx, hdr);
369 fprintf(ctx->file, "data(%d) = ", (int)val.dsize);
370 ctx->print_data(ctx->file, val);
371 fprintf(ctx->file, "\n}\n");
372 return 0;
375 void dump_header_full(struct dump_record_ctx* c, struct ctdb_ltdb_header* h)
377 fprintf(c->file, "dmaster: %d\nrsn: %llu\nflags: 0x%X\n",
378 (int)h->dmaster,
379 (unsigned long long)h->rsn, h->flags);
382 void print_data_tdbdump(FILE* file, TDB_DATA data) {
383 unsigned char *ptr = data.dptr;
384 fputc('"', file);
385 while (data.dsize--) {
386 if (isprint(*ptr) && !strchr("\"\\", *ptr)) {
387 fputc(*ptr, file);
388 } else {
389 fprintf(file, "\\%02X", *ptr);
391 ptr++;
393 fputc('"',file);