Eliminate type "byte"
[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 <rpmlib.h>
18 #include <rpmmacro.h>
19 #include <rpmfileutil.h>
20 #include <rpmstring.h>
21 #include "rpmio/rpmlua.h"
22
23 #include <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 const char ** platpat = NULL;
46 static int nplatpat = 0;
47
48 typedef const char * cptr_t;
49
50 typedef struct machCacheEntry_s {
51     const 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     const 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     const char * value;
74     /* eventually, this arch will be replaced with a generic condition */
75     const char * arch;
76 struct rpmvarValue * next;
77 };
78
79 struct rpmOption {
80     const 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 const char * name;
91 const char * defName;
92 } * defaultEntry;
93
94 typedef struct canonEntry_s {
95 const char * name;
96 const 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 const 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 int 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 int 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(((struct rpmOption *) a)->name,
166                       ((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 int 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 RPMLOG_ERR;
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 RPMLOG_ERR;
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(RPMLOG_ERR);
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 0;
371 }
372
373 static int 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 RPMLOG_ERR;
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 RPMLOG_ERR;
394     }
395
396     t->name = xstrdup(t->name);
397     t->defName = (t->defName ? xstrdup(t->defName) : NULL);
398
399     return 0;
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 int doReadRC( FD_t fd, const char * urlfn)
503 {
504     const 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 0;
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 = 1;
524     } else
525         rc = 0;
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 1;
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, *fn;
572
573             arch = val = fn = NULL;
574             if (*se == '\0') {
575                 rpmlog(RPMLOG_ERR, _("missing argument for %s at %s:%d\n"),
576                       option->name, urlfn, linenum);
577                 return 1;
578             }
579
580             switch (option->var) {
581             case RPMVAR_INCLUDE:
582               { FD_t fdinc;
583
584                 s = se;
585                 while (*se && !xisspace(*se)) se++;
586                 if (*se != '\0') *se++ = '\0';
587
588                 rpmRebuildTargetVars(NULL, NULL);
589
590                 fn = rpmGetPath(s, NULL);
591                 if (fn == NULL || *fn == '\0') {
592                     rpmlog(RPMLOG_ERR, _("%s expansion failed at %s:%d \"%s\"\n"),
593                         option->name, urlfn, linenum, s);
594                     fn = _free(fn);
595                     return 1;
596                 }
597
598                 fdinc = Fopen(fn, "r.fpio");
599                 if (fdinc == NULL || Ferror(fdinc)) {
600                     rpmlog(RPMLOG_ERR, _("cannot open %s at %s:%d: %s\n"),
601                         fn, urlfn, linenum, Fstrerror(fdinc));
602                     rc = 1;
603                 } else {
604                     rc = doReadRC(fdinc, fn);
605                 }
606                 fn = _free(fn);
607                 if (rc) return rc;
608                 continue;       /* XXX don't save include value as var/macro */
609               } break;
610             default:
611                 break;
612             }
613
614             if (option->archSpecific) {
615                 arch = se;
616                 while (*se && !xisspace(*se)) se++;
617                 if (*se == '\0') {
618                     rpmlog(RPMLOG_ERR,
619                                 _("missing architecture for %s at %s:%d\n"),
620                                 option->name, urlfn, linenum);
621                     return 1;
622                 }
623                 *se++ = '\0';
624                 while (*se && xisspace(*se)) se++;
625                 if (*se == '\0') {
626                     rpmlog(RPMLOG_ERR,
627                                 _("missing argument for %s at %s:%d\n"),
628                                 option->name, urlfn, linenum);
629                     return 1;
630                 }
631             }
632         
633             val = se;
634
635             /* Only add macros if appropriate for this arch */
636             if (option->macroize &&
637               (arch == NULL || !strcmp(arch, current[ARCH]))) {
638                 char *n, *name;
639                 n = name = xmalloc(strlen(option->name)+2);
640                 if (option->localize)
641                     *n++ = '_';
642                 strcpy(n, option->name);
643                 addMacro(NULL, name, NULL, val, RMIL_RPMRC);
644                 free(name);
645             }
646             rpmSetVarArch(option->var, val, arch);
647             fn = _free(fn);
648
649         } else {        /* For arch/os compatibilty tables ... */
650             int gotit;
651             int i;
652
653             gotit = 0;
654
655             for (i = 0; i < RPM_MACHTABLE_COUNT; i++) {
656                 if (!strncmp(tables[i].key, s, strlen(tables[i].key)))
657                     break;
658             }
659
660             if (i < RPM_MACHTABLE_COUNT) {
661                 const char *rest = s + strlen(tables[i].key);
662                 if (*rest == '_') rest++;
663
664                 if (!strcmp(rest, "compat")) {
665                     if (machCompatCacheAdd(se, urlfn, linenum,
666                                                 &tables[i].cache))
667                         return 1;
668                     gotit = 1;
669                 } else if (tables[i].hasTranslate &&
670                            !strcmp(rest, "translate")) {
671                     if (addDefault(&tables[i].defaults,
672                                    &tables[i].defaultsLength,
673                                    se, urlfn, linenum))
674                         return 1;
675                     gotit = 1;
676                 } else if (tables[i].hasCanon &&
677                            !strcmp(rest, "canon")) {
678                     if (addCanon(&tables[i].canons, &tables[i].canonsLength,
679                                  se, urlfn, linenum))
680                         return 1;
681                     gotit = 1;
682                 }
683             }
684
685             if (!gotit) {
686                 rpmlog(RPMLOG_ERR, _("bad option '%s' at %s:%d\n"),
687                             s, urlfn, linenum);
688             }
689         }
690     }
691
692     return 0;
693 }
694
695
696 /**
697  */
698 static int rpmPlatform(const char * platform)
699 {
700     char *cpu = NULL, *vendor = NULL, *os = NULL, *gnu = NULL;
701     uint8_t * b = NULL;
702     ssize_t blen = 0;
703     int init_platform = 0;
704     char * p, * pe;
705     int rc;
706
707     rc = rpmioSlurp(platform, &b, &blen);
708
709     if (rc || b == NULL || blen <= 0) {
710         rc = -1;
711         goto exit;
712     }
713
714     p = (char *)b;
715     for (pe = p; p && *p; p = pe) {
716         pe = strchr(p, '\n');
717         if (pe)
718             *pe++ = '\0';
719
720         while (*p && isspace(*p))
721             p++;
722         if (*p == '\0' || *p == '#')
723             continue;
724
725         if (init_platform) {
726             char * t = p + strlen(p);
727
728             while (--t > p && isspace(*t))
729                 *t = '\0';
730             if (t > p) {
731                 platpat = xrealloc(platpat, (nplatpat + 2) * sizeof(*platpat));
732                 platpat[nplatpat] = xstrdup(p);
733                 nplatpat++;
734                 platpat[nplatpat] = NULL;
735             }
736             continue;
737         }
738
739         cpu = p;
740         vendor = "unknown";
741         os = "unknown";
742         gnu = NULL;
743         while (*p && !(*p == '-' || isspace(*p)))
744             p++;
745         if (*p != '\0') *p++ = '\0';
746
747         vendor = p;
748         while (*p && !(*p == '-' || isspace(*p)))
749             p++;
750         if (*p != '-') {
751             if (*p != '\0') *p++ = '\0';
752             os = vendor;
753             vendor = "unknown";
754         } else {
755             if (*p != '\0') *p++ = '\0';
756
757             os = p;
758             while (*p && !(*p == '-' || isspace(*p)))
759                 p++;
760             if (*p == '-') {
761                 *p++ = '\0';
762
763                 gnu = p;
764                 while (*p && !(*p == '-' || isspace(*p)))
765                     p++;
766             }
767             if (*p != '\0') *p++ = '\0';
768         }
769
770         addMacro(NULL, "_host_cpu", NULL, cpu, -1);
771         addMacro(NULL, "_host_vendor", NULL, vendor, -1);
772         addMacro(NULL, "_host_os", NULL, os, -1);
773
774         platpat = xrealloc(platpat, (nplatpat + 2) * sizeof(*platpat));
775         platpat[nplatpat] = rpmExpand("%{_host_cpu}-%{_host_vendor}-%{_host_os}", (gnu && *gnu ? "-" : NULL), gnu, NULL);
776         nplatpat++;
777         platpat[nplatpat] = NULL;
778         
779         init_platform++;
780     }
781     rc = (init_platform ? 0 : -1);
782
783 exit:
784     b = _free(b);
785     return rc;
786 }
787
788
789 #       if defined(__linux__) && defined(__i386__)
790 #include <setjmp.h>
791 #include <signal.h>
792
793 /*
794  * Generic CPUID function
795  */
796 static inline void cpuid(unsigned int op, int *eax, int *ebx, int *ecx, int *edx)
797 {
798     asm volatile (
799         "pushl  %%ebx           \n"
800         "cpuid                  \n"
801         "movl   %%ebx,  %%esi   \n"
802         "popl   %%ebx           \n"
803     : "=a" (*eax), "=S" (*ebx), "=c" (*ecx), "=d" (*edx)
804     : "a" (op));
805 }
806
807 /*
808  * CPUID functions returning a single datum
809  */
810 static inline unsigned int cpuid_eax(unsigned int op)
811 {
812         unsigned int tmp, val;
813         cpuid(op, &val, &tmp, &tmp, &tmp);
814         return val;
815 }
816
817 static inline unsigned int cpuid_ebx(unsigned int op)
818 {
819         unsigned int tmp, val;
820         cpuid(op, &tmp, &val, &tmp, &tmp);
821         return val;
822 }
823
824 static inline unsigned int cpuid_ecx(unsigned int op)
825 {
826         unsigned int tmp, val;
827         cpuid(op, &tmp, &tmp, &val, &tmp);
828         return val;
829 }
830
831 static inline unsigned int cpuid_edx(unsigned int op)
832 {
833         unsigned int tmp, val;
834         cpuid(op, &tmp, &tmp, &tmp, &val);
835         return val;
836 }
837
838 static sigjmp_buf jenv;
839
840 static inline void model3(int _unused)
841 {
842         siglongjmp(jenv, 1);
843 }
844
845 static inline int RPMClass(void)
846 {
847         int cpu;
848         unsigned int tfms, junk, cap, capamd;
849         struct sigaction oldsa;
850         
851         sigaction(SIGILL, NULL, &oldsa);
852         signal(SIGILL, model3);
853         
854         if (sigsetjmp(jenv, 1)) {
855                 sigaction(SIGILL, &oldsa, NULL);
856                 return 3;
857         }
858                 
859         if (cpuid_eax(0x000000000)==0) {
860                 sigaction(SIGILL, &oldsa, NULL);
861                 return 4;
862         }
863
864         cpuid(0x00000001, &tfms, &junk, &junk, &cap);
865         cpuid(0x80000001, &junk, &junk, &junk, &capamd);
866         
867         cpu = (tfms>>8)&15;
868         
869         sigaction(SIGILL, &oldsa, NULL);
870
871         if (cpu < 6)
872                 return cpu;
873                 
874         if (cap & (1<<15)) {
875                 /* CMOV supported? */
876                 if (capamd & (1<<30))
877                         return 7;       /* 3DNOWEXT supported */
878                 return 6;
879         }
880                 
881         return 5;
882 }
883
884 /* should only be called for model 6 CPU's */
885 static int is_athlon(void)
886 {
887         unsigned int eax, ebx, ecx, edx;
888         char vendor[16];
889         int i;
890         
891         cpuid (0, &eax, &ebx, &ecx, &edx);
892
893         /* If you care about space, you can just check ebx, ecx and edx directly
894            instead of forming a string first and then doing a strcmp */
895         memset(vendor, 0, sizeof(vendor));
896         
897         for (i=0; i<4; i++)
898                 vendor[i] = (unsigned char) (ebx >>(8*i));
899         for (i=0; i<4; i++)
900                 vendor[4+i] = (unsigned char) (edx >>(8*i));
901         for (i=0; i<4; i++)
902                 vendor[8+i] = (unsigned char) (ecx >>(8*i));
903                 
904         if (strncmp(vendor, "AuthenticAMD", 12) != 0)  
905                 return 0;
906
907         return 1;
908 }
909
910 static int is_pentium3()
911 {
912     unsigned int eax, ebx, ecx, edx, family, model;
913     char vendor[16];
914     cpuid(0, &eax, &ebx, &ecx, &edx);
915     memset(vendor, 0, sizeof(vendor));
916     *((unsigned int *)&vendor[0]) = ebx;
917     *((unsigned int *)&vendor[4]) = edx;
918     *((unsigned int *)&vendor[8]) = ecx;
919     if (strncmp(vendor, "GenuineIntel", 12) != 0)
920         return 0;
921     cpuid(1, &eax, &ebx, &ecx, &edx);
922     family = (eax >> 8) & 0x0f;
923     model = (eax >> 4) & 0x0f;
924     if (family == 6)
925         switch (model)
926         {
927             case 7:     // Pentium III, Pentium III Xeon (model 7)
928             case 8:     // Pentium III, Pentium III Xeon, Celeron (model 8)
929             case 9:     // Pentium M
930                         /*
931                             Intel recently announced its new technology for mobile platforms,
932                             named Centrino, and presents it as a big advance in mobile PCs.
933                             One of the main part of Centrino consists in a brand new CPU,
934                             the Pentium M, codenamed Banias, that we'll study in this review.
935                             A particularity of this CPU is that it was designed for mobile platform
936                             exclusively, unlike previous mobile CPU (Pentium III-M, Pentium 4-M)
937                             that share the same micro-architecture as their desktop counterparts.
938                             The Pentium M introduces a new micro-architecture, adapted for mobility
939                             constraints, and that is halfway between the Pentium III and the Pentium 4.
940                                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
941                         */
942             case 10:    // Pentium III Xeon (model A)
943             case 11:    // Pentium III (model B)
944                 return 1;
945         }
946     return 0;
947 }
948
949 static int is_pentium4()
950 {
951     unsigned int eax, ebx, ecx, edx, family, model;
952     char vendor[16];
953     cpuid(0, &eax, &ebx, &ecx, &edx);
954     memset(vendor, 0, sizeof(vendor));
955     *((unsigned int *)&vendor[0]) = ebx;
956     *((unsigned int *)&vendor[4]) = edx;
957     *((unsigned int *)&vendor[8]) = ecx;
958     if (strncmp(vendor, "GenuineIntel", 12) != 0)
959         return 0;
960     cpuid(1, &eax, &ebx, &ecx, &edx);
961     family = (eax >> 8) & 0x0f;
962     model = (eax >> 4) & 0x0f;
963     if (family == 15)
964         switch (model)
965         {
966             case 0:     // Pentium 4, Pentium 4 Xeon                 (0.18um)
967             case 1:     // Pentium 4, Pentium 4 Xeon MP, Celeron     (0.18um)
968             case 2:     // Pentium 4, Mobile Pentium 4-M,
969                         // Pentium 4 Xeon, Pentium 4 Xeon MP,
970                         // Celeron, Mobile Celron                    (0.13um)
971             case 3:     // Pentium 4, Celeron                        (0.09um)
972                 return 1;
973         }
974     return 0;
975 }
976
977 #endif
978
979 #if defined(__linux__) && defined(__powerpc__)
980 static jmp_buf mfspr_jmpbuf;
981
982 static void mfspr_ill(int notused)
983 {
984     longjmp(mfspr_jmpbuf, -1);
985 }
986 #endif
987
988 /**
989  */
990 static void defaultMachine(const char ** arch,
991                 const char ** os)
992 {
993     static struct utsname un;
994     static int gotDefaults = 0;
995     char * chptr;
996     canonEntry canon;
997     int rc;
998
999     while (!gotDefaults) {
1000         if (!rpmPlatform(platform)) {
1001             const char * s;
1002             s = rpmExpand("%{_host_cpu}", NULL);
1003             if (s) {
1004                 strncpy(un.machine, s, sizeof(un.machine));
1005                 un.machine[sizeof(un.machine)-1] = '\0';
1006                 s = _free(s);
1007             }
1008             s = rpmExpand("%{_host_os}", NULL);
1009             if (s) {
1010                 strncpy(un.sysname, s, sizeof(un.sysname));
1011                 un.sysname[sizeof(un.sysname)-1] = '\0';
1012                 s = _free(s);
1013             }
1014             gotDefaults = 1;
1015             break;
1016         }
1017         rc = uname(&un);
1018         if (rc < 0) return;
1019
1020 #if !defined(__linux__)
1021 #ifdef SNI
1022         /* USUALLY un.sysname on sinix does start with the word "SINIX"
1023          * let's be absolutely sure
1024          */
1025         strncpy(un.sysname, "SINIX", sizeof(un.sysname));
1026 #endif
1027         if (!strcmp(un.sysname, "AIX")) {
1028             strcpy(un.machine, __power_pc() ? "ppc" : "rs6000");
1029             sprintf(un.sysname,"aix%s.%s", un.version, un.release);
1030         }
1031         else if(!strcmp(un.sysname, "Darwin")) { 
1032 #ifdef __ppc__
1033             strcpy(un.machine, "ppc");
1034 #else ifdef __i386__
1035             strcpy(un.machine, "i386");
1036 #endif 
1037         }
1038         else if (!strcmp(un.sysname, "SunOS")) {
1039             if (!strncmp(un.release,"4", 1)) /* SunOS 4.x */ {
1040                 int fd;
1041                 for (fd = 0;
1042                     (un.release[fd] != 0 && (fd < sizeof(un.release)));
1043                     fd++) {
1044                       if (!xisdigit(un.release[fd]) && (un.release[fd] != '.')) {
1045                         un.release[fd] = 0;
1046                         break;
1047                       }
1048                     }
1049                     sprintf(un.sysname,"sunos%s",un.release);
1050             }
1051
1052             else /* Solaris 2.x: n.x.x becomes n-3.x.x */
1053                 sprintf(un.sysname, "solaris%1d%s", atoi(un.release)-3,
1054                         un.release+1+(atoi(un.release)/10));
1055
1056             /* Solaris on Intel hardware reports i86pc instead of i386
1057              * (at least on 2.6 and 2.8)
1058              */
1059             if (!strcmp(un.machine, "i86pc"))
1060                 sprintf(un.machine, "i386");
1061         }
1062         else if (!strcmp(un.sysname, "HP-UX"))
1063             /*make un.sysname look like hpux9.05 for example*/
1064             sprintf(un.sysname, "hpux%s", strpbrk(un.release, "123456789"));
1065         else if (!strcmp(un.sysname, "OSF1"))
1066             /*make un.sysname look like osf3.2 for example*/
1067             sprintf(un.sysname, "osf%s", strpbrk(un.release, "123456789"));
1068         else if (!strncmp(un.sysname, "IP", 2))
1069             un.sysname[2] = '\0';
1070         else if (!strncmp(un.sysname, "SINIX", 5)) {
1071             sprintf(un.sysname, "sinix%s",un.release);
1072             if (!strncmp(un.machine, "RM", 2))
1073                 sprintf(un.machine, "mips");
1074         }
1075         else if ((!strncmp(un.machine, "34", 2) ||
1076                 !strncmp(un.machine, "33", 2)) && \
1077                 !strncmp(un.release, "4.0", 3))
1078         {
1079             /* we are on ncr-sysv4 */
1080             char * prelid = NULL;
1081             FD_t fd = Fopen("/etc/.relid", "r.fdio");
1082             int gotit = 0;
1083             if (fd != NULL && !Ferror(fd)) {
1084                 chptr = xcalloc(1, 256);
1085                 {   int irelid = Fread(chptr, sizeof(*chptr), 256, fd);
1086                     (void) Fclose(fd);
1087                     /* example: "112393 RELEASE 020200 Version 01 OS" */
1088                     if (irelid > 0) {
1089                         if ((prelid = strstr(chptr, "RELEASE "))){
1090                             prelid += strlen("RELEASE ")+1;
1091                             sprintf(un.sysname,"ncr-sysv4.%.*s",1,prelid);
1092                             gotit = 1;
1093                         }
1094                     }
1095                 }
1096                 chptr = _free (chptr);
1097             }
1098             if (!gotit) /* parsing /etc/.relid file failed? */
1099                 strcpy(un.sysname,"ncr-sysv4");
1100             /* wrong, just for now, find out how to look for i586 later*/
1101             strcpy(un.machine,"i486");
1102         }
1103 #endif  /* __linux__ */
1104
1105         /* get rid of the hyphens in the sysname */
1106         for (chptr = un.machine; *chptr != '\0'; chptr++)
1107             if (*chptr == '/') *chptr = '-';
1108
1109 #       if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL)
1110             /* little endian */
1111             strcpy(un.machine, "mipsel");
1112 #       elif defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB)
1113            /* big endian */
1114                 strcpy(un.machine, "mips");
1115 #       endif
1116
1117 #       if defined(__hpux) && defined(_SC_CPU_VERSION)
1118         {
1119 #           if !defined(CPU_PA_RISC1_2)
1120 #                define CPU_PA_RISC1_2  0x211 /* HP PA-RISC1.2 */
1121 #           endif
1122 #           if !defined(CPU_PA_RISC2_0)
1123 #               define CPU_PA_RISC2_0  0x214 /* HP PA-RISC2.0 */
1124 #           endif
1125             int cpu_version = sysconf(_SC_CPU_VERSION);
1126
1127 #           if defined(CPU_HP_MC68020)
1128                 if (cpu_version == CPU_HP_MC68020)
1129                     strcpy(un.machine, "m68k");
1130 #           endif
1131 #           if defined(CPU_HP_MC68030)
1132                 if (cpu_version == CPU_HP_MC68030)
1133                     strcpy(un.machine, "m68k");
1134 #           endif
1135 #           if defined(CPU_HP_MC68040)
1136                 if (cpu_version == CPU_HP_MC68040)
1137                     strcpy(un.machine, "m68k");
1138 #           endif
1139
1140 #           if defined(CPU_PA_RISC1_0)
1141                 if (cpu_version == CPU_PA_RISC1_0)
1142                     strcpy(un.machine, "hppa1.0");
1143 #           endif
1144 #           if defined(CPU_PA_RISC1_1)
1145                 if (cpu_version == CPU_PA_RISC1_1)
1146                     strcpy(un.machine, "hppa1.1");
1147 #           endif
1148 #           if defined(CPU_PA_RISC1_2)
1149                 if (cpu_version == CPU_PA_RISC1_2)
1150                     strcpy(un.machine, "hppa1.2");
1151 #           endif
1152 #           if defined(CPU_PA_RISC2_0)
1153                 if (cpu_version == CPU_PA_RISC2_0)
1154                     strcpy(un.machine, "hppa2.0");
1155 #           endif
1156         }
1157 #       endif   /* hpux */
1158
1159 #       if defined(__linux__) && defined(__sparc__)
1160         if (!strcmp(un.machine, "sparc")) {
1161             #define PERS_LINUX          0x00000000
1162             #define PERS_LINUX_32BIT    0x00800000
1163             #define PERS_LINUX32        0x00000008
1164
1165             extern int personality(unsigned long);
1166             int oldpers;
1167             
1168             oldpers = personality(PERS_LINUX_32BIT);
1169             if (oldpers != -1) {
1170                 if (personality(PERS_LINUX) != -1) {
1171                     uname(&un);
1172                     if (! strcmp(un.machine, "sparc64")) {
1173                         strcpy(un.machine, "sparcv9");
1174                         oldpers = PERS_LINUX32;
1175                     }
1176                 }
1177                 personality(oldpers);
1178             }
1179         }
1180 #       endif   /* sparc*-linux */
1181
1182 #       if defined(__GNUC__) && defined(__alpha__)
1183         {
1184             unsigned long amask, implver;
1185             register long v0 __asm__("$0") = -1;
1186             __asm__ (".long 0x47e00c20" : "=r"(v0) : "0"(v0));
1187             amask = ~v0;
1188             __asm__ (".long 0x47e03d80" : "=r"(v0));
1189             implver = v0;
1190             switch (implver) {
1191             case 1:
1192                 switch (amask) {
1193                 case 0: strcpy(un.machine, "alphaev5"); break;
1194                 case 1: strcpy(un.machine, "alphaev56"); break;
1195                 case 0x101: strcpy(un.machine, "alphapca56"); break;
1196                 }
1197                 break;
1198             case 2:
1199                 switch (amask) {
1200                 case 0x303: strcpy(un.machine, "alphaev6"); break;
1201                 case 0x307: strcpy(un.machine, "alphaev67"); break;
1202                 }
1203                 break;
1204             }
1205         }
1206 #       endif
1207
1208 #       if defined(__linux__) && defined(__i386__)
1209         {
1210             char class = (char) (RPMClass() | '0');
1211
1212             if ((class == '6' && is_athlon()) || class == '7')
1213                 strcpy(un.machine, "athlon");
1214             else if (is_pentium4())
1215                 strcpy(un.machine, "pentium4");
1216             else if (is_pentium3())
1217                 strcpy(un.machine, "pentium3");
1218             else if (strchr("3456", un.machine[1]) && un.machine[1] != class)
1219                 un.machine[1] = class;
1220         }
1221 #       endif
1222
1223         /* the uname() result goes through the arch_canon table */
1224         canon = lookupInCanonTable(un.machine,
1225                                    tables[RPM_MACHTABLE_INSTARCH].canons,
1226                                    tables[RPM_MACHTABLE_INSTARCH].canonsLength);
1227         if (canon)
1228             strcpy(un.machine, canon->short_name);
1229
1230         canon = lookupInCanonTable(un.sysname,
1231                                    tables[RPM_MACHTABLE_INSTOS].canons,
1232                                    tables[RPM_MACHTABLE_INSTOS].canonsLength);
1233         if (canon)
1234             strcpy(un.sysname, canon->short_name);
1235         gotDefaults = 1;
1236         break;
1237     }
1238
1239     if (arch) *arch = un.machine;
1240     if (os) *os = un.sysname;
1241 }
1242
1243 static
1244 const char * rpmGetVarArch(int var, const char * arch)
1245 {
1246     const struct rpmvarValue * next;
1247
1248     if (arch == NULL) arch = current[ARCH];
1249
1250     if (arch) {
1251         next = &values[var];
1252         while (next) {
1253             if (next->arch && !strcmp(next->arch, arch)) return next->value;
1254             next = next->next;
1255         }
1256     }
1257
1258     next = values + var;
1259     while (next && next->arch) next = next->next;
1260
1261     return next ? next->value : NULL;
1262 }
1263
1264 static const char *rpmGetVar(int var)
1265 {
1266     return rpmGetVarArch(var, NULL);
1267 }
1268
1269 static void rpmSetVarArch(int var, const char * val, const char * arch)
1270 {
1271     struct rpmvarValue * next = values + var;
1272
1273     if (next->value) {
1274         if (arch) {
1275             while (next->next) {
1276                 if (next->arch && !strcmp(next->arch, arch)) break;
1277                 next = next->next;
1278             }
1279         } else {
1280             while (next->next) {
1281                 if (!next->arch) break;
1282                 next = next->next;
1283             }
1284         }
1285
1286         if (next->arch && arch && !strcmp(next->arch, arch)) {
1287             next->value = _free(next->value);
1288             next->arch = _free(next->arch);
1289         } else if (next->arch || arch) {
1290             next->next = xmalloc(sizeof(*next->next));
1291             next = next->next;
1292             next->value = NULL;
1293             next->arch = NULL;
1294             next->next = NULL;
1295         }
1296     }
1297
1298     next->value = _free(next->value);
1299     next->value = xstrdup(val);
1300     next->arch = (arch ? xstrdup(arch) : NULL);
1301 }
1302
1303 void rpmSetTables(int archTable, int osTable)
1304 {
1305     const char * arch, * os;
1306
1307     defaultMachine(&arch, &os);
1308
1309     if (currTables[ARCH] != archTable) {
1310         currTables[ARCH] = archTable;
1311         rebuildCompatTables(ARCH, arch);
1312     }
1313
1314     if (currTables[OS] != osTable) {
1315         currTables[OS] = osTable;
1316         rebuildCompatTables(OS, os);
1317     }
1318 }
1319
1320 int rpmMachineScore(int type, const char * name)
1321 {
1322     machEquivInfo info = machEquivSearch(&tables[type].equiv, name);
1323     return (info != NULL ? info->score : 0);
1324 }
1325
1326 /** \ingroup rpmrc
1327  * Set current arch/os names.
1328  * NULL as argument is set to the default value (munged uname())
1329  * pushed through a translation table (if appropriate).
1330  * @deprecated Use addMacro to set _target_* macros.
1331  * @todo Eliminate 
1332  *
1333  * @param arch          arch name (or NULL)
1334  * @param os            os name (or NULL)
1335  *          */
1336
1337 static void rpmSetMachine(const char * arch, const char * os)
1338 {
1339     const char * host_cpu, * host_os;
1340
1341     defaultMachine(&host_cpu, &host_os);
1342
1343     if (arch == NULL) {
1344         arch = host_cpu;
1345         if (tables[currTables[ARCH]].hasTranslate)
1346             arch = lookupInDefaultTable(arch,
1347                             tables[currTables[ARCH]].defaults,
1348                             tables[currTables[ARCH]].defaultsLength);
1349     }
1350     if (arch == NULL) return;   /* XXX can't happen */
1351
1352     if (os == NULL) {
1353         os = host_os;
1354         if (tables[currTables[OS]].hasTranslate)
1355             os = lookupInDefaultTable(os,
1356                             tables[currTables[OS]].defaults,
1357                             tables[currTables[OS]].defaultsLength);
1358     }
1359     if (os == NULL) return;     /* XXX can't happen */
1360
1361     if (!current[ARCH] || strcmp(arch, current[ARCH])) {
1362         current[ARCH] = _free(current[ARCH]);
1363         current[ARCH] = xstrdup(arch);
1364         rebuildCompatTables(ARCH, host_cpu);
1365     }
1366
1367     if (!current[OS] || strcmp(os, current[OS])) {
1368         char * t = xstrdup(os);
1369         current[OS] = _free(current[OS]);
1370         /*
1371          * XXX Capitalizing the 'L' is needed to insure that old
1372          * XXX os-from-uname (e.g. "Linux") is compatible with the new
1373          * XXX os-from-platform (e.g "linux" from "sparc-*-linux").
1374          * XXX A copy of this string is embedded in headers and is
1375          * XXX used by rpmInstallPackage->{os,arch}Okay->rpmMachineScore->
1376          * XXX to verify correct arch/os from headers.
1377          */
1378         if (!strcmp(t, "linux"))
1379             *t = 'L';
1380         current[OS] = t;
1381         
1382         rebuildCompatTables(OS, host_os);
1383     }
1384 }
1385
1386 static void rebuildCompatTables(int type, const char * name)
1387 {
1388     machFindEquivs(&tables[currTables[type]].cache,
1389                    &tables[currTables[type]].equiv,
1390                    name);
1391 }
1392
1393 static void getMachineInfo(int type, const char ** name,
1394                         int * num)
1395 {
1396     canonEntry canon;
1397     int which = currTables[type];
1398
1399     /* use the normal canon tables, even if we're looking up build stuff */
1400     if (which >= 2) which -= 2;
1401
1402     canon = lookupInCanonTable(current[type],
1403                                tables[which].canons,
1404                                tables[which].canonsLength);
1405
1406     if (canon) {
1407         if (num) *num = canon->num;
1408         if (name) *name = canon->short_name;
1409     } else {
1410         if (num) *num = 255;
1411         if (name) *name = current[type];
1412
1413         if (tables[currTables[type]].hasCanon) {
1414             rpmlog(RPMLOG_WARNING, _("Unknown system: %s\n"), current[type]);
1415             rpmlog(RPMLOG_WARNING, _("Please contact %s\n"), PACKAGE_BUGREPORT);
1416         }
1417     }
1418 }
1419
1420 void rpmGetArchInfo(const char ** name, int * num)
1421 {
1422     getMachineInfo(ARCH, name, num);
1423 }
1424
1425 void rpmGetOsInfo(const char ** name, int * num)
1426 {
1427     getMachineInfo(OS, name, num);
1428 }
1429
1430 static void rpmRebuildTargetVars(const char ** target, const char ** canontarget)
1431 {
1432
1433     char *ca = NULL, *co = NULL, *ct = NULL;
1434     int x;
1435
1436     /* Rebuild the compat table to recalculate the current target arch.  */
1437
1438     rpmSetMachine(NULL, NULL);
1439     rpmSetTables(RPM_MACHTABLE_INSTARCH, RPM_MACHTABLE_INSTOS);
1440     rpmSetTables(RPM_MACHTABLE_BUILDARCH, RPM_MACHTABLE_BUILDOS);
1441
1442     if (target && *target) {
1443         char *c;
1444         /* Set arch and os from specified build target */
1445         ca = xstrdup(*target);
1446         if ((c = strchr(ca, '-')) != NULL) {
1447             *c++ = '\0';
1448             
1449             if ((co = strrchr(c, '-')) == NULL) {
1450                 co = c;
1451             } else {
1452                 if (!xstrcasecmp(co, "-gnu"))
1453                     *co = '\0';
1454                 if ((co = strrchr(c, '-')) == NULL)
1455                     co = c;
1456                 else
1457                     co++;
1458             }
1459             if (co != NULL) co = xstrdup(co);
1460         }
1461     } else {
1462         const char *a = NULL;
1463         const char *o = NULL;
1464         /* Set build target from rpm arch and os */
1465         rpmGetArchInfo(&a, NULL);
1466         ca = (a) ? xstrdup(a) : NULL;
1467         rpmGetOsInfo(&o, NULL);
1468         co = (o) ? xstrdup(o) : NULL;
1469     }
1470
1471     /* If still not set, Set target arch/os from default uname(2) values */
1472     if (ca == NULL) {
1473         const char *a = NULL;
1474         defaultMachine(&a, NULL);
1475         ca = (a) ? xstrdup(a) : NULL;
1476     }
1477     for (x = 0; ca[x] != '\0'; x++)
1478         ca[x] = xtolower(ca[x]);
1479
1480     if (co == NULL) {
1481         const char *o = NULL;
1482         defaultMachine(NULL, &o);
1483         co = (o) ? xstrdup(o) : NULL;
1484     }
1485     for (x = 0; co[x] != '\0'; x++)
1486         co[x] = xtolower(co[x]);
1487
1488     /* XXX For now, set canonical target to arch-os */
1489     if (ct == NULL) {
1490         ct = xmalloc(strlen(ca) + sizeof("-") + strlen(co));
1491         sprintf(ct, "%s-%s", ca, co);
1492     }
1493
1494 /*
1495  * XXX All this macro pokery/jiggery could be achieved by doing a delayed
1496  *      rpmInitMacros(NULL, PER-PLATFORM-MACRO-FILE-NAMES);
1497  */
1498     delMacro(NULL, "_target");
1499     addMacro(NULL, "_target", NULL, ct, RMIL_RPMRC);
1500     delMacro(NULL, "_target_cpu");
1501     addMacro(NULL, "_target_cpu", NULL, ca, RMIL_RPMRC);
1502     delMacro(NULL, "_target_os");
1503     addMacro(NULL, "_target_os", NULL, co, RMIL_RPMRC);
1504 /*
1505  * XXX Make sure that per-arch optflags is initialized correctly.
1506  */
1507   { const char *optflags = rpmGetVarArch(RPMVAR_OPTFLAGS, ca);
1508     if (optflags != NULL) {
1509         delMacro(NULL, "optflags");
1510         addMacro(NULL, "optflags", NULL, optflags, RMIL_RPMRC);
1511     }
1512   }
1513
1514     if (canontarget)
1515         *canontarget = ct;
1516     else
1517         ct = _free(ct);
1518     ca = _free(ca);
1519     co = _free(co);
1520 }
1521
1522 void rpmFreeRpmrc(void)
1523 {
1524     int i, j, k;
1525
1526     if (platpat)
1527     for (i = 0; i < nplatpat; i++)
1528         platpat[i] = _free(platpat[i]);
1529     platpat = _free(platpat);
1530     nplatpat = 0;
1531
1532     for (i = 0; i < RPM_MACHTABLE_COUNT; i++) {
1533         tableType t;
1534         t = tables + i;
1535         if (t->equiv.list) {
1536             for (j = 0; j < t->equiv.count; j++)
1537                 t->equiv.list[j].name = _free(t->equiv.list[j].name);
1538             t->equiv.list = _free(t->equiv.list);
1539             t->equiv.count = 0;
1540         }
1541         if (t->cache.cache) {
1542             for (j = 0; j < t->cache.size; j++) {
1543                 machCacheEntry e;
1544                 e = t->cache.cache + j;
1545                 if (e == NULL)
1546                     continue;
1547                 e->name = _free(e->name);
1548                 if (e->equivs) {
1549                     for (k = 0; k < e->count; k++)
1550                         e->equivs[k] = _free(e->equivs[k]);
1551                     e->equivs = _free(e->equivs);
1552                 }
1553             }
1554             t->cache.cache = _free(t->cache.cache);
1555             t->cache.size = 0;
1556         }
1557         if (t->defaults) {
1558             for (j = 0; j < t->defaultsLength; j++) {
1559                 t->defaults[j].name = _free(t->defaults[j].name);
1560                 t->defaults[j].defName = _free(t->defaults[j].defName);
1561             }
1562             t->defaults = _free(t->defaults);
1563             t->defaultsLength = 0;
1564         }
1565         if (t->canons) {
1566             for (j = 0; j < t->canonsLength; j++) {
1567                 t->canons[j].name = _free(t->canons[j].name);
1568                 t->canons[j].short_name = _free(t->canons[j].short_name);
1569             }
1570             t->canons = _free(t->canons);
1571             t->canonsLength = 0;
1572         }
1573     }
1574
1575     for (i = 0; i < RPMVAR_NUM; i++) {
1576         struct rpmvarValue * vp;
1577         while ((vp = values[i].next) != NULL) {
1578             values[i].next = vp->next;
1579             vp->value = _free(vp->value);
1580             vp->arch = _free(vp->arch);
1581             vp = _free(vp);
1582         }
1583         values[i].value = _free(values[i].value);
1584         values[i].arch = _free(values[i].arch);
1585     }
1586     current[OS] = _free(current[OS]);
1587     current[ARCH] = _free(current[ARCH]);
1588     defaultsInitialized = 0;
1589 /* FIX: platpat/current may be NULL */
1590     return;
1591 }
1592
1593 /** \ingroup rpmrc
1594  * Read rpmrc (and macro) configuration file(s).
1595  * @param rcfiles       colon separated files to read (NULL uses default)
1596  * @return              0 on success
1597  */
1598 static int rpmReadRC(const char * rcfiles)
1599 {
1600     char *myrcfiles, *r, *re;
1601     int rc;
1602
1603     if (!defaultsInitialized) {
1604         setDefaults();
1605         defaultsInitialized = 1;
1606     }
1607
1608     if (rcfiles == NULL)
1609         rcfiles = defrcfiles;
1610
1611     /* Read each file in rcfiles. */
1612     rc = 0;
1613     for (r = myrcfiles = xstrdup(rcfiles); r && *r != '\0'; r = re) {
1614         char fn[4096];
1615         FD_t fd;
1616
1617         /* Get pointer to rest of files */
1618         for (re = r; (re = strchr(re, ':')) != NULL; re++) {
1619             if (!(re[1] == '/' && re[2] == '/'))
1620                 break;
1621         }
1622         if (re && *re == ':')
1623             *re++ = '\0';
1624         else
1625             re = r + strlen(r);
1626
1627         /* Expand ~/ to $HOME/ */
1628         fn[0] = '\0';
1629         if (r[0] == '~' && r[1] == '/') {
1630             const char * home = getenv("HOME");
1631             if (home == NULL) {
1632             /* XXX Only /usr/lib/rpm/rpmrc must exist in default rcfiles list */
1633                 if (rcfiles == defrcfiles && myrcfiles != r)
1634                     continue;
1635                 rpmlog(RPMLOG_ERR, _("Cannot expand %s\n"), r);
1636                 rc = 1;
1637                 break;
1638             }
1639             if (strlen(home) > (sizeof(fn) - strlen(r))) {
1640                 rpmlog(RPMLOG_ERR, _("Cannot read %s, HOME is too large.\n"),
1641                                 r);
1642                 rc = 1;
1643                 break;
1644             }
1645             strcpy(fn, home);
1646             r++;
1647         }
1648         strncat(fn, r, sizeof(fn) - (strlen(fn) + 1));
1649         fn[sizeof(fn)-1] = '\0';
1650
1651         /* Read another rcfile */
1652         fd = Fopen(fn, "r.fpio");
1653         if (fd == NULL || Ferror(fd)) {
1654             /* XXX Only /usr/lib/rpm/rpmrc must exist in default rcfiles list */
1655             if (rcfiles == defrcfiles && myrcfiles != r)
1656                 continue;
1657             rpmlog(RPMLOG_ERR, _("Unable to open %s for reading: %s.\n"),
1658                  fn, Fstrerror(fd));
1659             rc = 1;
1660             break;
1661         } else {
1662             rc = doReadRC(fd, fn);
1663         }
1664         if (rc) break;
1665     }
1666     myrcfiles = _free(myrcfiles);
1667     if (rc)
1668         return rc;
1669
1670     rpmSetMachine(NULL, NULL);  /* XXX WTFO? Why bother? */
1671
1672     return rc;
1673 }
1674
1675 int rpmReadConfigFiles(const char * file, const char * target)
1676 {
1677     /* Initialize crypto engine as early as possible */
1678     if (rpmInitCrypto() < 0) {
1679         return -1;
1680     }   
1681
1682     /* Preset target macros */
1683         /* FIX: target can be NULL */
1684     rpmRebuildTargetVars(&target, NULL);
1685
1686     /* Read the files */
1687     if (rpmReadRC(file)) return -1;
1688
1689     if (macrofiles != NULL) {
1690         const char *mf = rpmGetPath(macrofiles, NULL);
1691         rpmInitMacros(NULL, mf);
1692         _free(mf);
1693     }
1694
1695     /* Reset target macros */
1696     rpmRebuildTargetVars(&target, NULL);
1697
1698     /* Finally set target platform */
1699     {   const char *cpu = rpmExpand("%{_target_cpu}", NULL);
1700         const char *os = rpmExpand("%{_target_os}", NULL);
1701         rpmSetMachine(cpu, os);
1702         cpu = _free(cpu);
1703         os = _free(os);
1704     }
1705
1706     /* Force Lua state initialization */
1707 #ifdef WITH_LUA
1708     (void)rpmluaGetPrintBuffer(NULL);
1709 #endif
1710
1711     return 0;
1712 }
1713
1714 int rpmShowRC(FILE * fp)
1715 {
1716     struct rpmOption *opt;
1717     int i;
1718     machEquivTable equivTable;
1719
1720     /* the caller may set the build arch which should be printed here */
1721     fprintf(fp, "ARCHITECTURE AND OS:\n");
1722     fprintf(fp, "build arch            : %s\n", current[ARCH]);
1723
1724     fprintf(fp, "compatible build archs:");
1725     equivTable = &tables[RPM_MACHTABLE_BUILDARCH].equiv;
1726     for (i = 0; i < equivTable->count; i++)
1727         fprintf(fp," %s", equivTable->list[i].name);
1728     fprintf(fp, "\n");
1729
1730     fprintf(fp, "build os              : %s\n", current[OS]);
1731
1732     fprintf(fp, "compatible build os's :");
1733     equivTable = &tables[RPM_MACHTABLE_BUILDOS].equiv;
1734     for (i = 0; i < equivTable->count; i++)
1735         fprintf(fp," %s", equivTable->list[i].name);
1736     fprintf(fp, "\n");
1737
1738     rpmSetTables(RPM_MACHTABLE_INSTARCH, RPM_MACHTABLE_INSTOS);
1739     rpmSetMachine(NULL, NULL);  /* XXX WTFO? Why bother? */
1740
1741     fprintf(fp, "install arch          : %s\n", current[ARCH]);
1742     fprintf(fp, "install os            : %s\n", current[OS]);
1743
1744     fprintf(fp, "compatible archs      :");
1745     equivTable = &tables[RPM_MACHTABLE_INSTARCH].equiv;
1746     for (i = 0; i < equivTable->count; i++)
1747         fprintf(fp," %s", equivTable->list[i].name);
1748     fprintf(fp, "\n");
1749
1750     fprintf(fp, "compatible os's       :");
1751     equivTable = &tables[RPM_MACHTABLE_INSTOS].equiv;
1752     for (i = 0; i < equivTable->count; i++)
1753         fprintf(fp," %s", equivTable->list[i].name);
1754     fprintf(fp, "\n");
1755
1756     fprintf(fp, "\nRPMRC VALUES:\n");
1757     for (i = 0, opt = optionTable; i < optionTableSize; i++, opt++) {
1758         const char *s = rpmGetVar(opt->var);
1759         if (s != NULL || rpmIsVerbose())
1760             fprintf(fp, "%-21s : %s\n", opt->name, s ? s : "(not set)");
1761     }
1762     fprintf(fp, "\n");
1763
1764     fprintf(fp, "Features supported by rpmlib:\n");
1765     rpmShowRpmlibProvides(fp);
1766     fprintf(fp, "\n");
1767
1768     rpmDumpMacroTable(NULL, fp);
1769
1770     return 0;
1771 }