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