1 #include "system.h"
2 
3 #include <fcntl.h>
4 #include <stdarg.h>
5 #include <pthread.h>
6 
7 #if defined(__linux__)
8 #include <elf.h>
9 #include <link.h>
10 #endif
11 
12 
13 #if HAVE_SYS_UTSNAME_H
14 #include <sys/utsname.h>
15 #endif
16 #include <ctype.h>	/* XXX for /etc/rpm/platform contents */
17 
18 #if HAVE_SYS_SYSTEMCFG_H
19 #include <sys/systemcfg.h>
20 #else
21 #define __power_pc() 0
22 #endif
23 
24 #ifdef HAVE_SYS_AUXV_H
25 #include <sys/auxv.h>
26 #endif
27 
28 #include <rpm/rpmlib.h>			/* RPM_MACTABLE*, Rc-prototypes */
29 #include <rpm/rpmmacro.h>
30 #include <rpm/rpmfileutil.h>
31 #include <rpm/rpmstring.h>
32 #include <rpm/rpmlog.h>
33 #include <rpm/argv.h>
34 
35 #include "rpmio/rpmlua.h"
36 #include "rpmio/rpmio_internal.h"	/* XXX for rpmioSlurp */
37 #include "lib/misc.h"
38 
39 #include "debug.h"
40 
41 static const char * defrcfiles = NULL;
42 const char * macrofiles = NULL;
43 
44 typedef struct machCacheEntry_s {
45     char * name;
46     int count;
47     char ** equivs;
48     int visited;
49 } * machCacheEntry;
50 
51 typedef struct machCache_s {
52     machCacheEntry cache;
53     int size;
54 } * machCache;
55 
56 typedef struct machEquivInfo_s {
57     char * name;
58     int score;
59 } * machEquivInfo;
60 
61 typedef struct machEquivTable_s {
62     int count;
63     machEquivInfo list;
64 } * machEquivTable;
65 
66 struct rpmvarValue {
67     char * value;
68     /* eventually, this arch will be replaced with a generic condition */
69     char * arch;
70 struct rpmvarValue * next;
71 };
72 
73 struct rpmOption {
74     char * name;
75     int var;
76     int archSpecific;
77     int macroize;
78     int localize;
79 };
80 
81 static struct rpmat_s {
82     const char *platform;
83     uint64_t hwcap;
84 } rpmat;
85 
86 typedef struct defaultEntry_s {
87     char * name;
88     char * defName;
89 } * defaultEntry;
90 
91 typedef struct canonEntry_s {
92     char * name;
93     char * short_name;
94     short num;
95 } * canonEntry;
96 
97 /* tags are 'key'canon, 'key'translate, 'key'compat
98  *
99  * for giggles, 'key'_canon, 'key'_compat, and 'key'_canon will also work
100  */
101 typedef struct tableType_s {
102     char * const key;
103     const int hasCanon;
104     const int hasTranslate;
105     struct machEquivTable_s equiv;
106     struct machCache_s cache;
107     defaultEntry defaults;
108     canonEntry canons;
109     int defaultsLength;
110     int canonsLength;
111 } * tableType;
112 
113 /* XXX get rid of this stuff... */
114 /* Stuff for maintaining "variables" like SOURCEDIR, BUILDDIR, etc */
115 #define RPMVAR_OPTFLAGS                 3
116 #define RPMVAR_ARCHCOLOR                42
117 #define RPMVAR_INCLUDE                  43
118 #define RPMVAR_MACROFILES               49
119 
120 #define RPMVAR_NUM                      55      /* number of RPMVAR entries */
121 
122 /* this *must* be kept in alphabetical order */
123 /* The order of the flags is archSpecific, macroize, localize */
124 
125 static const struct rpmOption optionTable[] = {
126     { "archcolor",		RPMVAR_ARCHCOLOR,               1, 0, 0 },
127     { "include",		RPMVAR_INCLUDE,			0, 0, 2 },
128     { "macrofiles",		RPMVAR_MACROFILES,		0, 0, 1 },
129     { "optflags",		RPMVAR_OPTFLAGS,		1, 1, 0 },
130 };
131 
132 static const size_t optionTableSize = sizeof(optionTable) / sizeof(*optionTable);
133 
134 #define OS	0
135 #define ARCH	1
136 
137 typedef struct rpmrcCtx_s * rpmrcCtx;
138 struct rpmrcCtx_s {
139     ARGV_t platpat;
140     char *current[2];
141     int currTables[2];
142     struct rpmvarValue values[RPMVAR_NUM];
143     struct tableType_s tables[RPM_MACHTABLE_COUNT];
144     int machDefaults;
145     int pathDefaults;
146     pthread_rwlock_t lock;
147 };
148 
149 /* prototypes */
150 static rpmRC doReadRC(rpmrcCtx ctx, const char * urlfn);
151 
152 static void rpmSetVarArch(rpmrcCtx ctx,
153 			  int var, const char * val, const char * arch);
154 
155 static void rebuildCompatTables(rpmrcCtx ctx, int type, const char * name);
156 
157 static void rpmRebuildTargetVars(rpmrcCtx ctx, const char **target, const char ** canontarget);
158 
159 /* Force context (lock) acquisition through a function */
rpmrcCtxAcquire(int write)160 static rpmrcCtx rpmrcCtxAcquire(int write)
161 {
162     static struct rpmrcCtx_s _globalCtx = {
163 	.lock = PTHREAD_RWLOCK_INITIALIZER,
164 	.currTables = { RPM_MACHTABLE_INSTOS, RPM_MACHTABLE_INSTARCH },
165 	.tables = {
166 	    { "arch", 1, 0 },
167 	    { "os", 1, 0 },
168 	    { "buildarch", 0, 1 },
169 	    { "buildos", 0, 1 }
170 	},
171     };
172     rpmrcCtx ctx = &_globalCtx;
173 
174     /* XXX: errors should be handled */
175     if (write)
176 	pthread_rwlock_wrlock(&ctx->lock);
177     else
178 	pthread_rwlock_rdlock(&ctx->lock);
179 
180     return ctx;
181 }
182 
183 /* Release context (lock) */
rpmrcCtxRelease(rpmrcCtx ctx)184 static rpmrcCtx rpmrcCtxRelease(rpmrcCtx ctx)
185 {
186     pthread_rwlock_unlock(&ctx->lock);
187     return NULL;
188 }
189 
optionCompare(const void * a,const void * b)190 static int optionCompare(const void * a, const void * b)
191 {
192     return rstrcasecmp(((const struct rpmOption *) a)->name,
193 		      ((const struct rpmOption *) b)->name);
194 }
195 
196 static machCacheEntry
machCacheFindEntry(const machCache cache,const char * key)197 machCacheFindEntry(const machCache cache, const char * key)
198 {
199     int i;
200 
201     for (i = 0; i < cache->size; i++)
202 	if (rstreq(cache->cache[i].name, key)) return cache->cache + i;
203 
204     return NULL;
205 }
206 
machCompatCacheAdd(char * name,const char * fn,int linenum,machCache cache)207 static int machCompatCacheAdd(char * name, const char * fn, int linenum,
208 				machCache cache)
209 {
210     machCacheEntry entry = NULL;
211     char * chptr;
212     char * equivs;
213     int delEntry = 0;
214     int i;
215 
216     while (*name && risspace(*name)) name++;
217 
218     chptr = name;
219     while (*chptr && *chptr != ':') chptr++;
220     if (!*chptr) {
221 	rpmlog(RPMLOG_ERR, _("missing second ':' at %s:%d\n"), fn, linenum);
222 	return 1;
223     } else if (chptr == name) {
224 	rpmlog(RPMLOG_ERR, _("missing architecture name at %s:%d\n"), fn,
225 			     linenum);
226 	return 1;
227     }
228 
229     while (*chptr == ':' || risspace(*chptr)) chptr--;
230     *(++chptr) = '\0';
231     equivs = chptr + 1;
232     while (*equivs && risspace(*equivs)) equivs++;
233     if (!*equivs) {
234 	delEntry = 1;
235     }
236 
237     if (cache->size) {
238 	entry = machCacheFindEntry(cache, name);
239 	if (entry) {
240 	    for (i = 0; i < entry->count; i++)
241 		entry->equivs[i] = _free(entry->equivs[i]);
242 	    entry->equivs = _free(entry->equivs);
243 	    entry->count = 0;
244 	}
245     }
246 
247     if (!entry) {
248 	cache->cache = xrealloc(cache->cache,
249 			       (cache->size + 1) * sizeof(*cache->cache));
250 	entry = cache->cache + cache->size++;
251 	entry->name = xstrdup(name);
252 	entry->count = 0;
253 	entry->visited = 0;
254     }
255 
256     if (delEntry) return 0;
257 
258     while ((chptr = strtok(equivs, " ")) != NULL) {
259 	equivs = NULL;
260 	if (chptr[0] == '\0')	/* does strtok() return "" ever?? */
261 	    continue;
262 	if (entry->count)
263 	    entry->equivs = xrealloc(entry->equivs, sizeof(*entry->equivs)
264 					* (entry->count + 1));
265 	else
266 	    entry->equivs = xmalloc(sizeof(*entry->equivs));
267 
268 	entry->equivs[entry->count] = xstrdup(chptr);
269 	entry->count++;
270     }
271 
272     return 0;
273 }
274 
275 static machEquivInfo
machEquivSearch(const machEquivTable table,const char * name)276 machEquivSearch(const machEquivTable table, const char * name)
277 {
278     int i;
279 
280     for (i = 0; i < table->count; i++)
281 	if (!rstrcasecmp(table->list[i].name, name))
282 	    return table->list + i;
283 
284     return NULL;
285 }
286 
machAddEquiv(machEquivTable table,const char * name,int distance)287 static void machAddEquiv(machEquivTable table, const char * name,
288 			   int distance)
289 {
290     machEquivInfo equiv;
291 
292     equiv = machEquivSearch(table, name);
293     if (!equiv) {
294 	if (table->count)
295 	    table->list = xrealloc(table->list, (table->count + 1)
296 				    * sizeof(*table->list));
297 	else
298 	    table->list = xmalloc(sizeof(*table->list));
299 
300 	table->list[table->count].name = xstrdup(name);
301 	table->list[table->count++].score = distance;
302     }
303 }
304 
machCacheEntryVisit(machCache cache,machEquivTable table,const char * name,int distance)305 static void machCacheEntryVisit(machCache cache,
306 		machEquivTable table, const char * name, int distance)
307 {
308     machCacheEntry entry;
309     int i;
310 
311     entry = machCacheFindEntry(cache, name);
312     if (!entry || entry->visited) return;
313 
314     entry->visited = 1;
315 
316     for (i = 0; i < entry->count; i++) {
317 	machAddEquiv(table, entry->equivs[i], distance);
318     }
319 
320     for (i = 0; i < entry->count; i++) {
321 	machCacheEntryVisit(cache, table, entry->equivs[i], distance + 1);
322     }
323 }
324 
machFindEquivs(machCache cache,machEquivTable table,const char * key)325 static void machFindEquivs(machCache cache, machEquivTable table,
326 		const char * key)
327 {
328     int i;
329 
330     for (i = 0; i < cache->size; i++)
331 	cache->cache[i].visited = 0;
332 
333     while (table->count > 0) {
334 	--table->count;
335 	table->list[table->count].name = _free(table->list[table->count].name);
336     }
337     table->count = 0;
338     table->list = _free(table->list);
339 
340     /*
341      *	We have a general graph built using strings instead of pointers.
342      *	Yuck. We have to start at a point at traverse it, remembering how
343      *	far away everything is.
344      */
345    	/* FIX: table->list may be NULL. */
346     machAddEquiv(table, key, 1);
347     machCacheEntryVisit(cache, table, key, 2);
348     return;
349 }
350 
addCanon(canonEntry * table,int * tableLen,char * line,const char * fn,int lineNum)351 static rpmRC addCanon(canonEntry * table, int * tableLen, char * line,
352 		    const char * fn, int lineNum)
353 {
354     canonEntry t;
355     char *s, *s1;
356     const char * tname;
357     const char * tshort_name;
358     int tnum;
359 
360     (*tableLen) += 2;
361     *table = xrealloc(*table, sizeof(**table) * (*tableLen));
362 
363     t = & ((*table)[*tableLen - 2]);
364 
365     tname = strtok(line, ": \t");
366     tshort_name = strtok(NULL, " \t");
367     s = strtok(NULL, " \t");
368     if (! (tname && tshort_name && s)) {
369 	rpmlog(RPMLOG_ERR, _("Incomplete data line at %s:%d\n"),
370 		fn, lineNum);
371 	return RPMRC_FAIL;
372     }
373     if (strtok(NULL, " \t")) {
374 	rpmlog(RPMLOG_ERR, _("Too many args in data line at %s:%d\n"),
375 	      fn, lineNum);
376 	return RPMRC_FAIL;
377     }
378 
379     tnum = strtoul(s, &s1, 10);
380     if ((*s1) || (s1 == s) || (tnum == ULONG_MAX)) {
381 	rpmlog(RPMLOG_ERR, _("Bad arch/os number: %s (%s:%d)\n"), s,
382 	      fn, lineNum);
383 	return RPMRC_FAIL;
384     }
385 
386     t[0].name = xstrdup(tname);
387     t[0].short_name = (tshort_name ? xstrdup(tshort_name) : xstrdup(""));
388     t[0].num = tnum;
389 
390     /* From A B C entry */
391     /* Add  B B C entry */
392     t[1].name = (tshort_name ? xstrdup(tshort_name) : xstrdup(""));
393     t[1].short_name = (tshort_name ? xstrdup(tshort_name) : xstrdup(""));
394     t[1].num = tnum;
395 
396     return RPMRC_OK;
397 }
398 
addDefault(defaultEntry * table,int * tableLen,char * line,const char * fn,int lineNum)399 static rpmRC addDefault(defaultEntry * table, int * tableLen, char * line,
400 			const char * fn, int lineNum)
401 {
402     defaultEntry t;
403 
404     (*tableLen)++;
405     *table = xrealloc(*table, sizeof(**table) * (*tableLen));
406 
407     t = & ((*table)[*tableLen - 1]);
408 
409     t->name = strtok(line, ": \t");
410     t->defName = strtok(NULL, " \t");
411     if (! (t->name && t->defName)) {
412 	rpmlog(RPMLOG_ERR, _("Incomplete default line at %s:%d\n"),
413 		 fn, lineNum);
414 	return RPMRC_FAIL;
415     }
416     if (strtok(NULL, " \t")) {
417 	rpmlog(RPMLOG_ERR, _("Too many args in default line at %s:%d\n"),
418 	      fn, lineNum);
419 	return RPMRC_FAIL;
420     }
421 
422     t->name = xstrdup(t->name);
423     t->defName = (t->defName ? xstrdup(t->defName) : NULL);
424 
425     return RPMRC_OK;
426 }
427 
lookupInCanonTable(const char * name,const canonEntry table,int tableLen)428 static canonEntry lookupInCanonTable(const char * name,
429 		const canonEntry table, int tableLen)
430 {
431     while (tableLen) {
432 	tableLen--;
433 	if (!rstreq(name, table[tableLen].name))
434 	    continue;
435 	return &(table[tableLen]);
436     }
437 
438     return NULL;
439 }
440 
441 static
lookupInDefaultTable(const char * name,const defaultEntry table,int tableLen)442 const char * lookupInDefaultTable(const char * name,
443 		const defaultEntry table, int tableLen)
444 {
445     while (tableLen) {
446 	tableLen--;
447 	if (table[tableLen].name && rstreq(name, table[tableLen].name))
448 	    return table[tableLen].defName;
449     }
450 
451     return name;
452 }
453 
setDefaults(void)454 static void setDefaults(void)
455 {
456     const char *confdir = rpmConfigDir();
457     if (!defrcfiles) {
458 	defrcfiles = rstrscat(NULL, confdir, "/rpmrc", ":",
459 				confdir, "/" RPMCANONVENDOR "/rpmrc", ":",
460 				SYSCONFDIR "/rpmrc", ":",
461 			  	"~/.rpmrc", NULL);
462     }
463 
464 #ifndef MACROFILES
465     if (!macrofiles) {
466 	macrofiles = rstrscat(NULL, confdir, "/macros", ":",
467 				confdir, "/macros.d/macros.*", ":",
468 				confdir, "/platform/%{_target}/macros", ":",
469 				confdir, "/fileattrs/*.attr", ":",
470   				confdir, "/" RPMCANONVENDOR "/macros", ":",
471 				SYSCONFDIR "/rpm/macros.*", ":",
472 				SYSCONFDIR "/rpm/macros", ":",
473 				SYSCONFDIR "/rpm/%{_target}/macros", ":",
474 				"~/.rpmmacros", NULL);
475     }
476 #else
477     macrofiles = MACROFILES;
478 #endif
479 }
480 
481 /* FIX: se usage inconsistent, W2DO? */
doReadRC(rpmrcCtx ctx,const char * urlfn)482 static rpmRC doReadRC(rpmrcCtx ctx, const char * urlfn)
483 {
484     char *s;
485     char *se, *next, *buf = NULL, *fn;
486     int linenum = 0;
487     struct rpmOption searchOption, * option;
488     rpmRC rc = RPMRC_FAIL;
489 
490     fn = rpmGetPath(urlfn, NULL);
491     if (rpmioSlurp(fn, (uint8_t **) &buf, NULL) || buf == NULL) {
492 	goto exit;
493     }
494 
495     next = buf;
496     while (*next != '\0') {
497 	linenum++;
498 
499 	s = se = next;
500 
501 	/* Find end-of-line. */
502 	while (*se && *se != '\n') se++;
503 	if (*se != '\0') *se++ = '\0';
504 	next = se;
505 
506 	/* Trim leading spaces */
507 	while (*s && risspace(*s)) s++;
508 
509 	/* We used to allow comments to begin anywhere, but not anymore. */
510 	if (*s == '#' || *s == '\0') continue;
511 
512 	/* Find end-of-keyword. */
513 	se = (char *)s;
514 	while (*se && !risspace(*se) && *se != ':') se++;
515 
516 	if (risspace(*se)) {
517 	    *se++ = '\0';
518 	    while (*se && risspace(*se) && *se != ':') se++;
519 	}
520 
521 	if (*se != ':') {
522 	    rpmlog(RPMLOG_ERR, _("missing ':' (found 0x%02x) at %s:%d\n"),
523 		     (unsigned)(0xff & *se), fn, linenum);
524 	    goto exit;
525 	}
526 	*se++ = '\0';	/* terminate keyword or option, point to value */
527 	while (*se && risspace(*se)) se++;
528 
529 	/* Find keyword in table */
530 	searchOption.name = s;
531 	option = bsearch(&searchOption, optionTable, optionTableSize,
532 			 sizeof(optionTable[0]), optionCompare);
533 
534 	if (option) {	/* For configuration variables  ... */
535 	    const char *arch, *val;
536 
537 	    arch = val = NULL;
538 	    if (*se == '\0') {
539 		rpmlog(RPMLOG_ERR, _("missing argument for %s at %s:%d\n"),
540 		      option->name, fn, linenum);
541 		goto exit;
542 	    }
543 
544 	    if (option->var == RPMVAR_INCLUDE) {
545 		s = se;
546 		while (*se && !risspace(*se)) se++;
547 		if (*se != '\0') *se = '\0';
548 
549 		if (doReadRC(ctx, s)) {
550 		    rpmlog(RPMLOG_ERR, _("cannot open %s at %s:%d: %m\n"),
551 			s, fn, linenum);
552 		    goto exit;
553 		}
554 		/* XXX don't save include value as var/macro */
555 		continue;
556 	    }
557 
558 	    if (option->archSpecific) {
559 		arch = se;
560 		while (*se && !risspace(*se)) se++;
561 		if (*se == '\0') {
562 		    rpmlog(RPMLOG_ERR,
563 				_("missing architecture for %s at %s:%d\n"),
564 			  	option->name, fn, linenum);
565 		    goto exit;
566 		}
567 		*se++ = '\0';
568 		while (*se && risspace(*se)) se++;
569 		if (*se == '\0') {
570 		    rpmlog(RPMLOG_ERR,
571 				_("missing argument for %s at %s:%d\n"),
572 			  	option->name, fn, linenum);
573 		    goto exit;
574 		}
575 	    }
576 
577 	    val = se;
578 
579 	    /* Only add macros if appropriate for this arch */
580 	    if (option->macroize &&
581 	      (arch == NULL || rstreq(arch, ctx->current[ARCH]))) {
582 		char *n, *name;
583 		n = name = xmalloc(strlen(option->name)+2);
584 		if (option->localize)
585 		    *n++ = '_';
586 		strcpy(n, option->name);
587 		rpmPushMacro(NULL, name, NULL, val, RMIL_RPMRC);
588 		free(name);
589 	    }
590 	    rpmSetVarArch(ctx, option->var, val, arch);
591 	    fn = _free(fn);
592 
593 	} else {	/* For arch/os compatibility tables ... */
594 	    int gotit;
595 	    int i;
596 
597 	    gotit = 0;
598 
599 	    for (i = 0; i < RPM_MACHTABLE_COUNT; i++) {
600 		if (rstreqn(ctx->tables[i].key, s, strlen(ctx->tables[i].key)))
601 		    break;
602 	    }
603 
604 	    if (i < RPM_MACHTABLE_COUNT) {
605 		const char *rest = s + strlen(ctx->tables[i].key);
606 		if (*rest == '_') rest++;
607 
608 		if (rstreq(rest, "compat")) {
609 		    if (machCompatCacheAdd(se, fn, linenum,
610 						&ctx->tables[i].cache))
611 			goto exit;
612 		    gotit = 1;
613 		} else if (ctx->tables[i].hasTranslate &&
614 			   rstreq(rest, "translate")) {
615 		    if (addDefault(&ctx->tables[i].defaults,
616 				   &ctx->tables[i].defaultsLength,
617 				   se, fn, linenum))
618 			goto exit;
619 		    gotit = 1;
620 		} else if (ctx->tables[i].hasCanon &&
621 			   rstreq(rest, "canon")) {
622 		    if (addCanon(&ctx->tables[i].canons,
623 				 &ctx->tables[i].canonsLength,
624 				 se, fn, linenum))
625 			goto exit;
626 		    gotit = 1;
627 		}
628 	    }
629 
630 	    if (!gotit) {
631 		rpmlog(RPMLOG_ERR, _("bad option '%s' at %s:%d\n"),
632 			    s, fn, linenum);
633 		goto exit;
634 	    }
635 	}
636     }
637     rc = RPMRC_OK;
638 
639 exit:
640     free(fn);
641     free(buf);
642 
643     return rc;
644 }
645 
646 
647 /**
648  */
rpmPlatform(rpmrcCtx ctx,const char * platform)649 static rpmRC rpmPlatform(rpmrcCtx ctx, const char * platform)
650 {
651     const char *cpu = NULL, *vendor = NULL, *os = NULL, *gnu = NULL;
652     uint8_t * b = NULL;
653     ssize_t blen = 0;
654     int init_platform = 0;
655     char * p, * pe;
656     rpmRC rc;
657 
658     rc = (rpmioSlurp(platform, &b, &blen) == 0) ? RPMRC_OK : RPMRC_FAIL;
659 
660     if (rc || b == NULL || blen <= 0) {
661 	rc = RPMRC_FAIL;
662 	goto exit;
663     }
664 
665     p = (char *)b;
666     for (pe = p; p && *p; p = pe) {
667 	pe = strchr(p, '\n');
668 	if (pe)
669 	    *pe++ = '\0';
670 
671 	while (*p && isspace(*p))
672 	    p++;
673 	if (*p == '\0' || *p == '#')
674 	    continue;
675 
676 	if (init_platform) {
677 	    char * t = p + strlen(p);
678 
679 	    while (--t > p && isspace(*t))
680 		*t = '\0';
681 	    if (t > p) {
682 		argvAdd(&ctx->platpat, p);
683 	    }
684 	    continue;
685 	}
686 
687 	cpu = p;
688 	vendor = "unknown";
689 	os = "unknown";
690 	gnu = NULL;
691 	while (*p && !(*p == '-' || isspace(*p)))
692 	    p++;
693 	if (*p != '\0') *p++ = '\0';
694 
695 	vendor = p;
696 	while (*p && !(*p == '-' || isspace(*p)))
697 	    p++;
698 	if (*p != '-') {
699 	    if (*p != '\0') *p = '\0';
700 	    os = vendor;
701 	    vendor = "unknown";
702 	} else {
703 	    if (*p != '\0') *p++ = '\0';
704 
705 	    os = p;
706 	    while (*p && !(*p == '-' || isspace(*p)))
707 		p++;
708 	    if (*p == '-') {
709 		*p++ = '\0';
710 
711 		gnu = p;
712 		while (*p && !(*p == '-' || isspace(*p)))
713 		    p++;
714 	    }
715 	    if (*p != '\0') *p = '\0';
716 	}
717 
718 	rpmPushMacro(NULL, "_host_cpu", NULL, cpu, -1);
719 	rpmPushMacro(NULL, "_host_vendor", NULL, vendor, -1);
720 	rpmPushMacro(NULL, "_host_os", NULL, os, -1);
721 
722 	char *plat = rpmExpand("%{_host_cpu}-%{_host_vendor}-%{_host_os}",
723 				(gnu && *gnu ? "-" : NULL), gnu, NULL);
724 	argvAdd(&ctx->platpat, plat);
725 	free(plat);
726 
727 	init_platform++;
728     }
729     rc = (init_platform ? RPMRC_OK : RPMRC_FAIL);
730 
731 exit:
732     b = _free(b);
733     return rc;
734 }
735 
736 
737 #	if defined(__linux__) && defined(__i386__)
738 #include <setjmp.h>
739 #include <signal.h>
740 
741 /*
742  * Generic CPUID function
743  */
cpuid(unsigned int op,unsigned int * eax,unsigned int * ebx,unsigned int * ecx,unsigned int * edx)744 static inline void cpuid(unsigned int op, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx)
745 {
746     asm volatile (
747 	"pushl	%%ebx		\n"
748 	"cpuid			\n"
749 	"movl	%%ebx,	%%esi	\n"
750 	"popl	%%ebx		\n"
751     : "=a" (*eax), "=S" (*ebx), "=c" (*ecx), "=d" (*edx)
752     : "a" (op));
753 }
754 
755 /*
756  * CPUID functions returning a single datum
757  */
cpuid_eax(unsigned int op)758 static inline unsigned int cpuid_eax(unsigned int op)
759 {
760 	unsigned int tmp, val;
761 	cpuid(op, &val, &tmp, &tmp, &tmp);
762 	return val;
763 }
764 
cpuid_ebx(unsigned int op)765 static inline unsigned int cpuid_ebx(unsigned int op)
766 {
767 	unsigned int tmp, val;
768 	cpuid(op, &tmp, &val, &tmp, &tmp);
769 	return val;
770 }
771 
cpuid_ecx(unsigned int op)772 static inline unsigned int cpuid_ecx(unsigned int op)
773 {
774 	unsigned int tmp, val;
775 	cpuid(op, &tmp, &tmp, &val, &tmp);
776 	return val;
777 }
778 
cpuid_edx(unsigned int op)779 static inline unsigned int cpuid_edx(unsigned int op)
780 {
781 	unsigned int tmp, val;
782 	cpuid(op, &tmp, &tmp, &tmp, &val);
783 	return val;
784 }
785 
786 static sigjmp_buf jenv;
787 
model3(int _unused)788 static inline void model3(int _unused)
789 {
790 	siglongjmp(jenv, 1);
791 }
792 
RPMClass(void)793 static inline int RPMClass(void)
794 {
795 	int cpu;
796 	unsigned int tfms, junk, cap, capamd;
797 	struct sigaction oldsa;
798 
799 	sigaction(SIGILL, NULL, &oldsa);
800 	signal(SIGILL, model3);
801 
802 	if (sigsetjmp(jenv, 1)) {
803 		sigaction(SIGILL, &oldsa, NULL);
804 		return 3;
805 	}
806 
807 	if (cpuid_eax(0x000000000)==0) {
808 		sigaction(SIGILL, &oldsa, NULL);
809 		return 4;
810 	}
811 
812 	cpuid(0x00000001, &tfms, &junk, &junk, &cap);
813 	cpuid(0x80000001, &junk, &junk, &junk, &capamd);
814 
815 	cpu = (tfms>>8)&15;
816 
817 	if (cpu == 5
818 	    && cpuid_ecx(0) == '68xM'
819 	    && cpuid_edx(0) == 'Teni'
820 	    && (cpuid_edx(1) & ((1<<8)|(1<<15))) == ((1<<8)|(1<<15))) {
821 		sigaction(SIGILL, &oldsa, NULL);
822 		return 6;	/* has CX8 and CMOV */
823 	}
824 
825 	sigaction(SIGILL, &oldsa, NULL);
826 
827 #define USER686 ((1<<4) | (1<<8) | (1<<15))
828 	/* Transmeta Crusoe CPUs say that their CPU family is "5" but they have enough features for i686. */
829 	if (cpu == 5 && (cap & USER686) == USER686)
830 		return 6;
831 
832 	if (cpu < 6)
833 		return cpu;
834 
835 	if (cap & (1<<15)) {
836 		/* CMOV supported? */
837 		if (capamd & (1<<30))
838 			return 7;	/* 3DNOWEXT supported */
839 		return 6;
840 	}
841 
842 	return 5;
843 }
844 
845 /* should only be called for model 6 CPU's */
is_athlon(void)846 static int is_athlon(void)
847 {
848 	unsigned int eax, ebx, ecx, edx;
849 	char vendor[16];
850 	int i;
851 
852 	cpuid (0, &eax, &ebx, &ecx, &edx);
853 
854  	memset(vendor, 0, sizeof(vendor));
855 
856  	for (i=0; i<4; i++)
857  		vendor[i] = (unsigned char) (ebx >>(8*i));
858  	for (i=0; i<4; i++)
859  		vendor[4+i] = (unsigned char) (edx >>(8*i));
860  	for (i=0; i<4; i++)
861  		vendor[8+i] = (unsigned char) (ecx >>(8*i));
862 
863  	if (!rstreqn(vendor, "AuthenticAMD", 12))
864  		return 0;
865 
866 	return 1;
867 }
868 
is_pentium3(void)869 static int is_pentium3(void)
870 {
871     unsigned int eax, ebx, ecx, edx, family, model;
872     char vendor[16];
873     cpuid(0, &eax, &ebx, &ecx, &edx);
874     memset(vendor, 0, sizeof(vendor));
875     *((unsigned int *)&vendor[0]) = ebx;
876     *((unsigned int *)&vendor[4]) = edx;
877     *((unsigned int *)&vendor[8]) = ecx;
878     if (!rstreqn(vendor, "GenuineIntel", 12))
879 	return 0;
880     cpuid(1, &eax, &ebx, &ecx, &edx);
881     family = (eax >> 8) & 0x0f;
882     model = (eax >> 4) & 0x0f;
883     if (family == 6)
884 	switch (model)
885 	{
886 	    case 7:	// Pentium III, Pentium III Xeon (model 7)
887 	    case 8:	// Pentium III, Pentium III Xeon, Celeron (model 8)
888 	    case 9:	// Pentium M
889 	    case 10:	// Pentium III Xeon (model A)
890 	    case 11:	// Pentium III (model B)
891 		return 1;
892 	}
893     return 0;
894 }
895 
is_pentium4(void)896 static int is_pentium4(void)
897 {
898     unsigned int eax, ebx, ecx, edx, family, model;
899     char vendor[16];
900     cpuid(0, &eax, &ebx, &ecx, &edx);
901     memset(vendor, 0, sizeof(vendor));
902     *((unsigned int *)&vendor[0]) = ebx;
903     *((unsigned int *)&vendor[4]) = edx;
904     *((unsigned int *)&vendor[8]) = ecx;
905     if (!rstreqn(vendor, "GenuineIntel", 12))
906 	return 0;
907     cpuid(1, &eax, &ebx, &ecx, &edx);
908     family = (eax >> 8) & 0x0f;
909     model = (eax >> 4) & 0x0f;
910     if (family == 15)
911 	switch (model)
912 	{
913 	    case 0:	// Pentium 4, Pentium 4 Xeon                 (0.18um)
914 	    case 1:	// Pentium 4, Pentium 4 Xeon MP, Celeron     (0.18um)
915 	    case 2:	// Pentium 4, Mobile Pentium 4-M,
916 			// Pentium 4 Xeon, Pentium 4 Xeon MP,
917 			// Celeron, Mobile Celron                    (0.13um)
918 	    case 3:	// Pentium 4, Celeron                        (0.09um)
919 		return 1;
920 	}
921     return 0;
922 }
923 
is_geode(void)924 static int is_geode(void)
925 {
926     unsigned int eax, ebx, ecx, edx, family, model;
927     char vendor[16];
928     memset(vendor, 0, sizeof(vendor));
929 
930     cpuid(0, &eax, &ebx, &ecx, &edx);
931     memset(vendor, 0, sizeof(vendor));
932     *((unsigned int *)&vendor[0]) = ebx;
933     *((unsigned int *)&vendor[4]) = edx;
934     *((unsigned int *)&vendor[8]) = ecx;
935     if (!rstreqn(vendor, "AuthenticAMD", 12))
936         return 0;
937     cpuid(1, &eax, &ebx, &ecx, &edx);
938     family = (eax >> 8) & 0x0f;
939     model = (eax >> 4) & 0x0f;
940     if (family == 5)
941 	switch (model)
942 	{
943             case 10: // Geode
944                 return 1;
945         }
946     return 0;
947 }
948 #endif
949 
950 
951 #if defined(__linux__)
952 /**
953  * Populate rpmat structure with auxv values
954  */
read_auxv(void)955 static void read_auxv(void)
956 {
957     static int oneshot = 1;
958 
959     if (oneshot) {
960 #ifdef HAVE_GETAUXVAL
961 	rpmat.platform = (char *) getauxval(AT_PLATFORM);
962 	if (!rpmat.platform)
963 	    rpmat.platform = "";
964 	rpmat.hwcap = getauxval(AT_HWCAP);
965 #else
966 	rpmat.platform = "";
967 	int fd = open("/proc/self/auxv", O_RDONLY);
968 
969 	if (fd == -1) {
970 	    rpmlog(RPMLOG_WARNING,
971 		   _("Failed to read auxiliary vector, /proc not mounted?\n"));
972             return;
973 	} else {
974 	    ElfW(auxv_t) auxv;
975 	    while (read(fd, &auxv, sizeof(auxv)) == sizeof(auxv)) {
976                 switch (auxv.a_type)
977                 {
978                     case AT_NULL:
979                         break;
980                     case AT_PLATFORM:
981                         rpmat.platform = strdup((char *) auxv.a_un.a_val);
982                         break;
983                     case AT_HWCAP:
984                         rpmat.hwcap = auxv.a_un.a_val;
985                         break;
986                 }
987 	    }
988 	    close(fd);
989 	}
990 #endif
991 	oneshot = 0; /* only try once even if it fails */
992     }
993     return;
994 }
995 #endif
996 
997 /**
998  */
defaultMachine(rpmrcCtx ctx,const char ** arch,const char ** os)999 static void defaultMachine(rpmrcCtx ctx, const char ** arch, const char ** os)
1000 {
1001     const char * const platform_path = SYSCONFDIR "/rpm/platform";
1002     static struct utsname un;
1003     char * chptr;
1004     canonEntry canon;
1005     int rc;
1006 
1007 #if defined(__linux__)
1008     /* Populate rpmat struct with hw info */
1009     read_auxv();
1010 #endif
1011 
1012     while (!ctx->machDefaults) {
1013 	if (!rpmPlatform(ctx, platform_path)) {
1014 	    char * s = rpmExpand("%{_host_cpu}", NULL);
1015 	    if (s) {
1016 		rstrlcpy(un.machine, s, sizeof(un.machine));
1017 		free(s);
1018 	    }
1019 	    s = rpmExpand("%{_host_os}", NULL);
1020 	    if (s) {
1021 		rstrlcpy(un.sysname, s, sizeof(un.sysname));
1022 		free(s);
1023 	    }
1024 	    ctx->machDefaults = 1;
1025 	    break;
1026 	}
1027 	rc = uname(&un);
1028 	if (rc < 0) return;
1029 
1030 #if !defined(__linux__)
1031 	if (rstreq(un.sysname, "AIX")) {
1032 	    strcpy(un.machine, __power_pc() ? "ppc" : "rs6000");
1033 	    sprintf(un.sysname,"aix%s.%s", un.version, un.release);
1034 	}
1035 	else if (rstreq(un.sysname, "Darwin")) {
1036 #if defined(__ppc__)
1037 	    strcpy(un.machine, "ppc");
1038 #elif defined(__i386__)
1039 	    strcpy(un.machine, "i386");
1040 #elif defined(__x86_64__)
1041 	    strcpy(un.machine, "x86_64");
1042 #else
1043 	    #warning "No architecture defined! Automatic detection may not work!"
1044 #endif
1045 	}
1046 	else if (rstreq(un.sysname, "SunOS")) {
1047 	    /* Solaris 2.x: n.x.x becomes n-3.x.x */
1048 	    sprintf(un.sysname, "solaris%1d%s", atoi(un.release)-3,
1049 		    un.release+1+(atoi(un.release)/10));
1050 
1051 	    /* Solaris on Intel hardware reports i86pc instead of i386
1052 	     * (at least on 2.6 and 2.8)
1053 	     */
1054 	    if (rstreq(un.machine, "i86pc"))
1055 		sprintf(un.machine, "i386");
1056 	}
1057 	else if (rstreq(un.sysname, "HP-UX"))
1058 	    /*make un.sysname look like hpux9.05 for example*/
1059 	    sprintf(un.sysname, "hpux%s", strpbrk(un.release, "123456789"));
1060 	else if (rstreq(un.sysname, "OSF1"))
1061 	    /*make un.sysname look like osf3.2 for example*/
1062 	    sprintf(un.sysname, "osf%s", strpbrk(un.release, "123456789"));
1063 #endif	/* __linux__ */
1064 
1065 	/* get rid of the hyphens in the sysname */
1066 	for (chptr = un.machine; *chptr != '\0'; chptr++)
1067 	    if (*chptr == '/') *chptr = '-';
1068 
1069 #	if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL)
1070 	    /* little endian */
1071 #		if defined(__mips64)
1072 		    /* 64-bit */
1073 #			if !defined(__mips_isa_rev) || __mips_isa_rev < 6
1074 			    /* r1-r5 */
1075 			    strcpy(un.machine, "mips64el");
1076 #			else
1077 			    /* r6 */
1078 			    strcpy(un.machine, "mips64r6el");
1079 #			endif
1080 #		else
1081 		    /* 32-bit */
1082 #			if !defined(__mips_isa_rev) || __mips_isa_rev < 6
1083 			    /* r1-r5 */
1084 			    strcpy(un.machine, "mipsel");
1085 #			else
1086 			    /* r6 */
1087 			    strcpy(un.machine, "mipsr6el");
1088 #			endif
1089 #		endif
1090 #	elif defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB)
1091 	   /* big endian */
1092 #		if defined(__mips64)
1093 		    /* 64-bit */
1094 #			if !defined(__mips_isa_rev) || __mips_isa_rev < 6
1095 			    /* r1-r5 */
1096 			    strcpy(un.machine, "mips64");
1097 #			else
1098 			    /* r6 */
1099 			    strcpy(un.machine, "mips64r6");
1100 #			endif
1101 #		else
1102 		    /* 32-bit */
1103 #			if !defined(__mips_isa_rev) || __mips_isa_rev < 6
1104 			    /* r1-r5 */
1105 			    strcpy(un.machine, "mips");
1106 #			else
1107 			    /* r6 */
1108 			    strcpy(un.machine, "mipsr6");
1109 #			endif
1110 #		endif
1111 #	endif
1112 
1113 #if defined(__linux__)
1114 	/* in linux, lets rename parisc to hppa */
1115 	if (rstreq(un.machine, "parisc"))
1116 	    strcpy(un.machine, "hppa");
1117 #endif
1118 
1119 #	if defined(__hpux) && defined(_SC_CPU_VERSION)
1120 	{
1121 #	    if !defined(CPU_PA_RISC1_2)
1122 #                define CPU_PA_RISC1_2  0x211 /* HP PA-RISC1.2 */
1123 #           endif
1124 #           if !defined(CPU_PA_RISC2_0)
1125 #               define CPU_PA_RISC2_0  0x214 /* HP PA-RISC2.0 */
1126 #           endif
1127 	    int cpu_version = sysconf(_SC_CPU_VERSION);
1128 
1129 #	    if defined(CPU_HP_MC68020)
1130 		if (cpu_version == CPU_HP_MC68020)
1131 		    strcpy(un.machine, "m68k");
1132 #	    endif
1133 #	    if defined(CPU_HP_MC68030)
1134 		if (cpu_version == CPU_HP_MC68030)
1135 		    strcpy(un.machine, "m68k");
1136 #	    endif
1137 #	    if defined(CPU_HP_MC68040)
1138 		if (cpu_version == CPU_HP_MC68040)
1139 		    strcpy(un.machine, "m68k");
1140 #	    endif
1141 
1142 #	    if defined(CPU_PA_RISC1_0)
1143 		if (cpu_version == CPU_PA_RISC1_0)
1144 		    strcpy(un.machine, "hppa1.0");
1145 #	    endif
1146 #	    if defined(CPU_PA_RISC1_1)
1147 		if (cpu_version == CPU_PA_RISC1_1)
1148 		    strcpy(un.machine, "hppa1.1");
1149 #	    endif
1150 #	    if defined(CPU_PA_RISC1_2)
1151 		if (cpu_version == CPU_PA_RISC1_2)
1152 		    strcpy(un.machine, "hppa1.2");
1153 #	    endif
1154 #	    if defined(CPU_PA_RISC2_0)
1155 		if (cpu_version == CPU_PA_RISC2_0)
1156 		    strcpy(un.machine, "hppa2.0");
1157 #	    endif
1158 	}
1159 #	endif	/* hpux */
1160 
1161 #	if defined(__linux__) && defined(__sparc__)
1162 #	if !defined(HWCAP_SPARC_BLKINIT)
1163 #	    define HWCAP_SPARC_BLKINIT	0x00000040
1164 #	endif
1165 	if (rstreq(un.machine, "sparc")) {
1166 	    #define PERS_LINUX		0x00000000
1167 	    #define PERS_LINUX_32BIT	0x00800000
1168 	    #define PERS_LINUX32	0x00000008
1169 
1170 	    extern int personality(unsigned long);
1171 	    int oldpers;
1172 
1173 	    oldpers = personality(PERS_LINUX_32BIT);
1174 	    if (oldpers != -1) {
1175 		if (personality(PERS_LINUX) != -1) {
1176 		    uname(&un);
1177 		    if (rstreq(un.machine, "sparc64")) {
1178 			strcpy(un.machine, "sparcv9");
1179 			oldpers = PERS_LINUX32;
1180 		    }
1181 		}
1182 		personality(oldpers);
1183 	    }
1184 
1185 	    /* This is how glibc detects Niagara so... */
1186 	    if (rpmat.hwcap & HWCAP_SPARC_BLKINIT) {
1187 		if (rstreq(un.machine, "sparcv9") || rstreq(un.machine, "sparc")) {
1188 		    strcpy(un.machine, "sparcv9v");
1189 		} else if (rstreq(un.machine, "sparc64")) {
1190 		    strcpy(un.machine, "sparc64v");
1191 		}
1192 	    }
1193 	}
1194 #	endif	/* sparc*-linux */
1195 
1196 #	if defined(__linux__) && defined(__powerpc__)
1197 #	if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
1198 	{
1199             int powerlvl;
1200             if (!rstreq(un.machine, "ppc") &&
1201 		    sscanf(rpmat.platform, "power%d", &powerlvl) == 1 &&
1202 		    powerlvl > 6) {
1203                 strcpy(un.machine, "ppc64p7");
1204 	    }
1205         }
1206 #	endif	/* __ORDER_BIG_ENDIAN__ */
1207 #	endif	/* ppc64*-linux */
1208 
1209 #	if defined(__linux__) && defined(__arm__) && defined(__ARM_PCS_VFP)
1210 #	if !defined(HWCAP_ARM_VFP)
1211 #	    define HWCAP_ARM_VFP	(1 << 6)
1212 #	endif
1213 #	if !defined(HWCAP_ARM_NEON)
1214 #	    define HWCAP_ARM_NEON	(1 << 12)
1215 #	endif
1216 #	if !defined(HWCAP_ARM_VFPv3)
1217 #	    define HWCAP_ARM_VFPv3	(1 << 13)
1218 #	endif
1219 	if (rstreq(un.machine, "armv7l")) {
1220 	    if (rpmat.hwcap & HWCAP_ARM_VFPv3) {
1221 		if (rpmat.hwcap & HWCAP_ARM_NEON)
1222 		    strcpy(un.machine, "armv7hnl");
1223 		else
1224 		    strcpy(un.machine, "armv7hl");
1225 	    }
1226 	} else if (rstreq(un.machine, "armv6l")) {
1227 	    if (rpmat.hwcap & HWCAP_ARM_VFP)
1228 		strcpy(un.machine, "armv6hl");
1229 	}
1230 #	endif	/* arm*-linux */
1231 
1232 #	if defined(__linux__) && defined(__riscv__)
1233 	if (rstreq(un.machine, "riscv")) {
1234 		if (sizeof(long) == 4)
1235 			strcpy(un.machine, "riscv32");
1236 		else if (sizeof(long) == 8)
1237 			strcpy(un.machine, "riscv64");
1238 		else if (sizeof(long) == 16)
1239 			strcpy(un.machine, "riscv128");
1240 	}
1241 #	endif	/* riscv */
1242 
1243 #	if defined(__GNUC__) && defined(__alpha__)
1244 	{
1245 	    unsigned long amask, implver;
1246 	    register long v0 __asm__("$0") = -1;
1247 	    __asm__ (".long 0x47e00c20" : "=r"(v0) : "0"(v0));
1248 	    amask = ~v0;
1249 	    __asm__ (".long 0x47e03d80" : "=r"(v0));
1250 	    implver = v0;
1251 	    switch (implver) {
1252 	    case 1:
1253 	    	switch (amask) {
1254 	    	case 0: strcpy(un.machine, "alphaev5"); break;
1255 	    	case 1: strcpy(un.machine, "alphaev56"); break;
1256 	    	case 0x101: strcpy(un.machine, "alphapca56"); break;
1257 	    	}
1258 	    	break;
1259 	    case 2:
1260 	    	switch (amask) {
1261 	    	case 0x303: strcpy(un.machine, "alphaev6"); break;
1262 	    	case 0x307: strcpy(un.machine, "alphaev67"); break;
1263 	    	}
1264 	    	break;
1265 	    }
1266 	}
1267 #	endif
1268 
1269 #	if defined(__linux__) && defined(__i386__)
1270 	{
1271 	    char mclass = (char) (RPMClass() | '0');
1272 
1273 	    if ((mclass == '6' && is_athlon()) || mclass == '7')
1274 	    	strcpy(un.machine, "athlon");
1275 	    else if (is_pentium4())
1276 		strcpy(un.machine, "pentium4");
1277 	    else if (is_pentium3())
1278 		strcpy(un.machine, "pentium3");
1279 	    else if (is_geode())
1280 		strcpy(un.machine, "geode");
1281 	    else if (strchr("3456", un.machine[1]) && un.machine[1] != mclass)
1282 		un.machine[1] = mclass;
1283 	}
1284 #	endif
1285 
1286 	/* the uname() result goes through the arch_canon table */
1287 	canon = lookupInCanonTable(un.machine,
1288 			   ctx->tables[RPM_MACHTABLE_INSTARCH].canons,
1289 			   ctx->tables[RPM_MACHTABLE_INSTARCH].canonsLength);
1290 	if (canon)
1291 	    rstrlcpy(un.machine, canon->short_name, sizeof(un.machine));
1292 
1293 	canon = lookupInCanonTable(un.sysname,
1294 			   ctx->tables[RPM_MACHTABLE_INSTOS].canons,
1295 			   ctx->tables[RPM_MACHTABLE_INSTOS].canonsLength);
1296 	if (canon)
1297 	    rstrlcpy(un.sysname, canon->short_name, sizeof(un.sysname));
1298 	ctx->machDefaults = 1;
1299 	break;
1300     }
1301 
1302     if (arch) *arch = un.machine;
1303     if (os) *os = un.sysname;
1304 }
1305 
1306 static
rpmGetVarArch(rpmrcCtx ctx,int var,const char * arch)1307 const char * rpmGetVarArch(rpmrcCtx ctx, int var, const char * arch)
1308 {
1309     const struct rpmvarValue * next;
1310 
1311     if (arch == NULL) arch = ctx->current[ARCH];
1312 
1313     if (arch) {
1314 	next = &ctx->values[var];
1315 	while (next) {
1316 	    if (next->arch && rstreq(next->arch, arch)) return next->value;
1317 	    next = next->next;
1318 	}
1319     }
1320 
1321     next = ctx->values + var;
1322     while (next && next->arch) next = next->next;
1323 
1324     return next ? next->value : NULL;
1325 }
1326 
rpmSetVarArch(rpmrcCtx ctx,int var,const char * val,const char * arch)1327 static void rpmSetVarArch(rpmrcCtx ctx,
1328 			  int var, const char * val, const char * arch)
1329 {
1330     struct rpmvarValue * next = ctx->values + var;
1331 
1332     if (next->value) {
1333 	if (arch) {
1334 	    while (next->next) {
1335 		if (next->arch && rstreq(next->arch, arch)) break;
1336 		next = next->next;
1337 	    }
1338 	} else {
1339 	    while (next->next) {
1340 		if (!next->arch) break;
1341 		next = next->next;
1342 	    }
1343 	}
1344 
1345 	if (next->arch && arch && rstreq(next->arch, arch)) {
1346 	    next->value = _free(next->value);
1347 	    next->arch = _free(next->arch);
1348 	} else if (next->arch || arch) {
1349 	    next->next = xmalloc(sizeof(*next->next));
1350 	    next = next->next;
1351 	    next->value = NULL;
1352 	    next->arch = NULL;
1353 	    next->next = NULL;
1354 	}
1355     }
1356 
1357     next->value = _free(next->value);
1358     next->value = xstrdup(val);
1359     next->arch = (arch ? xstrdup(arch) : NULL);
1360 }
1361 
rpmSetTables(rpmrcCtx ctx,int archTable,int osTable)1362 static void rpmSetTables(rpmrcCtx ctx, int archTable, int osTable)
1363 {
1364     const char * arch, * os;
1365 
1366     defaultMachine(ctx, &arch, &os);
1367 
1368     if (ctx->currTables[ARCH] != archTable) {
1369 	ctx->currTables[ARCH] = archTable;
1370 	rebuildCompatTables(ctx, ARCH, arch);
1371     }
1372 
1373     if (ctx->currTables[OS] != osTable) {
1374 	ctx->currTables[OS] = osTable;
1375 	rebuildCompatTables(ctx, OS, os);
1376     }
1377 }
1378 
1379 /** \ingroup rpmrc
1380  * Set current arch/os names.
1381  * NULL as argument is set to the default value (munged uname())
1382  * pushed through a translation table (if appropriate).
1383  * @deprecated Use addMacro to set _target_* macros.
1384  * @todo Eliminate
1385  *
1386  * @param ctx		rpmrc context
1387  * @param arch          arch name (or NULL)
1388  * @param os            os name (or NULL)
1389  *          */
1390 
rpmSetMachine(rpmrcCtx ctx,const char * arch,const char * os)1391 static void rpmSetMachine(rpmrcCtx ctx, const char * arch, const char * os)
1392 {
1393     const char * host_cpu, * host_os;
1394 
1395     defaultMachine(ctx, &host_cpu, &host_os);
1396 
1397     if (arch == NULL) {
1398 	arch = host_cpu;
1399 	if (ctx->tables[ctx->currTables[ARCH]].hasTranslate)
1400 	    arch = lookupInDefaultTable(arch,
1401 			    ctx->tables[ctx->currTables[ARCH]].defaults,
1402 			    ctx->tables[ctx->currTables[ARCH]].defaultsLength);
1403     }
1404     if (arch == NULL) return;	/* XXX can't happen */
1405 
1406     if (os == NULL) {
1407 	os = host_os;
1408 	if (ctx->tables[ctx->currTables[OS]].hasTranslate)
1409 	    os = lookupInDefaultTable(os,
1410 			    ctx->tables[ctx->currTables[OS]].defaults,
1411 			    ctx->tables[ctx->currTables[OS]].defaultsLength);
1412     }
1413     if (os == NULL) return;	/* XXX can't happen */
1414 
1415     if (!ctx->current[ARCH] || !rstreq(arch, ctx->current[ARCH])) {
1416 	ctx->current[ARCH] = _free(ctx->current[ARCH]);
1417 	ctx->current[ARCH] = xstrdup(arch);
1418 	rebuildCompatTables(ctx, ARCH, host_cpu);
1419     }
1420 
1421     if (!ctx->current[OS] || !rstreq(os, ctx->current[OS])) {
1422 	char * t = xstrdup(os);
1423 	ctx->current[OS] = _free(ctx->current[OS]);
1424 	/*
1425 	 * XXX Capitalizing the 'L' is needed to insure that old
1426 	 * XXX os-from-uname (e.g. "Linux") is compatible with the new
1427 	 * XXX os-from-platform (e.g "linux" from "sparc-*-linux").
1428 	 * XXX A copy of this string is embedded in headers and is
1429 	 * XXX used by rpmInstallPackage->{os,arch}Okay->rpmMachineScore->
1430 	 * XXX to verify correct arch/os from headers.
1431 	 */
1432 	if (rstreq(t, "linux"))
1433 	    *t = 'L';
1434 	ctx->current[OS] = t;
1435 
1436 	rebuildCompatTables(ctx, OS, host_os);
1437     }
1438 }
1439 
rebuildCompatTables(rpmrcCtx ctx,int type,const char * name)1440 static void rebuildCompatTables(rpmrcCtx ctx, int type, const char * name)
1441 {
1442     machFindEquivs(&ctx->tables[ctx->currTables[type]].cache,
1443 		   &ctx->tables[ctx->currTables[type]].equiv,
1444 		   name);
1445 }
1446 
getMachineInfo(rpmrcCtx ctx,int type,const char ** name,int * num)1447 static void getMachineInfo(rpmrcCtx ctx,
1448 			   int type, const char ** name, int * num)
1449 {
1450     canonEntry canon;
1451     int which = ctx->currTables[type];
1452 
1453     /* use the normal canon tables, even if we're looking up build stuff */
1454     if (which >= 2) which -= 2;
1455 
1456     canon = lookupInCanonTable(ctx->current[type],
1457 			       ctx->tables[which].canons,
1458 			       ctx->tables[which].canonsLength);
1459 
1460     if (canon) {
1461 	if (num) *num = canon->num;
1462 	if (name) *name = canon->short_name;
1463     } else {
1464 	if (num) *num = 255;
1465 	if (name) *name = ctx->current[type];
1466 
1467 	if (ctx->tables[ctx->currTables[type]].hasCanon) {
1468 	    rpmlog(RPMLOG_WARNING, _("Unknown system: %s\n"),
1469 		   ctx->current[type]);
1470 	    rpmlog(RPMLOG_WARNING, _("Please contact %s\n"), PACKAGE_BUGREPORT);
1471 	}
1472     }
1473 }
1474 
rpmRebuildTargetVars(rpmrcCtx ctx,const char ** target,const char ** canontarget)1475 static void rpmRebuildTargetVars(rpmrcCtx ctx,
1476 			const char ** target, const char ** canontarget)
1477 {
1478 
1479     char *ca = NULL, *co = NULL, *ct = NULL;
1480     int x;
1481 
1482     /* Rebuild the compat table to recalculate the current target arch.  */
1483 
1484     rpmSetMachine(ctx, NULL, NULL);
1485     rpmSetTables(ctx, RPM_MACHTABLE_INSTARCH, RPM_MACHTABLE_INSTOS);
1486     rpmSetTables(ctx, RPM_MACHTABLE_BUILDARCH, RPM_MACHTABLE_BUILDOS);
1487 
1488     if (target && *target) {
1489 	char *c;
1490 	/* Set arch and os from specified build target */
1491 	ca = xstrdup(*target);
1492 	if ((c = strchr(ca, '-')) != NULL) {
1493 	    *c++ = '\0';
1494 
1495 	    if ((co = strrchr(c, '-')) == NULL) {
1496 		co = c;
1497 	    } else {
1498 		if (!rstrcasecmp(co, "-gnu"))
1499 		    *co = '\0';
1500 		if ((co = strrchr(c, '-')) == NULL)
1501 		    co = c;
1502 		else
1503 		    co++;
1504 	    }
1505 	    if (co != NULL) co = xstrdup(co);
1506 	}
1507     } else {
1508 	const char *a = NULL;
1509 	const char *o = NULL;
1510 	/* Set build target from rpm arch and os */
1511 	getMachineInfo(ctx, ARCH, &a, NULL);
1512 	ca = (a) ? xstrdup(a) : NULL;
1513 	getMachineInfo(ctx, OS, &o, NULL);
1514 	co = (o) ? xstrdup(o) : NULL;
1515     }
1516 
1517     /* If still not set, Set target arch/os from default uname(2) values */
1518     if (ca == NULL) {
1519 	const char *a = NULL;
1520 	defaultMachine(ctx, &a, NULL);
1521 	ca = xstrdup(a ? a : "(arch)");
1522     }
1523     for (x = 0; ca[x] != '\0'; x++)
1524 	ca[x] = rtolower(ca[x]);
1525 
1526     if (co == NULL) {
1527 	const char *o = NULL;
1528 	defaultMachine(ctx, NULL, &o);
1529 	co = xstrdup(o ? o : "(os)");
1530     }
1531     for (x = 0; co[x] != '\0'; x++)
1532 	co[x] = rtolower(co[x]);
1533 
1534     /* XXX For now, set canonical target to arch-os */
1535     if (ct == NULL) {
1536 	rasprintf(&ct, "%s-%s", ca, co);
1537     }
1538 
1539 /*
1540  * XXX All this macro pokery/jiggery could be achieved by doing a delayed
1541  *	rpmInitMacros(NULL, PER-PLATFORM-MACRO-FILE-NAMES);
1542  */
1543     rpmPopMacro(NULL, "_target");
1544     rpmPushMacro(NULL, "_target", NULL, ct, RMIL_RPMRC);
1545     rpmPopMacro(NULL, "_target_cpu");
1546     rpmPushMacro(NULL, "_target_cpu", NULL, ca, RMIL_RPMRC);
1547     rpmPopMacro(NULL, "_target_os");
1548     rpmPushMacro(NULL, "_target_os", NULL, co, RMIL_RPMRC);
1549 /*
1550  * XXX Make sure that per-arch optflags is initialized correctly.
1551  */
1552   { const char *optflags = rpmGetVarArch(ctx, RPMVAR_OPTFLAGS, ca);
1553     if (optflags != NULL) {
1554 	rpmPopMacro(NULL, "optflags");
1555 	rpmPushMacro(NULL, "optflags", NULL, optflags, RMIL_RPMRC);
1556     }
1557   }
1558 
1559     if (canontarget)
1560 	*canontarget = ct;
1561     else
1562 	free(ct);
1563     free(ca);
1564     free(co);
1565 }
1566 
1567 /** \ingroup rpmrc
1568  * Read rpmrc (and macro) configuration file(s).
1569  * @param ctx		rpmrc context
1570  * @param rcfiles	colon separated files to read (NULL uses default)
1571  * @return		RPMRC_OK on success
1572  */
rpmReadRC(rpmrcCtx ctx,const char * rcfiles)1573 static rpmRC rpmReadRC(rpmrcCtx ctx, const char * rcfiles)
1574 {
1575     ARGV_t p, globs = NULL, files = NULL;
1576     rpmRC rc = RPMRC_FAIL;
1577 
1578     if (!ctx->pathDefaults) {
1579 	setDefaults();
1580 	ctx->pathDefaults = 1;
1581     }
1582 
1583     if (rcfiles == NULL)
1584 	rcfiles = defrcfiles;
1585 
1586     /* Expand any globs in rcfiles. Missing files are ok here. */
1587     argvSplit(&globs, rcfiles, ":");
1588     for (p = globs; *p; p++) {
1589 	ARGV_t av = NULL;
1590 	if (rpmGlob(*p, NULL, &av) == 0) {
1591 	    argvAppend(&files, av);
1592 	    argvFree(av);
1593 	}
1594     }
1595     argvFree(globs);
1596 
1597     /* Read each file in rcfiles. */
1598     for (p = files; p && *p; p++) {
1599 	/* XXX Only /usr/lib/rpm/rpmrc must exist in default rcfiles list */
1600 	if (access(*p, R_OK) != 0) {
1601 	    if (rcfiles == defrcfiles && p != files)
1602 		continue;
1603 	    rpmlog(RPMLOG_ERR, _("Unable to open %s for reading: %m.\n"), *p);
1604 	    goto exit;
1605 	    break;
1606 	} else {
1607 	    rc = doReadRC(ctx, *p);
1608 	}
1609     }
1610     rc = RPMRC_OK;
1611     rpmSetMachine(ctx, NULL, NULL);	/* XXX WTFO? Why bother? */
1612 
1613 exit:
1614     argvFree(files);
1615     return rc;
1616 }
1617 
register_atexit(void)1618 static void register_atexit(void)
1619 {
1620     if (atexit(rpmAtExit) != 0)
1621 	rpmlog(RPMLOG_WARNING, _("failed to register exit handler"));
1622 }
1623 
1624 /* External interfaces */
1625 
rpmReadConfigFiles(const char * file,const char * target)1626 int rpmReadConfigFiles(const char * file, const char * target)
1627 {
1628     static pthread_once_t atexit_registered = PTHREAD_ONCE_INIT;
1629     int rc = -1; /* assume failure */
1630     rpmrcCtx ctx = rpmrcCtxAcquire(1);
1631 
1632     pthread_once(&atexit_registered, register_atexit);
1633 
1634     if (rpmInitCrypto())
1635 	goto exit;
1636 
1637     /* Preset target macros */
1638    	/* FIX: target can be NULL */
1639     rpmRebuildTargetVars(ctx, &target, NULL);
1640 
1641     /* Read the files */
1642     if (rpmReadRC(ctx, file))
1643 	goto exit;
1644 
1645     if (macrofiles != NULL) {
1646 	char *mf = rpmGetPath(macrofiles, NULL);
1647 	rpmInitMacros(NULL, mf);
1648 	_free(mf);
1649     }
1650 
1651     /* Reset target macros */
1652     rpmRebuildTargetVars(ctx, &target, NULL);
1653 
1654     /* Finally set target platform */
1655     {	char *cpu = rpmExpand("%{_target_cpu}", NULL);
1656 	char *os = rpmExpand("%{_target_os}", NULL);
1657 	rpmSetMachine(ctx, cpu, os);
1658 	free(cpu);
1659 	free(os);
1660     }
1661 
1662 #ifdef WITH_LUA
1663     /* Force Lua state initialization */
1664     rpmluaGetGlobalState();
1665 #endif
1666     rc = 0;
1667 
1668 exit:
1669     rpmrcCtxRelease(ctx);
1670     return rc;
1671 }
1672 
rpmFreeRpmrc(void)1673 void rpmFreeRpmrc(void)
1674 {
1675     rpmrcCtx ctx = rpmrcCtxAcquire(1);
1676     int i, j, k;
1677 
1678     ctx->platpat = argvFree(ctx->platpat);
1679 
1680     for (i = 0; i < RPM_MACHTABLE_COUNT; i++) {
1681 	tableType t;
1682 	t = ctx->tables + i;
1683 	if (t->equiv.list) {
1684 	    for (j = 0; j < t->equiv.count; j++)
1685 		t->equiv.list[j].name = _free(t->equiv.list[j].name);
1686 	    t->equiv.list = _free(t->equiv.list);
1687 	    t->equiv.count = 0;
1688 	}
1689 	if (t->cache.cache) {
1690 	    for (j = 0; j < t->cache.size; j++) {
1691 		machCacheEntry e;
1692 		e = t->cache.cache + j;
1693 		if (e == NULL)
1694 		    continue;
1695 		e->name = _free(e->name);
1696 		if (e->equivs) {
1697 		    for (k = 0; k < e->count; k++)
1698 			e->equivs[k] = _free(e->equivs[k]);
1699 		    e->equivs = _free(e->equivs);
1700 		}
1701 	    }
1702 	    t->cache.cache = _free(t->cache.cache);
1703 	    t->cache.size = 0;
1704 	}
1705 	if (t->defaults) {
1706 	    for (j = 0; j < t->defaultsLength; j++) {
1707 		t->defaults[j].name = _free(t->defaults[j].name);
1708 		t->defaults[j].defName = _free(t->defaults[j].defName);
1709 	    }
1710 	    t->defaults = _free(t->defaults);
1711 	    t->defaultsLength = 0;
1712 	}
1713 	if (t->canons) {
1714 	    for (j = 0; j < t->canonsLength; j++) {
1715 		t->canons[j].name = _free(t->canons[j].name);
1716 		t->canons[j].short_name = _free(t->canons[j].short_name);
1717 	    }
1718 	    t->canons = _free(t->canons);
1719 	    t->canonsLength = 0;
1720 	}
1721     }
1722 
1723     for (i = 0; i < RPMVAR_NUM; i++) {
1724 	struct rpmvarValue * vp;
1725 	while ((vp = ctx->values[i].next) != NULL) {
1726 	    ctx->values[i].next = vp->next;
1727 	    vp->value = _free(vp->value);
1728 	    vp->arch = _free(vp->arch);
1729 	    vp = _free(vp);
1730 	}
1731 	ctx->values[i].value = _free(ctx->values[i].value);
1732 	ctx->values[i].arch = _free(ctx->values[i].arch);
1733     }
1734     ctx->current[OS] = _free(ctx->current[OS]);
1735     ctx->current[ARCH] = _free(ctx->current[ARCH]);
1736     ctx->machDefaults = 0;
1737     ctx->pathDefaults = 0;
1738 
1739     /* XXX doesn't really belong here but... */
1740     rpmFreeCrypto();
1741 #ifdef WITH_LUA
1742     rpmlua lua = rpmluaGetGlobalState();
1743     rpmluaFree(lua);
1744 #endif
1745 
1746     rpmrcCtxRelease(ctx);
1747     return;
1748 }
1749 
rpmShowRC(FILE * fp)1750 int rpmShowRC(FILE * fp)
1751 {
1752     /* Write-context necessary as this calls rpmSetTables(), ugh */
1753     rpmrcCtx ctx = rpmrcCtxAcquire(1);
1754     const struct rpmOption *opt;
1755     rpmds ds = NULL;
1756     int i;
1757     machEquivTable equivTable;
1758 
1759     /* the caller may set the build arch which should be printed here */
1760     fprintf(fp, "ARCHITECTURE AND OS:\n");
1761     fprintf(fp, "build arch            : %s\n", ctx->current[ARCH]);
1762 
1763     fprintf(fp, "compatible build archs:");
1764     equivTable = &ctx->tables[RPM_MACHTABLE_BUILDARCH].equiv;
1765     for (i = 0; i < equivTable->count; i++)
1766 	fprintf(fp," %s", equivTable->list[i].name);
1767     fprintf(fp, "\n");
1768 
1769     fprintf(fp, "build os              : %s\n", ctx->current[OS]);
1770 
1771     fprintf(fp, "compatible build os's :");
1772     equivTable = &ctx->tables[RPM_MACHTABLE_BUILDOS].equiv;
1773     for (i = 0; i < equivTable->count; i++)
1774 	fprintf(fp," %s", equivTable->list[i].name);
1775     fprintf(fp, "\n");
1776 
1777     rpmSetTables(ctx, RPM_MACHTABLE_INSTARCH, RPM_MACHTABLE_INSTOS);
1778     rpmSetMachine(ctx, NULL, NULL);	/* XXX WTFO? Why bother? */
1779 
1780     fprintf(fp, "install arch          : %s\n", ctx->current[ARCH]);
1781     fprintf(fp, "install os            : %s\n", ctx->current[OS]);
1782 
1783     fprintf(fp, "compatible archs      :");
1784     equivTable = &ctx->tables[RPM_MACHTABLE_INSTARCH].equiv;
1785     for (i = 0; i < equivTable->count; i++)
1786 	fprintf(fp," %s", equivTable->list[i].name);
1787     fprintf(fp, "\n");
1788 
1789     fprintf(fp, "compatible os's       :");
1790     equivTable = &ctx->tables[RPM_MACHTABLE_INSTOS].equiv;
1791     for (i = 0; i < equivTable->count; i++)
1792 	fprintf(fp," %s", equivTable->list[i].name);
1793     fprintf(fp, "\n");
1794 
1795     fprintf(fp, "\nRPMRC VALUES:\n");
1796     for (i = 0, opt = optionTable; i < optionTableSize; i++, opt++) {
1797 	const char *s = rpmGetVarArch(ctx, opt->var, NULL);
1798 	if (s != NULL || rpmIsVerbose())
1799 	    fprintf(fp, "%-21s : %s\n", opt->name, s ? s : "(not set)");
1800     }
1801     fprintf(fp, "\n");
1802 
1803     fprintf(fp, "Features supported by rpmlib:\n");
1804     rpmdsRpmlib(&ds, NULL);
1805     ds = rpmdsInit(ds);
1806     while (rpmdsNext(ds) >= 0) {
1807         const char * DNEVR = rpmdsDNEVR(ds);
1808         if (DNEVR != NULL)
1809             fprintf(fp, "    %s\n", DNEVR+2);
1810     }
1811     ds = rpmdsFree(ds);
1812     fprintf(fp, "\n");
1813 
1814     fprintf(fp, "Macro path: %s\n", macrofiles);
1815     fprintf(fp, "\n");
1816 
1817     rpmDumpMacroTable(NULL, fp);
1818 
1819     /* XXX: Move this earlier eventually... */
1820     rpmrcCtxRelease(ctx);
1821 
1822     return 0;
1823 }
1824 
rpmMachineScore(int type,const char * name)1825 int rpmMachineScore(int type, const char * name)
1826 {
1827     int score = 0;
1828     if (name) {
1829 	rpmrcCtx ctx = rpmrcCtxAcquire(0);
1830 	machEquivInfo info = machEquivSearch(&ctx->tables[type].equiv, name);
1831 	if (info)
1832 	    score = info->score;
1833 	rpmrcCtxRelease(ctx);
1834     }
1835     return score;
1836 }
1837 
rpmIsKnownArch(const char * name)1838 int rpmIsKnownArch(const char *name)
1839 {
1840     rpmrcCtx ctx = rpmrcCtxAcquire(0);
1841     canonEntry canon = lookupInCanonTable(name,
1842 			    ctx->tables[RPM_MACHTABLE_INSTARCH].canons,
1843 			    ctx->tables[RPM_MACHTABLE_INSTARCH].canonsLength);
1844     int known = (canon != NULL || rstreq(name, "noarch"));
1845     rpmrcCtxRelease(ctx);
1846     return known;
1847 }
1848 
rpmGetArchInfo(const char ** name,int * num)1849 void rpmGetArchInfo(const char ** name, int * num)
1850 {
1851     rpmrcCtx ctx = rpmrcCtxAcquire(0);
1852     getMachineInfo(ctx, ARCH, name, num);
1853     rpmrcCtxRelease(ctx);
1854 }
1855 
rpmGetArchColor(const char * arch)1856 int rpmGetArchColor(const char *arch)
1857 {
1858     rpmrcCtx ctx = rpmrcCtxAcquire(0);
1859     const char *color;
1860     char *e;
1861     int color_i = -1; /* assume failure */
1862 
1863     arch = lookupInDefaultTable(arch,
1864 			    ctx->tables[ctx->currTables[ARCH]].defaults,
1865 			    ctx->tables[ctx->currTables[ARCH]].defaultsLength);
1866     color = rpmGetVarArch(ctx, RPMVAR_ARCHCOLOR, arch);
1867     if (color) {
1868 	color_i = strtol(color, &e, 10);
1869 	if (!(e && *e == '\0')) {
1870 	    color_i = -1;
1871 	}
1872     }
1873     rpmrcCtxRelease(ctx);
1874 
1875     return color_i;
1876 }
1877 
rpmGetOsInfo(const char ** name,int * num)1878 void rpmGetOsInfo(const char ** name, int * num)
1879 {
1880     rpmrcCtx ctx = rpmrcCtxAcquire(0);
1881     getMachineInfo(ctx, OS, name, num);
1882     rpmrcCtxRelease(ctx);
1883 }
1884 
1885