rpm 5.3.7

lib/rpmrc.c

Go to the documentation of this file.
00001 #include "system.h"
00002 
00003 #include <stdarg.h>
00004 
00005 #if defined(HAVE_SYS_SYSTEMCFG_H)
00006 #include <sys/systemcfg.h>
00007 #else
00008 #define __power_pc() 0
00009 #endif
00010 
00011 #define _RPMIOB_INTERNAL        /* XXX for rpmiobSlurp */
00012 #include <rpmio.h>
00013 #include <rpmcb.h>
00014 #define _MIRE_INTERNAL
00015 #include <mire.h>
00016 #include <argv.h>
00017 #include <rpmlua.h>
00018 #include <rpmluaext.h>
00019 #include <rpmmacro.h>
00020 
00021 #include <rpmtypes.h>
00022 #include <rpmtag.h>
00023 #define _RPMEVR_INTERNAL
00024 #include <rpmevr.h>
00025 
00026 #define _RPMDS_INTERNAL
00027 #include <rpmds.h>
00028 
00029 #include <rpmcli.h>
00030 
00031 #include <rpmsyck.h>
00032 
00033 #include "debug.h"
00034 
00035 /*@access miRE@*/
00036 
00037 /*@unchecked@*/ /*@null@*/
00038 static const char * configTarget = NULL;
00039 
00040 /*@observer@*/ /*@unchecked@*/
00041 static const char * platform = SYSCONFIGDIR "/platform";
00042 
00043 /*@only@*/ /*@relnull@*/ /*@unchecked@*/
00044 void * platpat = NULL;
00045 /*@unchecked@*/
00046 int nplatpat = 0;
00047 
00048 extern rpmds cpuinfoP;
00049 
00050 
00051 
00057 enum rpm_machtable_e {
00058     RPM_MACHTABLE_INSTARCH      = 0,    
00059     RPM_MACHTABLE_INSTOS        = 1,    
00060     RPM_MACHTABLE_BUILDARCH     = 2,    
00061     RPM_MACHTABLE_BUILDOS       = 3     
00062 };
00063 #define RPM_MACHTABLE_COUNT     4       
00065 typedef /*@owned@*/ const char * cptr_t;
00066 
00067 typedef struct machCacheEntry_s {
00068     const char * name;
00069     int count;
00070     cptr_t * equivs;
00071     int visited;
00072 } * machCacheEntry;
00073 
00074 typedef struct machCache_s {
00075     machCacheEntry cache;
00076     int size;
00077 } * machCache;
00078 
00079 typedef struct machEquivInfo_s {
00080     const char * name;
00081     int score;
00082 } * machEquivInfo;
00083 
00084 typedef struct machEquivTable_s {
00085     int count;
00086     machEquivInfo list;
00087 } * machEquivTable;
00088 
00089 typedef struct defaultEntry_s {
00090 /*@owned@*/ /*@null@*/ const char * name;
00091 /*@owned@*/ /*@null@*/ const char * defName;
00092 } * defaultEntry;
00093 
00094 typedef struct canonEntry_s {
00095 /*@owned@*/ const char * name;
00096 /*@owned@*/ const char * short_name;
00097     short num;
00098 } * canonEntry;
00099 
00100 /* tags are 'key'canon, 'key'translate, 'key'compat
00101  *
00102  * for giggles, 'key'_canon, 'key'_compat, and 'key'_canon will also work
00103  */
00104 typedef struct tableType_s {
00105 /*@observer@*/ const char * const key;
00106     const int hasCanon;
00107     const int hasTranslate;
00108     struct machEquivTable_s equiv;
00109     struct machCache_s cache;
00110     defaultEntry defaults;
00111     canonEntry canons;
00112     int defaultsLength;
00113     int canonsLength;
00114 } * tableType;
00115 
00116 /*@-fullinitblock@*/
00117 /*@unchecked@*/
00118 static struct tableType_s tables[RPM_MACHTABLE_COUNT] = {
00119     { "arch", 1, 0  },
00120     { "os", 1, 0 },
00121     { "buildarch", 0, 1 },
00122     { "buildos", 0, 1 }
00123 };
00124 /*@=fullinitblock@*/
00125 
00126 #define OS      0
00127 #define ARCH    1
00128 
00129 /*@unchecked@*/
00130 static cptr_t current[2];
00131 
00132 /*@unchecked@*/
00133 static int currTables[2] = { RPM_MACHTABLE_INSTOS, RPM_MACHTABLE_INSTARCH };
00134 
00135 /*@unchecked@*/
00136 static int defaultsInitialized = 0;
00137 
00138 /* prototypes */
00139 static void rpmRebuildTargetVars(/*@null@*/ const char **target, /*@null@*/ const char ** canontarget)
00140         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00141         /*@modifies *canontarget, rpmGlobalMacroContext,
00142                 fileSystem, internalState @*/;
00143 
00144 static /*@observer@*/ /*@null@*/ machCacheEntry
00145 machCacheFindEntry(const machCache cache, const char * key)
00146         /*@*/
00147 {
00148     int i;
00149 
00150     for (i = 0; i < cache->size; i++)
00151         if (!strcmp(cache->cache[i].name, key)) return cache->cache + i;
00152 
00153     return NULL;
00154 }
00155 
00156 static void machAddEquiv(machEquivTable table, const char * name,
00157                            int distance)
00158         /*@modifies table->list, table->count @*/
00159 {
00160     machEquivInfo equiv;
00161 
00162     {   int i;
00163         equiv = NULL;
00164         for (i = 0; i < table->count; i++) {
00165             if (xstrcasecmp(table->list[i].name, name))
00166                 continue;
00167             equiv = table->list + i;
00168             break;
00169         }
00170     }
00171 
00172     if (!equiv) {
00173         if (table->count)
00174             table->list = xrealloc(table->list, (table->count + 1)
00175                                     * sizeof(*table->list));
00176         else
00177             table->list = xmalloc(sizeof(*table->list));
00178 
00179         table->list[table->count].name = xstrdup(name);
00180         table->list[table->count++].score = distance;
00181     }
00182 }
00183 
00184 static void machCacheEntryVisit(machCache cache,
00185                 machEquivTable table, const char * name, int distance)
00186         /*@modifies table->list, table->count @*/
00187 {
00188     machCacheEntry entry;
00189     int i;
00190 
00191     entry = machCacheFindEntry(cache, name);
00192     if (!entry || entry->visited) return;
00193 
00194     entry->visited = 1;
00195 
00196     for (i = 0; i < entry->count; i++) {
00197         machAddEquiv(table, entry->equivs[i], distance);
00198     }
00199 
00200     for (i = 0; i < entry->count; i++) {
00201         machCacheEntryVisit(cache, table, entry->equivs[i], distance + 1);
00202     }
00203 }
00204 
00205 static void rebuildCompatTables(int type, const char * name)
00206         /*@globals tables, internalState @*/
00207         /*@modifies tables, internalState @*/
00208 {
00209     machCache cache = &tables[currTables[type]].cache;
00210     machEquivTable table = &tables[currTables[type]].equiv;
00211     const char * key = name;
00212     int i;
00213 
00214     for (i = 0; i < cache->size; i++)
00215         cache->cache[i].visited = 0;
00216 
00217     while (table->count > 0) {
00218         --table->count;
00219         table->list[table->count].name = _free(table->list[table->count].name);
00220     }
00221     table->count = 0;
00222     table->list = _free(table->list);
00223 
00224     /*
00225      *  We have a general graph built using strings instead of pointers.
00226      *  Yuck. We have to start at a point at traverse it, remembering how
00227      *  far away everything is.
00228      */
00229     /*@-nullstate@*/    /* FIX: table->list may be NULL. */
00230     machAddEquiv(table, key, 1);
00231     machCacheEntryVisit(cache, table, key, 2);
00232     return;
00233     /*@=nullstate@*/
00234 }
00235 
00236 static /*@null@*/ canonEntry lookupInCanonTable(const char * name,
00237                 const canonEntry table, int tableLen)
00238         /*@*/
00239 {
00240     while (tableLen) {
00241         tableLen--;
00242         if (strcmp(name, table[tableLen].name))
00243             continue;
00244         /*@-immediatetrans -retalias@*/
00245         return &(table[tableLen]);
00246         /*@=immediatetrans =retalias@*/
00247     }
00248 
00249     return NULL;
00250 }
00251 
00252 static /*@observer@*/ /*@null@*/
00253 const char * lookupInDefaultTable(const char * name,
00254                 const defaultEntry table, int tableLen)
00255         /*@*/
00256 {
00257     while (tableLen) {
00258         tableLen--;
00259         if (table[tableLen].name && !strcmp(name, table[tableLen].name))
00260             return table[tableLen].defName;
00261     }
00262 
00263     return name;
00264 }
00265 
00266 static void addMacroDefault(const char * macroname,
00267                 const char * val, /*@null@*/ const char * body)
00268         /*@globals rpmGlobalMacroContext, internalState @*/
00269         /*@modifies rpmGlobalMacroContext, internalState @*/
00270 {
00271     if (body == NULL)
00272         body = val;
00273     addMacro(NULL, macroname, NULL, body, RMIL_DEFAULT);
00274 }
00275 
00276 static void setPathDefault(const char * macroname, const char * subdir)
00277         /*@globals rpmGlobalMacroContext, internalState @*/
00278         /*@modifies rpmGlobalMacroContext, internalState @*/
00279 {
00280     if (macroname != NULL) {
00281 #define _TOPDIRMACRO    "%{_topdir}/"
00282         char *body = alloca(sizeof(_TOPDIRMACRO) + strlen(subdir));
00283         strcpy(body, _TOPDIRMACRO);
00284         strcat(body, subdir);
00285         addMacro(NULL, macroname, NULL, body, RMIL_DEFAULT);
00286 #undef _TOPDIRMACRO
00287     }
00288 }
00289 
00290 /*@observer@*/ /*@unchecked@*/
00291 static const char * ___build_pre = "\n\
00292 RPM_SOURCE_DIR=\"%{_sourcedir}\"\n\
00293 RPM_BUILD_DIR=\"%{_builddir}\"\n\
00294 RPM_OPT_FLAGS=\"%{optflags}\"\n\
00295 RPM_ARCH=\"%{_arch}\"\n\
00296 RPM_OS=\"%{_os}\"\n\
00297 export RPM_SOURCE_DIR RPM_BUILD_DIR RPM_OPT_FLAGS RPM_ARCH RPM_OS\n\
00298 RPM_DOC_DIR=\"%{_docdir}\"\n\
00299 export RPM_DOC_DIR\n\
00300 RPM_PACKAGE_NAME=\"%{name}\"\n\
00301 RPM_PACKAGE_VERSION=\"%{version}\"\n\
00302 RPM_PACKAGE_RELEASE=\"%{release}\"\n\
00303 export RPM_PACKAGE_NAME RPM_PACKAGE_VERSION RPM_PACKAGE_RELEASE\n\
00304 %{?buildroot:RPM_BUILD_ROOT=\"%{buildroot}\"\n\
00305 export RPM_BUILD_ROOT\n}\
00306 ";
00307 
00308 #if defined(RPM_VENDOR_WINDRIVER)
00309 /*@unchecked@*/
00310 extern const char * __usrlibrpm;
00311 /*@unchecked@*/
00312 extern const char * __etcrpm;
00313 #endif
00314 
00315 static void setDefaults(void)
00316         /*@globals rpmGlobalMacroContext, internalState @*/
00317         /*@modifies rpmGlobalMacroContext, internalState @*/
00318 {
00319 
00320 #if defined(RPM_VENDOR_WINDRIVER)
00321     addMacro(NULL, "_usrlibrpm", NULL, __usrlibrpm, RMIL_DEFAULT);
00322     addMacro(NULL, "_etcrpm", NULL, __etcrpm, RMIL_DEFAULT);
00323     addMacro(NULL, "_vendor", NULL, "%{?_host_vendor}%{!?_host_vendor:wrs}", RMIL_DEFAULT);
00324 #endif
00325 
00326     addMacro(NULL, "_usr", NULL, USRPREFIX, RMIL_DEFAULT);
00327     addMacro(NULL, "_var", NULL, VARPREFIX, RMIL_DEFAULT);
00328     addMacro(NULL, "_prefix", NULL, "%{_usr}", RMIL_DEFAULT);
00329 
00330     addMacro(NULL, "___build_pre", NULL, ___build_pre, RMIL_DEFAULT);
00331 
00332     addMacroDefault("_topdir",
00333                 "%{_usr}/src/rpm",      NULL);
00334     addMacroDefault("_tmppath",
00335                 "%{_var}/tmp",          NULL);
00336     addMacroDefault("_dbpath",
00337                 "%{_var}/lib/rpm",      NULL);
00338     addMacroDefault("_defaultdocdir",
00339                 "%{_usr}/share/doc",    NULL);
00340 
00341     addMacroDefault("_rpmfilename",
00342         "%%{ARCH}/%%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm",NULL);
00343 
00344     addMacroDefault("optflags",
00345                 "-O2 -g",                       NULL);
00346     addMacroDefault("sigtype",
00347                 "none",                 NULL);
00348     addMacroDefault("_buildshell",
00349                 "/bin/sh",              NULL);
00350 
00351     setPathDefault("_builddir", "BUILD");
00352     setPathDefault("_rpmdir",   "RPMS");
00353     setPathDefault("_srcrpmdir",        "SRPMS");
00354     setPathDefault("_sourcedir",        "SOURCES");
00355     setPathDefault("_specdir",  "SPECS");
00356 
00357 }
00358 
00359 typedef struct cpu_vendor_os_gnu {
00360 /*@owned@*/
00361     const char * str;
00362 /*@observer@*/
00363     const char * cpu;
00364 /*@observer@*/
00365     const char * vendor;
00366 /*@observer@*/
00367     const char * os;
00368 /*@observer@*/
00369     const char * gnu;
00370 } * CVOG_t;
00371 
00374 static int parseCVOG(const char * str, CVOG_t *cvogp)
00375         /*@modifies *cvogp @*/
00376 {
00377     CVOG_t cvog = xcalloc(1, sizeof(*cvog));
00378     char * p, * pe;
00379 
00380     cvog->str = p = xstrdup(str);
00381     pe = p + strlen(p);
00382     while (pe-- > p && isspace(*pe))
00383         *pe = '\0';
00384 
00385     cvog->cpu = p;
00386     cvog->vendor = "unknown";
00387     cvog->os = "unknown";
00388     cvog->gnu = "";
00389     while (*p && !(*p == '-' || isspace(*p)))
00390             p++;
00391     if (*p != '\0') *p++ = '\0';
00392 
00393     cvog->vendor = p;
00394     while (*p && !(*p == '-' || isspace(*p)))
00395         p++;
00396     if (*p != '-') {
00397         if (*p != '\0') *p++ = '\0';
00398         cvog->os = cvog->vendor;
00399         cvog->vendor = "unknown";
00400     } else {
00401         if (*p != '\0') *p++ = '\0';
00402 
00403         cvog->os = p;
00404         while (*p && !(*p == '-' || isspace(*p)))
00405             p++;
00406         if (*p == '-') {
00407             *p++ = '\0';
00408 
00409             cvog->gnu = p;
00410             while (*p && !(*p == '-' || isspace(*p)))
00411                 p++;
00412         }
00413         if (*p != '\0') *p++ = '\0';
00414     }
00415 
00416     if (cvogp)
00417         *cvogp = cvog;
00418     else {
00419         cvog->str = _free(cvog->str);
00420         cvog = _free(cvog);
00421     }
00422     return 0;
00423 }
00424 
00430 /*@-onlytrans@*/        /* XXX miRE array, not refcounted. */
00431 static rpmRC rpmPlatform(const char * platform)
00432         /*@globals nplatpat, platpat,
00433                 rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00434         /*@modifies nplatpat, platpat,
00435                 rpmGlobalMacroContext, fileSystem, internalState @*/
00436 {
00437     CVOG_t cvog = NULL;
00438     rpmiob iob = NULL;
00439     int init_platform = 0;
00440     miRE mi_re = NULL;
00441     int mi_nre = 0;
00442     char * p, * pe;
00443     rpmRC rc;
00444     int xx;
00445 
00446     rc = rpmiobSlurp(platform, &iob);
00447 
00448     if (rc || iob == NULL) {
00449         rc = RPMRC_FAIL;
00450         goto exit;
00451     }
00452 
00453     p = (char *)iob->b;
00454     for (pe = p; p && *p; p = pe) {
00455         pe = strchr(p, '\n');
00456         if (pe)
00457             *pe++ = '\0';
00458 
00459         while (*p && xisspace(*p))
00460             p++;
00461         if (*p == '\0' || *p == '#')
00462             continue;
00463 
00464         if (init_platform) {
00465             char * t = p + strlen(p);
00466             while (--t > p && xisspace(*t))
00467                 *t = '\0';
00468             if (t > p) {
00469                 xx = mireAppend(RPMMIRE_REGEX, 0, p, NULL, &mi_re, &mi_nre);
00470             }
00471             continue;
00472         }
00473 
00474         if (!parseCVOG(p, &cvog) && cvog != NULL) {
00475             addMacro(NULL, "_host_cpu", NULL, cvog->cpu, -1);
00476             addMacro(NULL, "_host_vendor", NULL, cvog->vendor, -1);
00477             addMacro(NULL, "_host_os", NULL, cvog->os, -1);
00478         }
00479 
00480 #if defined(RPM_VENDOR_OPENPKG) /* explicit-platform */
00481         /* do not use vendor and GNU attribution */
00482         p = rpmExpand("%{_host_cpu}-%{_host_os}", NULL);
00483 #else
00484         p = rpmExpand("%{_host_cpu}-%{_host_vendor}-%{_host_os}",
00485                 (cvog && *cvog->gnu ? "-" : NULL),
00486                 (cvog ? cvog->gnu : NULL), NULL);
00487 #endif
00488         xx = mireAppend(RPMMIRE_STRCMP, 0, p, NULL, &mi_re, &mi_nre);
00489         p = _free(p);
00490         
00491         init_platform++;
00492     }
00493     rc = (init_platform ? RPMRC_OK : RPMRC_FAIL);
00494 
00495 exit:
00496     if (cvog) {
00497         cvog->str = _free(cvog->str);
00498         cvog = _free(cvog);
00499     }
00500     iob = rpmiobFree(iob);
00501     if (rc == RPMRC_OK) {
00502         platpat = mireFreeAll(platpat, nplatpat);
00503         platpat = mi_re;
00504         nplatpat = mi_nre;
00505     }
00506     return rc;
00507 }
00508 /*@=onlytrans@*/
00509 
00510 #if defined(WITH_CPUINFO) && defined(WITH_SYCK)
00511 static inline int rpmCpuinfoMatch(const char * feature, const char * EVR, rpmds cpuinfo)
00512 {
00513     rpmds cpufeature = rpmdsSingle(RPMTAG_REQUIRENAME, feature, EVR, RPMSENSE_PROBE);
00514     int ret = rpmdsMatch(cpufeature, cpuinfo);
00515 
00516     (void)rpmdsFree(cpufeature);
00517     cpufeature = NULL;
00518     return ret;
00519 }
00520 
00521 static rpmRC rpmCpuinfo(void)
00522 {
00523     rpmRC rc = RPMRC_FAIL;
00524     const char *cpu, *_cpuinfo_path;
00525     miRE mi_re = NULL;
00526     int mi_nre = 0, xx, i;
00527     CVOG_t cvog = NULL;
00528     struct stat st;
00529     char *yaml;
00530     rpmsyck_node *tmp, node;
00531     rpmSyck cpuinfoYaml;
00532     FD_t fd;
00533 
00534     _cpuinfo_path = rpmGetPath("%{?_rpmhome}%{!?_rpmhome:" USRLIBRPM "}/cpuinfo.yaml", NULL);
00535     if(Stat(_cpuinfo_path, &st))
00536         return rc;
00537 
00538     fd = Fopen(_cpuinfo_path, "r");
00539     _cpuinfo_path = _free(_cpuinfo_path);
00540     yaml = xcalloc(st.st_size+1, 1);
00541     Fread(yaml, 1, st.st_size, fd);
00542     Fclose(fd);
00543 
00544     xx = rpmdsCpuinfo(&cpuinfoP, NULL);
00545     cpuinfoYaml = rpmSyckLoad(yaml);
00546     yaml = _free(yaml);
00547     htGetEntry(cpuinfoYaml->firstNode->value.map, "cpuinfo", &tmp, NULL, NULL);
00548     node = tmp[0]->value.seq;
00549 
00550     /* TODO: cleanup.. */
00551     for(i = 0; node[i].type != T_END; i++) {
00552         if(node[i].type == T_MAP) {
00553             rpmsyck_node *tmp;
00554             if(htHasEntry(node[i].value.map, "Family")) {
00555                 htGetEntry(node[i].value.map, "Family", &tmp, NULL, NULL);
00556                 const char *family = tmp[0]->value.key;
00557                 int j;
00558                 hashTable cpus = NULL; 
00559                 if(rpmCpuinfoMatch(family, "", cpuinfoP)) {
00560                     if(htHasEntry(node[i].value.map, "Arch")) {
00561                         htGetEntry(node[i].value.map, "Arch", &tmp, NULL, NULL);
00562                         rpmsyck_node arch = tmp[0]->value.seq;
00563                         for(j = 0; arch[j].type != T_END; j++);
00564                         cpus = htCreate(j*2, 0, 0, NULL, NULL);
00565                         for(j = 0; arch[j].type != T_END; j++) {
00566                             if(htHasEntry(arch[j].value.map, "Extends")) {
00567                                 if(htGetEntry(arch[j].value.map, "Extends", &tmp, NULL, NULL) &&
00568                                         tmp[0]->type == T_STR && !htHasEntry(cpus, tmp[0]->value.key))
00569                                     continue;
00570                             }
00571                             if(htHasEntry(arch[j].value.map, "Features")) {
00572                                 htGetEntry(arch[j].value.map, "Features", &tmp, NULL, NULL);
00573                                 rpmsyck_node features = tmp[0]->value.seq;
00574                                 int k, match = 0;
00575                                 for(k = 0; features[k].type != T_END; k++)
00576                                     if(features[k].type == T_STR && !(match = rpmCpuinfoMatch(features[k].value.key, "", cpuinfoP))) break;
00577                                 if(!match) continue;
00578                             }
00579                             if(htHasEntry(arch[j].value.map, "Name")) {
00580                                 htGetEntry(arch[j].value.map, "Name", &tmp, NULL, NULL);
00581                                 if(tmp[0]->type != T_STR) continue;
00582                                 const char *name = tmp[0]->value.key;
00583                                 rpmsyck_node alias = NULL;
00584                                 if(htHasEntry(arch[j].value.map, "Alias")) {
00585                                     htGetEntry(arch[j].value.map, "Alias", &tmp, NULL, NULL);
00586                                     alias = tmp[0]->value.seq;
00587                                 }
00588                                 htAddEntry(cpus, name, alias);
00589                             }
00590                         }
00591                     }
00592                     if(htHasEntry(node[i].value.map, "Priority")) {
00593                         htGetEntry(node[i].value.map, "Priority", &tmp, NULL, NULL);
00594                         rpmsyck_node priority = tmp[0]->value.seq;
00595                         int j;
00596                         for(j = 0; priority[j].type != T_END; j++)
00597                             if(htHasEntry(cpus, priority[j].value.key)) {
00598                                 xx = mireAppend(RPMMIRE_REGEX, 0, priority[j].value.key, NULL, &mi_re, &mi_nre);
00599                                 htGetEntry(cpus, priority[j].value.key, &tmp, NULL, NULL);
00600                                 if(tmp[0]) {
00601                                     rpmsyck_node alias = tmp[0];
00602                                     int k;
00603                                     for(k = 0; alias[k].type != T_END; k++)
00604                                         xx = mireAppend(RPMMIRE_REGEX, 0, alias[k].value.key, NULL, &mi_re, &mi_nre);
00605                                 }
00606                             }
00607                     }
00608                 }
00609                 if(cpus) cpus = htFree(cpus);
00610             }
00611         }
00612     }
00613 
00614     cpuinfoYaml = rpmSyckFree(cpuinfoYaml);
00615 
00616     xx = mireAppend(RPMMIRE_REGEX, 0, "noarch", NULL, &mi_re, &mi_nre);
00617 
00618     cpu = mi_re[0].pattern;
00619     if(cpu != NULL)
00620     {
00621         if (!parseCVOG(cpu, &cvog) && cvog != NULL) {
00622             addMacro(NULL, "_host_cpu", NULL, cvog->cpu, -1);
00623             addMacro(NULL, "_host_vendor", NULL, cvog->vendor, -1);
00624             addMacro(NULL, "_host_os", NULL, cvog->os, -1);
00625         }
00626         if (cvog) {
00627             cvog->str = _free(cvog->str);
00628             cvog = _free(cvog);
00629         }
00630 
00631         rc = RPMRC_OK;
00632         if (rc == RPMRC_OK) {
00633             platpat = mireFreeAll(platpat, nplatpat);
00634             platpat = mi_re;
00635             nplatpat = mi_nre;
00636         }
00637 
00638     }
00639     return rc;
00640 }
00641 #endif
00642 
00643 /*@-onlytrans@*/        /* XXX miRE array, not refcounted. */
00644 int rpmPlatformScore(const char * platform, void * mi_re, int mi_nre)
00645 {
00646     miRE mire;
00647     int i;
00648 
00649     if (mi_re == NULL) {
00650         mi_re = platpat;
00651         mi_nre = nplatpat;
00652     }
00653 
00654     if ((mire = mi_re) != NULL)
00655     for (i = 0; i < mi_nre; i++) {
00656         if (mireRegexec(mire + i, platform, 0) >= 0)
00657             return (i + 1);
00658     }
00659     return 0;
00660 }
00661 /*@=onlytrans@*/
00662 
00665 static void defaultMachine(/*@out@*/ const char ** arch,
00666                 /*@out@*/ const char ** os)
00667         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00668         /*@modifies *arch, *os, rpmGlobalMacroContext, fileSystem, internalState @*/
00669 {
00670 #if defined(RPM_VENDOR_OPENPKG) /* larger-utsname */
00671     /* utsname fields on some platforms (like HP-UX) are very small
00672        (just about 8 characters). This is too small for OpenPKG, so cheat! */
00673     static struct utsname un_real;
00674     static struct {
00675         char sysname[32];
00676         char nodename[32];
00677         char release[32];
00678         char version[32];
00679         char machine[32];
00680     } un;
00681 #else
00682     static struct utsname un;
00683 #endif
00684     static int gotDefaults = 0;
00685     int rc;
00686 
00687     while (!gotDefaults) {
00688 #if defined(RPM_VENDOR_WINDRIVER)
00689         const char * _platform = rpmGetPath(__etcrpm, "/platform", NULL);
00690 #else
00691         const char * _platform = platform;
00692 #endif
00693         CVOG_t cvog = NULL;
00694 #if defined(RPM_VENDOR_OPENPKG) /* larger-utsname */
00695         const char *cp;
00696 #endif
00697 #if defined(RPM_VENDOR_OPENPKG) /* larger-utsname */
00698         /* utsname fields on some platforms (like HP-UX) are very small
00699            (just about 8 characters). This is too small for OpenPKG, so cheat! */
00700         rc = uname(&un_real);
00701         strncpy(un.sysname,  un_real.sysname,  sizeof(un.sysname));  un.sysname [sizeof(un.sysname) -1] = '\0';
00702         strncpy(un.nodename, un_real.nodename, sizeof(un.nodename)); un.nodename[sizeof(un.nodename)-1] = '\0';
00703         strncpy(un.release,  un_real.release,  sizeof(un.release));  un.release [sizeof(un.release) -1] = '\0';
00704         strncpy(un.version,  un_real.version,  sizeof(un.version));  un.version [sizeof(un.version) -1] = '\0';
00705         strncpy(un.machine,  un_real.machine,  sizeof(un.machine));  un.machine [sizeof(un.machine) -1] = '\0';
00706 #else
00707         rc = uname(&un);
00708 #endif
00709         if (rc < 0) return;
00710 
00711 #if defined(RPM_VENDOR_OPENPKG) /* platform-major-minor-only */
00712     /* Reduce the platform version to major and minor version numbers */
00713     {
00714         char *cp;
00715         char *cpR;
00716         int n;
00717         cpR = un.release;
00718         if ((n = strcspn(cpR, "0123456789")) > 0)
00719             cpR += n;
00720         if ((n = strspn(cpR, "0123456789.")) > 0) {
00721             /* terminate after "N.N.N...." prefix */
00722             cpR[n] = '\0';
00723             /* shorten to "N.N" if longer */
00724             if ((cp = strchr(cpR, '.')) != NULL) {
00725                 if ((cp = strchr(cp+1, '.')) != NULL)
00726                     *cp = '\0';
00727             }
00728             strcat(un.sysname, cpR);
00729         }
00730         /* fix up machine hardware name containing white-space as it
00731            happens to be on Power Macs running MacOS X */
00732         if (!strncmp(un.machine, "Power Macintosh", 15))
00733             sprintf(un.machine, "powerpc");
00734     }
00735 #endif
00736 
00737         if (!strncmp(un.machine, "Power Macintosh", 15)) {
00738             sprintf(un.machine, "ppc");
00739         }
00740 
00741 #if defined(RPM_VENDOR_OPENPKG) /* explicit-platform */
00742         /* allow the path to the "platforms" file be overridden under run-time */
00743         cp = rpmExpand("%{?__platform}", NULL);
00744         if (cp == NULL || cp[0] == '\0')
00745             cp = _platform;
00746         if (rpmPlatform(cp) == RPMRC_OK) {
00747 #elif defined(WITH_CPUINFO) && defined(WITH_SYCK)
00748         if (rpmPlatform(_platform) == RPMRC_OK || rpmCpuinfo() == RPMRC_OK)
00749 #else
00750         if (rpmPlatform(_platform) == RPMRC_OK)
00751 #endif
00752         {
00753             const char * s;
00754             gotDefaults = 1;
00755             s = rpmExpand("%{?_host_cpu}", NULL);
00756             if (s && *s != '\0') {
00757                 strncpy(un.machine, s, sizeof(un.machine));
00758                 un.machine[sizeof(un.machine)-1] = '\0';
00759             }
00760             s = _free(s);
00761             s = rpmExpand("%{?_host_os}", NULL);
00762             if (s && *s != '\0') {
00763                 strncpy(un.sysname, s, sizeof(un.sysname));
00764                 un.sysname[sizeof(un.sysname)-1] = '\0';
00765             }
00766             s = _free(s);
00767         }
00768 
00769 #if defined(RPM_VENDOR_OPENPKG) /* explicit-platform */
00770         /* cleanup after above processing */
00771         if (cp != NULL && cp != _platform)
00772             cp = _free(cp);
00773 #endif
00774 #if defined(RPM_VENDOR_WINDRIVER)
00775         _platform = _free(_platform);
00776 #endif
00777 
00778         if (configTarget && !parseCVOG(configTarget, &cvog) && cvog != NULL) {
00779             gotDefaults = 1;
00780             if (cvog->cpu && cvog->cpu[0] != '\0') {
00781                 strncpy(un.machine, cvog->cpu, sizeof(un.machine));
00782                 un.machine[sizeof(un.machine)-1] = '\0';
00783             }
00784             if (cvog->os && cvog->os[0] != '\0') {
00785                 strncpy(un.sysname, cvog->os, sizeof(un.sysname));
00786                 un.sysname[sizeof(un.sysname)-1] = '\0';
00787             }
00788             cvog->str = _free(cvog->str);
00789             cvog = _free(cvog);
00790         }
00791         if (gotDefaults)
00792             break;
00793         gotDefaults = 1;
00794         break;
00795     }
00796 
00797     if (arch) *arch = un.machine;
00798     if (os) *os = un.sysname;
00799 }
00800 
00808 static void rpmSetTables(int archTable, int osTable)
00809         /*@globals currTables, rpmGlobalMacroContext, h_errno,
00810                 fileSystem, internalState @*/
00811         /*@modifies currTables, rpmGlobalMacroContext,
00812                 fileSystem, internalState @*/
00813 {
00814     const char * arch, * os;
00815 
00816     defaultMachine(&arch, &os);
00817 
00818     if (currTables[ARCH] != archTable) {
00819         currTables[ARCH] = archTable;
00820         rebuildCompatTables(ARCH, arch);
00821     }
00822 
00823     if (currTables[OS] != osTable) {
00824         currTables[OS] = osTable;
00825         rebuildCompatTables(OS, os);
00826     }
00827 }
00828 
00829 static void rpmSetMachine(const char * arch, const char * os)
00830         /*@globals current, rpmGlobalMacroContext, h_errno,
00831                 fileSystem, internalState @*/
00832         /*@modifies current, rpmGlobalMacroContext,
00833                 fileSystem, internalState @*/
00834 {
00835     if (arch == NULL) {
00836 /*@i@*/ defaultMachine(&arch, NULL);
00837         if (tables[currTables[ARCH]].hasTranslate)
00838             arch = lookupInDefaultTable(arch,
00839                             tables[currTables[ARCH]].defaults,
00840                             tables[currTables[ARCH]].defaultsLength);
00841     }
00842 assert(arch != NULL);
00843 
00844     if (os == NULL) {
00845 /*@i@*/ defaultMachine(NULL, &os);
00846         if (tables[currTables[OS]].hasTranslate)
00847             os = lookupInDefaultTable(os,
00848                             tables[currTables[OS]].defaults,
00849                             tables[currTables[OS]].defaultsLength);
00850     }
00851 assert(os != NULL);
00852 
00853 
00854     if (!current[ARCH] || strcmp(arch, current[ARCH])) {
00855         current[ARCH] = _free(current[ARCH]);
00856         current[ARCH] = xstrdup(arch);
00857         rebuildCompatTables(ARCH, arch);
00858     }
00859 
00860     if (!current[OS] || strcmp(os, current[OS])) {
00861         char * t = xstrdup(os);
00862         current[OS] = _free(current[OS]);
00863         if (!strcmp(t, "linux"))
00864             *t = 'L';
00865         current[OS] = t;
00866         rebuildCompatTables(OS, os);
00867     }
00868 }
00869 
00870 static void getMachineInfo(int type, /*@null@*/ /*@out@*/ const char ** name,
00871                         /*@null@*/ /*@out@*/int * num)
00872         /*@modifies *name, *num @*/
00873 {
00874     canonEntry canon;
00875     int which = currTables[type];
00876 
00877     /* use the normal canon tables, even if we're looking up build stuff */
00878     if (which >= 2) which -= 2;
00879 
00880     canon = lookupInCanonTable(current[type],
00881                                tables[which].canons,
00882                                tables[which].canonsLength);
00883 
00884     if (canon) {
00885         if (num) *num = canon->num;
00886         if (name) *name = canon->short_name;
00887     } else {
00888         if (num) *num = 255;
00889 #if defined(WITH_CPUINFO)
00890         if (name) {
00891             if(type == ARCH) {
00892                 int i, j, n;
00893                 ARGV_t archs = NULL;
00894                 char *pref = rpmExpand("%{?_prefer_target_cpu}", NULL);
00895 
00896                 (void) argvSplit(&archs, pref, " ");
00897                 for(i = 0, n = argvCount(archs); (i < n && !*name); i++)
00898                     if((j = rpmPlatformScore(archs[i], platpat, nplatpat)) > 0)
00899                         *name = ((miRE)platpat)[j-1].pattern;
00900 
00901                 archs = argvFree(archs);
00902                 pref = _free(pref);
00903             }
00904             if(!*name) *name = current[type];
00905         }
00906 #else
00907         if (name) *name = current[type];
00908 #endif
00909     }
00910 }
00911 
00912 static void rpmRebuildTargetVars(const char ** target, const char ** canontarget)
00913 {
00914 
00915     char *ca = NULL, *co = NULL, *ct = NULL;
00916     int x;
00917 
00918     /* Rebuild the compat table to recalculate the current target arch.  */
00919 
00920     rpmSetMachine(NULL, NULL);
00921     rpmSetTables(RPM_MACHTABLE_INSTARCH, RPM_MACHTABLE_INSTOS);
00922     rpmSetTables(RPM_MACHTABLE_BUILDARCH, RPM_MACHTABLE_BUILDOS);
00923 
00924     if (target && *target) {
00925         char *c;
00926         /* Set arch and os from specified build target */
00927         ca = xstrdup(*target);
00928         if ((c = strchr(ca, '-')) != NULL) {
00929             *c++ = '\0';
00930             
00931             if ((co = strrchr(c, '-')) == NULL) {
00932                 co = c;
00933             } else {
00934                 if (!xstrcasecmp(co, "-gnu"))
00935                     *co = '\0';
00936                 if ((co = strrchr(c, '-')) == NULL)
00937                     co = c;
00938                 else
00939                     co++;
00940             }
00941             if (co != NULL) co = xstrdup(co);
00942         }
00943     } else {
00944         const char *a = NULL;
00945         const char *o = NULL;
00946         /* Set build target from rpm arch and os */
00947         getMachineInfo(ARCH, &a, NULL);
00948         ca = (a) ? xstrdup(a) : NULL;
00949         getMachineInfo(OS, &o, NULL);
00950         co = (o) ? xstrdup(o) : NULL;
00951     }
00952 
00953     /* If still not set, Set target arch/os from default uname(2) values */
00954     if (ca == NULL) {
00955         const char *a = NULL;
00956         defaultMachine(&a, NULL);
00957         ca = (a) ? xstrdup(a) : NULL;
00958     }
00959     if (ca != NULL)
00960     for (x = 0; ca[x] != '\0'; x++)
00961         ca[x] = (char)xtolower(ca[x]);
00962 
00963     if (co == NULL) {
00964         const char *o = NULL;
00965         defaultMachine(NULL, &o);
00966         co = (o) ? xstrdup(o) : NULL;
00967     }
00968     if (co != NULL)
00969     for (x = 0; co[x] != '\0'; x++)
00970         co[x] = (char)xtolower(co[x]);
00971 
00972     /* XXX For now, set canonical target to arch-os */
00973     if (ct == NULL) {
00974         ct = xmalloc(strlen(ca) + sizeof("-") + strlen(co));
00975         sprintf(ct, "%s-%s", ca, co);
00976     }
00977 
00978 /*
00979  * XXX All this macro pokery/jiggery could be achieved by doing a delayed
00980  *      rpmInitMacros(NULL, PER-PLATFORM-MACRO-FILE-NAMES);
00981  */
00982     delMacro(NULL, "_target");
00983     addMacro(NULL, "_target", NULL, ct, RMIL_RPMRC);
00984     delMacro(NULL, "_target_cpu");
00985     addMacro(NULL, "_target_cpu", NULL, ca, RMIL_RPMRC);
00986     delMacro(NULL, "_target_os");
00987     addMacro(NULL, "_target_os", NULL, co, RMIL_RPMRC);
00988 
00989     if (canontarget)
00990         *canontarget = ct;
00991     else
00992         ct = _free(ct);
00993     ca = _free(ca);
00994     /*@-usereleased@*/
00995     co = _free(co);
00996     /*@=usereleased@*/
00997 }
00998 
00999 void rpmFreeRpmrc(void)
01000         /*@globals current, tables, defaultsInitialized @*/
01001         /*@modifies current, tables, defaultsInitialized @*/
01002 {
01003     int i, j, k;
01004 
01005     (void)mireFreeAll(platpat, nplatpat);
01006     platpat = NULL;
01007     nplatpat = 0;
01008 
01009     for (i = 0; i < RPM_MACHTABLE_COUNT; i++) {
01010         tableType t;
01011         t = tables + i;
01012         if (t->equiv.list) {
01013             for (j = 0; j < t->equiv.count; j++)
01014                 t->equiv.list[j].name = _free(t->equiv.list[j].name);
01015             t->equiv.list = _free(t->equiv.list);
01016             t->equiv.count = 0;
01017         }
01018         if (t->cache.cache) {
01019             for (j = 0; j < t->cache.size; j++) {
01020                 machCacheEntry e;
01021                 e = t->cache.cache + j;
01022                 if (e == NULL)
01023                     /*@innercontinue@*/ continue;
01024                 e->name = _free(e->name);
01025                 if (e->equivs) {
01026                     for (k = 0; k < e->count; k++)
01027                         e->equivs[k] = _free(e->equivs[k]);
01028                     e->equivs = _free(e->equivs);
01029                 }
01030             }
01031             t->cache.cache = _free(t->cache.cache);
01032             t->cache.size = 0;
01033         }
01034         if (t->defaults) {
01035             for (j = 0; j < t->defaultsLength; j++) {
01036                 t->defaults[j].name = _free(t->defaults[j].name);
01037                 t->defaults[j].defName = _free(t->defaults[j].defName);
01038             }
01039             t->defaults = _free(t->defaults);
01040             t->defaultsLength = 0;
01041         }
01042         if (t->canons) {
01043             for (j = 0; j < t->canonsLength; j++) {
01044                 t->canons[j].name = _free(t->canons[j].name);
01045                 t->canons[j].short_name = _free(t->canons[j].short_name);
01046             }
01047             t->canons = _free(t->canons);
01048             t->canonsLength = 0;
01049         }
01050     }
01051 
01052     current[OS] = _free(current[OS]);
01053     current[ARCH] = _free(current[ARCH]);
01054     defaultsInitialized = 0;
01055 /*@-globstate -nullstate@*/ /* FIX: platpat/current may be NULL */
01056     return;
01057 /*@=globstate =nullstate@*/
01058 }
01059 
01064 static int rpmReadRC(const char *macrofiles)
01065         /*@globals defaultsInitialized,
01066                 rpmGlobalMacroContext, rpmCLIMacroContext, h_errno,
01067                 fileSystem, internalState @*/
01068         /*@modifies defaultsInitialized, rpmGlobalMacroContext,
01069                 fileSystem, internalState @*/
01070 {
01071     int rc = 0;
01072 
01073     if (!defaultsInitialized) {
01074         setDefaults();
01075         defaultsInitialized = 1;
01076     }
01077 
01078     /* Read macro files. */
01079     {   const char *mfpath = rpmExpand(macrofiles, NULL);
01080             
01081         if (mfpath != NULL) {
01082             rpmInitMacros(NULL, mfpath);
01083             mfpath = _free(mfpath);
01084         }
01085     }
01086 
01087     return rc;
01088 }
01089 
01090 int rpmReadConfigFiles(/*@unused@*/ const char * file,
01091                 const char * target)
01092         /*@globals configTarget, rpmMacrofiles @*/
01093         /*@modifies configTarget @*/
01094 {
01095     mode_t mode = 0022;
01096 
01097 #ifdef PREMACROFILES
01098     if (rpmReadRC(PREMACROFILES)) return -1;
01099 #endif
01100 
01101     /* Reset umask to its default umask(2) value. */
01102     mode = umask(mode);
01103 
01104     configTarget = target;
01105 
01106     /* Preset target macros */
01107     /*@-nullstate@*/    /* FIX: target can be NULL */
01108     rpmRebuildTargetVars(&target, NULL);
01109 
01110     /* Read the files */
01111 /*@-globs@*/
01112     if (rpmReadRC(rpmMacrofiles)) return -1;
01113 /*@=globs@*/
01114 
01115     /* Reset target macros */
01116     rpmRebuildTargetVars(&target, NULL);
01117     /*@=nullstate@*/
01118 
01119     /* Finally set target platform */
01120     {   const char *cpu = rpmExpand("%{_target_cpu}", NULL);
01121         const char *os = rpmExpand("%{_target_os}", NULL);
01122         rpmSetMachine(cpu, os);
01123 
01124         cpu = _free(cpu);
01125         os = _free(os);
01126     }
01127     configTarget = NULL;
01128 
01129     /* Force Lua state initialization */
01130 #ifdef WITH_LUA
01131     (void)rpmluaGetPrintBuffer(NULL);
01132 #if defined(RPM_VENDOR_OPENPKG) /* rpm-lua-extensions-based-on-rpm-lib-functionality */
01133     (void)rpmluaextActivate(rpmluaGetGlobalState());
01134 #endif /* RPM_VENDOR_OPENPKG */
01135 #endif
01136 
01137     return 0;
01138 }
01139 
01140 int rpmShowRC(FILE * fp)
01141 {
01142     rpmds ds = NULL;
01143     int i;
01144     machEquivTable equivTable;
01145     int xx;
01146     miRE mire;
01147 
01148     /* the caller may set the build arch which should be printed here */
01149     fprintf(fp, "ARCHITECTURE AND OS:\n");
01150     fprintf(fp, "build arch            : %s\n", current[ARCH]);
01151 
01152     fprintf(fp, "compatible build archs:");
01153     equivTable = &tables[RPM_MACHTABLE_BUILDARCH].equiv;
01154     for (i = 0; i < equivTable->count; i++)
01155         fprintf(fp," %s", equivTable->list[i].name);
01156     fprintf(fp, "\n");
01157 
01158     fprintf(fp, "build os              : %s\n", current[OS]);
01159 
01160     fprintf(fp, "compatible build os's :");
01161     equivTable = &tables[RPM_MACHTABLE_BUILDOS].equiv;
01162     for (i = 0; i < equivTable->count; i++)
01163         fprintf(fp," %s", equivTable->list[i].name);
01164     fprintf(fp, "\n");
01165 
01166     fprintf(fp, "install arch          : %s\n", current[ARCH]);
01167     fprintf(fp, "install os            : %s\n", current[OS]);
01168 
01169     fprintf(fp, "compatible archs      :");
01170     for (mire = platpat, i = 0; i < nplatpat; i++)
01171         fprintf(fp, " %s", mire[i].pattern);
01172     fprintf(fp, "\n");
01173 
01174     fprintf(fp, "compatible os's       :");
01175     equivTable = &tables[RPM_MACHTABLE_INSTOS].equiv;
01176     for (i = 0; i < equivTable->count; i++)
01177         fprintf(fp," %s", equivTable->list[i].name);
01178     fprintf(fp, "\n");
01179 
01180     {   const char * s = rpmExpand("%{?optflags}", NULL);
01181         fprintf(fp, "%-21s : %s\n", "optflags", ((s && *s) ? s : "(not set)"));
01182         s = _free(s);
01183 
01184 #ifdef  WITH_LUA
01185         fprintf(fp, "\nLUA MODULES:\n");
01186 /*@-globs@*/
01187         s = rpmExpand(rpmluaFiles, NULL);
01188 /*@=globs@*/
01189         fprintf(fp, "%-21s : %s\n", "luafiles", ((s && *s) ? s : "(not set)"));
01190         s = _free(s);
01191 /*@-globs@*/
01192         s = rpmExpand(rpmluaPath, NULL);
01193 /*@=globs@*/
01194         fprintf(fp, "%-21s : %s\n", "luapath", ((s && *s) ? s : "(not set)"));
01195         s = _free(s);
01196 #endif
01197 
01198         fprintf(fp, "\nMACRO DEFINITIONS:\n");
01199 /*@-globs@*/
01200         s = rpmExpand(rpmMacrofiles, NULL);
01201 /*@=globs@*/
01202         fprintf(fp, "%-21s : %s\n", "macrofiles", ((s && *s) ? s : "(not set)"));
01203         s = _free(s);
01204     }
01205 
01206     if (rpmIsVerbose()) {
01207         rpmPRCO PRCO = rpmdsNewPRCO(NULL);
01208         xx = rpmdsSysinfo(PRCO, NULL);
01209         ds = rpmdsFromPRCO(PRCO, RPMTAG_PROVIDENAME);
01210         if (ds != NULL) {
01211             const char * fn = (_sysinfo_path ? _sysinfo_path : "/etc/rpm/sysinfo");
01212             fprintf(fp, _("Configured system provides (from %s):\n"), fn);
01213             ds = rpmdsInit(ds);
01214             while (rpmdsNext(ds) >= 0) {
01215                 const char * DNEVR = rpmdsDNEVR(ds);
01216                 if (DNEVR != NULL)
01217                     fprintf(fp, "    %s\n", DNEVR+2);
01218             }
01219             (void)rpmdsFree(ds);
01220             ds = NULL;
01221             fprintf(fp, "\n");
01222         }
01223         PRCO = rpmdsFreePRCO(PRCO);
01224     }
01225 
01226     if (rpmIsVerbose()) {
01227         fprintf(fp, _("Features provided by rpmlib installer:\n"));
01228         xx = rpmdsRpmlib(&ds, NULL);
01229         ds = rpmdsInit(ds);
01230         while (rpmdsNext(ds) >= 0) {
01231             const char * DNEVR = rpmdsDNEVR(ds);
01232             if (DNEVR != NULL)
01233                 fprintf(fp, "    %s\n", DNEVR+2);
01234         }
01235         (void)rpmdsFree(ds);
01236         ds = NULL;
01237         fprintf(fp, "\n");
01238 
01239         if(cpuinfoP == NULL)
01240             xx = rpmdsCpuinfo(&cpuinfoP, NULL);
01241         if (cpuinfoP != NULL) {
01242 #if defined(WITH_CPUINFO)
01243             const char * fn = "libcpuinfo";
01244 #else
01245             const char * fn = (_cpuinfo_path ? _cpuinfo_path : "/proc/cpuinfo");
01246 #endif
01247             fprintf(fp,
01248                 _("Features provided by current cpuinfo (from %s):\n"), fn);
01249 /*@-mods@*/
01250             cpuinfoP = rpmdsInit(cpuinfoP);
01251             while (rpmdsNext(cpuinfoP) >= 0) {
01252                 const char * DNEVR = rpmdsDNEVR(cpuinfoP);
01253                 if (DNEVR != NULL)
01254                     fprintf(fp, "    %s\n", DNEVR+2);
01255             }
01256             (void)rpmdsFree(cpuinfoP);
01257             cpuinfoP = NULL;
01258 /*@=mods@*/
01259 
01260             fprintf(fp, "\n");
01261         }
01262     }
01263 
01264     if (rpmIsDebug()) {
01265         xx = rpmdsGetconf(&ds, NULL);
01266         if (ds != NULL) {
01267             fprintf(fp,
01268                 _("Features provided by current getconf:\n"));
01269             ds = rpmdsInit(ds);
01270             while (rpmdsNext(ds) >= 0) {
01271                 const char * DNEVR = rpmdsDNEVR(ds);
01272                 if (DNEVR != NULL)
01273                     fprintf(fp, "    %s\n", DNEVR+2);
01274             }
01275             (void)rpmdsFree(ds);
01276             ds = NULL;
01277             fprintf(fp, "\n");
01278         }
01279 
01280         xx = rpmdsUname(&ds, NULL);
01281         if (ds != NULL) {
01282             fprintf(fp,
01283                 _("Features provided by current uname:\n"));
01284             ds = rpmdsInit(ds);
01285             while (rpmdsNext(ds) >= 0) {
01286                 const char * DNEVR = rpmdsDNEVR(ds);
01287                 if (DNEVR != NULL)
01288                     fprintf(fp, "    %s\n", DNEVR+2);
01289             }
01290             (void)rpmdsFree(ds);
01291             ds = NULL;
01292             fprintf(fp, "\n");
01293         }
01294     }
01295 
01296     rpmDumpMacroTable(NULL, fp);
01297 
01298     return 0;
01299 }