From: Dan McGee <[email protected]>

This allows architecture to be multivalued. On x86-64 machines, this
could be something like:
    Architecture = x86-64-v3 x86-64

We use the first specified Architecture value in mirrorlist $arch
variable replacement, as this is backwards-compatible and sane.

Original-patch-by: Dan McGee <[email protected]>
Patch-updated-by: Allan McRae <[email protected]>
Signed-off-by: Allan McRae <[email protected]>
---

Here is the link to Dan's original patch from 2012!
https://code.toofishes.net/cgit/dan/pacman.git/commit/?h=multiarch&id=673c7d08c30fc897f534bda24e88e806e27bea2b

Getting this patch to apply did not require much effort, so I left
Dan as the author. We guess the original patch did not get applied
because it got lost due to no-one pushing it for inclusion.

 doc/pacman.conf.5.asciidoc                    | 10 +++---
 lib/libalpm/alpm.h                            | 30 ++++++++++++-----
 lib/libalpm/handle.c                          | 30 +++++++++++++----
 lib/libalpm/handle.h                          |  2 +-
 lib/libalpm/trans.c                           | 21 ++++++++++--
 src/pacman/conf.c                             | 33 ++++++++++++-------
 src/pacman/conf.h                             |  4 +--
 src/pacman/pacman-conf.c                      |  4 +--
 src/pacman/pacman.c                           |  2 +-
 test/pacman/meson.build                       |  2 ++
 test/pacman/tests/multiple-architectires01.py | 14 ++++++++
 test/pacman/tests/multiple-architectires02.py | 16 +++++++++
 12 files changed, 127 insertions(+), 41 deletions(-)
 create mode 100644 test/pacman/tests/multiple-architectires01.py
 create mode 100644 test/pacman/tests/multiple-architectires02.py

diff --git a/doc/pacman.conf.5.asciidoc b/doc/pacman.conf.5.asciidoc
index 9bd31916..11ca1e4f 100644
--- a/doc/pacman.conf.5.asciidoc
+++ b/doc/pacman.conf.5.asciidoc
@@ -113,9 +113,9 @@ Options
        general configuration options. Wildcards in the specified paths will get
        expanded based on linkman:glob[7] rules.
 
-*Architecture =* auto | i686 | x86_64 | ...::
-       If set, pacman will only allow installation of packages of the given
-       architecture (e.g. 'i686', 'x86_64', etc). The special value 'auto' will
+*Architecture =* auto &| i686 &| x86_64 | ...::
+       If set, pacman will only allow installation of packages with the given
+       architectures (e.g. 'i686', 'x86_64', etc). The special value 'auto' 
will
        use the system architecture, provided via ``uname -m''. If unset, no
        architecture checks are made. *NOTE*: Packages with the special
        architecture 'any' can always be installed, as they are meant to be
@@ -252,8 +252,8 @@ number.
 During parsing, pacman will define the `$repo` variable to the name of the
 current section. This is often utilized in files specified using the 'Include'
 directive so all repositories can use the same mirrorfile. pacman also defines
-the `$arch` variable to the value of `Architecture`, so the same mirrorfile can
-even be used for different architectures.
+the `$arch` variable to the first (or only) value of the `Architecture` option,
+so the same mirrorfile can even be used for different architectures.
 
 *SigLevel =* ...::
        Set the signature verification level for this repository. For more
diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h
index 833df829..2e99d4d8 100644
--- a/lib/libalpm/alpm.h
+++ b/lib/libalpm/alpm.h
@@ -2016,25 +2016,37 @@ int alpm_option_remove_assumeinstalled(alpm_handle_t 
*handle, const alpm_depend_
 /** @} */
 
 
-/** @name Accessors for the configured architecture
- *
- * libalpm will only install packages that match the configured architecture.
- * The architecture does not need to match the physical architecture.
- * It can just be treated as a label.
+/** @name Accessors to the list of allowed architectures.
+ * libalpm will only install packages that match one of the configured
+ * architectures. The architectures do not need to match the physical
+   architecture. They can just be treated as a label.
  * @{
  */
 
 /** Returns the allowed package architecture.
  * @param handle the context handle
- * @return the configured package architecture
+ * @return the configured package architectures
  */
-const char *alpm_option_get_arch(alpm_handle_t *handle);
+alpm_list_t *alpm_option_get_architectures(alpm_handle_t *handle);
 
-/** Sets the allowed package architecture.
+/** Adds an allowed package architecture.
  * @param handle the context handle
  * @param arch the architecture to set
  */
-int alpm_option_set_arch(alpm_handle_t *handle, const char *arch);
+int alpm_option_add_architecture(alpm_handle_t *handle, const char *arch);
+
+/** Sets the allowed package architecture.
+ * @param handle the context handle
+ * @param arches the architecture to set
+ */
+int alpm_option_set_architectures(alpm_handle_t *handle, alpm_list_t *arches);
+
+/** Removes an allowed package architecture.
+ * @param handle the context handle
+ * @param arch the architecture to remove
+ */
+int alpm_option_remove_architecture(alpm_handle_t *handle, const char *arch);
+
 /* End of arch accessors */
 /** @} */
 
diff --git a/lib/libalpm/handle.c b/lib/libalpm/handle.c
index 7b8cb1da..46224a25 100644
--- a/lib/libalpm/handle.c
+++ b/lib/libalpm/handle.c
@@ -77,7 +77,7 @@ void _alpm_handle_free(alpm_handle_t *handle)
        FREELIST(handle->hookdirs);
        FREE(handle->logfile);
        FREE(handle->lockfile);
-       FREE(handle->arch);
+       FREELIST(handle->architectures);
        FREE(handle->gpgdir);
        FREELIST(handle->noupgrade);
        FREELIST(handle->noextract);
@@ -276,10 +276,10 @@ alpm_list_t SYMEXPORT 
*alpm_option_get_assumeinstalled(alpm_handle_t *handle)
        return handle->assumeinstalled;
 }
 
-const char SYMEXPORT *alpm_option_get_arch(alpm_handle_t *handle)
+alpm_list_t SYMEXPORT *alpm_option_get_architectures(alpm_handle_t *handle)
 {
        CHECK_HANDLE(handle, return NULL);
-       return handle->arch;
+       return handle->architectures;
 }
 
 int SYMEXPORT alpm_option_get_checkspace(alpm_handle_t *handle)
@@ -720,11 +720,29 @@ int SYMEXPORT 
alpm_option_remove_assumeinstalled(alpm_handle_t *handle, const al
        return 0;
 }
 
-int SYMEXPORT alpm_option_set_arch(alpm_handle_t *handle, const char *arch)
+int SYMEXPORT alpm_option_add_architecture(alpm_handle_t *handle, const char 
*arch)
 {
+       handle->architectures = alpm_list_add(handle->architectures, 
strdup(arch));
+       return 0;
+}
+
+int SYMEXPORT alpm_option_set_architectures(alpm_handle_t *handle, alpm_list_t 
*arches)
+{
+       CHECK_HANDLE(handle, return -1);
+       if(handle->architectures) FREELIST(handle->architectures);
+       handle->architectures = alpm_list_strdup(arches);
+       return 0;
+}
+
+int SYMEXPORT alpm_option_remove_architecture(alpm_handle_t *handle, const 
char *arch)
+{
+       char *vdata = NULL;
        CHECK_HANDLE(handle, return -1);
-       if(handle->arch) FREE(handle->arch);
-       STRDUP(handle->arch, arch, RET_ERR(handle, ALPM_ERR_MEMORY, -1));
+       handle->architectures = alpm_list_remove_str(handle->architectures, 
arch, &vdata);
+       if(vdata != NULL) {
+               FREE(vdata);
+               return 1;
+       }
        return 0;
 }
 
