# Unknown ‘uname -p’ output?

Intro

I usually tend to write longer posts on the exciting things I did, but this time I’m going to focus on a bug. It’s not a bug, but rather a consequence of a syscall interface in Linux.

So, what’s the fuss about? Somehow I treated the uname -p output as granted:

[admin@arch ~]$ uname -p
unknown

But yet I was getting the “unknown” both on my laptop and ARM boxes. I could swear “it used to work” in the past, so I found it pretty annoying.

I guess many people would agree with me that uname -p is just a nice and convenient method to get processor type, no need to grep /proc or anything as such. Thus I’d expect it to work.

Ubuntu test

To proof myself I am not making things up, I invoked the same command on the Ubuntu (instead of Arch Linux where the issue is present):

[admin@ubuntu ~]$ uname -p
armv7l

It looks all good here as expected.

Investigating coreutils

Where does uname reads data from? Let’s see the sources.

[admin@od1 arch]$ yay -Gf $(pkgfile -s $(which uname))
:: Querying AUR...
:: Downloaded PKGBUILD from ABS (1/1): coreutils

PKGBUILD indicates coreutils-8.31, let’s look at src/uname.c which looks like this:

  if (toprint & PRINT_PROCESSOR)
    {
      char const *element = unknown;
#if HAVE_SYSINFO && defined SI_ARCHITECTURE
      {
        static char processor[257];
        if (0 <= sysinfo (SI_ARCHITECTURE, processor, sizeof processor))
          element = processor;
      }
#endif
#ifdef UNAME_PROCESSOR
      if (element == unknown)
        {
          static char processor[257];
          size_t s = sizeof processor;
          static int mib[] = { CTL_HW, UNAME_PROCESSOR };
          if (sysctl (mib, 2, processor, &s, 0, 0) >= 0)
            element = processor;

# ifdef __APPLE__
          /* This kludge works around a bug in Mac OS X.  */
          if (element == unknown)
            {
              cpu_type_t cputype;
              size_t cs = sizeof cputype;
              NXArchInfo const *ai;
              if (sysctlbyname ("hw.cputype", &cputype, &cs, NULL, 0) == 0
                  && (ai = NXGetArchInfoFromCpuType (cputype,
                                                     CPU_SUBTYPE_MULTIPLE))
                  != NULL)
                element = ai->name;

              /* Hack "safely" around the ppc vs. powerpc return value. */
              if (cputype == CPU_TYPE_POWERPC
                  && STRNCMP_LIT (element, "ppc") == 0)
                element = "powerpc";
            }
# endif
        }
#endif
      if (! (toprint == UINT_MAX && element == unknown))
        print_element (element);

Reading the code:

  • SI_ARCHITECTURE – comes from solaris so we’re ignoring sysinfo syscall for now
  • UNAME_PROCESSOR – this is the gateway to sysctl syscall that works on i.e FreeBSD but no longer on Linux (kernel 5.5 patch)
  • APPLE – nope, not apple this time

No branch entered, so the default unknown is set.

Mailing list

It seems it was never there or at least removed when sysctl was deprecated a decade ago. Quick googling led me to this discussion where it’s explained:

Linux doesn’t support the relevant sysinfo (Solaris-style) or sysctl (BSD-style) system calls

Coreutils team seems to be hesitant to apply proposed patches, voting for making the Linux syscall support it “the right way”:

I’d rather have the Linux folks support this stuff in their system calls; that’s where it belongs

Patch

Yup, it seems the Ubuntu/Fedora patches the coreutils with uname syscall:

+#else
+      {
+    struct utsname u;
+    uname(&u);
+    element = u.machine;

Conclusion

It’s still odd to me the above patch isn’t pushed upstream. In any case, once I applied the patch, uname works the way I expected (y).

Overall I am not a picky user, but those small things can be annoying sometimes.