diff --git a/debian/cdebconf.install b/debian/cdebconf.install
index aa3b8a5..e48461b 100644
--- a/debian/cdebconf.install
+++ b/debian/cdebconf.install
@@ -4,7 +4,10 @@ deb/usr/lib/cdebconf/debconf usr/lib/cdebconf
 deb/usr/lib/cdebconf/debconf-communicate usr/lib/cdebconf
 deb/usr/lib/cdebconf/debconf-copydb usr/lib/cdebconf
 deb/usr/lib/cdebconf/debconf-dumpdb usr/lib/cdebconf
+deb/usr/lib/cdebconf/debconf-escape usr/lib/cdebconf
+deb/usr/lib/cdebconf/debconf-get-selections usr/lib/cdebconf
 deb/usr/lib/cdebconf/debconf-loadtemplate usr/lib/cdebconf
+deb/usr/lib/cdebconf/debconf-show usr/lib/cdebconf
 deb/usr/lib/cdebconf/dpkg-reconfigure usr/lib/cdebconf
 deb/usr/lib/cdebconf/frontend/passthrough.so usr/lib/cdebconf/frontend
 deb/usr/lib/cdebconf/frontend/newt.so usr/lib/cdebconf/frontend
diff --git a/src/.gitignore b/src/.gitignore
index 4bb4aea..71f9df8 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -7,7 +7,10 @@ debconf
 debconf-communicate
 debconf-copydb
 debconf-dumpdb
+debconf-escape
+debconf-get-selections
 debconf-loadtemplate
+debconf-show
 dpkg-reconfigure
 debconf.conf
 cdebconf.conf-dist
diff --git a/src/Makefile.in b/src/Makefile.in
index e97bbfb..1273039 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -13,8 +13,9 @@ CLILIBNAME=$(CLILIB).$(MAJOR).$(MINOR).$(MICRO)
 CLISONAME=$(CLILIB).$(MAJOR)
 DEBCONF=debconf
 TOOLS=debconf-loadtemplate debconf-copydb debconf-communicate \
-	debconf-dumpdb \
-	dpkg-reconfigure #dpkg-preconfigure
+	debconf-dumpdb debconf-escape \
+	debconf-get-selections \
+	dpkg-reconfigure debconf-show #dpkg-preconfigure
 BIN=$(DEBCONF) $(TOOLS)
 
 LIBOBJS=commands.opic configuration.opic confmodule.opic debug.opic \
@@ -65,6 +66,9 @@ install:
 	install -m 755 debconf-copydb debconf-dumpdb $(DESTDIR)${moddir}
 ifneq ($(TARGET),udeb)
 	install -m 755 debconf-communicate $(DESTDIR)${moddir}
+	install -m 755 debconf-escape $(DESTDIR)${moddir}
+	install -m 755 debconf-get-selections $(DESTDIR)${moddir}
+	install -m 755 debconf-show $(DESTDIR)${moddir}
 	install -m 755 dpkg-reconfigure $(DESTDIR)${moddir}
 endif
 	install -m 644 $(LIBNAME) $(DESTDIR)${moddir}
diff --git a/src/cdebconf.conf-dist.in b/src/cdebconf.conf-dist.in
index 369be94..6036d04 100644
--- a/src/cdebconf.conf-dist.in
+++ b/src/cdebconf.conf-dist.in
@@ -31,6 +31,11 @@ template {
     driver "rfc822db";
     path "/target/var/cache/debconf/templates.dat";
   };
+
+  instance "di_templatedb" {
+    driver "rfc822db";
+    path "/var/log/installer/cdebconf/templates.dat";
+  };
 };
 
 config {
@@ -68,5 +73,11 @@ config {
     stack { "target_config_gen_db"; "target_config_passwd_db"; };
     template "target_templatedb";
   };
+
+  instance "di_configdb" {
+    driver "rfc822db";
+    path "/var/log/installer/cdebconf/questions.dat";
+    template "di_templatedb";
+  };
 };
 
