Commit 3179db10 authored by Dan McGee's avatar Dan McGee Committed by Allan McRae
Browse files

Add support for multiple 'Architecture' values



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: default avatarDan McGee <dan@archlinux.org>
Patch-updated-by: Allan McRae's avatarAllan McRae <allan@archlinux.org>
Signed-off-by: Allan McRae's avatarAllan McRae <allan@archlinux.org>
parent abdb4d7f
......@@ -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
......
......@@ -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 */
/** @} */
......
......@@ -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;
}
......
......@@ -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 */
......
......@@ -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;
......
......@@ -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);
......
......@@ -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);
......
......@@ -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);
......
......@@ -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;
......
......@@ -85,6 +85,8 @@ pacman_tests = [
'tests/mode001.py',
'tests/mode002.py',
'tests/mode003.py',
'tests/multiple-architectures01.py',
'tests/multiple-architectures02.py',
'tests/noupgrade-inverted.py',
'tests/overwrite-files-match-negated.py',
'tests/overwrite-files-match.py',
......
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")
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
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment