pytest:security descriptors: hack to capture results as json
[Samba.git] / ctdb / tools / ltdbtool.c
blob98a1b5167510bc876b3dfdc35921ee15dd72aac8
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 "replace.h"
22 #include "system/filesys.h"
23 #include "system/network.h"
24 #include "system/locale.h"
26 #include <tdb.h>
28 #include "protocol/protocol.h"
30 enum {
31 MAX_HEADER_SIZE=24,
32 OUT_MODE = S_IRUSR | S_IWUSR,
33 OUT_FLAGS = O_EXCL|O_CREAT|O_RDWR,
36 union ltdb_header {
37 struct ctdb_ltdb_header hdr;
38 uint32_t uints[MAX_HEADER_SIZE/4];
41 static const union ltdb_header DEFAULT_HDR = {
42 .hdr = {
43 .dmaster = -1,
47 static int help(const char* cmd)
49 fprintf(stdout, ""
50 "Usage: %s [options] <command>\n"
51 "\n"
52 "Options:\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"
59 "\n"
60 " -S <num> the number of bytes to interpret as ctdb record header\n"
61 " for the input database (beware!)\n"
62 "\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"
69 "\n"
70 " -O <num> the number of bytes to interpret as ctdb record header\n"
71 " for the output database (beware!)\n"
72 "\n"
73 " -e Include empty records, defaults to off\n"
74 "\n"
75 " -p print header (for the dump command), defaults to off\n"
76 "\n"
77 " -h print this help\n"
78 "\n"
79 "Commands:\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);
83 return 0;
86 static int usage(const char* cmd)
88 fprintf(stderr,
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"
91 " %s {help|-h}\n"
92 , cmd, cmd, cmd);
93 return -1;
96 static int
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 {
102 TDB_CONTEXT* tdb;
103 size_t hsize;
104 int tdb_store_flags;
107 static int
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 {
114 FILE* file;
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,
129 FILE* ofile,
130 size_t hsize,
131 bool dump_header,
132 bool empty)
134 int ret = -1;
135 TDB_CONTEXT* idb = tdb_open(iname, 0, TDB_DEFAULT, O_RDONLY, 0);
136 if (!idb) {
137 perror("tdbopen in");
138 } else {
139 struct dump_record_ctx dump_ctx = {
140 .file = ofile,
141 .print_data = &print_data_tdbdump,
142 .dump_header = dump_header ? &dump_header_full
143 : &dump_header_nop,
145 ret = ltdb_traverse(idb, &dump_record, &dump_ctx, hsize, !empty);
146 tdb_close(idb);
148 return ret;
151 static int conv_db(const char* iname, const char* oname, size_t isize,
152 size_t osize, bool keep_empty)
154 int ret = -1;
155 TDB_CONTEXT* idb = tdb_open(iname, 0, TDB_DEFAULT, O_RDONLY, 0);
156 if (!idb) {
157 perror("tdbopen in");
158 } else {
159 TDB_CONTEXT* odb = tdb_open(oname, 0, TDB_DEFAULT, OUT_FLAGS, OUT_MODE);
160 if (!odb) {
161 perror("tdbopen out");
162 } else {
163 struct write_record_ctx ctx = {
164 .tdb = odb,
165 .hsize = osize,
166 .tdb_store_flags = TDB_REPLACE,
168 ret = ltdb_traverse(idb, &write_record, &ctx, isize, !keep_empty);
169 tdb_close(odb);
171 tdb_close(idb);
173 return ret;
176 static bool parse_size(size_t* size, const char* arg, bool raw) {
177 long val;
178 errno = 0;
179 val = strtol(arg, (char **) NULL, 10);
180 if (errno != 0) {
181 return false;
183 if (!raw) {
184 switch(val) {
185 case 0:
186 break;
187 case 32:
188 val = 20;
189 break;
190 case 64:
191 val = 24;
192 break;
193 default:
194 return false;
197 *size = MIN(val, MAX_HEADER_SIZE);
198 return true;
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;
208 int opt;
209 const char *cmd, *idb, *odb;
211 while ((opt = getopt(argc, argv, "s:o:S:O:phe")) != -1) {
212 switch (opt) {
213 case 's':
214 case 'S':
215 if (!parse_size(&isize, optarg, isupper(opt))) {
216 return usage(argv[0]);
218 break;
219 case 'o':
220 case 'O':
221 if (!parse_size(&osize, optarg, isupper(opt))) {
222 return usage(argv[0]);
224 break;
225 case 'p':
226 print_header = true;
227 break;
228 case 'e':
229 keep_empty = true;
230 break;
231 case 'h':
232 return help(argv[0]);
233 default:
234 return usage(argv[0]);
238 if (argc - optind < 1) {
239 return usage(argv[0]);
242 cmd = argv[optind];
244 if (strcmp(cmd, "help") == 0) {
245 return help(argv[0]);
247 else if (strcmp(cmd, "dump") == 0) {
248 int ret;
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) {
257 int ret;
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 *);
272 void* state;
273 size_t hsize;
274 bool skip_empty;
275 int nempty;
278 static int
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);
292 fputc('\n', stderr);
293 return -1;
295 if (val.dsize == hsize && ctx->skip_empty) {
296 ctx->nempty++;
297 return 0;
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 = {
316 .fn = fn,
317 .state = state,
318 .hsize = hsize,
319 .skip_empty = skip_empty,
320 .nempty = 0,
322 int ret = tdb_traverse(tdb, &ltdb_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;
333 int ret;
335 if (ctx->hsize == 0) {
336 ret = tdb_store(ctx->tdb, key, val, ctx->tdb_store_flags);
337 } else {
338 TDB_DATA rec[2];
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);
349 if (ret == -1) {
350 fprintf(stderr, "tdb_store: %s\n", tdb_errorstr(ctx->tdb));
351 return -1;
354 return 0;
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");
370 return 0;
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",
377 (int)h->dmaster,
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;
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);