aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Hunkeler <jhunkeler@gmail.com>2023-04-23 17:55:16 -0400
committerJoseph Hunkeler <jhunkeler@gmail.com>2023-04-23 17:55:16 -0400
commit1f0c894080e0a3d62694a056456e378e36eb12a1 (patch)
tree7abd3928808aa9f03a4dd17dd3eb5ecde7607d18
parent0ec45301dc4d1a61cc1d9bd2906cd010c88f81c0 (diff)
downloadwhatami-1f0c894080e0a3d62694a056456e378e36eb12a1.tar.gz
Refactor
Split linux, darwin, and x86 into separate modules
-rw-r--r--CMakeLists.txt2
-rw-r--r--common.h55
-rw-r--r--darwin.c38
-rw-r--r--linux.c187
-rw-r--r--main.c372
-rw-r--r--util.c23
-rw-r--r--x86.c117
-rw-r--r--x86.h13
8 files changed, 439 insertions, 368 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 61ff659..dd032c7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,4 +3,4 @@ project(whatami C)
set(CMAKE_C_STANDARD 99)
-add_executable(whatami main.c)
+add_executable(whatami main.c util.c darwin.c linux.c common.h x86.c x86.h)
diff --git a/common.h b/common.h
new file mode 100644
index 0000000..b936a62
--- /dev/null
+++ b/common.h
@@ -0,0 +1,55 @@
+#ifndef WHATAMI_COMMON_H
+#define WHATAMI_COMMON_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/utsname.h>
+#include <cpuid.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <limits.h>
+
+#if defined(__x86_64__) || defined(__i386__)
+#include "x86.h"
+#endif
+
+#if defined(__linux__)
+#elif defined(__APPLE__)
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#endif
+
+union regs_t {
+ struct {
+ unsigned int eax;
+ unsigned int ebx;
+ unsigned int ecx;
+ unsigned int edx;
+ } gpr;
+ unsigned int bytes[15];
+};
+
+struct Block_Device {
+ char path[PATH_MAX];
+ char model[254];
+ size_t size;
+};
+
+unsigned int CPUID(unsigned int leaf, union regs_t *reg);
+int is_cpu_hyperthreaded();
+int is_cpu_virtual();
+char *get_sys_product();
+unsigned int get_cpu_count();
+char *get_cpu_manufacturer();
+char *get_cpu_vendor();
+
+
+size_t rstrip(char *s);
+int get_sys_os_dist(char **name, char **version);
+ssize_t get_sys_memory();
+char *get_sys_dmi_product();
+struct Block_Device **get_block_devices(size_t *total);
+
+#endif //WHATAMI_COMMON_H
diff --git a/darwin.c b/darwin.c
new file mode 100644
index 0000000..9167dc2
--- /dev/null
+++ b/darwin.c
@@ -0,0 +1,38 @@
+#if defined(__APPLE__)
+#include "common.h"
+
+char *get_sys_product() {
+ char model[100] = {0};
+ size_t len;
+
+ len = sizeof(model);
+ sysctlbyname("hw.model", model, &len, NULL, 0);
+ return strdup(model);
+}
+
+size_t get_sys_memory() {
+ size_t mem_size;
+ size_t len;
+
+ mem_size= 0;
+ len = sizeof(mem_size);
+ sysctlbyname("hw.memsize", &mem_size, &len, NULL, 0);
+
+ return mem_size / 1024;
+}
+
+int *get_sys_os_dist(char **a, char **b) {
+ char version[255] = {0};
+ size_t version_len;
+
+ version_len = sizeof(version);
+ sysctlbyname("kern.osproductversion", version, &version_len, NULL, 0);
+ *a = strdup("MacOS");
+ *b = strdup(version);
+ return 0;
+}
+
+void *get_block_devices(void *x) {
+ return NULL;
+}
+#endif \ No newline at end of file
diff --git a/linux.c b/linux.c
new file mode 100644
index 0000000..4836955
--- /dev/null
+++ b/linux.c
@@ -0,0 +1,187 @@
+#if defined(__linux__)
+#include "common.h"
+
+int get_sys_os_dist(char **name, char **version) {
+ char buf[255] = {0};
+ const char *filename = "/etc/os-release";
+ FILE *fp;
+
+ fp = fopen(filename, "r");
+ if (!fp) {
+ *name = strdup("Unknown");
+ *version = strdup("Unknown");
+ return -1;
+ }
+
+ while (fgets(buf, sizeof(buf) - 1, fp) != NULL) {
+ rstrip(buf);
+ char *key, *value;
+ char *start;
+ start = buf;
+ key = strchr(buf, '=');
+ if (key) {
+ size_t diff = key - start;
+ *key = 0;
+ key = start;
+ value = key + diff + 1;
+ } else {
+ continue;
+ }
+ key = buf;
+
+ if (value[0] == '\"') {
+ memmove(value, &value[1], strlen(&value[1]));
+ if (strlen(value))
+ value[strlen(value) - 1] = '\0';
+ }
+ if (strlen(value) && value[strlen(value) - 1] == '\"') {
+ value[strlen(value) - 1] = '\0';
+ }
+ if (!strcmp(key, "NAME")) {
+ *name = strdup(value);
+ }
+ if (!strcmp(key, "VERSION") || !strcmp(key, "VERSION_ID") || !strcmp(key, "BUILD_ID")) {
+ *version = strdup(value);
+ }
+ }
+ fclose(fp);
+ return 0;
+}
+
+ssize_t get_sys_memory() {
+ char buf[255] = {0};
+ ssize_t result;
+ FILE *fp;
+
+ fp = fopen("/proc/meminfo", "r");
+ if (!fp) {
+ perror("Unable to open /proc/meminfo");
+ return -1;
+ }
+
+ result = 0;
+ while (fgets(buf, sizeof(buf) - 1, fp) != NULL) {
+ char *key = strstr(buf, "MemTotal:");
+ if (key) {
+ result = strtoll(key + strlen("MemTotal:"), NULL, 10);
+ break;
+ }
+ }
+
+ fclose(fp);
+ return result;
+}
+
+char *get_sys_dmi_product() {
+ FILE *fp;
+ char *buf;
+ const int buf_size = 255;
+
+ buf = calloc(buf_size, sizeof(*buf));
+ if (!buf) {
+ return NULL;
+ }
+
+ fp = fopen("/sys/class/dmi/id/product_name", "r");
+ if (!fp) {
+ free(buf);
+ return NULL;
+ }
+
+ if (!fgets(buf, buf_size, fp)) {
+ perror("Unable to read system vendor");
+ if (fp != NULL) {
+ free(buf);
+ fclose(fp);
+ }
+ return NULL;
+ }
+
+ fclose(fp);
+ return buf;
+}
+
+struct Block_Device **get_block_devices(size_t *total) {
+ struct Block_Device **result;
+ struct dirent *rec;
+ DIR *dp;
+ size_t i;
+ size_t devices_total;
+
+ dp = opendir("/sys/block");
+ if (!dp) {
+ perror("/sys/block");
+ return 0;
+ }
+
+ i = 0;
+ devices_total = 0;
+ *total = devices_total;
+ while ((rec = readdir(dp)) != NULL) {
+ if (!strcmp(rec->d_name, ".") || !strcmp(rec->d_name, "..")) {
+ continue;
+ }
+ devices_total++;
+ }
+ rewinddir(dp);
+
+ result = calloc(devices_total + 1, sizeof(result));
+ for (size_t d = 0; d < devices_total; d++) {
+ result[d] = calloc(1, sizeof(*result[0]));
+ }
+
+ while ((rec = readdir(dp)) != NULL) {
+ if (!strcmp(rec->d_name, ".") || !strcmp(rec->d_name, "..")) {
+ continue;
+ }
+
+ char device_path[PATH_MAX] = {0};
+ snprintf(device_path, sizeof(device_path) - 1, "/dev/%s", rec->d_name);
+
+ char device_size_file[PATH_MAX] = {0};
+ snprintf(device_size_file, sizeof(device_size_file) - 1, "/sys/block/%s/size", rec->d_name);
+
+ char device_model_file[PATH_MAX] = {0};
+ snprintf(device_model_file, sizeof(device_model_file) - 1, "/sys/block/%s/device/model", rec->d_name);
+
+ char line[255] = {0};
+ FILE *fp;
+
+ size_t device_size;
+ fp = fopen(device_size_file, "r");
+ if (!fp) {
+ device_size = 0;
+ } else {
+ if (!fgets(line, sizeof(line) - 1, fp)) {
+ perror("Unable to read from file");
+ continue;
+ }
+ device_size = strtoull(line, NULL, 10);
+ fclose(fp);
+ }
+
+ char device_model[255] = {0};
+ fp = fopen(device_model_file, "r");
+ if (!fp) {
+ // no model file
+ strcpy(device_model, "Unnamed");
+ } else {
+ if (!fgets(device_model, sizeof(line) - 1, fp)) {
+ perror("Unable to read device model");
+ continue;
+ }
+ fclose(fp);
+ }
+
+ rstrip(device_model);
+ strcpy(result[i]->model, device_model);
+ strncpy(result[i]->path, rec->d_name, sizeof(result[i]->path) - 1);
+ result[i]->size = device_size;
+ i++;
+ }
+
+ *total = devices_total;
+ closedir(dp);
+ return result;
+}
+#endif \ No newline at end of file
diff --git a/main.c b/main.c
index 48e5e0f..ca59c79 100644
--- a/main.c
+++ b/main.c
@@ -1,371 +1,6 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/utsname.h>
-#include <cpuid.h>
-#include <ctype.h>
-#include <dirent.h>
-#include <limits.h>
+#include "common.h"
-#if defined(__linux__)
-#define get_sys_memory get_memory_linux
-#define get_sys_os_dist get_os_dist_linux
-#else
-#error No platform drivers
-#endif
-
-#if defined(__x86_64__) || defined(__i386__)
-// Hyperthreading
-#define bit_HTT (1 << 28)
-// Virtualization
-#define bit_VRT (1 << 31)
-
-#define is_cpu_hyperthreaded is_cpu_hyperthreaded_x86
-#define is_cpu_virtual is_cpu_virtual_x86
-#define get_cpu_vendor get_cpu_vendor_x86
-#define get_cpu_manufacturer get_cpu_manufacturer_x86
-#define get_cpu_count get_cpu_count_x86
-#define get_sys_product get_sys_product_x86
-#else
-#error No driver to retrieve CPU information
-#endif
-
-union regs_t {
- struct {
- unsigned int eax;
- unsigned int ebx;
- unsigned int ecx;
- unsigned int edx;
- } gpr;
- unsigned int bytes[16];
-};
-
-struct Block_Device {
- char path[PATH_MAX];
- char model[255];
- size_t size;
-};
-
-/***
- * Strip whitespace from end of string
- * @param s string
- * @return count of characters stripped
- */
-size_t rstrip(char *s) {
- char *ch;
- size_t i;
-
- i = 0;
- ch = &s[strlen(s)];
- if (ch) {
- while (isspace(*ch) || iscntrl(*ch)) {
- *ch = '\0';
- --ch;
- i++;
- }
- }
- return i;
-}
-
-/***
- *
- * @param leaf
- * @param reg union regs_t
- * @return contents of eax register
- */
-unsigned int CPUID(unsigned int leaf, union regs_t *reg) {
- memset(reg, 0, sizeof(*reg));
- __get_cpuid(leaf, &reg->gpr.eax, &reg->gpr.ebx, &reg->gpr.ecx, &reg->gpr.edx);
- return reg->gpr.eax;
-}
-
-int get_os_dist_linux(char **name, char **version) {
- char buf[255] = {0};
- const char *filename = "/etc/os-release";
- FILE *fp;
-
- fp = fopen(filename, "r");
- if (!fp) {
- *name = strdup("Unknown");
- *version = strdup("Unknown");
- return -1;
- }
-
- while (fgets(buf, sizeof(buf) - 1, fp) != NULL) {
- rstrip(buf);
- char *key, *value;
- char *start;
- start = buf;
- key = strchr(buf, '=');
- if (key) {
- size_t diff = key - start;
- *key = 0;
- key = start;
- value = key + diff + 1;
- } else {
- continue;
- }
- key = buf;
-
- if (value[0] == '\"') {
- memmove(value, &value[1], strlen(&value[1]));
- if (strlen(value))
- value[strlen(value) - 1] = '\0';
- }
- if (strlen(value) && value[strlen(value) - 1] == '\"') {
- value[strlen(value) - 1] = '\0';
- }
- if (!strcmp(key, "NAME")) {
- *name = strdup(value);
- }
- if (!strcmp(key, "VERSION") || !strcmp(key, "VERSION_ID") || !strcmp(key, "BUILD_ID")) {
- *version = strdup(value);
- }
- }
- fclose(fp);
- return 0;
-}
-
-ssize_t get_memory_linux() {
- char buf[255] = {0};
- ssize_t result;
- FILE *fp;
-
- fp = fopen("/proc/meminfo", "r");
- if (!fp) {
- perror("Unable to open /proc/meminfo");
- return -1;
- }
-
- result = 0;
- while (fgets(buf, sizeof(buf) - 1, fp) != NULL) {
- char *key = strstr(buf, "MemTotal:");
- if (key) {
- result = strtoll(key + strlen("MemTotal:"), NULL, 10);
- break;
- }
- }
-
- fclose(fp);
- return result;
-}
-
-int is_cpu_hyperthreaded_x86() {
- union regs_t reg;
-
- CPUID(1, &reg);
- // Hyperthreading feature flag is located in bit 28 of EDX (regs[3])
- if (reg.gpr.edx & bit_HTT) {
- // hyperthreaded
- return 1;
- }
- return 0;
-}
-
-int is_cpu_virtual_x86() {
- union regs_t reg;
-
- CPUID(1, &reg);
- // Virtualization flag is located in bit 31 of ECX
- if (reg.gpr.ecx & bit_VRT) {
- return 1;
- }
- return 0;
-}
-
-char *get_sys_dmi_product_linux() {
- FILE *fp;
- char *buf;
- const int buf_size = 255;
-
- buf = calloc(buf_size, sizeof(*buf));
- if (!buf) {
- return NULL;
- }
-
- fp = fopen("/sys/class/dmi/id/product_name", "r");
- if (!fp) {
- free(buf);
- return NULL;
- }
-
- if (!fgets(buf, buf_size, fp)) {
- perror("Unable to read system vendor");
- if (fp != NULL) {
- free(buf);
- fclose(fp);
- }
- return NULL;
- }
-
- fclose(fp);
- return buf;
-}
-
-char *get_sys_product_x86() {
- union regs_t reg;
- char *vendor;
-
- vendor = NULL;
- if (is_cpu_virtual_x86()) {
- vendor = calloc(255, sizeof(*vendor));
- if (!vendor) {
- return NULL;
- }
- CPUID(0x40000000, &reg);
- strncat(vendor, (char *) &reg.bytes[1], sizeof(reg.bytes));
- rstrip(vendor);
- }
-
-#if defined(__linux__)
- if (!vendor || !strlen(vendor)) {
- vendor = get_sys_dmi_product_linux();
- rstrip(vendor);
- }
-#endif
-
- return vendor;
-}
-
-unsigned int get_cpu_count_x86() {
- union regs_t reg;
- unsigned int result;
-
- if (is_cpu_hyperthreaded()) {
- CPUID(1, &reg);
- // cpu count is located in bits 16:23 of EBX
- result = reg.gpr.ebx >> 16 & 0xff;
- } else { // Legacy check
- // Core Count is located in 0:7 of ECX
- CPUID(0x80000008, &reg);
- result = 1 + (reg.gpr.ecx & 0xff);
- }
-
-#if defined(__linux__) || (defined(__APPLE__) || defined(TARGET_OS_MAC))
- if (result == 1) {
- // One CPU might indicate we were unable to poll the information
- // See what the kernel thinks
- result = sysconf(_SC_NPROCESSORS_ONLN);
- }
-#endif
- return result;
-}
-
-char *get_cpu_manufacturer_x86() {
- union regs_t reg;
- char *manufacturer;
-
- CPUID(0, &reg);
- manufacturer = calloc(sizeof(reg.bytes), sizeof(*reg.bytes));
- if (!manufacturer) {
- return NULL;
- }
- strncat(manufacturer, (char *) &reg.bytes[1], 4);
- strncat(manufacturer, (char *) &reg.bytes[3], 4);
- strncat(manufacturer, (char *) &reg.bytes[2], 4);
- return manufacturer;
-}
-
-char *get_cpu_vendor_x86() {
- union regs_t reg;
- char *vendor;
-
- vendor = calloc(sizeof(reg.bytes) * 3, sizeof(*reg.bytes));
- for (unsigned int leaf = 2; leaf < 5; leaf++) {
- CPUID(0x80000000 + leaf, &reg);
- strncat(vendor, (char *) reg.bytes, sizeof(reg.bytes));
- }
-
- rstrip(vendor);
- return vendor;
-}
-
-struct Block_Device **get_block_devices(size_t *total) {
- struct Block_Device **result;
- struct dirent *rec;
- DIR *dp;
- size_t i;
- size_t devices_total;
-
- dp = opendir("/sys/block");
- if (!dp) {
- perror("/sys/block");
- return 0;
- }
-
- i = 0;
- devices_total = 0;
- *total = devices_total;
- while ((rec = readdir(dp)) != NULL) {
- if (!strcmp(rec->d_name, ".") || !strcmp(rec->d_name, "..")) {
- continue;
- }
- devices_total++;
- }
- rewinddir(dp);
-
- result = calloc(devices_total + 1, sizeof(result));
- for (size_t d = 0; d < devices_total; d++) {
- result[d] = calloc(1, sizeof(*result[0]));
- }
-
- while ((rec = readdir(dp)) != NULL) {
- if (!strcmp(rec->d_name, ".") || !strcmp(rec->d_name, "..")) {
- continue;
- }
-
- char device_path[PATH_MAX] = {0};
- snprintf(device_path, sizeof(device_path) - 1, "/dev/%s", rec->d_name);
-
- char device_size_file[PATH_MAX] = {0};
- snprintf(device_size_file, sizeof(device_size_file) - 1, "/sys/block/%s/size", rec->d_name);
-
- char device_model_file[PATH_MAX] = {0};
- snprintf(device_model_file, sizeof(device_model_file) - 1, "/sys/block/%s/device/model", rec->d_name);
-
- char line[255] = {0};
- FILE *fp;
-
- size_t device_size;
- fp = fopen(device_size_file, "r");
- if (!fp) {
- device_size = 0;
- } else {
- if (!fgets(line, sizeof(line) - 1, fp)) {
- perror("Unable to read from file");
- continue;
- }
- device_size = strtoull(line, NULL, 10);
- fclose(fp);
- }
-
- char device_model[255] = {0};
- fp = fopen(device_model_file, "r");
- if (!fp) {
- // no model file
- strcpy(device_model, "Unnamed");
- } else {
- if (!fgets(device_model, sizeof(line) - 1, fp)) {
- perror("Unable to read device model");
- continue;
- }
- fclose(fp);
- }
-
- rstrip(device_model);
- strcpy(result[i]->model, device_model);
- strncpy(result[i]->path, rec->d_name, sizeof(result[i]->path) - 1);
- result[i]->size = device_size;
- i++;
- }
-
- *total = devices_total;
- closedir(dp);
- return result;
-}
-
-int cmp_block_device(const void *aa, const void *bb) {
+static int cmp_block_device(const void *aa, const void *bb) {
const char *a = ((struct Block_Device *) aa)->path;
const char *b = ((struct Block_Device *) bb)->path;
return strcmp(a, b) == 0;
@@ -391,6 +26,7 @@ int main() {
perror("Unable to read uts data");
exit(1);
}
+
get_sys_os_dist(&distro_name, &distro_version);
cpu_manufacturer = get_cpu_manufacturer();
cpu_vendor = get_cpu_vendor();
@@ -406,7 +42,9 @@ int main() {
printf("KERNEL: %s %s\n", kinfo.release, kinfo.version);
printf("CPU: %s (%s)\n", cpu_vendor, cpu_manufacturer);
printf("CPUs: %u\n", cpu_count);
+#if defined(__x86_64__) || (__i386__)
printf("Hyperthreaded: %s\n", is_cpu_hyperthreaded() ? "Yes" : "No");
+#endif
printf("RAM: %0.2lfGB\n", ((double) get_sys_memory() / 1024 / 1024));
printf("Block devices:\n");
diff --git a/util.c b/util.c
new file mode 100644
index 0000000..1f74ad5
--- /dev/null
+++ b/util.c
@@ -0,0 +1,23 @@
+#include "common.h"
+
+/***
+ * Strip whitespace from end of string
+ * @param s string
+ * @return count of characters stripped
+ */
+size_t rstrip(char *s) {
+ char *ch;
+ size_t i;
+
+ i = 0;
+ ch = &s[strlen(s)];
+ if (ch) {
+ while (isspace(*ch) || iscntrl(*ch)) {
+ *ch = '\0';
+ --ch;
+ i++;
+ }
+ }
+ return i;
+}
+
diff --git a/x86.c b/x86.c
new file mode 100644
index 0000000..647d6ac
--- /dev/null
+++ b/x86.c
@@ -0,0 +1,117 @@
+#include "common.h"
+
+/***
+ *
+ * @param leaf
+ * @param reg union regs_t
+ * @return contents of eax register
+ */
+unsigned int CPUID(unsigned int leaf, union regs_t *reg) {
+ memset(reg, 0, sizeof(*reg));
+ __get_cpuid(leaf, &reg->gpr.eax, &reg->gpr.ebx, &reg->gpr.ecx, &reg->gpr.edx);
+ return reg->gpr.eax;
+}
+
+int is_cpu_hyperthreaded() {
+ union regs_t reg;
+
+ CPUID(1, &reg);
+ // Hyperthreading feature flag is located in bit 28 of EDX (regs[3])
+ if (reg.gpr.edx & bit_HTT) {
+ // hyperthreaded
+ return 1;
+ }
+ return 0;
+}
+
+int is_cpu_virtual() {
+ union regs_t reg;
+
+ CPUID(1, &reg);
+ // Virtualization flag is located in bit 31 of ECX
+ if (reg.gpr.ecx & bit_VRT) {
+ return 1;
+ }
+ return 0;
+}
+
+char *get_sys_product() {
+ union regs_t reg;
+ char *vendor;
+
+ vendor = NULL;
+ if (is_cpu_virtual()) {
+ vendor = calloc(255, sizeof(*vendor));
+ if (!vendor) {
+ return NULL;
+ }
+ CPUID(0x40000000, &reg);
+ strncat(vendor, (char *) &reg.bytes[1], sizeof(reg.bytes));
+ rstrip(vendor);
+ }
+#if defined(__linux__)
+ if (!vendor || !strlen(vendor)) {
+ vendor = get_sys_dmi_product();
+ rstrip(vendor);
+ }
+#elif defined(__APPLE__)
+ if (!vendor || !strlen(vendor)) {
+ vendor = get_sys_product_darwin();
+ rstrip(vendor);
+ }
+#endif
+ return vendor;
+}
+
+unsigned int get_cpu_count() {
+ union regs_t reg;
+ unsigned int result;
+
+ if (is_cpu_hyperthreaded()) {
+ CPUID(1, &reg);
+ // cpu count is located in bits 16:23 of EBX
+ result = reg.gpr.ebx >> 16 & 0xff;
+ } else { // Legacy check
+ // Core Count is located in 0:7 of ECX
+ CPUID(0x80000008, &reg);
+ result = 1 + (reg.gpr.ecx & 0xff);
+ }
+
+#if defined(__linux__) || (defined(__APPLE__) || defined(TARGET_OS_MAC))
+ if (result == 1) {
+ // One CPU might indicate we were unable to poll the information
+ // See what the kernel thinks
+ result = sysconf(_SC_NPROCESSORS_ONLN);
+ }
+#endif
+ return result;
+}
+
+char *get_cpu_manufacturer() {
+ union regs_t reg;
+ char *manufacturer;
+
+ CPUID(0, &reg);
+ manufacturer = calloc(sizeof(reg.bytes), sizeof(*reg.bytes));
+ if (!manufacturer) {
+ return NULL;
+ }
+ strncat(manufacturer, (char *) &reg.bytes[1], 4);
+ strncat(manufacturer, (char *) &reg.bytes[3], 4);
+ strncat(manufacturer, (char *) &reg.bytes[2], 4);
+ return manufacturer;
+}
+
+char *get_cpu_vendor() {
+ union regs_t reg;
+ char *vendor;
+
+ vendor = calloc(sizeof(reg.bytes) * 3, sizeof(*reg.bytes));
+ for (unsigned int leaf = 2; leaf < 5; leaf++) {
+ CPUID(0x80000000 + leaf, &reg);
+ strncat(vendor, (char *) reg.bytes, sizeof(reg.bytes));
+ }
+
+ rstrip(vendor);
+ return vendor;
+}
diff --git a/x86.h b/x86.h
new file mode 100644
index 0000000..9d7ec4f
--- /dev/null
+++ b/x86.h
@@ -0,0 +1,13 @@
+#ifndef WHATAMI_X86_H
+#define WHATAMI_X86_H
+#if defined(__x86_64__) || defined(__i386__)
+
+#ifndef bit_HTT
+// Hyperthreading
+#define bit_HTT (1 << 28)
+#endif
+// Virtualization
+#define bit_VRT (1 << 31)
+
+#endif // x86_64 || i386
+#endif //WHATAMI_X86_H