Main Page Modules Data Structures File List Data Fields Globals Related Pages

# lib/rpmrc.c

Go to the documentation of this file.

    00001 /*@-bounds@*/
    00002 /*@-mods@*/
    00003 #include "system.h"
    00004
    00005 #include <stdarg.h>
    00006 #if defined(__linux__) && defined(__powerpc__)
    00007 #include <setjmp.h>
    00008 #endif
    00009
    00010 #include <ctype.h>      /* XXX for /etc/rpm/platform contents */
    00011
    00012 #if HAVE_SYS_SYSTEMCFG_H
    00013 #include <sys/systemcfg.h>
    00014 #else
    00015 #define __power_pc() 0
    00016 #endif
    00017
    00018 #include <rpmlib.h>
    00019 #include <rpmmacro.h>
    00020
    00021 #include "misc.h"
    00022 #include "debug.h"
    00023
    00024 /*@access FD_t@*/               /* compared with NULL */
    00025
    00026 /*@observer@*/ /*@unchecked@*/
    00027 static const char *defrcfiles = LIBRPMRC_FILENAME ":" VENDORRPMRC_FILENAME ":/etc/rpmrc:~/.rpmrc";
    00028
    00029 /*@observer@*/ /*@checked@*/
    00030 const char * macrofiles = MACROFILES;
    00031
    00032 /*@observer@*/ /*@unchecked@*/
    00033 static const char * platform = "/etc/rpm/platform";
    00034 /*@only@*/ /*@relnul@*/ /*@unchecked@*/
    00035 static const char ** platpat = NULL;
    00036 /*@unchecked@*/
    00037 static int nplatpat = 0;
    00038
    00039 typedef /*@owned@*/ const char * cptr_t;
    00040
    00041 typedef struct machCacheEntry_s {
    00042     const char * name;
    00043     int count;
    00044     cptr_t * equivs;
    00045     int visited;
    00046 } * machCacheEntry;
    00047
    00048 typedef struct machCache_s {
    00049     machCacheEntry cache;
    00050     int size;
    00051 } * machCache;
    00052
    00053 typedef struct machEquivInfo_s {
    00054     const char * name;
    00055     int score;
    00056 } * machEquivInfo;
    00057
    00058 typedef struct machEquivTable_s {
    00059     int count;
    00060     machEquivInfo list;
    00061 } * machEquivTable;
    00062
    00063 struct rpmvarValue {
    00064     const char * value;
    00065     /* eventually, this arch will be replaced with a generic condition */
    00066     const char * arch;
    00067 /*@only@*/ /*@null@*/ struct rpmvarValue * next;
    00068 };
    00069
    00070 struct rpmOption {
    00071     const char * name;
    00072     int var;
    00073     int archSpecific;
    00074 /*@unused@*/ int required;
    00075     int macroize;
    00076     int localize;
    00077 /*@unused@*/ struct rpmOptionValue * value;
    00078 };
    00079
    00080 typedef struct defaultEntry_s {
    00081 /*@owned@*/ /*@null@*/ const char * name;
    00082 /*@owned@*/ /*@null@*/ const char * defName;
    00083 } * defaultEntry;
    00084
    00085 typedef struct canonEntry_s {
    00086 /*@owned@*/ const char * name;
    00087 /*@owned@*/ const char * short_name;
    00088     short num;
    00089 } * canonEntry;
    00090
    00091 /* tags are 'key'canon, 'key'translate, 'key'compat
    00092  *
    00093  * for giggles, 'key'_canon, 'key'_compat, and 'key'_canon will also work
    00094  */
    00095 typedef struct tableType_s {
    00096 /*@observer@*/ const char * const key;
    00097     const int hasCanon;
    00098     const int hasTranslate;
    00099     struct machEquivTable_s equiv;
    00100     struct machCache_s cache;
    00101     defaultEntry defaults;
    00102     canonEntry canons;
    00103     int defaultsLength;
    00104     int canonsLength;
    00105 } * tableType;
    00106
    00107 /*@-fullinitblock@*/
    00108 /*@unchecked@*/
    00109 static struct tableType_s tables[RPM_MACHTABLE_COUNT] = {
    00110     { "arch", 1, 0 },
    00111     { "os", 1, 0 },
    00112     { "buildarch", 0, 1 },
    00113     { "buildos", 0, 1 }
    00114 };
    00115
    00116 /* this *must* be kept in alphabetical order */
    00117 /* The order of the flags is archSpecific, required, macroize, localize */
    00118
    00119 /*@unchecked@*/
    00120 static struct rpmOption optionTable[] = {
    00121     { "include",                RPMVAR_INCLUDE,                 0, 1,   0, 2 },
    00122     { "macrofiles",             RPMVAR_MACROFILES,              0, 0,   0, 1 },
    00123     { "optflags",               RPMVAR_OPTFLAGS,                1, 0,   1, 0 },
    00124     { "provides",               RPMVAR_PROVIDES,                0, 0,   0, 0 },
    00125 };
    00126 /*@=fullinitblock@*/
    00127
    00128 /*@unchecked@*/
    00129 static int optionTableSize = sizeof(optionTable) / sizeof(*optionTable);
    00130
    00131 #define OS      0
    00132 #define ARCH    1
    00133
    00134 /*@unchecked@*/
    00135 static cptr_t current[2];
    00136
    00137 /*@unchecked@*/
    00138 static int currTables[2] = { RPM_MACHTABLE_INSTOS, RPM_MACHTABLE_INSTARCH };
    00139
    00140 /*@unchecked@*/
    00141 static struct rpmvarValue values[RPMVAR_NUM];
    00142
    00143 /*@unchecked@*/
    00144 static int defaultsInitialized = 0;
    00145
    00146 /* prototypes */
    00147 static int doReadRC( /*@killref@*/ FD_t fd, const char * urlfn)
    00148         /*@globals rpmGlobalMacroContext,
    00149                 fileSystem, internalState @*/
    00150         /*@modifies fd, fileSystem, internalState @*/;
    00151
    00152 static void rpmSetVarArch(int var, const char * val,
    00153                 /*@null@*/ const char * arch)
    00154         /*@globals internalState @*/
    00155         /*@modifies internalState @*/;
    00156
    00157 static void rebuildCompatTables(int type, const char * name)
    00158         /*@globals internalState @*/
    00159         /*@modifies internalState @*/;
    00160
    00161 static void rpmRebuildTargetVars(/*@null@*/ const char **target, /*@null@*/ const char ** canontarget)
    00162         /*@globals rpmGlobalMacroContext,
    00163                 fileSystem, internalState @*/
    00164         /*@modifies *canontarget, fileSystem, internalState @*/;
    00165
    00166 static int optionCompare(const void * a, const void * b)
    00167         /*@*/
    00168 {
    00169     return xstrcasecmp(((struct rpmOption *) a)->name,
    00170                       ((struct rpmOption *) b)->name);
    00171 }
    00172
    00173 static /*@observer@*/ /*@null@*/ machCacheEntry
    00174 machCacheFindEntry(const machCache cache, const char * key)
    00175         /*@*/
    00176 {
    00177     int i;
    00178
    00179     for (i = 0; i < cache->size; i++)
    00180         if (!strcmp(cache->cache[i].name, key)) return cache->cache + i;
    00181
    00182     return NULL;
    00183 }
    00184
    00185 static int machCompatCacheAdd(char * name, const char * fn, int linenum,
    00186                                 machCache cache)
    00187         /*@globals internalState @*/
    00188         /*@modifies *name, cache->cache, cache->size, internalState @*/
    00189 {
    00190     machCacheEntry entry = NULL;
    00191     char * chptr;
    00192     char * equivs;
    00193     int delEntry = 0;
    00194     int i;
    00195
    00196     while (*name && xisspace(*name)) name++;
    00197
    00198     chptr = name;
    00199     while (*chptr && *chptr != ':') chptr++;
    00200     if (!*chptr) {
    00201         rpmError(RPMERR_RPMRC, _("missing second ':' at %s:%d\n"), fn, linenum);
    00202         return 1;
    00203     } else if (chptr == name) {
    00204         rpmError(RPMERR_RPMRC, _("missing architecture name at %s:%d\n"), fn,
    00205                              linenum);
    00206         return 1;
    00207     }
    00208
    00209     while (*chptr == ':' || xisspace(*chptr)) chptr--;
    00210     *(++chptr) = '\0';
    00211     equivs = chptr + 1;
    00212     while (*equivs && xisspace(*equivs)) equivs++;
    00213     if (!*equivs) {
    00214         delEntry = 1;
    00215     }
    00216
    00217     if (cache->size) {
    00218         entry = machCacheFindEntry(cache, name);
    00219         if (entry) {
    00220             for (i = 0; i < entry->count; i++)
    00221                 entry->equivs[i] = _free(entry->equivs[i]);
    00222             entry->equivs = _free(entry->equivs);
    00223             entry->count = 0;
    00224         }
    00225     }
    00226
    00227     if (!entry) {
    00228         cache->cache = xrealloc(cache->cache,
    00229                                (cache->size + 1) * sizeof(*cache->cache));
    00230         entry = cache->cache + cache->size++;
    00231         entry->name = xstrdup(name);
    00232         entry->count = 0;
    00233         entry->visited = 0;
    00234     }
    00235
    00236     if (delEntry) return 0;
    00237
    00238     while ((chptr = strtok(equivs, " ")) != NULL) {
    00239         equivs = NULL;
    00240         if (chptr[0] == '\0')   /* does strtok() return "" ever?? */
    00241             continue;
    00242         if (entry->count)
    00243             entry->equivs = xrealloc(entry->equivs, sizeof(*entry->equivs)
    00244                                         * (entry->count + 1));
    00245         else
    00246             entry->equivs = xmalloc(sizeof(*entry->equivs));
    00247
    00248         entry->equivs[entry->count] = xstrdup(chptr);
    00249         entry->count++;
    00250     }
    00251
    00252     return 0;
    00253 }
    00254
    00255 static /*@observer@*/ /*@null@*/ machEquivInfo
    00256 machEquivSearch(const machEquivTable table, const char * name)
    00257         /*@*/
    00258 {
    00259     int i;
    00260
    00261     for (i = 0; i < table->count; i++)
    00262         if (!xstrcasecmp(table->list[i].name, name))
    00263             return table->list + i;
    00264
    00265     return NULL;
    00266 }
    00267
    00268 static void machAddEquiv(machEquivTable table, const char * name,
    00269                            int distance)
    00270         /*@modifies table->list, table->count @*/
    00271 {
    00272     machEquivInfo equiv;
    00273
    00274     equiv = machEquivSearch(table, name);
    00275     if (!equiv) {
    00276         if (table->count)
    00277             table->list = xrealloc(table->list, (table->count + 1)
    00278                                     * sizeof(*table->list));
    00279         else
    00280             table->list = xmalloc(sizeof(*table->list));
    00281
    00282         table->list[table->count].name = xstrdup(name);
    00283         table->list[table->count++].score = distance;
    00284     }
    00285 }
    00286
    00287 static void machCacheEntryVisit(machCache cache,
    00288                 machEquivTable table, const char * name, int distance)
    00289         /*@modifies table->list, table->count @*/
    00290 {
    00291     machCacheEntry entry;
    00292     int i;
    00293
    00294     entry = machCacheFindEntry(cache, name);
    00295     if (!entry || entry->visited) return;
    00296
    00297     entry->visited = 1;
    00298
    00299     for (i = 0; i < entry->count; i++) {
    00300         machAddEquiv(table, entry->equivs[i], distance);
    00301     }
    00302
    00303     for (i = 0; i < entry->count; i++) {
    00304         machCacheEntryVisit(cache, table, entry->equivs[i], distance + 1);
    00305     }
    00306 }
    00307
    00308 static void machFindEquivs(machCache cache, machEquivTable table,
    00309                 const char * key)
    00310         /*@modifies cache->cache, table->list, table->count @*/
    00311 {
    00312     int i;
    00313
    00314     for (i = 0; i < cache->size; i++)
    00315         cache->cache[i].visited = 0;
    00316
    00317     while (table->count > 0) {
    00318         --table->count;
    00319         table->list[table->count].name = _free(table->list[table->count].name);
    00320     }
    00321     table->count = 0;
    00322     table->list = _free(table->list);
    00323
    00324     /*
    00325      *  We have a general graph built using strings instead of pointers.
    00326      *  Yuck. We have to start at a point at traverse it, remembering how
    00327      *  far away everything is.
    00328      */
    00329     /*@-nullstate@*/    /* FIX: table->list may be NULL. */
    00330     machAddEquiv(table, key, 1);
    00331     machCacheEntryVisit(cache, table, key, 2);
    00332     return;
    00333     /*@=nullstate@*/
    00334 }
    00335
    00336 static int addCanon(canonEntry * table, int * tableLen, char * line,
    00337                     const char * fn, int lineNum)
    00338         /*@globals internalState @*/
    00339         /*@modifies *table, *tableLen, *line, internalState @*/
    00340 {
    00341     canonEntry t;
    00342     char *s, *s1;
    00343     const char * tname;
    00344     const char * tshort_name;
    00345     int tnum;
    00346
    00347     (*tableLen) += 2;
    00348     /*@-unqualifiedtrans@*/
    00349     *table = xrealloc(*table, sizeof(**table) * (*tableLen));
    00350     /*@=unqualifiedtrans@*/
    00351
    00352     t = & ((*table)[*tableLen - 2]);
    00353
    00354     tname = strtok(line, ": \t");
    00355     tshort_name = strtok(NULL, " \t");
    00356     s = strtok(NULL, " \t");
    00357     if (! (tname && tshort_name && s)) {
    00358         rpmError(RPMERR_RPMRC, _("Incomplete data line at %s:%d\n"),
    00359                 fn, lineNum);
    00360         return RPMERR_RPMRC;
    00361     }
    00362     if (strtok(NULL, " \t")) {
    00363         rpmError(RPMERR_RPMRC, _("Too many args in data line at %s:%d\n"),
    00364               fn, lineNum);
    00365         return RPMERR_RPMRC;
    00366     }
    00367
    00368     /*@-nullpass@*/     /* LCL: s != NULL here. */
    00369     tnum = strtoul(s, &s1, 10);
    00370     if ((*s1) || (s1 == s) || (tnum == ULONG_MAX)) {
    00371         rpmError(RPMERR_RPMRC, _("Bad arch/os number: %s (%s:%d)\n"), s,
    00372               fn, lineNum);
    00373         return(RPMERR_RPMRC);
    00374     }
    00375     /*@=nullpass@*/
    00376
    00377     t[0].name = xstrdup(tname);
    00378     t[0].short_name = (tshort_name ? xstrdup(tshort_name) : xstrdup(""));
    00379     t[0].num = tnum;
    00380
    00381     /* From A B C entry */
    00382     /* Add  B B C entry */
    00383     t[1].name = (tshort_name ? xstrdup(tshort_name) : xstrdup(""));
    00384     t[1].short_name = (tshort_name ? xstrdup(tshort_name) : xstrdup(""));
    00385     t[1].num = tnum;
    00386
    00387     return 0;
    00388 }
    00389
    00390 static int addDefault(defaultEntry * table, int * tableLen, char * line,
    00391                         const char * fn, int lineNum)
    00392         /*@globals internalState @*/
    00393         /*@modifies *table, *tableLen, *line, internalState @*/
    00394 {
    00395     defaultEntry t;
    00396
    00397     (*tableLen)++;
    00398     /*@-unqualifiedtrans@*/
    00399     *table = xrealloc(*table, sizeof(**table) * (*tableLen));
    00400     /*@=unqualifiedtrans@*/
    00401
    00402     t = & ((*table)[*tableLen - 1]);
    00403
    00404     /*@-temptrans@*/
    00405     t->name = strtok(line, ": \t");
    00406     t->defName = strtok(NULL, " \t");
    00407     if (! (t->name && t->defName)) {
    00408         rpmError(RPMERR_RPMRC, _("Incomplete default line at %s:%d\n"),
    00409                  fn, lineNum);
    00410         return RPMERR_RPMRC;
    00411     }
    00412     if (strtok(NULL, " \t")) {
    00413         rpmError(RPMERR_RPMRC, _("Too many args in default line at %s:%d\n"),
    00414               fn, lineNum);
    00415         return RPMERR_RPMRC;
    00416     }
    00417
    00418     t->name = xstrdup(t->name);
    00419     t->defName = (t->defName ? xstrdup(t->defName) : NULL);
    00420     /*@=temptrans@*/
    00421
    00422     return 0;
    00423 }
    00424
    00425 static /*@null@*/ canonEntry lookupInCanonTable(const char * name,
    00426                 const canonEntry table, int tableLen)
    00427         /*@*/
    00428 {
    00429     while (tableLen) {
    00430         tableLen--;
    00431         if (strcmp(name, table[tableLen].name))
    00432             continue;
    00433         /*@-immediatetrans -retalias@*/
    00434         return &(table[tableLen]);
    00435         /*@=immediatetrans =retalias@*/
    00436     }
    00437
    00438     return NULL;
    00439 }
    00440
    00441 static /*@observer@*/ /*@null@*/
    00442 const char * lookupInDefaultTable(const char * name,
    00443                 const defaultEntry table, int tableLen)
    00444         /*@*/
    00445 {
    00446     while (tableLen) {
    00447         tableLen--;
    00448         if (table[tableLen].name && !strcmp(name, table[tableLen].name))
    00449             return table[tableLen].defName;
    00450     }
    00451
    00452     return name;
    00453 }
    00454
    00455 static void setVarDefault(int var, const char * macroname, const char * val,
    00456                 /*@null@*/ const char * body)
    00457         /*@globals rpmGlobalMacroContext,
    00458                 internalState @*/
    00459         /*@modifies internalState @*/
    00460 {
    00461     if (var >= 0) {     /* XXX Dying ... */
    00462         if (rpmGetVar(var)) return;
    00463         rpmSetVar(var, val);
    00464     }
    00465     if (body == NULL)
    00466         body = val;
    00467     addMacro(NULL, macroname, NULL, body, RMIL_DEFAULT);
    00468 }
    00469
    00470 static void setPathDefault(int var, const char * macroname, const char * subdir)
    00471         /*@globals rpmGlobalMacroContext,
    00472                 internalState @*/
    00473         /*@modifies internalState @*/
    00474 {
    00475
    00476     if (var >= 0) {     /* XXX Dying ... */
    00477         const char * topdir;
    00478         char * fn;
    00479
    00480         if (rpmGetVar(var)) return;
    00481
    00482         topdir = rpmGetPath("%{_topdir}", NULL);
    00483
    00484         fn = alloca(strlen(topdir) + strlen(subdir) + 2);
    00485         strcpy(fn, topdir);
    00486         if (fn[strlen(topdir) - 1] != '/')
    00487             strcat(fn, "/");
    00488         strcat(fn, subdir);
    00489
    00490         rpmSetVar(var, fn);
    00491         topdir = _free(topdir);
    00492     }
    00493
    00494     if (macroname != NULL) {
    00495 #define _TOPDIRMACRO    "%{_topdir}/"
    00496         char *body = alloca(sizeof(_TOPDIRMACRO) + strlen(subdir));
    00497         strcpy(body, _TOPDIRMACRO);
    00498         strcat(body, subdir);
    00499         addMacro(NULL, macroname, NULL, body, RMIL_DEFAULT);
    00500 #undef _TOPDIRMACRO
    00501     }
    00502 }
    00503
    00504 /*@observer@*/ /*@unchecked@*/
    00505 static const char * prescriptenviron = "\n\
    00506 RPM_SOURCE_DIR=\"%{_sourcedir}\"\n\
    00507 RPM_BUILD_DIR=\"%{_builddir}\"\n\
    00508 RPM_OPT_FLAGS=\"%{optflags}\"\n\
    00509 RPM_ARCH=\"%{_arch}\"\n\
    00510 RPM_OS=\"%{_os}\"\n\
    00511 export RPM_SOURCE_DIR RPM_BUILD_DIR RPM_OPT_FLAGS RPM_ARCH RPM_OS\n\
    00512 RPM_DOC_DIR=\"%{_docdir}\"\n\
    00513 export RPM_DOC_DIR\n\
    00514 RPM_PACKAGE_NAME=\"%{name}\"\n\
    00515 RPM_PACKAGE_VERSION=\"%{version}\"\n\
    00516 RPM_PACKAGE_RELEASE=\"%{release}\"\n\
    00517 export RPM_PACKAGE_NAME RPM_PACKAGE_VERSION RPM_PACKAGE_RELEASE\n\
    00518 %{?buildroot:RPM_BUILD_ROOT=\"%{buildroot}\"\n\
    00519 export RPM_BUILD_ROOT\n}\
    00520 ";
    00521
    00522 static void setDefaults(void)
    00523         /*@globals rpmGlobalMacroContext,
    00524                 internalState @*/
    00525         /*@modifies internalState @*/
    00526 {
    00527
    00528     addMacro(NULL, "_usr", NULL, "/usr", RMIL_DEFAULT);
    00529     addMacro(NULL, "_var", NULL, "/var", RMIL_DEFAULT);
    00530
    00531     addMacro(NULL, "_preScriptEnvironment",NULL, prescriptenviron,RMIL_DEFAULT);
    00532
    00533     setVarDefault(-1,                   "_topdir",
    00534                 "/usr/src/redhat",      "%{_usr}/src/redhat");
    00535     setVarDefault(-1,                   "_tmppath",
    00536                 "/var/tmp",             "%{_var}/tmp");
    00537     setVarDefault(-1,                   "_dbpath",
    00538                 "/var/lib/rpm",         "%{_var}/lib/rpm");
    00539     setVarDefault(-1,                   "_defaultdocdir",
    00540                 "/usr/doc",             "%{_usr}/doc");
    00541
    00542     setVarDefault(-1,                   "_rpmfilename",
    00543         "%%{ARCH}/%%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm",NULL);
    00544
    00545     setVarDefault(RPMVAR_OPTFLAGS,      "optflags",
    00546                 "-O2",                  NULL);
    00547     setVarDefault(-1,                   "sigtype",
    00548                 "none",                 NULL);
    00549     setVarDefault(-1,                   "_buildshell",
    00550                 "/bin/sh",              NULL);
    00551
    00552     setPathDefault(-1,                  "_builddir",    "BUILD");
    00553     setPathDefault(-1,                  "_rpmdir",      "RPMS");
    00554     setPathDefault(-1,                  "_srcrpmdir",   "SRPMS");
    00555     setPathDefault(-1,                  "_sourcedir",   "SOURCES");
    00556     setPathDefault(-1,                  "_specdir",     "SPECS");
    00557
    00558 }
    00559
    00560 /*@-usedef@*/   /*@ FIX: se usage inconsistent, W2DO? */
    00561 static int doReadRC( /*@killref@*/ FD_t fd, const char * urlfn)
    00562         /*@globals rpmGlobalMacroContext,
    00563                 fileSystem, internalState @*/
    00564         /*@modifies fd, fileSystem, internalState @*/
    00565 {
    00566     const char *s;
    00567     char *se, *next;
    00568     int linenum = 0;
    00569     struct rpmOption searchOption, * option;
    00570     int rc;
    00571
    00572     /* XXX really need rc = Slurp(fd, const char * filename, char ** buf) */
    00573   { off_t size = fdSize(fd);
    00574     size_t nb = (size >= 0 ? size : (8*BUFSIZ - 2));
    00575     if (nb == 0) {
    00576         (void) Fclose(fd);
    00577         return 0;
    00578     }
    00579     next = alloca(nb + 2);
    00580     next[0] = '\0';
    00581     rc = Fread(next, sizeof(*next), nb, fd);
    00582     if (Ferror(fd) || (size > 0 && rc != nb)) { /* XXX Feof(fd) */
    00583         rpmError(RPMERR_RPMRC, _("Failed to read %s: %s.\n"), urlfn,
    00584                  Fstrerror(fd));
    00585         rc = 1;
    00586     } else
    00587         rc = 0;
    00588     (void) Fclose(fd);
    00589     if (rc) return rc;
    00590     next[nb] = '\n';
    00591     next[nb + 1] = '\0';
    00592   }
    00593
    00594     /*@-branchstate@*/
    00595     while (*next != '\0') {
    00596         linenum++;
    00597
    00598         s = se = next;
    00599
    00600         /* Find end-of-line. */
    00601         while (*se && *se != '\n') se++;
    00602         if (*se != '\0') *se++ = '\0';
    00603         next = se;
    00604
    00605         /* Trim leading spaces */
    00606         while (*s && xisspace(*s)) s++;
    00607
    00608         /* We used to allow comments to begin anywhere, but not anymore. */
    00609         if (*s == '#' || *s == '\0') continue;
    00610
    00611         /* Find end-of-keyword. */
    00612         se = (char *)s;
    00613         while (*se && !xisspace(*se) && *se != ':') se++;
    00614
    00615         if (xisspace(*se)) {
    00616             *se++ = '\0';
    00617             while (*se && xisspace(*se) && *se != ':') se++;
    00618         }
    00619
    00620         if (*se != ':') {
    00621             rpmError(RPMERR_RPMRC, _("missing ':' (found 0x%02x) at %s:%d\n"),
    00622                      (unsigned)(0xff & *se), urlfn, linenum);
    00623             return 1;
    00624         }
    00625         *se++ = '\0';   /* terminate keyword or option, point to value */
    00626         while (*se && xisspace(*se)) se++;
    00627
    00628         /* Find keyword in table */
    00629         searchOption.name = s;
    00630         option = bsearch(&searchOption, optionTable, optionTableSize,
    00631                          sizeof(optionTable[0]), optionCompare);
    00632
    00633         if (option) {   /* For configuration variables  ... */
    00634             const char *arch, *val, *fn;
    00635
    00636             arch = val = fn = NULL;
    00637             if (*se == '\0') {
    00638                 rpmError(RPMERR_RPMRC, _("missing argument for %s at %s:%d\n"),
    00639                       option->name, urlfn, linenum);
    00640                 return 1;
    00641             }
    00642
    00643             switch (option->var) {
    00644             case RPMVAR_INCLUDE:
    00645               { FD_t fdinc;
    00646
    00647                 s = se;
    00648                 while (*se && !xisspace(*se)) se++;
    00649                 if (*se != '\0') *se++ = '\0';
    00650
    00651                 rpmRebuildTargetVars(NULL, NULL);
    00652
    00653                 fn = rpmGetPath(s, NULL);
    00654                 if (fn == NULL || *fn == '\0') {
    00655                     rpmError(RPMERR_RPMRC, _("%s expansion failed at %s:%d \"%s\"\n"),
    00656                         option->name, urlfn, linenum, s);
    00657                     fn = _free(fn);
    00658                     return 1;
    00659                     /*@notreached@*/
    00660                 }
    00661
    00662                 fdinc = Fopen(fn, "r.fpio");
    00663                 if (fdinc == NULL || Ferror(fdinc)) {
    00664                     rpmError(RPMERR_RPMRC, _("cannot open %s at %s:%d: %s\n"),
    00665                         fn, urlfn, linenum, Fstrerror(fdinc));
    00666                     rc = 1;
    00667                 } else {
    00668                     rc = doReadRC(fdinc, fn);
    00669                 }
    00670                 fn = _free(fn);
    00671                 if (rc) return rc;
    00672                 continue;       /* XXX don't save include value as var/macro */
    00673               } /*@notreached@*/ /*@switchbreak@*/ break;
    00674             case RPMVAR_MACROFILES:
    00675                 fn = rpmGetPath(se, NULL);
    00676                 if (fn == NULL || *fn == '\0') {
    00677                     rpmError(RPMERR_RPMRC, _("%s expansion failed at %s:%d \"%s\"\n"),
    00678                         option->name, urlfn, linenum, fn);
    00679                     fn = _free(fn);
    00680                     return 1;
    00681                 }
    00682                 se = (char *)fn;
    00683                 /*@switchbreak@*/ break;
    00684             case RPMVAR_PROVIDES:
    00685               { char *t;
    00686                 s = rpmGetVar(RPMVAR_PROVIDES);
    00687                 if (s == NULL) s = "";
    00688                 fn = t = xmalloc(strlen(s) + strlen(se) + 2);
    00689                 while (*s != '\0') *t++ = *s++;
    00690                 *t++ = ' ';
    00691                 while (*se != '\0') *t++ = *se++;
    00692                 *t++ = '\0';
    00693                 se = (char *)fn;
    00694               } /*@switchbreak@*/ break;
    00695             default:
    00696                 /*@switchbreak@*/ break;
    00697             }
    00698
    00699             if (option->archSpecific) {
    00700                 arch = se;
    00701                 while (*se && !xisspace(*se)) se++;
    00702                 if (*se == '\0') {
    00703                     rpmError(RPMERR_RPMRC,
    00704                                 _("missing architecture for %s at %s:%d\n"),
    00705                                 option->name, urlfn, linenum);
    00706                     return 1;
    00707                 }
    00708                 *se++ = '\0';
    00709                 while (*se && xisspace(*se)) se++;
    00710                 if (*se == '\0') {
    00711                     rpmError(RPMERR_RPMRC,
    00712                                 _("missing argument for %s at %s:%d\n"),
    00713                                 option->name, urlfn, linenum);
    00714                     return 1;
    00715                 }
    00716             }
    00717
    00718             val = se;
    00719
    00720             /* Only add macros if appropriate for this arch */
    00721             if (option->macroize &&
    00722               (arch == NULL || !strcmp(arch, current[ARCH]))) {
    00723                 char *n, *name;
    00724                 n = name = xmalloc(strlen(option->name)+2);
    00725                 if (option->localize)
    00726                     *n++ = '_';
    00727                 strcpy(n, option->name);
    00728                 addMacro(NULL, name, NULL, val, RMIL_RPMRC);
    00729                 free(name);
    00730             }
    00731             rpmSetVarArch(option->var, val, arch);
    00732             fn = _free(fn);
    00733
    00734         } else {        /* For arch/os compatibilty tables ... */
    00735             int gotit;
    00736             int i;
    00737
    00738             gotit = 0;
    00739
    00740             for (i = 0; i < RPM_MACHTABLE_COUNT; i++) {
    00741                 if (!strncmp(tables[i].key, s, strlen(tables[i].key)))
    00742                     /*@innerbreak@*/ break;
    00743             }
    00744
    00745             if (i < RPM_MACHTABLE_COUNT) {
    00746                 const char *rest = s + strlen(tables[i].key);
    00747                 if (*rest == '_') rest++;
    00748
    00749                 if (!strcmp(rest, "compat")) {
    00750                     if (machCompatCacheAdd(se, urlfn, linenum,
    00751                                                 &tables[i].cache))
    00752                         return 1;
    00753                     gotit = 1;
    00754                 } else if (tables[i].hasTranslate &&
    00755                            !strcmp(rest, "translate")) {
    00756                     if (addDefault(&tables[i].defaults,
    00757                                    &tables[i].defaultsLength,
    00758                                    se, urlfn, linenum))
    00759                         return 1;
    00760                     gotit = 1;
    00761                 } else if (tables[i].hasCanon &&
    00762                            !strcmp(rest, "canon")) {
    00763                     if (addCanon(&tables[i].canons, &tables[i].canonsLength,
    00764                                  se, urlfn, linenum))
    00765                         return 1;
    00766                     gotit = 1;
    00767                 }
    00768             }
    00769
    00770             if (!gotit) {
    00771                 rpmError(RPMERR_RPMRC, _("bad option '%s' at %s:%d\n"),
    00772                             s, urlfn, linenum);
    00773             }
    00774         }
    00775     }
    00776     /*@=branchstate@*/
    00777
    00778     return 0;
    00779 }
    00780 /*@=usedef@*/
    00781
    00782
    00785 /*@-bounds@*/
    00786 static int rpmPlatform(const char * platform)
    00787         /*@globals nplatpat, platpat,
    00788                 rpmGlobalMacroContext, fileSystem, internalState @*/
    00789         /*@modifies nplatpat, platpat,
    00790                 rpmGlobalMacroContext, fileSystem, internalState @*/
    00791 {
    00792     char *cpu = NULL, *vendor = NULL, *os = NULL, *gnu = NULL;
    00793     char * b = NULL;
    00794     ssize_t blen = 0;
    00795     int init_platform = 0;
    00796     char * p, * pe;
    00797     int rc;
    00798
    00799     rc = rpmioSlurp(platform, &b, &blen);
    00800
    00801     if (rc || b == NULL || blen <= 0) {
    00802         rc = -1;
    00803         goto exit;
    00804     }
    00805
    00806     p = b;
    00807     for (pe = p; p && *p; p = pe) {
    00808         pe = strchr(p, '\n');
    00809         if (pe)
    00810             *pe++ = '\0';
    00811
    00812         while (*p && isspace(*p))
    00813             p++;
    00814         if (*p == '\0' || *p == '#')
    00815             continue;
    00816
    00817         if (init_platform) {
    00818             char * t = p + strlen(p);
    00819
    00820             while (--t > p && isspace(*t))
    00821                 *t = '\0';
    00822             if (t > p) {
    00823                 platpat = xrealloc(platpat, (nplatpat + 2) * sizeof(*platpat));
    00824 /*@-onlyunqglobaltrans@*/
    00825                 platpat[nplatpat] = xstrdup(p);
    00826                 nplatpat++;
    00827                 platpat[nplatpat] = NULL;
    00828 /*@=onlyunqglobaltrans@*/
    00829             }
    00830             continue;
    00831         }
    00832
    00833         cpu = p;
    00834         vendor = "unknown";
    00835         os = "unknown";
    00836         gnu = NULL;
    00837         while (*p && !(*p == '-' || isspace(*p)))
    00838             p++;
    00839         if (*p != '\0') *p++ = '\0';
    00840
    00841         vendor = p;
    00842         while (*p && !(*p == '-' || isspace(*p)))
    00843             p++;
    00844 /*@-branchstate@*/
    00845         if (*p != '-') {
    00846             if (*p != '\0') *p++ = '\0';
    00847             os = vendor;
    00848             vendor = "unknown";
    00849         } else {
    00850             if (*p != '\0') *p++ = '\0';
    00851
    00852             os = p;
    00853             while (*p && !(*p == '-' || isspace(*p)))
    00854                 p++;
    00855             if (*p == '-') {
    00856                 *p++ = '\0';
    00857
    00858                 gnu = p;
    00859                 while (*p && !(*p == '-' || isspace(*p)))
    00860                     p++;
    00861             }
    00862             if (*p != '\0') *p++ = '\0';
    00863         }
    00864 /*@=branchstate@*/
    00865
    00866         addMacro(NULL, "_host_cpu", NULL, cpu, -1);
    00867         addMacro(NULL, "_host_vendor", NULL, vendor, -1);
    00868         addMacro(NULL, "_host_os", NULL, os, -1);
    00869
    00870         platpat = xrealloc(platpat, (nplatpat + 2) * sizeof(*platpat));
    00871 /*@-onlyunqglobaltrans@*/
    00872         platpat[nplatpat] = rpmExpand("%{_host_cpu}-%{_host_vendor}-%{_host_os}", (gnu && *gnu ? "-" : NULL), gnu, NULL);
    00873         nplatpat++;
    00874         platpat[nplatpat] = NULL;
    00875 /*@=onlyunqglobaltrans@*/
    00876
    00877         init_platform++;
    00878     }
    00879     rc = (init_platform ? 0 : -1);
    00880
    00881 exit:
    00882 /*@-modobserver@*/
    00883     b = _free(b);
    00884 /*@=modobserver@*/
    00885     return rc;
    00886 }
    00887 /*@=bounds@*/
    00888
    00889
    00890 #       if defined(__linux__) && defined(__i386__)
    00891 #include <setjmp.h>
    00892 #include <signal.h>
    00893
    00894 /*
    00895  * Generic CPUID function
    00896  */
    00897 static inline void cpuid(unsigned int op, int *eax, int *ebx, int *ecx, int *edx)
    00898         /*@modifies *eax, *ebx, *ecx, *edx @*/
    00899 {
    00900 #ifdef  __LCLINT__
    00901     *eax = *ebx = *ecx = *edx = 0;
    00902 #endif
    00903 #ifdef PIC
    00904         __asm__("pushl %%ebx; cpuid; movl %%ebx,%1; popl %%ebx"
    00905                 : "=a"(*eax), "=g"(*ebx), "=&c"(*ecx), "=&d"(*edx)
    00906                 : "a" (op));
    00907 #else
    00908         __asm__("cpuid"
    00909                 : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
    00910                 : "a" (op));
    00911 #endif
    00912
    00913 }
    00914
    00915 /*
    00916  * CPUID functions returning a single datum
    00917  */
    00918 static inline unsigned int cpuid_eax(unsigned int op)
    00919         /*@*/
    00920 {
    00921         unsigned int val;
    00922
    00923 #ifdef PIC
    00924         __asm__("pushl %%ebx; cpuid; popl %%ebx"
    00925                 : "=a" (val) : "a" (op) : "ecx", "edx");
    00926 #else
    00927         __asm__("cpuid"
    00928                 : "=a" (val) : "a" (op) : "ebx", "ecx", "edx");
    00929 #endif
    00930         return val;
    00931 }
    00932
    00933 static inline unsigned int cpuid_ebx(unsigned int op)
    00934         /*@*/
    00935 {
    00936         unsigned int tmp, val;
    00937
    00938 #ifdef PIC
    00939         __asm__("pushl %%ebx; cpuid; movl %%ebx,%1; popl %%ebx"
    00940                 : "=a" (tmp), "=g" (val) : "a" (op) : "ecx", "edx");
    00941 #else
    00942         __asm__("cpuid"
    00943                 : "=a" (tmp), "=b" (val) : "a" (op) : "ecx", "edx");
    00944 #endif
    00945         return val;
    00946 }
    00947
    00948 static inline unsigned int cpuid_ecx(unsigned int op)
    00949         /*@*/
    00950 {
    00951         unsigned int tmp, val;
    00952 #ifdef PIC
    00953         __asm__("pushl %%ebx; cpuid; popl %%ebx"
    00954                 : "=a" (tmp), "=c" (val) : "a" (op) : "edx");
    00955 #else
    00956         __asm__("cpuid"
    00957                 : "=a" (tmp), "=c" (val) : "a" (op) : "ebx", "edx");
    00958 #endif
    00959         return val;
    00960
    00961 }
    00962
    00963 static inline unsigned int cpuid_edx(unsigned int op)
    00964         /*@*/
    00965 {
    00966         unsigned int tmp, val;
    00967 #ifdef PIC
    00968         __asm__("pushl %%ebx; cpuid; popl %%ebx"
    00969                 : "=a" (tmp), "=d" (val) : "a" (op) : "ecx");
    00970 #else
    00971         __asm__("cpuid"
    00972                 : "=a" (tmp), "=d" (val) : "a" (op) : "ebx", "ecx");
    00973 #endif
    00974         return val;
    00975
    00976 }
    00977
    00978 /*@unchecked@*/
    00979 static sigjmp_buf jenv;
    00980
    00981 static inline void model3(int _unused)
    00982         /*@globals internalState @*/
    00983         /*@modifies internalState @*/
    00984 {
    00985         siglongjmp(jenv, 1);
    00986 }
    00987
    00988 static inline int RPMClass(void)
    00989         /*@globals internalState @*/
    00990         /*@modifies internalState @*/
    00991 {
    00992         int cpu;
    00993         unsigned int tfms, junk, cap, capamd;
    00994
    00995         signal(SIGILL, model3);
    00996
    00997         if (sigsetjmp(jenv, 1))
    00998                 return 3;
    00999
    01000         if (cpuid_eax(0x000000000)==0)
    01001                 return 4;
    01002
    01003         cpuid(0x00000001, &tfms, &junk, &junk, &cap);
    01004         cpuid(0x80000001, &junk, &junk, &junk, &capamd);
    01005
    01006         cpu = (tfms>>8)&15;
    01007
    01008         if (cpu < 6)
    01009                 return cpu;
    01010
    01011         if (cap & (1<<15)) {
    01012                 /* CMOV supported? */
    01013                 if (capamd & (1<<30))
    01014                         return 7;       /* 3DNOWEXT supported */
    01015                 return 6;
    01016         }
    01017
    01018         return 5;
    01019 }
    01020
    01021 /* should only be called for model 6 CPU's */
    01022 static int is_athlon(void)
    01023         /*@*/
    01024 {
    01025         unsigned int eax, ebx, ecx, edx;
    01026         char vendor[16];
    01027         int i;
    01028
    01029         cpuid (0, &eax, &ebx, &ecx, &edx);
    01030
    01031         /* If you care about space, you can just check ebx, ecx and edx directly
    01032            instead of forming a string first and then doing a strcmp */
    01033         memset(vendor, 0, sizeof(vendor));
    01034
    01035         for (i=0; i<4; i++)
    01036                 vendor[i] = (unsigned char) (ebx >>(8*i));
    01037         for (i=0; i<4; i++)
    01038                 vendor[4+i] = (unsigned char) (edx >>(8*i));
    01039         for (i=0; i<4; i++)
    01040                 vendor[8+i] = (unsigned char) (ecx >>(8*i));
    01041
    01042         if (strncmp(vendor, "AuthenticAMD", 12) != 0)
    01043                 return 0;
    01044
    01045         return 1;
    01046 }
    01047
    01048 #endif
    01049
    01050 #if defined(__linux__) && defined(__powerpc__)
    01051 static jmp_buf mfspr_jmpbuf;
    01052
    01053 static void mfspr_ill(int notused)
    01054 {
    01055     longjmp(mfspr_jmpbuf, -1);
    01056 }
    01057 #endif
    01058
    01061 static void defaultMachine(/*@out@*/ const char ** arch,
    01062                 /*@out@*/ const char ** os)
    01063         /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
    01064         /*@modifies *arch, *os, rpmGlobalMacroContext, fileSystem, internalState @*/
    01065 {
    01066     static struct utsname un;
    01067     static int gotDefaults = 0;
    01068     char * chptr;
    01069     canonEntry canon;
    01070     int rc;
    01071
    01072     while (!gotDefaults) {
    01073         if (!rpmPlatform(platform)) {
    01074             const char * s;
    01075             s = rpmExpand("%{_host_cpu}", NULL);
    01076             if (s) {
    01077                 strncpy(un.machine, s, sizeof(un.machine));
    01078                 un.machine[sizeof(un.machine)-1] = '\0';
    01079                 s = _free(s);
    01080             }
    01081             s = rpmExpand("%{_host_os}", NULL);
    01082             if (s) {
    01083                 strncpy(un.sysname, s, sizeof(un.sysname));
    01084                 un.sysname[sizeof(un.sysname)-1] = '\0';
    01085                 s = _free(s);
    01086             }
    01087             gotDefaults = 1;
    01088             break;
    01089         }
    01090         rc = uname(&un);
    01091         if (rc < 0) return;
    01092
    01093 #if !defined(__linux__)
    01094 #ifdef SNI
    01095         /* USUALLY un.sysname on sinix does start with the word "SINIX"
    01096          * let's be absolutely sure
    01097          */
    01098         strncpy(un.sysname, "SINIX", sizeof(un.sysname));
    01099 #endif
    01100         /*@-nullpass@*/
    01101         if (!strcmp(un.sysname, "AIX")) {
    01102             strcpy(un.machine, __power_pc() ? "ppc" : "rs6000");
    01103             sprintf(un.sysname,"aix%s.%s", un.version, un.release);
    01104         }
    01105         else if (!strcmp(un.sysname, "SunOS")) {
    01106             if (!strncmp(un.release,"4", 1)) /* SunOS 4.x */ {
    01107                 int fd;
    01108                 for (fd = 0;
    01109                     (un.release[fd] != 0 && (fd < sizeof(un.release)));
    01110                     fd++) {
    01111                       if (!xisdigit(un.release[fd]) && (un.release[fd] != '.')) {
    01112                         un.release[fd] = 0;
    01113                         /*@innerbreak@*/ break;
    01114                       }
    01115                     }
    01116                     sprintf(un.sysname,"sunos%s",un.release);
    01117             }
    01118
    01119             else /* Solaris 2.x: n.x.x becomes n-3.x.x */
    01120                 sprintf(un.sysname, "solaris%1d%s", atoi(un.release)-3,
    01121                         un.release+1+(atoi(un.release)/10));
    01122
    01123             /* Solaris on Intel hardware reports i86pc instead of i386
    01124              * (at least on 2.6 and 2.8)
    01125              */
    01126             if (!strcmp(un.machine, "i86pc"))
    01127                 sprintf(un.machine, "i386");
    01128         }
    01129         else if (!strcmp(un.sysname, "HP-UX"))
    01130             /*make un.sysname look like hpux9.05 for example*/
    01131             sprintf(un.sysname, "hpux%s", strpbrk(un.release, "123456789"));
    01132         else if (!strcmp(un.sysname, "OSF1"))
    01133             /*make un.sysname look like osf3.2 for example*/
    01134             sprintf(un.sysname, "osf%s", strpbrk(un.release, "123456789"));
    01135         else if (!strncmp(un.sysname, "IP", 2))
    01136             un.sysname[2] = '\0';
    01137         else if (!strncmp(un.sysname, "SINIX", 5)) {
    01138             sprintf(un.sysname, "sinix%s",un.release);
    01139             if (!strncmp(un.machine, "RM", 2))
    01140                 sprintf(un.machine, "mips");
    01141         }
    01142         else if ((!strncmp(un.machine, "34", 2) ||
    01143                 !strncmp(un.machine, "33", 2)) && \
    01144                 !strncmp(un.release, "4.0", 3))
    01145         {
    01146             /* we are on ncr-sysv4 */
    01147             char * prelid = NULL;
    01148             FD_t fd = Fopen("/etc/.relid", "r.fdio");
    01149             int gotit = 0;
    01150             /*@-branchstate@*/
    01151             if (fd != NULL && !Ferror(fd)) {
    01152                 chptr = xcalloc(1, 256);
    01153                 {   int irelid = Fread(chptr, sizeof(*chptr), 256, fd);
    01154                     (void) Fclose(fd);
    01155                     /* example: "112393 RELEASE 020200 Version 01 OS" */
    01156                     if (irelid > 0) {
    01157                         if ((prelid = strstr(chptr, "RELEASE "))){
    01158                             prelid += strlen("RELEASE ")+1;
    01159                             sprintf(un.sysname,"ncr-sysv4.%.*s",1,prelid);
    01160                             gotit = 1;
    01161                         }
    01162                     }
    01163                 }
    01164                 chptr = _free (chptr);
    01165             }
    01166             /*@=branchstate@*/
    01167             if (!gotit) /* parsing /etc/.relid file failed? */
    01168                 strcpy(un.sysname,"ncr-sysv4");
    01169             /* wrong, just for now, find out how to look for i586 later*/
    01170             strcpy(un.machine,"i486");
    01171         }
    01172         /*@=nullpass@*/
    01173 #endif  /* __linux__ */
    01174
    01175         /* get rid of the hyphens in the sysname */
    01176         for (chptr = un.machine; *chptr != '\0'; chptr++)
    01177             if (*chptr == '/') *chptr = '-';
    01178
    01179 #       if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL)
    01180             /* little endian */
    01181             strcpy(un.machine, "mipsel");
    01182 #       elif defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB)
    01183            /* big endian */
    01184                 strcpy(un.machine, "mips");
    01185 #       endif
    01186
    01187 #       if defined(__hpux) && defined(_SC_CPU_VERSION)
    01188         {
    01189 #           if !defined(CPU_PA_RISC1_2)
    01190 #                define CPU_PA_RISC1_2  0x211 /* HP PA-RISC1.2 */
    01191 #           endif
    01192 #           if !defined(CPU_PA_RISC2_0)
    01193 #               define CPU_PA_RISC2_0  0x214 /* HP PA-RISC2.0 */
    01194 #           endif
    01195             int cpu_version = sysconf(_SC_CPU_VERSION);
    01196
    01197 #           if defined(CPU_HP_MC68020)
    01198                 if (cpu_version == CPU_HP_MC68020)
    01199                     strcpy(un.machine, "m68k");
    01200 #           endif
    01201 #           if defined(CPU_HP_MC68030)
    01202                 if (cpu_version == CPU_HP_MC68030)
    01203                     strcpy(un.machine, "m68k");
    01204 #           endif
    01205 #           if defined(CPU_HP_MC68040)
    01206                 if (cpu_version == CPU_HP_MC68040)
    01207                     strcpy(un.machine, "m68k");
    01208 #           endif
    01209
    01210 #           if defined(CPU_PA_RISC1_0)
    01211                 if (cpu_version == CPU_PA_RISC1_0)
    01212                     strcpy(un.machine, "hppa1.0");
    01213 #           endif
    01214 #           if defined(CPU_PA_RISC1_1)
    01215                 if (cpu_version == CPU_PA_RISC1_1)
    01216                     strcpy(un.machine, "hppa1.1");
    01217 #           endif
    01218 #           if defined(CPU_PA_RISC1_2)
    01219                 if (cpu_version == CPU_PA_RISC1_2)
    01220                     strcpy(un.machine, "hppa1.2");
    01221 #           endif
    01222 #           if defined(CPU_PA_RISC2_0)
    01223                 if (cpu_version == CPU_PA_RISC2_0)
    01224                     strcpy(un.machine, "hppa2.0");
    01225 #           endif
    01226         }
    01227 #       endif   /* hpux */
    01228
    01229 #       if defined(__linux__) && defined(__sparc__)
    01230         if (!strcmp(un.machine, "sparc")) {
    01231             #define PERS_LINUX          0x00000000
    01232             #define PERS_LINUX_32BIT    0x00800000
    01233             #define PERS_LINUX32        0x00000008
    01234
    01235             extern int personality(unsigned long);
    01236             int oldpers;
    01237
    01238             oldpers = personality(PERS_LINUX_32BIT);
    01239             if (oldpers != -1) {
    01240                 if (personality(PERS_LINUX) != -1) {
    01241                     uname(&un);
    01242                     if (! strcmp(un.machine, "sparc64")) {
    01243                         strcpy(un.machine, "sparcv9");
    01244                         oldpers = PERS_LINUX32;
    01245                     }
    01246                 }
    01247                 personality(oldpers);
    01248             }
    01249         }
    01250 #       endif   /* sparc*-linux */
    01251
    01252 #       if defined(__GNUC__) && defined(__alpha__)
    01253         {
    01254             unsigned long amask, implver;
    01255             register long v0 __asm__("$0") = -1;
    01256             __asm__ (".long 0x47e00c20" : "=r"(v0) : "0"(v0));
    01257             amask = ~v0;
    01258             __asm__ (".long 0x47e03d80" : "=r"(v0));
    01259             implver = v0;
    01260             switch (implver) {
    01261             case 1:
    01262                 switch (amask) {
    01263                 case 0: strcpy(un.machine, "alphaev5"); break;
    01264                 case 1: strcpy(un.machine, "alphaev56"); break;
    01265                 case 0x101: strcpy(un.machine, "alphapca56"); break;
    01266                 }
    01267                 break;
    01268             case 2:
    01269                 switch (amask) {
    01270                 case 0x303: strcpy(un.machine, "alphaev6"); break;
    01271                 case 0x307: strcpy(un.machine, "alphaev67"); break;
    01272                 }
    01273                 break;
    01274             }
    01275         }
    01276 #       endif
    01277
    01278 #       if defined(__linux__) && defined(__i386__)
    01279         {
    01280             char class = (char) (RPMClass() | '0');
    01281
    01282             if ((class == '6' && is_athlon()) || class == '7')
    01283                 strcpy(un.machine, "athlon");
    01284             else if (strchr("3456", un.machine[1]) && un.machine[1] != class)
    01285                 un.machine[1] = class;
    01286         }
    01287 #       endif
    01288
    01289 #       if defined(__linux__) && defined(__powerpc__)
    01290         {
    01291             unsigned pvr = 0;
    01292             __sighandler_t oldh = signal(SIGILL, mfspr_ill);
    01293             if (setjmp(mfspr_jmpbuf) == 0) {
    01294                 __asm__ __volatile__ ("mfspr %0, 287" : "=r" (pvr));
    01295             }
    01296             signal(SIGILL, oldh);
    01297
    01298             if ( pvr ) {
    01299                 pvr >>= 16;
    01300                 if ( pvr >= 0x40)
    01301                     strcpy(un.machine, "ppcpseries");
    01302                 else if ( (pvr == 0x36) || (pvr == 0x37) )
    01303                     strcpy(un.machine, "ppciseries");
    01304                 else
    01305                     strcpy(un.machine, "ppc");
    01306             }
    01307         }
    01308 #       endif
    01309
    01310         /* the uname() result goes through the arch_canon table */
    01311         canon = lookupInCanonTable(un.machine,
    01312                                    tables[RPM_MACHTABLE_INSTARCH].canons,
    01313                                    tables[RPM_MACHTABLE_INSTARCH].canonsLength);
    01314         if (canon)
    01315             strcpy(un.machine, canon->short_name);
    01316
    01317         canon = lookupInCanonTable(un.sysname,
    01318                                    tables[RPM_MACHTABLE_INSTOS].canons,
    01319                                    tables[RPM_MACHTABLE_INSTOS].canonsLength);
    01320         if (canon)
    01321             strcpy(un.sysname, canon->short_name);
    01322         gotDefaults = 1;
    01323         break;
    01324     }
    01325
    01326     if (arch) *arch = un.machine;
    01327     if (os) *os = un.sysname;
    01328 }
    01329
    01330 static /*@observer@*/ /*@null@*/
    01331 const char * rpmGetVarArch(int var, /*@null@*/ const char * arch)
    01332         /*@*/
    01333 {
    01334     const struct rpmvarValue * next;
    01335
    01336     if (arch == NULL) arch = current[ARCH];
    01337
    01338     if (arch) {
    01339         next = &values[var];
    01340         while (next) {
    01341             if (next->arch && !strcmp(next->arch, arch)) return next->value;
    01342             next = next->next;
    01343         }
    01344     }
    01345
    01346     next = values + var;
    01347     while (next && next->arch) next = next->next;
    01348
    01349     return next ? next->value : NULL;
    01350 }
    01351
    01352 const char *rpmGetVar(int var)
    01353 {
    01354     return rpmGetVarArch(var, NULL);
    01355 }
    01356
    01357 /* this doesn't free the passed pointer! */
    01358 static void freeRpmVar(/*@only@*/ struct rpmvarValue * orig)
    01359         /*@modifies *orig @*/
    01360 {
    01361     struct rpmvarValue * next, * var = orig;
    01362
    01363     while (var) {
    01364         next = var->next;
    01365         var->arch = _free(var->arch);
    01366         var->value = _free(var->value);
    01367
    01368         /*@-branchstate@*/
    01369         if (var != orig) var = _free(var);
    01370         /*@=branchstate@*/
    01371         var = next;
    01372     }
    01373 }
    01374
    01375 void rpmSetVar(int var, const char * val)
    01376 {
    01377     /*@-immediatetrans@*/
    01378     freeRpmVar(&values[var]);
    01379     /*@=immediatetrans@*/
    01380     values[var].value = (val ? xstrdup(val) : NULL);
    01381 }
    01382
    01383 static void rpmSetVarArch(int var, const char * val, const char * arch)
    01384         /*@*/
    01385 {
    01386     struct rpmvarValue * next = values + var;
    01387
    01388     if (next->value) {
    01389         if (arch) {
    01390             while (next->next) {
    01391                 if (next->arch && !strcmp(next->arch, arch)) break;
    01392                 next = next->next;
    01393             }
    01394         } else {
    01395             while (next->next) {
    01396                 if (!next->arch) break;
    01397                 next = next->next;
    01398             }
    01399         }
    01400
    01401         /*@-nullpass@*/ /* LCL: arch != NULL here. */
    01402         if (next->arch && arch && !strcmp(next->arch, arch)) {
    01403         /*@=nullpass@*/
    01404             next->value = _free(next->value);
    01405             next->arch = _free(next->arch);
    01406         } else if (next->arch || arch) {
    01407             next->next = xmalloc(sizeof(*next->next));
    01408             next = next->next;
    01409             next->value = NULL;
    01410             next->arch = NULL;
    01411             next->next = NULL;
    01412         }
    01413     }
    01414
    01415     next->value = xstrdup(val);         /* XXX memory leak, hard to plug */
    01416     next->arch = (arch ? xstrdup(arch) : NULL);
    01417 }
    01418
    01419 void rpmSetTables(int archTable, int osTable)
    01420 {
    01421     const char * arch, * os;
    01422
    01423     defaultMachine(&arch, &os);
    01424
    01425     if (currTables[ARCH] != archTable) {
    01426         currTables[ARCH] = archTable;
    01427         rebuildCompatTables(ARCH, arch);
    01428     }
    01429
    01430     if (currTables[OS] != osTable) {
    01431         currTables[OS] = osTable;
    01432         rebuildCompatTables(OS, os);
    01433     }
    01434 }
    01435
    01436 int rpmMachineScore(int type, const char * name)
    01437 {
    01438     machEquivInfo info = machEquivSearch(&tables[type].equiv, name);
    01439     return (info != NULL ? info->score : 0);
    01440 }
    01441
    01442 void rpmGetMachine(const char ** arch, const char ** os)
    01443 {
    01444     if (arch)
    01445         *arch = current[ARCH];
    01446
    01447     if (os)
    01448         *os = current[OS];
    01449 }
    01450
    01451 void rpmSetMachine(const char * arch, const char * os)
    01452 {
    01453     const char * host_cpu, * host_os;
    01454
    01455     defaultMachine(&host_cpu, &host_os);
    01456
    01457     if (arch == NULL) {
    01458         arch = host_cpu;
    01459         if (tables[currTables[ARCH]].hasTranslate)
    01460             arch = lookupInDefaultTable(arch,
    01461                             tables[currTables[ARCH]].defaults,
    01462                             tables[currTables[ARCH]].defaultsLength);
    01463     }
    01464     if (arch == NULL) return;   /* XXX can't happen */
    01465
    01466     if (os == NULL) {
    01467         os = host_os;
    01468         if (tables[currTables[OS]].hasTranslate)
    01469             os = lookupInDefaultTable(os,
    01470                             tables[currTables[OS]].defaults,
    01471                             tables[currTables[OS]].defaultsLength);
    01472     }
    01473     if (os == NULL) return;     /* XXX can't happen */
    01474
    01475     if (!current[ARCH] || strcmp(arch, current[ARCH])) {
    01476         current[ARCH] = _free(current[ARCH]);
    01477         current[ARCH] = xstrdup(arch);
    01478         rebuildCompatTables(ARCH, host_cpu);
    01479     }
    01480
    01481     if (!current[OS] || strcmp(os, current[OS])) {
    01482         char * t = xstrdup(os);
    01483         current[OS] = _free(current[OS]);
    01484         /*
    01485          * XXX Capitalizing the 'L' is needed to insure that old
    01486          * XXX os-from-uname (e.g. "Linux") is compatible with the new
    01487          * XXX os-from-platform (e.g "linux" from "sparc-*-linux").
    01488          * XXX A copy of this string is embedded in headers and is
    01489          * XXX used by rpmInstallPackage->{os,arch}Okay->rpmMachineScore->
    01490          * XXX to verify correct arch/os from headers.
    01491          */
    01492         if (!strcmp(t, "linux"))
    01493             *t = 'L';
    01494         current[OS] = t;
    01495
    01496         rebuildCompatTables(OS, host_os);
    01497     }
    01498 }
    01499
    01500 static void rebuildCompatTables(int type, const char * name)
    01501         /*@*/
    01502 {
    01503     machFindEquivs(&tables[currTables[type]].cache,
    01504                    &tables[currTables[type]].equiv,
    01505                    name);
    01506 }
    01507
    01508 static void getMachineInfo(int type, /*@null@*/ /*@out@*/ const char ** name,
    01509                         /*@null@*/ /*@out@*/int * num)
    01510         /*@modifies *name, *num @*/
    01511 {
    01512     canonEntry canon;
    01513     int which = currTables[type];
    01514
    01515     /* use the normal canon tables, even if we're looking up build stuff */
    01516     if (which >= 2) which -= 2;
    01517
    01518     canon = lookupInCanonTable(current[type],
    01519                                tables[which].canons,
    01520                                tables[which].canonsLength);
    01521
    01522     if (canon) {
    01523         if (num) *num = canon->num;
    01524         if (name) *name = canon->short_name;
    01525     } else {
    01526         if (num) *num = 255;
    01527         if (name) *name = current[type];
    01528
    01529         if (tables[currTables[type]].hasCanon) {
    01530             rpmMessage(RPMMESS_WARNING, _("Unknown system: %s\n"), current[type]);
    01531             rpmMessage(RPMMESS_WARNING, _("Please contact rpm-list@redhat.com\n"));
    01532         }
    01533     }
    01534 }
    01535
    01536 void rpmGetArchInfo(const char ** name, int * num)
    01537 {
    01538     getMachineInfo(ARCH, name, num);
    01539 }
    01540
    01541 void rpmGetOsInfo(const char ** name, int * num)
    01542 {
    01543     getMachineInfo(OS, name, num);
    01544 }
    01545
    01546 static void rpmRebuildTargetVars(const char ** target, const char ** canontarget)
    01547 {
    01548
    01549     char *ca = NULL, *co = NULL, *ct = NULL;
    01550     int x;
    01551
    01552     /* Rebuild the compat table to recalculate the current target arch.  */
    01553
    01554     rpmSetMachine(NULL, NULL);
    01555     rpmSetTables(RPM_MACHTABLE_INSTARCH, RPM_MACHTABLE_INSTOS);
    01556     rpmSetTables(RPM_MACHTABLE_BUILDARCH, RPM_MACHTABLE_BUILDOS);
    01557
    01558     /*@-branchstate@*/
    01559     if (target && *target) {
    01560         char *c;
    01561         /* Set arch and os from specified build target */
    01562         ca = xstrdup(*target);
    01563         if ((c = strchr(ca, '-')) != NULL) {
    01564             *c++ = '\0';
    01565
    01566             if ((co = strrchr(c, '-')) == NULL) {
    01567                 co = c;
    01568             } else {
    01569                 if (!xstrcasecmp(co, "-gnu"))
    01570                     *co = '\0';
    01571                 if ((co = strrchr(c, '-')) == NULL)
    01572                     co = c;
    01573                 else
    01574                     co++;
    01575             }
    01576             if (co != NULL) co = xstrdup(co);
    01577         }
    01578     } else {
    01579         const char *a = NULL;
    01580         const char *o = NULL;
    01581         /* Set build target from rpm arch and os */
    01582         rpmGetArchInfo(&a, NULL);
    01583         ca = (a) ? xstrdup(a) : NULL;
    01584         rpmGetOsInfo(&o, NULL);
    01585         co = (o) ? xstrdup(o) : NULL;
    01586     }
    01587     /*@=branchstate@*/
    01588
    01589     /* If still not set, Set target arch/os from default uname(2) values */
    01590     if (ca == NULL) {
    01591         const char *a = NULL;
    01592         defaultMachine(&a, NULL);
    01593         ca = (a) ? xstrdup(a) : NULL;
    01594     }
    01595     for (x = 0; ca[x] != '\0'; x++)
    01596         ca[x] = xtolower(ca[x]);
    01597
    01598     if (co == NULL) {
    01599         const char *o = NULL;
    01600         defaultMachine(NULL, &o);
    01601         co = (o) ? xstrdup(o) : NULL;
    01602     }
    01603     for (x = 0; co[x] != '\0'; x++)
    01604         co[x] = xtolower(co[x]);
    01605
    01606     /* XXX For now, set canonical target to arch-os */
    01607     if (ct == NULL) {
    01608         ct = xmalloc(strlen(ca) + sizeof("-") + strlen(co));
    01609         sprintf(ct, "%s-%s", ca, co);
    01610     }
    01611
    01612 /*
    01613  * XXX All this macro pokery/jiggery could be achieved by doing a delayed
    01614  *      rpmInitMacros(NULL, PER-PLATFORM-MACRO-FILE-NAMES);
    01615  */
    01616     delMacro(NULL, "_target");
    01617     addMacro(NULL, "_target", NULL, ct, RMIL_RPMRC);
    01618     delMacro(NULL, "_target_cpu");
    01619     addMacro(NULL, "_target_cpu", NULL, ca, RMIL_RPMRC);
    01620     delMacro(NULL, "_target_os");
    01621     addMacro(NULL, "_target_os", NULL, co, RMIL_RPMRC);
    01622 /*
    01623  * XXX Make sure that per-arch optflags is initialized correctly.
    01624  */
    01625   { const char *optflags = rpmGetVarArch(RPMVAR_OPTFLAGS, ca);
    01626     if (optflags != NULL) {
    01627         delMacro(NULL, "optflags");
    01628         addMacro(NULL, "optflags", NULL, optflags, RMIL_RPMRC);
    01629     }
    01630   }
    01631
    01632     /*@-branchstate@*/
    01633     if (canontarget)
    01634         *canontarget = ct;
    01635     else
    01636         ct = _free(ct);
    01637     /*@=branchstate@*/
    01638     ca = _free(ca);
    01639     /*@-usereleased@*/
    01640     co = _free(co);
    01641     /*@=usereleased@*/
    01642 }
    01643
    01644 void rpmFreeRpmrc(void)
    01645 {
    01646     int i, j, k;
    01647
    01648 /*@-onlyunqglobaltrans -unqualifiedtrans @*/
    01649     if (platpat)
    01650     for (i = 0; i < nplatpat; i++)
    01651         platpat[i] = _free(platpat[i]);
    01652     platpat = _free(platpat);
    01653 /*@-onlyunqglobaltrans =unqualifiedtrans @*/
    01654     nplatpat = 0;
    01655
    01656     for (i = 0; i < RPM_MACHTABLE_COUNT; i++) {
    01657         tableType t;
    01658         t = tables + i;
    01659         if (t->equiv.list) {
    01660             for (j = 0; j < t->equiv.count; j++)
    01661                 t->equiv.list[j].name = _free(t->equiv.list[j].name);
    01662             t->equiv.list = _free(t->equiv.list);
    01663             t->equiv.count = 0;
    01664         }
    01665         if (t->cache.cache) {
    01666             for (j = 0; j < t->cache.size; j++) {
    01667                 machCacheEntry e;
    01668                 e = t->cache.cache + j;
    01669                 if (e == NULL)
    01670                     /*@innercontinue@*/ continue;
    01671                 e->name = _free(e->name);
    01672                 if (e->equivs) {
    01673                     for (k = 0; k < e->count; k++)
    01674                         e->equivs[k] = _free(e->equivs[k]);
    01675                     e->equivs = _free(e->equivs);
    01676                 }
    01677             }
    01678             t->cache.cache = _free(t->cache.cache);
    01679             t->cache.size = 0;
    01680         }
    01681         if (t->defaults) {
    01682             for (j = 0; j < t->defaultsLength; j++) {
    01683                 t->defaults[j].name = _free(t->defaults[j].name);
    01684                 t->defaults[j].defName = _free(t->defaults[j].defName);
    01685             }
    01686             t->defaults = _free(t->defaults);
    01687             t->defaultsLength = 0;
    01688         }
    01689         if (t->canons) {
    01690             for (j = 0; j < t->canonsLength; j++) {
    01691                 t->canons[j].name = _free(t->canons[j].name);
    01692                 t->canons[j].short_name = _free(t->canons[j].short_name);
    01693             }
    01694             t->canons = _free(t->canons);
    01695             t->canonsLength = 0;
    01696         }
    01697     }
    01698
    01699     for (i = 0; i < RPMVAR_NUM; i++) {
    01700         /*@only@*/ /*@null@*/ struct rpmvarValue * vp;
    01701         while ((vp = values[i].next) != NULL) {
    01702             values[i].next = vp->next;
    01703             vp->value = _free(vp->value);
    01704             vp->arch = _free(vp->arch);
    01705             vp = _free(vp);
    01706         }
    01707         values[i].value = _free(values[i].value);
    01708         values[i].arch = _free(values[i].arch);
    01709     }
    01710     current[OS] = _free(current[OS]);
    01711     current[ARCH] = _free(current[ARCH]);
    01712     defaultsInitialized = 0;
    01713 /*@-globstate -nullstate@*/ /* FIX: platpat/current may be NULL */
    01714     return;
    01715 /*@=globstate =nullstate@*/
    01716 }
    01717
    01723 static int rpmReadRC(/*@null@*/ const char * rcfiles)
    01724         /*@globals rpmGlobalMacroContext, rpmCLIMacroContext,
    01725                 fileSystem, internalState @*/
    01726         /*@modifies rpmGlobalMacroContext,
    01727                 fileSystem, internalState @*/
    01728 {
    01729     char *myrcfiles, *r, *re;
    01730     int rc;
    01731
    01732     if (!defaultsInitialized) {
    01733         setDefaults();
    01734         defaultsInitialized = 1;
    01735     }
    01736
    01737     if (rcfiles == NULL)
    01738         rcfiles = defrcfiles;
    01739
    01740     /* Read each file in rcfiles. */
    01741     rc = 0;
    01742     for (r = myrcfiles = xstrdup(rcfiles); r && *r != '\0'; r = re) {
    01743         char fn[4096];
    01744         FD_t fd;
    01745
    01746         /* Get pointer to rest of files */
    01747         for (re = r; (re = strchr(re, ':')) != NULL; re++) {
    01748             if (!(re[1] == '/' && re[2] == '/'))
    01749                 /*@innerbreak@*/ break;
    01750         }
    01751         if (re && *re == ':')
    01752             *re++ = '\0';
    01753         else
    01754             re = r + strlen(r);
    01755
    01756         /* Expand ~/ to $HOME/ */
    01757         fn[0] = '\0';
    01758         if (r[0] == '~' && r[1] == '/') {
    01759             const char * home = getenv("HOME");
    01760             if (home == NULL) {
    01761             /* XXX Only /usr/lib/rpm/rpmrc must exist in default rcfiles list */
    01762                 if (rcfiles == defrcfiles && myrcfiles != r)
    01763                     continue;
    01764                 rpmError(RPMERR_RPMRC, _("Cannot expand %s\n"), r);
    01765                 rc = 1;
    01766                 break;
    01767             }
    01768             if (strlen(home) > (sizeof(fn) - strlen(r))) {
    01769                 rpmError(RPMERR_RPMRC, _("Cannot read %s, HOME is too large.\n"),
    01770                                 r);
    01771                 rc = 1;
    01772                 break;
    01773             }
    01774             strcpy(fn, home);
    01775             r++;
    01776         }
    01777         strncat(fn, r, sizeof(fn) - (strlen(fn) + 1));
    01778         fn[sizeof(fn)-1] = '\0';
    01779
    01780         /* Read another rcfile */
    01781         fd = Fopen(fn, "r.fpio");
    01782         if (fd == NULL || Ferror(fd)) {
    01783             /* XXX Only /usr/lib/rpm/rpmrc must exist in default rcfiles list */
    01784             if (rcfiles == defrcfiles && myrcfiles != r)
    01785                 continue;
    01786             rpmError(RPMERR_RPMRC, _("Unable to open %s for reading: %s.\n"),
    01787                  fn, Fstrerror(fd));
    01788             rc = 1;
    01789             break;
    01790         } else {
    01791             rc = doReadRC(fd, fn);
    01792         }
    01793         if (rc) break;
    01794     }
    01795     myrcfiles = _free(myrcfiles);
    01796     if (rc)
    01797         return rc;
    01798
    01799     rpmSetMachine(NULL, NULL);  /* XXX WTFO? Why bother? */
    01800
    01801     {   const char *mfpath;
    01802         /*@-branchstate@*/
    01803         if ((mfpath = rpmGetVar(RPMVAR_MACROFILES)) != NULL) {
    01804             mfpath = xstrdup(mfpath);
    01805             rpmInitMacros(NULL, mfpath);
    01806             mfpath = _free(mfpath);
    01807         }
    01808         /*@=branchstate@*/
    01809     }
    01810
    01811     return rc;
    01812 }
    01813
    01814 int rpmReadConfigFiles(const char * file, const char * target)
    01815 {
    01816
    01817     /* Preset target macros */
    01818     /*@-nullstate@*/    /* FIX: target can be NULL */
    01819     rpmRebuildTargetVars(&target, NULL);
    01820
    01821     /* Read the files */
    01822     if (rpmReadRC(file)) return -1;
    01823
    01824     /* Reset target macros */
    01825     rpmRebuildTargetVars(&target, NULL);
    01826     /*@=nullstate@*/
    01827
    01828     /* Finally set target platform */
    01829     {   const char *cpu = rpmExpand("%{_target_cpu}", NULL);
    01830         const char *os = rpmExpand("%{_target_os}", NULL);
    01831         rpmSetMachine(cpu, os);
    01832         cpu = _free(cpu);
    01833         os = _free(os);
    01834     }
    01835
    01836     return 0;
    01837 }
    01838
    01839 int rpmShowRC(FILE * fp)
    01840 {
    01841     struct rpmOption *opt;
    01842     int i;
    01843     machEquivTable equivTable;
    01844
    01845     /* the caller may set the build arch which should be printed here */
    01846     fprintf(fp, "ARCHITECTURE AND OS:\n");
    01847     fprintf(fp, "build arch            : %s\n", current[ARCH]);
    01848
    01849     fprintf(fp, "compatible build archs:");
    01850     equivTable = &tables[RPM_MACHTABLE_BUILDARCH].equiv;
    01851     for (i = 0; i < equivTable->count; i++)
    01852         fprintf(fp," %s", equivTable->list[i].name);
    01853     fprintf(fp, "\n");
    01854
    01855     fprintf(fp, "build os              : %s\n", current[OS]);
    01856
    01857     fprintf(fp, "compatible build os's :");
    01858     equivTable = &tables[RPM_MACHTABLE_BUILDOS].equiv;
    01859     for (i = 0; i < equivTable->count; i++)
    01860         fprintf(fp," %s", equivTable->list[i].name);
    01861     fprintf(fp, "\n");
    01862
    01863     rpmSetTables(RPM_MACHTABLE_INSTARCH, RPM_MACHTABLE_INSTOS);
    01864     rpmSetMachine(NULL, NULL);  /* XXX WTFO? Why bother? */
    01865
    01866     fprintf(fp, "install arch          : %s\n", current[ARCH]);
    01867     fprintf(fp, "install os            : %s\n", current[OS]);
    01868
    01869     fprintf(fp, "compatible archs      :");
    01870     equivTable = &tables[RPM_MACHTABLE_INSTARCH].equiv;
    01871     for (i = 0; i < equivTable->count; i++)
    01872         fprintf(fp," %s", equivTable->list[i].name);
    01873     fprintf(fp, "\n");
    01874
    01875     fprintf(fp, "compatible os's       :");
    01876     equivTable = &tables[RPM_MACHTABLE_INSTOS].equiv;
    01877     for (i = 0; i < equivTable->count; i++)
    01878         fprintf(fp," %s", equivTable->list[i].name);
    01879     fprintf(fp, "\n");
    01880
    01881     fprintf(fp, "\nRPMRC VALUES:\n");
    01882     for (i = 0, opt = optionTable; i < optionTableSize; i++, opt++) {
    01883         const char *s = rpmGetVar(opt->var);
    01884         if (s != NULL || rpmIsVerbose())
    01885             fprintf(fp, "%-21s : %s\n", opt->name, s ? s : "(not set)");
    01886     }
    01887     fprintf(fp, "\n");
    01888
    01889     fprintf(fp, "Features supported by rpmlib:\n");
    01890     rpmShowRpmlibProvides(fp);
    01891     fprintf(fp, "\n");
    01892
    01893     rpmDumpMacroTable(NULL, fp);
    01894
    01895     return 0;
    01896 }
    01897 /*@=mods@*/
    01898 /*@=bounds@*/