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