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