diff --git a/lib/libalpm/handle.h b/lib/libalpm/handle.h
index 2d8d0f9e..52dc2125 100644
--- a/lib/libalpm/handle.h
+++ b/lib/libalpm/handle.h
@@ -96,7 +96,7 @@ struct __alpm_handle_t {
        alpm_list_t *assumeinstalled;   /* List of virtual packages used to 
satisfy dependencies */
 
        /* options */
-       char *arch;              /* Architecture of packages we should allow */
+       alpm_list_t *architectures; /* Architectures of packages we should 
allow */
        int usesyslog;           /* Use syslog instead of logfile? */ /* TODO 
move to frontend */
        int checkspace;          /* Check disk space before installing */
        char *dbext;             /* Sync DB extension */
diff --git a/lib/libalpm/trans.c b/lib/libalpm/trans.c
index c6ec7eea..939ab05a 100644
--- a/lib/libalpm/trans.c
+++ b/lib/libalpm/trans.c
@@ -71,14 +71,29 @@ static alpm_list_t *check_arch(alpm_handle_t *handle, 
alpm_list_t *pkgs)
        alpm_list_t *i;
        alpm_list_t *invalid = NULL;
 
-       const char *arch = handle->arch;
-       if(!arch) {
+       if(!handle->architectures) {
+               _alpm_log(handle, ALPM_LOG_DEBUG, "skipping architecture 
checks\n");
                return NULL;
        }
        for(i = pkgs; i; i = i->next) {
                alpm_pkg_t *pkg = i->data;
+               alpm_list_t *j;
+               int found = 0;
                const char *pkgarch = alpm_pkg_get_arch(pkg);
-               if(pkgarch && strcmp(pkgarch, arch) && strcmp(pkgarch, "any")) {
+
+               /* always allow non-architecture packages and those marked 
"any" */
+               if(!pkgarch || strcmp(pkgarch, "any") == 0) {
+                       continue;
+               }
+
+               for(j = handle->architectures; j; j = j->next) {
+                       if(strcmp(pkgarch, j->data) == 0) {
+                               found = 1;
+                               break;
+                       }
+               }
+
+               if(!found) {
                        char *string;
                        const char *pkgname = pkg->name;
                        const char *pkgver = pkg->version;
diff --git a/src/pacman/conf.c b/src/pacman/conf.c
index cde96716..9578daa3 100644
--- a/src/pacman/conf.c
+++ b/src/pacman/conf.c
@@ -159,7 +159,7 @@ int config_free(config_t *oldconfig)
        FREELIST(oldconfig->cachedirs);
        free(oldconfig->xfercommand);
        free(oldconfig->print_format);
-       free(oldconfig->arch);
+       FREELIST(oldconfig->architectures);
        wordsplit_free(oldconfig->xfercommand_argv);
        free(oldconfig);
 
@@ -394,16 +394,19 @@ cleanup:
 }
 
 
-int config_set_arch(const char *arch)
+int config_add_architecture(char *arch)
 {
        if(strcmp(arch, "auto") == 0) {
                struct utsname un;
+               char *newarch;
                uname(&un);
-               config->arch = strdup(un.machine);
-       } else {
-               config->arch = strdup(arch);
+               newarch = strdup(un.machine);
+               free(arch);
+               arch = newarch;
        }
-       pm_printf(ALPM_LOG_DEBUG, "config: arch: %s\n", config->arch);
+
+       pm_printf(ALPM_LOG_DEBUG, "config: arch: %s\n", arch);
+       config->architectures = alpm_list_add(config->architectures, arch);
        return 0;
 }
 
@@ -638,9 +641,12 @@ static int _parse_options(const char *key, char *value,
                } else if(strcmp(key, "HookDir") == 0) {
                        setrepeatingoption(value, "HookDir", 
&(config->hookdirs));
                } else if(strcmp(key, "Architecture") == 0) {
-                       if(!config->arch) {
-                               config_set_arch(value);
+                       alpm_list_t *i, *arches = NULL;
+                       setrepeatingoption(value, "Architecture", &arches);
+                       for(i = arches; i; i = alpm_list_next(i)) {
+                               config_add_architecture(i->data);
                        }
+                       alpm_list_free(arches);
                } else if(strcmp(key, "DBPath") == 0) {
                        /* don't overwrite a path specified on the command line 
*/
                        if(!config->dbpath) {
@@ -751,17 +757,20 @@ static int _parse_options(const char *key, char *value,
 
 static char *replace_server_vars(config_t *c, config_repo_t *r, const char *s)
 {
-       if(c->arch == NULL && strstr(s, "$arch")) {
+       if(c->architectures == NULL && strstr(s, "$arch")) {
                pm_printf(ALPM_LOG_ERROR,
                                _("mirror '%s' contains the '%s' variable, but 
no '%s' is defined.\n"),
                                s, "$arch", "Architecture");
                return NULL;
        }
 
-       if(c->arch) {
+       /* use first specified architecture */
+       if(c->architectures) {
                char *temp, *replaced;
+               alpm_list_t *i = config->architectures;
+               const char *arch = i->data;
 
-               replaced = strreplace(s, "$arch", c->arch);
+               replaced = strreplace(s, "$arch", arch);
 
                temp = replaced;
                replaced = strreplace(temp, "$repo", r->name);
@@ -893,7 +902,7 @@ static int setup_libalpm(void)
                pm_printf(ALPM_LOG_WARNING, _("no '%s' configured\n"), 
"XferCommand");
        }
 
-       alpm_option_set_arch(handle, config->arch);
+       alpm_option_set_architectures(handle, config->architectures);
        alpm_option_set_checkspace(handle, config->checkspace);
        alpm_option_set_usesyslog(handle, config->usesyslog);
 
diff --git a/src/pacman/conf.h b/src/pacman/conf.h
index 1b9fb337..316c8d0f 100644
--- a/src/pacman/conf.h
+++ b/src/pacman/conf.h
@@ -57,7 +57,6 @@ typedef struct __config_t {
        unsigned short usesyslog;
        unsigned short color;
        unsigned short disable_dl_timeout;
-       char *arch;
        char *print_format;
        /* unfortunately, we have to keep track of paths both here and in the 
library
         * because they can come from both the command line or config file, and 
we
@@ -70,6 +69,7 @@ typedef struct __config_t {
        char *sysroot;
        alpm_list_t *hookdirs;
        alpm_list_t *cachedirs;
+       alpm_list_t *architectures;
 
        unsigned short op_q_isfile;
        unsigned short op_q_info;
@@ -244,7 +244,7 @@ int config_free(config_t *oldconfig);
 
 void config_repo_free(config_repo_t *repo);
 
-int config_set_arch(const char *arch);
+int config_add_architecture(char *arch);
 int parseconfig(const char *file);
 int parseconfigfile(const char *file);
 int setdefaults(config_t *c);
diff --git a/src/pacman/pacman-conf.c b/src/pacman/pacman-conf.c
index f8fac75d..6ca21119 100644
--- a/src/pacman/pacman-conf.c
+++ b/src/pacman/pacman-conf.c
@@ -258,7 +258,7 @@ static void dump_config(void)
        show_list_str("NoUpgrade", config->noupgrade);
        show_list_str("NoExtract", config->noextract);
 
-       show_str("Architecture", config->arch);
+       show_list_str("Architecture", config->architectures);
        show_str("XferCommand", config->xfercommand);
 
        show_bool("UseSyslog", config->usesyslog);
@@ -364,7 +364,7 @@ static int list_directives(void)
 
 
                } else if(strcasecmp(i->data, "Architecture") == 0) {
-                       show_str("Architecture", config->arch);
+                       show_list_str("Architecture", config->architectures);
                } else if(strcasecmp(i->data, "XferCommand") == 0) {
                        show_str("XferCommand", config->xfercommand);
 
diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c
index b2aabc08..7e810127 100644
--- a/src/pacman/pacman.c
+++ b/src/pacman/pacman.c
@@ -377,7 +377,7 @@ static int parsearg_global(int opt)
 {
        switch(opt) {
                case OP_ARCH:
-                       config_set_arch(optarg);
+                       config_add_architecture(strdup(optarg));
                        break;
                case OP_ASK:
                        config->noask = 1;
diff --git a/test/pacman/meson.build b/test/pacman/meson.build
index 52ff9b9a..60722a8a 100644
--- a/test/pacman/meson.build
+++ b/test/pacman/meson.build
@@ -85,6 +85,8 @@ pacman_tests = [
   'tests/mode001.py',
   'tests/mode002.py',
   'tests/mode003.py',
+  'tests/multiple-architectires01.py',
+  'tests/multiple-architectires02.py',
   'tests/noupgrade-inverted.py',
   'tests/overwrite-files-match-negated.py',
   'tests/overwrite-files-match.py',
diff --git a/test/pacman/tests/multiple-architectires01.py 
b/test/pacman/tests/multiple-architectires01.py
new file mode 100644
index 00000000..39f3e1f7
--- /dev/null
+++ b/test/pacman/tests/multiple-architectires01.py
@@ -0,0 +1,14 @@
+self.description = "Install a package (multiple Architecture options, wrong)"
+
+p = pmpkg("dummy")
+p.files = ["bin/dummy",
+           "usr/man/man1/dummy.1"]
+p.arch = 'i686'
+self.addpkg(p)
+
+self.option["Architecture"] = ['i586', 'i486', 'i386']
+
+self.args = "-U %s" % p.filename()
+
+self.addrule("PACMAN_RETCODE=1")
+self.addrule("!PKG_EXIST=dummy")
diff --git a/test/pacman/tests/multiple-architectires02.py 
b/test/pacman/tests/multiple-architectires02.py
new file mode 100644
index 00000000..18625ec6
--- /dev/null
+++ b/test/pacman/tests/multiple-architectires02.py
@@ -0,0 +1,16 @@
+self.description = "Install a package (multiple Architecture options)"
+
+p = pmpkg("dummy")
+p.files = ["bin/dummy",
+           "usr/man/man1/dummy.1"]
+p.arch = 'i486'
+self.addpkg(p)
+
+self.option["Architecture"] = ['i586', 'i486', 'i386']
+
+self.args = "-U %s" % p.filename()
+
+self.addrule("PACMAN_RETCODE=0")
+self.addrule("PKG_EXIST=dummy")
+for f in p.files:
+       self.addrule("FILE_EXIST=%s" % f)
\ No newline at end of file
-- 
2.31.1

Reply via email to