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/>.
22 #include "system/filesys.h"
23 #include "system/network.h"
24 #include "system/locale.h"
28 #include "protocol/protocol.h"
32 OUT_MODE
= S_IRUSR
| S_IWUSR
,
33 OUT_FLAGS
= O_EXCL
|O_CREAT
|O_RDWR
,
37 struct ctdb_ltdb_header hdr
;
38 uint32_t uints
[MAX_HEADER_SIZE
/4];
41 static const union ltdb_header DEFAULT_HDR
= {
47 static int help(const char* cmd
)
50 "Usage: %s [options] <command>\n"
53 " -s {0|32|64} specify how to determine the ctdb record header size\n"
54 " for the input database:\n"
55 " 0: no ctdb header\n"
56 " 32: ctdb header size of a 32 bit system (20 bytes)\n"
57 " 64: ctdb header size of a 64 bit system (24 bytes)\n"
58 " default: 32 or 64 depending on the system architecture\n"
60 " -S <num> the number of bytes to interpret as ctdb record header\n"
61 " for the input database (beware!)\n"
63 " -o {0|32|64} specify how to determine the ctdb record header size\n"
64 " for the output database\n"
65 " 0: no ctdb header\n"
66 " 32: ctdb header size of a 32 bit system (20 bytes)\n"
67 " 64: ctdb header size of a 64 bit system (24 bytes)\n"
68 " default: 32 or 64 depending on the system architecture\n"
70 " -O <num> the number of bytes to interpret as ctdb record header\n"
71 " for the output database (beware!)\n"
73 " -e Include empty records, defaults to off\n"
75 " -p print header (for the dump command), defaults to off\n"
77 " -h print this help\n"
80 " help print this help\n"
81 " dump <db> dump the db to stdout\n"
82 " convert <in_db> <out_db> convert the db\n\n", cmd
);
86 static int usage(const char* cmd
)
89 "Usage: %s dump [-e] [-p] [-s{0|32|64}] <idb>\n"
90 " %s convert [-e] [-s{0|32|64}] [-o{0|32|64}] <idb> <odb>\n"
97 ltdb_traverse(TDB_CONTEXT
*tdb
, int (*fn
)(TDB_CONTEXT
*, TDB_DATA
, TDB_DATA
,
98 struct ctdb_ltdb_header
*, void *),
99 void *state
, int hsize
, bool skip_empty
);
101 struct write_record_ctx
{
108 write_record(TDB_CONTEXT
* tdb
, TDB_DATA key
, TDB_DATA val
,
109 struct ctdb_ltdb_header
* hdr
,
110 void* write_record_ctx
);
113 struct dump_record_ctx
{
115 void (*print_data
)(FILE*, TDB_DATA
);
116 void (*dump_header
)(struct dump_record_ctx
*, struct ctdb_ltdb_header
*);
119 static int dump_record(TDB_CONTEXT
* tdb
, TDB_DATA key
, TDB_DATA val
,
120 struct ctdb_ltdb_header
* hdr
,
121 void* dump_record_ctx
);
122 static void print_data_tdbdump(FILE* file
, TDB_DATA data
);
123 static void dump_header_full(struct dump_record_ctx
*, struct ctdb_ltdb_header
*);
124 static void dump_header_nop(struct dump_record_ctx
* c
,
125 struct ctdb_ltdb_header
* h
)
128 static int dump_db(const char* iname
, FILE* ofile
, int hsize
, bool dump_header
,
132 TDB_CONTEXT
* idb
= tdb_open(iname
, 0, TDB_DEFAULT
, O_RDONLY
, 0);
134 perror("tdbopen in");
136 struct dump_record_ctx dump_ctx
= {
138 .print_data
= &print_data_tdbdump
,
139 .dump_header
= dump_header
? &dump_header_full
142 ret
= ltdb_traverse(idb
, &dump_record
, &dump_ctx
, hsize
, !empty
);
148 static int conv_db(const char* iname
, const char* oname
, size_t isize
,
149 size_t osize
, bool keep_empty
)
152 TDB_CONTEXT
* idb
= tdb_open(iname
, 0, TDB_DEFAULT
, O_RDONLY
, 0);
154 perror("tdbopen in");
156 TDB_CONTEXT
* odb
= tdb_open(oname
, 0, TDB_DEFAULT
, OUT_FLAGS
, OUT_MODE
);
158 perror("tdbopen out");
160 struct write_record_ctx ctx
= {
163 .tdb_store_flags
= TDB_REPLACE
,
165 ret
= ltdb_traverse(idb
, &write_record
, &ctx
, isize
, !keep_empty
);
173 static bool parse_size(size_t* size
, const char* arg
, bool raw
) {
176 val
= strtol(arg
, (char **) NULL
, 10);
194 *size
= MIN(val
, MAX_HEADER_SIZE
);
199 int main(int argc
, char* argv
[])
201 size_t isize
= sizeof(struct ctdb_ltdb_header
);
202 size_t osize
= sizeof(struct ctdb_ltdb_header
);
203 bool print_header
= false;
204 bool keep_empty
= false;
206 const char *cmd
, *idb
, *odb
;
208 while ((opt
= getopt(argc
, argv
, "s:o:S:O:phe")) != -1) {
212 if (!parse_size(&isize
, optarg
, isupper(opt
))) {
213 return usage(argv
[0]);
218 if (!parse_size(&osize
, optarg
, isupper(opt
))) {
219 return usage(argv
[0]);
229 return help(argv
[0]);
231 return usage(argv
[0]);
235 if (argc
- optind
< 1) {
236 return usage(argv
[0]);
241 if (strcmp(cmd
, "help") == 0) {
242 return help(argv
[0]);
244 else if (strcmp(cmd
, "dump") == 0) {
246 if (argc
- optind
!= 2) {
247 return usage(argv
[0]);
249 idb
= argv
[optind
+1];
250 ret
= dump_db(idb
, stdout
, isize
, print_header
, keep_empty
);
251 return (ret
>= 0) ? 0 : ret
;
253 else if (strcmp(cmd
, "convert") == 0) {
255 if (argc
- optind
!= 3) {
256 return usage(argv
[0]);
258 idb
= argv
[optind
+1];
259 odb
= argv
[optind
+2];
260 ret
= conv_db(idb
, odb
, isize
, osize
, keep_empty
);
261 return (ret
>= 0) ? 0 : ret
;
264 return usage(argv
[0]);
267 struct ltdb_traverse_ctx
{
268 int (*fn
)(TDB_CONTEXT
*,TDB_DATA
,TDB_DATA
,struct ctdb_ltdb_header
*,void *);
276 ltdb_traverse_fn(TDB_CONTEXT
* tdb
, TDB_DATA key
, TDB_DATA val
,
277 void* ltdb_traverse_ctx
)
279 struct ltdb_traverse_ctx
* ctx
=
280 (struct ltdb_traverse_ctx
*)ltdb_traverse_ctx
;
281 union ltdb_header hdr
= DEFAULT_HDR
;
283 const size_t hsize
= MIN(sizeof(hdr
), ctx
->hsize
);
284 if (val
.dsize
< hsize
) {
285 fprintf(stderr
, "Value too short to contain a ctdb header: ");
286 print_data_tdbdump(stderr
, key
);
287 fprintf(stderr
, " = ");
288 print_data_tdbdump(stderr
, val
);
292 if (val
.dsize
== hsize
&& ctx
->skip_empty
) {
297 memcpy(&hdr
, val
.dptr
, hsize
);
299 if (hdr
.uints
[5] != 0) {
300 fprintf(stderr
, "Warning: header padding isn't zero! Wrong header size?\n");
302 val
.dptr
+= ctx
->hsize
;
303 val
.dsize
-= ctx
->hsize
;
304 return ctx
->fn(tdb
, key
, val
, &hdr
.hdr
, ctx
->state
);
307 static int ltdb_traverse(TDB_CONTEXT
*tdb
,
308 int (*fn
)(TDB_CONTEXT
*, TDB_DATA
, TDB_DATA
,
309 struct ctdb_ltdb_header
*, void *),
310 void *state
, int hsize
, bool skip_empty
)
312 struct ltdb_traverse_ctx ctx
= {
315 .hsize
= hsize
< 0 ? sizeof(struct ctdb_ltdb_header
) : hsize
,
316 .skip_empty
= skip_empty
,
319 int ret
= tdb_traverse(tdb
, <db_traverse_fn
, &ctx
);
321 return (ret
< 0) ? ret
: (ret
- ctx
.nempty
);
324 static int write_record(TDB_CONTEXT
* tdb
, TDB_DATA key
, TDB_DATA val
,
325 struct ctdb_ltdb_header
* hdr
,
326 void* write_record_ctx
)
328 struct write_record_ctx
* ctx
329 = (struct write_record_ctx
*)write_record_ctx
;
332 if (ctx
->hsize
== 0) {
333 ret
= tdb_store(ctx
->tdb
, key
, val
, ctx
->tdb_store_flags
);
337 rec
[0].dsize
= ctx
->hsize
;
338 rec
[0].dptr
= (uint8_t *)hdr
;
340 rec
[1].dsize
= val
.dsize
;
341 rec
[1].dptr
= val
.dptr
;
343 ret
= tdb_storev(ctx
->tdb
, key
, rec
, 2, ctx
->tdb_store_flags
);
347 fprintf(stderr
, "tdb_store: %s\n", tdb_errorstr(ctx
->tdb
));
354 static int dump_record(TDB_CONTEXT
* tdb
, TDB_DATA key
, TDB_DATA val
,
355 struct ctdb_ltdb_header
* hdr
,
356 void* dump_record_ctx
)
358 struct dump_record_ctx
* ctx
= (struct dump_record_ctx
*)dump_record_ctx
;
360 fprintf(ctx
->file
, "{\nkey(%d) = ", (int)key
.dsize
);
361 ctx
->print_data(ctx
->file
, key
);
362 fputc('\n', ctx
->file
);
363 ctx
->dump_header(ctx
, hdr
);
364 fprintf(ctx
->file
, "data(%d) = ", (int)val
.dsize
);
365 ctx
->print_data(ctx
->file
, val
);
366 fprintf(ctx
->file
, "\n}\n");
370 static void dump_header_full(struct dump_record_ctx
* c
,
371 struct ctdb_ltdb_header
* h
)
373 fprintf(c
->file
, "dmaster: %d\nrsn: %llu\nflags: 0x%X\n",
375 (unsigned long long)h
->rsn
, h
->flags
);
378 static void print_data_tdbdump(FILE* file
, TDB_DATA data
)
380 unsigned char *ptr
= data
.dptr
;
382 while (data
.dsize
--) {
383 if (isprint(*ptr
) && !strchr("\"\\", *ptr
)) {
386 fprintf(file
, "\\%02X", *ptr
);