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