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

Generated on Sun Oct 26 13:02:01 2003 for rpm by doxygen1.2.18