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/>.
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 */
34 #include <unistd.h> /* getopt */
37 #include "ctdb_protocol.h"
41 OUT_MODE
= S_IRUSR
| S_IWUSR
,
42 OUT_FLAGS
= O_EXCL
|O_CREAT
|O_RDWR
,
46 struct ctdb_ltdb_header hdr
;
47 uint32_t uints
[MAX_HEADER_SIZE
/4];
50 static const union ltdb_header DEFAULT_HDR
= {
54 static int help(const char* cmd
)
57 "Usage: %s [options] <command>\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"
67 " -S <num> the number of bytes to interpret as ctdb record header\n"
68 " for the input database (beware!)\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"
77 " -O <num> the number of bytes to interpret as ctdb record header\n"
78 " for the output database (beware!)\n"
80 " -e Include empty records, defaults to off\n"
82 " -p print header (for the dump command), defaults to off\n"
84 " -h print this help\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
);
93 static int usage(const char* cmd
)
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"
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
{
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
{
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
,
139 TDB_CONTEXT
* idb
= tdb_open(iname
, 0, TDB_DEFAULT
, O_RDONLY
, 0);
141 perror("tdbopen in");
143 struct dump_record_ctx dump_ctx
= {
145 .print_data
= &print_data_tdbdump
,
146 .dump_header
= dump_header
? &dump_header_full
149 ret
= ltdb_traverse(idb
, &dump_record
, &dump_ctx
, hsize
, !empty
);
155 static int conv_db(const char* iname
, const char* oname
, size_t isize
,
156 size_t osize
, bool keep_empty
)
159 TDB_CONTEXT
* idb
= tdb_open(iname
, 0, TDB_DEFAULT
, O_RDONLY
, 0);
161 perror("tdbopen in");
163 TDB_CONTEXT
* odb
= tdb_open(oname
, 0, TDB_DEFAULT
, OUT_FLAGS
, OUT_MODE
);
165 perror("tdbopen out");
167 struct write_record_ctx ctx
= {
170 .tdb_store_flags
= TDB_REPLACE
,
172 ret
= ltdb_traverse(idb
, &write_record
, &ctx
, isize
, !keep_empty
);
180 static bool parse_size(size_t* size
, const char* arg
, bool raw
) {
183 val
= strtol(arg
, (char **) NULL
, 10);
201 *size
= MIN(val
, MAX_HEADER_SIZE
);
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;
213 const char *cmd
, *idb
, *odb
;
215 while ((opt
= getopt(argc
, argv
, "s:o:S:O:phe")) != -1) {
219 if (!parse_size(&isize
, optarg
, isupper(opt
))) {
220 return usage(argv
[0]);
225 if (!parse_size(&osize
, optarg
, isupper(opt
))) {
226 return usage(argv
[0]);
236 return help(argv
[0]);
238 return usage(argv
[0]);
242 if (argc
- optind
< 1) {
243 return usage(argv
[0]);
248 if (strcmp(cmd
, "help") == 0) {
249 return help(argv
[0]);
251 else if (strcmp(cmd
, "dump") == 0) {
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) {
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 *);
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
);
299 if (val
.dsize
== hsize
&& ctx
->skip_empty
) {
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
= {
321 .hsize
= hsize
< 0 ? sizeof(struct ctdb_ltdb_header
) : hsize
,
322 .skip_empty
= skip_empty
,
325 int ret
= tdb_traverse(tdb
, <db_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
));
347 if(tdb_store(ctx
->tdb
, key
, h
, ctx
->tdb_store_flags
) == -1) {
348 fprintf(stderr
, "tdb_store: %s\n", tdb_errorstr(ctx
->tdb
));
351 if(tdb_append(ctx
->tdb
, key
, val
) == -1) {
352 fprintf(stderr
, "tdb_append: %s\n", tdb_errorstr(ctx
->tdb
));
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");
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",
379 (unsigned long long)h
->rsn
, h
->flags
);
382 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
);