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