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

lib/rpmrc.c

Go to the documentation of this file.
00001 /*@-mods@*/
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 /*@access FD_t@*/               /* compared with NULL */
00024 
00025 /*@observer@*/ /*@unchecked@*/
00026 static const char *defrcfiles = LIBRPMRC_FILENAME ":" VENDORRPMRC_FILENAME ":/etc/rpmrc:~/.rpmrc";
00027 
00028 /*@observer@*/ /*@checked@*/
00029 const char * macrofiles = MACROFILES;
00030 
00031 /*@observer@*/ /*@unchecked@*/
00032 static const char * platform = "/etc/rpm/platform";
00033 /*@only@*/ /*@unchecked@*/
00034 static const char ** platpat = NULL;
00035 /*@unchecked@*/
00036 static int nplatpat = 0;
00037 
00038 typedef /*@owned@*/ const char * cptr_t;
00039 
00040 typedef struct machCacheEntry_s {
00041     const char * name;
00042     int count;
00043     cptr_t * equivs;
00044     int visited;
00045 } * machCacheEntry;
00046 
00047 typedef struct machCache_s {
00048     machCacheEntry cache;
00049     int size;
00050 } * machCache;
00051 
00052 typedef struct machEquivInfo_s {
00053     const char * name;
00054     int score;
00055 } * machEquivInfo;
00056 
00057 typedef struct machEquivTable_s {
00058     int count;
00059     machEquivInfo list;
00060 } * machEquivTable;
00061 
00062 struct rpmvarValue {
00063     const char * value;
00064     /* eventually, this arch will be replaced with a generic condition */
00065     const char * arch;
00066 /*@only@*/ /*@null@*/ struct rpmvarValue * next;
00067 };
00068 
00069 struct rpmOption {
00070     const char * name;
00071     int var;
00072     int archSpecific;
00073 /*@unused@*/ int required;
00074     int macroize;
00075     int localize;
00076 /*@unused@*/ struct rpmOptionValue * value;
00077 };
00078 
00079 typedef struct defaultEntry_s {
00080 /*@owned@*/ /*@null@*/ const char * name;
00081 /*@owned@*/ /*@null@*/ const char * defName;
00082 } * defaultEntry;
00083 
00084 typedef struct canonEntry_s {
00085 /*@owned@*/ const char * name;
00086 /*@owned@*/ const char * short_name;
00087     short num;
00088 } * canonEntry;
00089 
00090 /* tags are 'key'canon, 'key'translate, 'key'compat
00091  *
00092  * for giggles, 'key'_canon, 'key'_compat, and 'key'_canon will also work
00093  */
00094 typedef struct tableType_s {
00095 /*@observer@*/ const char * const key;
00096     const int hasCanon;
00097     const int hasTranslate;
00098     struct machEquivTable_s equiv;
00099     struct machCache_s cache;
00100     defaultEntry defaults;
00101     canonEntry canons;
00102     int defaultsLength;
00103     int canonsLength;
00104 } * tableType;
00105 
00106 /*@-fullinitblock@*/
00107 /*@unchecked@*/
00108 static struct tableType_s tables[RPM_MACHTABLE_COUNT] = {
00109     { "arch", 1, 0 },
00110     { "os", 1, 0 },
00111     { "buildarch", 0, 1 },
00112     { "buildos", 0, 1 }
00113 };
00114 
00115 /* this *must* be kept in alphabetical order */
00116 /* The order of the flags is archSpecific, required, macroize, localize */
00117 
00118 /*@unchecked@*/
00119 static struct rpmOption optionTable[] = {
00120     { "include",                RPMVAR_INCLUDE,                 0, 1,   0, 2 },
00121     { "macrofiles",             RPMVAR_MACROFILES,              0, 0,   0, 1 },
00122     { "optflags",               RPMVAR_OPTFLAGS,                1, 0,   1, 0 },
00123     { "provides",               RPMVAR_PROVIDES,                0, 0,   0, 0 },
00124 };
00125 /*@=fullinitblock@*/
00126 
00127 /*@unchecked@*/
00128 static int optionTableSize = sizeof(optionTable) / sizeof(*optionTable);
00129 
00130 #define OS      0
00131 #define ARCH    1
00132 
00133 /*@unchecked@*/
00134 static cptr_t current[2];
00135 
00136 /*@unchecked@*/
00137 static int currTables[2] = { RPM_MACHTABLE_INSTOS, RPM_MACHTABLE_INSTARCH };
00138 
00139 /*@unchecked@*/
00140 static struct rpmvarValue values[RPMVAR_NUM];
00141 
00142 /*@unchecked@*/
00143 static int defaultsInitialized = 0;
00144 
00145 /* prototypes */
00146 static int doReadRC( /*@killref@*/ FD_t fd, const char * urlfn)
00147         /*@globals rpmGlobalMacroContext,
00148                 fileSystem, internalState @*/
00149         /*@modifies fd, fileSystem, internalState @*/;
00150 
00151 static void rpmSetVarArch(int var, const char * val,
00152                 /*@null@*/ const char * arch)
00153         /*@globals internalState @*/
00154         /*@modifies internalState @*/;
00155 
00156 static void rebuildCompatTables(int type, const char * name)
00157         /*@globals internalState @*/
00158         /*@modifies internalState @*/;
00159 
00160 static void rpmRebuildTargetVars(/*@null@*/ const char **target, /*@null@*/ const char ** canontarget)
00161         /*@globals rpmGlobalMacroContext,
00162                 fileSystem, internalState @*/
00163         /*@modifies *canontarget, fileSystem, internalState @*/;
00164 
00165 static int optionCompare(const void * a, const void * b)
00166         /*@*/
00167 {
00168     return xstrcasecmp(((struct rpmOption *) a)->name,
00169                       ((struct rpmOption *) b)->name);
00170 }
00171 
00172 static /*@observer@*/ /*@null@*/ machCacheEntry
00173 machCacheFindEntry(const machCache cache, const char * key)
00174         /*@*/
00175 {
00176     int i;
00177 
00178     for (i = 0; i < cache->size; i++)
00179         if (!strcmp(cache->cache[i].name, key)) return cache->cache + i;
00180 
00181     return NULL;
00182 }
00183 
00184 static int machCompatCacheAdd(char * name, const char * fn, int linenum,
00185                                 machCache cache)
00186         /*@globals internalState @*/
00187         /*@modifies *name, cache->cache, cache->size, internalState @*/
00188 {
00189     machCacheEntry entry = NULL;
00190     char * chptr;
00191     char * equivs;
00192     int delEntry = 0;
00193     int i;
00194 
00195     while (*name && xisspace(*name)) name++;
00196 
00197     chptr = name;
00198     while (*chptr && *chptr != ':') chptr++;
00199     if (!*chptr) {
00200         rpmError(RPMERR_RPMRC, _("missing second ':' at %s:%d\n"), fn, linenum);
00201         return 1;
00202     } else if (chptr == name) {
00203         rpmError(RPMERR_RPMRC, _("missing architecture name at %s:%d\n"), fn,
00204                              linenum);
00205         return 1;
00206     }
00207 
00208     while (*chptr == ':' || xisspace(*chptr)) chptr--;
00209     *(++chptr) = '\0';
00210     equivs = chptr + 1;
00211     while (*equivs && xisspace(*equivs)) equivs++;
00212     if (!*equivs) {
00213         delEntry = 1;
00214     }
00215 
00216     if (cache->size) {
00217         entry = machCacheFindEntry(cache, name);
00218         if (entry) {
00219             for (i = 0; i < entry->count; i++)
00220                 entry->equivs[i] = _free(entry->equivs[i]);
00221             entry->equivs = _free(entry->equivs);
00222             entry->count = 0;
00223         }
00224     }
00225 
00226     if (!entry) {
00227         cache->cache = xrealloc(cache->cache,
00228                                (cache->size + 1) * sizeof(*cache->cache));
00229         entry = cache->cache + cache->size++;
00230         entry->name = xstrdup(name);
00231         entry->count = 0;
00232         entry->visited = 0;
00233     }
00234 
00235     if (delEntry) return 0;
00236 
00237     while ((chptr = strtok(equivs, " ")) != NULL) {
00238         equivs = NULL;
00239         if (chptr[0] == '\0')   /* does strtok() return "" ever?? */
00240             continue;
00241         if (entry->count)
00242             entry->equivs = xrealloc(entry->equivs, sizeof(*entry->equivs)
00243                                         * (entry->count + 1));
00244         else
00245             entry->equivs = xmalloc(sizeof(*entry->equivs));
00246 
00247         entry->equivs[entry->count] = xstrdup(chptr);
00248         entry->count++;
00249     }
00250 
00251     return 0;
00252 }
00253 
00254 static /*@observer@*/ /*@null@*/ machEquivInfo
00255 machEquivSearch(const machEquivTable table, const char * name)
00256         /*@*/
00257 {
00258     int i;
00259 
00260     for (i = 0; i < table->count; i++)
00261         if (!xstrcasecmp(table->list[i].name, name))
00262             return table->list + i;
00263 
00264     return NULL;
00265 }
00266 
00267 static void machAddEquiv(machEquivTable table, const char * name,
00268                            int distance)
00269         /*@modifies table->list, table->count @*/
00270 {
00271     machEquivInfo equiv;
00272 
00273     equiv = machEquivSearch(table, name);
00274     if (!equiv) {
00275         if (table->count)
00276             table->list = xrealloc(table->list, (table->count + 1)
00277                                     * sizeof(*table->list));
00278         else
00279             table->list = xmalloc(sizeof(*table->list));
00280 
00281         table->list[table->count].name = xstrdup(name);
00282         table->list[table->count++].score = distance;
00283     }
00284 }
00285 
00286 static void machCacheEntryVisit(machCache cache,
00287                 machEquivTable table, const char * name, int distance)
00288         /*@modifies table->list, table->count @*/
00289 {
00290     machCacheEntry entry;
00291     int i;
00292 
00293     entry = machCacheFindEntry(cache, name);
00294     if (!entry || entry->visited) return;
00295 
00296     entry->visited = 1;
00297 
00298     for (i = 0; i < entry->count; i++) {
00299         machAddEquiv(table, entry->equivs[i], distance);
00300     }
00301 
00302     for (i = 0; i < entry->count; i++) {
00303         machCacheEntryVisit(cache, table, entry->equivs[i], distance + 1);
00304     }
00305 }
00306 
00307 static void machFindEquivs(machCache cache, machEquivTable table,
00308                 const char * key)
00309         /*@modifies cache->cache, table->list, table->count @*/
00310 {
00311     int i;
00312 
00313     for (i = 0; i < cache->size; i++)
00314         cache->cache[i].visited = 0;
00315 
00316     while (table->count > 0) {
00317         --table->count;
00318         table->list[table->count].name = _free(table->list[table->count].name);
00319     }
00320     table->count = 0;
00321     table->list = _free(table->list);
00322 
00323     /*
00324      *  We have a general graph built using strings instead of pointers.
00325      *  Yuck. We have to start at a point at traverse it, remembering how
00326      *  far away everything is.
00327      */
00328     /*@-nullstate@*/    /* FIX: table->list may be NULL. */
00329     machAddEquiv(table, key, 1);
00330     machCacheEntryVisit(cache, table, key, 2);
00331     return;
00332     /*@=nullstate@*/
00333 }
00334 
00335 static int addCanon(canonEntry * table, int * tableLen, char * line,
00336                     const char * fn, int lineNum)
00337         /*@globals internalState @*/
00338         /*@modifies *table, *tableLen, *line, internalState @*/
00339 {
00340     canonEntry t;
00341     char *s, *s1;
00342     const char * tname;
00343     const char * tshort_name;
00344     int tnum;
00345 
00346     (*tableLen) += 2;
00347     /*@-unqualifiedtrans@*/
00348     *table = xrealloc(*table, sizeof(**table) * (*tableLen));
00349     /*@=unqualifiedtrans@*/
00350 
00351     t = & ((*table)[*tableLen - 2]);
00352 
00353     tname = strtok(line, ": \t");
00354     tshort_name = strtok(NULL, " \t");
00355     s = strtok(NULL, " \t");
00356     if (! (tname && tshort_name && s)) {
00357         rpmError(RPMERR_RPMRC, _("Incomplete data line at %s:%d\n"),
00358                 fn, lineNum);
00359         return RPMERR_RPMRC;
00360     }
00361     if (strtok(NULL, " \t")) {
00362         rpmError(RPMERR_RPMRC, _("Too many args in data line at %s:%d\n"),
00363               fn, lineNum);
00364         return RPMERR_RPMRC;
00365     }
00366 
00367     /*@-nullpass@*/     /* LCL: s != NULL here. */
00368     tnum = strtoul(s, &s1, 10);
00369     if ((*s1) || (s1 == s) || (tnum == ULONG_MAX)) {
00370         rpmError(RPMERR_RPMRC, _("Bad arch/os number: %s (%s:%d)\n"), s,
00371               fn, lineNum);
00372         return(RPMERR_RPMRC);
00373     }
00374     /*@=nullpass@*/
00375 
00376     t[0].name = xstrdup(tname);
00377     t[0].short_name = (tshort_name ? xstrdup(tshort_name) : xstrdup(""));
00378     t[0].num = tnum;
00379 
00380     /* From A B C entry */
00381     /* Add  B B C entry */
00382     t[1].name = (tshort_name ? xstrdup(tshort_name) : xstrdup(""));
00383     t[1].short_name = (tshort_name ? xstrdup(tshort_name) : xstrdup(""));
00384     t[1].num = tnum;
00385 
00386     return 0;
00387 }
00388 
00389 static int addDefault(defaultEntry * table, int * tableLen, char * line,
00390                         const char * fn, int lineNum)
00391         /*@globals internalState @*/
00392         /*@modifies *table, *tableLen, *line, internalState @*/
00393 {
00394     defaultEntry t;
00395 
00396     (*tableLen)++;
00397     /*@-unqualifiedtrans@*/
00398     *table = xrealloc(*table, sizeof(**table) * (*tableLen));
00399     /*@=unqualifiedtrans@*/
00400 
00401     t = & ((*table)[*tableLen - 1]);
00402 
00403     /*@-temptrans@*/
00404     t->name = strtok(line, ": \t");
00405     t->defName = strtok(NULL, " \t");
00406     if (! (t->name && t->defName)) {
00407         rpmError(RPMERR_RPMRC, _("Incomplete default line at %s:%d\n"),
00408                  fn, lineNum);
00409         return RPMERR_RPMRC;
00410     }
00411     if (strtok(NULL, " \t")) {
00412         rpmError(RPMERR_RPMRC, _("Too many args in default line at %s:%d\n"),
00413               fn, lineNum);
00414         return RPMERR_RPMRC;
00415     }
00416 
00417     t->name = xstrdup(t->name);
00418     t->defName = (t->defName ? xstrdup(t->defName) : NULL);
00419     /*@=temptrans@*/
00420 
00421     return 0;
00422 }
00423 
00424 static /*@null@*/ canonEntry lookupInCanonTable(const char * name,
00425                 const canonEntry table, int tableLen)
00426         /*@*/
00427 {
00428     while (tableLen) {
00429         tableLen--;
00430         if (strcmp(name, table[tableLen].name))
00431             continue;
00432         /*@-immediatetrans -retalias@*/
00433         return &(table[tableLen]);
00434         /*@=immediatetrans =retalias@*/
00435     }
00436 
00437     return NULL;
00438 }
00439 
00440 static /*@observer@*/ /*@null@*/
00441 const char * lookupInDefaultTable(const char * name,
00442                 const defaultEntry table, int tableLen)
00443         /*@*/
00444 {
00445     while (tableLen) {
00446         tableLen--;
00447         if (table[tableLen].name && !strcmp(name, table[tableLen].name))
00448             return table[tableLen].defName;
00449     }
00450 
00451     return name;
00452 }
00453 
00454 static void setVarDefault(int var, const char * macroname, const char * val,
00455                 /*@null@*/ const char * body)
00456         /*@globals rpmGlobalMacroContext,
00457                 internalState @*/
00458         /*@modifies internalState @*/
00459 {
00460     if (var >= 0) {     /* XXX Dying ... */
00461         if (rpmGetVar(var)) return;
00462         rpmSetVar(var, val);
00463     }
00464     if (body == NULL)
00465         body = val;
00466     addMacro(NULL, macroname, NULL, body, RMIL_DEFAULT);
00467 }
00468 
00469 static void setVar( const char *macroname, const char *body )
00470         /*@globals rpmGlobalMacroContext,
00471                 internalState @*/
00472         /*@modifies internalState @*/
00473 {
00474         if ( macroname && body )
00475                 addMacro( NULL, macroname, NULL, body, RMIL_DEFAULT );
00476 }
00477 
00478 /*@observer@*/ /*@unchecked@*/
00479 static const char * prescriptenviron = "\n\
00480 RPM_SOURCE_DIR=\"%{_sourcedir}\"\n\
00481 RPM_BUILD_DIR=\"%{_builddir}\"\n\
00482 RPM_DOC_DIR=\"%{_docdir}\"\n\
00483 export RPM_SOURCE_DIR RPM_BUILD_DIR RPM_DOC_DIR\n\
00484 RPM_OPT_FLAGS=\"%{optflags}\"\n\
00485 RPM_ARCH=\"%{_arch}\"\n\
00486 RPM_OS=\"%{_os}\"\n\
00487 export RPM_OPT_FLAGS RPM_ARCH RPM_OS\n\
00488 RPM_PACKAGE_NAME=\"%{name}\"\n\
00489 RPM_PACKAGE_VERSION=\"%{version}\"\n\
00490 RPM_PACKAGE_RELEASE=\"%{release}\"\n\
00491 export RPM_PACKAGE_NAME RPM_PACKAGE_VERSION RPM_PACKAGE_RELEASE\n\
00492 %{?buildroot:RPM_BUILD_ROOT=\"%{buildroot}\"\n\
00493 export RPM_BUILD_ROOT\n}\
00494 ";
00495 
00496 static void rpmSetDefaults(void)
00497         /*@globals rpmGlobalMacroContext,
00498                 internalState @*/
00499         /*@modifies internalState @*/
00500 {
00501         if ( defaultsInitialized )
00502                 return;
00503         else
00504         {
00505                 setVar( "_usr", "/usr" );
00506                 setVar( "_var", "/var" );
00507                 setVar( "_preScriptEnvironment", prescriptenviron );
00508 
00509                 setVar( "_topdir", "%{_usr}/src/RPM" );
00510                 setVar( "_tmppath", "%{_var}/tmp" );
00511                 setVar( "_dbpath", "%{_var}/lib/rpm" );
00512                 setVar( "_defaultdocdir", "%{_usr}/share/doc" );
00513 
00514                 setVar( "_rpmfilename", "%%{ARCH}/%%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm" );
00515 
00516                 setVar( "_signature", "none" );
00517                 setVar( "_buildshell", "/bin/sh" );
00518 
00519                 setVar( "_topsrcdir", "%{_topdir}" );
00520                 setVar( "_builddir", "%{_topdir}/BUILD" );
00521                 setVar( "_rpmdir", "%{_topdir}/RPMS" );
00522                 setVar( "_srcrpmdir", "%{_topdir}/SRPMS" );
00523                 setVar( "_sourcedir", "%{_topsrcdir}/SOURCES" );
00524                 setVar( "_specdir", "%{_topsrcdir}/SPECS" );
00525 
00526                 setVarDefault( RPMVAR_OPTFLAGS, "optflags", "-O2", NULL );
00527  
00528                 defaultsInitialized = 1;
00529         }
00530 }
00531 
00532 /*@-usedef@*/   /*@ FIX: se usage inconsistent, W2DO? */
00533 static int doReadRC( /*@killref@*/ FD_t fd, const char * urlfn)
00534         /*@globals rpmGlobalMacroContext,
00535                 fileSystem, internalState @*/
00536         /*@modifies fd, fileSystem, internalState @*/
00537 {
00538     const char *s;
00539     char *se, *next;
00540     int linenum = 0;
00541     struct rpmOption searchOption, * option;
00542     int rc;
00543 
00544     /* XXX really need rc = Slurp(fd, const char * filename, char ** buf) */
00545   { off_t size = fdSize(fd);
00546     size_t nb = (size >= 0 ? size : (8*BUFSIZ - 2));
00547     if (nb == 0) {
00548         (void) Fclose(fd);
00549         return 0;
00550     }
00551     next = alloca(nb + 2);
00552     next[0] = '\0';
00553     rc = Fread(next, sizeof(*next), nb, fd);
00554     if (Ferror(fd) || (size > 0 && rc != nb)) { /* XXX Feof(fd) */
00555         rpmError(RPMERR_RPMRC, _("Failed to read %s: %s.\n"), urlfn,
00556                  Fstrerror(fd));
00557         rc = 1;
00558     } else
00559         rc = 0;
00560     (void) Fclose(fd);
00561     if (rc) return rc;
00562     next[nb] = '\n';
00563     next[nb + 1] = '\0';
00564   }
00565 
00566     /*@-branchstate@*/
00567     while (*next != '\0') {
00568         linenum++;
00569 
00570         s = se = next;
00571 
00572         /* Find end-of-line. */
00573         while (*se && *se != '\n') se++;
00574         if (*se != '\0') *se++ = '\0';
00575         next = se;
00576 
00577         /* Trim leading spaces */
00578         while (*s && xisspace(*s)) s++;
00579 
00580         /* We used to allow comments to begin anywhere, but not anymore. */
00581         if (*s == '#' || *s == '\0') continue;
00582 
00583         /* Find end-of-keyword. */
00584         se = (char *)s;
00585         while (*se && !xisspace(*se) && *se != ':') se++;
00586 
00587         if (xisspace(*se)) {
00588             *se++ = '\0';
00589             while (*se && xisspace(*se) && *se != ':') se++;
00590         }
00591 
00592         if (*se != ':') {
00593             rpmError(RPMERR_RPMRC, _("missing ':' (found 0x%02x) at %s:%d\n"),
00594                      (unsigned)(0xff & *se), urlfn, linenum);
00595             return 1;
00596         }
00597         *se++ = '\0';   /* terminate keyword or option, point to value */
00598         while (*se && xisspace(*se)) se++;
00599 
00600         /* Find keyword in table */
00601         searchOption.name = s;
00602         option = bsearch(&searchOption, optionTable, optionTableSize,
00603                          sizeof(optionTable[0]), optionCompare);
00604 
00605         if (option) {   /* For configuration variables  ... */
00606             const char *arch, *val, *fn;
00607 
00608             arch = val = fn = NULL;
00609             if (*se == '\0') {
00610                 rpmError(RPMERR_RPMRC, _("missing argument for %s at %s:%d\n"),
00611                       option->name, urlfn, linenum);
00612                 return 1;
00613             }
00614 
00615             switch (option->var) {
00616             case RPMVAR_INCLUDE:
00617               { FD_t fdinc;
00618 
00619                 s = se;
00620                 while (*se && !xisspace(*se)) se++;
00621                 if (*se != '\0') *se++ = '\0';
00622 
00623                 rpmRebuildTargetVars(NULL, NULL);
00624 
00625                 fn = rpmGetPath(s, NULL);
00626                 if (fn == NULL || *fn == '\0') {
00627                     rpmError(RPMERR_RPMRC, _("%s expansion failed at %s:%d \"%s\"\n"),
00628                         option->name, urlfn, linenum, s);
00629                     fn = _free(fn);
00630                     return 1;
00631                     /*@notreached@*/
00632                 }
00633 
00634                 fdinc = Fopen(fn, "r.fpio");
00635                 if (fdinc == NULL || Ferror(fdinc)) {
00636                     rpmError(RPMERR_RPMRC, _("cannot open %s at %s:%d: %s\n"),
00637                         fn, urlfn, linenum, Fstrerror(fdinc));
00638                     rc = 1;
00639                 } else {
00640                     rc = doReadRC(fdinc, fn);
00641                 }
00642                 fn = _free(fn);
00643                 if (rc) return rc;
00644                 continue;       /* XXX don't save include value as var/macro */
00645               } /*@notreached@*/ /*@switchbreak@*/ break;
00646             case RPMVAR_MACROFILES:
00647                 fn = rpmGetPath(se, NULL);
00648                 if (fn == NULL || *fn == '\0') {
00649                     rpmError(RPMERR_RPMRC, _("%s expansion failed at %s:%d \"%s\"\n"),
00650                         option->name, urlfn, linenum, fn);
00651                     fn = _free(fn);
00652                     return 1;
00653                 }
00654                 se = (char *)fn;
00655                 /*@switchbreak@*/ break;
00656             case RPMVAR_PROVIDES:
00657               { char *t;
00658                 s = rpmGetVar(RPMVAR_PROVIDES);
00659                 if (s == NULL) s = "";
00660                 fn = t = xmalloc(strlen(s) + strlen(se) + 2);
00661                 while (*s != '\0') *t++ = *s++;
00662                 *t++ = ' ';
00663                 while (*se != '\0') *t++ = *se++;
00664                 *t++ = '\0';
00665                 se = (char *)fn;
00666               } /*@switchbreak@*/ break;
00667             default:
00668                 /*@switchbreak@*/ break;
00669             }
00670 
00671             if (option->archSpecific) {
00672                 arch = se;
00673                 while (*se && !xisspace(*se)) se++;
00674                 if (*se == '\0') {
00675                     rpmError(RPMERR_RPMRC,
00676                                 _("missing architecture for %s at %s:%d\n"),
00677                                 option->name, urlfn, linenum);
00678                     return 1;
00679                 }
00680                 *se++ = '\0';
00681                 while (*se && xisspace(*se)) se++;
00682                 if (*se == '\0') {
00683                     rpmError(RPMERR_RPMRC,
00684                                 _("missing argument for %s at %s:%d\n"),
00685                                 option->name, urlfn, linenum);
00686                     return 1;
00687                 }
00688             }
00689         
00690             val = se;
00691 
00692             /* Only add macros if appropriate for this arch */
00693             if (option->macroize &&
00694               (arch == NULL || !strcmp(arch, current[ARCH]))) {
00695                 char *n, *name;
00696                 n = name = xmalloc(strlen(option->name)+2);
00697                 if (option->localize)
00698                     *n++ = '_';
00699                 strcpy(n, option->name);
00700                 addMacro(NULL, name, NULL, val, RMIL_RPMRC);
00701                 free(name);
00702             }
00703             rpmSetVarArch(option->var, val, arch);
00704             fn = _free(fn);
00705 
00706         } else {        /* For arch/os compatibilty tables ... */
00707             int gotit;
00708             int i;
00709 
00710             gotit = 0;
00711 
00712             for (i = 0; i < RPM_MACHTABLE_COUNT; i++) {
00713                 if (!strncmp(tables[i].key, s, strlen(tables[i].key)))
00714                     /*@innerbreak@*/ break;
00715             }
00716 
00717             if (i < RPM_MACHTABLE_COUNT) {
00718                 const char *rest = s + strlen(tables[i].key);
00719                 if (*rest == '_') rest++;
00720 
00721                 if (!strcmp(rest, "compat")) {
00722                     if (machCompatCacheAdd(se, urlfn, linenum,
00723                                                 &tables[i].cache))
00724                         return 1;
00725                     gotit = 1;
00726                 } else if (tables[i].hasTranslate &&
00727                            !strcmp(rest, "translate")) {
00728                     if (addDefault(&tables[i].defaults,
00729                                    &tables[i].defaultsLength,
00730                                    se, urlfn, linenum))
00731                         return 1;
00732                     gotit = 1;
00733                 } else if (tables[i].hasCanon &&
00734                            !strcmp(rest, "canon")) {
00735                     if (addCanon(&tables[i].canons, &tables[i].canonsLength,
00736                                  se, urlfn, linenum))
00737                         return 1;
00738                     gotit = 1;
00739                 }
00740             }
00741 
00742             if (!gotit) {
00743                 rpmError(RPMERR_RPMRC, _("bad option '%s' at %s:%d\n"),
00744                             s, urlfn, linenum);
00745             }
00746         }
00747     }
00748     /*@=branchstate@*/
00749 
00750     return 0;
00751 }
00752 /*@=usedef@*/
00753 
00754 
00757 static int rpmPlatform(const char * platform)
00758         /*@globals nplatpat, platpat,
00759                 rpmGlobalMacroContext, fileSystem, internalState @*/
00760         /*@modifies nplatpat, platpat,
00761                 rpmGlobalMacroContext, fileSystem, internalState @*/
00762 {
00763     char *cpu = NULL, *vendor = NULL, *os = NULL, *gnu = NULL;
00764     char * b = NULL;
00765     ssize_t blen = 0;
00766     int init_platform = 0;
00767     char * p, * pe;
00768     int rc;
00769 
00770     rc = rpmioSlurp(platform, &b, &blen);
00771 
00772     if (rc || b == NULL || blen <= 0) {
00773         rc = -1;
00774         goto exit;
00775     }
00776 
00777     p = b;
00778     for (pe = p; p && *p; p = pe) {
00779         pe = strchr(p, '\n');
00780         if (pe)
00781             *pe++ = '\0';
00782 
00783         while (*p && isspace(*p))
00784             p++;
00785         if (*p == '\0' || *p == '#')
00786             continue;
00787 
00788         if (init_platform) {
00789             char * t = p + strlen(p);
00790 
00791             while (--t > p && isspace(*t))
00792                 *t = '\0';
00793             if (t > p) {
00794                 platpat = xrealloc(platpat, (nplatpat + 2) * sizeof(*platpat));
00795 /*@-onlyunqglobaltrans@*/
00796                 platpat[nplatpat] = xstrdup(p);
00797                 nplatpat++;
00798                 platpat[nplatpat] = NULL;
00799 /*@=onlyunqglobaltrans@*/
00800             }
00801             continue;
00802         }
00803 
00804         cpu = p;
00805         vendor = "unknown";
00806         os = "unknown";
00807         gnu = NULL;
00808         while (*p && !(*p == '-' || isspace(*p)))
00809             p++;
00810         if (*p != '\0') *p++ = '\0';
00811 
00812         vendor = p;
00813         while (*p && !(*p == '-' || isspace(*p)))
00814             p++;
00815 /*@-branchstate@*/
00816         if (*p != '-') {
00817             if (*p != '\0') *p++ = '\0';
00818             os = vendor;
00819             vendor = "unknown";
00820         } else {
00821             if (*p != '\0') *p++ = '\0';
00822 
00823             os = p;
00824             while (*p && !(*p == '-' || isspace(*p)))
00825                 p++;
00826             if (*p == '-') {
00827                 *p++ = '\0';
00828 
00829                 gnu = p;
00830                 while (*p && !(*p == '-' || isspace(*p)))
00831                     p++;
00832             }
00833             if (*p != '\0') *p++ = '\0';
00834         }
00835 /*@=branchstate@*/
00836 
00837         addMacro(NULL, "_host_cpu", NULL, cpu, -1);
00838         addMacro(NULL, "_host_vendor", NULL, vendor, -1);
00839         addMacro(NULL, "_host_os", NULL, os, -1);
00840 
00841         platpat = xrealloc(platpat, (nplatpat + 2) * sizeof(*platpat));
00842 /*@-onlyunqglobaltrans@*/
00843         platpat[nplatpat] = rpmExpand("%{_host_cpu}-%{_host_vendor}-%{_host_os}", (gnu && *gnu ? "-" : NULL), gnu, NULL);
00844         nplatpat++;
00845         platpat[nplatpat] = NULL;
00846 /*@=onlyunqglobaltrans@*/
00847         
00848         init_platform++;
00849     }
00850     rc = (init_platform ? 0 : -1);
00851 
00852 exit:
00853 /*@-modobserver@*/
00854     b = _free(b);
00855 /*@=modobserver@*/
00856     return rc;
00857 }
00858 
00859 
00860 #       if defined(__linux__) && defined(__i386__)
00861 #include <setjmp.h>
00862 #include <signal.h>
00863 
00864 /*
00865  * Generic CPUID function
00866  */
00867 static inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx)
00868         /*@modifies *eax, *ebx, *ecx, *edx @*/
00869 {
00870 #ifdef  __LCLINT__
00871     *eax = *ebx = *ecx = *edx = 0;
00872 #endif
00873 #ifdef PIC
00874         __asm__("pushl %%ebx; cpuid; movl %%ebx,%1; popl %%ebx"
00875                 : "=a"(*eax), "=g"(*ebx), "=&c"(*ecx), "=&d"(*edx)
00876                 : "a" (op));
00877 #else
00878         __asm__("cpuid"
00879                 : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
00880                 : "a" (op));
00881 #endif
00882 
00883 }
00884 
00885 /*
00886  * CPUID functions returning a single datum
00887  */
00888 static inline unsigned int cpuid_eax(unsigned int op)
00889         /*@*/
00890 {
00891         unsigned int val;
00892 
00893 #ifdef PIC
00894         __asm__("pushl %%ebx; cpuid; popl %%ebx"
00895                 : "=a" (val) : "a" (op) : "ecx", "edx");
00896 #else
00897         __asm__("cpuid"
00898                 : "=a" (val) : "a" (op) : "ebx", "ecx", "edx");
00899 #endif
00900         return val;
00901 }
00902 
00903 static inline unsigned int cpuid_ebx(unsigned int op)
00904         /*@*/
00905 {
00906         unsigned int tmp, val;
00907 
00908 #ifdef PIC
00909         __asm__("pushl %%ebx; cpuid; movl %%ebx,%1; popl %%ebx"
00910                 : "=a" (tmp), "=g" (val) : "a" (op) : "ecx", "edx");
00911 #else
00912         __asm__("cpuid"
00913                 : "=a" (tmp), "=b" (val) : "a" (op) : "ecx", "edx");
00914 #endif
00915         return val;
00916 }
00917 
00918 static inline unsigned int cpuid_ecx(unsigned int op)
00919         /*@*/
00920 {
00921         unsigned int tmp, val;
00922 #ifdef PIC
00923         __asm__("pushl %%ebx; cpuid; popl %%ebx"
00924                 : "=a" (tmp), "=c" (val) : "a" (op) : "edx");
00925 #else
00926         __asm__("cpuid"
00927                 : "=a" (tmp), "=c" (val) : "a" (op) : "ebx", "edx");
00928 #endif
00929         return val;
00930 
00931 }
00932 
00933 static inline unsigned int cpuid_edx(unsigned int op)
00934         /*@*/
00935 {
00936         unsigned int tmp, val;
00937 #ifdef PIC
00938         __asm__("pushl %%ebx; cpuid; popl %%ebx"
00939                 : "=a" (tmp), "=d" (val) : "a" (op) : "ecx");
00940 #else
00941         __asm__("cpuid"
00942                 : "=a" (tmp), "=d" (val) : "a" (op) : "ebx", "ecx");
00943 #endif
00944         return val;
00945 
00946 }
00947 
00948 /*@unchecked@*/
00949 static sigjmp_buf jenv;
00950 
00951 static inline void model3(int _unused)
00952         /*@globals internalState @*/
00953         /*@modifies internalState @*/
00954 {
00955         siglongjmp(jenv, 1);
00956 }
00957 
00958 static inline int RPMClass(void)
00959         /*@globals internalState @*/
00960         /*@modifies internalState @*/
00961 {
00962         int cpu;
00963         unsigned int tfms, junk, cap;
00964         
00965         signal(SIGILL, model3);
00966         
00967         if(sigsetjmp(jenv, 1))
00968                 return 3;
00969                 
00970         if(cpuid_eax(0x000000000)==0)
00971                 return 4;
00972         cpuid(0x000000001, &tfms, &junk, &junk, &cap);
00973         
00974         cpu = (tfms>>8)&15;
00975         
00976         if(cpu < 6)
00977                 return cpu;
00978                 
00979         if(cap & (1<<15))
00980                 return 6;
00981                 
00982         return 5;
00983 }
00984 
00985 /* should only be called for model 6 CPU's */
00986 static int is_athlon(void)
00987         /*@*/
00988 {
00989         unsigned int eax, ebx, ecx, edx;
00990         char vendor[16];
00991         int i;
00992         
00993         cpuid (0, &eax, &ebx, &ecx, &edx);
00994 
00995         /* If you care about space, you can just check ebx, ecx and edx directly
00996            instead of forming a string first and then doing a strcmp */
00997         memset(vendor, 0, sizeof(vendor));
00998         
00999         for (i=0; i<4; i++)
01000                 vendor[i] = (unsigned char) (ebx >>(8*i));
01001         for (i=0; i<4; i++)
01002                 vendor[4+i] = (unsigned char) (edx >>(8*i));
01003         for (i=0; i<4; i++)
01004                 vendor[8+i] = (unsigned char) (ecx >>(8*i));
01005                 
01006         if (strcmp(vendor, "AuthenticAMD") != 0)  
01007                 return 0;
01008 
01009         return 1;
01010 }
01011 
01012 #endif
01013 
01014 #if defined(__linux__) && defined(__powerpc__)
01015 static jmp_buf mfspr_jmpbuf;
01016 
01017 static void mfspr_ill(int notused)
01018 {
01019     longjmp(mfspr_jmpbuf, -1);
01020 }
01021 #endif
01022 
01023 static const char *checkAMD( void )
01024 {
01025         int     fd = open( "/proc/cpuinfo", O_RDONLY );
01026         if ( !fd )
01027                 return 0;
01028         else
01029         {
01030                 char    buffer[ 1 + getpagesize() ];
01031 
01032                 memset( buffer, 0, sizeof buffer );
01033                 read( fd, buffer, sizeof buffer - 1 );
01034                 close( fd );
01035 
01036                 if ( !strstr( buffer, "AMD" ) )
01037                         return 0;
01038 
01039                 if ( strstr( buffer, "Athlon" ) || strstr( buffer, "Duron" ) )
01040                         return "athlon";
01041 
01042                 if ( strstr( buffer, "K6" ) )
01043                         return "k6";
01044 
01045                 return 0;
01046         }
01047 }
01048 
01051 static void defaultMachine(/*@out@*/ const char ** arch,
01052                 /*@out@*/ const char ** os)
01053         /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
01054         /*@modifies *arch, *os, rpmGlobalMacroContext, fileSystem, internalState @*/
01055 {
01056     static struct utsname un;
01057     static int gotDefaults = 0;
01058     char * chptr;
01059     canonEntry canon;
01060     int rc;
01061 
01062     while (!gotDefaults) {
01063         if (!rpmPlatform(platform)) {
01064             const char * s;
01065             s = rpmExpand("%{_host_cpu}", NULL);
01066             if (s) {
01067                 strncpy(un.machine, s, sizeof(un.machine));
01068                 un.machine[sizeof(un.machine)-1] = '\0';
01069                 s = _free(s);
01070             }
01071             s = rpmExpand("%{_host_os}", NULL);
01072             if (s) {
01073                 strncpy(un.sysname, s, sizeof(un.sysname));
01074                 un.sysname[sizeof(un.sysname)-1] = '\0';
01075                 s = _free(s);
01076             }
01077             gotDefaults = 1;
01078             break;
01079         }
01080         rc = uname(&un);
01081         if (rc < 0) return;
01082 
01083 #if !defined(__linux__)
01084 #ifdef SNI
01085         /* USUALLY un.sysname on sinix does start with the word "SINIX"
01086          * let's be absolutely sure
01087          */
01088         strncpy(un.sysname, "SINIX", sizeof(un.sysname));
01089 #endif
01090         /*@-nullpass@*/
01091         if (!strcmp(un.sysname, "AIX")) {
01092             strcpy(un.machine, __power_pc() ? "ppc" : "rs6000");
01093             sprintf(un.sysname,"aix%s.%s", un.version, un.release);
01094         }
01095         else if (!strcmp(un.sysname, "SunOS")) {
01096             if (!strncmp(un.release,"4", 1)) /* SunOS 4.x */ {
01097                 int fd;
01098                 for (fd = 0;
01099                     (un.release[fd] != 0 && (fd < sizeof(un.release)));
01100                     fd++) {
01101                       if (!xisdigit(un.release[fd]) && (un.release[fd] != '.')) {
01102                         un.release[fd] = 0;
01103                         /*@innerbreak@*/ break;
01104                       }
01105                     }
01106                     sprintf(un.sysname,"sunos%s",un.release);
01107             }
01108 
01109             else /* Solaris 2.x: n.x.x becomes n-3.x.x */
01110                 sprintf(un.sysname, "solaris%1d%s", atoi(un.release)-3,
01111                         un.release+1+(atoi(un.release)/10));
01112 
01113             /* Solaris on Intel hardware reports i86pc instead of i386
01114              * (at least on 2.6 and 2.8)
01115              */
01116             if (!strcmp(un.machine, "i86pc"))
01117                 sprintf(un.machine, "i386");
01118         }
01119         else if (!strcmp(un.sysname, "HP-UX"))
01120             /*make un.sysname look like hpux9.05 for example*/
01121             sprintf(un.sysname, "hpux%s", strpbrk(un.release, "123456789"));
01122         else if (!strcmp(un.sysname, "OSF1"))
01123             /*make un.sysname look like osf3.2 for example*/
01124             sprintf(un.sysname, "osf%s", strpbrk(un.release, "123456789"));
01125         else if (!strncmp(un.sysname, "IP", 2))
01126             un.sysname[2] = '\0';
01127         else if (!strncmp(un.sysname, "SINIX", 5)) {
01128             sprintf(un.sysname, "sinix%s",un.release);
01129             if (!strncmp(un.machine, "RM", 2))
01130                 sprintf(un.machine, "mips");
01131         }
01132         else if ((!strncmp(un.machine, "34", 2) ||
01133                 !strncmp(un.machine, "33", 2)) && \
01134                 !strncmp(un.release, "4.0", 3))
01135         {
01136             /* we are on ncr-sysv4 */
01137             char * prelid = NULL;
01138             FD_t fd = Fopen("/etc/.relid", "r.fdio");
01139             int gotit = 0;
01140             /*@-branchstate@*/
01141             if (fd != NULL && !Ferror(fd)) {
01142                 chptr = xcalloc(1, 256);
01143                 {   int irelid = Fread(chptr, sizeof(*chptr), 256, fd);
01144                     (void) Fclose(fd);
01145                     /* example: "112393 RELEASE 020200 Version 01 OS" */
01146                     if (irelid > 0) {
01147                         if ((prelid = strstr(chptr, "RELEASE "))){
01148                             prelid += strlen("RELEASE ")+1;
01149                             sprintf(un.sysname,"ncr-sysv4.%.*s",1,prelid);
01150                             gotit = 1;
01151                         }
01152                     }
01153                 }
01154                 chptr = _free (chptr);
01155             }
01156             /*@=branchstate@*/
01157             if (!gotit) /* parsing /etc/.relid file failed? */
01158                 strcpy(un.sysname,"ncr-sysv4");
01159             /* wrong, just for now, find out how to look for i586 later*/
01160             strcpy(un.machine,"i486");
01161         }
01162         /*@=nullpass@*/
01163 #endif  /* __linux__ */
01164 
01165         /* get rid of the hyphens in the sysname */
01166         for (chptr = un.machine; *chptr != '\0'; chptr++)
01167             if (*chptr == '/') *chptr = '-';
01168 
01169 #       if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL)
01170             /* little endian */
01171             strcpy(un.machine, "mipsel");
01172 #       elif defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB)
01173            /* big endian */
01174                 strcpy(un.machine, "mips");
01175 #       endif
01176 
01177 #       if defined(__hpux) && defined(_SC_CPU_VERSION)
01178         {
01179 #           if !defined(CPU_PA_RISC1_2)
01180 #                define CPU_PA_RISC1_2  0x211 /* HP PA-RISC1.2 */
01181 #           endif
01182 #           if !defined(CPU_PA_RISC2_0)
01183 #               define CPU_PA_RISC2_0  0x214 /* HP PA-RISC2.0 */
01184 #           endif
01185             int cpu_version = sysconf(_SC_CPU_VERSION);
01186 
01187 #           if defined(CPU_HP_MC68020)
01188                 if (cpu_version == CPU_HP_MC68020)
01189                     strcpy(un.machine, "m68k");
01190 #           endif
01191 #           if defined(CPU_HP_MC68030)
01192                 if (cpu_version == CPU_HP_MC68030)
01193                     strcpy(un.machine, "m68k");
01194 #           endif
01195 #           if defined(CPU_HP_MC68040)
01196                 if (cpu_version == CPU_HP_MC68040)
01197                     strcpy(un.machine, "m68k");
01198 #           endif
01199 
01200 #           if defined(CPU_PA_RISC1_0)
01201                 if (cpu_version == CPU_PA_RISC1_0)
01202                     strcpy(un.machine, "hppa1.0");
01203 #           endif
01204 #           if defined(CPU_PA_RISC1_1)
01205                 if (cpu_version == CPU_PA_RISC1_1)
01206                     strcpy(un.machine, "hppa1.1");
01207 #           endif
01208 #           if defined(CPU_PA_RISC1_2)
01209                 if (cpu_version == CPU_PA_RISC1_2)
01210                     strcpy(un.machine, "hppa1.2");
01211 #           endif
01212 #           if defined(CPU_PA_RISC2_0)
01213                 if (cpu_version == CPU_PA_RISC2_0)
01214                     strcpy(un.machine, "hppa2.0");
01215 #           endif
01216         }
01217 #       endif   /* hpux */
01218 
01219 #       if HAVE_PERSONALITY && defined(__linux__) && defined(__sparc__)
01220         if (!strcmp(un.machine, "sparc")) {
01221             #define PERS_LINUX          0x00000000
01222             #define PERS_LINUX_32BIT    0x00800000
01223             #define PERS_LINUX32        0x00000008
01224 
01225             extern int personality(unsigned long);
01226             int oldpers;
01227             
01228             oldpers = personality(PERS_LINUX_32BIT);
01229             if (oldpers != -1) {
01230                 if (personality(PERS_LINUX) != -1) {
01231                     uname(&un);
01232                     if (! strcmp(un.machine, "sparc64")) {
01233                         strcpy(un.machine, "sparcv9");
01234                         oldpers = PERS_LINUX32;
01235                     }
01236                 }
01237                 personality(oldpers);
01238             }
01239         }
01240 #       endif   /* sparc*-linux */
01241 
01242 #       if defined(__GNUC__) && defined(__alpha__)
01243         {
01244             unsigned long amask, implver;
01245             register long v0 __asm__("$0") = -1;
01246             __asm__ (".long 0x47e00c20" : "=r"(v0) : "0"(v0));
01247             amask = ~v0;
01248             __asm__ (".long 0x47e03d80" : "=r"(v0));
01249             implver = v0;
01250             switch (implver) {
01251             case 1:
01252                 switch (amask) {
01253                 case 0: strcpy(un.machine, "alphaev5"); break;
01254                 case 1: strcpy(un.machine, "alphaev56"); break;
01255                 case 0x101: strcpy(un.machine, "alphapca56"); break;
01256                 }
01257                 break;
01258             case 2:
01259                 switch (amask) {
01260                 case 0x303: strcpy(un.machine, "alphaev6"); break;
01261                 case 0x307: strcpy(un.machine, "alphaev67"); break;
01262                 }
01263                 break;
01264             }
01265         }
01266 #       endif
01267 
01268 #       if defined(__linux__) && defined(__i386__)
01269 #if 0
01270         {
01271             char class = (char) (RPMClass() | '0');
01272 
01273             if (class == '6' && is_athlon())
01274                 strcpy(un.machine, "athlon");
01275             else if (strchr("3456", un.machine[1]) && un.machine[1] != class)
01276                 un.machine[1] = class;
01277         }
01278 #endif
01279 
01280         if ( !strcmp( un.machine, "i586" ) || !strcmp( un.machine, "i686" ) )
01281         {
01282                 const char *amd = checkAMD();
01283                 if ( amd )
01284                         strcpy( un.machine, amd );
01285         }
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     for (i = 0; i < RPM_MACHTABLE_COUNT; i++) {
01649         tableType t;
01650         t = tables + i;
01651         if (t->equiv.list) {
01652             for (j = 0; j < t->equiv.count; j++)
01653                 t->equiv.list[j].name = _free(t->equiv.list[j].name);
01654             t->equiv.list = _free(t->equiv.list);
01655             t->equiv.count = 0;
01656         }
01657         if (t->cache.cache) {
01658             for (j = 0; j < t->cache.size; j++) {
01659                 machCacheEntry e;
01660                 e = t->cache.cache + j;
01661                 if (e == NULL)
01662                     /*@innercontinue@*/ continue;
01663                 e->name = _free(e->name);
01664                 if (e->equivs) {
01665                     for (k = 0; k < e->count; k++)
01666                         e->equivs[k] = _free(e->equivs[k]);
01667                     e->equivs = _free(e->equivs);
01668                 }
01669             }
01670             t->cache.cache = _free(t->cache.cache);
01671             t->cache.size = 0;
01672         }
01673         if (t->defaults) {
01674             for (j = 0; j < t->defaultsLength; j++) {
01675                 t->defaults[j].name = _free(t->defaults[j].name);
01676                 t->defaults[j].defName = _free(t->defaults[j].defName);
01677             }
01678             t->defaults = _free(t->defaults);
01679             t->defaultsLength = 0;
01680         }
01681         if (t->canons) {
01682             for (j = 0; j < t->canonsLength; j++) {
01683                 t->canons[j].name = _free(t->canons[j].name);
01684                 t->canons[j].short_name = _free(t->canons[j].short_name);
01685             }
01686             t->canons = _free(t->canons);
01687             t->canonsLength = 0;
01688         }
01689     }
01690 
01691     for (i = 0; i < RPMVAR_NUM; i++) {
01692         /*@only@*/ /*@null@*/ struct rpmvarValue * vp;
01693         while ((vp = values[i].next) != NULL) {
01694             values[i].next = vp->next;
01695             vp->value = _free(vp->value);
01696             vp->arch = _free(vp->arch);
01697             vp = _free(vp);
01698         }
01699         values[i].value = _free(values[i].value);
01700         values[i].arch = _free(values[i].arch);
01701     }
01702     current[OS] = _free(current[OS]);
01703     current[ARCH] = _free(current[ARCH]);
01704     defaultsInitialized = 0;
01705 /*@-nullstate@*/ /* FIX: current may be NULL */
01706     return;
01707 /*@=nullstate@*/
01708 }
01709 
01715 static int rpmReadRC(/*@null@*/ const char * rcfiles)
01716         /*@globals rpmGlobalMacroContext, rpmCLIMacroContext,
01717                 fileSystem, internalState @*/
01718         /*@modifies rpmGlobalMacroContext,
01719                 fileSystem, internalState @*/
01720 {
01721     char *myrcfiles, *r, *re;
01722     int rc;
01723 
01724     rpmSetDefaults();
01725 
01726     if (rcfiles == NULL)
01727         rcfiles = defrcfiles;
01728 
01729     /* Read each file in rcfiles. */
01730     rc = 0;
01731     for (r = myrcfiles = xstrdup(rcfiles); r && *r != '\0'; r = re) {
01732         char fn[4096];
01733         FD_t fd;
01734 
01735         /* Get pointer to rest of files */
01736         for (re = r; (re = strchr(re, ':')) != NULL; re++) {
01737             if (!(re[1] == '/' && re[2] == '/'))
01738                 /*@innerbreak@*/ break;
01739         }
01740         if (re && *re == ':')
01741             *re++ = '\0';
01742         else
01743             re = r + strlen(r);
01744 
01745         /* Expand ~/ to $HOME/ */
01746         fn[0] = '\0';
01747         if (r[0] == '~' && r[1] == '/') {
01748             const char * home = getenv("HOME");
01749             if (home == NULL) {
01750             /* XXX Only /usr/lib/rpm/rpmrc must exist in default rcfiles list */
01751                 if (rcfiles == defrcfiles && myrcfiles != r)
01752                     continue;
01753                 rpmError(RPMERR_RPMRC, _("Cannot expand %s\n"), r);
01754                 rc = 1;
01755                 break;
01756             }
01757             if (strlen(home) > (sizeof(fn) - strlen(r))) {
01758                 rpmError(RPMERR_RPMRC, _("Cannot read %s, HOME is too large.\n"),
01759                                 r);
01760                 rc = 1;
01761                 break;
01762             }
01763             strcpy(fn, home);
01764             r++;
01765         }
01766         strncat(fn, r, sizeof(fn) - (strlen(fn) + 1));
01767         fn[sizeof(fn)-1] = '\0';
01768 
01769         /* Read another rcfile */
01770         fd = Fopen(fn, "r.fpio");
01771         if (fd == NULL || Ferror(fd)) {
01772             /* XXX Only /usr/lib/rpm/rpmrc must exist in default rcfiles list */
01773             if (rcfiles == defrcfiles && myrcfiles != r)
01774                 continue;
01775             rpmError(RPMERR_RPMRC, _("Unable to open %s for reading: %s.\n"),
01776                  fn, Fstrerror(fd));
01777             rc = 1;
01778             break;
01779         } else {
01780             rc = doReadRC(fd, fn);
01781         }
01782         if (rc) break;
01783     }
01784     myrcfiles = _free(myrcfiles);
01785     if (rc)
01786         return rc;
01787 
01788     rpmSetMachine(NULL, NULL);  /* XXX WTFO? Why bother? */
01789 
01790     {   const char *mfpath;
01791         /*@-branchstate@*/
01792         if ((mfpath = rpmGetVar(RPMVAR_MACROFILES)) != NULL) {
01793             mfpath = xstrdup(mfpath);
01794             rpmInitMacros(NULL, mfpath);
01795             mfpath = _free(mfpath);
01796         }
01797         /*@=branchstate@*/
01798     }
01799 
01800     return rc;
01801 }
01802 
01803 int rpmReadConfigFiles(const char * file, const char * target)
01804 {
01805 
01806     /* Preset target macros */
01807     /*@-nullstate@*/    /* FIX: target can be NULL */
01808     rpmRebuildTargetVars(&target, NULL);
01809 
01810     /* Read the files */
01811     if (rpmReadRC(file)) return -1;
01812 
01813     /* Reset target macros */
01814     rpmRebuildTargetVars(&target, NULL);
01815     /*@=nullstate@*/
01816 
01817     /* Finally set target platform */
01818     {   const char *cpu = rpmExpand("%{_target_cpu}", NULL);
01819         const char *os = rpmExpand("%{_target_os}", NULL);
01820         rpmSetMachine(cpu, os);
01821         cpu = _free(cpu);
01822         os = _free(os);
01823     }
01824 
01825     return 0;
01826 }
01827 
01828 int rpmShowRC(FILE * fp)
01829 {
01830     struct rpmOption *opt;
01831     int i;
01832     machEquivTable equivTable;
01833 
01834     /* the caller may set the build arch which should be printed here */
01835     fprintf(fp, "ARCHITECTURE AND OS:\n");
01836     fprintf(fp, "build arch            : %s\n", current[ARCH]);
01837 
01838     fprintf(fp, "compatible build archs:");
01839     equivTable = &tables[RPM_MACHTABLE_BUILDARCH].equiv;
01840     for (i = 0; i < equivTable->count; i++)
01841         fprintf(fp," %s", equivTable->list[i].name);
01842     fprintf(fp, "\n");
01843 
01844     fprintf(fp, "build os              : %s\n", current[OS]);
01845 
01846     fprintf(fp, "compatible build os's :");
01847     equivTable = &tables[RPM_MACHTABLE_BUILDOS].equiv;
01848     for (i = 0; i < equivTable->count; i++)
01849         fprintf(fp," %s", equivTable->list[i].name);
01850     fprintf(fp, "\n");
01851 
01852     rpmSetTables(RPM_MACHTABLE_INSTARCH, RPM_MACHTABLE_INSTOS);
01853     rpmSetMachine(NULL, NULL);  /* XXX WTFO? Why bother? */
01854 
01855     fprintf(fp, "install arch          : %s\n", current[ARCH]);
01856     fprintf(fp, "install os            : %s\n", current[OS]);
01857 
01858     fprintf(fp, "compatible archs      :");
01859     equivTable = &tables[RPM_MACHTABLE_INSTARCH].equiv;
01860     for (i = 0; i < equivTable->count; i++)
01861         fprintf(fp," %s", equivTable->list[i].name);
01862     fprintf(fp, "\n");
01863 
01864     fprintf(fp, "compatible os's       :");
01865     equivTable = &tables[RPM_MACHTABLE_INSTOS].equiv;
01866     for (i = 0; i < equivTable->count; i++)
01867         fprintf(fp," %s", equivTable->list[i].name);
01868     fprintf(fp, "\n");
01869 
01870     fprintf(fp, "\nRPMRC VALUES:\n");
01871     for (i = 0, opt = optionTable; i < optionTableSize; i++, opt++) {
01872         const char *s = rpmGetVar(opt->var);
01873         if (s != NULL || rpmIsVerbose())
01874             fprintf(fp, "%-21s : %s\n", opt->name, s ? s : "(not set)");
01875     }
01876     fprintf(fp, "\n");
01877 
01878     fprintf(fp, "Features supported by rpmlib:\n");
01879     rpmShowRpmlibProvides(fp);
01880     fprintf(fp, "\n");
01881 
01882     rpmDumpMacroTable(NULL, fp);
01883 
01884     return 0;
01885 }
01886 /*@=mods@*/

Generated on Sun Feb 2 23:32:03 2003 for rpm by doxygen1.2.18