From a71ad96bd046f1199e67b4fe8fc7783cbd8dd771 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 30 Oct 2012 15:41:27 +1100 Subject: [PATCH] ldb: Add ldbdump, based on tdbdump This uses a tdb_traverse or (more usefully) the tdb_rescue API, like tdbdump. The difference here is that it uses ldb helper functions to further eliminate faulty records, which avoids creating duplicates in the output. (The duplicates come from parts of records that are left in blank space in the db, which tdb_rescue finds, but which are not actually a full record). Andrew Bartlett Autobuild-User(master): Andrew Bartlett Autobuild-Date(master): Tue Oct 30 23:56:11 CET 2012 on sn-devel-104 --- lib/ldb/tools/ldbdump.c | 219 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/ldb/wscript | 4 + 2 files changed, 223 insertions(+) create mode 100644 lib/ldb/tools/ldbdump.c diff --git a/lib/ldb/tools/ldbdump.c b/lib/ldb/tools/ldbdump.c new file mode 100644 index 00000000000..7a2ba3d385b --- /dev/null +++ b/lib/ldb/tools/ldbdump.c @@ -0,0 +1,219 @@ +/* + Unix SMB/CIFS implementation. + simple ldb tdb dump util + Copyright (C) Andrew Tridgell 2001 + Copyright (C) Andrew Bartlett 2012 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "replace.h" +#include "system/locale.h" +#include "system/time.h" +#include "system/filesys.h" +#include "system/wait.h" +#include +#include +#include "../ldb_tdb/ldb_tdb.h" + +static struct ldb_context *ldb; +bool show_index = false; +bool validate_contents = false; + +static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state) +{ + int ret, i, j; + struct ldb_dn *dn = state; + struct ldb_message *msg = talloc_zero(NULL, struct ldb_message); + struct ldb_ldif ldif = { + .msg = msg, + .changetype = LDB_CHANGETYPE_NONE + }; + if (!msg) { + return -1; + } + ret = ltdb_unpack_data(ldb, &dbuf, msg); + if (ret != 0) { + fprintf(stderr, "Failed to parse record %*.*s as an LDB record\n", (int)key.dsize, (int)key.dsize, (char *)key.dptr); + TALLOC_FREE(msg); + return 0; + } + + if (dn && ldb_dn_compare(msg->dn, dn) != 0) { + TALLOC_FREE(msg); + return 0; + } + + if (!show_index && ldb_dn_is_special(msg->dn)) { + const char *dn_lin = ldb_dn_get_linearized(msg->dn); + if ((strcmp(dn_lin, LTDB_BASEINFO) == 0) || (strncmp(dn_lin, LTDB_INDEX ":", strlen( LTDB_INDEX ":")) == 0)) { + TALLOC_FREE(msg); + return 0; + } + } + + if (!validate_contents || ldb_dn_is_special(msg->dn)) { + ldb_ldif_write_file(ldb, stdout, &ldif); + TALLOC_FREE(msg); + return 0; + } + + for (i=0;inum_elements;i++) { + const struct ldb_schema_attribute *a; + + a = ldb_schema_attribute_by_name(ldb, msg->elements[i].name); + for (j=0;jelements[i].num_values;j++) { + struct ldb_val v; + ret = a->syntax->ldif_write_fn(ldb, msg, &msg->elements[i].values[j], &v); + if (ret != 0) { + v = msg->elements[i].values[j]; + if (ldb_should_b64_encode(ldb, &v)) { + v.data = (uint8_t *)ldb_base64_encode(ldb, (char *)v.data, v.length); + v.length = strlen((char *)v.data); + } + fprintf(stderr, "On %s element %s value %d (%*.*s) failed to convert to LDIF correctly, skipping possibly corrupt record\n", + ldb_dn_get_linearized(msg->dn), + msg->elements[i].name, + j, (int)v.length, (int)v.length, + v.data); + TALLOC_FREE(msg); + return 0; + } + } + } + ldb_ldif_write_file(ldb, stdout, &ldif); + TALLOC_FREE(msg); + + return 0; +} + +static void log_stderr(struct tdb_context *tdb, enum tdb_debug_level level, + const char *fmt, ...) +{ + va_list ap; + const char *name = tdb_name(tdb); + const char *prefix = ""; + + if (!name) + name = "unnamed"; + + switch (level) { + case TDB_DEBUG_ERROR: + prefix = "ERROR: "; + break; + case TDB_DEBUG_WARNING: + prefix = "WARNING: "; + break; + case TDB_DEBUG_TRACE: + return; + + default: + case TDB_DEBUG_FATAL: + prefix = "FATAL: "; + break; + } + + va_start(ap, fmt); + fprintf(stderr, "tdb(%s): %s", name, prefix); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + +static void emergency_walk(TDB_DATA key, TDB_DATA dbuf, void *keyname) +{ + traverse_fn(NULL, key, dbuf, keyname); +} + +static int dump_tdb(const char *fname, struct ldb_dn *dn, bool emergency) +{ + TDB_CONTEXT *tdb; + struct tdb_logging_context logfn = { log_stderr }; + + tdb = tdb_open_ex(fname, 0, 0, O_RDONLY, 0, &logfn, NULL); + if (!tdb) { + fprintf(stderr, "Failed to open %s\n", fname); + return 1; + } + + if (emergency) { + return tdb_rescue(tdb, emergency_walk, dn) == 0; + } + return tdb_traverse(tdb, traverse_fn, dn) == -1 ? 1 : 0; +} + +static void usage( void) +{ + printf( "Usage: tdbdump [options] \n\n"); + printf( " -h this help message\n"); + printf( " -d DN dumps DN only\n"); + printf( " -e emergency dump, for corrupt databases\n"); + printf( " -i include index and @BASEINFO records in dump\n"); + printf( " -c validate contents of the records\n"); +} + + int main(int argc, char *argv[]) +{ + bool emergency = false; + int c, rc; + char *fname; + struct ldb_dn *dn = NULL; + + ldb = ldb_init(NULL, NULL); + if (ldb == NULL) { + fprintf(stderr, "ldb: ldb_init failed()"); + exit(1); + } + + rc = ldb_modules_hook(ldb, LDB_MODULE_HOOK_CMDLINE_PRECONNECT); + if (rc != LDB_SUCCESS) { + fprintf(stderr, "ldb: failed to run preconnect hooks (needed to get Samba LDIF handlers): %s\n", ldb_strerror(rc)); + exit(1); + } + + if (argc < 2) { + printf("Usage: ldbdump \n"); + exit(1); + } + + while ((c = getopt( argc, argv, "hd:ec")) != -1) { + switch (c) { + case 'h': + usage(); + exit( 0); + case 'd': + dn = ldb_dn_new(ldb, ldb, optarg); + if (!dn) { + fprintf(stderr, "ldb failed to parse %s as a DN\n", optarg); + exit(1); + } + break; + case 'e': + emergency = true; + break; + case 'i': + show_index = true; + break; + case 'c': + validate_contents = true; + break; + default: + usage(); + exit( 1); + } + } + + fname = argv[optind]; + + return dump_tdb(fname, dn, emergency); +} diff --git a/lib/ldb/wscript b/lib/ldb/wscript index 566c05eac61..66fa24ba583 100755 --- a/lib/ldb/wscript +++ b/lib/ldb/wscript @@ -253,6 +253,10 @@ def build(bld): bld.SAMBA_BINARY('ldbtest', 'tools/ldbtest.c', deps='ldb-cmdline ldb', install=False) + # ldbdump doesn't get installed + bld.SAMBA_BINARY('ldbdump', 'tools/ldbdump.c ldb_tdb/ldb_pack.c', deps='ldb-cmdline ldb', + install=False) + bld.SAMBA_LIBRARY('ldb-cmdline', source='tools/ldbutil.c tools/cmdline.c', deps='ldb dl popt', -- 2.11.4.GIT