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

lib/rpmrc.c

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

Generated at Thu Sep 6 11:25:42 2001 for rpm by doxygen1.2.8.1 written by Dimitri van Heesch, © 1997-2001