Bug#537535: debconf-set-selections patch
Hi folks,
I haven't disappeared yet, still working on cdebconf, and should
hopefully have more time to hack on it in a couple of days. Here is a
patch implementing debconf-set-slections.
flag_value() should probably be moved somewhere more reusable like
question.c, as it is exactly the same logic as what I did in rfc822db.c
for #625317, and sounds like something that could be useful in general.
I also have a patch for the escape CAPB, though the results I get with
my tests look a bit odd, so any input with an actual example, or a patch
to test.config, so I could compare the result with the original debconf
would be very useful.
As before, any feedback or comment would be very welcome.
Regis
diff --git a/debian/cdebconf.install b/debian/cdebconf.install
index e48461b..658613e 100644
--- a/debian/cdebconf.install
+++ b/debian/cdebconf.install
@@ -7,6 +7,7 @@ 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-set-selections 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
diff --git a/debian/changelog b/debian/changelog
index 2b3cfc8..2b89ed6 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,8 +1,9 @@
cdebconf (0.156) UNRELEASED; urgency=low
[ Regis Boudin ]
- * Add cdebconf versions of debconf-escape, debconf-get-selections, and
- debconf-show. (Initial debconf-escape code by Colin Watson.)
+ * Add cdebconf versions of debconf-escape, debconf-get-selections,
+ debconf-set-selections, and debconf-show. (Initial debconf-escape code by
+ Colin Watson.)
* Fix FTBFS with the future GCC 4.6.1 (Closes: #625317).
* Implement handling of multiple flags in the rfc822db backend.
diff --git a/src/.gitignore b/src/.gitignore
index 71f9df8..dd96885 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -10,6 +10,7 @@ debconf-dumpdb
debconf-escape
debconf-get-selections
debconf-loadtemplate
+debconf-set-selections
debconf-show
dpkg-reconfigure
debconf.conf
diff --git a/src/Makefile.in b/src/Makefile.in
index 1273039..4be1c28 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -14,7 +14,7 @@ CLISONAME=$(CLILIB).$(MAJOR)
DEBCONF=debconf
TOOLS=debconf-loadtemplate debconf-copydb debconf-communicate \
debconf-dumpdb debconf-escape \
- debconf-get-selections \
+ debconf-get-selections debconf-set-selections \
dpkg-reconfigure debconf-show #dpkg-preconfigure
BIN=$(DEBCONF) $(TOOLS)
@@ -68,6 +68,7 @@ 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-set-selections $(DESTDIR)${moddir}
install -m 755 debconf-show $(DESTDIR)${moddir}
install -m 755 dpkg-reconfigure $(DESTDIR)${moddir}
endif
diff --git a/src/debconf-set-selections.c b/src/debconf-set-selections.c
new file mode 100644
index 0000000..f50a95b
--- /dev/null
+++ b/src/debconf-set-selections.c
@@ -0,0 +1,311 @@
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <locale.h>
+#include <string.h>
+
+#include "common.h"
+#include "configuration.h"
+#include "database.h"
+#include "question.h"
+#include "template.h"
+
+static int debug = 0;
+static int checkonly = 0;
+static int unseen = 0;
+
+static struct option params[] = {
+ { "help", 0, NULL, 'h' },
+ { "verbose", 0, &debug, 'v' },
+ { "checkonly", 0, &checkonly, 'c' },
+ { "unseen", 0, &unseen, 'u' },
+ { 0, 0, 0, 0 }
+};
+
+static const struct {
+ const char *name;
+ unsigned int value;
+} flags[] = {
+ { "seen", DC_QFLAG_SEEN },
+ { 0, 0 }
+};
+
+static const char * known_types[] = {
+ "select",
+ "boolean",
+ "string",
+ "multiselect",
+ "note",
+ "password",
+ "text",
+ "title",
+ NULL
+};
+
+static void usage(const char *exename)
+{
+ printf("%s [-vcu] [file]\n", exename);
+ puts("\t-v, --verbose verbose output\n"
+ "\t-c, --checkonly only check the input file format\n"
+ "\t-u, --unseen do not set the 'seen' flag when preseeding values\n");
+ exit(0);
+}
+
+static void load_answer(const char *owner, const char *label, const char * type,
+ const char *content, struct question_db *qdb, struct template_db *tdb)
+{
+ if (debug)
+ fprintf(stderr, "info: Loading answer for '%s'\n", label);
+
+ struct template *tp = tdb->methods.get(tdb, label);
+ if (!tp)
+ {
+ tp = template_new(label);
+ template_lset(tp, NULL, "type", type);
+ template_lset(tp, NULL, "description", "Dummy template");
+ template_lset(tp, NULL, "extended_description",
+ "This is a fake template used to pre-seed the debconf database. "
+ "If you are seeing this, something is probably wrong.");
+ }
+ else
+ {
+ template_lset(tp, NULL, "default", content);
+ template_lset(tp, NULL, "type", type);
+ }
+
+ tdb->methods.set(tdb, tp);
+ template_deref(tp);
+
+ struct question *q = qdb->methods.get(qdb, label);
+
+ if (!q)
+ {
+ fprintf(stderr, "Cannot find a question for %s\n", label);
+ return;
+ }
+
+ question_owner_add(q, owner);
+ question_setvalue(q, content);
+ if (!unseen)
+ q->flags |= DC_QFLAG_SEEN;
+
+ qdb->methods.set(qdb, q);
+
+ question_deref(q);
+}
+
+static void set_flag(const char *label, const char *flag, unsigned int value,
+ const char *content, struct question_db *qdb)
+{
+ if (debug)
+ fprintf(stderr, "info: Setting %s flag\n", flag);
+
+ struct question *q = qdb->methods.get(qdb, label);
+
+ if (!q)
+ {
+ fprintf(stderr, "Cannot find a question for %s\n", label);
+ return;
+ }
+
+ if (0 == strcmp(content, "true"))
+ q->flags |= value;
+ else if (0 == strcmp(content, "false"))
+ q->flags &= ~value;
+
+ qdb->methods.set(qdb, q);
+
+ question_deref(q);
+}
+
+static int flag_value(const char *type)
+{
+ int i;
+
+ if (!type)
+ return 0;
+
+ for (i = 0; flags[i].name != NULL; i++)
+ {
+ if (0 == strcmp(flags[i].name, type))
+ return flags[i].value;
+ }
+
+ return 0;
+}
+
+static int is_known_type(const char *type)
+{
+ int i;
+
+ if (!type)
+ return 0;
+
+ for (i = 0; known_types[i] != NULL; i++)
+ {
+ if (0 == strcmp(known_types[i], type))
+ return 1;
+ }
+
+ return 0;
+}
+
+static size_t strlenmunge(char *buf, int *line)
+{
+ size_t tmplen = strlen(buf);
+ if (buf[tmplen - 1] == '\n')
+ {
+ (*line)++;
+ if (tmplen >= 2 && buf[tmplen - 2] == '\r')
+ {
+ buf[tmplen - 1] = '\0';
+ buf[tmplen - 2] = '\n';
+ tmplen -= 1;
+ }
+
+ if (tmplen >= 2 && buf[tmplen - 2] == '\\')
+ {
+ buf[tmplen - 2] = '\0';
+ tmplen -= 2;
+ }
+ }
+
+ return tmplen;
+}
+
+#define BUFFERSIZE 2048
+#define IS_SPACE(c) ((c == ' ') || (c == '\t'))
+#define NOT_SET(var) (!var || *var == ' ' || *var == '\t')
+
+int main(int argc, char **argv)
+{
+ int bufsize = BUFFERSIZE;
+ char *buf;
+ FILE *stream = stdin;
+ struct configuration *config;
+ struct template_db *tdb;
+ struct question_db *qdb;
+ int c, line = 0;
+
+ setlocale(LC_ALL, "");
+
+ config = config_new();
+
+ while ((c = getopt_long(argc, argv, "hvcu:", params, NULL)) >= 0)
+ {
+ switch (c)
+ {
+ case 'h': usage(argv[0]); break;
+ case 'v': debug = 1; break;
+ case 'c': checkonly = 1; break;
+ case 'u': unseen = 1; break;
+ default: break;
+ }
+ }
+
+ if (optind < argc)
+ {
+ stream = fopen(argv[optind], "r");
+ if (!stream)
+ {
+ fprintf(stderr, "Can't open %s\n", argv[optind]);
+ return 1;
+ }
+ }
+
+ /* parse the configuration info */
+ if (config->read(config, DEBCONFCONFIG) == 0)
+ DIE("Error reading configuration information");
+
+ /* initialize database modules */
+ if ((tdb = template_db_new(config, NULL)) == 0)
+ DIE("Cannot initialize DebConf template database");
+ if ((qdb = question_db_new(config, tdb, NULL)) == 0)
+ DIE("Cannot initialize DebConf config database");
+
+ /* load database */
+ tdb->methods.load(tdb);
+ qdb->methods.load(qdb);
+
+ buf = (char *)malloc(bufsize * sizeof(*buf));
+
+ while (fgets(buf, bufsize, stream))
+ {
+ size_t tmplen = strlenmunge(buf, &line);
+
+ while (buf[tmplen-1] != '\n')
+ {
+ bufsize += BUFFERSIZE;
+ buf = realloc(buf, bufsize * sizeof(*buf));
+ if (!buf)
+ DIE("Could not allocate memory !");
+ if (!fgets(buf + tmplen, bufsize - tmplen, stream))
+ break;
+ tmplen = strlenmunge(buf, &line);
+ }
+
+ CHOMP(buf);
+
+ {
+ char *ch = buf;
+ char *owner = NULL, *label = NULL, *type = NULL, *content = NULL;
+
+ while (IS_SPACE(*ch))
+ ch++;
+
+ owner = ch;
+
+ while (*ch && NOT_SET(content))
+ {
+ if (IS_SPACE(*ch))
+ {
+ *ch = '\0';
+ if (NOT_SET(label))
+ label = ch+1;
+ else if (NOT_SET(type))
+ type = ch+1;
+ else if (NOT_SET(content))
+ content = ch+1;
+ }
+ ch++;
+ }
+
+ if (owner && owner[0] && owner[0] != '#' &&
+ label && label[0] && type && type[0] && content)
+ {
+ int flagvalue = flag_value(type);
+
+ if (flagvalue)
+ {
+ if (debug)
+ fprintf(stderr, "info: Trying to set %s flag to %s\n", type, content);
+ set_flag(label, type, flagvalue, content, qdb);
+ }
+ else if (is_known_type(type))
+ {
+ if (debug)
+ fprintf(stderr, "info: Trying to set '%s' [%s] to '%s'\n", label, type, content);
+ load_answer(owner, label, type, content, qdb, tdb);
+ }
+ else
+ fprintf(stderr, "warning: Unknown type %s, skipping line %i\n", type, line);
+ }
+ }
+ }
+
+ fclose(stream);
+
+ if (!checkonly)
+ {
+ qdb->methods.save(qdb);
+ tdb->methods.save(tdb);
+ }
+
+ free(buf);
+ question_db_delete(qdb);
+ template_db_delete(tdb);
+ config_delete(config);
+
+ return 0;
+}
Reply to: