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