6 #if HAVE_SYS_SYSTEMCFG_H
7 #include <sys/systemcfg.h>
18 /*@access FD_t@*/ /* compared with NULL */
20 /*@observer@*/ /*@unchecked@*/
21 static const char *defrcfiles = LIBRPMRC_FILENAME ":/etc/rpmrc:~/.rpmrc";
23 /*@observer@*/ /*@checked@*/
24 const char * macrofiles = MACROFILES;
26 typedef /*@owned@*/ const char * cptr_t;
28 typedef struct machCacheEntry_s {
35 typedef struct machCache_s {
40 typedef struct machEquivInfo_s {
45 typedef struct machEquivTable_s {
52 /* eventually, this arch will be replaced with a generic condition */
54 /*@only@*/ /*@null@*/ struct rpmvarValue * next;
61 /*@unused@*/ int required;
64 /*@unused@*/ struct rpmOptionValue * value;
67 typedef struct defaultEntry_s {
68 /*@owned@*/ /*@null@*/ const char * name;
69 /*@owned@*/ /*@null@*/ const char * defName;
72 typedef struct canonEntry_s {
73 /*@owned@*/ const char * name;
74 /*@owned@*/ const char * short_name;
78 /* tags are 'key'canon, 'key'translate, 'key'compat
80 * for giggles, 'key'_canon, 'key'_compat, and 'key'_canon will also work
82 typedef struct tableType_s {
83 /*@observer@*/ const char * const key;
85 const int hasTranslate;
86 struct machEquivTable_s equiv;
87 struct machCache_s cache;
88 defaultEntry defaults;
96 static struct tableType_s tables[RPM_MACHTABLE_COUNT] = {
99 { "buildarch", 0, 1 },
103 /* this *must* be kept in alphabetical order */
104 /* The order of the flags is archSpecific, required, macroize, localize */
107 static struct rpmOption optionTable[] = {
108 { "include", RPMVAR_INCLUDE, 0, 1, 0, 2 },
109 { "macrofiles", RPMVAR_MACROFILES, 0, 0, 0, 1 },
110 { "optflags", RPMVAR_OPTFLAGS, 1, 0, 1, 0 },
111 { "provides", RPMVAR_PROVIDES, 0, 0, 0, 0 },
116 static int optionTableSize = sizeof(optionTable) / sizeof(*optionTable);
122 static cptr_t current[2];
125 static int currTables[2] = { RPM_MACHTABLE_INSTOS, RPM_MACHTABLE_INSTARCH };
128 static struct rpmvarValue values[RPMVAR_NUM];
131 static int defaultsInitialized = 0;
134 static int doReadRC( /*@killref@*/ FD_t fd, const char * urlfn)
135 /*@globals rpmGlobalMacroContext,
136 fileSystem, internalState @*/
137 /*@modifies fd, fileSystem, internalState @*/;
139 static void rpmSetVarArch(int var, const char * val,
140 /*@null@*/ const char * arch)
141 /*@globals internalState @*/
142 /*@modifies internalState @*/;
144 static void rebuildCompatTables(int type, const char * name)
145 /*@globals internalState @*/
146 /*@modifies internalState @*/;
148 static void rpmRebuildTargetVars(/*@null@*/ const char **target, /*@null@*/ const char ** canontarget)
149 /*@globals rpmGlobalMacroContext,
150 fileSystem, internalState @*/
151 /*@modifies *canontarget, fileSystem, internalState @*/;
153 static int optionCompare(const void * a, const void * b)
156 return xstrcasecmp(((struct rpmOption *) a)->name,
157 ((struct rpmOption *) b)->name);
160 static /*@observer@*/ /*@null@*/ machCacheEntry
161 machCacheFindEntry(const machCache cache, const char * key)
166 for (i = 0; i < cache->size; i++)
167 if (!strcmp(cache->cache[i].name, key)) return cache->cache + i;
172 static int machCompatCacheAdd(char * name, const char * fn, int linenum,
174 /*@globals internalState @*/
175 /*@modifies *name, cache->cache, cache->size, internalState @*/
177 machCacheEntry entry = NULL;
183 while (*name && xisspace(*name)) name++;
186 while (*chptr && *chptr != ':') chptr++;
188 rpmError(RPMERR_RPMRC, _("missing second ':' at %s:%d\n"), fn, linenum);
190 } else if (chptr == name) {
191 rpmError(RPMERR_RPMRC, _("missing architecture name at %s:%d\n"), fn,
196 while (*chptr == ':' || xisspace(*chptr)) chptr--;
199 while (*equivs && xisspace(*equivs)) equivs++;
205 entry = machCacheFindEntry(cache, name);
207 for (i = 0; i < entry->count; i++)
208 entry->equivs[i] = _free(entry->equivs[i]);
209 entry->equivs = _free(entry->equivs);
215 cache->cache = xrealloc(cache->cache,
216 (cache->size + 1) * sizeof(*cache->cache));
217 entry = cache->cache + cache->size++;
218 entry->name = xstrdup(name);
223 if (delEntry) return 0;
225 while ((chptr = strtok(equivs, " ")) != NULL) {
227 if (chptr[0] == '\0') /* does strtok() return "" ever?? */
230 entry->equivs = xrealloc(entry->equivs, sizeof(*entry->equivs)
231 * (entry->count + 1));
233 entry->equivs = xmalloc(sizeof(*entry->equivs));
235 entry->equivs[entry->count] = xstrdup(chptr);
242 static /*@observer@*/ /*@null@*/ machEquivInfo
243 machEquivSearch(const machEquivTable table, const char * name)
248 for (i = 0; i < table->count; i++)
249 if (!xstrcasecmp(table->list[i].name, name))
250 return table->list + i;
255 static void machAddEquiv(machEquivTable table, const char * name,
257 /*@modifies table->list, table->count @*/
261 equiv = machEquivSearch(table, name);
264 table->list = xrealloc(table->list, (table->count + 1)
265 * sizeof(*table->list));
267 table->list = xmalloc(sizeof(*table->list));
269 table->list[table->count].name = xstrdup(name);
270 table->list[table->count++].score = distance;
274 static void machCacheEntryVisit(machCache cache,
275 machEquivTable table, const char * name, int distance)
276 /*@modifies table->list, table->count @*/
278 machCacheEntry entry;
281 entry = machCacheFindEntry(cache, name);
282 if (!entry || entry->visited) return;
286 for (i = 0; i < entry->count; i++) {
287 machAddEquiv(table, entry->equivs[i], distance);
290 for (i = 0; i < entry->count; i++) {
291 machCacheEntryVisit(cache, table, entry->equivs[i], distance + 1);
295 static void machFindEquivs(machCache cache, machEquivTable table,
297 /*@modifies cache->cache, table->list, table->count @*/
301 for (i = 0; i < cache->size; i++)
302 cache->cache[i].visited = 0;
304 while (table->count > 0) {
306 table->list[table->count].name = _free(table->list[table->count].name);
309 table->list = _free(table->list);
312 * We have a general graph built using strings instead of pointers.
313 * Yuck. We have to start at a point at traverse it, remembering how
314 * far away everything is.
316 /*@-nullstate@*/ /* FIX: table->list may be NULL. */
317 machAddEquiv(table, key, 1);
318 machCacheEntryVisit(cache, table, key, 2);
323 static int addCanon(canonEntry * table, int * tableLen, char * line,
324 const char * fn, int lineNum)
325 /*@globals internalState @*/
326 /*@modifies *table, *tableLen, *line, internalState @*/
331 const char * tshort_name;
335 /*@-unqualifiedtrans@*/
336 *table = xrealloc(*table, sizeof(**table) * (*tableLen));
337 /*@=unqualifiedtrans@*/
339 t = & ((*table)[*tableLen - 2]);
341 tname = strtok(line, ": \t");
342 tshort_name = strtok(NULL, " \t");
343 s = strtok(NULL, " \t");
344 if (! (tname && tshort_name && s)) {
345 rpmError(RPMERR_RPMRC, _("Incomplete data line at %s:%d\n"),
349 if (strtok(NULL, " \t")) {
350 rpmError(RPMERR_RPMRC, _("Too many args in data line at %s:%d\n"),
355 /*@-nullpass@*/ /* LCL: s != NULL here. */
356 tnum = strtoul(s, &s1, 10);
357 if ((*s1) || (s1 == s) || (tnum == ULONG_MAX)) {
358 rpmError(RPMERR_RPMRC, _("Bad arch/os number: %s (%s:%d)\n"), s,
360 return(RPMERR_RPMRC);
364 t[0].name = xstrdup(tname);
365 t[0].short_name = (tshort_name ? xstrdup(tshort_name) : xstrdup(""));
368 /* From A B C entry */
369 /* Add B B C entry */
370 t[1].name = (tshort_name ? xstrdup(tshort_name) : xstrdup(""));
371 t[1].short_name = (tshort_name ? xstrdup(tshort_name) : xstrdup(""));
377 static int addDefault(defaultEntry * table, int * tableLen, char * line,
378 const char * fn, int lineNum)
379 /*@globals internalState @*/
380 /*@modifies *table, *tableLen, *line, internalState @*/
385 /*@-unqualifiedtrans@*/
386 *table = xrealloc(*table, sizeof(**table) * (*tableLen));
387 /*@=unqualifiedtrans@*/
389 t = & ((*table)[*tableLen - 1]);
392 t->name = strtok(line, ": \t");
393 t->defName = strtok(NULL, " \t");
394 if (! (t->name && t->defName)) {
395 rpmError(RPMERR_RPMRC, _("Incomplete default line at %s:%d\n"),
399 if (strtok(NULL, " \t")) {
400 rpmError(RPMERR_RPMRC, _("Too many args in default line at %s:%d\n"),
405 t->name = xstrdup(t->name);
406 t->defName = (t->defName ? xstrdup(t->defName) : NULL);
412 static /*@null@*/ const canonEntry lookupInCanonTable(const char * name,
413 const canonEntry table, int tableLen)
418 if (strcmp(name, table[tableLen].name))
420 /*@-immediatetrans -retalias@*/
421 return &(table[tableLen]);
422 /*@=immediatetrans =retalias@*/
428 static /*@observer@*/ /*@null@*/
429 const char * lookupInDefaultTable(const char * name,
430 const defaultEntry table, int tableLen)
435 if (table[tableLen].name && !strcmp(name, table[tableLen].name))
436 return table[tableLen].defName;
442 static void setVarDefault(int var, const char * macroname, const char * val,
443 /*@null@*/ const char * body)
444 /*@globals rpmGlobalMacroContext,
446 /*@modifies internalState @*/
448 if (var >= 0) { /* XXX Dying ... */
449 if (rpmGetVar(var)) return;
454 addMacro(NULL, macroname, NULL, body, RMIL_DEFAULT);
457 static void setPathDefault(int var, const char * macroname, const char * subdir)
458 /*@globals rpmGlobalMacroContext,
460 /*@modifies internalState @*/
463 if (var >= 0) { /* XXX Dying ... */
467 if (rpmGetVar(var)) return;
469 topdir = rpmGetPath("%{_topdir}", NULL);
471 fn = alloca(strlen(topdir) + strlen(subdir) + 2);
473 if (fn[strlen(topdir) - 1] != '/')
478 topdir = _free(topdir);
481 if (macroname != NULL) {
482 #define _TOPDIRMACRO "%{_topdir}/"
483 char *body = alloca(sizeof(_TOPDIRMACRO) + strlen(subdir));
484 strcpy(body, _TOPDIRMACRO);
485 strcat(body, subdir);
486 addMacro(NULL, macroname, NULL, body, RMIL_DEFAULT);
491 /*@observer@*/ /*@unchecked@*/
492 static const char * prescriptenviron = "\n\
493 RPM_SOURCE_DIR=\"%{_sourcedir}\"\n\
494 RPM_BUILD_DIR=\"%{_builddir}\"\n\
495 RPM_OPT_FLAGS=\"%{optflags}\"\n\
496 RPM_ARCH=\"%{_arch}\"\n\
498 export RPM_SOURCE_DIR RPM_BUILD_DIR RPM_OPT_FLAGS RPM_ARCH RPM_OS\n\
499 RPM_DOC_DIR=\"%{_docdir}\"\n\
500 export RPM_DOC_DIR\n\
501 RPM_PACKAGE_NAME=\"%{name}\"\n\
502 RPM_PACKAGE_VERSION=\"%{version}\"\n\
503 RPM_PACKAGE_RELEASE=\"%{release}\"\n\
504 export RPM_PACKAGE_NAME RPM_PACKAGE_VERSION RPM_PACKAGE_RELEASE\n\
505 %{?buildroot:RPM_BUILD_ROOT=\"%{buildroot}\"\n\
506 export RPM_BUILD_ROOT\n}\
509 static void setDefaults(void)
510 /*@globals rpmGlobalMacroContext,
512 /*@modifies internalState @*/
515 addMacro(NULL, "_usr", NULL, "/usr", RMIL_DEFAULT);
516 addMacro(NULL, "_var", NULL, "/var", RMIL_DEFAULT);
518 addMacro(NULL, "_preScriptEnvironment",NULL, prescriptenviron,RMIL_DEFAULT);
520 setVarDefault(-1, "_topdir",
521 "/usr/src/redhat", "%{_usr}/src/redhat");
522 setVarDefault(-1, "_tmppath",
523 "/var/tmp", "%{_var}/tmp");
524 setVarDefault(-1, "_dbpath",
525 "/var/lib/rpm", "%{_var}/lib/rpm");
526 setVarDefault(-1, "_defaultdocdir",
527 "/usr/doc", "%{_usr}/doc");
529 setVarDefault(-1, "_rpmfilename",
530 "%%{ARCH}/%%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm",NULL);
532 setVarDefault(RPMVAR_OPTFLAGS, "optflags",
534 setVarDefault(-1, "sigtype",
536 setVarDefault(-1, "_buildshell",
539 setPathDefault(-1, "_builddir", "BUILD");
540 setPathDefault(-1, "_rpmdir", "RPMS");
541 setPathDefault(-1, "_srcrpmdir", "SRPMS");
542 setPathDefault(-1, "_sourcedir", "SOURCES");
543 setPathDefault(-1, "_specdir", "SPECS");
547 /*@-usedef@*/ /*@ FIX: se usage inconsistent, W2DO? */
548 static int doReadRC( /*@killref@*/ FD_t fd, const char * urlfn)
549 /*@globals rpmGlobalMacroContext,
550 fileSystem, internalState @*/
551 /*@modifies fd, fileSystem, internalState @*/
556 struct rpmOption searchOption, * option;
559 /* XXX really need rc = Slurp(fd, const char * filename, char ** buf) */
560 { off_t size = fdSize(fd);
561 size_t nb = (size >= 0 ? size : (8*BUFSIZ - 2));
566 next = alloca(nb + 2);
568 rc = Fread(next, sizeof(*next), nb, fd);
569 if (Ferror(fd) || (size > 0 && rc != nb)) { /* XXX Feof(fd) */
570 rpmError(RPMERR_RPMRC, _("Failed to read %s: %s.\n"), urlfn,
582 while (*next != '\0') {
587 /* Find end-of-line. */
588 while (*se && *se != '\n') se++;
589 if (*se != '\0') *se++ = '\0';
592 /* Trim leading spaces */
593 while (*s && xisspace(*s)) s++;
595 /* We used to allow comments to begin anywhere, but not anymore. */
596 if (*s == '#' || *s == '\0') continue;
598 /* Find end-of-keyword. */
600 while (*se && !xisspace(*se) && *se != ':') se++;
604 while (*se && xisspace(*se) && *se != ':') se++;
608 rpmError(RPMERR_RPMRC, _("missing ':' (found 0x%02x) at %s:%d\n"),
609 (unsigned)(0xff & *se), urlfn, linenum);
612 *se++ = '\0'; /* terminate keyword or option, point to value */
613 while (*se && xisspace(*se)) se++;
615 /* Find keyword in table */
616 searchOption.name = s;
617 option = bsearch(&searchOption, optionTable, optionTableSize,
618 sizeof(optionTable[0]), optionCompare);
620 if (option) { /* For configuration variables ... */
621 const char *arch, *val, *fn;
623 arch = val = fn = NULL;
625 rpmError(RPMERR_RPMRC, _("missing argument for %s at %s:%d\n"),
626 option->name, urlfn, linenum);
630 switch (option->var) {
635 while (*se && !xisspace(*se)) se++;
636 if (*se != '\0') *se++ = '\0';
638 rpmRebuildTargetVars(NULL, NULL);
640 fn = rpmGetPath(s, NULL);
641 if (fn == NULL || *fn == '\0') {
642 rpmError(RPMERR_RPMRC, _("%s expansion failed at %s:%d \"%s\"\n"),
643 option->name, urlfn, linenum, s);
649 fdinc = Fopen(fn, "r.fpio");
650 if (fdinc == NULL || Ferror(fdinc)) {
651 rpmError(RPMERR_RPMRC, _("cannot open %s at %s:%d: %s\n"),
652 fn, urlfn, linenum, Fstrerror(fdinc));
655 rc = doReadRC(fdinc, fn);
659 continue; /* XXX don't save include value as var/macro */
660 } /*@notreached@*/ /*@switchbreak@*/ break;
661 case RPMVAR_MACROFILES:
662 fn = rpmGetPath(se, NULL);
663 if (fn == NULL || *fn == '\0') {
664 rpmError(RPMERR_RPMRC, _("%s expansion failed at %s:%d \"%s\"\n"),
665 option->name, urlfn, linenum, fn);
670 /*@switchbreak@*/ break;
671 case RPMVAR_PROVIDES:
673 s = rpmGetVar(RPMVAR_PROVIDES);
674 if (s == NULL) s = "";
675 fn = t = xmalloc(strlen(s) + strlen(se) + 2);
676 while (*s != '\0') *t++ = *s++;
678 while (*se != '\0') *t++ = *se++;
681 } /*@switchbreak@*/ break;
683 /*@switchbreak@*/ break;
686 if (option->archSpecific) {
688 while (*se && !xisspace(*se)) se++;
690 rpmError(RPMERR_RPMRC,
691 _("missing architecture for %s at %s:%d\n"),
692 option->name, urlfn, linenum);
696 while (*se && xisspace(*se)) se++;
698 rpmError(RPMERR_RPMRC,
699 _("missing argument for %s at %s:%d\n"),
700 option->name, urlfn, linenum);
707 /* Only add macros if appropriate for this arch */
708 if (option->macroize &&
709 (arch == NULL || !strcmp(arch, current[ARCH]))) {
711 n = name = xmalloc(strlen(option->name)+2);
712 if (option->localize)
714 strcpy(n, option->name);
715 addMacro(NULL, name, NULL, val, RMIL_RPMRC);
718 rpmSetVarArch(option->var, val, arch);
721 } else { /* For arch/os compatibilty tables ... */
727 for (i = 0; i < RPM_MACHTABLE_COUNT; i++) {
728 if (!strncmp(tables[i].key, s, strlen(tables[i].key)))
729 /*@innerbreak@*/ break;
732 if (i < RPM_MACHTABLE_COUNT) {
733 const char *rest = s + strlen(tables[i].key);
734 if (*rest == '_') rest++;
736 if (!strcmp(rest, "compat")) {
737 if (machCompatCacheAdd(se, urlfn, linenum,
741 } else if (tables[i].hasTranslate &&
742 !strcmp(rest, "translate")) {
743 if (addDefault(&tables[i].defaults,
744 &tables[i].defaultsLength,
748 } else if (tables[i].hasCanon &&
749 !strcmp(rest, "canon")) {
750 if (addCanon(&tables[i].canons, &tables[i].canonsLength,
758 rpmError(RPMERR_RPMRC, _("bad option '%s' at %s:%d\n"),
769 # if defined(__linux__) && defined(__i386__)
774 * Generic CPUID function
776 static inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx)
777 /*@modifies *eax, *ebx, *ecx, *edx @*/
780 *eax = *ebx = *ecx = *edx = 0;
783 __asm__("pushl %%ebx; cpuid; movl %%ebx,%1; popl %%ebx"
784 : "=a"(*eax), "=g"(*ebx), "=&c"(*ecx), "=&d"(*edx)
788 : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
795 * CPUID functions returning a single datum
797 static inline unsigned int cpuid_eax(unsigned int op)
803 __asm__("pushl %%ebx; cpuid; popl %%ebx"
804 : "=a" (val) : "a" (op) : "ecx", "edx");
807 : "=a" (val) : "a" (op) : "ebx", "ecx", "edx");
812 static inline unsigned int cpuid_ebx(unsigned int op)
815 unsigned int tmp, val;
818 __asm__("pushl %%ebx; cpuid; movl %%ebx,%1; popl %%ebx"
819 : "=a" (tmp), "=g" (val) : "a" (op) : "ecx", "edx");
822 : "=a" (tmp), "=b" (val) : "a" (op) : "ecx", "edx");
827 static inline unsigned int cpuid_ecx(unsigned int op)
830 unsigned int tmp, val;
832 __asm__("pushl %%ebx; cpuid; popl %%ebx"
833 : "=a" (tmp), "=c" (val) : "a" (op) : "edx");
836 : "=a" (tmp), "=c" (val) : "a" (op) : "ebx", "edx");
842 static inline unsigned int cpuid_edx(unsigned int op)
845 unsigned int tmp, val;
847 __asm__("pushl %%ebx; cpuid; popl %%ebx"
848 : "=a" (tmp), "=d" (val) : "a" (op) : "ecx");
851 : "=a" (tmp), "=d" (val) : "a" (op) : "ebx", "ecx");
858 static sigjmp_buf jenv;
860 static inline void model3(int _unused)
861 /*@globals internalState @*/
862 /*@modifies internalState @*/
867 static inline int RPMClass(void)
868 /*@globals internalState @*/
869 /*@modifies internalState @*/
872 unsigned int tfms, junk, cap;
874 signal(SIGILL, model3);
876 if(sigsetjmp(jenv, 1))
879 if(cpuid_eax(0x000000000)==0)
881 cpuid(0x000000001, &tfms, &junk, &junk, &cap);
894 /* should only be called for model 6 CPU's */
895 static int is_athlon(void)
898 unsigned int eax, ebx, ecx, edx;
902 cpuid (0, &eax, &ebx, &ecx, &edx);
904 /* If you care about space, you can just check ebx, ecx and edx directly
905 instead of forming a string first and then doing a strcmp */
906 memset(vendor, 0, sizeof(vendor));
909 vendor[i] = (unsigned char) (ebx >>(8*i));
911 vendor[4+i] = (unsigned char) (edx >>(8*i));
913 vendor[8+i] = (unsigned char) (ecx >>(8*i));
915 if (strcmp(vendor, "AuthenticAMD") != 0)
923 static void defaultMachine(/*@out@*/ const char ** arch,
924 /*@out@*/ const char ** os)
925 /*@globals fileSystem@*/
926 /*@modifies *arch, *os, fileSystem @*/
928 static struct utsname un;
929 static int gotDefaults = 0;
938 #if !defined(__linux__)
940 /* USUALLY un.sysname on sinix does start with the word "SINIX"
941 * let's be absolutely sure
943 strncpy(un.sysname, "SINIX", sizeof(un.sysname));
946 if (!strcmp(un.sysname, "AIX")) {
947 strcpy(un.machine, __power_pc() ? "ppc" : "rs6000");
948 sprintf(un.sysname,"aix%s.%s", un.version, un.release);
950 else if (!strcmp(un.sysname, "SunOS")) {
951 if (!strncmp(un.release,"4", 1)) /* SunOS 4.x */ {
954 (un.release[fd] != 0 && (fd < sizeof(un.release)));
956 if (!xisdigit(un.release[fd]) && (un.release[fd] != '.')) {
961 sprintf(un.sysname,"sunos%s",un.release);
964 else /* Solaris 2.x: n.x.x becomes n-3.x.x */
965 sprintf(un.sysname, "solaris%1d%s", atoi(un.release)-3,
966 un.release+1+(atoi(un.release)/10));
968 else if (!strcmp(un.sysname, "HP-UX"))
969 /*make un.sysname look like hpux9.05 for example*/
970 sprintf(un.sysname, "hpux%s", strpbrk(un.release, "123456789"));
971 else if (!strcmp(un.sysname, "OSF1"))
972 /*make un.sysname look like osf3.2 for example*/
973 sprintf(un.sysname, "osf%s", strpbrk(un.release, "123456789"));
974 else if (!strncmp(un.sysname, "IP", 2))
975 un.sysname[2] = '\0';
976 else if (!strncmp(un.sysname, "SINIX", 5)) {
977 sprintf(un.sysname, "sinix%s",un.release);
978 if (!strncmp(un.machine, "RM", 2))
979 sprintf(un.machine, "mips");
981 else if ((!strncmp(un.machine, "34", 2) ||
982 !strncmp(un.machine, "33", 2)) && \
983 !strncmp(un.release, "4.0", 3))
985 /* we are on ncr-sysv4 */
986 char * prelid = NULL;
987 FD_t fd = Fopen("/etc/.relid", "r.fdio");
990 if (fd != NULL && !Ferror(fd)) {
991 chptr = xcalloc(1, 256);
992 { int irelid = Fread(chptr, sizeof(*chptr), 256, fd);
994 /* example: "112393 RELEASE 020200 Version 01 OS" */
996 if ((prelid = strstr(chptr, "RELEASE "))){
997 prelid += strlen("RELEASE ")+1;
998 sprintf(un.sysname,"ncr-sysv4.%.*s",1,prelid);
1003 chptr = _free (chptr);
1006 if (!gotit) /* parsing /etc/.relid file failed? */
1007 strcpy(un.sysname,"ncr-sysv4");
1008 /* wrong, just for now, find out how to look for i586 later*/
1009 strcpy(un.machine,"i486");
1012 #endif /* __linux__ */
1014 /* get rid of the hyphens in the sysname */
1015 for (chptr = un.machine; *chptr != '\0'; chptr++)
1016 if (*chptr == '/') *chptr = '-';
1018 # if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL)
1020 strcpy(un.machine, "mipsel");
1021 # elif defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB)
1023 strcpy(un.machine, "mipseb");
1026 # if defined(__hpux) && defined(_SC_CPU_VERSION)
1028 # if !defined(CPU_PA_RISC1_2)
1029 # define CPU_PA_RISC1_2 0x211 /* HP PA-RISC1.2 */
1031 # if !defined(CPU_PA_RISC2_0)
1032 # define CPU_PA_RISC2_0 0x214 /* HP PA-RISC2.0 */
1034 int cpu_version = sysconf(_SC_CPU_VERSION);
1036 # if defined(CPU_HP_MC68020)
1037 if (cpu_version == CPU_HP_MC68020)
1038 strcpy(un.machine, "m68k");
1040 # if defined(CPU_HP_MC68030)
1041 if (cpu_version == CPU_HP_MC68030)
1042 strcpy(un.machine, "m68k");
1044 # if defined(CPU_HP_MC68040)
1045 if (cpu_version == CPU_HP_MC68040)
1046 strcpy(un.machine, "m68k");
1049 # if defined(CPU_PA_RISC1_0)
1050 if (cpu_version == CPU_PA_RISC1_0)
1051 strcpy(un.machine, "hppa1.0");
1053 # if defined(CPU_PA_RISC1_1)
1054 if (cpu_version == CPU_PA_RISC1_1)
1055 strcpy(un.machine, "hppa1.1");
1057 # if defined(CPU_PA_RISC1_2)
1058 if (cpu_version == CPU_PA_RISC1_2)
1059 strcpy(un.machine, "hppa1.2");
1061 # if defined(CPU_PA_RISC2_0)
1062 if (cpu_version == CPU_PA_RISC2_0)
1063 strcpy(un.machine, "hppa2.0");
1068 # if HAVE_PERSONALITY && defined(__linux__) && defined(__sparc__)
1069 if (!strcmp(un.machine, "sparc")) {
1070 #define PERS_LINUX 0x00000000
1071 #define PERS_LINUX_32BIT 0x00800000
1072 #define PERS_LINUX32 0x00000008
1074 extern int personality(unsigned long);
1077 oldpers = personality(PERS_LINUX_32BIT);
1078 if (oldpers != -1) {
1079 if (personality(PERS_LINUX) != -1) {
1081 if (! strcmp(un.machine, "sparc64")) {
1082 strcpy(un.machine, "sparcv9");
1083 oldpers = PERS_LINUX32;
1086 personality(oldpers);
1089 # endif /* sparc*-linux */
1091 # if defined(__GNUC__) && defined(__alpha__)
1093 unsigned long amask, implver;
1094 register long v0 __asm__("$0") = -1;
1095 __asm__ (".long 0x47e00c20" : "=r"(v0) : "0"(v0));
1097 __asm__ (".long 0x47e03d80" : "=r"(v0));
1102 case 0: strcpy(un.machine, "alphaev5"); break;
1103 case 1: strcpy(un.machine, "alphaev56"); break;
1104 case 0x101: strcpy(un.machine, "alphapca56"); break;
1109 case 0x303: strcpy(un.machine, "alphaev6"); break;
1110 case 0x307: strcpy(un.machine, "alphaev67"); break;
1117 # if defined(__linux__) && defined(__i386__)
1119 char class = (char) (RPMClass() | '0');
1121 if (class == '6' && is_athlon())
1122 strcpy(un.machine, "athlon");
1123 else if (strchr("3456", un.machine[1]) && un.machine[1] != class)
1124 un.machine[1] = class;
1128 # if defined(__linux__) && defined(__powerpc__)
1131 __asm__ __volatile__ ("mfspr %0, 287" : "=r" (pvr));
1135 strcpy(un.machine, "ppcpseries");
1136 else if ( (pvr == 0x36) || (pvr == 0x37) )
1137 strcpy(un.machine, "ppciseries");
1139 strcpy(un.machine, "ppc");
1143 /* the uname() result goes through the arch_canon table */
1144 canon = lookupInCanonTable(un.machine,
1145 tables[RPM_MACHTABLE_INSTARCH].canons,
1146 tables[RPM_MACHTABLE_INSTARCH].canonsLength);
1148 strcpy(un.machine, canon->short_name);
1150 canon = lookupInCanonTable(un.sysname,
1151 tables[RPM_MACHTABLE_INSTOS].canons,
1152 tables[RPM_MACHTABLE_INSTOS].canonsLength);
1154 strcpy(un.sysname, canon->short_name);
1158 if (arch) *arch = un.machine;
1159 if (os) *os = un.sysname;
1162 static /*@observer@*/ /*@null@*/
1163 const char * rpmGetVarArch(int var, /*@null@*/ const char * arch)
1166 const struct rpmvarValue * next;
1168 if (arch == NULL) arch = current[ARCH];
1171 next = &values[var];
1173 if (next->arch && !strcmp(next->arch, arch)) return next->value;
1178 next = values + var;
1179 while (next && next->arch) next = next->next;
1181 return next ? next->value : NULL;
1184 const char *rpmGetVar(int var)
1186 return rpmGetVarArch(var, NULL);
1189 /* this doesn't free the passed pointer! */
1190 static void freeRpmVar(/*@only@*/ struct rpmvarValue * orig)
1191 /*@modifies *orig @*/
1193 struct rpmvarValue * next, * var = orig;
1197 var->arch = _free(var->arch);
1198 var->value = _free(var->value);
1201 if (var != orig) var = _free(var);
1207 void rpmSetVar(int var, const char * val)
1209 /*@-immediatetrans@*/
1210 freeRpmVar(&values[var]);
1211 /*@=immediatetrans@*/
1212 values[var].value = (val ? xstrdup(val) : NULL);
1215 static void rpmSetVarArch(int var, const char * val, const char * arch)
1218 struct rpmvarValue * next = values + var;
1222 while (next->next) {
1223 if (next->arch && !strcmp(next->arch, arch)) break;
1227 while (next->next) {
1228 if (!next->arch) break;
1233 /*@-nullpass@*/ /* LCL: arch != NULL here. */
1234 if (next->arch && arch && !strcmp(next->arch, arch)) {
1236 next->value = _free(next->value);
1237 next->arch = _free(next->arch);
1238 } else if (next->arch || arch) {
1239 next->next = xmalloc(sizeof(*next->next));
1247 next->value = xstrdup(val); /* XXX memory leak, hard to plug */
1248 next->arch = (arch ? xstrdup(arch) : NULL);
1251 void rpmSetTables(int archTable, int osTable)
1253 const char * arch, * os;
1255 defaultMachine(&arch, &os);
1257 if (currTables[ARCH] != archTable) {
1258 currTables[ARCH] = archTable;
1259 rebuildCompatTables(ARCH, arch);
1262 if (currTables[OS] != osTable) {
1263 currTables[OS] = osTable;
1264 rebuildCompatTables(OS, os);
1268 int rpmMachineScore(int type, const char * name)
1270 machEquivInfo info = machEquivSearch(&tables[type].equiv, name);
1271 return (info != NULL ? info->score : 0);
1274 void rpmGetMachine(const char ** arch, const char ** os)
1277 *arch = current[ARCH];
1283 void rpmSetMachine(const char * arch, const char * os)
1285 const char * host_cpu, * host_os;
1287 defaultMachine(&host_cpu, &host_os);
1291 if (tables[currTables[ARCH]].hasTranslate)
1292 arch = lookupInDefaultTable(arch,
1293 tables[currTables[ARCH]].defaults,
1294 tables[currTables[ARCH]].defaultsLength);
1296 if (arch == NULL) return; /* XXX can't happen */
1300 if (tables[currTables[OS]].hasTranslate)
1301 os = lookupInDefaultTable(os,
1302 tables[currTables[OS]].defaults,
1303 tables[currTables[OS]].defaultsLength);
1305 if (os == NULL) return; /* XXX can't happen */
1307 if (!current[ARCH] || strcmp(arch, current[ARCH])) {
1308 current[ARCH] = _free(current[ARCH]);
1309 current[ARCH] = xstrdup(arch);
1310 rebuildCompatTables(ARCH, host_cpu);
1313 if (!current[OS] || strcmp(os, current[OS])) {
1314 char * t = xstrdup(os);
1315 current[OS] = _free(current[OS]);
1317 * XXX Capitalizing the 'L' is needed to insure that old
1318 * XXX os-from-uname (e.g. "Linux") is compatible with the new
1319 * XXX os-from-platform (e.g "linux" from "sparc-*-linux").
1320 * XXX A copy of this string is embedded in headers and is
1321 * XXX used by rpmInstallPackage->{os,arch}Okay->rpmMachineScore->
1322 * XXX to verify correct arch/os from headers.
1324 if (!strcmp(t, "linux"))
1328 rebuildCompatTables(OS, host_os);
1332 static void rebuildCompatTables(int type, const char * name)
1335 machFindEquivs(&tables[currTables[type]].cache,
1336 &tables[currTables[type]].equiv,
1340 static void getMachineInfo(int type, /*@null@*/ /*@out@*/ const char ** name,
1341 /*@null@*/ /*@out@*/int * num)
1342 /*@modifies *name, *num @*/
1345 int which = currTables[type];
1347 /* use the normal canon tables, even if we're looking up build stuff */
1348 if (which >= 2) which -= 2;
1350 canon = lookupInCanonTable(current[type],
1351 tables[which].canons,
1352 tables[which].canonsLength);
1355 if (num) *num = canon->num;
1356 if (name) *name = canon->short_name;
1358 if (num) *num = 255;
1359 if (name) *name = current[type];
1361 if (tables[currTables[type]].hasCanon) {
1362 rpmMessage(RPMMESS_WARNING, _("Unknown system: %s\n"), current[type]);
1363 rpmMessage(RPMMESS_WARNING, _("Please contact rpm-list@redhat.com\n"));
1368 void rpmGetArchInfo(const char ** name, int * num)
1370 getMachineInfo(ARCH, name, num);
1373 void rpmGetOsInfo(const char ** name, int * num)
1375 getMachineInfo(OS, name, num);
1378 void rpmRebuildTargetVars(const char ** target, const char ** canontarget)
1381 char *ca = NULL, *co = NULL, *ct = NULL;
1384 /* Rebuild the compat table to recalculate the current target arch. */
1386 rpmSetMachine(NULL, NULL);
1387 rpmSetTables(RPM_MACHTABLE_INSTARCH, RPM_MACHTABLE_INSTOS);
1388 rpmSetTables(RPM_MACHTABLE_BUILDARCH, RPM_MACHTABLE_BUILDOS);
1391 if (target && *target) {
1393 /* Set arch and os from specified build target */
1394 ca = xstrdup(*target);
1395 if ((c = strchr(ca, '-')) != NULL) {
1398 if ((co = strrchr(c, '-')) == NULL) {
1401 if (!xstrcasecmp(co, "-gnu"))
1403 if ((co = strrchr(c, '-')) == NULL)
1408 if (co != NULL) co = xstrdup(co);
1411 const char *a = NULL;
1412 const char *o = NULL;
1413 /* Set build target from rpm arch and os */
1414 rpmGetArchInfo(&a, NULL);
1415 ca = (a) ? xstrdup(a) : NULL;
1416 rpmGetOsInfo(&o, NULL);
1417 co = (o) ? xstrdup(o) : NULL;
1421 /* If still not set, Set target arch/os from default uname(2) values */
1423 const char *a = NULL;
1424 defaultMachine(&a, NULL);
1425 ca = (a) ? xstrdup(a) : NULL;
1427 for (x = 0; ca[x] != '\0'; x++)
1428 ca[x] = xtolower(ca[x]);
1431 const char *o = NULL;
1432 defaultMachine(NULL, &o);
1433 co = (o) ? xstrdup(o) : NULL;
1435 for (x = 0; co[x] != '\0'; x++)
1436 co[x] = xtolower(co[x]);
1438 /* XXX For now, set canonical target to arch-os */
1440 ct = xmalloc(strlen(ca) + sizeof("-") + strlen(co));
1441 sprintf(ct, "%s-%s", ca, co);
1445 * XXX All this macro pokery/jiggery could be achieved by doing a delayed
1446 * rpmInitMacros(NULL, PER-PLATFORM-MACRO-FILE-NAMES);
1448 delMacro(NULL, "_target");
1449 addMacro(NULL, "_target", NULL, ct, RMIL_RPMRC);
1450 delMacro(NULL, "_target_cpu");
1451 addMacro(NULL, "_target_cpu", NULL, ca, RMIL_RPMRC);
1452 delMacro(NULL, "_target_os");
1453 addMacro(NULL, "_target_os", NULL, co, RMIL_RPMRC);
1455 * XXX Make sure that per-arch optflags is initialized correctly.
1457 { const char *optflags = rpmGetVarArch(RPMVAR_OPTFLAGS, ca);
1458 if (optflags != NULL) {
1459 delMacro(NULL, "optflags");
1460 addMacro(NULL, "optflags", NULL, optflags, RMIL_RPMRC);
1476 void rpmFreeRpmrc(void)
1480 for (i = 0; i < RPM_MACHTABLE_COUNT; i++) {
1483 if (t->equiv.list) {
1484 for (j = 0; j < t->equiv.count; j++)
1485 t->equiv.list[j].name = _free(t->equiv.list[j].name);
1486 t->equiv.list = _free(t->equiv.list);
1489 if (t->cache.cache) {
1490 for (j = 0; j < t->cache.size; j++) {
1492 e = t->cache.cache + j;
1494 /*@innercontinue@*/ continue;
1495 e->name = _free(e->name);
1497 for (k = 0; k < e->count; k++)
1498 e->equivs[k] = _free(e->equivs[k]);
1499 e->equivs = _free(e->equivs);
1502 t->cache.cache = _free(t->cache.cache);
1506 for (j = 0; j < t->defaultsLength; j++) {
1507 t->defaults[j].name = _free(t->defaults[j].name);
1508 t->defaults[j].defName = _free(t->defaults[j].defName);
1510 t->defaults = _free(t->defaults);
1511 t->defaultsLength = 0;
1514 for (j = 0; j < t->canonsLength; j++) {
1515 t->canons[j].name = _free(t->canons[j].name);
1516 t->canons[j].short_name = _free(t->canons[j].short_name);
1518 t->canons = _free(t->canons);
1519 t->canonsLength = 0;
1523 for (i = 0; i < RPMVAR_NUM; i++) {
1524 /*@only@*/ /*@null@*/ struct rpmvarValue * vp;
1525 while ((vp = values[i].next) != NULL) {
1526 values[i].next = vp->next;
1527 vp->value = _free(vp->value);
1528 vp->arch = _free(vp->arch);
1531 values[i].value = _free(values[i].value);
1532 values[i].arch = _free(values[i].arch);
1534 current[OS] = _free(current[OS]);
1535 current[ARCH] = _free(current[ARCH]);
1536 defaultsInitialized = 0;
1537 /*@-nullstate@*/ /* FIX: current may be NULL */
1543 * Read rpmrc (and macro) configuration file(s).
1544 * @param rcfiles colon separated files to read (NULL uses default)
1545 * @return 0 on succes
1547 static int rpmReadRC(/*@null@*/ const char * rcfiles)
1548 /*@globals rpmGlobalMacroContext, rpmCLIMacroContext,
1549 fileSystem, internalState @*/
1550 /*@modifies rpmGlobalMacroContext,
1551 fileSystem, internalState @*/
1553 char *myrcfiles, *r, *re;
1556 if (!defaultsInitialized) {
1558 defaultsInitialized = 1;
1561 if (rcfiles == NULL)
1562 rcfiles = defrcfiles;
1564 /* Read each file in rcfiles. */
1566 for (r = myrcfiles = xstrdup(rcfiles); r && *r != '\0'; r = re) {
1570 /* Get pointer to rest of files */
1571 for (re = r; (re = strchr(re, ':')) != NULL; re++) {
1572 if (!(re[1] == '/' && re[2] == '/'))
1573 /*@innerbreak@*/ break;
1575 if (re && *re == ':')
1580 /* Expand ~/ to $HOME/ */
1582 if (r[0] == '~' && r[1] == '/') {
1583 const char * home = getenv("HOME");
1585 /* XXX Only /usr/lib/rpm/rpmrc must exist in default rcfiles list */
1586 if (rcfiles == defrcfiles && myrcfiles != r)
1588 rpmError(RPMERR_RPMRC, _("Cannot expand %s\n"), r);
1592 if (strlen(home) > (sizeof(fn) - strlen(r))) {
1593 rpmError(RPMERR_RPMRC, _("Cannot read %s, HOME is too large.\n"),
1601 strncat(fn, r, sizeof(fn) - (strlen(fn) + 1));
1602 fn[sizeof(fn)-1] = '\0';
1604 /* Read another rcfile */
1605 fd = Fopen(fn, "r.fpio");
1606 if (fd == NULL || Ferror(fd)) {
1607 /* XXX Only /usr/lib/rpm/rpmrc must exist in default rcfiles list */
1608 if (rcfiles == defrcfiles && myrcfiles != r)
1610 rpmError(RPMERR_RPMRC, _("Unable to open %s for reading: %s.\n"),
1615 rc = doReadRC(fd, fn);
1619 myrcfiles = _free(myrcfiles);
1623 rpmSetMachine(NULL, NULL); /* XXX WTFO? Why bother? */
1625 { const char *mfpath;
1627 if ((mfpath = rpmGetVar(RPMVAR_MACROFILES)) != NULL) {
1628 mfpath = xstrdup(mfpath);
1629 rpmInitMacros(NULL, mfpath);
1630 mfpath = _free(mfpath);
1638 int rpmReadConfigFiles(const char * file, const char * target)
1641 /* Preset target macros */
1642 /*@-nullstate@*/ /* FIX: target can be NULL */
1643 rpmRebuildTargetVars(&target, NULL);
1645 /* Read the files */
1646 if (rpmReadRC(file)) return -1;
1648 /* Reset target macros */
1649 rpmRebuildTargetVars(&target, NULL);
1652 /* Finally set target platform */
1653 { const char *cpu = rpmExpand("%{_target_cpu}", NULL);
1654 const char *os = rpmExpand("%{_target_os}", NULL);
1655 rpmSetMachine(cpu, os);
1663 int rpmShowRC(FILE * fp)
1665 struct rpmOption *opt;
1667 machEquivTable equivTable;
1669 /* the caller may set the build arch which should be printed here */
1670 fprintf(fp, "ARCHITECTURE AND OS:\n");
1671 fprintf(fp, "build arch : %s\n", current[ARCH]);
1673 fprintf(fp, "compatible build archs:");
1674 equivTable = &tables[RPM_MACHTABLE_BUILDARCH].equiv;
1675 for (i = 0; i < equivTable->count; i++)
1676 fprintf(fp," %s", equivTable->list[i].name);
1679 fprintf(fp, "build os : %s\n", current[OS]);
1681 fprintf(fp, "compatible build os's :");
1682 equivTable = &tables[RPM_MACHTABLE_BUILDOS].equiv;
1683 for (i = 0; i < equivTable->count; i++)
1684 fprintf(fp," %s", equivTable->list[i].name);
1687 rpmSetTables(RPM_MACHTABLE_INSTARCH, RPM_MACHTABLE_INSTOS);
1688 rpmSetMachine(NULL, NULL); /* XXX WTFO? Why bother? */
1690 fprintf(fp, "install arch : %s\n", current[ARCH]);
1691 fprintf(fp, "install os : %s\n", current[OS]);
1693 fprintf(fp, "compatible archs :");
1694 equivTable = &tables[RPM_MACHTABLE_INSTARCH].equiv;
1695 for (i = 0; i < equivTable->count; i++)
1696 fprintf(fp," %s", equivTable->list[i].name);
1699 fprintf(fp, "compatible os's :");
1700 equivTable = &tables[RPM_MACHTABLE_INSTOS].equiv;
1701 for (i = 0; i < equivTable->count; i++)
1702 fprintf(fp," %s", equivTable->list[i].name);
1705 fprintf(fp, "\nRPMRC VALUES:\n");
1706 for (i = 0, opt = optionTable; i < optionTableSize; i++, opt++) {
1707 const char *s = rpmGetVar(opt->var);
1708 if (s != NULL || rpmIsVerbose())
1709 fprintf(fp, "%-21s : %s\n", opt->name, s ? s : "(not set)");
1713 fprintf(fp, "Features supported by rpmlib:\n");
1714 rpmShowRpmlibProvides(fp);
1717 rpmDumpMacroTable(NULL, fp);