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