From 210a25afdeceb386b8dac84c0fedcaa12ca36370 Mon Sep 17 00:00:00 2001 From: Marek Blaha Date: Tue, 5 Dec 2023 11:30:49 +0100 Subject: [PATCH 1/2] vars: Use uname() for architecture autodetection The %_host_cpu macro is not runtime detected, it's only usable to detect which architecture rpm was built for. To detect that dnf5 is running on 32bit personality on x86_64 we need to use uname(). The code is taken from libdnf (see libdnf/hy-util.cpp). Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2252671 --- libdnf5/conf/vars.cpp | 46 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/libdnf5/conf/vars.cpp b/libdnf5/conf/vars.cpp index 5905069ab..08785ea71 100644 --- a/libdnf5/conf/vars.cpp +++ b/libdnf5/conf/vars.cpp @@ -33,7 +33,9 @@ along with libdnf. If not, see . #include #include #include +#include #include +#include #include #include @@ -73,14 +75,46 @@ static constexpr const char * DISTROVERPKGS[] = { "redhat-release", "suse-release"}; +/* ARM specific HWCAP defines may be missing on non-ARM devices */ +#ifndef HWCAP_ARM_VFP +#define HWCAP_ARM_VFP (1 << 6) +#endif +#ifndef HWCAP_ARM_NEON +#define HWCAP_ARM_NEON (1 << 12) +#endif + static std::string detect_arch() { - std::string value{}; - char * tmp = rpmExpand("%{_host_cpu}", NULL); - if (tmp != nullptr) { - value = tmp; - free(tmp); + struct utsname un; + + if (uname(&un) < 0) { + throw RuntimeError(M_("Failed to execute uname()")); + } + + if (!strncmp(un.machine, "armv", 4)) { + /* un.machine is armvXE, where X is version number and E is + * endianness (b or l); we need to add modifiers such as + * h (hardfloat), n (neon). Neon is a requirement of armv8 so + * as far as rpm is concerned armv8l is the equivilent of armv7hnl + * (or 7hnb) so we don't explicitly add 'n' for 8+ as it's expected. */ + char endian = un.machine[strlen(un.machine) - 1]; + char * modifier = un.machine + 5; + while (isdigit(*modifier)) /* keep armv7, armv8, armv9, armv10, armv100, ... */ + modifier++; + if (getauxval(AT_HWCAP) & HWCAP_ARM_VFP) + *modifier++ = 'h'; + if ((atoi(un.machine + 4) == 7) && (getauxval(AT_HWCAP) & HWCAP_ARM_NEON)) + *modifier++ = 'n'; + *modifier++ = endian; + *modifier = 0; } - return value; +#ifdef __MIPSEL__ + // support for little endian MIPS + if (!strcmp(un.machine, "mips")) + strcpy(un.machine, "mipsel"); + else if (!strcmp(un.machine, "mips64")) + strcpy(un.machine, "mips64el"); +#endif + return un.machine; } From 8086e212c5e85c4954f237e1fa7aed55f0144ea6 Mon Sep 17 00:00:00 2001 From: Marek Blaha Date: Wed, 6 Dec 2023 10:59:59 +0100 Subject: [PATCH 2/2] vars: Always init librpm with correct architecture Now that detect_arch() no longer relies on initialized librpm, we can defer the librpm initialization until after the arch is detected and use the detected architecture as its argument. --- libdnf5/conf/vars.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/libdnf5/conf/vars.cpp b/libdnf5/conf/vars.cpp index 08785ea71..a017e2000 100644 --- a/libdnf5/conf/vars.cpp +++ b/libdnf5/conf/vars.cpp @@ -411,15 +411,11 @@ void Vars::load(const std::string & installroot, const std::vector } void Vars::detect_vars(const std::string & installroot) { - const char * arch = nullptr; - if (contains("arch")) { - arch = get_value("arch").c_str(); - } - init_lib_rpm(arch); - set_lazy( "arch", []() -> auto { return std::make_unique(detect_arch()); }, Priority::AUTO); + init_lib_rpm(get_value("arch").c_str()); + set_lazy( "basearch", [this]() -> auto {