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
, size_t 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
,
135 TDB_CONTEXT
* idb
= tdb_open(iname
, 0, TDB_DEFAULT
, O_RDONLY
, 0);
137 perror("tdbopen in");
139 struct dump_record_ctx dump_ctx
= {
141 .print_data
= &print_data_tdbdump
,
142 .dump_header
= dump_header
? &dump_header_full
145 ret
= ltdb_traverse(idb
, &dump_record
, &dump_ctx
, hsize
, !empty
);
151 static int conv_db(const char* iname
, const char* oname
, size_t isize
,
152 size_t osize
, bool keep_empty
)
155 TDB_CONTEXT
* idb
= tdb_open(iname
, 0, TDB_DEFAULT
, O_RDONLY
, 0);
157 perror("tdbopen in");
159 TDB_CONTEXT
* odb
= tdb_open(oname
, 0, TDB_DEFAULT
, OUT_FLAGS
, OUT_MODE
);
161 perror("tdbopen out");
163 struct write_record_ctx ctx
= {
166 .tdb_store_flags
= TDB_REPLACE
,
168 ret
= ltdb_traverse(idb
, &write_record
, &ctx
, isize
, !keep_empty
);
176 static bool parse_size(size_t* size
, const char* arg
, bool raw
) {
179 val
= strtol(arg
, (char **) NULL
, 10);
197 *size
= MIN(val
, MAX_HEADER_SIZE
);
202 int main(int argc
, char* argv
[])
204 size_t isize
= sizeof(struct ctdb_ltdb_header
);
205 size_t osize
= sizeof(struct ctdb_ltdb_header
);
206 bool print_header
= false;
207 bool keep_empty
= false;
209 const char *cmd
, *idb
, *odb
;
211 while ((opt
= getopt(argc
, argv
, "s:o:S:O:phe")) != -1) {
215 if (!parse_size(&isize
, optarg
, isupper(opt
))) {
216 return usage(argv
[0]);
221 if (!parse_size(&osize
, optarg
, isupper(opt
))) {
222 return usage(argv
[0]);
232 return help(argv
[0]);
234 return usage(argv
[0]);
238 if (argc
- optind
< 1) {
239 return usage(argv
[0]);
244 if (strcmp(cmd
, "help") == 0) {
245 return help(argv
[0]);
247 else if (strcmp(cmd
, "dump") == 0) {
249 if (argc
- optind
!= 2) {
250 return usage(argv
[0]);
252 idb
= argv
[optind
+1];
253 ret
= dump_db(idb
, stdout
, isize
, print_header
, keep_empty
);
254 return (ret
>= 0) ? 0 : ret
;
256 else if (strcmp(cmd
, "convert") == 0) {
258 if (argc
- optind
!= 3) {
259 return usage(argv
[0]);
261 idb
= argv
[optind
+1];
262 odb
= argv
[optind
+2];
263 ret
= conv_db(idb
, odb
, isize
, osize
, keep_empty
);
264 return (ret
>= 0) ? 0 : ret
;
267 return usage(argv
[0]);
270 struct ltdb_traverse_ctx
{
271 int (*fn
)(TDB_CONTEXT
*,TDB_DATA
,TDB_DATA
,struct ctdb_ltdb_header
*,void *);
279 ltdb_traverse_fn(TDB_CONTEXT
* tdb
, TDB_DATA key
, TDB_DATA val
,
280 void* ltdb_traverse_ctx
)
282 struct ltdb_traverse_ctx
* ctx
=
283 (struct ltdb_traverse_ctx
*)ltdb_traverse_ctx
;
284 union ltdb_header hdr
= DEFAULT_HDR
;
286 const size_t hsize
= MIN(sizeof(hdr
), ctx
->hsize
);
287 if (val
.dsize
< hsize
) {
288 fprintf(stderr
, "Value too short to contain a ctdb header: ");
289 print_data_tdbdump(stderr
, key
);
290 fprintf(stderr
, " = ");
291 print_data_tdbdump(stderr
, val
);
295 if (val
.dsize
== hsize
&& ctx
->skip_empty
) {
300 memcpy(&hdr
, val
.dptr
, hsize
);
302 if (hdr
.uints
[5] != 0) {
303 fprintf(stderr
, "Warning: header padding isn't zero! Wrong header size?\n");
305 val
.dptr
+= ctx
->hsize
;
306 val
.dsize
-= ctx
->hsize
;
307 return ctx
->fn(tdb
, key
, val
, &hdr
.hdr
, ctx
->state
);
310 static int ltdb_traverse(TDB_CONTEXT
*tdb
,
311 int (*fn
)(TDB_CONTEXT
*, TDB_DATA
, TDB_DATA
,
312 struct ctdb_ltdb_header
*, void *),
313 void *state
, size_t hsize
, bool skip_empty
)
315 struct ltdb_traverse_ctx ctx
= {
319 .skip_empty
= skip_empty
,
322 int ret
= tdb_traverse(tdb
, <db_traverse_fn
, &ctx
);
324 return (ret
< 0) ? ret
: (ret
- ctx
.nempty
);
327 static int write_record(TDB_CONTEXT
* tdb
, TDB_DATA key
, TDB_DATA val
,
328 struct ctdb_ltdb_header
* hdr
,
329 void* write_record_ctx
)
331 struct write_record_ctx
* ctx
332 = (struct write_record_ctx
*)write_record_ctx
;
335 if (ctx
->hsize
== 0) {
336 ret
= tdb_store(ctx
->tdb
, key
, val
, ctx
->tdb_store_flags
);
340 rec
[0].dsize
= ctx
->hsize
;
341 rec
[0].dptr
= (uint8_t *)hdr
;
343 rec
[1].dsize
= val
.dsize
;
344 rec
[1].dptr
= val
.dptr
;
346 ret
= tdb_storev(ctx
->tdb
, key
, rec
, 2, ctx
->tdb_store_flags
);
350 fprintf(stderr
, "tdb_store: %s\n", tdb_errorstr(ctx
->tdb
));
357 static int dump_record(TDB_CONTEXT
* tdb
, TDB_DATA key
, TDB_DATA val
,
358 struct ctdb_ltdb_header
* hdr
,
359 void* dump_record_ctx
)
361 struct dump_record_ctx
* ctx
= (struct dump_record_ctx
*)dump_record_ctx
;
363 fprintf(ctx
->file
, "{\nkey(%d) = ", (int)key
.dsize
);
364 ctx
->print_data(ctx
->file
, key
);
365 fputc('\n', ctx
->file
);
366 ctx
->dump_header(ctx
, hdr
);
367 fprintf(ctx
->file
, "data(%d) = ", (int)val
.dsize
);
368 ctx
->print_data(ctx
->file
, val
);
369 fprintf(ctx
->file
, "\n}\n");
373 static void dump_header_full(struct dump_record_ctx
* c
,
374 struct ctdb_ltdb_header
* h
)
376 fprintf(c
->file
, "dmaster: %d\nrsn: %llu\nflags: 0x%X\n",
378 (unsigned long long)h
->rsn
, h
->flags
);
381 static void print_data_tdbdump(FILE* file
, TDB_DATA data
)
383 unsigned char *ptr
= data
.dptr
;
385 while (data
.dsize
--) {
386 if (isprint(*ptr
) && !strchr("\"\\", *ptr
)) {
389 fprintf(file
, "\\%02X", *ptr
);