summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan McGee <dan@archlinux.org>2012-02-24 12:13:23 -0600
committerDan McGee <dan@archlinux.org>2012-08-02 09:49:43 -0500
commit673c7d08c30fc897f534bda24e88e806e27bea2b (patch)
treea7542f429b554213716cd2e9d2009e97446e2cfb
parentec5e6d90294f3322b7015b422db948770ecb41b6 (diff)
downloadpacman-multiarch.tar.gz
pacman-multiarch.zip
Add support for multiple 'Architecture' valuesmultiarch
This allows architecture to be multivalued. On x86 32-bit machines, this could be something like: Architecture = auto i586 i486 i386 However, this is much more useful on the ARM platform, where packages might be specialized for later instruction sets but all versions share the same ABI. Thus, on a ARMv6-based machine, I might have the following: Architecture = armv6l armv5tel For now, we use the first specified Architecture value in mirrorlist $arch variable replacement, as this is backwards-compatible and sane. Signed-off-by: Dan McGee <dan@archlinux.org>
-rw-r--r--doc/pacman.conf.5.txt10
-rw-r--r--lib/libalpm/alpm.h14
-rw-r--r--lib/libalpm/handle.c33
-rw-r--r--lib/libalpm/handle.h2
-rw-r--r--lib/libalpm/trans.c18
-rw-r--r--src/pacman/conf.c31
-rw-r--r--src/pacman/conf.h4
-rw-r--r--src/pacman/pacman.c2
-rw-r--r--test/pacman/tests/upgrade085.py14
-rw-r--r--test/pacman/tests/upgrade086.py16
10 files changed, 106 insertions, 38 deletions
diff --git a/doc/pacman.conf.5.txt b/doc/pacman.conf.5.txt
index a9c5db36..e9aa8ccc 100644
--- a/doc/pacman.conf.5.txt
+++ b/doc/pacman.conf.5.txt
@@ -103,9 +103,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 by in ``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
@@ -219,8 +219,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 1d6a8c6c..e58f225b 100644
--- a/lib/libalpm/alpm.h
+++ b/lib/libalpm/alpm.h
@@ -536,10 +536,16 @@ int alpm_option_set_ignoregroups(alpm_handle_t *handle, alpm_list_t *ignoregrps)
int alpm_option_remove_ignoregroup(alpm_handle_t *handle, const char *grp);
/** @} */
-/** Returns the targeted architecture. */
-const char *alpm_option_get_arch(alpm_handle_t *handle);
-/** Sets the targeted architecture. */
-int alpm_option_set_arch(alpm_handle_t *handle, const char *arch);
+/** @name Accessors to the list of allowed architectures.
+ * These functions modify the list of architectures whose packages
+ * we allow to be installed.
+ * @{
+ */
+alpm_list_t *alpm_option_get_architectures(alpm_handle_t *handle);
+int alpm_option_add_architecture(alpm_handle_t *handle, const char *arch);
+int alpm_option_set_architectures(alpm_handle_t *handle, alpm_list_t *arches);
+int alpm_option_remove_architecture(alpm_handle_t *handle, const char *arch);
+/** @} */
double alpm_option_get_deltaratio(alpm_handle_t *handle);
int alpm_option_set_deltaratio(alpm_handle_t *handle, double ratio);
diff --git a/lib/libalpm/handle.c b/lib/libalpm/handle.c
index 816162bd..b1262633 100644
--- a/lib/libalpm/handle.c
+++ b/lib/libalpm/handle.c
@@ -78,13 +78,13 @@ void _alpm_handle_free(alpm_handle_t *handle)
FREELIST(handle->cachedirs);
FREE(handle->logfile);
FREE(handle->lockfile);
- FREE(handle->arch);
FREE(handle->gpgdir);
FREELIST(handle->dbs_sync);
FREELIST(handle->noupgrade);
FREELIST(handle->noextract);
FREELIST(handle->ignorepkg);
FREELIST(handle->ignoregroup);
+ FREELIST(handle->architectures);
FREE(handle);
}
@@ -247,10 +247,10 @@ alpm_list_t SYMEXPORT *alpm_option_get_ignoregroups(alpm_handle_t *handle)
return handle->ignoregroup;
}
-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;
}
double SYMEXPORT alpm_option_get_deltaratio(alpm_handle_t *handle)
@@ -571,14 +571,29 @@ int SYMEXPORT alpm_option_remove_ignoregroup(alpm_handle_t *handle, const char *
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)
{
CHECK_HANDLE(handle, return -1);
- if(handle->arch) FREE(handle->arch);
- if(arch) {
- handle->arch = strdup(arch);
- } else {
- handle->arch = NULL;
+ 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);
+ 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 c0ad6686..7f73ef8e 100644
--- a/lib/libalpm/handle.h
+++ b/lib/libalpm/handle.h
@@ -87,7 +87,7 @@ struct __alpm_handle_t {
alpm_list_t *ignoregroup; /* List of groups to ignore */
/* options */
- char *arch; /* Architecture of packages we should allow */
+ alpm_list_t *architectures; /* Architectures of packages we should allow */
double deltaratio; /* Download deltas if possible; a ratio value */
int usesyslog; /* Use syslog instead of logfile? */ /* TODO move to frontend */
int checkspace; /* Check disk space before installing */
diff --git a/lib/libalpm/trans.c b/lib/libalpm/trans.c
index 08f70dd7..243c6a5d 100644
--- a/lib/libalpm/trans.c
+++ b/lib/libalpm/trans.c
@@ -75,14 +75,26 @@ 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 f47b92dc..5cdd30d2 100644
--- a/src/pacman/conf.c
+++ b/src/pacman/conf.c
@@ -81,9 +81,9 @@ int config_free(config_t *oldconfig)
free(oldconfig->logfile);
free(oldconfig->gpgdir);
FREELIST(oldconfig->cachedirs);
+ FREELIST(oldconfig->architectures);
free(oldconfig->xfercommand);
free(oldconfig->print_format);
- free(oldconfig->arch);
free(oldconfig);
return 0;
@@ -222,17 +222,18 @@ cleanup:
return ret;
}
-
-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;
}
@@ -424,9 +425,12 @@ static int _parse_options(const char *key, char *value,
} else if(strcmp(key, "CacheDir") == 0) {
setrepeatingoption(value, "CacheDir", &(config->cachedirs));
} 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, "UseDelta") == 0) {
double ratio;
char *endptr;
@@ -495,10 +499,11 @@ static int _add_mirror(alpm_db_t *db, char *value)
const char *dbname = alpm_db_get_name(db);
/* let's attempt a replacement for the current repo */
char *temp = strreplace(value, "$repo", dbname);
- /* let's attempt a replacement for the arch */
- const char *arch = config->arch;
char *server;
- if(arch) {
+ /* let's attempt a replacement for the arch */
+ if(config->architectures) {
+ alpm_list_t *i = config->architectures;
+ const char *arch = i->data;
server = strreplace(temp, "$arch", arch);
free(temp);
} else {
@@ -612,7 +617,7 @@ static int setup_libalpm(void)
alpm_option_set_totaldlcb(handle, cb_dl_total);
}
- 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);
alpm_option_set_deltaratio(handle, config->deltaratio);
diff --git a/src/pacman/conf.h b/src/pacman/conf.h
index 69c955ed..bbb2f440 100644
--- a/src/pacman/conf.h
+++ b/src/pacman/conf.h
@@ -35,7 +35,6 @@ typedef struct __config_t {
unsigned short checkspace;
unsigned short usesyslog;
double deltaratio;
- 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
@@ -46,6 +45,7 @@ typedef struct __config_t {
char *logfile;
char *gpgdir;
alpm_list_t *cachedirs;
+ alpm_list_t *architectures;
unsigned short op_q_isfile;
unsigned short op_q_info;
@@ -142,7 +142,7 @@ extern config_t *config;
config_t *config_new(void);
int config_free(config_t *oldconfig);
-int config_set_arch(const char *arch);
+int config_add_architecture(char *arch);
int parseconfig(const char *file);
#endif /* _PM_CONF_H */
diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c
index 73d5be94..f45276c2 100644
--- a/src/pacman/pacman.c
+++ b/src/pacman/pacman.c
@@ -381,7 +381,7 @@ static int parsearg_global(int opt)
switch(opt) {
case OP_ARCH:
check_optarg();
- config_set_arch(optarg);
+ config_add_architecture(strdup(optarg));
break;
case OP_ASK:
check_optarg();
diff --git a/test/pacman/tests/upgrade085.py b/test/pacman/tests/upgrade085.py
new file mode 100644
index 00000000..39f3e1f7
--- /dev/null
+++ b/test/pacman/tests/upgrade085.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/upgrade086.py b/test/pacman/tests/upgrade086.py
new file mode 100644
index 00000000..bbd14129
--- /dev/null
+++ b/test/pacman/tests/upgrade086.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)