[pacman-dev] [PATCH] Add support for multiple 'Architecture' values
Allan McRae
allan at archlinux.org
Wed Apr 21 13:25:20 UTC 2021
From: Dan McGee <dan at archlinux.org>
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 <dan at archlinux.org>
Patch-updated-by: Allan McRae <allan at archlinux.org>
Signed-off-by: Allan McRae <allan at archlinux.org>
---
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
More information about the pacman-dev
mailing list