lib/rpmrc.c

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

Generated on Thu Mar 9 17:27:44 2006 for rpm by  doxygen 1.4.6