7 #include <sys/utsname.h>
13 /* the rpmrc is read from /etc/rpmrc or $HOME/.rpmrc - it is not affected
19 int archSpecific, required;
22 struct archosCacheEntry {
30 struct archosCacheEntry * cache;
34 struct archosEquivInfo {
39 struct archosEquivTable {
41 struct archosEquivInfo * list;
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,
61 static void archosAddEquiv(struct archosEquivTable * table, char * name,
63 static void archosCacheEntryVisit(struct archosCache * cache,
64 struct archosEquivTable * table,
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);
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 },
106 static int optionTableSize = sizeof(optionTable) / sizeof(struct rpmoption);
108 #define READ_TABLES 1
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);
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,
124 static char *lookupInDefaultTable(char *name,
125 struct defaultEntry *table,
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;
137 static struct archosCache archCache;
138 static struct archosCache osCache;
139 static struct archosEquivTable archEquivTable;
140 static struct archosEquivTable osEquivTable;
142 static int optionCompare(const void * a, const void * b) {
143 return strcasecmp(((struct rpmoption *) a)->name,
144 ((struct rpmoption *) b)->name);
147 static struct archosEquivInfo * archosEquivSearch(
148 struct archosEquivTable * table, char * name) {
151 for (i = 0; i < table->count; i++)
152 if (!strcmp(table->list[i].name, name))
153 return table->list + i;
158 static int findArchOsScore(struct archosEquivTable * table, char * name) {
159 struct archosEquivInfo * info;
161 info = archosEquivSearch(table, name);
168 int rpmArchScore(char * test) {
169 return findArchOsScore(&archEquivTable, test);
172 int rpmOsScore(char * test) {
173 return findArchOsScore(&osEquivTable, test);
176 static struct archosCacheEntry *
177 archosCacheFindEntry(struct archosCache * cache, char * key) {
180 for (i = 0; i < cache->size; i++)
181 if (!strcmp(cache->cache[i].name, key)) return cache->cache + i;
186 static void archosFindEquivs(struct archosCache * cache,
187 struct archosEquivTable * table,
191 for (i = 0; i < cache->size; i++)
192 cache->cache[i].visited = 0;
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);
203 static void archosAddEquiv(struct archosEquivTable * table, char * name,
205 struct archosEquivInfo * equiv;
207 equiv = archosEquivSearch(table, name);
210 table->list = realloc(table->list, (table->count + 1)
211 * sizeof(*table->list));
213 table->list = malloc(sizeof(*table->list));
215 table->list[table->count].name = strdup(name);
216 table->list[table->count++].score = distance;
220 static void archosCacheEntryVisit(struct archosCache * cache,
221 struct archosEquivTable * table,
224 struct archosCacheEntry * entry;
227 entry = archosCacheFindEntry(cache, name);
228 if (!entry || entry->visited) return;
232 for (i = 0; i < entry->count; i++) {
233 archosAddEquiv(table, entry->equivs[i], distance);
236 for (i = 0; i < entry->count; i++) {
237 archosCacheEntryVisit(cache, table, entry->equivs[i], distance + 1);
241 static int archosCompatCacheAdd(char * name, char * fn, int linenum,
242 struct archosCache * cache) {
243 char * chptr, * equivs;
246 struct archosCacheEntry * entry = NULL;
249 while (*chptr && *chptr != ':') chptr++;
251 rpmError(RPMERR_RPMRC, "missing second ':' at %s:%d", fn, linenum);
253 } else if (chptr == name) {
254 rpmError(RPMERR_RPMRC, "missing architecture name at %s:%d", fn,
259 while (*chptr == ':' || isspace(*chptr)) chptr--;
262 while (*equivs && isspace(*equivs)) equivs++;
268 entry = archosCacheFindEntry(cache, name);
270 for (i = 0; i < entry->count; i++)
271 free(entry->equivs[i]);
272 if (entry->count) free(entry->equivs);
278 cache->cache = realloc(cache->cache,
279 (cache->size + 1) * sizeof(*cache->cache));
280 entry = cache->cache + cache->size++;
281 entry->name = strdup(name);
286 if (delEntry) return 0;
288 chptr = strtok(equivs, " ");
290 if (strlen(chptr)) { /* does strtok() return "" ever?? */
292 entry->equivs = realloc(entry->equivs, sizeof(*entry->equivs)
293 * (entry->count + 1));
295 entry->equivs = malloc(sizeof(*entry->equivs));
297 entry->equivs[entry->count] = strdup(chptr);
301 chptr = strtok(NULL, " ");
307 static int addCanon(struct canonEntry **table, int *tableLen, char *line,
308 char *fn, int lineNum)
310 struct canonEntry *t;
315 *table = malloc(2 * sizeof(struct canonEntry));
318 *table = realloc(*table, sizeof(struct canonEntry) * (*tableLen));
320 t = & ((*table)[*tableLen - 2]);
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);
329 if (strtok(NULL, " \t")) {
330 rpmError(RPMERR_RPMRC, "Too many args in data line at %s:%d",
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,
339 return(RPMERR_RPMRC);
342 t->name = strdup(t->name);
343 t->short_name = strdup(t->short_name);
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);
354 static int addDefault(struct defaultEntry **table, int *tableLen, char *line,
355 char *fn, int lineNum)
357 struct defaultEntry *t;
361 *table = malloc(sizeof(struct defaultEntry));
364 *table = realloc(*table, sizeof(struct defaultEntry) * (*tableLen));
366 t = & ((*table)[*tableLen - 1]);
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);
374 if (strtok(NULL, " \t")) {
375 rpmError(RPMERR_RPMRC, "Too many args in default line at %s:%d",
380 t->name = strdup(t->name);
381 t->defName = strdup(t->defName);
386 static struct canonEntry *lookupInCanonTable(char *name,
387 struct canonEntry *table,
392 if (!strcmp(name, table[tableLen].name)) {
393 return &(table[tableLen]);
400 static char *lookupInDefaultTable(char *name,
401 struct defaultEntry *table,
406 if (!strcmp(name, table[tableLen].name)) {
407 return table[tableLen].defName;
414 static int readRpmrc(FILE * f, char * fn, int readWhat) {
418 char * archName = NULL;
420 struct rpmoption * option, searchOption;
422 while (fgets(buf, sizeof(buf), f)) {
425 /* strip off leading spaces */
427 while (*start && isspace(*start)) start++;
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
452 /* strip trailing spaces - chptr is at the end of the line already*/
453 for (chptr--; chptr >= start && isspace(*chptr); chptr--);
456 if (!start[0]) continue; /* blank line */
458 /* look for a :, the id part ends there */
459 for (chptr = start; *chptr && *chptr != ':'; chptr++);
462 rpmError(RPMERR_RPMRC, "missing ':' at %s:%d", fn, linenum);
467 chptr++; /* now points at beginning of argument */
468 while (*chptr && isspace(*chptr)) chptr++;
471 rpmError(RPMERR_RPMRC, "missing argument for %s at %s:%d",
476 rpmMessage(RPMMESS_DEBUG, "got var '%s' arg '%s'\n", start, chptr);
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))
483 } else if (!strcasecmp(start, "os_compat")) {
484 if (readWhat != READ_TABLES) continue;
485 if (archosCompatCacheAdd(chptr, fn, linenum, &osCache))
487 } else if (!strcasecmp(start, "arch_canon")) {
488 if (readWhat != READ_TABLES) continue;
489 if (addCanon(&archCanonTable, &archCanonTableLen,
492 } else if (!strcasecmp(start, "os_canon")) {
493 if (readWhat != READ_TABLES) continue;
494 if (addCanon(&osCanonTable, &osCanonTableLen,
497 } else if (!strcasecmp(start, "buildarchtranslate")) {
498 if (readWhat != READ_TABLES) continue;
499 if (addDefault(&archDefaultTable, &archDefaultTableLen,
502 } else if (!strcasecmp(start, "buildostranslate")) {
503 if (readWhat != READ_TABLES) continue;
504 if (addDefault(&osDefaultTable, &osDefaultTableLen,
508 if (readWhat == READ_TABLES) {
512 /* Parse the argument a little further */
513 searchOption.name = start;
514 option = bsearch(&searchOption, optionTable, optionTableSize,
515 sizeof(struct rpmoption), optionCompare);
517 rpmError(RPMERR_RPMRC, "bad option '%s' at %s:%d",
519 continue; /* aborting here is rude */
522 if (readWhat == READ_OTHER) {
523 if (option->archSpecific) {
526 /* rpmGetArchName() should be safe by now */
527 if (!archName) archName = rpmGetArchName();
529 for (chptr = start; *chptr && !isspace(*chptr); chptr++);
531 rpmError(RPMERR_RPMRC, "missing argument for %s at %s:%d",
532 option->name, fn, linenum);
537 while (*chptr && isspace(*chptr)) chptr++;
539 rpmError(RPMERR_RPMRC, "missing argument for %s at %s:%d",
540 option->name, fn, linenum);
544 if (!strcmp(archName, start)) {
545 rpmMessage(RPMMESS_DEBUG, "%s is arg for %s platform", chptr,
547 rpmSetVar(option->var, chptr);
550 rpmSetVar(option->var, chptr);
554 rpmError(RPMERR_INTERNAL, "Bad readWhat: %d", readWhat);
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");
568 static int readConfigFilesAux(char *file, int readWhat)
575 f = fopen(LIBRPMRC_FILENAME, "r");
577 rc = readRpmrc(f, LIBRPMRC_FILENAME, readWhat);
581 rpmError(RPMERR_RPMRC, "Unable to read " LIBRPMRC_FILENAME);
592 rc = readRpmrc(f, fn, readWhat);
596 rpmError(RPMERR_RPMRC, "Unable to open %s for reading.", file);
601 home = getenv("HOME");
603 fn = alloca(strlen(home) + 8);
605 strcat(fn, "/.rpmrc");
608 rc |= readRpmrc(f, fn, readWhat);
618 int rpmReadConfigFiles(char * file, char * arch, char * os, int building)
623 static int alreadyInit = 0;
632 rc = readConfigFilesAux(file, READ_TABLES);
635 setArchOs(arch, os, building);
637 rc = readConfigFilesAux(file, READ_OTHER);
640 /* set default directories */
642 if (!rpmGetVar(RPMVAR_TMPPATH))
643 rpmSetVar(RPMVAR_TMPPATH, "/tmp");
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");
651 /* setup arch equivalences */
653 archosFindEquivs(&archCache, &archEquivTable, rpmGetArchName());
654 archosFindEquivs(&osCache, &osEquivTable, rpmGetOsName());
656 /* Do some checking */
657 if ((tcs = rpmGetVar(RPMVAR_TIMECHECK))) {
659 tc = strtoul(tcs, &tcse, 10);
660 if ((*tcse) || (tcse == tcs) || (tc == ULONG_MAX)) {
661 rpmError(RPMERR_RPMRC, "Bad arg to timecheck: %s", tcs);
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);
677 static void setPathDefault(int var, char * s) {
681 if (rpmGetVar(var)) return;
683 topdir = rpmGetVar(RPMVAR_TOPDIR);
684 if (!topdir) topdir = rpmGetVar(RPMVAR_TMPPATH);
686 fn = alloca(strlen(topdir) + strlen(s) + 2);
688 if (fn[strlen(topdir) - 1] != '/')
698 static char *archname;
699 static int archOsIsInit = 0;
701 static void setArchOs(char *arch, char *os, int build)
704 struct canonEntry *archCanon, *osCanon;
707 rpmError(RPMERR_INTERNAL, "Internal error: Arch/OS already initialized!");
708 rpmError(RPMERR_INTERNAL, "Arch: %d\nOS: %d", archnum, osnum);
715 arch = lookupInDefaultTable(un.machine, archDefaultTable,
716 archDefaultTableLen);
719 os = lookupInDefaultTable(un.sysname, osDefaultTable,
727 archCanon = lookupInCanonTable(arch, archCanonTable, archCanonTableLen);
728 osCanon = lookupInCanonTable(os, osCanonTable, osCanonTableLen);
730 archnum = archCanon->num;
731 archname = strdup(archCanon->short_name);
734 archname = strdup(arch);
735 rpmMessage(RPMMESS_WARNING, "Unknown architecture: %s\n", arch);
736 rpmMessage(RPMMESS_WARNING, "Please contact rpm-list@redhat.com\n");
739 osnum = osCanon->num;
740 osname = strdup(osCanon->short_name);
744 rpmMessage(RPMMESS_WARNING, "Unknown OS: %s\n", os);
745 rpmMessage(RPMMESS_WARNING, "Please contact rpm-list@redhat.com\n");
751 #define FAIL_IF_NOT_INIT \
753 if (! archOsIsInit) {\
754 rpmError(RPMERR_INTERNAL, "Internal error: Arch/OS not initialized!");\
755 rpmError(RPMERR_INTERNAL, "Arch: %d\nOS: %d", archnum, osnum);\
760 int rpmGetOsNum(void)
766 int rpmGetArchNum(void)
772 char *rpmGetOsName(void)
778 char *rpmGetArchName(void)
784 int rpmShowRC(FILE *f)
786 struct rpmoption *opt;
791 fprintf(f, "ARCHITECTURE AND OS:\n");
792 fprintf(f, "build arch : %s\n", rpmGetArchName());
793 fprintf(f, "build os : %s\n", rpmGetOsName());
795 /* This is a major hack */
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);
806 fprintf(f, "compatible os list :");
807 for (i = 0; i < osEquivTable.count; i++)
808 fprintf(f," %s", osEquivTable.list[i].name);
811 fprintf(f, "RPMRC VALUES:\n");
813 while (count < optionTableSize) {
814 s = rpmGetVar(opt->var);
815 fprintf(f, "%-20s : %s\n", opt->name, s ? s : "(not set)");