Explorar el Código

libdpkg: Allow pkg:arch syntax in package relationship fields

Implement support for the packagename:archname syntax in package
relationships, required for multiarch.

Also, the only architecture value currently allowed is “any”, consistent
with round one of <https://wiki.ubuntu.com/MultiarchSpec>. This may be
relaxed before the wheezy release to allow for arch-specific cross
dependencies in the next release, but should probably not be relaxed
for package generation in order to avoid accidental archive uploads of
uninstallable packages.

[guillem@debian.org:
 - Rearrange struct deppossi for better memory alignment.
 - Do not print the arch qualifier if arch_none instead of NULL.
 - Check against arch_wildcard instead of the literal string.
 - Check archlength == 0 instead of arch[0] being NUL. ]

Signed-off-by: Guillem Jover <guillem@debian.org>
Steve Langasek hace 17 años
padre
commit
64fb693c76
Se han modificado 5 ficheros con 64 adiciones y 3 borrados
  1. 2 0
      lib/dpkg/dpkg-db.h
  2. 4 0
      lib/dpkg/dump.c
  3. 47 3
      lib/dpkg/fields.c
  4. 9 0
      lib/dpkg/parse.c
  5. 2 0
      src/processarc.c

+ 2 - 0
lib/dpkg/dpkg-db.h

@@ -72,8 +72,10 @@ struct deppossi {
   struct dependency *up;
   struct pkgset *ed;
   struct deppossi *next, *rev_next, *rev_prev;
+  const struct dpkg_arch *arch;
   struct versionrevision version;
   enum depverrel verrel;
+  bool arch_is_implicit;
   bool cyclebreak;
 };
 

+ 4 - 0
lib/dpkg/dump.c

@@ -283,6 +283,10 @@ void varbufdependency(struct varbuf *vb, struct dependency *dep) {
     varbuf_add_str(vb, possdel);
     possdel = " | ";
     varbuf_add_str(vb, dop->ed->name);
+    if (!dop->arch_is_implicit && dop->arch->type != arch_none) {
+      varbuf_add_char(vb, ':');
+      varbuf_add_str(vb, dop->arch->name);
+    }
     if (dop->verrel != dvr_none) {
       varbuf_add_str(vb, " (");
       switch (dop->verrel) {

+ 47 - 3
lib/dpkg/fields.c

@@ -5,6 +5,7 @@
  * Copyright © 1995 Ian Jackson <ian@chiark.greenend.org.uk>
  * Copyright © 2001 Wichert Akkerman
  * Copyright © 2006-2011 Guillem Jover <guillem@debian.org>
+ * Copyright © 2009 Canonical Ltd.
  * Copyright © 2011 Linaro Limited
  * Copyright © 2011 Raphaël Hertzog <hertzog@debian.org>
  *
@@ -32,6 +33,7 @@
 #include <dpkg/i18n.h>
 #include <dpkg/dpkg.h>
 #include <dpkg/dpkg-db.h>
+#include <dpkg/arch.h>
 #include <dpkg/path.h>
 #include <dpkg/parsedump.h>
 #include <dpkg/triglib.h>
@@ -386,9 +388,9 @@ f_dependency(struct pkginfo *pigp, struct pkgbin *pifp,
     for (;;) {
       depnamestart= p;
       /* Skip over package name characters. */
-      while (*p && !isspace(*p) && *p != '(' && *p != ',' && *p != '|') {
-	p++;
-      }
+      while (*p && !isspace(*p) && *p != ':' && *p != '(' && *p != ',' &&
+             *p != '|')
+        p++;
       depnamelength= p - depnamestart ;
       if (depnamelength == 0)
         parse_error(ps,
@@ -420,6 +422,48 @@ f_dependency(struct pkginfo *pigp, struct pkgbin *pifp,
 
       dop->cyclebreak = false;
 
+      /* See if we have an architecture qualifier. */
+      if (*p == ':') {
+        static struct varbuf arch;
+        const char *archstart;
+        int archlength;
+
+        archstart = ++p;
+        while (*p && !isspace(*p) && *p != '(' && *p != ',' && *p != '|')
+          p++;
+        archlength = p - archstart;
+        if (archlength == 0)
+          parse_error(ps, _("'%s' field, missing architecture name, or garbage "
+                            "where architecture name expected"), fip->name);
+
+        varbuf_reset(&arch);
+        varbuf_add_buf(&arch, archstart, archlength);
+        varbuf_end_str(&arch);
+
+        dop->arch_is_implicit = false;
+        dop->arch = dpkg_arch_find(arch.buf);
+
+        if (dop->arch->type == arch_illegal)
+          emsg = dpkg_arch_name_is_illegal(arch.buf);
+        else if (dop->arch->type != arch_wildcard)
+          emsg = _("a value different from 'any' is currently not allowed");
+        if (emsg)
+          parse_error(ps, _("'%s' field, reference to '%.255s': "
+                            "invalid architecture name '%.255s': %s"),
+                      fip->name, depname.buf, arch.buf, emsg);
+      } else if (fip->integer == dep_conflicts || fip->integer == dep_breaks ||
+                 fip->integer == dep_replaces) {
+        /* Conflics/Breaks/Replaces get an implicit "any" arch qualifier. */
+        dop->arch_is_implicit = true;
+        dop->arch = dpkg_arch_find("any");
+      } else {
+        /* Otherwise use the pkgbin architecture, which will be assigned to
+         * later on by parse.c, once we can guarantee we have parsed it from
+         * the control stanza. */
+        dop->arch_is_implicit = true;
+        dop->arch = NULL;
+      }
+
       /* Skip whitespace after package name. */
       while (isspace(*p)) p++;
 

+ 9 - 0
lib/dpkg/parse.c

@@ -170,6 +170,9 @@ static void
 pkg_parse_verify(struct parsedb_state *ps,
                  struct pkginfo *pkg, struct pkgbin *pkgbin)
 {
+  struct dependency *dep;
+  struct deppossi *dop;
+
   parse_must_have_field(ps, pkg->set->name, "package name");
 
   /* XXX: We need to check for status != stat_halfinstalled as while
@@ -204,6 +207,12 @@ pkg_parse_verify(struct parsedb_state *ps,
     parse_error(ps, _("package has field '%s' but is architecture all"),
                 "Multi-Arch: same");
 
+  /* Initialize deps to be arch-specific unless stated otherwise. */
+  for (dep = pkgbin->depends; dep; dep = dep->next)
+    for (dop = dep->list; dop; dop = dop->next)
+      if (!dop->arch)
+        dop->arch = pkgbin->arch;
+
   /* Check the Config-Version information:
    * If there is a Config-Version it is definitely to be used, but
    * there shouldn't be one if the package is ‘installed’ (in which case

+ 2 - 0
src/processarc.c

@@ -1091,6 +1091,8 @@ void process_archive(const char *filename) {
       newpossi->ed= possi->ed;
       newpossi->next = NULL;
       newpossi->rev_next = newpossi->rev_prev = NULL;
+      newpossi->arch_is_implicit = possi->arch_is_implicit;
+      newpossi->arch = possi->arch;
       newpossi->verrel= possi->verrel;
       if (possi->verrel != dvr_none)
         newpossi->version= possi->version;