home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 February / CHIP_2_98.iso / misc / src / rpm / lib / rpmrc.c < prev    next >
C/C++ Source or Header  |  1997-09-17  |  25KB  |  983 lines

  1. #include "config.h"
  2. #include "miscfn.h"
  3.  
  4. #if HAVE_ALLOCA_H
  5. # include <alloca.h>
  6. #endif
  7.  
  8. #include <ctype.h>
  9. #include <errno.h>
  10. #include <fcntl.h>
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <sys/resource.h>
  15. #include <sys/stat.h>
  16. #include <sys/utsname.h>
  17. #include <unistd.h>
  18.  
  19. #include "messages.h"
  20. #include "misc.h"
  21. #include "rpmlib.h"
  22.  
  23. #if HAVE_SYS_SYSTEMCFG_H
  24. #include <sys/systemcfg.h>
  25. #else
  26. #define __power_pc() 0
  27. #endif
  28.  
  29. struct machCacheEntry {
  30.     char * name;
  31.     int count;
  32.     char ** equivs;
  33.     int visited;
  34. };
  35.  
  36. struct machCache {
  37.     struct machCacheEntry * cache;
  38.     int size;
  39. };
  40.  
  41. struct machEquivInfo {
  42.     char * name;
  43.     int score;
  44. };
  45.  
  46. struct machEquivTable {
  47.     int count;
  48.     struct machEquivInfo * list;
  49. };
  50.  
  51. struct rpmvarValue {
  52.     char * value;
  53.     /* eventually, this arch will be replaced with a generic condition */
  54.     char * arch;        
  55.     struct rpmvarValue * next;
  56. };
  57.  
  58. struct rpmOption {
  59.     char * name;
  60.     int var;
  61.     int archSpecific, required;
  62.     struct rpmOptionValue * value;
  63. };
  64.  
  65. struct defaultEntry {
  66.     char *name;
  67.     char *defName;
  68. };
  69.  
  70. struct canonEntry {
  71.     char *name;
  72.     char *short_name;
  73.     short num;
  74. };
  75.  
  76. /* tags are 'key'canon, 'key'translate, 'key'compat 
  77.  
  78.    for giggles, 'key'_canon, 'key'_compat, and 'key'_canon will also work */
  79. struct tableType {
  80.     char * key;
  81.     int hasCanon, hasTranslate;
  82.     struct machEquivTable equiv;
  83.     struct machCache cache;
  84.     struct defaultEntry * defaults;
  85.     struct canonEntry * canons;
  86.     int defaultsLength;
  87.     int canonsLength;
  88. };
  89.  
  90. static struct tableType tables[RPM_MACHTABLE_COUNT] = {
  91.     { "arch", 1, 0 },
  92.     { "os", 1, 0 },
  93.     { "buildarch", 0, 1 },
  94.     { "buildos", 0, 1 }
  95. };
  96.  
  97. /* this *must* be kept in alphabetical order */
  98. static struct rpmOption optionTable[] = {
  99.     { "builddir",        RPMVAR_BUILDDIR,        0, 0 },
  100.     { "buildroot",              RPMVAR_BUILDROOT,               0, 0 },
  101.     { "dbpath",            RPMVAR_DBPATH,            0, 1 },
  102.     { "defaultdocdir",        RPMVAR_DEFAULTDOCDIR,        0, 0 },
  103.     { "distribution",        RPMVAR_DISTRIBUTION,        0, 0 },
  104.     { "excludedocs",            RPMVAR_EXCLUDEDOCS,             0, 0 },
  105.     { "fixperms",        RPMVAR_FIXPERMS,        0, 1 },
  106.     { "ftpport",        RPMVAR_FTPPORT,            0, 0 },
  107.     { "ftpproxy",        RPMVAR_FTPPROXY,        0, 0 },
  108.     { "gzipbin",        RPMVAR_GZIPBIN,            0, 1 },
  109.     { "messagelevel",        RPMVAR_MESSAGELEVEL,        0, 0 },
  110.     { "netsharedpath",        RPMVAR_NETSHAREDPATH,        0, 0 },
  111.     { "optflags",        RPMVAR_OPTFLAGS,        1, 0 },
  112.     { "packager",               RPMVAR_PACKAGER,                0, 0 },
  113.     { "pgp_name",               RPMVAR_PGP_NAME,                0, 0 },
  114.     { "pgp_path",               RPMVAR_PGP_PATH,                0, 0 },
  115.     { "provides",               RPMVAR_PROVIDES,                0, 0 },
  116.     { "require_distribution",    RPMVAR_REQUIREDISTRIBUTION,    0, 0 },
  117.     { "require_icon",        RPMVAR_REQUIREICON,        0, 0 },
  118.     { "require_vendor",        RPMVAR_REQUIREVENDOR,        0, 0 },
  119.     { "root",            RPMVAR_ROOT,            0, 0 },
  120.     { "rpmdir",            RPMVAR_RPMDIR,            0, 0 },
  121.     { "rpmfilename",        RPMVAR_RPMFILENAME,        0, 1 },
  122.     { "signature",        RPMVAR_SIGTYPE,            0, 0 },
  123.     { "sourcedir",        RPMVAR_SOURCEDIR,        0, 0 },
  124.     { "specdir",        RPMVAR_SPECDIR,            0, 0 },
  125.     { "srcrpmdir",        RPMVAR_SRPMDIR,            0, 0 },
  126.     { "timecheck",        RPMVAR_TIMECHECK,        0, 0 },
  127.     { "tmppath",        RPMVAR_TMPPATH,            0, 1 },
  128.     { "topdir",            RPMVAR_TOPDIR,            0, 0 },
  129.     { "vendor",            RPMVAR_VENDOR,            0, 0 },
  130. };
  131. static int optionTableSize = sizeof(optionTable) / sizeof(*optionTable);
  132.  
  133. #define OS    0
  134. #define ARCH    1
  135.  
  136. static char * current[2];
  137. static int currTables[2] = { RPM_MACHTABLE_INSTOS, RPM_MACHTABLE_INSTARCH };
  138. static struct rpmvarValue values[RPMVAR_NUM];
  139.  
  140. /* prototypes */
  141. static void defaultMachine(char ** arch, char ** os);
  142. static int doReadRC(int fd, char * filename);
  143. static int optionCompare(const void * a, const void * b);
  144. static int addCanon(struct canonEntry **table, int *tableLen, char *line,
  145.            char *fn, int lineNum);
  146. static int addDefault(struct defaultEntry **table, int *tableLen, char *line,
  147.               char *fn, int lineNum);
  148. static void freeRpmVar(struct rpmvarValue * orig);
  149. static void rpmSetVarArch(int var, char * val, char * arch);
  150. static struct canonEntry *lookupInCanonTable(char *name,
  151.                        struct canonEntry *table,
  152.                        int tableLen);
  153. static char *lookupInDefaultTable(char *name,
  154.                   struct defaultEntry *table,
  155.                   int tableLen);
  156. static void setDefaults(void);
  157. static void setPathDefault(int var, char * s);
  158. static void rebuildCompatTables(int type, char * name);
  159.  
  160. /* compatiblity tables */
  161. static int machCompatCacheAdd(char * name, char * fn, int linenum,
  162.                 struct machCache * cache);
  163. static struct machCacheEntry * machCacheFindEntry(struct machCache * cache, 
  164.                           char * key);
  165. static struct machEquivInfo * machEquivSearch(
  166.         struct machEquivTable * table, char * name);
  167. static void machAddEquiv(struct machEquivTable * table, char * name,
  168.                int distance);
  169. static void machCacheEntryVisit(struct machCache * cache, 
  170.                   struct machEquivTable * table, 
  171.                   char * name,
  172.                     int distance);
  173. static void machFindEquivs(struct machCache * cache, 
  174.                  struct machEquivTable * table,
  175.                  char * key);
  176.  
  177.  
  178. static int optionCompare(const void * a, const void * b) {
  179.     return strcasecmp(((struct rpmOption *) a)->name,
  180.               ((struct rpmOption *) b)->name);
  181. }
  182.  
  183. static struct machCacheEntry * machCacheFindEntry(struct machCache * cache, 
  184.                           char * key) {
  185.     int i;
  186.  
  187.     for (i = 0; i < cache->size; i++)
  188.     if (!strcmp(cache->cache[i].name, key)) return cache->cache + i;
  189.  
  190.     return NULL;
  191. }
  192.  
  193. static int machCompatCacheAdd(char * name, char * fn, int linenum,
  194.                 struct machCache * cache) {
  195.     char * chptr, * equivs;
  196.     int delEntry = 0;
  197.     int i;
  198.     struct machCacheEntry * entry = NULL;
  199.  
  200.     while (*name && isspace(*name)) name++;
  201.   
  202.     chptr = name;
  203.     while (*chptr && *chptr != ':') chptr++;
  204.     if (!*chptr) {
  205.     rpmError(RPMERR_RPMRC, "missing second ':' at %s:%d", fn, linenum);
  206.     return 1;
  207.     } else if (chptr == name) {
  208.     rpmError(RPMERR_RPMRC, "missing architecture name at %s:%d", fn, 
  209.                  linenum);
  210.     return 1;
  211.     }
  212.  
  213.     while (*chptr == ':' || isspace(*chptr)) chptr--;
  214.     *(++chptr) = '\0';
  215.     equivs = chptr + 1;
  216.     while (*equivs && isspace(*equivs)) equivs++;
  217.     if (!*equivs) {
  218.     delEntry = 1;
  219.     }
  220.  
  221.     if (cache->size) {
  222.     entry = machCacheFindEntry(cache, name);
  223.     if (entry) {
  224.         for (i = 0; i < entry->count; i++)
  225.         free(entry->equivs[i]);
  226.         if (entry->count) free(entry->equivs);
  227.         entry->count = 0;
  228.     }
  229.     }
  230.  
  231.     if (!entry) {
  232.     cache->cache = realloc(cache->cache, 
  233.                    (cache->size + 1) * sizeof(*cache->cache));
  234.     entry = cache->cache + cache->size++;
  235.     entry->name = strdup(name);
  236.     entry->count = 0;
  237.     entry->visited = 0;
  238.     }
  239.  
  240.     if (delEntry) return 0;
  241.     
  242.     chptr = strtok(equivs, " ");
  243.     while (chptr) {
  244.     if (strlen(chptr)) {        /* does strtok() return "" ever?? */
  245.         if (entry->count)
  246.         entry->equivs = realloc(entry->equivs, sizeof(*entry->equivs) 
  247.                     * (entry->count + 1));
  248.         else
  249.         entry->equivs = malloc(sizeof(*entry->equivs));
  250.  
  251.         entry->equivs[entry->count] = strdup(chptr);
  252.         entry->count++;
  253.     }
  254.  
  255.     chptr = strtok(NULL, " ");
  256.     }
  257.  
  258.     return 0;
  259. }
  260.  
  261. static struct machEquivInfo * machEquivSearch(
  262.         struct machEquivTable * table, char * name) {
  263.     int i;
  264.  
  265.     for (i = 0; i < table->count; i++)
  266.     if (!strcmp(table->list[i].name, name)) 
  267.         return table->list + i;
  268.  
  269.     return NULL;
  270. }
  271.  
  272. static void machAddEquiv(struct machEquivTable * table, char * name,
  273.                int distance) {
  274.     struct machEquivInfo * equiv;
  275.  
  276.     equiv = machEquivSearch(table, name);
  277.     if (!equiv) {
  278.     if (table->count)
  279.         table->list = realloc(table->list, (table->count + 1)
  280.                     * sizeof(*table->list));
  281.     else
  282.         table->list = malloc(sizeof(*table->list));
  283.     
  284.     table->list[table->count].name = strdup(name);
  285.     table->list[table->count++].score = distance;
  286.     }
  287. }
  288.  
  289. static void machCacheEntryVisit(struct machCache * cache, 
  290.                   struct machEquivTable * table, 
  291.                   char * name,
  292.                     int distance) {
  293.     struct machCacheEntry * entry;
  294.     int i;
  295.  
  296.     entry = machCacheFindEntry(cache, name);
  297.     if (!entry || entry->visited) return;
  298.  
  299.     entry->visited = 1;
  300.  
  301.     for (i = 0; i < entry->count; i++) {
  302.     machAddEquiv(table, entry->equivs[i], distance);
  303.     }
  304.  
  305.     for (i = 0; i < entry->count; i++) {
  306.     machCacheEntryVisit(cache, table, entry->equivs[i], distance + 1);
  307.     }
  308. };
  309.  
  310. static void machFindEquivs(struct machCache * cache, 
  311.                  struct machEquivTable * table,
  312.                  char * key) {
  313.     int i;
  314.  
  315.     for (i = 0; i < cache->size; i++)
  316.     cache->cache[i].visited = 0;
  317.  
  318.     table->count = 0;
  319.  
  320.     /* We have a general graph built using strings instead of pointers.
  321.        Yuck. We have to start at a point at traverse it, remembering how
  322.        far away everything is. */
  323.     machAddEquiv(table, key, 1);
  324.     machCacheEntryVisit(cache, table, key, 2);
  325. }
  326.  
  327. static int addCanon(struct canonEntry **table, int *tableLen, char *line,
  328.             char *fn, int lineNum) {
  329.     struct canonEntry *t;
  330.     char *s, *s1;
  331.     
  332.     if (! *tableLen) {
  333.     *tableLen = 2;
  334.     *table = malloc(2 * sizeof(struct canonEntry));
  335.     } else {
  336.     (*tableLen) += 2;
  337.     *table = realloc(*table, sizeof(struct canonEntry) * (*tableLen));
  338.     }
  339.     t = & ((*table)[*tableLen - 2]);
  340.  
  341.     t->name = strtok(line, ": \t");
  342.     t->short_name = strtok(NULL, " \t");
  343.     s = strtok(NULL, " \t");
  344.     if (! (t->name && t->short_name && s)) {
  345.     rpmError(RPMERR_RPMRC, "Incomplete data line at %s:%d", fn, lineNum);
  346.     return RPMERR_RPMRC;
  347.     }
  348.     if (strtok(NULL, " \t")) {
  349.     rpmError(RPMERR_RPMRC, "Too many args in data line at %s:%d",
  350.           fn, lineNum);
  351.     return RPMERR_RPMRC;
  352.     }
  353.  
  354.     t->num = strtoul(s, &s1, 10);
  355.     if ((*s1) || (s1 == s) || (t->num == ULONG_MAX)) {
  356.     rpmError(RPMERR_RPMRC, "Bad arch/os number: %s (%s:%d)", s,
  357.           fn, lineNum);
  358.     return(RPMERR_RPMRC);
  359.     }
  360.  
  361.     t->name = strdup(t->name);
  362.     t->short_name = strdup(t->short_name);
  363.  
  364.     /* From A B C entry */
  365.     /* Add  B B C entry */
  366.     t[1].name = strdup(t->short_name);
  367.     t[1].short_name = strdup(t->short_name);
  368.     t[1].num = t->num;
  369.  
  370.     return 0;
  371. }
  372.  
  373. static int addDefault(struct defaultEntry **table, int *tableLen, char *line,
  374.               char *fn, int lineNum) {
  375.     struct defaultEntry *t;
  376.     
  377.     if (! *tableLen) {
  378.     *tableLen = 1;
  379.     *table = malloc(sizeof(struct defaultEntry));
  380.     } else {
  381.     (*tableLen)++;
  382.     *table = realloc(*table, sizeof(struct defaultEntry) * (*tableLen));
  383.     }
  384.     t = & ((*table)[*tableLen - 1]);
  385.  
  386.     t->name = strtok(line, ": \t");
  387.     t->defName = strtok(NULL, " \t");
  388.     if (! (t->name && t->defName)) {
  389.     rpmError(RPMERR_RPMRC, "Incomplete default line at %s:%d", fn, lineNum);
  390.     return RPMERR_RPMRC;
  391.     }
  392.     if (strtok(NULL, " \t")) {
  393.     rpmError(RPMERR_RPMRC, "Too many args in default line at %s:%d",
  394.           fn, lineNum);
  395.     return RPMERR_RPMRC;
  396.     }
  397.  
  398.     t->name = strdup(t->name);
  399.     t->defName = strdup(t->defName);
  400.  
  401.     return 0;
  402. }
  403.  
  404. static struct canonEntry *lookupInCanonTable(char *name,
  405.                          struct canonEntry *table,
  406.                          int tableLen) {
  407.     while (tableLen) {
  408.     tableLen--;
  409.     if (!strcmp(name, table[tableLen].name)) {
  410.         return &(table[tableLen]);
  411.     }
  412.     }
  413.  
  414.     return NULL;
  415. }
  416.  
  417. static char *lookupInDefaultTable(char *name, struct defaultEntry *table,
  418.                   int tableLen) {
  419.     while (tableLen) {
  420.     tableLen--;
  421.     if (!strcmp(name, table[tableLen].name)) {
  422.         return table[tableLen].defName;
  423.     }
  424.     }
  425.  
  426.     return name;
  427. }
  428.  
  429. int rpmReadConfigFiles(char * file, char * arch, char * os, int building) {
  430.     if (rpmReadRC(file)) return -1;
  431.  
  432.     if (building)
  433.     rpmSetTables(RPM_MACHTABLE_BUILDARCH, RPM_MACHTABLE_BUILDOS);
  434.  
  435.     rpmSetMachine(arch, os);
  436.  
  437.     return 0;
  438. }
  439.  
  440. static void setPathDefault(int var, char * s) {
  441.     char * topdir;
  442.     char * fn;
  443.  
  444.     if (rpmGetVar(var)) return;
  445.  
  446.     topdir = rpmGetVar(RPMVAR_TOPDIR);
  447.     if (!topdir) topdir = rpmGetVar(RPMVAR_TMPPATH);
  448.     
  449.     fn = alloca(strlen(topdir) + strlen(s) + 2);
  450.     strcpy(fn, topdir);
  451.     if (fn[strlen(topdir) - 1] != '/')
  452.     strcat(fn, "/");
  453.     strcat(fn, s);
  454.    
  455.     rpmSetVar(var, fn);
  456. }
  457.  
  458. static void setDefaults(void) {
  459.     rpmSetVar(RPMVAR_OPTFLAGS, "-O2");
  460.     rpmSetVar(RPMVAR_SIGTYPE, "none");
  461.     rpmSetVar(RPMVAR_DEFAULTDOCDIR, "/usr/doc");
  462.     rpmSetVar(RPMVAR_TOPDIR, "/usr/src/redhat");
  463. }
  464.  
  465. int rpmReadRC(char * file) {
  466.     int fd;
  467.     char * fn;
  468.     char * home;
  469.     int rc = 0;
  470.     static int first = 1;
  471.  
  472.     if (first) {
  473.     setDefaults();
  474.     first = 0;
  475.     }
  476.  
  477.     fd = open(LIBRPMRC_FILENAME, O_RDONLY);
  478.     if (fd > 0) {
  479.     rc = doReadRC(fd, LIBRPMRC_FILENAME);
  480.     close(fd);
  481.     if (rc) return rc;
  482.     } else {
  483.     rpmError(RPMERR_RPMRC, "Unable to open %s for reading: %s.", 
  484.          LIBRPMRC_FILENAME, strerror(errno));
  485.     return 1;
  486.     }
  487.     
  488.     if (file) 
  489.     fn = file;
  490.     else
  491.     fn = "/etc/rpmrc";
  492.  
  493.     fd = open(fn, O_RDONLY);
  494.     if (fd > 0) {
  495.     rc = doReadRC(fd, fn);
  496.     close(fd);
  497.     if (rc) return rc;
  498.     } else if (file) {
  499.     rpmError(RPMERR_RPMRC, "Unable to open %s for reading: %s.", file,
  500.          strerror(errno));
  501.     return 1;
  502.     }
  503.  
  504.     if (!file) {
  505.     home = getenv("HOME");
  506.     if (home) {
  507.         fn = alloca(strlen(home) + 8);
  508.         strcpy(fn, home);
  509.         strcat(fn, "/.rpmrc");
  510.         fd = open(fn, O_RDONLY);
  511.         if (fd > 0) {
  512.         rc |= doReadRC(fd, fn);
  513.         close(fd);
  514.         if (rc) return rc;
  515.         }
  516.     }
  517.     }
  518.  
  519.     rpmSetMachine(NULL, NULL);
  520.  
  521.     setPathDefault(RPMVAR_BUILDDIR, "BUILD");    
  522.     setPathDefault(RPMVAR_RPMDIR, "RPMS");    
  523.     setPathDefault(RPMVAR_SRPMDIR, "SRPMS");    
  524.     setPathDefault(RPMVAR_SOURCEDIR, "SOURCES");    
  525.     setPathDefault(RPMVAR_SPECDIR, "SPECS");
  526.  
  527.     return 0;
  528. }
  529.  
  530. static int doReadRC(int fd, char * filename) {
  531.     struct stat sb;
  532.     char * buf;
  533.     char * start, * chptr, * next, * rest;
  534.     int linenum = 0;
  535.     struct rpmOption searchOption, * option;
  536.     int i;
  537.     int gotit;
  538.  
  539.     fstat(fd, &sb);
  540.     next = buf = alloca(sb.st_size + 2);
  541.     if (read(fd, buf, sb.st_size) != sb.st_size) {
  542.     rpmError(RPMERR_RPMRC, "Failed to read %s: %s.", filename,
  543.          strerror(errno));
  544.     return 1;
  545.     }
  546.     buf[sb.st_size] = '\n';
  547.     buf[sb.st_size + 1] = '\0';
  548.  
  549.     while (*next) {
  550.     linenum++;
  551.  
  552.     chptr = start = next;
  553.     while (*chptr != '\n') chptr++;
  554.  
  555.     *chptr = '\0';
  556.     next = chptr + 1;
  557.  
  558.     while (isspace(*start)) start++;
  559.  
  560.     /* we used to allow comments to begin anywhere, but not anymore */
  561.     if (*start == '#' || !*start) continue;
  562.  
  563.     chptr = start;
  564.     while (!isspace(*chptr) && *chptr != ':' && *chptr) chptr++;
  565.  
  566.     if (isspace(*chptr)) {
  567.         *chptr++ = '\0';
  568.         while (isspace(*chptr) && *chptr != ':' && *chptr) chptr++;
  569.     }
  570.  
  571.     if (*chptr != ':') {
  572.         rpmError(RPMERR_RPMRC, "missing ':' at %s:%d", filename, linenum);
  573.         return 1;
  574.     }
  575.  
  576.     *chptr++ = '\0';
  577.  
  578.     searchOption.name = start;
  579.     option = bsearch(&searchOption, optionTable, optionTableSize,
  580.              sizeof(struct rpmOption), optionCompare);
  581.  
  582.     if (option) {
  583.         start = chptr;
  584.         while (isspace(*start) && *start) start++;
  585.  
  586.         if (! *start) {
  587.         rpmError(RPMERR_RPMRC, "missing argument for %s at %s:%d", 
  588.               option->name, filename, linenum);
  589.         return 1;
  590.         }
  591.  
  592.         if (option->archSpecific) {
  593.         chptr = start;
  594.         while (!isspace(*chptr) && *chptr) chptr++;
  595.  
  596.         if (!*chptr) {
  597.             rpmError(RPMERR_RPMRC, 
  598.                 "missing architecture for %s at %s:%d", 
  599.                   option->name, filename, linenum);
  600.             return 1;
  601.         }
  602.  
  603.         *chptr++ = '\0';
  604.  
  605.         while (isspace(*chptr) && *chptr) chptr++;
  606.         if (!*chptr) {
  607.             rpmError(RPMERR_RPMRC, 
  608.                 "missing argument for %s at %s:%d", 
  609.                   option->name, filename, linenum);
  610.             return 1;
  611.         }
  612.         
  613.         rpmSetVarArch(option->var, chptr, start);
  614.         } else {
  615.         rpmSetVarArch(option->var, start, NULL);
  616.         }
  617.     } else {
  618.         gotit = 0;
  619.  
  620.         for (i = 0; i < RPM_MACHTABLE_COUNT; i++) {
  621.         if (!strncmp(tables[i].key, start, strlen(tables[i].key)))
  622.             break;
  623.         }
  624.  
  625.         if (i < RPM_MACHTABLE_COUNT) {
  626.         rest = start + strlen(tables[i].key);
  627.         if (*rest == '_') rest++;
  628.  
  629.         if (!strcmp(rest, "compat")) {
  630.             if (machCompatCacheAdd(chptr, filename, linenum, 
  631.                         &tables[i].cache))
  632.             return 1;
  633.             gotit = 1;
  634.         } else if (tables[i].hasTranslate &&
  635.                !strcmp(rest, "translate")) {
  636.             if (addDefault(&tables[i].defaults, 
  637.                    &tables[i].defaultsLength,
  638.                    chptr, filename, linenum))
  639.             return 1;
  640.             gotit = 1;
  641.         } else if (tables[i].hasCanon &&
  642.                !strcmp(rest, "canon")) {
  643.             if (addCanon(&tables[i].canons, &tables[i].canonsLength,
  644.                  chptr, filename, linenum))
  645.             return 1;
  646.             gotit = 1;
  647.         }
  648.         }
  649.  
  650.         if (!gotit) {
  651.         rpmError(RPMERR_RPMRC, "bad option '%s' at %s:%d", 
  652.                 start, filename, linenum);
  653.         }
  654.     }
  655.     }
  656.  
  657.     return 0;
  658. }
  659.  
  660. static void defaultMachine(char ** arch, char ** os) {
  661.     static struct utsname un;
  662.     static int gotDefaults = 0;
  663.     char * chptr;
  664.     struct canonEntry * canon;
  665.  
  666.     if (!gotDefaults) {
  667.     uname(&un);
  668.     if (!strcmp(un.sysname, "AIX")) {
  669.         strcpy(un.machine, __power_pc() ? "ppc" : "rs6000");
  670.     } else if (!strncmp(un.sysname, "IP", 2)) {
  671.         un.sysname[2] = '\0';
  672.     }
  673.  
  674.     /* get rid of the hyphens in the sysname */
  675.     chptr = un.machine;
  676.     while (*chptr++)
  677.         if (*chptr == '/') *chptr = '-';
  678.  
  679.     #if defined(__hpux) && defined(_SC_CPU_VERSION)
  680.     {
  681.         int cpu_version = sysconf(_SC_CPU_VERSION);
  682.  
  683.         #if defined(CPU_HP_MC68020)
  684.         if (cpu_version == CPU_HP_MC68020)
  685.             strcpy(un.machine, "m68k");
  686.         #endif
  687.         #if defined(CPU_HP_MC68030)
  688.         if (cpu_version == CPU_HP_MC68030)
  689.             strcpy(un.machine, "m68k");
  690.         #endif
  691.         #if defined(CPU_HP_MC68040)
  692.         if (cpu_version == CPU_HP_MC68040)
  693.             strcpy(un.machine, "m68k");
  694.         #endif
  695.  
  696.         #if defined(CPU_PA_RISC1_0)
  697.         if (cpu_version == CPU_PA_RISC1_0)
  698.             strcpy(un.machine, "parisc");
  699.         #endif
  700.         #if defined(CPU_PA_RISC1_1)
  701.         if (cpu_version == CPU_PA_RISC1_1)
  702.             strcpy(un.machine, "parisc");
  703.         #endif
  704.         #if defined(CPU_PA_RISC1_2)
  705.         if (cpu_version == CPU_PA_RISC1_2)
  706.             strcpy(un.machine, "parisc");
  707.         #endif
  708.     }
  709.     #endif
  710.  
  711.     /* the uname() result goes through the arch_canon table */
  712.     canon = lookupInCanonTable(un.machine,
  713.                    tables[RPM_MACHTABLE_INSTARCH].canons,
  714.                    tables[RPM_MACHTABLE_INSTARCH].canonsLength);
  715.     if (canon)
  716.         strcpy(un.machine, canon->short_name);
  717.  
  718.     canon = lookupInCanonTable(un.sysname,
  719.                    tables[RPM_MACHTABLE_INSTOS].canons,
  720.                    tables[RPM_MACHTABLE_INSTOS].canonsLength);
  721.     if (canon)
  722.         strcpy(un.sysname, canon->short_name);
  723.     }
  724.  
  725.     if (arch) *arch = un.machine;
  726.     if (os) *os = un.sysname;
  727. }
  728.  
  729. static char * rpmGetVarArch(int var, char * arch) {
  730.     struct rpmvarValue * next;
  731.  
  732.     if (!arch) arch = current[ARCH];
  733.  
  734.     if (arch) {
  735.     next = &values[var];
  736.     while (next) {
  737.         if (next->arch && !strcmp(next->arch, arch)) return next->value;
  738.         next = next->next;
  739.     }
  740.     }
  741.  
  742.     next = values + var;
  743.     while (next && next->arch) next = next->next;
  744.  
  745.     return next ? next->value : NULL;
  746. }
  747.  
  748. char *rpmGetVar(int var)
  749. {
  750.     return rpmGetVarArch(var, NULL);
  751. }
  752.  
  753. int rpmGetBooleanVar(int var) {
  754.     char * val;
  755.     int num;
  756.     char * chptr;
  757.  
  758.     val = rpmGetVar(var);
  759.     if (!val) return 0;
  760.  
  761.     if (val[0] == 'y' || val[0] == 'Y') return 1;
  762.  
  763.     num = strtol(val, &chptr, 0);
  764.     if (chptr && *chptr == '\0') {
  765.     return num != 0;
  766.     }
  767.  
  768.     return 0;
  769. }
  770.  
  771. void rpmSetVar(int var, char *val) {
  772.     freeRpmVar(&values[var]);
  773.    
  774.     values[var].arch = NULL;
  775.     values[var].next = NULL;
  776.  
  777.     if (val) 
  778.     values[var].value = strdup(val);
  779.     else
  780.     values[var].value = NULL;
  781. }
  782.  
  783. /* this doesn't free the passed pointer! */
  784. static void freeRpmVar(struct rpmvarValue * orig) {
  785.     struct rpmvarValue * next, * var = orig;
  786.  
  787.     while (var) {
  788.     next = var->next;
  789.     if (var->arch) free(var->arch);
  790.     if (var->value) free(var->value);
  791.  
  792.     if (var != orig) free(var);
  793.     var = next;
  794.     }
  795. }
  796.  
  797. static void rpmSetVarArch(int var, char * val, char * arch) {
  798.     struct rpmvarValue * next = values + var;
  799.  
  800.     if (next->value) {
  801.     if (arch) {
  802.         while (next->next) {
  803.         if (next->arch && !strcmp(next->arch, arch)) break;
  804.         next = next->next;
  805.         }
  806.     } else {
  807.         while (next->next) {
  808.         if (!next->arch) break;
  809.         next = next->next;
  810.         }
  811.     }
  812.  
  813.     if (next->arch && arch && !strcmp(next->arch, arch)) {
  814.         if (next->value) free(next->value);
  815.         if (next->arch) free(next->arch);
  816.     } else if (next->arch || arch) {
  817.         next->next = malloc(sizeof(*next->next));
  818.         next = next->next;
  819.         next->next = NULL;
  820.     }
  821.     }
  822.  
  823.     next->value = strdup(val);
  824.     if (arch)
  825.     next->arch = strdup(arch);
  826.     else
  827.     next->arch = NULL;
  828. }
  829.  
  830. void rpmSetTables(int archTable, int osTable) {
  831.     char * arch, * os;
  832.  
  833.     defaultMachine(&arch, &os);
  834.  
  835.     if (currTables[ARCH] != archTable) {
  836.     currTables[ARCH] = archTable;
  837.     rebuildCompatTables(ARCH, arch);
  838.     }
  839.  
  840.     if (currTables[OS] != osTable) {
  841.     currTables[OS] = osTable;
  842.     rebuildCompatTables(OS, os);
  843.     }
  844. }
  845.  
  846. int rpmMachineScore(int type, char * name) {
  847.     struct machEquivInfo * info;
  848.  
  849.     info = machEquivSearch(&tables[type].equiv, name);
  850.     if (info) 
  851.     return info->score;
  852.     else
  853.     return 0;
  854. }
  855.  
  856. void rpmSetMachine(char * arch, char * os) {
  857.     int transOs = os == NULL;
  858.     int transArch = arch == NULL;
  859.     char * realArch, * realOs;
  860.  
  861.     defaultMachine(&realArch, &realOs);
  862.  
  863.     if (!arch)
  864.     arch = realArch;
  865.     if (!os)
  866.     os = realOs;
  867.  
  868.     if (transArch && tables[currTables[ARCH]].hasTranslate)
  869.     arch = lookupInDefaultTable(arch,
  870.                 tables[currTables[ARCH]].defaults,
  871.                 tables[currTables[ARCH]].defaultsLength);
  872.     if (transOs && tables[currTables[OS]].hasTranslate)
  873.     os = lookupInDefaultTable(os,
  874.                 tables[currTables[OS]].defaults,
  875.                 tables[currTables[OS]].defaultsLength);
  876.  
  877.     if (!current[ARCH] || strcmp(arch, current[ARCH])) {
  878.     if (current[ARCH]) free(current[ARCH]);
  879.     current[ARCH] = strdup(arch);
  880.     rebuildCompatTables(ARCH, realArch);
  881.     }
  882.  
  883.     if (!current[OS] || strcmp(os, current[OS])) {
  884.     if (current[OS]) free(current[OS]);
  885.     current[OS] = strdup(os);
  886.     rebuildCompatTables(OS, realOs);
  887.     }
  888. }
  889.  
  890. static void rebuildCompatTables(int type, char * name) {
  891.     machFindEquivs(&tables[currTables[type]].cache,
  892.            &tables[currTables[type]].equiv,
  893.            name);
  894. }
  895.  
  896. static void getMachineInfo(int type, char ** name, int * num) {
  897.     struct canonEntry * canon;
  898.  
  899.     if (!tables[currTables[type]].hasCanon) {
  900.     if (num) *num = 255;
  901.     if (name) *name = current[type];
  902.     return;
  903.     }
  904.  
  905.     canon = lookupInCanonTable(current[type], 
  906.                    tables[currTables[type]].canons,
  907.                    tables[currTables[type]].canonsLength);
  908.  
  909.     if (canon) {
  910.     if (num) *num = canon->num;
  911.     if (name) *name = canon->short_name;
  912.     } else {
  913.     if (num) *num = 255;
  914.     if (name) *name = current[type];
  915.     rpmMessage(RPMMESS_WARNING, "Unknown system: %s\n", current[type]);
  916.     rpmMessage(RPMMESS_WARNING, "Please contact rpm-list@redhat.com\n");
  917.     }
  918. }
  919.  
  920. void rpmGetArchInfo(char ** name, int * num) {
  921.     getMachineInfo(ARCH, name, num);
  922. }
  923.  
  924. void rpmGetOsInfo(char ** name, int * num) {
  925.     getMachineInfo(OS, name, num);
  926. }
  927.  
  928. int rpmShowRC(FILE *f)
  929. {
  930.     struct rpmOption *opt;
  931.     int count = 0;
  932.     char *s;
  933.     int i;
  934.     struct machEquivTable * equivTable;
  935.  
  936.     /* the caller may set the build arch which should be printed here */
  937.     fprintf(f, "ARCHITECTURE AND OS:\n");
  938.     fprintf(f, "build arch            : %s\n", current[ARCH]);
  939.  
  940.     fprintf(f, "compatible build archs:");
  941.     equivTable = &tables[RPM_MACHTABLE_BUILDARCH].equiv;
  942.     for (i = 0; i < equivTable->count; i++)
  943.     fprintf(f," %s", equivTable->list[i].name);
  944.     fprintf(f, "\n");
  945.  
  946.     fprintf(f, "build os              : %s\n", current[OS]);
  947.  
  948.     fprintf(f, "compatible build os's :");
  949.     equivTable = &tables[RPM_MACHTABLE_BUILDOS].equiv;
  950.     for (i = 0; i < equivTable->count; i++)
  951.     fprintf(f," %s", equivTable->list[i].name);
  952.     fprintf(f, "\n");
  953.  
  954.     rpmSetTables(RPM_MACHTABLE_INSTARCH, RPM_MACHTABLE_INSTOS);
  955.     rpmSetMachine(NULL, NULL);
  956.  
  957.     fprintf(f, "install arch          : %s\n", current[ARCH]);
  958.     fprintf(f, "install os            : %s\n", current[OS]);
  959.  
  960.     fprintf(f, "compatible archs      :");
  961.     equivTable = &tables[RPM_MACHTABLE_INSTARCH].equiv;
  962.     for (i = 0; i < equivTable->count; i++)
  963.     fprintf(f," %s", equivTable->list[i].name);
  964.     fprintf(f, "\n");
  965.  
  966.     fprintf(f, "compatible os's       :");
  967.     equivTable = &tables[RPM_MACHTABLE_INSTOS].equiv;
  968.     for (i = 0; i < equivTable->count; i++)
  969.     fprintf(f," %s", equivTable->list[i].name);
  970.     fprintf(f, "\n");
  971.  
  972.     fprintf(f, "RPMRC VALUES:\n");
  973.     opt = optionTable;
  974.     while (count < optionTableSize) {
  975.     s = rpmGetVar(opt->var);
  976.     fprintf(f, "%-21s : %s\n", opt->name, s ? s : "(not set)");
  977.     opt++;
  978.     count++;
  979.     }
  980.     
  981.     return 0;
  982. }
  983.