diff options
author | Joseph Hunkeler <jhunkeler@gmail.com> | 2023-04-23 17:55:16 -0400 |
---|---|---|
committer | Joseph Hunkeler <jhunkeler@gmail.com> | 2023-04-23 17:55:16 -0400 |
commit | 1f0c894080e0a3d62694a056456e378e36eb12a1 (patch) | |
tree | 7abd3928808aa9f03a4dd17dd3eb5ecde7607d18 | |
parent | 0ec45301dc4d1a61cc1d9bd2906cd010c88f81c0 (diff) | |
download | whatami-1f0c894080e0a3d62694a056456e378e36eb12a1.tar.gz |
Refactor
Split linux, darwin, and x86 into separate modules
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | common.h | 55 | ||||
-rw-r--r-- | darwin.c | 38 | ||||
-rw-r--r-- | linux.c | 187 | ||||
-rw-r--r-- | main.c | 372 | ||||
-rw-r--r-- | util.c | 23 | ||||
-rw-r--r-- | x86.c | 117 | ||||
-rw-r--r-- | x86.h | 13 |
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 @@ -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 @@ -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, ®->gpr.eax, ®->gpr.ebx, ®->gpr.ecx, ®->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, ®); - // 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, ®); - // 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, ®); - strncat(vendor, (char *) ®.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, ®); - // 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, ®); - 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, ®); - manufacturer = calloc(sizeof(reg.bytes), sizeof(*reg.bytes)); - if (!manufacturer) { - return NULL; - } - strncat(manufacturer, (char *) ®.bytes[1], 4); - strncat(manufacturer, (char *) ®.bytes[3], 4); - strncat(manufacturer, (char *) ®.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, ®); - 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"); @@ -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; +} + @@ -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, ®->gpr.eax, ®->gpr.ebx, ®->gpr.ecx, ®->gpr.edx); + return reg->gpr.eax; +} + +int is_cpu_hyperthreaded() { + union regs_t reg; + + CPUID(1, ®); + // 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, ®); + // 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, ®); + strncat(vendor, (char *) ®.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, ®); + // 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, ®); + 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, ®); + manufacturer = calloc(sizeof(reg.bytes), sizeof(*reg.bytes)); + if (!manufacturer) { + return NULL; + } + strncat(manufacturer, (char *) ®.bytes[1], 4); + strncat(manufacturer, (char *) ®.bytes[3], 4); + strncat(manufacturer, (char *) ®.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, ®); + strncat(vendor, (char *) reg.bytes, sizeof(reg.bytes)); + } + + rstrip(vendor); + return vendor; +} @@ -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 |