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 { "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 },
107 static int optionTableSize = sizeof(optionTable) / sizeof(struct rpmoption);
109 #define READ_TABLES 1
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);
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,
125 static char *lookupInDefaultTable(char *name,
126 struct defaultEntry *table,
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;
138 static struct archosCache archCache;
139 static struct archosCache osCache;
140 static struct archosEquivTable archEquivTable;
141 static struct archosEquivTable osEquivTable;
143 static int optionCompare(const void * a, const void * b) {
144 return strcasecmp(((struct rpmoption *) a)->name,
145 ((struct rpmoption *) b)->name);
148 static struct archosEquivInfo * archosEquivSearch(
149 struct archosEquivTable * table, char * name) {
152 for (i = 0; i < table->count; i++)
153 if (!strcmp(table->list[i].name, name))
154 return table->list + i;
159 static int findArchOsScore(struct archosEquivTable * table, char * name) {
160 struct archosEquivInfo * info;
162 info = archosEquivSearch(table, name);
169 int rpmArchScore(char * test) {
170 return findArchOsScore(&archEquivTable, test);
173 int rpmOsScore(char * test) {
174 return findArchOsScore(&osEquivTable, test);
177 static struct archosCacheEntry *
178 archosCacheFindEntry(struct archosCache * cache, char * key) {
181 for (i = 0; i < cache->size; i++)
182 if (!strcmp(cache->cache[i].name, key)) return cache->cache + i;
187 static void archosFindEquivs(struct archosCache * cache,
188 struct archosEquivTable * table,
192 for (i = 0; i < cache->size; i++)
193 cache->cache[i].visited = 0;
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);
204 static void archosAddEquiv(struct archosEquivTable * table, char * name,
206 struct archosEquivInfo * equiv;
208 equiv = archosEquivSearch(table, name);
211 table->list = realloc(table->list, (table->count + 1)
212 * sizeof(*table->list));
214 table->list = malloc(sizeof(*table->list));
216 table->list[table->count].name = strdup(name);
217 table->list[table->count++].score = distance;
221 static void archosCacheEntryVisit(struct archosCache * cache,
222 struct archosEquivTable * table,
225 struct archosCacheEntry * entry;
228 entry = archosCacheFindEntry(cache, name);
229 if (!entry || entry->visited) return;
233 for (i = 0; i < entry->count; i++) {
234 archosAddEquiv(table, entry->equivs[i], distance);
237 for (i = 0; i < entry->count; i++) {
238 archosCacheEntryVisit(cache, table, entry->equivs[i], distance + 1);
242 static int archosCompatCacheAdd(char * name, char * fn, int linenum,
243 struct archosCache * cache) {
244 char * chptr, * equivs;
247 struct archosCacheEntry * entry = NULL;
250 while (*chptr && *chptr != ':') chptr++;
252 rpmError(RPMERR_RPMRC, "missing second ':' at %s:%d", fn, linenum);
254 } else if (chptr == name) {
255 rpmError(RPMERR_RPMRC, "missing architecture name at %s:%d", fn,
260 while (*chptr == ':' || isspace(*chptr)) chptr--;
263 while (*equivs && isspace(*equivs)) equivs++;
269 entry = archosCacheFindEntry(cache, name);
271 for (i = 0; i < entry->count; i++)
272 free(entry->equivs[i]);
273 if (entry->count) free(entry->equivs);
279 cache->cache = realloc(cache->cache,
280 (cache->size + 1) * sizeof(*cache->cache));
281 entry = cache->cache + cache->size++;
282 entry->name = strdup(name);
287 if (delEntry) return 0;
289 chptr = strtok(equivs, " ");
291 if (strlen(chptr)) { /* does strtok() return "" ever?? */
293 entry->equivs = realloc(entry->equivs, sizeof(*entry->equivs)
294 * (entry->count + 1));
296 entry->equivs = malloc(sizeof(*entry->equivs));
298 entry->equivs[entry->count] = strdup(chptr);
302 chptr = strtok(NULL, " ");
308 static int addCanon(struct canonEntry **table, int *tableLen, char *line,
309 char *fn, int lineNum)
311 struct canonEntry *t;
316 *table = malloc(2 * sizeof(struct canonEntry));
319 *table = realloc(*table, sizeof(struct canonEntry) * (*tableLen));
321 t = & ((*table)[*tableLen - 2]);
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);
330 if (strtok(NULL, " \t")) {
331 rpmError(RPMERR_RPMRC, "Too many args in data line at %s:%d",
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,
340 return(RPMERR_RPMRC);
343 t->name = strdup(t->name);
344 t->short_name = strdup(t->short_name);
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);
355 static int addDefault(struct defaultEntry **table, int *tableLen, char *line,
356 char *fn, int lineNum)
358 struct defaultEntry *t;
362 *table = malloc(sizeof(struct defaultEntry));
365 *table = realloc(*table, sizeof(struct defaultEntry) * (*tableLen));
367 t = & ((*table)[*tableLen - 1]);
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);
375 if (strtok(NULL, " \t")) {
376 rpmError(RPMERR_RPMRC, "Too many args in default line at %s:%d",
381 t->name = strdup(t->name);
382 t->defName = strdup(t->defName);
387 static struct canonEntry *lookupInCanonTable(char *name,
388 struct canonEntry *table,
393 if (!strcmp(name, table[tableLen].name)) {
394 return &(table[tableLen]);
401 static char *lookupInDefaultTable(char *name,
402 struct defaultEntry *table,
407 if (!strcmp(name, table[tableLen].name)) {
408 return table[tableLen].defName;
415 static int readRpmrc(FILE * f, char * fn, int readWhat) {
419 char * archName = NULL;
421 struct rpmoption * option, searchOption;
423 while (fgets(buf, sizeof(buf), f)) {
426 /* strip off leading spaces */
428 while (*start && isspace(*start)) start++;
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
453 /* strip trailing spaces - chptr is at the end of the line already*/
454 for (chptr--; chptr >= start && isspace(*chptr); chptr--);
457 if (!start[0]) continue; /* blank line */
459 /* look for a :, the id part ends there */
460 for (chptr = start; *chptr && *chptr != ':'; chptr++);
463 rpmError(RPMERR_RPMRC, "missing ':' at %s:%d", fn, linenum);
468 chptr++; /* now points at beginning of argument */
469 while (*chptr && isspace(*chptr)) chptr++;
472 rpmError(RPMERR_RPMRC, "missing argument for %s at %s:%d",
477 rpmMessage(RPMMESS_DEBUG, "got var '%s' arg '%s'\n", start, chptr);
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))
484 } else if (!strcasecmp(start, "os_compat")) {
485 if (readWhat != READ_TABLES) continue;
486 if (archosCompatCacheAdd(chptr, fn, linenum, &osCache))
488 } else if (!strcasecmp(start, "arch_canon")) {
489 if (readWhat != READ_TABLES) continue;
490 if (addCanon(&archCanonTable, &archCanonTableLen,
493 } else if (!strcasecmp(start, "os_canon")) {
494 if (readWhat != READ_TABLES) continue;
495 if (addCanon(&osCanonTable, &osCanonTableLen,
498 } else if (!strcasecmp(start, "buildarchtranslate")) {
499 if (readWhat != READ_TABLES) continue;
500 if (addDefault(&archDefaultTable, &archDefaultTableLen,
503 } else if (!strcasecmp(start, "buildostranslate")) {
504 if (readWhat != READ_TABLES) continue;
505 if (addDefault(&osDefaultTable, &osDefaultTableLen,
509 if (readWhat == READ_TABLES) {
513 /* Parse the argument a little further */
514 searchOption.name = start;
515 option = bsearch(&searchOption, optionTable, optionTableSize,
516 sizeof(struct rpmoption), optionCompare);
518 rpmError(RPMERR_RPMRC, "bad option '%s' at %s:%d",
520 continue; /* aborting here is rude */
523 if (readWhat == READ_OTHER) {
524 if (option->archSpecific) {
527 /* rpmGetArchName() should be safe by now */
528 if (!archName) archName = rpmGetArchName();
530 for (chptr = start; *chptr && !isspace(*chptr); chptr++);
532 rpmError(RPMERR_RPMRC, "missing argument for %s at %s:%d",
533 option->name, fn, linenum);
538 while (*chptr && isspace(*chptr)) chptr++;
540 rpmError(RPMERR_RPMRC, "missing argument for %s at %s:%d",
541 option->name, fn, linenum);
545 if (!strcmp(archName, start)) {
546 rpmMessage(RPMMESS_DEBUG, "%s is arg for %s platform", chptr,
548 rpmSetVar(option->var, chptr);
551 rpmSetVar(option->var, chptr);
555 rpmError(RPMERR_INTERNAL, "Bad readWhat: %d", readWhat);
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");
569 static int readConfigFilesAux(char *file, int readWhat)
576 f = fopen(LIBRPMRC_FILENAME, "r");
578 rc = readRpmrc(f, LIBRPMRC_FILENAME, readWhat);
582 rpmError(RPMERR_RPMRC, "Unable to read " LIBRPMRC_FILENAME);
593 rc = readRpmrc(f, fn, readWhat);
597 rpmError(RPMERR_RPMRC, "Unable to open %s for reading.", file);
602 home = getenv("HOME");
604 fn = alloca(strlen(home) + 8);
606 strcat(fn, "/.rpmrc");
609 rc |= readRpmrc(f, fn, readWhat);
619 int rpmReadConfigFiles(char * file, char * arch, char * os, int building)
624 static int alreadyInit = 0;
633 rc = readConfigFilesAux(file, READ_TABLES);
636 setArchOs(arch, os, building);
638 rc = readConfigFilesAux(file, READ_OTHER);
641 /* set default directories */
643 if (!rpmGetVar(RPMVAR_TMPPATH))
644 rpmSetVar(RPMVAR_TMPPATH, "/tmp");
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");
652 /* setup arch equivalences */
654 archosFindEquivs(&archCache, &archEquivTable, rpmGetArchName());
655 archosFindEquivs(&osCache, &osEquivTable, rpmGetOsName());
657 /* Do some checking */
658 if ((tcs = rpmGetVar(RPMVAR_TIMECHECK))) {
660 tc = strtoul(tcs, &tcse, 10);
661 if ((*tcse) || (tcse == tcs) || (tc == ULONG_MAX)) {
662 rpmError(RPMERR_RPMRC, "Bad arg to timecheck: %s", tcs);
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);
678 static void setPathDefault(int var, char * s) {
682 if (rpmGetVar(var)) return;
684 topdir = rpmGetVar(RPMVAR_TOPDIR);
685 if (!topdir) topdir = rpmGetVar(RPMVAR_TMPPATH);
687 fn = alloca(strlen(topdir) + strlen(s) + 2);
689 if (fn[strlen(topdir) - 1] != '/')
699 static char *archname;
700 static int archOsIsInit = 0;
702 static void setArchOs(char *arch, char *os, int build)
705 struct canonEntry *archCanon, *osCanon;
708 rpmError(RPMERR_INTERNAL, "Internal error: Arch/OS already initialized!");
709 rpmError(RPMERR_INTERNAL, "Arch: %d\nOS: %d", archnum, osnum);
716 arch = lookupInDefaultTable(un.machine, archDefaultTable,
717 archDefaultTableLen);
720 os = lookupInDefaultTable(un.sysname, osDefaultTable,
728 archCanon = lookupInCanonTable(arch, archCanonTable, archCanonTableLen);
729 osCanon = lookupInCanonTable(os, osCanonTable, osCanonTableLen);
731 archnum = archCanon->num;
732 archname = strdup(archCanon->short_name);
735 archname = strdup(arch);
736 rpmMessage(RPMMESS_WARNING, "Unknown architecture: %s\n", arch);
737 rpmMessage(RPMMESS_WARNING, "Please contact rpm-list@redhat.com\n");
740 osnum = osCanon->num;
741 osname = strdup(osCanon->short_name);
745 rpmMessage(RPMMESS_WARNING, "Unknown OS: %s\n", os);
746 rpmMessage(RPMMESS_WARNING, "Please contact rpm-list@redhat.com\n");
752 #define FAIL_IF_NOT_INIT \
754 if (! archOsIsInit) {\
755 rpmError(RPMERR_INTERNAL, "Internal error: Arch/OS not initialized!");\
756 rpmError(RPMERR_INTERNAL, "Arch: %d\nOS: %d", archnum, osnum);\
761 int rpmGetOsNum(void)
767 int rpmGetArchNum(void)
773 char *rpmGetOsName(void)
779 char *rpmGetArchName(void)
785 int rpmShowRC(FILE *f)
787 struct rpmoption *opt;
792 fprintf(f, "ARCHITECTURE AND OS:\n");
793 fprintf(f, "build arch : %s\n", rpmGetArchName());
794 fprintf(f, "build os : %s\n", rpmGetOsName());
796 /* This is a major hack */
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);
807 fprintf(f, "compatible os list :");
808 for (i = 0; i < osEquivTable.count; i++)
809 fprintf(f," %s", osEquivTable.list[i].name);
812 fprintf(f, "RPMRC VALUES:\n");
814 while (count < optionTableSize) {
815 s = rpmGetVar(opt->var);
816 fprintf(f, "%-20s : %s\n", opt->name, s ? s : "(not set)");