diff --git a/src/debconf-escape.c b/src/debconf-escape.c
new file mode 100644
index 0000000..bc83758
--- /dev/null
+++ b/src/debconf-escape.c
@@ -0,0 +1,126 @@
+/**
+ * @file debconf-escape.c
+ * @brief helper when working with debconf's escape capability
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <getopt.h>
+
+static int escape = 0;
+static int unescape = 0;
+
+static struct option options[] = {
+    { "help", 0, 0, 'h' },
+    { "escape", 0, 0, 'e' },
+    { "unescape", 0, 0, 'u' },
+    { 0, 0, 0, 0 },
+};
+
+static void help(FILE *f, const char *exename)
+{
+    fprintf(f, "Usage: %s -e|-u < input-text\n", exename);
+    fputs("  -e, --escape      escape text\n"
+        "  -u, --unescape    unescape text\n"
+        "\n"
+        "Exactly one of -e or -u must be used.\n", f);
+}
+
+static void parsecmdline(int argc, char **argv)
+{
+    int c;
+
+    while ((c = getopt_long(argc, argv, "euh", options, NULL)) >= 0)
+    {
+        switch (c)
+        {
+            case 'h':
+                help(stdout, argv[0]);
+                exit(0);
+                break;
+            case 'e':
+                escape = 1;
+                break;
+            case 'u':
+                unescape = 1;
+                break;
+            default:
+                break;
+        }
+    }
+
+    if (optind > argc || escape == unescape)
+    {
+        help(stderr, argv[0]);
+        exit(1);
+    }
+}
+
+int main(int argc, char **argv)
+{
+    char buf[1024];
+    const char *p;
+    size_t r;
+
+    parsecmdline(argc, argv);
+
+    if (escape)
+    {
+        while (!feof(stdin) && !ferror(stdin))
+        {
+            r = fread(buf, sizeof(*buf), 1024, stdin);
+            for (p = buf; p < buf + r; ++p)
+            {
+                switch (*p)
+                {
+                    case '\\':
+                        fputs("\\\\", stdout);
+                        break;
+                    case '\n':
+                        fputs("\\n", stdout);
+                        break;
+                    default:
+                        fputc(*p, stdout);
+                        break;
+                }
+            }
+        }
+    }
+    else
+    {
+        int unesc = 0;
+        while (!feof(stdin) && !ferror(stdin))
+        {
+            r = fread(buf, sizeof(*buf), 1024, stdin);
+            for (p = buf; p < buf + r; ++p)
+            {
+                if (unesc)
+                {
+                    switch (*p)
+                    {
+                        case 'n':
+                            fputc('\n', stdout);
+                            break;
+                        default:
+                            fputc(*p, stdout);
+                            break;
+                    }
+                    unesc = 0;
+                }
+                else if (*p == '\\')
+                    unesc = 1;
+                else
+                    fputc(*p, stdout);
+            }
+        }
+    }
+
+    if (ferror(stdin))
+    {
+        fprintf(stderr, "%s: error reading stdin\n", argv[0]);
+        return 1;
+    }
+
+    return 0;
+}
diff --git a/src/debconf-get-selections.c b/src/debconf-get-selections.c
new file mode 100644
index 0000000..5e8a985
--- /dev/null
+++ b/src/debconf-get-selections.c
@@ -0,0 +1,112 @@
+/**
+ * @file debconf-get-selections.c
+ * @brief Output contents of debconf database
+ *
+ */
+
+#include "common.h"
+#include "configuration.h"
+#include "database.h"
+#include "question.h"
+#include "template.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <locale.h>
+#include <string.h>
+
+static int installer = 0;
+static struct option options[] = {
+    { "installer", 0, &installer, 'i' },
+    { 0, 0, 0, 0 }
+};
+
+static const char *defaultowner = "unknown";
+
+static void parsecmd(int argc, char **argv)
+{
+    int c;
+
+    while ((c = getopt_long(argc, argv, "", options, NULL)) > 0)
+    {
+        switch (c)
+        {
+            case 'i':
+                defaultowner = "d-i";
+                break;
+            default:
+                break;
+        }
+    }
+}
+
+int main(int argc, char **argv)
+{
+    struct configuration *config;
+    struct template_db *tdb;
+    struct question_db *qdb;
+    struct question *q;
+    void *iter;
+
+    parsecmd(argc, argv);
+    
+    setlocale(LC_ALL, "");
+
+    config = config_new();
+
+    /* parse the configuration info */
+    if (config->read(config, DEBCONFCONFIG) == 0)
+        DIE("Error reading configuration information");
+
+    /* initialize database modules */
+    if ((tdb = template_db_new(config, installer?"di_templatedb":NULL)) == 0)
+        DIE("Cannot initialize DebConf template database");
+    if ((qdb = question_db_new(config, tdb, installer?"di_configdb":NULL)) == 0)
+        DIE("Cannot initialize DebConf config database");
+
+    /* load database */
+    tdb->methods.load(tdb);
+    qdb->methods.load(qdb);
+
+    iter = 0;
+    while ((q = qdb->methods.iterate(qdb, &iter)) != NULL)
+    {
+        struct questionowner *owner = q->owners;
+        const char *type = template_lget(q->template, NULL, "type");
+
+        if ((type == NULL) ||
+            (strcmp(type, "title") == 0) ||
+            (strcmp(type, "text") == 0))
+            continue;
+
+	    printf("# %s\n", q_get_description(0, q));
+        if ((strcmp(type, "select") == 0) ||
+            (strcmp(type, "multiselect") == 0))
+            printf("# Choices: %s\n", q_get_choices(0, q));
+
+        if (!owner)
+        {
+            printf("%s\t%s\t%s\t%s\n", defaultowner, q->tag,
+                type, q->value?q->value:"");
+        }
+        else
+        {
+            while (owner)
+            {
+                printf("%s\t%s\t%s\t%s\n", owner->owner, q->tag,
+                    type, q->value?q->value:"");
+                owner = owner->next;
+            }
+        }
+        question_deref(q);
+    }
+
+    template_db_delete(tdb);
+    question_db_delete(qdb);
+
+    config_delete(config);
+
+    return 0;
+}
+
diff --git a/src/debconf-show.c b/src/debconf-show.c
new file mode 100644
index 0000000..db85dbb
--- /dev/null
+++ b/src/debconf-show.c
@@ -0,0 +1,183 @@
+
+#include "common.h"
+#include "configuration.h"
+#include "database.h"
+#include "question.h"
+#include "template.h"
+
+#include <getopt.h>
+#include <locale.h>
+#include <string.h>
+
+int listowners = 0;
+int listdbs = 0;
+static struct option options[] = {
+    { "db", 1, NULL, 'd' },
+    { "listowners", 0, &listowners, 'o' },
+    { "listdbs", 0, &listdbs, 'l' },
+    { 0, 0, 0, 0 }
+};
+
+static void usage(const char *exename)
+{
+    printf("Usage:\n");
+    printf("\t%s packagename [...] [--db=dbname]\n", exename);
+    printf("\t%s --listowners [--db=dbname]\n", exename);
+    printf("\t%s --listdbs\n", exename);
+    exit(0);
+}
+
+int main(int argc, char **argv)
+{
+	struct configuration *config = config_new();
+	struct template_db *tdb;
+	struct question_db *qdb;
+	struct question *q;
+	void *iter = 0;
+	const char *tdbname = NULL;
+
+    int c;
+	const char *dbname = NULL;
+	struct questionowner *owners = NULL;
+
+    setlocale(LC_ALL, "");
+
+    while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0)
+    {
+        switch (c)
+        {
+            case 'd':
+				dbname = optarg;
+                break;
+            default:
+                break;
+        }
+    }
+
+	config = config_new();
+
+	if (config->read(config, DEBCONFCONFIG) == 0)
+		DIE("Error reading configuration information");
+
+	if (listdbs)
+	{
+		struct configitem *instance, *item;
+
+		instance = config->tree(config,"config::instance");
+		if (instance)
+		{
+			for (item=instance->child; item != NULL; item = item->next)
+			{
+				printf("%s %s\n", item->tag, item->value);
+			}
+		}
+		
+		config_delete(config);
+		
+		return 0;
+	}
+	
+	if (dbname)
+	{
+		/* find out which template databases to load; fall back to global
+		 * default if not configured otherwise
+		 */
+	    char *configpath;
+		if (asprintf(&configpath, "config::instance::%s::template", dbname) == -1)
+		    DIE("Out of memory");
+		tdbname = config->get(config, configpath, NULL);
+		free(configpath);
+	}
+
+	/* initialize database modules */
+	if ((tdb = template_db_new(config, tdbname)) == 0)
+		DIE("Cannot initialize debconf template database");
+	if ((qdb = question_db_new(config, tdb, dbname)) == 0)
+		DIE("Cannot initialize debconf database");
+
+	tdb->methods.load(tdb);
+	qdb->methods.load(qdb);
+
+	if (listowners)
+	{
+		while((q = qdb->methods.iterate(qdb, &iter)) != NULL)
+		{
+			struct questionowner *owner = q->owners;
+
+			while (owner)
+			{
+				struct questionowner *o = owners;
+				while (o != NULL)
+				{
+					if (0 == strcmp(o->owner, owner->owner))
+						break;
+					o = o->next;
+				}
+				if (o == NULL)
+				{
+					o = malloc(sizeof(struct questionowner));
+					o->next = owners;
+					o->owner = owner->owner;
+					owners = o;
+					fprintf(stdout, "%s\n", owner->owner);
+				}
+				owner = owner->next;
+			}
+		}
+	}
+	else
+	{
+		for (c = optind; c < argc; c++)
+		{
+			struct questionowner *o = malloc(sizeof(struct questionowner));
+			o->next = owners;
+			o->owner = argv[c];
+			owners = o;
+		}
+
+		if (!owners)
+		{
+			usage(argv[0]);
+		}
+
+		while((q = qdb->methods.iterate(qdb, &iter)) != NULL)
+		{
+			const char seen = (q->flags & DC_QFLAG_SEEN)?'*':' ';
+			const char *type = q->template->type?q->template->type:"";
+			const char *value = strcmp("password", type)?q->value:"(password omitted)";
+
+			const struct questionowner *owner = q->owners;
+			while (owner)
+			{
+				const struct questionowner *o = owners;
+				while (o != NULL)
+				{
+					if (0 == strcmp(o->owner, owner->owner))
+					{
+						fprintf(stdout, "%c %s:", seen, q->tag);
+						if (value)
+							fprintf(stdout, " %s", value);
+						fputc('\n', stdout);
+						break;
+					}
+					o = o->next;
+				}
+				owner = owner->next;
+			}
+		}
+	}
+
+	while (owners)
+	{
+		struct questionowner *o = owners;
+		owners = o->next;
+		free(o);
+	}
+
+	question_db_delete(qdb);
+	template_db_delete(tdb);
+
+	config_delete(config);
+
+	return 0;
+}
