# 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@*/