85e7684379aa17be505cf2bfed8c15a97ffce112
[platform/upstream/rpm.git] / lib / rpmrc.c
1 #include "miscfn.h"
2
3 #include <ctype.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <sys/utsname.h>
8
9 #include "messages.h"
10 #include "misc.h"
11 #include "rpmlib.h"
12
13 /* the rpmrc is read from /etc/rpmrc or $HOME/.rpmrc - it is not affected
14    by a --root option */
15
16 struct rpmoption {
17     char * name;
18     int var;
19     int archSpecific, required;
20 };
21
22 struct archosCacheEntry {
23     char * name;
24     int count;
25     char ** equivs;
26     int visited;
27 };
28
29 struct archosCache {
30     struct archosCacheEntry * cache;
31     int size;
32 };
33
34 struct archosEquivInfo {
35     char * name;
36     int score;
37 };
38
39 struct archosEquivTable {
40     int count;
41     struct archosEquivInfo * list;
42 };
43
44 struct defaultEntry {
45     char *name;
46     char *defName;
47 };
48
49 struct canonEntry {
50     char *name;
51     char *short_name;
52     short num;
53 };
54
55 static int findArchOsScore(struct archosEquivTable * table, char * name);
56 static struct archosCacheEntry * 
57   archosCacheFindEntry(struct archosCache * cache, char * key);
58 static void archosFindEquivs(struct archosCache * cache, 
59                              struct archosEquivTable * table,
60                              char * key);
61 static void archosAddEquiv(struct archosEquivTable * table, char * name,
62                            int distance);
63 static void archosCacheEntryVisit(struct archosCache * cache, 
64                                   struct archosEquivTable * table, 
65                                   char * name,
66                                   int distance);
67 static int archosCompatCacheAdd(char * name, char * fn, int linenum,
68                                 struct archosCache * cache);
69 static struct archosEquivInfo * archosEquivSearch(
70                 struct archosEquivTable * table, char * name);
71
72 /* this *must* be kept in alphabetical order */
73 struct rpmoption optionTable[] = {
74     { "builddir",               RPMVAR_BUILDDIR,                0, 0 },
75     { "buildroot",              RPMVAR_BUILDROOT,               0, 0 },
76     { "cpiobin",                RPMVAR_CPIOBIN,                 0, 1 },
77     { "dbpath",                 RPMVAR_DBPATH,                  0, 1 },
78     { "defaultdocdir",          RPMVAR_DEFAULTDOCDIR,           0, 0 },
79     { "distribution",           RPMVAR_DISTRIBUTION,            0, 0 },
80     { "excludedocs",            RPMVAR_EXCLUDEDOCS,             0, 0 },
81     { "fixperms",               RPMVAR_FIXPERMS,                0, 1 },
82     { "ftpport",                RPMVAR_FTPPORT,                 0, 0 },
83     { "ftpproxy",               RPMVAR_FTPPROXY,                0, 0 },
84     { "gzipbin",                RPMVAR_GZIPBIN,                 0, 1 },
85     { "messagelevel",           RPMVAR_MESSAGELEVEL,            0, 0 },
86     { "netsharedpath",          RPMVAR_NETSHAREDPATH,           0, 0 },
87     { "optflags",               RPMVAR_OPTFLAGS,                1, 0 },
88     { "packager",               RPMVAR_PACKAGER,                0, 0 },
89     { "pgp_name",               RPMVAR_PGP_NAME,                0, 0 },
90     { "pgp_path",               RPMVAR_PGP_PATH,                0, 0 },
91     { "require_distribution",   RPMVAR_REQUIREDISTRIBUTION,     0, 0 },
92     { "require_icon",           RPMVAR_REQUIREICON,             0, 0 },
93     { "require_vendor",         RPMVAR_REQUIREVENDOR,           0, 0 },
94     { "root",                   RPMVAR_ROOT,                    0, 0 },
95     { "rpmdir",                 RPMVAR_RPMDIR,                  0, 0 },
96     { "signature",              RPMVAR_SIGTYPE,                 0, 0 },
97     { "sourcedir",              RPMVAR_SOURCEDIR,               0, 0 },
98     { "specdir",                RPMVAR_SPECDIR,                 0, 0 },
99     { "srcrpmdir",              RPMVAR_SRPMDIR,                 0, 0 },
100     { "timecheck",              RPMVAR_TIMECHECK,               0, 0 },
101     { "tmppath",                RPMVAR_TMPPATH,                 0, 1 },
102     { "topdir",                 RPMVAR_TOPDIR,                  0, 0 },
103     { "vendor",                 RPMVAR_VENDOR,                  0, 0 },
104 };
105
106 static int optionTableSize = sizeof(optionTable) / sizeof(struct rpmoption);
107
108 #define READ_TABLES       1
109 #define READ_OTHER        2
110
111 static int readRpmrc(FILE * fd, char * fn, int readWhat);
112 static void setDefaults(void);
113 static void setPathDefault(int var, char * s);
114 static int optionCompare(const void * a, const void * b);
115
116 static void setArchOs(char *arch, char *os, int building);
117 static int addCanon(struct canonEntry **table, int *tableLen, char *line,
118                    char *fn, int lineNum);
119 static int addDefault(struct defaultEntry **table, int *tableLen, char *line,
120                       char *fn, int lineNum);
121 static struct canonEntry *lookupInCanonTable(char *name,
122                                            struct canonEntry *table,
123                                            int tableLen);
124 static char *lookupInDefaultTable(char *name,
125                                   struct defaultEntry *table,
126                                   int tableLen);
127
128 static int archDefaultTableLen = 0;
129 static int osDefaultTableLen = 0;
130 static int archCanonTableLen = 0;
131 static int osCanonTableLen = 0;
132 static struct defaultEntry * archDefaultTable = NULL;
133 static struct defaultEntry * osDefaultTable = NULL;
134 static struct canonEntry * archCanonTable = NULL;
135 static struct canonEntry * osCanonTable = NULL;
136
137 static struct archosCache archCache;
138 static struct archosCache osCache;
139 static struct archosEquivTable archEquivTable;
140 static struct archosEquivTable osEquivTable;
141
142 static int optionCompare(const void * a, const void * b) {
143     return strcasecmp(((struct rpmoption *) a)->name,
144                       ((struct rpmoption *) b)->name);
145 }
146
147 static struct archosEquivInfo * archosEquivSearch(
148                 struct archosEquivTable * table, char * name) {
149     int i;
150
151     for (i = 0; i < table->count; i++)
152         if (!strcmp(table->list[i].name, name)) 
153             return table->list + i;
154
155     return NULL;
156 }
157
158 static int findArchOsScore(struct archosEquivTable * table, char * name) {
159     struct archosEquivInfo * info;
160
161     info = archosEquivSearch(table, name);
162     if (info) 
163         return info->score;
164     else
165         return 0;
166 }
167
168 int rpmArchScore(char * test) {
169     return findArchOsScore(&archEquivTable, test);
170 }
171
172 int rpmOsScore(char * test) {
173     return findArchOsScore(&osEquivTable, test);
174 }
175
176 static struct archosCacheEntry * 
177   archosCacheFindEntry(struct archosCache * cache, char * key) {
178     int i;
179
180     for (i = 0; i < cache->size; i++)
181         if (!strcmp(cache->cache[i].name, key)) return cache->cache + i;
182
183     return NULL;
184 }
185
186 static void archosFindEquivs(struct archosCache * cache, 
187                              struct archosEquivTable * table,
188                              char * key) {
189     int i;
190
191     for (i = 0; i < cache->size; i++)
192         cache->cache[i].visited = 0;
193
194     table->count = 0;
195
196     /* We have a general graph built using strings instead of pointers.
197        Yuck. We have to start at a point at traverse it, remembering how
198        far away everything is. */
199     archosAddEquiv(table, key, 1);
200     archosCacheEntryVisit(cache, table, key, 2);
201 }
202
203 static void archosAddEquiv(struct archosEquivTable * table, char * name,
204                            int distance) {
205     struct archosEquivInfo * equiv;
206
207     equiv = archosEquivSearch(table, name);
208     if (!equiv) {
209         if (table->count)
210             table->list = realloc(table->list, (table->count + 1)
211                                     * sizeof(*table->list));
212         else
213             table->list = malloc(sizeof(*table->list));
214     
215         table->list[table->count].name = strdup(name);
216         table->list[table->count++].score = distance;
217     }
218 }
219
220 static void archosCacheEntryVisit(struct archosCache * cache, 
221                                   struct archosEquivTable * table, 
222                                   char * name,
223                                   int distance) {
224     struct archosCacheEntry * entry;
225     int i;
226
227     entry = archosCacheFindEntry(cache, name);
228     if (!entry || entry->visited) return;
229
230     entry->visited = 1;
231
232     for (i = 0; i < entry->count; i++) {
233         archosAddEquiv(table, entry->equivs[i], distance);
234     }
235
236     for (i = 0; i < entry->count; i++) {
237         archosCacheEntryVisit(cache, table, entry->equivs[i], distance + 1);
238     }
239 };
240
241 static int archosCompatCacheAdd(char * name, char * fn, int linenum,
242                                 struct archosCache * cache) {
243     char * chptr, * equivs;
244     int delEntry = 0;
245     int i;
246     struct archosCacheEntry * entry = NULL;
247   
248     chptr = name;
249     while (*chptr && *chptr != ':') chptr++;
250     if (!*chptr) {
251         rpmError(RPMERR_RPMRC, "missing second ':' at %s:%d", fn, linenum);
252         return 1;
253     } else if (chptr == name) {
254         rpmError(RPMERR_RPMRC, "missing architecture name at %s:%d", fn, 
255                              linenum);
256         return 1;
257     }
258
259     while (*chptr == ':' || isspace(*chptr)) chptr--;
260     *(++chptr) = '\0';
261     equivs = chptr + 1;
262     while (*equivs && isspace(*equivs)) equivs++;
263     if (!*equivs) {
264         delEntry = 1;
265     }
266
267     if (cache->size) {
268         entry = archosCacheFindEntry(cache, name);
269         if (entry) {
270             for (i = 0; i < entry->count; i++)
271                 free(entry->equivs[i]);
272             if (entry->count) free(entry->equivs);
273             entry->count = 0;
274         }
275     }
276
277     if (!entry) {
278         cache->cache = realloc(cache->cache, 
279                                (cache->size + 1) * sizeof(*cache->cache));
280         entry = cache->cache + cache->size++;
281         entry->name = strdup(name);
282         entry->count = 0;
283         entry->visited = 0;
284     }
285
286     if (delEntry) return 0;
287         
288     chptr = strtok(equivs, " ");
289     while (chptr) {
290         if (strlen(chptr)) {            /* does strtok() return "" ever?? */
291             if (entry->count)
292                 entry->equivs = realloc(entry->equivs, sizeof(*entry->equivs) 
293                                         * (entry->count + 1));
294             else
295                 entry->equivs = malloc(sizeof(*entry->equivs));
296
297             entry->equivs[entry->count] = strdup(chptr);
298             entry->count++;
299         }
300
301         chptr = strtok(NULL, " ");
302     }
303
304     return 0;
305 }
306
307 static int addCanon(struct canonEntry **table, int *tableLen, char *line,
308                    char *fn, int lineNum)
309 {
310     struct canonEntry *t;
311     char *s, *s1;
312     
313     if (! *tableLen) {
314         *tableLen = 2;
315         *table = malloc(2 * sizeof(struct canonEntry));
316     } else {
317         (*tableLen) += 2;
318         *table = realloc(*table, sizeof(struct canonEntry) * (*tableLen));
319     }
320     t = & ((*table)[*tableLen - 2]);
321
322     t->name = strtok(line, ": \t");
323     t->short_name = strtok(NULL, " \t");
324     s = strtok(NULL, " \t");
325     if (! (t->name && t->short_name && s)) {
326         rpmError(RPMERR_RPMRC, "Incomplete data line at %s:%d", fn, lineNum);
327         return RPMERR_RPMRC;
328     }
329     if (strtok(NULL, " \t")) {
330         rpmError(RPMERR_RPMRC, "Too many args in data line at %s:%d",
331               fn, lineNum);
332         return RPMERR_RPMRC;
333     }
334
335     t->num = strtoul(s, &s1, 10);
336     if ((*s1) || (s1 == s) || (t->num == ULONG_MAX)) {
337         rpmError(RPMERR_RPMRC, "Bad arch/os number: %s (%s:%d)", s,
338               fn, lineNum);
339         return(RPMERR_RPMRC);
340     }
341
342     t->name = strdup(t->name);
343     t->short_name = strdup(t->short_name);
344
345     /* From A B C entry */
346     /* Add  B B C entry */
347     t[1].name = strdup(t->short_name);
348     t[1].short_name = strdup(t->short_name);
349     t[1].num = t->num;
350
351     return 0;
352 }
353
354 static int addDefault(struct defaultEntry **table, int *tableLen, char *line,
355                       char *fn, int lineNum)
356 {
357     struct defaultEntry *t;
358     
359     if (! *tableLen) {
360         *tableLen = 1;
361         *table = malloc(sizeof(struct defaultEntry));
362     } else {
363         (*tableLen)++;
364         *table = realloc(*table, sizeof(struct defaultEntry) * (*tableLen));
365     }
366     t = & ((*table)[*tableLen - 1]);
367
368     t->name = strtok(line, ": \t");
369     t->defName = strtok(NULL, " \t");
370     if (! (t->name && t->defName)) {
371         rpmError(RPMERR_RPMRC, "Incomplete default line at %s:%d", fn, lineNum);
372         return RPMERR_RPMRC;
373     }
374     if (strtok(NULL, " \t")) {
375         rpmError(RPMERR_RPMRC, "Too many args in default line at %s:%d",
376               fn, lineNum);
377         return RPMERR_RPMRC;
378     }
379
380     t->name = strdup(t->name);
381     t->defName = strdup(t->defName);
382
383     return 0;
384 }
385
386 static struct canonEntry *lookupInCanonTable(char *name,
387                                            struct canonEntry *table,
388                                            int tableLen)
389 {
390     while (tableLen) {
391         tableLen--;
392         if (!strcmp(name, table[tableLen].name)) {
393             return &(table[tableLen]);
394         }
395     }
396
397     return NULL;
398 }
399
400 static char *lookupInDefaultTable(char *name,
401                                   struct defaultEntry *table,
402                                   int tableLen)
403 {
404     while (tableLen) {
405         tableLen--;
406         if (!strcmp(name, table[tableLen].name)) {
407             return table[tableLen].defName;
408         }
409     }
410
411     return name;
412 }
413
414 static int readRpmrc(FILE * f, char * fn, int readWhat) {
415     char buf[1024];
416     char * start;
417     char * chptr;
418     char * archName = NULL;
419     int linenum = 0;
420     struct rpmoption * option, searchOption;
421
422     while (fgets(buf, sizeof(buf), f)) {
423         linenum++;
424
425         /* strip off leading spaces */
426         start = buf;
427         while (*start && isspace(*start)) start++;
428
429         /* I guess #.* should be a comment, but I don't know that. I'll
430            just assume that and hope I'm right. For kicks, I'll take
431            \# to escape it */
432
433         chptr = start;
434         while (*chptr) {
435             switch (*chptr) {
436               case '#':
437                 *chptr = '\0';
438                 break;
439
440               case '\n':
441                 *chptr = '\0';
442                 break;
443
444               case '\\':
445                 chptr++;
446                 /* fallthrough */
447               default:
448                 chptr++;
449             }
450         }
451
452         /* strip trailing spaces - chptr is at the end of the line already*/
453         for (chptr--; chptr >= start && isspace(*chptr); chptr--);
454         *(chptr + 1) = '\0';
455
456         if (!start[0]) continue;                        /* blank line */
457         
458         /* look for a :, the id part ends there */
459         for (chptr = start; *chptr && *chptr != ':'; chptr++);
460
461         if (! *chptr) {
462             rpmError(RPMERR_RPMRC, "missing ':' at %s:%d", fn, linenum);
463             return 1;
464         }
465
466         *chptr = '\0';
467         chptr++;         /* now points at beginning of argument */
468         while (*chptr && isspace(*chptr)) chptr++;
469
470         if (! *chptr) {
471             rpmError(RPMERR_RPMRC, "missing argument for %s at %s:%d", 
472                   start, fn, linenum);
473             return 1;
474         }
475
476         rpmMessage(RPMMESS_DEBUG, "got var '%s' arg '%s'\n", start, chptr);
477
478         /* these are options that don't just get stuffed in a VAR somewhere */
479         if (!strcasecmp(start, "arch_compat")) {
480             if (readWhat != READ_TABLES) continue;
481             if (archosCompatCacheAdd(chptr, fn, linenum, &archCache))
482                 return 1;
483         } else if (!strcasecmp(start, "os_compat")) {
484             if (readWhat != READ_TABLES) continue;
485             if (archosCompatCacheAdd(chptr, fn, linenum, &osCache))
486                 return 1;
487         } else if (!strcasecmp(start, "arch_canon")) {
488             if (readWhat != READ_TABLES) continue;
489             if (addCanon(&archCanonTable, &archCanonTableLen,
490                         chptr, fn, linenum))
491                 return 1;
492         } else if (!strcasecmp(start, "os_canon")) {
493             if (readWhat != READ_TABLES) continue;
494             if (addCanon(&osCanonTable, &osCanonTableLen,
495                         chptr, fn, linenum))
496                 return 1;
497         } else if (!strcasecmp(start, "buildarchtranslate")) {
498             if (readWhat != READ_TABLES) continue;
499             if (addDefault(&archDefaultTable, &archDefaultTableLen,
500                            chptr, fn, linenum))
501                 return 1;
502         } else if (!strcasecmp(start, "buildostranslate")) {
503             if (readWhat != READ_TABLES) continue;
504             if (addDefault(&osDefaultTable, &osDefaultTableLen,
505                            chptr, fn, linenum))
506                 return 1;
507         }
508         if (readWhat == READ_TABLES) {
509             continue;
510         }
511
512         /* Parse the argument a little further */
513         searchOption.name = start;
514         option = bsearch(&searchOption, optionTable, optionTableSize,
515                          sizeof(struct rpmoption), optionCompare);
516         if (!option) {
517             rpmError(RPMERR_RPMRC, "bad option '%s' at %s:%d", 
518                         start, fn, linenum);
519             continue;                   /* aborting here is rude */
520         }
521
522         if (readWhat == READ_OTHER) {
523             if (option->archSpecific) {
524                 start = chptr;
525
526                 /* rpmGetArchName() should be safe by now */
527                 if (!archName) archName = rpmGetArchName();
528
529                 for (chptr = start; *chptr && !isspace(*chptr); chptr++);
530                 if (! *chptr) {
531                     rpmError(RPMERR_RPMRC, "missing argument for %s at %s:%d", 
532                           option->name, fn, linenum);
533                     return 1;
534                 }
535                 *chptr++ = '\0';
536                 
537                 while (*chptr && isspace(*chptr)) chptr++;
538                 if (! *chptr) {
539                     rpmError(RPMERR_RPMRC, "missing argument for %s at %s:%d", 
540                           option->name, fn, linenum);
541                     return 1;
542                 }
543                 
544                 if (!strcmp(archName, start)) {
545                     rpmMessage(RPMMESS_DEBUG, "%s is arg for %s platform", chptr,
546                             archName);
547                     rpmSetVar(option->var, chptr);
548                 }
549             } else {
550                 rpmSetVar(option->var, chptr);
551             }
552             continue;
553         }
554         rpmError(RPMERR_INTERNAL, "Bad readWhat: %d", readWhat);
555         exit(1);
556     }
557
558     return 0;
559 }
560
561 static void setDefaults(void) {
562     rpmSetVar(RPMVAR_OPTFLAGS, "-O2");
563     rpmSetVar(RPMVAR_SIGTYPE, "none");
564     rpmSetVar(RPMVAR_DEFAULTDOCDIR, "/usr/doc");
565     rpmSetVar(RPMVAR_TOPDIR, "/usr/src/redhat");
566 }
567
568 static int readConfigFilesAux(char *file, int readWhat)
569 {
570     FILE * f;
571     char * fn;
572     char * home;
573     int rc = 0;
574
575     f = fopen(LIBRPMRC_FILENAME, "r");
576     if (f) {
577         rc = readRpmrc(f, LIBRPMRC_FILENAME, readWhat);
578         fclose(f);
579         if (rc) return rc;
580     } else {
581         rpmError(RPMERR_RPMRC, "Unable to read " LIBRPMRC_FILENAME);
582         return RPMERR_RPMRC;
583     }
584     
585     if (file) 
586         fn = file;
587     else
588         fn = "/etc/rpmrc";
589
590     f = fopen(fn, "r");
591     if (f) {
592         rc = readRpmrc(f, fn, readWhat);
593         fclose(f);
594         if (rc) return rc;
595     } else if (file) {
596         rpmError(RPMERR_RPMRC, "Unable to open %s for reading.", file);
597         return 1;
598     }
599
600     if (!file) {
601         home = getenv("HOME");
602         if (home) {
603             fn = alloca(strlen(home) + 8);
604             strcpy(fn, home);
605             strcat(fn, "/.rpmrc");
606             f = fopen(fn, "r");
607             if (f) {
608                 rc |= readRpmrc(f, fn, readWhat);
609                 fclose(f);
610                 if (rc) return rc;
611             }
612         }
613     }
614
615     return 0;
616 }
617
618 int rpmReadConfigFiles(char * file, char * arch, char * os, int building)
619 {
620     int rc = 0;
621     int tc;
622     char *tcs, *tcse;
623     static int alreadyInit = 0;
624     int i;
625
626     if (alreadyInit)
627       return 1;
628     alreadyInit = 1;
629     
630     setDefaults();
631     
632     rc = readConfigFilesAux(file, READ_TABLES);
633     if (rc) return rc;
634
635     setArchOs(arch, os, building);
636
637     rc = readConfigFilesAux(file, READ_OTHER);
638     if (rc) return rc;
639
640     /* set default directories */
641
642     if (!rpmGetVar(RPMVAR_TMPPATH))
643         rpmSetVar(RPMVAR_TMPPATH, "/tmp");
644
645     setPathDefault(RPMVAR_BUILDDIR, "BUILD");    
646     setPathDefault(RPMVAR_RPMDIR, "RPMS");    
647     setPathDefault(RPMVAR_SRPMDIR, "SRPMS");    
648     setPathDefault(RPMVAR_SOURCEDIR, "SOURCES");    
649     setPathDefault(RPMVAR_SPECDIR, "SPECS");
650
651     /* setup arch equivalences */
652     
653     archosFindEquivs(&archCache, &archEquivTable, rpmGetArchName());
654     archosFindEquivs(&osCache, &osEquivTable, rpmGetOsName());
655
656     /* Do some checking */
657     if ((tcs = rpmGetVar(RPMVAR_TIMECHECK))) {
658         tcse = NULL;
659         tc = strtoul(tcs, &tcse, 10);
660         if ((*tcse) || (tcse == tcs) || (tc == ULONG_MAX)) {
661             rpmError(RPMERR_RPMRC, "Bad arg to timecheck: %s", tcs);
662             return 1;
663         }
664     }
665
666     for (i = 0; i < optionTableSize; i++) {
667         if (optionTable[i].required && !rpmGetVar(optionTable[i].var)) {
668             rpmError(RPMERR_RPMRC, "Missing definition of %s in rc files.",
669                         optionTable[i].name);
670             rc = 1;
671         }
672     }
673     
674     return rc;
675 }
676
677 static void setPathDefault(int var, char * s) {
678     char * topdir;
679     char * fn;
680
681     if (rpmGetVar(var)) return;
682
683     topdir = rpmGetVar(RPMVAR_TOPDIR);
684     if (!topdir) topdir = rpmGetVar(RPMVAR_TMPPATH);
685         
686     fn = alloca(strlen(topdir) + strlen(s) + 2);
687     strcpy(fn, topdir);
688     if (fn[strlen(topdir) - 1] != '/')
689         strcat(fn, "/");
690     strcat(fn, s);
691    
692     rpmSetVar(var, fn);
693 }
694
695 static int osnum;
696 static int archnum;
697 static char *osname;
698 static char *archname;
699 static int archOsIsInit = 0;
700
701 static void setArchOs(char *arch, char *os, int build)
702 {
703     struct utsname un;
704     struct canonEntry *archCanon, *osCanon;
705
706     if (archOsIsInit) {
707         rpmError(RPMERR_INTERNAL, "Internal error: Arch/OS already initialized!");
708         rpmError(RPMERR_INTERNAL, "Arch: %d\nOS: %d", archnum, osnum);
709         exit(1);
710     }
711
712     uname(&un);
713     if (build) {
714         if (! arch) {
715             arch = lookupInDefaultTable(un.machine, archDefaultTable,
716                                         archDefaultTableLen);
717         }
718         if (! os) {
719             os = lookupInDefaultTable(un.sysname, osDefaultTable,
720                                       osDefaultTableLen);
721         }
722     } else {
723         arch = un.machine;
724         os = un.sysname;
725     }
726
727     archCanon = lookupInCanonTable(arch, archCanonTable, archCanonTableLen);
728     osCanon = lookupInCanonTable(os, osCanonTable, osCanonTableLen);
729     if (archCanon) {
730         archnum = archCanon->num;
731         archname = strdup(archCanon->short_name);
732     } else {
733         archnum = 255;
734         archname = strdup(arch);
735         rpmMessage(RPMMESS_WARNING, "Unknown architecture: %s\n", arch);
736         rpmMessage(RPMMESS_WARNING, "Please contact rpm-list@redhat.com\n");
737     }
738     if (osCanon) {
739         osnum = osCanon->num;
740         osname = strdup(osCanon->short_name);
741     } else {
742         osnum = 255;
743         osname = strdup(os);
744         rpmMessage(RPMMESS_WARNING, "Unknown OS: %s\n", os);
745         rpmMessage(RPMMESS_WARNING, "Please contact rpm-list@redhat.com\n");
746     }
747
748     archOsIsInit = 1;
749 }
750
751 #define FAIL_IF_NOT_INIT \
752 {\
753     if (! archOsIsInit) {\
754         rpmError(RPMERR_INTERNAL, "Internal error: Arch/OS not initialized!");\
755         rpmError(RPMERR_INTERNAL, "Arch: %d\nOS: %d", archnum, osnum);\
756         exit(1);\
757     }\
758 }
759
760 int rpmGetOsNum(void)
761 {
762     FAIL_IF_NOT_INIT;
763     return osnum;
764 }
765
766 int rpmGetArchNum(void)
767 {
768     FAIL_IF_NOT_INIT;
769     return archnum;
770 }
771
772 char *rpmGetOsName(void)
773 {
774     FAIL_IF_NOT_INIT;
775     return osname;
776 }
777
778 char *rpmGetArchName(void)
779 {
780     FAIL_IF_NOT_INIT;
781     return archname;
782 }
783
784 int rpmShowRC(FILE *f)
785 {
786     struct rpmoption *opt;
787     int count = 0;
788     char *s;
789     int i;
790
791     fprintf(f, "ARCHITECTURE AND OS:\n");
792     fprintf(f, "build arch           : %s\n", rpmGetArchName());
793     fprintf(f, "build os             : %s\n", rpmGetOsName());
794
795     /* This is a major hack */
796     archOsIsInit = 0;
797     setArchOs(NULL, NULL, 0);
798     archosFindEquivs(&archCache, &archEquivTable, rpmGetArchName());
799     archosFindEquivs(&osCache, &osEquivTable, rpmGetOsName());
800     fprintf(f, "install arch         : %s\n", rpmGetArchName());
801     fprintf(f, "install os           : %s\n", rpmGetOsName());
802     fprintf(f, "compatible arch list :");
803     for (i = 0; i < archEquivTable.count; i++)
804         fprintf(f," %s", archEquivTable.list[i].name);
805     fprintf(f, "\n");
806     fprintf(f, "compatible os list   :");
807     for (i = 0; i < osEquivTable.count; i++)
808         fprintf(f," %s", osEquivTable.list[i].name);
809     fprintf(f, "\n");
810
811     fprintf(f, "RPMRC VALUES:\n");
812     opt = optionTable;
813     while (count < optionTableSize) {
814         s = rpmGetVar(opt->var);
815         fprintf(f, "%-20s : %s\n", opt->name, s ? s : "(not set)");
816         opt++;
817         count++;
818     }
819     
820     return 0;
821 }