[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#537535: Offer for help, first patch



Hi Joey,

Sorry for the delay. Don't worry, I'm not going to disappear after
offering help, there's just a lot going on real-life wise.

On Sat, 2011-04-16 at 19:40 -0400, Joey Hess wrote:
> Regis Boudin wrote:
> > Last question, how would you like me to provide patche(s) ? Is one for
> > each utility ok ?
> 
> If you're going to have a lot of patches, it would probably make sense
> to keep them in git.

As I explained to Christian in private, I'd rather keep my git stuff
"private" for now. It's my first proper attempt at using git and I've
already managed to break things a couple of times on my attempt at
setting up and using my public repository. Once I know better what I can
and can't do, I'll be more than happy to use the official one.

In the meantime I'd like to submit the attached patch. It implements
debconf-escape, debconf-get-selections, and debconf-show. I've done a
fair bit of testing with them, and they seem to give output similar to
their perl versions.
I'd really like to see the patch merged, or get feedback on the changes
needed for it to be merged.

I still need to do more tests on the escape CAPB and get
-set-selections, but hopefully we'll be able to close this bug soon. :)

Regi
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;
+}

Reply to: