csomh / source-git / rpm

Forked from source-git/rpm 4 years ago
Clone
2ff057
#include "system.h"
2ff057
2ff057
#include <stdarg.h>
2ff057
#include <pthread.h>
2ff057
2ff057
#if defined(__linux__)
2ff057
#include <elf.h>
2ff057
#include <link.h>
2ff057
#endif
2ff057
2ff057
2ff057
#if HAVE_SYS_UTSNAME_H
2ff057
#include <sys/utsname.h>
2ff057
#endif
2ff057
#include <ctype.h>	/* XXX for /etc/rpm/platform contents */
2ff057
2ff057
#if HAVE_SYS_SYSTEMCFG_H
2ff057
#include <sys/systemcfg.h>
2ff057
#else
2ff057
#define __power_pc() 0
2ff057
#endif
2ff057
2ff057
#ifdef HAVE_SYS_AUXV_H
2ff057
#include <sys/auxv.h>
2ff057
#endif
2ff057
2ff057
#include <rpm/rpmlib.h>			/* RPM_MACTABLE*, Rc-prototypes */
2ff057
#include <rpm/rpmmacro.h>
2ff057
#include <rpm/rpmfileutil.h>
2ff057
#include <rpm/rpmstring.h>
2ff057
#include <rpm/rpmlog.h>
2ff057
#include <rpm/argv.h>
2ff057
2ff057
#include "rpmio/rpmlua.h"
2ff057
#include "rpmio/rpmio_internal.h"	/* XXX for rpmioSlurp */
2ff057
#include "lib/misc.h"
2ff057
#include "lib/rpmliblua.h"
2ff057
#include "lib/rpmug.h"
2ff057
2ff057
#include "debug.h"
2ff057
2ff057
static const char * defrcfiles = NULL;
2ff057
const char * macrofiles = NULL;
2ff057
2ff057
typedef struct machCacheEntry_s {
2ff057
    char * name;
2ff057
    int count;
2ff057
    char ** equivs;
2ff057
    int visited;
2ff057
} * machCacheEntry;
2ff057
2ff057
typedef struct machCache_s {
2ff057
    machCacheEntry cache;
2ff057
    int size;
2ff057
} * machCache;
2ff057
2ff057
typedef struct machEquivInfo_s {
2ff057
    char * name;
2ff057
    int score;
2ff057
} * machEquivInfo;
2ff057
2ff057
typedef struct machEquivTable_s {
2ff057
    int count;
2ff057
    machEquivInfo list;
2ff057
} * machEquivTable;
2ff057
2ff057
struct rpmvarValue {
2ff057
    char * value;
2ff057
    /* eventually, this arch will be replaced with a generic condition */
2ff057
    char * arch;
2ff057
struct rpmvarValue * next;
2ff057
};
2ff057
2ff057
struct rpmOption {
2ff057
    char * name;
2ff057
    int var;
2ff057
    int archSpecific;
2ff057
    int macroize;
2ff057
    int localize;
2ff057
};
2ff057
2ff057
static struct rpmat_s {
2ff057
    const char *platform;
2ff057
    uint64_t hwcap;
2ff057
} rpmat;
2ff057
2ff057
typedef struct defaultEntry_s {
2ff057
    char * name;
2ff057
    char * defName;
2ff057
} * defaultEntry;
2ff057
2ff057
typedef struct canonEntry_s {
2ff057
    char * name;
2ff057
    char * short_name;
2ff057
    short num;
2ff057
} * canonEntry;
2ff057
2ff057
/* tags are 'key'canon, 'key'translate, 'key'compat
2ff057
 *
2ff057
 * for giggles, 'key'_canon, 'key'_compat, and 'key'_canon will also work
2ff057
 */
2ff057
typedef struct tableType_s {
2ff057
    char * const key;
2ff057
    const int hasCanon;
2ff057
    const int hasTranslate;
2ff057
    struct machEquivTable_s equiv;
2ff057
    struct machCache_s cache;
2ff057
    defaultEntry defaults;
2ff057
    canonEntry canons;
2ff057
    int defaultsLength;
2ff057
    int canonsLength;
2ff057
} * tableType;
2ff057
2ff057
/* XXX get rid of this stuff... */
2ff057
/* Stuff for maintaining "variables" like SOURCEDIR, BUILDDIR, etc */
2ff057
#define RPMVAR_OPTFLAGS                 3
2ff057
#define RPMVAR_ARCHCOLOR                42
2ff057
#define RPMVAR_INCLUDE                  43
2ff057
#define RPMVAR_MACROFILES               49
2ff057
2ff057
#define RPMVAR_NUM                      55      /* number of RPMVAR entries */
2ff057
2ff057
/* this *must* be kept in alphabetical order */
2ff057
/* The order of the flags is archSpecific, macroize, localize */
2ff057
2ff057
static const struct rpmOption optionTable[] = {
2ff057
    { "archcolor",		RPMVAR_ARCHCOLOR,               1, 0, 0 },
2ff057
    { "include",		RPMVAR_INCLUDE,			0, 0, 2 },
2ff057
    { "macrofiles",		RPMVAR_MACROFILES,		0, 0, 1 },
2ff057
    { "optflags",		RPMVAR_OPTFLAGS,		1, 1, 0 },
2ff057
};
2ff057
2ff057
static const size_t optionTableSize = sizeof(optionTable) / sizeof(*optionTable);
2ff057
2ff057
#define OS	0
2ff057
#define ARCH	1
2ff057
2ff057
typedef struct rpmrcCtx_s * rpmrcCtx;
2ff057
struct rpmrcCtx_s {
2ff057
    ARGV_t platpat;
2ff057
    char *current[2];
2ff057
    int currTables[2];
2ff057
    struct rpmvarValue values[RPMVAR_NUM];
2ff057
    struct tableType_s tables[RPM_MACHTABLE_COUNT];
2ff057
    int machDefaults;
2ff057
    int pathDefaults;
2ff057
    pthread_rwlock_t lock;
2ff057
};
2ff057
2ff057
/* prototypes */
2ff057
static rpmRC doReadRC(rpmrcCtx ctx, const char * urlfn);
2ff057
2ff057
static void rpmSetVarArch(rpmrcCtx ctx,
2ff057
			  int var, const char * val, const char * arch);
2ff057
2ff057
static void rebuildCompatTables(rpmrcCtx ctx, int type, const char * name);
2ff057
2ff057
static void rpmRebuildTargetVars(rpmrcCtx ctx, const char **target, const char ** canontarget);
2ff057
2ff057
/* Force context (lock) acquisition through a function */
2ff057
static rpmrcCtx rpmrcCtxAcquire(int write)
2ff057
{
2ff057
    static struct rpmrcCtx_s _globalCtx = {
2ff057
	.lock = PTHREAD_RWLOCK_INITIALIZER,
2ff057
	.currTables = { RPM_MACHTABLE_INSTOS, RPM_MACHTABLE_INSTARCH },
2ff057
	.tables = {
2ff057
	    { "arch", 1, 0 },
2ff057
	    { "os", 1, 0 },
2ff057
	    { "buildarch", 0, 1 },
2ff057
	    { "buildos", 0, 1 }
2ff057
	},
2ff057
    };
2ff057
    rpmrcCtx ctx = &_globalCtx;
2ff057
2ff057
    /* XXX: errors should be handled */
2ff057
    if (write)
2ff057
	pthread_rwlock_wrlock(&ctx->lock);
2ff057
    else
2ff057
	pthread_rwlock_rdlock(&ctx->lock);
2ff057
2ff057
    return ctx;
2ff057
}
2ff057
2ff057
/* Release context (lock) */
2ff057
static rpmrcCtx rpmrcCtxRelease(rpmrcCtx ctx)
2ff057
{
2ff057
    pthread_rwlock_unlock(&ctx->lock);
2ff057
    return NULL;
2ff057
}
2ff057
2ff057
static int optionCompare(const void * a, const void * b)
2ff057
{
2ff057
    return rstrcasecmp(((const struct rpmOption *) a)->name,
2ff057
		      ((const struct rpmOption *) b)->name);
2ff057
}
2ff057
2ff057
static machCacheEntry
2ff057
machCacheFindEntry(const machCache cache, const char * key)
2ff057
{
2ff057
    int i;
2ff057
2ff057
    for (i = 0; i < cache->size; i++)
2ff057
	if (rstreq(cache->cache[i].name, key)) return cache->cache + i;
2ff057
2ff057
    return NULL;
2ff057
}
2ff057
2ff057
static int machCompatCacheAdd(char * name, const char * fn, int linenum,
2ff057
				machCache cache)
2ff057
{
2ff057
    machCacheEntry entry = NULL;
2ff057
    char * chptr;
2ff057
    char * equivs;
2ff057
    int delEntry = 0;
2ff057
    int i;
2ff057
2ff057
    while (*name && risspace(*name)) name++;
2ff057
2ff057
    chptr = name;
2ff057
    while (*chptr && *chptr != ':') chptr++;
2ff057
    if (!*chptr) {
2ff057
	rpmlog(RPMLOG_ERR, _("missing second ':' at %s:%d\n"), fn, linenum);
2ff057
	return 1;
2ff057
    } else if (chptr == name) {
2ff057
	rpmlog(RPMLOG_ERR, _("missing architecture name at %s:%d\n"), fn,
2ff057
			     linenum);
2ff057
	return 1;
2ff057
    }
2ff057
2ff057
    while (*chptr == ':' || risspace(*chptr)) chptr--;
2ff057
    *(++chptr) = '\0';
2ff057
    equivs = chptr + 1;
2ff057
    while (*equivs && risspace(*equivs)) equivs++;
2ff057
    if (!*equivs) {
2ff057
	delEntry = 1;
2ff057
    }
2ff057
2ff057
    if (cache->size) {
2ff057
	entry = machCacheFindEntry(cache, name);
2ff057
	if (entry) {
2ff057
	    for (i = 0; i < entry->count; i++)
2ff057
		entry->equivs[i] = _free(entry->equivs[i]);
2ff057
	    entry->equivs = _free(entry->equivs);
2ff057
	    entry->count = 0;
2ff057
	}
2ff057
    }
2ff057
2ff057
    if (!entry) {
2ff057
	cache->cache = xrealloc(cache->cache,
2ff057
			       (cache->size + 1) * sizeof(*cache->cache));
2ff057
	entry = cache->cache + cache->size++;
2ff057
	entry->name = xstrdup(name);
2ff057
	entry->count = 0;
2ff057
	entry->visited = 0;
2ff057
    }
2ff057
2ff057
    if (delEntry) return 0;
2ff057
2ff057
    while ((chptr = strtok(equivs, " ")) != NULL) {
2ff057
	equivs = NULL;
2ff057
	if (chptr[0] == '\0')	/* does strtok() return "" ever?? */
2ff057
	    continue;
2ff057
	if (entry->count)
2ff057
	    entry->equivs = xrealloc(entry->equivs, sizeof(*entry->equivs)
2ff057
					* (entry->count + 1));
2ff057
	else
2ff057
	    entry->equivs = xmalloc(sizeof(*entry->equivs));
2ff057
2ff057
	entry->equivs[entry->count] = xstrdup(chptr);
2ff057
	entry->count++;
2ff057
    }
2ff057
2ff057
    return 0;
2ff057
}
2ff057
2ff057
static machEquivInfo
2ff057
machEquivSearch(const machEquivTable table, const char * name)
2ff057
{
2ff057
    int i;
2ff057
2ff057
    for (i = 0; i < table->count; i++)
2ff057
	if (!rstrcasecmp(table->list[i].name, name))
2ff057
	    return table->list + i;
2ff057
2ff057
    return NULL;
2ff057
}
2ff057
2ff057
static void machAddEquiv(machEquivTable table, const char * name,
2ff057
			   int distance)
2ff057
{
2ff057
    machEquivInfo equiv;
2ff057
2ff057
    equiv = machEquivSearch(table, name);
2ff057
    if (!equiv) {
2ff057
	if (table->count)
2ff057
	    table->list = xrealloc(table->list, (table->count + 1)
2ff057
				    * sizeof(*table->list));
2ff057
	else
2ff057
	    table->list = xmalloc(sizeof(*table->list));
2ff057
2ff057
	table->list[table->count].name = xstrdup(name);
2ff057
	table->list[table->count++].score = distance;
2ff057
    }
2ff057
}
2ff057
2ff057
static void machCacheEntryVisit(machCache cache,
2ff057
		machEquivTable table, const char * name, int distance)
2ff057
{
2ff057
    machCacheEntry entry;
2ff057
    int i;
2ff057
2ff057
    entry = machCacheFindEntry(cache, name);
2ff057
    if (!entry || entry->visited) return;
2ff057
2ff057
    entry->visited = 1;
2ff057
2ff057
    for (i = 0; i < entry->count; i++) {
2ff057
	machAddEquiv(table, entry->equivs[i], distance);
2ff057
    }
2ff057
2ff057
    for (i = 0; i < entry->count; i++) {
2ff057
	machCacheEntryVisit(cache, table, entry->equivs[i], distance + 1);
2ff057
    }
2ff057
}
2ff057
2ff057
static void machFindEquivs(machCache cache, machEquivTable table,
2ff057
		const char * key)
2ff057
{
2ff057
    int i;
2ff057
2ff057
    for (i = 0; i < cache->size; i++)
2ff057
	cache->cache[i].visited = 0;
2ff057
2ff057
    while (table->count > 0) {
2ff057
	--table->count;
2ff057
	table->list[table->count].name = _free(table->list[table->count].name);
2ff057
    }
2ff057
    table->count = 0;
2ff057
    table->list = _free(table->list);
2ff057
2ff057
    /*
2ff057
     *	We have a general graph built using strings instead of pointers.
2ff057
     *	Yuck. We have to start at a point at traverse it, remembering how
2ff057
     *	far away everything is.
2ff057
     */
2ff057
   	/* FIX: table->list may be NULL. */
2ff057
    machAddEquiv(table, key, 1);
2ff057
    machCacheEntryVisit(cache, table, key, 2);
2ff057
    return;
2ff057
}
2ff057
2ff057
static rpmRC addCanon(canonEntry * table, int * tableLen, char * line,
2ff057
		    const char * fn, int lineNum)
2ff057
{
2ff057
    canonEntry t;
2ff057
    char *s, *s1;
2ff057
    const char * tname;
2ff057
    const char * tshort_name;
2ff057
    int tnum;
2ff057
2ff057
    (*tableLen) += 2;
2ff057
    *table = xrealloc(*table, sizeof(**table) * (*tableLen));
2ff057
2ff057
    t = & ((*table)[*tableLen - 2]);
2ff057
2ff057
    tname = strtok(line, ": \t");
2ff057
    tshort_name = strtok(NULL, " \t");
2ff057
    s = strtok(NULL, " \t");
2ff057
    if (! (tname && tshort_name && s)) {
2ff057
	rpmlog(RPMLOG_ERR, _("Incomplete data line at %s:%d\n"),
2ff057
		fn, lineNum);
2ff057
	return RPMRC_FAIL;
2ff057
    }
2ff057
    if (strtok(NULL, " \t")) {
2ff057
	rpmlog(RPMLOG_ERR, _("Too many args in data line at %s:%d\n"),
2ff057
	      fn, lineNum);
2ff057
	return RPMRC_FAIL;
2ff057
    }
2ff057
2ff057
    tnum = strtoul(s, &s1, 10);
2ff057
    if ((*s1) || (s1 == s) || (tnum == ULONG_MAX)) {
2ff057
	rpmlog(RPMLOG_ERR, _("Bad arch/os number: %s (%s:%d)\n"), s,
2ff057
	      fn, lineNum);
2ff057
	return RPMRC_FAIL;
2ff057
    }
2ff057
2ff057
    t[0].name = xstrdup(tname);
2ff057
    t[0].short_name = (tshort_name ? xstrdup(tshort_name) : xstrdup(""));
2ff057
    t[0].num = tnum;
2ff057
2ff057
    /* From A B C entry */
2ff057
    /* Add  B B C entry */
2ff057
    t[1].name = (tshort_name ? xstrdup(tshort_name) : xstrdup(""));
2ff057
    t[1].short_name = (tshort_name ? xstrdup(tshort_name) : xstrdup(""));
2ff057
    t[1].num = tnum;
2ff057
2ff057
    return RPMRC_OK;
2ff057
}
2ff057
2ff057
static rpmRC addDefault(defaultEntry * table, int * tableLen, char * line,
2ff057
			const char * fn, int lineNum)
2ff057
{
2ff057
    defaultEntry t;
2ff057
2ff057
    (*tableLen)++;
2ff057
    *table = xrealloc(*table, sizeof(**table) * (*tableLen));
2ff057
2ff057
    t = & ((*table)[*tableLen - 1]);
2ff057
2ff057
    t->name = strtok(line, ": \t");
2ff057
    t->defName = strtok(NULL, " \t");
2ff057
    if (! (t->name && t->defName)) {
2ff057
	rpmlog(RPMLOG_ERR, _("Incomplete default line at %s:%d\n"),
2ff057
		 fn, lineNum);
2ff057
	return RPMRC_FAIL;
2ff057
    }
2ff057
    if (strtok(NULL, " \t")) {
2ff057
	rpmlog(RPMLOG_ERR, _("Too many args in default line at %s:%d\n"),
2ff057
	      fn, lineNum);
2ff057
	return RPMRC_FAIL;
2ff057
    }
2ff057
2ff057
    t->name = xstrdup(t->name);
2ff057
    t->defName = (t->defName ? xstrdup(t->defName) : NULL);
2ff057
2ff057
    return RPMRC_OK;
2ff057
}
2ff057
2ff057
static canonEntry lookupInCanonTable(const char * name,
2ff057
		const canonEntry table, int tableLen)
2ff057
{
2ff057
    while (tableLen) {
2ff057
	tableLen--;
2ff057
	if (!rstreq(name, table[tableLen].name))
2ff057
	    continue;
2ff057
	return &(table[tableLen]);
2ff057
    }
2ff057
2ff057
    return NULL;
2ff057
}
2ff057
2ff057
static
2ff057
const char * lookupInDefaultTable(const char * name,
2ff057
		const defaultEntry table, int tableLen)
2ff057
{
2ff057
    while (tableLen) {
2ff057
	tableLen--;
2ff057
	if (table[tableLen].name && rstreq(name, table[tableLen].name))
2ff057
	    return table[tableLen].defName;
2ff057
    }
2ff057
2ff057
    return name;
2ff057
}
2ff057
2ff057
static void setDefaults(void)
2ff057
{
2ff057
    const char *confdir = rpmConfigDir();
2ff057
    if (!defrcfiles) {
2ff057
	defrcfiles = rstrscat(NULL, confdir, "/rpmrc", ":",
2ff057
				confdir, "/" RPMCANONVENDOR "/rpmrc", ":",
2ff057
				SYSCONFDIR "/rpmrc", ":",
2ff057
			  	"~/.rpmrc", NULL);
2ff057
    }
2ff057
2ff057
#ifndef MACROFILES
2ff057
    if (!macrofiles) {
2ff057
	macrofiles = rstrscat(NULL, confdir, "/macros", ":",
2ff057
				confdir, "/macros.d/macros.*", ":",
2ff057
				confdir, "/platform/%{_target}/macros", ":",
2ff057
				confdir, "/fileattrs/*.attr", ":",
2ff057
  				confdir, "/" RPMCANONVENDOR "/macros", ":",
2ff057
				SYSCONFDIR "/rpm/macros.*", ":",
2ff057
				SYSCONFDIR "/rpm/macros", ":",
2ff057
				SYSCONFDIR "/rpm/%{_target}/macros", ":",
2ff057
				"~/.rpmmacros", NULL);
2ff057
    }
2ff057
#else
2ff057
    macrofiles = MACROFILES;
2ff057
#endif
2ff057
}
2ff057
2ff057
/* FIX: se usage inconsistent, W2DO? */
2ff057
static rpmRC doReadRC(rpmrcCtx ctx, const char * urlfn)
2ff057
{
2ff057
    char *s;
2ff057
    char *se, *next, *buf = NULL, *fn;
2ff057
    int linenum = 0;
2ff057
    struct rpmOption searchOption, * option;
2ff057
    rpmRC rc = RPMRC_FAIL;
2ff057
2ff057
    fn = rpmGetPath(urlfn, NULL);
2ff057
    if (rpmioSlurp(fn, (uint8_t **) &buf, NULL) || buf == NULL) {
2ff057
	goto exit;
2ff057
    }
2ff057
	
2ff057
    next = buf;
2ff057
    while (*next != '\0') {
2ff057
	linenum++;
2ff057
2ff057
	s = se = next;
2ff057
2ff057
	/* Find end-of-line. */
2ff057
	while (*se && *se != '\n') se++;
2ff057
	if (*se != '\0') *se++ = '\0';
2ff057
	next = se;
2ff057
2ff057
	/* Trim leading spaces */
2ff057
	while (*s && risspace(*s)) s++;
2ff057
2ff057
	/* We used to allow comments to begin anywhere, but not anymore. */
2ff057
	if (*s == '#' || *s == '\0') continue;
2ff057
2ff057
	/* Find end-of-keyword. */
2ff057
	se = (char *)s;
2ff057
	while (*se && !risspace(*se) && *se != ':') se++;
2ff057
2ff057
	if (risspace(*se)) {
2ff057
	    *se++ = '\0';
2ff057
	    while (*se && risspace(*se) && *se != ':') se++;
2ff057
	}
2ff057
2ff057
	if (*se != ':') {
2ff057
	    rpmlog(RPMLOG_ERR, _("missing ':' (found 0x%02x) at %s:%d\n"),
2ff057
		     (unsigned)(0xff & *se), fn, linenum);
2ff057
	    goto exit;
2ff057
	}
2ff057
	*se++ = '\0';	/* terminate keyword or option, point to value */
2ff057
	while (*se && risspace(*se)) se++;
2ff057
2ff057
	/* Find keyword in table */
2ff057
	searchOption.name = s;
2ff057
	option = bsearch(&searchOption, optionTable, optionTableSize,
2ff057
			 sizeof(optionTable[0]), optionCompare);
2ff057
2ff057
	if (option) {	/* For configuration variables  ... */
2ff057
	    const char *arch, *val;
2ff057
2ff057
	    arch = val = NULL;
2ff057
	    if (*se == '\0') {
2ff057
		rpmlog(RPMLOG_ERR, _("missing argument for %s at %s:%d\n"),
2ff057
		      option->name, fn, linenum);
2ff057
		goto exit;
2ff057
	    }
2ff057
2ff057
	    if (option->var == RPMVAR_INCLUDE) {
2ff057
		s = se;
2ff057
		while (*se && !risspace(*se)) se++;
2ff057
		if (*se != '\0') *se = '\0';
2ff057
2ff057
		if (doReadRC(ctx, s)) {
2ff057
		    rpmlog(RPMLOG_ERR, _("cannot open %s at %s:%d: %m\n"),
2ff057
			s, fn, linenum);
2ff057
		    goto exit;
2ff057
		}
2ff057
		/* XXX don't save include value as var/macro */
2ff057
		continue;
2ff057
	    }
2ff057
2ff057
	    if (option->archSpecific) {
2ff057
		arch = se;
2ff057
		while (*se && !risspace(*se)) se++;
2ff057
		if (*se == '\0') {
2ff057
		    rpmlog(RPMLOG_ERR,
2ff057
				_("missing architecture for %s at %s:%d\n"),
2ff057
			  	option->name, fn, linenum);
2ff057
		    goto exit;
2ff057
		}
2ff057
		*se++ = '\0';
2ff057
		while (*se && risspace(*se)) se++;
2ff057
		if (*se == '\0') {
2ff057
		    rpmlog(RPMLOG_ERR,
2ff057
				_("missing argument for %s at %s:%d\n"),
2ff057
			  	option->name, fn, linenum);
2ff057
		    goto exit;
2ff057
		}
2ff057
	    }
2ff057
	
2ff057
	    val = se;
2ff057
2ff057
	    /* Only add macros if appropriate for this arch */
2ff057
	    if (option->macroize &&
2ff057
	      (arch == NULL || rstreq(arch, ctx->current[ARCH]))) {
2ff057
		char *n, *name;
2ff057
		n = name = xmalloc(strlen(option->name)+2);
2ff057
		if (option->localize)
2ff057
		    *n++ = '_';
2ff057
		strcpy(n, option->name);
2ff057
		rpmPushMacro(NULL, name, NULL, val, RMIL_RPMRC);
2ff057
		free(name);
2ff057
	    }
2ff057
	    rpmSetVarArch(ctx, option->var, val, arch);
2ff057
	    fn = _free(fn);
2ff057
2ff057
	} else {	/* For arch/os compatibility tables ... */
2ff057
	    int gotit;
2ff057
	    int i;
2ff057
2ff057
	    gotit = 0;
2ff057
2ff057
	    for (i = 0; i < RPM_MACHTABLE_COUNT; i++) {
2ff057
		if (rstreqn(ctx->tables[i].key, s, strlen(ctx->tables[i].key)))
2ff057
		    break;
2ff057
	    }
2ff057
2ff057
	    if (i < RPM_MACHTABLE_COUNT) {
2ff057
		const char *rest = s + strlen(ctx->tables[i].key);
2ff057
		if (*rest == '_') rest++;
2ff057
2ff057
		if (rstreq(rest, "compat")) {
2ff057
		    if (machCompatCacheAdd(se, fn, linenum,
2ff057
						&ctx->tables[i].cache))
2ff057
			goto exit;
2ff057
		    gotit = 1;
2ff057
		} else if (ctx->tables[i].hasTranslate &&
2ff057
			   rstreq(rest, "translate")) {
2ff057
		    if (addDefault(&ctx->tables[i].defaults,
2ff057
				   &ctx->tables[i].defaultsLength,
2ff057
				   se, fn, linenum))
2ff057
			goto exit;
2ff057
		    gotit = 1;
2ff057
		} else if (ctx->tables[i].hasCanon &&
2ff057
			   rstreq(rest, "canon")) {
2ff057
		    if (addCanon(&ctx->tables[i].canons,
2ff057
				 &ctx->tables[i].canonsLength,
2ff057
				 se, fn, linenum))
2ff057
			goto exit;
2ff057
		    gotit = 1;
2ff057
		}
2ff057
	    }
2ff057
2ff057
	    if (!gotit) {
2ff057
		rpmlog(RPMLOG_ERR, _("bad option '%s' at %s:%d\n"),
2ff057
			    s, fn, linenum);
2ff057
		goto exit;
2ff057
	    }
2ff057
	}
2ff057
    }
2ff057
    rc = RPMRC_OK;
2ff057
2ff057
exit:
2ff057
    free(fn);
2ff057
    free(buf);
2ff057
2ff057
    return rc;
2ff057
}
2ff057
2ff057
2ff057
/**
2ff057
 */
2ff057
static rpmRC rpmPlatform(rpmrcCtx ctx, const char * platform)
2ff057
{
2ff057
    const char *cpu = NULL, *vendor = NULL, *os = NULL, *gnu = NULL;
2ff057
    uint8_t * b = NULL;
2ff057
    ssize_t blen = 0;
2ff057
    int init_platform = 0;
2ff057
    char * p, * pe;
2ff057
    rpmRC rc;
2ff057
2ff057
    rc = (rpmioSlurp(platform, &b, &blen) == 0) ? RPMRC_OK : RPMRC_FAIL;
2ff057
2ff057
    if (rc || b == NULL || blen <= 0) {
2ff057
	rc = RPMRC_FAIL;
2ff057
	goto exit;
2ff057
    }
2ff057
2ff057
    p = (char *)b;
2ff057
    for (pe = p; p && *p; p = pe) {
2ff057
	pe = strchr(p, '\n');
2ff057
	if (pe)
2ff057
	    *pe++ = '\0';
2ff057
2ff057
	while (*p && isspace(*p))
2ff057
	    p++;
2ff057
	if (*p == '\0' || *p == '#')
2ff057
	    continue;
2ff057
2ff057
	if (init_platform) {
2ff057
	    char * t = p + strlen(p);
2ff057
2ff057
	    while (--t > p && isspace(*t))
2ff057
		*t = '\0';
2ff057
	    if (t > p) {
2ff057
		argvAdd(&ctx->platpat, p);
2ff057
	    }
2ff057
	    continue;
2ff057
	}
2ff057
2ff057
	cpu = p;
2ff057
	vendor = "unknown";
2ff057
	os = "unknown";
2ff057
	gnu = NULL;
2ff057
	while (*p && !(*p == '-' || isspace(*p)))
2ff057
	    p++;
2ff057
	if (*p != '\0') *p++ = '\0';
2ff057
2ff057
	vendor = p;
2ff057
	while (*p && !(*p == '-' || isspace(*p)))
2ff057
	    p++;
2ff057
	if (*p != '-') {
2ff057
	    if (*p != '\0') *p = '\0';
2ff057
	    os = vendor;
2ff057
	    vendor = "unknown";
2ff057
	} else {
2ff057
	    if (*p != '\0') *p++ = '\0';
2ff057
2ff057
	    os = p;
2ff057
	    while (*p && !(*p == '-' || isspace(*p)))
2ff057
		p++;
2ff057
	    if (*p == '-') {
2ff057
		*p++ = '\0';
2ff057
2ff057
		gnu = p;
2ff057
		while (*p && !(*p == '-' || isspace(*p)))
2ff057
		    p++;
2ff057
	    }
2ff057
	    if (*p != '\0') *p = '\0';
2ff057
	}
2ff057
2ff057
	rpmPushMacro(NULL, "_host_cpu", NULL, cpu, -1);
2ff057
	rpmPushMacro(NULL, "_host_vendor", NULL, vendor, -1);
2ff057
	rpmPushMacro(NULL, "_host_os", NULL, os, -1);
2ff057
2ff057
	char *plat = rpmExpand("%{_host_cpu}-%{_host_vendor}-%{_host_os}",
2ff057
				(gnu && *gnu ? "-" : NULL), gnu, NULL);
2ff057
	argvAdd(&ctx->platpat, plat);
2ff057
	free(plat);
2ff057
	
2ff057
	init_platform++;
2ff057
    }
2ff057
    rc = (init_platform ? RPMRC_OK : RPMRC_FAIL);
2ff057
2ff057
exit:
2ff057
    b = _free(b);
2ff057
    return rc;
2ff057
}
2ff057
2ff057
2ff057
#	if defined(__linux__) && defined(__i386__)
2ff057
#include <setjmp.h>
2ff057
#include <signal.h>
2ff057
2ff057
/*
2ff057
 * Generic CPUID function
2ff057
 */
2ff057
static inline void cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx)
2ff057
{
2ff057
    asm volatile (
2ff057
	"pushl	%%ebx		\n"
2ff057
	"cpuid			\n"
2ff057
	"movl	%%ebx,	%%esi	\n"
2ff057
	"popl	%%ebx		\n"
2ff057
    : "=a" (*eax), "=S" (*ebx), "=c" (*ecx), "=d" (*edx)
2ff057
    : "a" (op));
2ff057
}
2ff057
2ff057
/*
2ff057
 * CPUID functions returning a single datum
2ff057
 */
2ff057
static inline unsigned int cpuid_eax(unsigned int op)
2ff057
{
2ff057
	unsigned int tmp, val;
2ff057
	cpuid(op, &val, &tmp, &tmp, &tmp);
2ff057
	return val;
2ff057
}
2ff057
2ff057
static inline unsigned int cpuid_ebx(unsigned int op)
2ff057
{
2ff057
	unsigned int tmp, val;
2ff057
	cpuid(op, &tmp, &val, &tmp, &tmp);
2ff057
	return val;
2ff057
}
2ff057
2ff057
static inline unsigned int cpuid_ecx(unsigned int op)
2ff057
{
2ff057
	unsigned int tmp, val;
2ff057
	cpuid(op, &tmp, &tmp, &val, &tmp);
2ff057
	return val;
2ff057
}
2ff057
2ff057
static inline unsigned int cpuid_edx(unsigned int op)
2ff057
{
2ff057
	unsigned int tmp, val;
2ff057
	cpuid(op, &tmp, &tmp, &tmp, &val;;
2ff057
	return val;
2ff057
}
2ff057
2ff057
static sigjmp_buf jenv;
2ff057
2ff057
static inline void model3(int _unused)
2ff057
{
2ff057
	siglongjmp(jenv, 1);
2ff057
}
2ff057
2ff057
static inline int RPMClass(void)
2ff057
{
2ff057
	int cpu;
2ff057
	unsigned int tfms, junk, cap, capamd;
2ff057
	struct sigaction oldsa;
2ff057
	
2ff057
	sigaction(SIGILL, NULL, &oldsa);
2ff057
	signal(SIGILL, model3);
2ff057
	
2ff057
	if (sigsetjmp(jenv, 1)) {
2ff057
		sigaction(SIGILL, &oldsa, NULL);
2ff057
		return 3;
2ff057
	}
2ff057
		
2ff057
	if (cpuid_eax(0x000000000)==0) {
2ff057
		sigaction(SIGILL, &oldsa, NULL);
2ff057
		return 4;
2ff057
	}
2ff057
2ff057
	cpuid(0x00000001, &tfms, &junk, &junk, &cap);
2ff057
	cpuid(0x80000001, &junk, &junk, &junk, &capamd);
2ff057
	
2ff057
	cpu = (tfms>>8)&1;;
2ff057
	
2ff057
	if (cpu == 5
2ff057
	    && cpuid_ecx(0) == '68xM'
2ff057
	    && cpuid_edx(0) == 'Teni'
2ff057
	    && (cpuid_edx(1) & ((1<<8)|(1<<15))) == ((1<<8)|(1<<15))) {
2ff057
		sigaction(SIGILL, &oldsa, NULL);
2ff057
		return 6;	/* has CX8 and CMOV */
2ff057
	}
2ff057
2ff057
	sigaction(SIGILL, &oldsa, NULL);
2ff057
2ff057
#define USER686 ((1<<4) | (1<<8) | (1<<15))
2ff057
	/* Transmeta Crusoe CPUs say that their CPU family is "5" but they have enough features for i686. */
2ff057
	if (cpu == 5 && (cap & USER686) == USER686)
2ff057
		return 6;
2ff057
2ff057
	if (cpu < 6)
2ff057
		return cpu;
2ff057
		
2ff057
	if (cap & (1<<15)) {
2ff057
		/* CMOV supported? */
2ff057
		if (capamd & (1<<30))
2ff057
			return 7;	/* 3DNOWEXT supported */
2ff057
		return 6;
2ff057
	}
2ff057
		
2ff057
	return 5;
2ff057
}
2ff057
2ff057
/* should only be called for model 6 CPU's */
2ff057
static int is_athlon(void)
2ff057
{
2ff057
	unsigned int eax, ebx, ecx, edx;
2ff057
	char vendor[16];
2ff057
	int i;
2ff057
	
2ff057
	cpuid (0, &eax, &ebx, &ecx, &edx;;
2ff057
2ff057
 	memset(vendor, 0, sizeof(vendor));
2ff057
 	
2ff057
 	for (i=0; i<4; i++)
2ff057
 		vendor[i] = (unsigned char) (ebx >>(8*i));
2ff057
 	for (i=0; i<4; i++)
2ff057
 		vendor[4+i] = (unsigned char) (edx >>(8*i));
2ff057
 	for (i=0; i<4; i++)
2ff057
 		vendor[8+i] = (unsigned char) (ecx >>(8*i));
2ff057
 		
2ff057
 	if (!rstreqn(vendor, "AuthenticAMD", 12))  
2ff057
 		return 0;
2ff057
2ff057
	return 1;
2ff057
}
2ff057
2ff057
static int is_pentium3(void)
2ff057
{
2ff057
    unsigned int eax, ebx, ecx, edx, family, model;
2ff057
    char vendor[16];
2ff057
    cpuid(0, &eax, &ebx, &ecx, &edx;;
2ff057
    memset(vendor, 0, sizeof(vendor));
2ff057
    *((unsigned int *)&vendor[0]) = ebx;
2ff057
    *((unsigned int *)&vendor[4]) = edx;
2ff057
    *((unsigned int *)&vendor[8]) = ecx;
2ff057
    if (!rstreqn(vendor, "GenuineIntel", 12))
2ff057
	return 0;
2ff057
    cpuid(1, &eax, &ebx, &ecx, &edx;;
2ff057
    family = (eax >> 8) & 0x0f;
2ff057
    model = (eax >> 4) & 0x0f;
2ff057
    if (family == 6)
2ff057
	switch (model)
2ff057
	{
2ff057
	    case 7:	// Pentium III, Pentium III Xeon (model 7)
2ff057
	    case 8:	// Pentium III, Pentium III Xeon, Celeron (model 8)
2ff057
	    case 9:	// Pentium M
2ff057
	    case 10:	// Pentium III Xeon (model A)
2ff057
	    case 11:	// Pentium III (model B)
2ff057
		return 1;
2ff057
	}
2ff057
    return 0;
2ff057
}
2ff057
2ff057
static int is_pentium4(void)
2ff057
{
2ff057
    unsigned int eax, ebx, ecx, edx, family, model;
2ff057
    char vendor[16];
2ff057
    cpuid(0, &eax, &ebx, &ecx, &edx;;
2ff057
    memset(vendor, 0, sizeof(vendor));
2ff057
    *((unsigned int *)&vendor[0]) = ebx;
2ff057
    *((unsigned int *)&vendor[4]) = edx;
2ff057
    *((unsigned int *)&vendor[8]) = ecx;
2ff057
    if (!rstreqn(vendor, "GenuineIntel", 12))
2ff057
	return 0;
2ff057
    cpuid(1, &eax, &ebx, &ecx, &edx;;
2ff057
    family = (eax >> 8) & 0x0f;
2ff057
    model = (eax >> 4) & 0x0f;
2ff057
    if (family == 15)
2ff057
	switch (model)
2ff057
	{
2ff057
	    case 0:	// Pentium 4, Pentium 4 Xeon                 (0.18um)
2ff057
	    case 1:	// Pentium 4, Pentium 4 Xeon MP, Celeron     (0.18um)
2ff057
	    case 2:	// Pentium 4, Mobile Pentium 4-M,
2ff057
			// Pentium 4 Xeon, Pentium 4 Xeon MP,
2ff057
			// Celeron, Mobile Celron                    (0.13um)
2ff057
	    case 3:	// Pentium 4, Celeron                        (0.09um)
2ff057
		return 1;
2ff057
	}
2ff057
    return 0;
2ff057
}
2ff057
2ff057
static int is_geode(void)
2ff057
{
2ff057
    unsigned int eax, ebx, ecx, edx, family, model;
2ff057
    char vendor[16];
2ff057
    memset(vendor, 0, sizeof(vendor));
2ff057
    
2ff057
    cpuid(0, &eax, &ebx, &ecx, &edx;;
2ff057
    memset(vendor, 0, sizeof(vendor));
2ff057
    *((unsigned int *)&vendor[0]) = ebx;
2ff057
    *((unsigned int *)&vendor[4]) = edx;
2ff057
    *((unsigned int *)&vendor[8]) = ecx;
2ff057
    if (!rstreqn(vendor, "AuthenticAMD", 12))
2ff057
        return 0;
2ff057
    cpuid(1, &eax, &ebx, &ecx, &edx;;
2ff057
    family = (eax >> 8) & 0x0f;
2ff057
    model = (eax >> 4) & 0x0f;
2ff057
    if (family == 5)
2ff057
	switch (model)
2ff057
	{
2ff057
            case 10: // Geode 
2ff057
                return 1;
2ff057
        }
2ff057
    return 0;
2ff057
}
2ff057
#endif
2ff057
2ff057
2ff057
#if defined(__linux__)
2ff057
/**
2ff057
 * Populate rpmat structure with auxv values
2ff057
 */
2ff057
static void read_auxv(void)
2ff057
{
2ff057
    static int oneshot = 1;
2ff057
2ff057
    if (oneshot) {
2ff057
#ifdef HAVE_GETAUXVAL
2ff057
	rpmat.platform = (char *) getauxval(AT_PLATFORM);
2ff057
	if (!rpmat.platform)
2ff057
	    rpmat.platform = "";
2ff057
	rpmat.hwcap = getauxval(AT_HWCAP);
2ff057
#else
2ff057
	rpmat.platform = "";
2ff057
	int fd = open("/proc/self/auxv", O_RDONLY);
2ff057
2ff057
	if (fd == -1) {
2ff057
	    rpmlog(RPMLOG_WARNING,
2ff057
		   _("Failed to read auxiliary vector, /proc not mounted?\n"));
2ff057
            return;
2ff057
	} else {
2ff057
	    ElfW(auxv_t) auxv;
2ff057
	    while (read(fd, &auxv, sizeof(auxv)) == sizeof(auxv)) {
2ff057
                switch (auxv.a_type)
2ff057
                {
2ff057
                    case AT_NULL:
2ff057
                        break;
2ff057
                    case AT_PLATFORM:
2ff057
                        rpmat.platform = strdup((char *) auxv.a_un.a_val);
2ff057
                        break;
2ff057
                    case AT_HWCAP:
2ff057
                        rpmat.hwcap = auxv.a_un.a_val;
2ff057
                        break;
2ff057
                }
2ff057
	    }
2ff057
	    close(fd);
2ff057
	}
2ff057
#endif
2ff057
	oneshot = 0; /* only try once even if it fails */
2ff057
    }
2ff057
    return;
2ff057
}
2ff057
#endif
2ff057
2ff057
/**
2ff057
 */
2ff057
static void defaultMachine(rpmrcCtx ctx, const char ** arch, const char ** os)
2ff057
{
2ff057
    const char * const platform_path = SYSCONFDIR "/rpm/platform";
2ff057
    static struct utsname un;
2ff057
    char * chptr;
2ff057
    canonEntry canon;
2ff057
    int rc;
2ff057
2ff057
#if defined(__linux__)
2ff057
    /* Populate rpmat struct with hw info */
2ff057
    read_auxv();
2ff057
#endif
2ff057
2ff057
    while (!ctx->machDefaults) {
2ff057
	if (!rpmPlatform(ctx, platform_path)) {
2ff057
	    char * s = rpmExpand("%{_host_cpu}", NULL);
2ff057
	    if (s) {
2ff057
		rstrlcpy(un.machine, s, sizeof(un.machine));
2ff057
		free(s);
2ff057
	    }
2ff057
	    s = rpmExpand("%{_host_os}", NULL);
2ff057
	    if (s) {
2ff057
		rstrlcpy(un.sysname, s, sizeof(un.sysname));
2ff057
		free(s);
2ff057
	    }
2ff057
	    ctx->machDefaults = 1;
2ff057
	    break;
2ff057
	}
2ff057
	rc = uname(&un;;
2ff057
	if (rc < 0) return;
2ff057
2ff057
#if !defined(__linux__)
2ff057
	if (rstreq(un.sysname, "AIX")) {
2ff057
	    strcpy(un.machine, __power_pc() ? "ppc" : "rs6000");
2ff057
	    sprintf(un.sysname,"aix%s.%s", un.version, un.release);
2ff057
	}
2ff057
	else if (rstreq(un.sysname, "Darwin")) { 
2ff057
#if defined(__ppc__)
2ff057
	    strcpy(un.machine, "ppc");
2ff057
#elif defined(__i386__)
2ff057
	    strcpy(un.machine, "i386");
2ff057
#elif defined(__x86_64__)
2ff057
	    strcpy(un.machine, "x86_64");
2ff057
#else
2ff057
	    #warning "No architecture defined! Automatic detection may not work!"
2ff057
#endif 
2ff057
	}
2ff057
	else if (rstreq(un.sysname, "SunOS")) {
2ff057
	    /* Solaris 2.x: n.x.x becomes n-3.x.x */
2ff057
	    sprintf(un.sysname, "solaris%1d%s", atoi(un.release)-3,
2ff057
		    un.release+1+(atoi(un.release)/10));
2ff057
2ff057
	    /* Solaris on Intel hardware reports i86pc instead of i386
2ff057
	     * (at least on 2.6 and 2.8)
2ff057
	     */
2ff057
	    if (rstreq(un.machine, "i86pc"))
2ff057
		sprintf(un.machine, "i386");
2ff057
	}
2ff057
	else if (rstreq(un.sysname, "HP-UX"))
2ff057
	    /*make un.sysname look like hpux9.05 for example*/
2ff057
	    sprintf(un.sysname, "hpux%s", strpbrk(un.release, "123456789"));
2ff057
	else if (rstreq(un.sysname, "OSF1"))
2ff057
	    /*make un.sysname look like osf3.2 for example*/
2ff057
	    sprintf(un.sysname, "osf%s", strpbrk(un.release, "123456789"));
2ff057
#endif	/* __linux__ */
2ff057
2ff057
	/* get rid of the hyphens in the sysname */
2ff057
	for (chptr = un.machine; *chptr != '\0'; chptr++)
2ff057
	    if (*chptr == '/') *chptr = '-';
2ff057
2ff057
#	if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL)
2ff057
	    /* little endian */
2ff057
#		if defined(__mips64)
2ff057
		    /* 64-bit */
2ff057
#			if !defined(__mips_isa_rev) || __mips_isa_rev < 6
2ff057
			    /* r1-r5 */
2ff057
			    strcpy(un.machine, "mips64el");
2ff057
#			else
2ff057
			    /* r6 */
2ff057
			    strcpy(un.machine, "mips64r6el");
2ff057
#			endif
2ff057
#		else
2ff057
		    /* 32-bit */
2ff057
#			if !defined(__mips_isa_rev) || __mips_isa_rev < 6
2ff057
			    /* r1-r5 */
2ff057
			    strcpy(un.machine, "mipsel");
2ff057
#			else
2ff057
			    /* r6 */
2ff057
			    strcpy(un.machine, "mipsr6el");
2ff057
#			endif
2ff057
#		endif
2ff057
#	elif defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB)
2ff057
	   /* big endian */
2ff057
#		if defined(__mips64)
2ff057
		    /* 64-bit */
2ff057
#			if !defined(__mips_isa_rev) || __mips_isa_rev < 6
2ff057
			    /* r1-r5 */
2ff057
			    strcpy(un.machine, "mips64");
2ff057
#			else
2ff057
			    /* r6 */
2ff057
			    strcpy(un.machine, "mips64r6");
2ff057
#			endif
2ff057
#		else
2ff057
		    /* 32-bit */
2ff057
#			if !defined(__mips_isa_rev) || __mips_isa_rev < 6
2ff057
			    /* r1-r5 */
2ff057
			    strcpy(un.machine, "mips");
2ff057
#			else
2ff057
			    /* r6 */
2ff057
			    strcpy(un.machine, "mipsr6");
2ff057
#			endif
2ff057
#		endif
2ff057
#	endif
2ff057
2ff057
#if defined(__linux__)
2ff057
	/* in linux, lets rename parisc to hppa */
2ff057
	if (rstreq(un.machine, "parisc"))
2ff057
	    strcpy(un.machine, "hppa");
2ff057
#endif
2ff057
2ff057
#	if defined(__hpux) && defined(_SC_CPU_VERSION)
2ff057
	{
2ff057
#	    if !defined(CPU_PA_RISC1_2)
2ff057
#                define CPU_PA_RISC1_2  0x211 /* HP PA-RISC1.2 */
2ff057
#           endif
2ff057
#           if !defined(CPU_PA_RISC2_0)
2ff057
#               define CPU_PA_RISC2_0  0x214 /* HP PA-RISC2.0 */
2ff057
#           endif
2ff057
	    int cpu_version = sysconf(_SC_CPU_VERSION);
2ff057
2ff057
#	    if defined(CPU_HP_MC68020)
2ff057
		if (cpu_version == CPU_HP_MC68020)
2ff057
		    strcpy(un.machine, "m68k");
2ff057
#	    endif
2ff057
#	    if defined(CPU_HP_MC68030)
2ff057
		if (cpu_version == CPU_HP_MC68030)
2ff057
		    strcpy(un.machine, "m68k");
2ff057
#	    endif
2ff057
#	    if defined(CPU_HP_MC68040)
2ff057
		if (cpu_version == CPU_HP_MC68040)
2ff057
		    strcpy(un.machine, "m68k");
2ff057
#	    endif
2ff057
2ff057
#	    if defined(CPU_PA_RISC1_0)
2ff057
		if (cpu_version == CPU_PA_RISC1_0)
2ff057
		    strcpy(un.machine, "hppa1.0");
2ff057
#	    endif
2ff057
#	    if defined(CPU_PA_RISC1_1)
2ff057
		if (cpu_version == CPU_PA_RISC1_1)
2ff057
		    strcpy(un.machine, "hppa1.1");
2ff057
#	    endif
2ff057
#	    if defined(CPU_PA_RISC1_2)
2ff057
		if (cpu_version == CPU_PA_RISC1_2)
2ff057
		    strcpy(un.machine, "hppa1.2");
2ff057
#	    endif
2ff057
#	    if defined(CPU_PA_RISC2_0)
2ff057
		if (cpu_version == CPU_PA_RISC2_0)
2ff057
		    strcpy(un.machine, "hppa2.0");
2ff057
#	    endif
2ff057
	}
2ff057
#	endif	/* hpux */
2ff057
2ff057
#	if defined(__linux__) && defined(__sparc__)
2ff057
#	if !defined(HWCAP_SPARC_BLKINIT)
2ff057
#	    define HWCAP_SPARC_BLKINIT	0x00000040
2ff057
#	endif
2ff057
	if (rstreq(un.machine, "sparc")) {
2ff057
	    #define PERS_LINUX		0x00000000
2ff057
	    #define PERS_LINUX_32BIT	0x00800000
2ff057
	    #define PERS_LINUX32	0x00000008
2ff057
2ff057
	    extern int personality(unsigned long);
2ff057
	    int oldpers;
2ff057
	    
2ff057
	    oldpers = personality(PERS_LINUX_32BIT);
2ff057
	    if (oldpers != -1) {
2ff057
		if (personality(PERS_LINUX) != -1) {
2ff057
		    uname(&un;;
2ff057
		    if (rstreq(un.machine, "sparc64")) {
2ff057
			strcpy(un.machine, "sparcv9");
2ff057
			oldpers = PERS_LINUX32;
2ff057
		    }
2ff057
		}
2ff057
		personality(oldpers);
2ff057
	    }
2ff057
2ff057
	    /* This is how glibc detects Niagara so... */
2ff057
	    if (rpmat.hwcap & HWCAP_SPARC_BLKINIT) {
2ff057
		if (rstreq(un.machine, "sparcv9") || rstreq(un.machine, "sparc")) {
2ff057
		    strcpy(un.machine, "sparcv9v");
2ff057
		} else if (rstreq(un.machine, "sparc64")) {
2ff057
		    strcpy(un.machine, "sparc64v");
2ff057
		}
2ff057
	    }
2ff057
	}
2ff057
#	endif	/* sparc*-linux */
2ff057
2ff057
#	if defined(__linux__) && defined(__powerpc__)
2ff057
#	if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
2ff057
	{
2ff057
            int powerlvl;
2ff057
            if (!rstreq(un.machine, "ppc") &&
2ff057
		    sscanf(rpmat.platform, "power%d", &powerlvl) == 1 &&
2ff057
		    powerlvl > 6) {
2ff057
                strcpy(un.machine, "ppc64p7");
2ff057
	    }
2ff057
        }
2ff057
#	endif	/* __ORDER_BIG_ENDIAN__ */
2ff057
#	endif	/* ppc64*-linux */
2ff057
2ff057
#	if defined(__linux__) && defined(__arm__) && defined(__ARM_PCS_VFP)
2ff057
#	if !defined(HWCAP_ARM_VFP)
2ff057
#	    define HWCAP_ARM_VFP	(1 << 6)
2ff057
#	endif
2ff057
#	if !defined(HWCAP_ARM_NEON)
2ff057
#	    define HWCAP_ARM_NEON	(1 << 12)
2ff057
#	endif
2ff057
#	if !defined(HWCAP_ARM_VFPv3)
2ff057
#	    define HWCAP_ARM_VFPv3	(1 << 13)
2ff057
#	endif
2ff057
	if (rstreq(un.machine, "armv7l")) {
2ff057
	    if (rpmat.hwcap & HWCAP_ARM_VFPv3) {
2ff057
		if (rpmat.hwcap & HWCAP_ARM_NEON)
2ff057
		    strcpy(un.machine, "armv7hnl");
2ff057
		else
2ff057
		    strcpy(un.machine, "armv7hl");
2ff057
	    }
2ff057
	} else if (rstreq(un.machine, "armv6l")) {
2ff057
	    if (rpmat.hwcap & HWCAP_ARM_VFP)
2ff057
		strcpy(un.machine, "armv6hl");
2ff057
	}
2ff057
#	endif	/* arm*-linux */
2ff057
2ff057
#	if defined(__linux__) && defined(__riscv__)
2ff057
	if (rstreq(un.machine, "riscv")) {
2ff057
		if (sizeof(long) == 4)
2ff057
			strcpy(un.machine, "riscv32");
2ff057
		else if (sizeof(long) == 8)
2ff057
			strcpy(un.machine, "riscv64");
2ff057
		else if (sizeof(long) == 16)
2ff057
			strcpy(un.machine, "riscv128");
2ff057
	}
2ff057
#	endif	/* riscv */
2ff057
2ff057
#	if defined(__GNUC__) && defined(__alpha__)
2ff057
	{
2ff057
	    unsigned long amask, implver;
2ff057
	    register long v0 __asm__("$0") = -1;
2ff057
	    __asm__ (".long 0x47e00c20" : "=r"(v0) : "0"(v0));
2ff057
	    amask = ~v0;
2ff057
	    __asm__ (".long 0x47e03d80" : "=r"(v0));
2ff057
	    implver = v0;
2ff057
	    switch (implver) {
2ff057
	    case 1:
2ff057
	    	switch (amask) {
2ff057
	    	case 0: strcpy(un.machine, "alphaev5"); break;
2ff057
	    	case 1: strcpy(un.machine, "alphaev56"); break;
2ff057
	    	case 0x101: strcpy(un.machine, "alphapca56"); break;
2ff057
	    	}
2ff057
	    	break;
2ff057
	    case 2:
2ff057
	    	switch (amask) {
2ff057
	    	case 0x303: strcpy(un.machine, "alphaev6"); break;
2ff057
	    	case 0x307: strcpy(un.machine, "alphaev67"); break;
2ff057
	    	}
2ff057
	    	break;
2ff057
	    }
2ff057
	}
2ff057
#	endif
2ff057
2ff057
#	if defined(__linux__) && defined(__i386__)
2ff057
	{
2ff057
	    char mclass = (char) (RPMClass() | '0');
2ff057
2ff057
	    if ((mclass == '6' && is_athlon()) || mclass == '7')
2ff057
	    	strcpy(un.machine, "athlon");
2ff057
	    else if (is_pentium4())
2ff057
		strcpy(un.machine, "pentium4");
2ff057
	    else if (is_pentium3())
2ff057
		strcpy(un.machine, "pentium3");
2ff057
	    else if (is_geode())
2ff057
		strcpy(un.machine, "geode");
2ff057
	    else if (strchr("3456", un.machine[1]) && un.machine[1] != mclass)
2ff057
		un.machine[1] = mclass;
2ff057
	}
2ff057
#	endif
2ff057
2ff057
	/* the uname() result goes through the arch_canon table */
2ff057
	canon = lookupInCanonTable(un.machine,
2ff057
			   ctx->tables[RPM_MACHTABLE_INSTARCH].canons,
2ff057
			   ctx->tables[RPM_MACHTABLE_INSTARCH].canonsLength);
2ff057
	if (canon)
2ff057
	    rstrlcpy(un.machine, canon->short_name, sizeof(un.machine));
2ff057
2ff057
	canon = lookupInCanonTable(un.sysname,
2ff057
			   ctx->tables[RPM_MACHTABLE_INSTOS].canons,
2ff057
			   ctx->tables[RPM_MACHTABLE_INSTOS].canonsLength);
2ff057
	if (canon)
2ff057
	    rstrlcpy(un.sysname, canon->short_name, sizeof(un.sysname));
2ff057
	ctx->machDefaults = 1;
2ff057
	break;
2ff057
    }
2ff057
2ff057
    if (arch) *arch = un.machine;
2ff057
    if (os) *os = un.sysname;
2ff057
}
2ff057
2ff057
static
2ff057
const char * rpmGetVarArch(rpmrcCtx ctx, int var, const char * arch)
2ff057
{
2ff057
    const struct rpmvarValue * next;
2ff057
2ff057
    if (arch == NULL) arch = ctx->current[ARCH];
2ff057
2ff057
    if (arch) {
2ff057
	next = &ctx->values[var];
2ff057
	while (next) {
2ff057
	    if (next->arch && rstreq(next->arch, arch)) return next->value;
2ff057
	    next = next->next;
2ff057
	}
2ff057
    }
2ff057
2ff057
    next = ctx->values + var;
2ff057
    while (next && next->arch) next = next->next;
2ff057
2ff057
    return next ? next->value : NULL;
2ff057
}
2ff057
2ff057
static void rpmSetVarArch(rpmrcCtx ctx,
2ff057
			  int var, const char * val, const char * arch)
2ff057
{
2ff057
    struct rpmvarValue * next = ctx->values + var;
2ff057
2ff057
    if (next->value) {
2ff057
	if (arch) {
2ff057
	    while (next->next) {
2ff057
		if (next->arch && rstreq(next->arch, arch)) break;
2ff057
		next = next->next;
2ff057
	    }
2ff057
	} else {
2ff057
	    while (next->next) {
2ff057
		if (!next->arch) break;
2ff057
		next = next->next;
2ff057
	    }
2ff057
	}
2ff057
2ff057
	if (next->arch && arch && rstreq(next->arch, arch)) {
2ff057
	    next->value = _free(next->value);
2ff057
	    next->arch = _free(next->arch);
2ff057
	} else if (next->arch || arch) {
2ff057
	    next->next = xmalloc(sizeof(*next->next));
2ff057
	    next = next->next;
2ff057
	    next->value = NULL;
2ff057
	    next->arch = NULL;
2ff057
	    next->next = NULL;
2ff057
	}
2ff057
    }
2ff057
2ff057
    next->value = _free(next->value);
2ff057
    next->value = xstrdup(val);
2ff057
    next->arch = (arch ? xstrdup(arch) : NULL);
2ff057
}
2ff057
2ff057
static void rpmSetTables(rpmrcCtx ctx, int archTable, int osTable)
2ff057
{
2ff057
    const char * arch, * os;
2ff057
2ff057
    defaultMachine(ctx, &arch, &os);
2ff057
2ff057
    if (ctx->currTables[ARCH] != archTable) {
2ff057
	ctx->currTables[ARCH] = archTable;
2ff057
	rebuildCompatTables(ctx, ARCH, arch);
2ff057
    }
2ff057
2ff057
    if (ctx->currTables[OS] != osTable) {
2ff057
	ctx->currTables[OS] = osTable;
2ff057
	rebuildCompatTables(ctx, OS, os);
2ff057
    }
2ff057
}
2ff057
2ff057
/** \ingroup rpmrc
2ff057
 * Set current arch/os names.
2ff057
 * NULL as argument is set to the default value (munged uname())
2ff057
 * pushed through a translation table (if appropriate).
2ff057
 * @deprecated Use addMacro to set _target_* macros.
2ff057
 * @todo Eliminate 
2ff057
 *
2ff057
 * @param ctx		rpmrc context
2ff057
 * @param arch          arch name (or NULL)
2ff057
 * @param os            os name (or NULL)
2ff057
 *          */
2ff057
2ff057
static void rpmSetMachine(rpmrcCtx ctx, const char * arch, const char * os)
2ff057
{
2ff057
    const char * host_cpu, * host_os;
2ff057
2ff057
    defaultMachine(ctx, &host_cpu, &host_os);
2ff057
2ff057
    if (arch == NULL) {
2ff057
	arch = host_cpu;
2ff057
	if (ctx->tables[ctx->currTables[ARCH]].hasTranslate)
2ff057
	    arch = lookupInDefaultTable(arch,
2ff057
			    ctx->tables[ctx->currTables[ARCH]].defaults,
2ff057
			    ctx->tables[ctx->currTables[ARCH]].defaultsLength);
2ff057
    }
2ff057
    if (arch == NULL) return;	/* XXX can't happen */
2ff057
2ff057
    if (os == NULL) {
2ff057
	os = host_os;
2ff057
	if (ctx->tables[ctx->currTables[OS]].hasTranslate)
2ff057
	    os = lookupInDefaultTable(os,
2ff057
			    ctx->tables[ctx->currTables[OS]].defaults,
2ff057
			    ctx->tables[ctx->currTables[OS]].defaultsLength);
2ff057
    }
2ff057
    if (os == NULL) return;	/* XXX can't happen */
2ff057
2ff057
    if (!ctx->current[ARCH] || !rstreq(arch, ctx->current[ARCH])) {
2ff057
	ctx->current[ARCH] = _free(ctx->current[ARCH]);
2ff057
	ctx->current[ARCH] = xstrdup(arch);
2ff057
	rebuildCompatTables(ctx, ARCH, host_cpu);
2ff057
    }
2ff057
2ff057
    if (!ctx->current[OS] || !rstreq(os, ctx->current[OS])) {
2ff057
	char * t = xstrdup(os);
2ff057
	ctx->current[OS] = _free(ctx->current[OS]);
2ff057
	/*
2ff057
	 * XXX Capitalizing the 'L' is needed to insure that old
2ff057
	 * XXX os-from-uname (e.g. "Linux") is compatible with the new
2ff057
	 * XXX os-from-platform (e.g "linux" from "sparc-*-linux").
2ff057
	 * XXX A copy of this string is embedded in headers and is
2ff057
	 * XXX used by rpmInstallPackage->{os,arch}Okay->rpmMachineScore->
2ff057
	 * XXX to verify correct arch/os from headers.
2ff057
	 */
2ff057
	if (rstreq(t, "linux"))
2ff057
	    *t = 'L';
2ff057
	ctx->current[OS] = t;
2ff057
	
2ff057
	rebuildCompatTables(ctx, OS, host_os);
2ff057
    }
2ff057
}
2ff057
2ff057
static void rebuildCompatTables(rpmrcCtx ctx, int type, const char * name)
2ff057
{
2ff057
    machFindEquivs(&ctx->tables[ctx->currTables[type]].cache,
2ff057
		   &ctx->tables[ctx->currTables[type]].equiv,
2ff057
		   name);
2ff057
}
2ff057
2ff057
static void getMachineInfo(rpmrcCtx ctx,
2ff057
			   int type, const char ** name, int * num)
2ff057
{
2ff057
    canonEntry canon;
2ff057
    int which = ctx->currTables[type];
2ff057
2ff057
    /* use the normal canon tables, even if we're looking up build stuff */
2ff057
    if (which >= 2) which -= 2;
2ff057
2ff057
    canon = lookupInCanonTable(ctx->current[type],
2ff057
			       ctx->tables[which].canons,
2ff057
			       ctx->tables[which].canonsLength);
2ff057
2ff057
    if (canon) {
2ff057
	if (num) *num = canon->num;
2ff057
	if (name) *name = canon->short_name;
2ff057
    } else {
2ff057
	if (num) *num = 255;
2ff057
	if (name) *name = ctx->current[type];
2ff057
2ff057
	if (ctx->tables[ctx->currTables[type]].hasCanon) {
2ff057
	    rpmlog(RPMLOG_WARNING, _("Unknown system: %s\n"),
2ff057
		   ctx->current[type]);
2ff057
	    rpmlog(RPMLOG_WARNING, _("Please contact %s\n"), PACKAGE_BUGREPORT);
2ff057
	}
2ff057
    }
2ff057
}
2ff057
2ff057
static void rpmRebuildTargetVars(rpmrcCtx ctx,
2ff057
			const char ** target, const char ** canontarget)
2ff057
{
2ff057
2ff057
    char *ca = NULL, *co = NULL, *ct = NULL;
2ff057
    int x;
2ff057
2ff057
    /* Rebuild the compat table to recalculate the current target arch.  */
2ff057
2ff057
    rpmSetMachine(ctx, NULL, NULL);
2ff057
    rpmSetTables(ctx, RPM_MACHTABLE_INSTARCH, RPM_MACHTABLE_INSTOS);
2ff057
    rpmSetTables(ctx, RPM_MACHTABLE_BUILDARCH, RPM_MACHTABLE_BUILDOS);
2ff057
2ff057
    if (target && *target) {
2ff057
	char *c;
2ff057
	/* Set arch and os from specified build target */
2ff057
	ca = xstrdup(*target);
2ff057
	if ((c = strchr(ca, '-')) != NULL) {
2ff057
	    *c++ = '\0';
2ff057
	    
2ff057
	    if ((co = strrchr(c, '-')) == NULL) {
2ff057
		co = c;
2ff057
	    } else {
2ff057
		if (!rstrcasecmp(co, "-gnu"))
2ff057
		    *co = '\0';
2ff057
		if ((co = strrchr(c, '-')) == NULL)
2ff057
		    co = c;
2ff057
		else
2ff057
		    co++;
2ff057
	    }
2ff057
	    if (co != NULL) co = xstrdup(co);
2ff057
	}
2ff057
    } else {
2ff057
	const char *a = NULL;
2ff057
	const char *o = NULL;
2ff057
	/* Set build target from rpm arch and os */
2ff057
	getMachineInfo(ctx, ARCH, &a, NULL);
2ff057
	ca = (a) ? xstrdup(a) : NULL;
2ff057
	getMachineInfo(ctx, OS, &o, NULL);
2ff057
	co = (o) ? xstrdup(o) : NULL;
2ff057
    }
2ff057
2ff057
    /* If still not set, Set target arch/os from default uname(2) values */
2ff057
    if (ca == NULL) {
2ff057
	const char *a = NULL;
2ff057
	defaultMachine(ctx, &a, NULL);
2ff057
	ca = xstrdup(a ? a : "(arch)");
2ff057
    }
2ff057
    for (x = 0; ca[x] != '\0'; x++)
2ff057
	ca[x] = rtolower(ca[x]);
2ff057
2ff057
    if (co == NULL) {
2ff057
	const char *o = NULL;
2ff057
	defaultMachine(ctx, NULL, &o);
2ff057
	co = xstrdup(o ? o : "(os)");
2ff057
    }
2ff057
    for (x = 0; co[x] != '\0'; x++)
2ff057
	co[x] = rtolower(co[x]);
2ff057
2ff057
    /* XXX For now, set canonical target to arch-os */
2ff057
    if (ct == NULL) {
2ff057
	rasprintf(&ct, "%s-%s", ca, co);
2ff057
    }
2ff057
2ff057
/*
2ff057
 * XXX All this macro pokery/jiggery could be achieved by doing a delayed
2ff057
 *	rpmInitMacros(NULL, PER-PLATFORM-MACRO-FILE-NAMES);
2ff057
 */
2ff057
    rpmPopMacro(NULL, "_target");
2ff057
    rpmPushMacro(NULL, "_target", NULL, ct, RMIL_RPMRC);
2ff057
    rpmPopMacro(NULL, "_target_cpu");
2ff057
    rpmPushMacro(NULL, "_target_cpu", NULL, ca, RMIL_RPMRC);
2ff057
    rpmPopMacro(NULL, "_target_os");
2ff057
    rpmPushMacro(NULL, "_target_os", NULL, co, RMIL_RPMRC);
2ff057
/*
2ff057
 * XXX Make sure that per-arch optflags is initialized correctly.
2ff057
 */
2ff057
  { const char *optflags = rpmGetVarArch(ctx, RPMVAR_OPTFLAGS, ca);
2ff057
    if (optflags != NULL) {
2ff057
	rpmPopMacro(NULL, "optflags");
2ff057
	rpmPushMacro(NULL, "optflags", NULL, optflags, RMIL_RPMRC);
2ff057
    }
2ff057
  }
2ff057
2ff057
    if (canontarget)
2ff057
	*canontarget = ct;
2ff057
    else
2ff057
	free(ct);
2ff057
    free(ca);
2ff057
    free(co);
2ff057
}
2ff057
2ff057
/** \ingroup rpmrc
2ff057
 * Read rpmrc (and macro) configuration file(s).
2ff057
 * @param ctx		rpmrc context
2ff057
 * @param rcfiles	colon separated files to read (NULL uses default)
2ff057
 * @return		RPMRC_OK on success
2ff057
 */
2ff057
static rpmRC rpmReadRC(rpmrcCtx ctx, const char * rcfiles)
2ff057
{
2ff057
    ARGV_t p, globs = NULL, files = NULL;
2ff057
    rpmRC rc = RPMRC_FAIL;
2ff057
2ff057
    if (!ctx->pathDefaults) {
2ff057
	setDefaults();
2ff057
	ctx->pathDefaults = 1;
2ff057
    }
2ff057
2ff057
    if (rcfiles == NULL)
2ff057
	rcfiles = defrcfiles;
2ff057
2ff057
    /* Expand any globs in rcfiles. Missing files are ok here. */
2ff057
    argvSplit(&globs, rcfiles, ":");
2ff057
    for (p = globs; *p; p++) {
2ff057
	ARGV_t av = NULL;
2ff057
	if (rpmGlob(*p, NULL, &av) == 0) {
2ff057
	    argvAppend(&files, av);
2ff057
	    argvFree(av);
2ff057
	}
2ff057
    }
2ff057
    argvFree(globs);
2ff057
2ff057
    /* Read each file in rcfiles. */
2ff057
    for (p = files; p && *p; p++) {
2ff057
	/* XXX Only /usr/lib/rpm/rpmrc must exist in default rcfiles list */
2ff057
	if (access(*p, R_OK) != 0) {
2ff057
	    if (rcfiles == defrcfiles && p != files)
2ff057
		continue;
2ff057
	    rpmlog(RPMLOG_ERR, _("Unable to open %s for reading: %m.\n"), *p);
2ff057
	    goto exit;
2ff057
	    break;
2ff057
	} else {
2ff057
	    rc = doReadRC(ctx, *p);
2ff057
	}
2ff057
    }
2ff057
    rc = RPMRC_OK;
2ff057
    rpmSetMachine(ctx, NULL, NULL);	/* XXX WTFO? Why bother? */
2ff057
2ff057
exit:
2ff057
    argvFree(files);
2ff057
    return rc;
2ff057
}
2ff057
2ff057
static void register_atexit(void)
2ff057
{
2ff057
    if (atexit(rpmAtExit) != 0)
2ff057
	rpmlog(RPMLOG_WARNING, _("failed to register exit handler"));
2ff057
}
2ff057
2ff057
/* External interfaces */
2ff057
2ff057
int rpmReadConfigFiles(const char * file, const char * target)
2ff057
{
2ff057
    static pthread_once_t atexit_registered = PTHREAD_ONCE_INIT;
2ff057
    int rc = -1; /* assume failure */
2ff057
    rpmrcCtx ctx = rpmrcCtxAcquire(1);
2ff057
2ff057
    pthread_once(&atexit_registered, register_atexit);
2ff057
2ff057
    /* Force preloading of dlopen()'ed libraries in case we go chrooting */
2ff057
    if (rpmugInit())
2ff057
	goto exit;
2ff057
2ff057
    if (rpmInitCrypto())
2ff057
	goto exit;
2ff057
2ff057
    /* Preset target macros */
2ff057
   	/* FIX: target can be NULL */
2ff057
    rpmRebuildTargetVars(ctx, &target, NULL);
2ff057
2ff057
    /* Read the files */
2ff057
    if (rpmReadRC(ctx, file))
2ff057
	goto exit;
2ff057
2ff057
    if (macrofiles != NULL) {
2ff057
	char *mf = rpmGetPath(macrofiles, NULL);
2ff057
	rpmInitMacros(NULL, mf);
2ff057
	_free(mf);
2ff057
    }
2ff057
2ff057
    /* Reset target macros */
2ff057
    rpmRebuildTargetVars(ctx, &target, NULL);
2ff057
2ff057
    /* Finally set target platform */
2ff057
    {	char *cpu = rpmExpand("%{_target_cpu}", NULL);
2ff057
	char *os = rpmExpand("%{_target_os}", NULL);
2ff057
	rpmSetMachine(ctx, cpu, os);
2ff057
	free(cpu);
2ff057
	free(os);
2ff057
    }
2ff057
2ff057
#ifdef WITH_LUA
2ff057
    /* Force Lua state initialization */
2ff057
    rpmLuaInit();
2ff057
#endif
2ff057
    rc = 0;
2ff057
2ff057
exit:
2ff057
    rpmrcCtxRelease(ctx);
2ff057
    return rc;
2ff057
}
2ff057
2ff057
void rpmFreeRpmrc(void)
2ff057
{
2ff057
    rpmrcCtx ctx = rpmrcCtxAcquire(1);
2ff057
    int i, j, k;
2ff057
2ff057
    ctx->platpat = argvFree(ctx->platpat);
2ff057
2ff057
    for (i = 0; i < RPM_MACHTABLE_COUNT; i++) {
2ff057
	tableType t;
2ff057
	t = ctx->tables + i;
2ff057
	if (t->equiv.list) {
2ff057
	    for (j = 0; j < t->equiv.count; j++)
2ff057
		t->equiv.list[j].name = _free(t->equiv.list[j].name);
2ff057
	    t->equiv.list = _free(t->equiv.list);
2ff057
	    t->equiv.count = 0;
2ff057
	}
2ff057
	if (t->cache.cache) {
2ff057
	    for (j = 0; j < t->cache.size; j++) {
2ff057
		machCacheEntry e;
2ff057
		e = t->cache.cache + j;
2ff057
		if (e == NULL)
2ff057
		    continue;
2ff057
		e->name = _free(e->name);
2ff057
		if (e->equivs) {
2ff057
		    for (k = 0; k < e->count; k++)
2ff057
			e->equivs[k] = _free(e->equivs[k]);
2ff057
		    e->equivs = _free(e->equivs);
2ff057
		}
2ff057
	    }
2ff057
	    t->cache.cache = _free(t->cache.cache);
2ff057
	    t->cache.size = 0;
2ff057
	}
2ff057
	if (t->defaults) {
2ff057
	    for (j = 0; j < t->defaultsLength; j++) {
2ff057
		t->defaults[j].name = _free(t->defaults[j].name);
2ff057
		t->defaults[j].defName = _free(t->defaults[j].defName);
2ff057
	    }
2ff057
	    t->defaults = _free(t->defaults);
2ff057
	    t->defaultsLength = 0;
2ff057
	}
2ff057
	if (t->canons) {
2ff057
	    for (j = 0; j < t->canonsLength; j++) {
2ff057
		t->canons[j].name = _free(t->canons[j].name);
2ff057
		t->canons[j].short_name = _free(t->canons[j].short_name);
2ff057
	    }
2ff057
	    t->canons = _free(t->canons);
2ff057
	    t->canonsLength = 0;
2ff057
	}
2ff057
    }
2ff057
2ff057
    for (i = 0; i < RPMVAR_NUM; i++) {
2ff057
	struct rpmvarValue * vp;
2ff057
	while ((vp = ctx->values[i].next) != NULL) {
2ff057
	    ctx->values[i].next = vp->next;
2ff057
	    vp->value = _free(vp->value);
2ff057
	    vp->arch = _free(vp->arch);
2ff057
	    vp = _free(vp);
2ff057
	}
2ff057
	ctx->values[i].value = _free(ctx->values[i].value);
2ff057
	ctx->values[i].arch = _free(ctx->values[i].arch);
2ff057
    }
2ff057
    ctx->current[OS] = _free(ctx->current[OS]);
2ff057
    ctx->current[ARCH] = _free(ctx->current[ARCH]);
2ff057
    ctx->machDefaults = 0;
2ff057
    ctx->pathDefaults = 0;
2ff057
2ff057
    /* XXX doesn't really belong here but... */
2ff057
    rpmFreeCrypto();
2ff057
#ifdef WITH_LUA
2ff057
    rpmLuaFree();
2ff057
#endif
2ff057
2ff057
    rpmrcCtxRelease(ctx);
2ff057
    return;
2ff057
}
2ff057
2ff057
int rpmShowRC(FILE * fp)
2ff057
{
2ff057
    /* Write-context necessary as this calls rpmSetTables(), ugh */
2ff057
    rpmrcCtx ctx = rpmrcCtxAcquire(1);
2ff057
    const struct rpmOption *opt;
2ff057
    rpmds ds = NULL;
2ff057
    int i;
2ff057
    machEquivTable equivTable;
2ff057
2ff057
    /* the caller may set the build arch which should be printed here */
2ff057
    fprintf(fp, "ARCHITECTURE AND OS:\n");
2ff057
    fprintf(fp, "build arch            : %s\n", ctx->current[ARCH]);
2ff057
2ff057
    fprintf(fp, "compatible build archs:");
2ff057
    equivTable = &ctx->tables[RPM_MACHTABLE_BUILDARCH].equiv;
2ff057
    for (i = 0; i < equivTable->count; i++)
2ff057
	fprintf(fp," %s", equivTable->list[i].name);
2ff057
    fprintf(fp, "\n");
2ff057
2ff057
    fprintf(fp, "build os              : %s\n", ctx->current[OS]);
2ff057
2ff057
    fprintf(fp, "compatible build os's :");
2ff057
    equivTable = &ctx->tables[RPM_MACHTABLE_BUILDOS].equiv;
2ff057
    for (i = 0; i < equivTable->count; i++)
2ff057
	fprintf(fp," %s", equivTable->list[i].name);
2ff057
    fprintf(fp, "\n");
2ff057
2ff057
    rpmSetTables(ctx, RPM_MACHTABLE_INSTARCH, RPM_MACHTABLE_INSTOS);
2ff057
    rpmSetMachine(ctx, NULL, NULL);	/* XXX WTFO? Why bother? */
2ff057
2ff057
    fprintf(fp, "install arch          : %s\n", ctx->current[ARCH]);
2ff057
    fprintf(fp, "install os            : %s\n", ctx->current[OS]);
2ff057
2ff057
    fprintf(fp, "compatible archs      :");
2ff057
    equivTable = &ctx->tables[RPM_MACHTABLE_INSTARCH].equiv;
2ff057
    for (i = 0; i < equivTable->count; i++)
2ff057
	fprintf(fp," %s", equivTable->list[i].name);
2ff057
    fprintf(fp, "\n");
2ff057
2ff057
    fprintf(fp, "compatible os's       :");
2ff057
    equivTable = &ctx->tables[RPM_MACHTABLE_INSTOS].equiv;
2ff057
    for (i = 0; i < equivTable->count; i++)
2ff057
	fprintf(fp," %s", equivTable->list[i].name);
2ff057
    fprintf(fp, "\n");
2ff057
2ff057
    fprintf(fp, "\nRPMRC VALUES:\n");
2ff057
    for (i = 0, opt = optionTable; i < optionTableSize; i++, opt++) {
2ff057
	const char *s = rpmGetVarArch(ctx, opt->var, NULL);
2ff057
	if (s != NULL || rpmIsVerbose())
2ff057
	    fprintf(fp, "%-21s : %s\n", opt->name, s ? s : "(not set)");
2ff057
    }
2ff057
    fprintf(fp, "\n");
2ff057
2ff057
    fprintf(fp, "Features supported by rpmlib:\n");
2ff057
    rpmdsRpmlib(&ds, NULL);
2ff057
    ds = rpmdsInit(ds);
2ff057
    while (rpmdsNext(ds) >= 0) {
2ff057
        const char * DNEVR = rpmdsDNEVR(ds);
2ff057
        if (DNEVR != NULL)
2ff057
            fprintf(fp, "    %s\n", DNEVR+2);
2ff057
    }
2ff057
    ds = rpmdsFree(ds);
2ff057
    fprintf(fp, "\n");
2ff057
2ff057
    fprintf(fp, "Macro path: %s\n", macrofiles);
2ff057
    fprintf(fp, "\n");
2ff057
2ff057
    rpmDumpMacroTable(NULL, fp);
2ff057
2ff057
    /* XXX: Move this earlier eventually... */
2ff057
    rpmrcCtxRelease(ctx);
2ff057
2ff057
    return 0;
2ff057
}
2ff057
2ff057
int rpmMachineScore(int type, const char * name)
2ff057
{
2ff057
    int score = 0;
2ff057
    if (name) {
2ff057
	rpmrcCtx ctx = rpmrcCtxAcquire(0);
2ff057
	machEquivInfo info = machEquivSearch(&ctx->tables[type].equiv, name);
2ff057
	if (info)
2ff057
	    score = info->score;
2ff057
	rpmrcCtxRelease(ctx);
2ff057
    }
2ff057
    return score;
2ff057
}
2ff057
2ff057
int rpmIsKnownArch(const char *name)
2ff057
{
2ff057
    rpmrcCtx ctx = rpmrcCtxAcquire(0);
2ff057
    canonEntry canon = lookupInCanonTable(name,
2ff057
			    ctx->tables[RPM_MACHTABLE_INSTARCH].canons,
2ff057
			    ctx->tables[RPM_MACHTABLE_INSTARCH].canonsLength);
2ff057
    int known = (canon != NULL || rstreq(name, "noarch"));
2ff057
    rpmrcCtxRelease(ctx);
2ff057
    return known;
2ff057
}
2ff057
2ff057
void rpmGetArchInfo(const char ** name, int * num)
2ff057
{
2ff057
    rpmrcCtx ctx = rpmrcCtxAcquire(0);
2ff057
    getMachineInfo(ctx, ARCH, name, num);
2ff057
    rpmrcCtxRelease(ctx);
2ff057
}
2ff057
2ff057
int rpmGetArchColor(const char *arch)
2ff057
{
2ff057
    rpmrcCtx ctx = rpmrcCtxAcquire(0);
2ff057
    const char *color;
2ff057
    char *e;
2ff057
    int color_i = -1; /* assume failure */
2ff057
2ff057
    arch = lookupInDefaultTable(arch,
2ff057
			    ctx->tables[ctx->currTables[ARCH]].defaults,
2ff057
			    ctx->tables[ctx->currTables[ARCH]].defaultsLength);
2ff057
    color = rpmGetVarArch(ctx, RPMVAR_ARCHCOLOR, arch);
2ff057
    if (color) {
2ff057
	color_i = strtol(color, &e, 10);
2ff057
	if (!(e && *e == '\0')) {
2ff057
	    color_i = -1;
2ff057
	}
2ff057
    }
2ff057
    rpmrcCtxRelease(ctx);
2ff057
2ff057
    return color_i;
2ff057
}
2ff057
2ff057
void rpmGetOsInfo(const char ** name, int * num)
2ff057
{
2ff057
    rpmrcCtx ctx = rpmrcCtxAcquire(0);
2ff057
    getMachineInfo(ctx, OS, name, num);
2ff057
    rpmrcCtxRelease(ctx);
2ff057
}
2ff057