summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2012-10-30 15:41:27 +1100
committerAndrew Bartlett <abartlet@samba.org>2012-10-30 23:56:11 +0100
commita71ad96bd046f1199e67b4fe8fc7783cbd8dd771 (patch)
tree566b6530d3c98b32486c8a874929c002ea857796
parent4b2f3c6dec997b0dd4bcafeae662a71ebd34e12b (diff)
downloadsamba-a71ad96bd046f1199e67b4fe8fc7783cbd8dd771.tar.gz
samba-a71ad96bd046f1199e67b4fe8fc7783cbd8dd771.tar.bz2
samba-a71ad96bd046f1199e67b4fe8fc7783cbd8dd771.zip
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 <abartlet@samba.org> Autobuild-Date(master): Tue Oct 30 23:56:11 CET 2012 on sn-devel-104
-rw-r--r--lib/ldb/tools/ldbdump.c219
-rwxr-xr-xlib/ldb/wscript4
2 files changed, 223 insertions, 0 deletions
diff --git a/lib/ldb/tools/ldbdump.c b/lib/ldb/tools/ldbdump.c
new file mode 100644
index 0000000000..7a2ba3d385
--- /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 <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "system/locale.h"
+#include "system/time.h"
+#include "system/filesys.h"
+#include "system/wait.h"
+#include <tdb.h>
+#include <ldb.h>
+#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;i<msg->num_elements;i++) {
+ const struct ldb_schema_attribute *a;
+
+ a = ldb_schema_attribute_by_name(ldb, msg->elements[i].name);
+ for (j=0;j<msg->elements[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] <filename>\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 <fname>\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 566c05eac6..66fa24ba58 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',