Subject: [PATCH] uname: add -i/-p decoding to Linux platforms

From: Mike Frysinger <[email-masked]>
Date: Mon, 26 Nov 2012 14:35:26 -0500

To add support for additional platforms, check out the show_cpuinfo()
func in the linux/arch/<ARCH>/ source tree of the kernel.

* src/uname.c: Include trim.h.
(linux_procinfo): New function.
(main): Call linux_procinfo when __linux__ is defined and
PRINT_PROCESSOR or PRINT_HARDWARE_PLATFORM is requested.
---
 src/uname.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 113 insertions(+)

diff --git a/src/uname.c b/src/uname.c
index 0eb123b..18f6290 100644
--- a/src/uname.c
+++ b/src/uname.c
@@ -52,6 +52,7 @@
 #include "system.h"
 #include "error.h"
 #include "quote.h"
+#include "trim.h"
 #include "uname.h"
 
 /* The official name of this program (e.g., no 'g' prefix).  */
@@ -153,6 +154,100 @@ Print machine architecture.\n\
   exit (status);
 }
 
+#ifdef __linux__
+
+# if defined(__s390__) || defined(__s390x__)
+#  define CPUINFO_FILE    "/proc/sysinfo"
+#  define CPUINFO_FORMAT  "%64[^\t :]%*[ :]%256[^\n]%c"
+# else
+#  define CPUINFO_FILE    "/proc/cpuinfo"
+#  define CPUINFO_FORMAT  "%64[^\t:]\t:%256[^\n]%c"
+# endif
+
+# define PROCINFO_PROCESSOR         0
+# define PROCINFO_HARDWARE_PLATFORM 1
+
+static int linux_procinfo(int x, char *fstr, size_t s)
+{
+  static const char * const procinfo_keys[] = {
+    /* --processor --hardware-platform */
+# if defined(__alpha__)
+    "cpu model", "system type"
+# elif defined(__arm__)
+    "Processor", "Hardware"
+# elif defined(__avr32__)
+    "processor", "cpu family"
+# elif defined(__bfin__)
+    "model name", "vendor_id",
+# elif defined(__c6x__)
+    "cpu", "soc",
+# elif defined(__cris__)
+    "cpu", "cpu model"
+# elif defined(__frv__)
+    "CPU-Core", "System"
+# elif defined(__i386__) || defined(__x86_64__)
+    "model name", "vendor_id"
+# elif defined(__ia64__)
+    "model name", "vendor"
+# elif defined(__hppa__)
+    "cpu", "model"
+# elif defined(__m68k__)
+    "CPU", "MMU"
+# elif defined(__mips__)
+    "cpu model", "system type"
+# elif defined(__powerpc__) || defined(__powerpc64__)
+    "cpu", "machine"
+# elif defined(__s390__) || defined(__s390x__)
+    "Type", "Manufacturer"
+# elif defined(__sh__)
+    "cpu type", "machine"
+# elif defined(sparc) || defined(__sparc__)
+    "type", "cpu"
+# elif defined(__vax__)
+    "cpu type", "cpu"
+# else
+    "unknown", "unknown"
+# endif
+  };
+  FILE *fp;
+  char key[65], value[257], eol, *ret;
+
+  fp = fopen(CPUINFO_FILE, "r");
+  if (fp == NULL)
+    return -1;
+
+  ret = NULL;
+  while (fscanf(fp, CPUINFO_FORMAT, key, value, &eol) != EOF)
+    {
+      if (!strcmp(trim(key), procinfo_keys[x]))
+        {
+          ret = trim(value);
+          break;
+        }
+
+      if (eol != '\n')
+        {
+          /* We need two fscanf's here in case the previous length limit
+             caused us to read right up to the newline.  Doing something
+             like "%*[^\n]\n" won't eat the newline.  */
+          if (fscanf(fp, "%*[^\n]")) {}
+          if (fscanf(fp, "\n")) {}
+        }
+    }
+
+  fclose(fp);
+
+  if (ret)
+    {
+      strncpy(fstr, ret, s);
+      return 0;
+    }
+
+  return -1;
+}
+
+#endif
+
 /* Print ELEMENT, preceded by a space if something has already been
    printed.  */
 
@@ -307,6 +402,15 @@ main (int argc, char **argv)
           element = processor;
       }
 #endif
+#ifdef __linux__
+      if (element == unknown)
+        {
+          static char processor[257];
+          if (0 <= linux_procinfo (PROCINFO_PROCESSOR, processor,
+                                   sizeof processor))
+            element = processor;
+        }
+#endif
 #ifdef UNAME_PROCESSOR
       if (element == unknown)
         {
@@ -352,6 +456,15 @@ main (int argc, char **argv)
           element = hardware_platform;
       }
 #endif
+#ifdef __linux__
+      if (element == unknown)
+        {
+          static char hardware_platform[257];
+          if (0 <= linux_procinfo (PROCINFO_HARDWARE_PLATFORM,
+                                   hardware_platform, sizeof hardware_platform))
+            element = hardware_platform;
+        }
+#endif
 #ifdef UNAME_HARDWARE_PLATFORM
       if (element == unknown)
         {
-- 
1.7.12.4