Compile in default macro values sufficient to pass make check.
[platform/upstream/rpm.git] / lib / rpmrc.c
1 #include "system.h"
2
3 #if HAVE_SYS_SYSTEMCFG_H
4 #include <sys/systemcfg.h>
5 #else
6 #define __power_pc() 0
7 #endif
8
9 #include "rpmlib.h"
10 #include "rpmmacro.h"
11
12 #include "misc.h"
13
14 static const char *defrcfiles = LIBRPMRC_FILENAME ":/etc/rpmrc:~/.rpmrc";
15
16 #if UNUSED
17 static const char *macrofiles = MACROFILES;
18 #endif
19
20 struct MacroContext globalMacroContext;
21
22 struct machCacheEntry {
23     char * name;
24     int count;
25     char ** equivs;
26     int visited;
27 };
28
29 struct machCache {
30     struct machCacheEntry * cache;
31     int size;
32 };
33
34 struct machEquivInfo {
35     char * name;
36     int score;
37 };
38
39 struct machEquivTable {
40     int count;
41     struct machEquivInfo * list;
42 };
43
44 struct rpmvarValue {
45     char * value;
46     /* eventually, this arch will be replaced with a generic condition */
47     char * arch;
48     struct rpmvarValue * next;
49 };
50
51 struct rpmOption {
52     char * name;
53     int var;
54     int archSpecific, required, macroize, localize;
55     struct rpmOptionValue * value;
56 };
57
58 struct defaultEntry {
59     char *name;
60     char *defName;
61 };
62
63 struct canonEntry {
64     char *name;
65     char *short_name;
66     short num;
67 };
68
69 /* tags are 'key'canon, 'key'translate, 'key'compat
70
71    for giggles, 'key'_canon, 'key'_compat, and 'key'_canon will also work */
72 struct tableType {
73     char * key;
74     int hasCanon, hasTranslate;
75     struct machEquivTable equiv;
76     struct machCache cache;
77     struct defaultEntry * defaults;
78     struct canonEntry * canons;
79     int defaultsLength;
80     int canonsLength;
81 };
82
83 /*@-fullinitblock@*/
84 static struct tableType tables[RPM_MACHTABLE_COUNT] = {
85     { "arch", 1, 0 },
86     { "os", 1, 0 },
87     { "buildarch", 0, 1 },
88     { "buildos", 0, 1 }
89 };
90
91 /* this *must* be kept in alphabetical order */
92 /* The order of the flags is archSpecific, required, macroize, localize */
93
94 static struct rpmOption optionTable[] = {
95     { "builddir",               RPMVAR_BUILDDIR,                0, 0,   1, 2 },
96     { "buildroot",              RPMVAR_BUILDROOT,               0, 0,   1, 0 },
97     { "buildshell",             RPMVAR_BUILDSHELL,              0, 0,   1, 0 },
98     { "bzip2bin",               RPMVAR_BZIP2BIN,                0, 1,   1, 2 },
99     { "dbpath",                 RPMVAR_DBPATH,                  0, 1,   1, 2 },
100     { "defaultdocdir",          RPMVAR_DEFAULTDOCDIR,           0, 0,   1, 1 },
101     { "distribution",           RPMVAR_DISTRIBUTION,            0, 0,   1, 0 },
102     { "excludedocs",            RPMVAR_EXCLUDEDOCS,             0, 0,   1, 0 },
103     { "fixperms",               RPMVAR_FIXPERMS,                0, 1,   1, 2 },
104     { "ftpport",                RPMVAR_FTPPORT,                 0, 0,   1, 0 },
105     { "ftpproxy",               RPMVAR_FTPPROXY,                0, 0,   1, 0 },
106     { "gzipbin",                RPMVAR_GZIPBIN,                 0, 1,   1, 2 },
107     { "include",                RPMVAR_INCLUDE,                 0, 1,   1, 2 },
108     { "instchangelog",          RPMVAR_INSTCHANGELOG,           0, 0,   0, 0 },
109     { "langpatt",               RPMVAR_LANGPATT,                0, 0,   1, 0 },
110     { "macrofiles",             RPMVAR_MACROFILES,              0, 0,   1, 1 },
111     { "messagelevel",           RPMVAR_MESSAGELEVEL,            0, 0,   1, 0 },
112     { "netsharedpath",          RPMVAR_NETSHAREDPATH,           0, 0,   1, 0 },
113     { "optflags",               RPMVAR_OPTFLAGS,                1, 0,   1, 0 },
114     { "packager",               RPMVAR_PACKAGER,                0, 0,   1, 0 },
115     { "pgp_name",               RPMVAR_PGP_NAME,                0, 0,   1, 0 },
116     { "pgp_path",               RPMVAR_PGP_PATH,                0, 0,   1, 0 },
117     { "provides",               RPMVAR_PROVIDES,                0, 0,   1, 0 },
118     { "require_distribution",   RPMVAR_REQUIREDISTRIBUTION,     0, 0,   1, 0 },
119     { "require_icon",           RPMVAR_REQUIREICON,             0, 0,   1, 0 },
120     { "require_vendor",         RPMVAR_REQUIREVENDOR,           0, 0,   1, 0 },
121     { "rpmdir",                 RPMVAR_RPMDIR,                  0, 0,   1, 1 },
122     { "rpmfilename",            RPMVAR_RPMFILENAME,             0, 1,   1, 2 },
123 #if defined(RPMVAR_SETENV)
124     { "setenv",                 RPMVAR_SETENV,                  0, 1,   0. 0 },
125 #endif
126     { "signature",              RPMVAR_SIGTYPE,                 0, 0,   0, 0 },
127     { "sourcedir",              RPMVAR_SOURCEDIR,               0, 0,   1, 1 },
128     { "specdir",                RPMVAR_SPECDIR,                 0, 0,   1, 1 },
129     { "srcrpmdir",              RPMVAR_SRPMDIR,                 0, 0,   1, 1 },
130     { "timecheck",              RPMVAR_TIMECHECK,               0, 0,   1, 0 },
131     { "tmppath",                RPMVAR_TMPPATH,                 0, 1,   1, 2 },
132     { "topdir",                 RPMVAR_TOPDIR,                  0, 0,   1, 1 },
133     { "vendor",                 RPMVAR_VENDOR,                  0, 0,   1, 1 },
134 };
135 /*@=fullinitblock@*/
136 static int optionTableSize = sizeof(optionTable) / sizeof(*optionTable);
137
138 #define OS      0
139 #define ARCH    1
140
141 static char * current[2];
142 static int currTables[2] = { RPM_MACHTABLE_INSTOS, RPM_MACHTABLE_INSTARCH };
143 static struct rpmvarValue values[RPMVAR_NUM];
144
145 /* prototypes */
146 static void defaultMachine(char ** arch, char ** os);
147 static int doReadRC(FD_t fd, const char * filename);
148 static int optionCompare(const void * a, const void * b);
149 static int addCanon(struct canonEntry **table, int *tableLen, char *line,
150                         const char *fn, int lineNum);
151 static int addDefault(struct defaultEntry **table, int *tableLen, char *line,
152                         const char *fn, int lineNum);
153 static void freeRpmVar(struct rpmvarValue * orig);
154 static void rpmSetVarArch(int var, char * val, char * arch);
155 static struct canonEntry *lookupInCanonTable(char *name,
156                                            struct canonEntry *table,
157                                            int tableLen);
158 static const char *lookupInDefaultTable(const char *name,
159                                   struct defaultEntry *table,
160                                   int tableLen);
161
162 static void setVarDefault(int var, const char *macroname, const char *val, const char *body);
163 static void setPathDefault(int var, const char *macroname, const char *subdir);
164 static void setDefaults(void);
165
166 static void rebuildCompatTables(int type, char *name);
167
168 /* compatiblity tables */
169 static int machCompatCacheAdd(char * name, const char * fn, int linenum,
170                                 struct machCache * cache);
171 static struct machCacheEntry * machCacheFindEntry(struct machCache * cache,
172                                                   char * key);
173 static struct machEquivInfo * machEquivSearch(
174                 struct machEquivTable * table, char * name);
175 static void machAddEquiv(struct machEquivTable * table, char * name,
176                            int distance);
177 static void machCacheEntryVisit(struct machCache * cache,
178                                   struct machEquivTable * table,
179                                   char * name,
180                                   int distance);
181 static void machFindEquivs(struct machCache * cache,
182                              struct machEquivTable * table,
183                              char * key);
184
185 static int optionCompare(const void * a, const void * b) {
186     return strcasecmp(((struct rpmOption *) a)->name,
187                       ((struct rpmOption *) b)->name);
188 }
189
190 static void rpmRebuildTargetVars(const char ** canontarget);
191
192
193 static struct machCacheEntry * machCacheFindEntry(struct machCache * cache,
194                                                   char * key)
195 {
196     int i;
197
198     for (i = 0; i < cache->size; i++)
199         if (!strcmp(cache->cache[i].name, key)) return cache->cache + i;
200
201     return NULL;
202 }
203
204 static int machCompatCacheAdd(char * name, const char * fn, int linenum,
205                                 struct machCache * cache)
206 {
207     char * chptr, * equivs;
208     int delEntry = 0;
209     int i;
210     struct machCacheEntry * entry = NULL;
211
212     while (*name && isspace(*name)) name++;
213
214     chptr = name;
215     while (*chptr && *chptr != ':') chptr++;
216     if (!*chptr) {
217         rpmError(RPMERR_RPMRC, _("missing second ':' at %s:%d"), fn, linenum);
218         return 1;
219     } else if (chptr == name) {
220         rpmError(RPMERR_RPMRC, _("missing architecture name at %s:%d"), fn,
221                              linenum);
222         return 1;
223     }
224
225     while (*chptr == ':' || isspace(*chptr)) chptr--;
226     *(++chptr) = '\0';
227     equivs = chptr + 1;
228     while (*equivs && isspace(*equivs)) equivs++;
229     if (!*equivs) {
230         delEntry = 1;
231     }
232
233     if (cache->size) {
234         entry = machCacheFindEntry(cache, name);
235         if (entry) {
236             for (i = 0; i < entry->count; i++)
237                 free(entry->equivs[i]);
238             if (entry->count) free(entry->equivs);
239             entry->count = 0;
240         }
241     }
242
243     if (!entry) {
244         cache->cache = realloc(cache->cache,
245                                (cache->size + 1) * sizeof(*cache->cache));
246         entry = cache->cache + cache->size++;
247         entry->name = strdup(name);
248         entry->count = 0;
249         entry->visited = 0;
250     }
251
252     if (delEntry) return 0;
253
254     while ((chptr = strtok(equivs, " ")) != NULL) {
255         equivs = NULL;
256         if (chptr[0] == '\0')   /* does strtok() return "" ever?? */
257             continue;
258         if (entry->count)
259             entry->equivs = realloc(entry->equivs, sizeof(*entry->equivs)
260                                         * (entry->count + 1));
261         else
262             entry->equivs = malloc(sizeof(*entry->equivs));
263
264         entry->equivs[entry->count] = strdup(chptr);
265         entry->count++;
266     }
267
268     return 0;
269 }
270
271 static struct machEquivInfo * machEquivSearch(
272                 struct machEquivTable * table, char * name)
273 {
274     int i;
275
276 /*
277  * XXX The strcasecmp below is necessary so the old (rpm < 2.90) style
278  * XXX os-from-uname (e.g. "Linux") is compatible with the new
279  * XXX os-from-platform (e.g "linux" from "sparc-*-linux").
280  * XXX A copy of this string is embedded in headers and is
281  * XXX used by rpmInstallPackage->{os,arch}Okay->rpmMachineScore->.
282  * XXX to verify correct arch/os from headers.
283  */
284     for (i = 0; i < table->count; i++)
285         if (!strcasecmp(table->list[i].name, name))
286             return table->list + i;
287
288     return NULL;
289 }
290
291 static void machAddEquiv(struct machEquivTable * table, char * name,
292                            int distance)
293 {
294     struct machEquivInfo * equiv;
295
296     equiv = machEquivSearch(table, name);
297     if (!equiv) {
298         if (table->count)
299             table->list = realloc(table->list, (table->count + 1)
300                                     * sizeof(*table->list));
301         else
302             table->list = malloc(sizeof(*table->list));
303
304         table->list[table->count].name = strdup(name);
305         table->list[table->count++].score = distance;
306     }
307 }
308
309 static void machCacheEntryVisit(struct machCache * cache,
310                                   struct machEquivTable * table,
311                                   char * name,
312                                   int distance)
313 {
314     struct machCacheEntry * entry;
315     int i;
316
317     entry = machCacheFindEntry(cache, name);
318     if (!entry || entry->visited) return;
319
320     entry->visited = 1;
321
322     for (i = 0; i < entry->count; i++) {
323         machAddEquiv(table, entry->equivs[i], distance);
324     }
325
326     for (i = 0; i < entry->count; i++) {
327         machCacheEntryVisit(cache, table, entry->equivs[i], distance + 1);
328     }
329 }
330
331 static void machFindEquivs(struct machCache * cache,
332                              struct machEquivTable * table,
333                              char * key)
334 {
335     int i;
336
337     for (i = 0; i < cache->size; i++)
338         cache->cache[i].visited = 0;
339
340     table->count = 0;
341
342     /* We have a general graph built using strings instead of pointers.
343        Yuck. We have to start at a point at traverse it, remembering how
344        far away everything is. */
345     machAddEquiv(table, key, 1);
346     machCacheEntryVisit(cache, table, key, 2);
347 }
348
349 static int addCanon(struct canonEntry **table, int *tableLen, char *line,
350                     const char *fn, int lineNum)
351 {
352     struct canonEntry *t;
353     char *s, *s1;
354
355     if (! *tableLen) {
356         *tableLen = 2;
357         *table = malloc(2 * sizeof(struct canonEntry));
358     } else {
359         (*tableLen) += 2;
360         *table = realloc(*table, sizeof(struct canonEntry) * (*tableLen));
361     }
362     t = & ((*table)[*tableLen - 2]);
363
364     t->name = strtok(line, ": \t");
365     t->short_name = strtok(NULL, " \t");
366     s = strtok(NULL, " \t");
367     if (! (t->name && t->short_name && s)) {
368         rpmError(RPMERR_RPMRC, _("Incomplete data line at %s:%d"), fn, lineNum);
369         return RPMERR_RPMRC;
370     }
371     if (strtok(NULL, " \t")) {
372         rpmError(RPMERR_RPMRC, _("Too many args in data line at %s:%d"),
373               fn, lineNum);
374         return RPMERR_RPMRC;
375     }
376
377     t->num = strtoul(s, &s1, 10);
378     if ((*s1) || (s1 == s) || (t->num == ULONG_MAX)) {
379         rpmError(RPMERR_RPMRC, _("Bad arch/os number: %s (%s:%d)"), s,
380               fn, lineNum);
381         return(RPMERR_RPMRC);
382     }
383
384     t->name = strdup(t->name);
385     t->short_name = strdup(t->short_name);
386
387     /* From A B C entry */
388     /* Add  B B C entry */
389     t[1].name = strdup(t->short_name);
390     t[1].short_name = strdup(t->short_name);
391     t[1].num = t->num;
392
393     return 0;
394 }
395
396 static int addDefault(struct defaultEntry **table, int *tableLen, char *line,
397                         const char *fn, int lineNum)
398 {
399     struct defaultEntry *t;
400
401     if (! *tableLen) {
402         *tableLen = 1;
403         *table = malloc(sizeof(struct defaultEntry));
404     } else {
405         (*tableLen)++;
406         *table = realloc(*table, sizeof(struct defaultEntry) * (*tableLen));
407     }
408     t = & ((*table)[*tableLen - 1]);
409
410     t->name = strtok(line, ": \t");
411     t->defName = strtok(NULL, " \t");
412     if (! (t->name && t->defName)) {
413         rpmError(RPMERR_RPMRC, _("Incomplete default line at %s:%d"),
414                  fn, lineNum);
415         return RPMERR_RPMRC;
416     }
417     if (strtok(NULL, " \t")) {
418         rpmError(RPMERR_RPMRC, _("Too many args in default line at %s:%d"),
419               fn, lineNum);
420         return RPMERR_RPMRC;
421     }
422
423     t->name = strdup(t->name);
424     t->defName = strdup(t->defName);
425
426     return 0;
427 }
428
429 static struct canonEntry *lookupInCanonTable(char *name,
430                                              struct canonEntry *table,
431                                              int tableLen) {
432     while (tableLen) {
433         tableLen--;
434         if (!strcmp(name, table[tableLen].name)) {
435             return &(table[tableLen]);
436         }
437     }
438
439     return NULL;
440 }
441
442 static const char *lookupInDefaultTable(const char *name, struct defaultEntry *table,
443                                   int tableLen) {
444     while (tableLen) {
445         tableLen--;
446         if (!strcmp(name, table[tableLen].name)) {
447             return table[tableLen].defName;
448         }
449     }
450
451     return name;
452 }
453
454 int rpmReadConfigFiles(const char * file, const char * target)
455 {
456
457     rpmSetMachine(NULL, NULL);
458
459     if (target == NULL) {
460        rpmRebuildTargetVars(&target);
461     } else {
462        addMacro(&globalMacroContext, "_target", NULL, target, RMIL_RPMRC);
463     }
464
465     if (rpmReadRC(file)) return -1;
466
467     rpmRebuildTargetVars(&target);
468
469    {    const char *cpu = getMacroBody(&globalMacroContext, "_target_cpu");
470         const char *os = getMacroBody(&globalMacroContext, "_target_os");
471         rpmSetMachine(cpu, os);
472    }
473
474     return 0;
475 }
476
477 static void setVarDefault(int var, const char *macroname, const char *val, const char *body)
478 {
479     if (rpmGetVar(var)) return;
480     rpmSetVar(var, val);
481     if (body == NULL)
482         body = val;
483     addMacro(&globalMacroContext, macroname, NULL, body, RMIL_DEFAULT);
484 }
485
486 static void setPathDefault(int var, const char *macroname, const char *subdir)
487 {
488     const char * topdir;
489     char * fn;
490
491     if (rpmGetVar(var)) return;
492
493     topdir = rpmGetVar(RPMVAR_TOPDIR);
494     if (topdir == NULL) topdir = rpmGetVar(RPMVAR_TMPPATH);
495
496     fn = alloca(strlen(topdir) + strlen(subdir) + 2);
497     strcpy(fn, topdir);
498     if (fn[strlen(topdir) - 1] != '/')
499         strcat(fn, "/");
500     strcat(fn, subdir);
501
502     rpmSetVar(var, fn);
503
504     if (macroname != NULL) {
505 #define _TOPDIRMACRO    "%{_topdir}/"
506         char *body = alloca(sizeof(_TOPDIRMACRO) + strlen(subdir));
507         strcpy(body, _TOPDIRMACRO);
508         strcat(body, subdir);
509         addMacro(&globalMacroContext, macroname, NULL, body, RMIL_DEFAULT);
510 #undef _TOPDIRMACRO
511     }
512 }
513
514 static const char *prescriptenviron = "\n\
515 RPM_SOURCE_DIR=\"%{_sourcedir}\"\n\
516 RPM_BUILD_DIR=\"%{_builddir}\"\n\
517 RPM_OPT_FLAGS=\"%{optflags}\"\n\
518 RPM_ARCH=\"%{_target_cpu}\"\n\
519 RPM_OS=\"%{_target_os}\"\n\
520 export RPM_SOURCE_DIR RPM_BUILD_DIR RPM_OPT_FLAGS RPM_ARCH RPM_OS\n\
521 RPM_DOC_DIR=\"%{_docdir}\"\n\
522 export RPM_DOC_DIR\
523 RPM_PACKAGE_NAME=\"%{name}\"\n\
524 RPM_PACKAGE_VERSION=\"%{version}\"\n\
525 RPM_PACKAGE_RELEASE=\"%{release}\"\n\
526 export RPM_PACKAGE_NAME RPM_PACKAGE_VERSION RPM_PACKAGE_RELEASE\n\
527 %{?buildroot:RPM_BUILD_ROOT=\"%{buildroot}\"\n\
528 export RPM_BUILD_ROOT\n}\
529 ";
530
531 static void setDefaults(void) {
532
533     initMacros(&globalMacroContext, NULL); /* XXX initialize data structures */
534     addMacro(&globalMacroContext, "_usr", NULL, "/usr", RMIL_DEFAULT);
535     addMacro(&globalMacroContext, "_var", NULL, "/var", RMIL_DEFAULT);
536
537     addMacro(&globalMacroContext, "_preScriptEnvironment", NULL,
538         prescriptenviron, RMIL_DEFAULT);
539
540     setVarDefault(RPMVAR_MACROFILES,    "_macrofiles",
541                 "/usr/lib/rpm/macros", "%{_usr}/lib/rpm/macros");
542     setVarDefault(RPMVAR_TOPDIR,        "_topdir",
543                 "/usr/src/redhat", "%{_usr}/src/redhat");
544     setVarDefault(RPMVAR_TMPPATH,       "_tmppath",
545                 "/var/tmp",     "%{_var}/tmp");
546     setVarDefault(RPMVAR_DBPATH,        "_dbpath",
547                 "/var/lib/rpm", "%{_var}/lib/rpm");
548     setVarDefault(RPMVAR_DEFAULTDOCDIR, "_defaultdocdir",
549                 "/usr/doc",     "%{_usr}/doc");
550
551     setVarDefault(RPMVAR_OPTFLAGS,      "optflags",     "-O2",          NULL);
552     setVarDefault(RPMVAR_SIGTYPE,       "sigtype",      "none",         NULL);
553     setVarDefault(RPMVAR_BUILDSHELL,    "buildshell",   "/bin/sh",      NULL);
554
555     setPathDefault(RPMVAR_BUILDDIR, "_builddir", "BUILD");
556     setPathDefault(RPMVAR_RPMDIR, "_rpmdir", "RPMS");
557     setPathDefault(RPMVAR_SRPMDIR, "_srcrpmdir", "SRPMS");
558     setPathDefault(RPMVAR_SOURCEDIR, "_sourcedir", "SOURCES");
559     setPathDefault(RPMVAR_SPECDIR, "_specdir", "SPECS");
560
561 }
562
563 int rpmReadRC(const char * rcfiles)
564 {
565     char *myrcfiles, *r, *re;
566     int rc;
567     static int first = 1;
568
569     if (first) {
570         setDefaults();
571         first = 0;
572     }
573
574     if (rcfiles == NULL)
575         rcfiles = defrcfiles;
576
577     /* Read each file in rcfiles. */
578     rc = 0;
579     for (r = myrcfiles = strdup(rcfiles); *r != '\0'; r = re) {
580         char fn[FILENAME_MAX+1];
581         FD_t fd;
582
583         /* Get pointer to rest of files */
584         if ((re = strchr(r, ':')) != NULL)
585             *re++ = '\0';
586         else
587             re = r + strlen(r);
588
589         /* Expand ~/ to $HOME/ */
590         fn[0] = '\0';
591         if (r[0] == '~' && r[1] == '/') {
592             char *home = getenv("HOME");
593             if (home == NULL) {
594                 rpmError(RPMERR_RPMRC, _("Cannot expand %s"), r);
595                 rc = 1;
596                 break;
597             }
598             strcpy(fn, home);
599             r++;
600         }
601         strcat(fn, r);
602             
603         /* Read another rcfile */
604         fd = fdOpen(fn, O_RDONLY, 0);
605         if (fdFileno(fd) < 0) {
606             /* XXX Only /usr/lib/rpm/rpmrc must exist in default rcfiles list */
607             if (rcfiles == defrcfiles && myrcfiles != r)
608                 continue;
609             rpmError(RPMERR_RPMRC, _("Unable to open %s for reading: %s."),
610                  fn, strerror(errno));
611             rc = 1;
612             break;
613         }
614         rc = doReadRC(fd, fn);
615         fdClose(fd);
616         if (rc) break;
617     }
618     if (myrcfiles)      free(myrcfiles);
619     if (rc)
620         return rc;
621
622     rpmSetMachine(NULL, NULL);  /* XXX WTFO? Why bother? */
623
624     if ((r = rpmGetVar(RPMVAR_MACROFILES)) != NULL)
625         initMacros(&globalMacroContext, r);
626
627     return rc;
628 }
629
630 static int doReadRC(FD_t fd, const char * filename) {
631     char buf[BUFSIZ];
632     char * start, * chptr, * next, * rest;
633     int linenum = 0;
634     struct rpmOption searchOption, * option;
635     int i;
636     int gotit;
637     int rc;
638
639   { struct stat sb;
640     fstat(fdFileno(fd), &sb);
641     next = alloca(sb.st_size + 2);
642     if (fdRead(fd, next, sb.st_size) != sb.st_size) {
643         rpmError(RPMERR_RPMRC, _("Failed to read %s: %s."), filename,
644                  strerror(errno));
645         return 1;
646     }
647     next[sb.st_size] = '\n';
648     next[sb.st_size + 1] = '\0';
649   }
650
651     while (*next) {
652         linenum++;
653
654         chptr = start = next;
655         while (*chptr != '\n') chptr++;
656
657         *chptr = '\0';
658         next = chptr + 1;
659
660         while (isspace(*start)) start++;
661
662         /* we used to allow comments to begin anywhere, but not anymore */
663         if (*start == '#' || !*start) continue;
664
665         chptr = start;
666         while (!isspace(*chptr) && *chptr != ':' && *chptr) chptr++;
667
668         if (isspace(*chptr)) {
669             *chptr++ = '\0';
670             while (isspace(*chptr) && *chptr != ':' && *chptr) chptr++;
671         }
672
673         if (*chptr != ':') {
674             rpmError(RPMERR_RPMRC, _("missing ':' at %s:%d"),
675                      filename, linenum);
676             return 1;
677         }
678
679         *chptr++ = '\0';
680
681         searchOption.name = start;
682         option = bsearch(&searchOption, optionTable, optionTableSize,
683                          sizeof(struct rpmOption), optionCompare);
684
685         if (option) {
686             start = chptr;
687             while (isspace(*start) && *start) start++;
688
689             if (! *start) {
690                 rpmError(RPMERR_RPMRC, _("missing argument for %s at %s:%d"),
691                       option->name, filename, linenum);
692                 return 1;
693             }
694
695             switch (option->var) {
696
697             case RPMVAR_INCLUDE:
698               { FD_t fdinc;
699
700                 rpmRebuildTargetVars(NULL);
701
702                 strcpy(buf, start);
703                 if (expandMacros(NULL, &globalMacroContext, buf, sizeof(buf))) {
704                     rpmError(RPMERR_RPMRC, _("expansion failed at %s:d \"%s\""),
705                         filename, linenum, start);
706                     return 1;
707                 }
708
709                 if (fdFileno(fdinc = fdOpen(buf, O_RDONLY, 0)) < 0) {
710                     rpmError(RPMERR_RPMRC, _("cannot open %s at %s:%d"),
711                         buf, filename, linenum);
712                         return 1;
713                 }
714                 rc = doReadRC(fdinc, buf);
715                 fdClose(fdinc);
716                 if (rc) return rc;
717               } break;
718             default:
719                 break;
720             }
721
722             chptr = start;
723             if (option->archSpecific) {
724                 while (!isspace(*chptr) && *chptr) chptr++;
725
726                 if (!*chptr) {
727                     rpmError(RPMERR_RPMRC,
728                                 _("missing architecture for %s at %s:%d"),
729                                 option->name, filename, linenum);
730                     return 1;
731                 }
732
733                 *chptr++ = '\0';
734
735                 while (isspace(*chptr) && *chptr) chptr++;
736                 if (!*chptr) {
737                     rpmError(RPMERR_RPMRC,
738                                 _("missing argument for %s at %s:%d"),
739                                 option->name, filename, linenum);
740                     return 1;
741                 }
742                 if (option->macroize && !strcmp(start, current[ARCH])) {
743                     char *s = buf;
744                     if (option->localize)
745                         *s++ = '_';
746                     strcpy(s, option->name);
747                     addMacro(&globalMacroContext, buf, NULL, chptr, RMIL_RPMRC);
748                 }
749             } else {
750                 start = NULL;   /* no arch */
751                 /* XXX for now only non-arch values can get macroized */
752                 if (option->macroize) {
753                     char *s = buf;
754                     if (option->localize)
755                         *s++ = '_';
756                     strcpy(s, option->name);
757                     addMacro(&globalMacroContext, buf, NULL, chptr, RMIL_RPMRC);
758                 }
759             }
760             rpmSetVarArch(option->var, chptr, start);
761         } else {
762             gotit = 0;
763
764             for (i = 0; i < RPM_MACHTABLE_COUNT; i++) {
765                 if (!strncmp(tables[i].key, start, strlen(tables[i].key)))
766                     break;
767             }
768
769             if (i < RPM_MACHTABLE_COUNT) {
770                 rest = start + strlen(tables[i].key);
771                 if (*rest == '_') rest++;
772
773                 if (!strcmp(rest, "compat")) {
774                     if (machCompatCacheAdd(chptr, filename, linenum,
775                                                 &tables[i].cache))
776                         return 1;
777                     gotit = 1;
778                 } else if (tables[i].hasTranslate &&
779                            !strcmp(rest, "translate")) {
780                     if (addDefault(&tables[i].defaults,
781                                    &tables[i].defaultsLength,
782                                    chptr, filename, linenum))
783                         return 1;
784                     gotit = 1;
785                 } else if (tables[i].hasCanon &&
786                            !strcmp(rest, "canon")) {
787                     if (addCanon(&tables[i].canons, &tables[i].canonsLength,
788                                  chptr, filename, linenum))
789                         return 1;
790                     gotit = 1;
791                 }
792             }
793
794             if (!gotit) {
795                 rpmError(RPMERR_RPMRC, _("bad option '%s' at %s:%d"),
796                             start, filename, linenum);
797             }
798         }
799     }
800
801     return 0;
802 }
803
804 static void defaultMachine(char ** arch, char ** os) {
805     static struct utsname un;
806     static int gotDefaults = 0;
807     char * chptr;
808     struct canonEntry * canon;
809
810     if (!gotDefaults) {
811         uname(&un);
812
813 #if !defined(__linux__)
814 #ifdef SNI
815         /* USUALLY un.sysname on sinix does start with the word "SINIX"
816          * let's be absolutely sure
817          */
818         sprintf(un.sysname,"SINIX");
819 #endif
820         if (!strcmp(un.sysname, "AIX")) {
821             strcpy(un.machine, __power_pc() ? "ppc" : "rs6000");
822             sprintf(un.sysname,"aix%s.%s",un.version,un.release);
823         }
824         else if (!strcmp(un.sysname, "SunOS")) {
825            if (!strncmp(un.release,"4", 1)) /* SunOS 4.x */ {
826               int fd;
827               for (fd=0;(un.release[fd] != 0 && (fd < sizeof(un.release)));fd++)
828                  if (!isdigit(un.release[fd]) && (un.release[fd] != '.')) {
829                     un.release[fd] = 0;
830                     break;
831                  }
832               sprintf(un.sysname,"sunos%s",un.release);
833            }
834            
835            else /* Solaris 2.x: n.x.x becomes n-3.x.x */
836               sprintf(un.sysname,"solaris%1d%s",atoi(un.release)-3,un.release+1+(atoi(un.release)/10));
837         }
838         else if (!strcmp(un.sysname, "HP-UX"))
839            /*make un.sysname look like hpux9.05 for example*/
840            sprintf(un.sysname,"hpux%s",strpbrk(un.release,"123456789"));
841         else if (!strcmp(un.sysname, "OSF1"))
842            /*make un.sysname look like osf3.2 for example*/
843            sprintf(un.sysname,"osf%s",strpbrk(un.release,"123456789"));
844         else if (!strncmp(un.sysname, "IP", 2))
845            un.sysname[2] = '\0';
846         else if (!strncmp(un.sysname, "SINIX", 5)) {
847            sprintf(un.sysname, "sinix%s",un.release);
848            if (!strncmp(un.machine, "RM", 2))
849               sprintf(un.machine, "mips");
850         }
851         else if ((!strncmp(un.machine, "34", 2) || \
852                  !strncmp(un.machine, "33", 2)) && \
853                  !strncmp(un.release, "4.0", 3)) {
854            /* we are on ncr-sysv4 */
855            char *prelid = NULL;
856            FD_t fd = fdOpen("/etc/.relid", O_RDONLY, 0700);
857            if (fdFileno(fd) > 0) {
858               chptr = (char *) calloc(256,1);
859               if (chptr != NULL) {
860                  int irelid = read(fd, (void *)chptr, 256);
861                  fdClose(fd);
862                  /* example: "112393 RELEASE 020200 Version 01 OS" */
863                  if (irelid > 0) {
864                     if ((prelid=strstr(chptr, "RELEASE "))){
865                        prelid += strlen("RELEASE ")+1;
866                        sprintf(un.sysname,"ncr-sysv4.%.*s",1,prelid);
867                     }
868                  }
869                  free (chptr);
870               }
871            }           
872            if (!prelid)
873               /* parsing /etc/.relid file failed */
874               strcpy(un.sysname,"ncr-sysv4");
875            /* wrong, just for now, find out how to look for i586 later*/
876            strcpy(un.machine,"i486");
877         }
878 #endif  /* __linux__ */
879                    
880         /* get rid of the hyphens in the sysname */
881         for (chptr = un.machine; *chptr; chptr++)
882             if (*chptr == '/') *chptr = '-';
883
884 #       if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL)
885             /* little endian */
886             strcpy(un.machine, "mipsel");
887 #       elif defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB)
888            /* big endian */
889                 strcpy(un.machine, "mipseb");
890 #       endif
891
892 #       if defined(__hpux) && defined(_SC_CPU_VERSION)
893         {
894 #           if !defined(CPU_PA_RISC1_2)
895 #                define CPU_PA_RISC1_2  0x211 /* HP PA-RISC1.2 */
896 #           endif
897 #           if !defined(CPU_PA_RISC2_0)
898 #               define CPU_PA_RISC2_0  0x214 /* HP PA-RISC2.0 */
899 #           endif
900             int cpu_version = sysconf(_SC_CPU_VERSION);
901
902 #           if defined(CPU_HP_MC68020)
903                 if (cpu_version == CPU_HP_MC68020)
904                     strcpy(un.machine, "m68k");
905 #           endif
906 #           if defined(CPU_HP_MC68030)
907                 if (cpu_version == CPU_HP_MC68030)
908                     strcpy(un.machine, "m68k");
909 #           endif
910 #           if defined(CPU_HP_MC68040)
911                 if (cpu_version == CPU_HP_MC68040)
912                     strcpy(un.machine, "m68k");
913 #           endif
914
915 #           if defined(CPU_PA_RISC1_0)
916                 if (cpu_version == CPU_PA_RISC1_0)
917                     strcpy(un.machine, "hppa1.0");
918 #           endif
919 #           if defined(CPU_PA_RISC1_1)
920                 if (cpu_version == CPU_PA_RISC1_1)
921                     strcpy(un.machine, "hppa1.1");
922 #           endif
923 #           if defined(CPU_PA_RISC1_2)
924                 if (cpu_version == CPU_PA_RISC1_2)
925                     strcpy(un.machine, "hppa1.2");
926 #           endif
927 #           if defined(CPU_PA_RISC2_0)
928                 if (cpu_version == CPU_PA_RISC2_0)
929                     strcpy(un.machine, "hppa2.0");
930 #           endif
931         }
932 #       endif   /* hpux */
933
934         /* the uname() result goes through the arch_canon table */
935         canon = lookupInCanonTable(un.machine,
936                                    tables[RPM_MACHTABLE_INSTARCH].canons,
937                                    tables[RPM_MACHTABLE_INSTARCH].canonsLength);
938         if (canon)
939             strcpy(un.machine, canon->short_name);
940
941         canon = lookupInCanonTable(un.sysname,
942                                    tables[RPM_MACHTABLE_INSTOS].canons,
943                                    tables[RPM_MACHTABLE_INSTOS].canonsLength);
944         if (canon)
945             strcpy(un.sysname, canon->short_name);
946         gotDefaults = 1;
947     }
948
949     if (arch) *arch = un.machine;
950     if (os) *os = un.sysname;
951 }
952
953 static char * rpmGetVarArch(int var, char * arch) {
954     struct rpmvarValue * next;
955
956     if (!arch) arch = current[ARCH];
957
958     if (arch) {
959         next = &values[var];
960         while (next) {
961             if (next->arch && !strcmp(next->arch, arch)) return next->value;
962             next = next->next;
963         }
964     }
965
966     next = values + var;
967     while (next && next->arch) next = next->next;
968
969     return next ? next->value : NULL;
970 }
971
972 char *rpmGetVar(int var)
973 {
974     return rpmGetVarArch(var, NULL);
975 }
976
977 int rpmGetBooleanVar(int var) {
978     char * val;
979     int num;
980     char * chptr;
981
982     val = rpmGetVar(var);
983     if (!val) return 0;
984
985     if (val[0] == 'y' || val[0] == 'Y') return 1;
986
987     num = strtol(val, &chptr, 0);
988     if (chptr && *chptr == '\0') {
989         return num != 0;
990     }
991
992     return 0;
993 }
994
995 void rpmSetVar(int var, const char *val) {
996     freeRpmVar(&values[var]);
997
998     values[var].arch = NULL;
999     values[var].next = NULL;
1000
1001     if (val)
1002         values[var].value = strdup(val);
1003     else
1004         values[var].value = NULL;
1005 }
1006
1007 /* this doesn't free the passed pointer! */
1008 static void freeRpmVar(struct rpmvarValue * orig) {
1009     struct rpmvarValue * next, * var = orig;
1010
1011     while (var) {
1012         next = var->next;
1013         if (var->arch) free(var->arch);
1014         if (var->value) free(var->value);
1015
1016         if (var != orig) free(var);
1017         var = next;
1018     }
1019 }
1020
1021 static void rpmSetVarArch(int var, char * val, char * arch) {
1022     struct rpmvarValue * next = values + var;
1023
1024     if (next->value) {
1025         if (arch) {
1026             while (next->next) {
1027                 if (next->arch && !strcmp(next->arch, arch)) break;
1028                 next = next->next;
1029             }
1030         } else {
1031             while (next->next) {
1032                 if (!next->arch) break;
1033                 next = next->next;
1034             }
1035         }
1036
1037         if (next->arch && arch && !strcmp(next->arch, arch)) {
1038             if (next->value) free(next->value);
1039             if (next->arch) free(next->arch);
1040         } else if (next->arch || arch) {
1041             next->next = malloc(sizeof(*next->next));
1042             next = next->next;
1043             next->next = NULL;
1044         }
1045     }
1046
1047     next->value = strdup(val);
1048     if (arch)
1049         next->arch = strdup(arch);
1050     else
1051         next->arch = NULL;
1052 }
1053
1054 void rpmSetTables(int archTable, int osTable) {
1055     char * arch, * os;
1056
1057     defaultMachine(&arch, &os);
1058
1059     if (currTables[ARCH] != archTable) {
1060         currTables[ARCH] = archTable;
1061         rebuildCompatTables(ARCH, arch);
1062     }
1063
1064     if (currTables[OS] != osTable) {
1065         currTables[OS] = osTable;
1066         rebuildCompatTables(OS, os);
1067     }
1068 }
1069
1070 int rpmMachineScore(int type, char * name) {
1071     struct machEquivInfo * info = machEquivSearch(&tables[type].equiv, name);
1072     return (info != NULL ? info->score : 0);
1073 }
1074
1075 void rpmGetMachine(char **arch, char **os)
1076 {
1077     if (arch)
1078         *arch = current[ARCH];
1079
1080     if (os)
1081         *os = current[OS];
1082 }
1083
1084 void rpmSetMachine(const char * arch, const char * os) {
1085     char * host_cpu, * host_os;
1086
1087     defaultMachine(&host_cpu, &host_os);
1088
1089     if (arch == NULL) {
1090         arch = host_cpu;
1091         if (tables[currTables[ARCH]].hasTranslate)
1092             arch = lookupInDefaultTable(arch,
1093                             tables[currTables[ARCH]].defaults,
1094                             tables[currTables[ARCH]].defaultsLength);
1095     }
1096
1097     if (os == NULL) {
1098         os = host_os;
1099         if (tables[currTables[OS]].hasTranslate)
1100             os = lookupInDefaultTable(os,
1101                             tables[currTables[OS]].defaults,
1102                             tables[currTables[OS]].defaultsLength);
1103     }
1104
1105     if (!current[ARCH] || strcmp(arch, current[ARCH])) {
1106         if (current[ARCH]) free(current[ARCH]);
1107         current[ARCH] = strdup(arch);
1108         rebuildCompatTables(ARCH, host_cpu);
1109     }
1110
1111     if (!current[OS] || strcmp(os, current[OS])) {
1112         if (current[OS]) free(current[OS]);
1113         current[OS] = strdup(os);
1114         /*
1115          * XXX Capitalizing the 'L' is needed to insure that old
1116          * XXX os-from-uname (e.g. "Linux") is compatible with the new
1117          * XXX os-from-platform (e.g "linux" from "sparc-*-linux").
1118          * XXX A copy of this string is embedded in headers and is
1119          * XXX used by rpmInstallPackage->{os,arch}Okay->rpmMachineScore->
1120          * XXX to verify correct arch/os from headers.
1121          */
1122         if (!strcmp(current[OS], "linux"))
1123             *current[OS]= 'L';
1124         rebuildCompatTables(OS, host_os);
1125     }
1126 }
1127
1128 static void rebuildCompatTables(int type, char * name) {
1129     machFindEquivs(&tables[currTables[type]].cache,
1130                    &tables[currTables[type]].equiv,
1131                    name);
1132 }
1133
1134 static void getMachineInfo(int type, char ** name, int * num) {
1135     struct canonEntry * canon;
1136     int which = currTables[type];
1137
1138     /* use the normal canon tables, even if we're looking up build stuff */
1139     if (which >= 2) which -= 2;
1140
1141     canon = lookupInCanonTable(current[type],
1142                                tables[which].canons,
1143                                tables[which].canonsLength);
1144
1145     if (canon) {
1146         if (num) *num = canon->num;
1147         if (name) *name = canon->short_name;
1148     } else {
1149         if (num) *num = 255;
1150         if (name) *name = current[type];
1151
1152         if (tables[currTables[type]].hasCanon) {
1153             rpmMessage(RPMMESS_WARNING, _("Unknown system: %s\n"), current[type]);
1154             rpmMessage(RPMMESS_WARNING, _("Please contact rpm-list@redhat.com\n"));
1155         }
1156     }
1157 }
1158
1159 void rpmGetArchInfo(char ** name, int * num) {
1160     getMachineInfo(ARCH, name, num);
1161 }
1162
1163 void rpmGetOsInfo(char ** name, int * num) {
1164     getMachineInfo(OS, name, num);
1165 }
1166
1167 void rpmRebuildTargetVars(const char ** canontarget)
1168 {
1169
1170     char * ca = NULL, * co = NULL;
1171     const char * target = NULL;
1172     int x;
1173
1174 /*
1175  * XXX getMacroBody() may be nuked -- I originally added it for tdyas and it's
1176  * kinda half-baked (remember, each macro is actually a stack so it's not
1177  * clear which body is intended).
1178  *
1179  * You can, however, always do
1180  *      char buf[BUFSIZ];
1181  *      strcpy(buf, "%_target")
1182  *      expandMacros(NULL, &globalMacroContext, buf, sizeof(buf)))
1183  *      target = strdup(buf);
1184  *
1185  */
1186     if ((target = getMacroBody(&globalMacroContext, "_target")) != NULL)
1187         target = strdup(target);
1188
1189     /* Rebuild the compat table to recalculate the current target arch.  */
1190
1191     rpmSetMachine(NULL, NULL);
1192     rpmSetTables(RPM_MACHTABLE_INSTARCH, RPM_MACHTABLE_INSTOS);
1193     rpmSetTables(RPM_MACHTABLE_BUILDARCH, RPM_MACHTABLE_BUILDOS);
1194
1195     rpmGetArchInfo(&ca,NULL);
1196     rpmGetOsInfo(&co,NULL);
1197
1198     if (ca == NULL) defaultMachine(&ca, NULL);
1199     if (co == NULL) defaultMachine(NULL, &co);
1200
1201     for (x = 0; ca[x]; x++)
1202         ca[x] = tolower(ca[x]);
1203     for (x = 0; co[x]; x++)
1204         co[x] = tolower(co[x]);
1205
1206     if (target == NULL) {
1207         char *ct = malloc(strlen(co)+strlen(ca)+2);
1208         sprintf(ct, "%s-%s", ca, co);
1209         target = ct;
1210     }
1211
1212 /*
1213  * XXX All this macro pokery/jiggery could be achieved (I think)
1214  * by doing a delayed
1215  *      initMacros(&globalMacroContext, PER-PLATFORM-MACRO-FILE-NAMES);
1216  * (I haven't looked at the code :-)
1217  *
1218  * In fact, if you want to get really sophisticated, you could encapsulate
1219  * within per-platform MacroContexts (but I'm not quite ready for that yet).
1220  */
1221     delMacro(&globalMacroContext, "_target");
1222     addMacro(&globalMacroContext, "_target", NULL, target, RMIL_RPMRC);
1223     delMacro(&globalMacroContext, "_target_cpu");
1224     addMacro(&globalMacroContext, "_target_cpu", NULL, ca, RMIL_RPMRC);
1225     delMacro(&globalMacroContext, "_target_os");
1226     addMacro(&globalMacroContext, "_target_os", NULL, co, RMIL_RPMRC);
1227
1228     if (canontarget)
1229         *canontarget = target;
1230 }
1231
1232 int rpmShowRC(FILE *f)
1233 {
1234     struct rpmOption *opt;
1235     int i;
1236     struct machEquivTable * equivTable;
1237
1238     /* the caller may set the build arch which should be printed here */
1239     fprintf(f, "ARCHITECTURE AND OS:\n");
1240     fprintf(f, "build arch            : %s\n", current[ARCH]);
1241
1242     fprintf(f, "compatible build archs:");
1243     equivTable = &tables[RPM_MACHTABLE_BUILDARCH].equiv;
1244     for (i = 0; i < equivTable->count; i++)
1245         fprintf(f," %s", equivTable->list[i].name);
1246     fprintf(f, "\n");
1247
1248     fprintf(f, "build os              : %s\n", current[OS]);
1249
1250     fprintf(f, "compatible build os's :");
1251     equivTable = &tables[RPM_MACHTABLE_BUILDOS].equiv;
1252     for (i = 0; i < equivTable->count; i++)
1253         fprintf(f," %s", equivTable->list[i].name);
1254     fprintf(f, "\n");
1255
1256     rpmSetTables(RPM_MACHTABLE_INSTARCH, RPM_MACHTABLE_INSTOS);
1257     rpmSetMachine(NULL, NULL);  /* XXX WTFO? Why bother? */
1258
1259     fprintf(f, "install arch          : %s\n", current[ARCH]);
1260     fprintf(f, "install os            : %s\n", current[OS]);
1261
1262     fprintf(f, "compatible archs      :");
1263     equivTable = &tables[RPM_MACHTABLE_INSTARCH].equiv;
1264     for (i = 0; i < equivTable->count; i++)
1265         fprintf(f," %s", equivTable->list[i].name);
1266     fprintf(f, "\n");
1267
1268     fprintf(f, "compatible os's       :");
1269     equivTable = &tables[RPM_MACHTABLE_INSTOS].equiv;
1270     for (i = 0; i < equivTable->count; i++)
1271         fprintf(f," %s", equivTable->list[i].name);
1272     fprintf(f, "\n");
1273
1274     fprintf(f, "\nRPMRC VALUES:\n");
1275     for (i = 0, opt = optionTable; i < optionTableSize; i++, opt++) {
1276         char *s = rpmGetVar(opt->var);
1277         if (s != NULL || rpmGetVerbosity() < RPMMESS_NORMAL)
1278             fprintf(f, "%-21s : %s\n", opt->name, s ? s : "(not set)");
1279     }
1280
1281     dumpMacroTable(&globalMacroContext);
1282
1283     return 0;
1284 }