Added shell,terminal,desktop,init and battery detection
All checks were successful
build / clang-build (push) Successful in 18s
All checks were successful
build / clang-build (push) Successful in 18s
This commit is contained in:
21
README.md
21
README.md
@@ -50,6 +50,11 @@ DISK = 1
|
|||||||
IP = 1
|
IP = 1
|
||||||
LOGO = 1
|
LOGO = 1
|
||||||
BARS = 0
|
BARS = 0
|
||||||
|
SHELL = 1
|
||||||
|
TERMINAL = 0
|
||||||
|
DESKTOP = 1
|
||||||
|
INIT = 1
|
||||||
|
BATTERY = 1
|
||||||
```
|
```
|
||||||
|
|
||||||
Any other line will be considered invalid and silently skipped by the builtin parser.
|
Any other line will be considered invalid and silently skipped by the builtin parser.
|
||||||
@@ -66,6 +71,11 @@ DISK : ON
|
|||||||
IP : ON
|
IP : ON
|
||||||
LOGO : ON
|
LOGO : ON
|
||||||
BARS : OFF
|
BARS : OFF
|
||||||
|
SHELL : ON
|
||||||
|
TERMINAL : OFF
|
||||||
|
DESKTOP : ON
|
||||||
|
INIT : ON
|
||||||
|
BATTERY : ON
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also dynamically specify a different path by using the `-c` CLI argument:
|
You can also dynamically specify a different path by using the `-c` CLI argument:
|
||||||
@@ -73,15 +83,20 @@ You can also dynamically specify a different path by using the `-c` CLI argument
|
|||||||
```sh
|
```sh
|
||||||
$ ./zfetch -c $PWD/config -s
|
$ ./zfetch -c $PWD/config -s
|
||||||
Using custom config file: '/home/marco/Projects/zfetch/config'
|
Using custom config file: '/home/marco/Projects/zfetch/config'
|
||||||
HOST : OFF
|
HOST : ON
|
||||||
OS : OFF
|
OS : OFF
|
||||||
UPTIME : OFF
|
UPTIME : OFF
|
||||||
CPU : OFF
|
CPU : OFF
|
||||||
MEMORY : ON
|
MEMORY : ON
|
||||||
DISK : ON
|
DISK : ON
|
||||||
IP : ON
|
IP : ON
|
||||||
LOGO : OFF
|
LOGO : ON
|
||||||
BARS : ON
|
BARS : OFF
|
||||||
|
SHELL : ON
|
||||||
|
TERMINAL : OFF
|
||||||
|
DESKTOP : ON
|
||||||
|
INIT : ON
|
||||||
|
BATTERY : ON
|
||||||
```
|
```
|
||||||
|
|
||||||
Finally, you can list all supported distribution, using the `--list-logos/-a` flag:
|
Finally, you can list all supported distribution, using the `--list-logos/-a` flag:
|
||||||
|
|||||||
289
zfetch.c
289
zfetch.c
@@ -33,6 +33,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
#include <sys/statvfs.h>
|
#include <sys/statvfs.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
#include <ifaddrs.h>
|
#include <ifaddrs.h>
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
@@ -41,6 +42,7 @@
|
|||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
|
||||||
#define Z_PATH_MAX 4096
|
#define Z_PATH_MAX 4096
|
||||||
#define IFACE_ENTRY_LEN 64
|
#define IFACE_ENTRY_LEN 64
|
||||||
@@ -85,6 +87,11 @@
|
|||||||
#define OPT_IP 1U << 6
|
#define OPT_IP 1U << 6
|
||||||
#define OPT_LOGO 1U << 7
|
#define OPT_LOGO 1U << 7
|
||||||
#define OPT_BARS 1U << 8
|
#define OPT_BARS 1U << 8
|
||||||
|
#define OPT_SHELL 1U << 9
|
||||||
|
#define OPT_TERMINAL 1U << 0xA
|
||||||
|
#define OPT_DESKTOP 1U << 0xB
|
||||||
|
#define OPT_INIT 1U << 0xC
|
||||||
|
#define OPT_BATTERY 1U << 0xD
|
||||||
|
|
||||||
#define ARR_LEN(X) (sizeof(X) / sizeof(X[0]))
|
#define ARR_LEN(X) (sizeof(X) / sizeof(X[0]))
|
||||||
#define STRCMP(X, Y) (strcmp(X, Y) == 0)
|
#define STRCMP(X, Y) (strcmp(X, Y) == 0)
|
||||||
@@ -304,9 +311,10 @@ static void strip_quotes(char *str) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint16_t default_opts(void) {
|
static inline uint16_t default_opts(void) {
|
||||||
return OPT_HOST | OPT_OS | OPT_UPTIME | OPT_CPU |
|
return OPT_HOST | OPT_OS | OPT_UPTIME | OPT_CPU |
|
||||||
OPT_MEMORY | OPT_DISK | OPT_IP | OPT_LOGO | OPT_BARS;
|
OPT_MEMORY | OPT_DISK | OPT_IP | OPT_LOGO | OPT_BARS |
|
||||||
|
OPT_SHELL | OPT_TERMINAL | OPT_DESKTOP | OPT_INIT | OPT_BATTERY;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_option(uint16_t *options, const char *opt, int value) {
|
static void set_option(uint16_t *options, const char *opt, int value) {
|
||||||
@@ -321,6 +329,11 @@ static void set_option(uint16_t *options, const char *opt, int value) {
|
|||||||
else if (STRCMP(opt, "IP")) { flag = OPT_IP; }
|
else if (STRCMP(opt, "IP")) { flag = OPT_IP; }
|
||||||
else if (STRCMP(opt, "LOGO")) { flag = OPT_LOGO; }
|
else if (STRCMP(opt, "LOGO")) { flag = OPT_LOGO; }
|
||||||
else if (STRCMP(opt, "BARS")) { flag = OPT_BARS; }
|
else if (STRCMP(opt, "BARS")) { flag = OPT_BARS; }
|
||||||
|
else if (STRCMP(opt, "SHELL")) { flag = OPT_SHELL; }
|
||||||
|
else if (STRCMP(opt, "TERMINAL")) { flag = OPT_TERMINAL; }
|
||||||
|
else if (STRCMP(opt, "DESKTOP")) { flag = OPT_DESKTOP; }
|
||||||
|
else if (STRCMP(opt, "INIT")) { flag = OPT_INIT; }
|
||||||
|
else if (STRCMP(opt, "BATTERY")) { flag = OPT_BATTERY; }
|
||||||
|
|
||||||
if (flag == 0) { return; }
|
if (flag == 0) { return; }
|
||||||
|
|
||||||
@@ -463,14 +476,21 @@ static const char **get_logo(const char *id) {
|
|||||||
return logo_linux;
|
return logo_linux;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *get_percentage_color(double percent) {
|
static inline const char *get_percentage_color(double percent) {
|
||||||
if (percent >= 85.0) { return C1; } // Red
|
if (percent >= 85.0) { return C1; } // Red
|
||||||
else if (percent >= 60.0) { return C3; } // Yellow/orange
|
else if (percent >= 60.0) { return C3; } // Yellow/orange
|
||||||
|
|
||||||
return C2; // Green
|
return C2; // Green
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *get_logo_accent(const char **logo) {
|
static inline const char *get_battery_color(int percent) {
|
||||||
|
if (percent >= 90) { return C2; } // Green
|
||||||
|
else if (percent >= 50) { return C3; } // Yellow/Orange
|
||||||
|
|
||||||
|
return C1; // Red
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline const char *get_logo_accent(const char **logo) {
|
||||||
if (logo == logo_arch || logo == logo_artix) {
|
if (logo == logo_arch || logo == logo_artix) {
|
||||||
return C6; // Cyan
|
return C6; // Cyan
|
||||||
} else if (logo == logo_debian || logo == logo_redhat) {
|
} else if (logo == logo_debian || logo == logo_redhat) {
|
||||||
@@ -548,6 +568,35 @@ static void fmt_size(uint64_t used_kib, uint64_t total_kib, char *buf, size_t bu
|
|||||||
used, unit, total, unit, get_percentage_color(percent), percent, RESET);
|
used, unit, total, unit, get_percentage_color(percent), percent, RESET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t fmt_uptime(char *buf, size_t buf_size, size_t offset, uint64_t value, const char *unit) {
|
||||||
|
if (value == 0) {
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *sep = (offset == 0) ? "" : ", ";
|
||||||
|
|
||||||
|
if (offset >= buf_size) {
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
int n = snprintf(buf + offset, buf_size - offset,
|
||||||
|
"%s%" PRIu64 " %s%s",
|
||||||
|
sep, value, unit,
|
||||||
|
value == 1 ? "" : "s");
|
||||||
|
|
||||||
|
if (n < 0) {
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t written = (size_t)n;
|
||||||
|
|
||||||
|
if (written >= buf_size - offset) {
|
||||||
|
return buf_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return offset + written;
|
||||||
|
}
|
||||||
|
|
||||||
// Retrieve the first line of a file
|
// Retrieve the first line of a file
|
||||||
static bool get_head(const char *path, const char *prefix, char *buf, size_t buf_size) {
|
static bool get_head(const char *path, const char *prefix, char *buf, size_t buf_size) {
|
||||||
FILE *fp = fopen(path, "r");
|
FILE *fp = fopen(path, "r");
|
||||||
@@ -578,35 +627,6 @@ static inline void str_to_lower(char *str) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline size_t fmt_uptime(char *buf, size_t buf_size, size_t offset, uint64_t value, const char *unit) {
|
|
||||||
if (value == 0) {
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *sep = (offset == 0) ? "" : ", ";
|
|
||||||
|
|
||||||
if (offset >= buf_size) {
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
int n = snprintf(buf + offset, buf_size - offset,
|
|
||||||
"%s%" PRIu64 " %s%s",
|
|
||||||
sep, value, unit,
|
|
||||||
value == 1 ? "" : "s");
|
|
||||||
|
|
||||||
if (n < 0) {
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t written = (size_t)n;
|
|
||||||
|
|
||||||
if (written >= buf_size - offset) {
|
|
||||||
return buf_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
return offset + written;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Features
|
* Features
|
||||||
*/
|
*/
|
||||||
@@ -736,6 +756,170 @@ static void get_disk(char *buf, size_t buf_size) {
|
|||||||
fmt_size(used_kib, total_kib, buf, buf_size);
|
fmt_size(used_kib, total_kib, buf, buf_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void get_shell(char *buf, size_t buf_size) {
|
||||||
|
const char *shell = getenv("SHELL");
|
||||||
|
const char *base;
|
||||||
|
|
||||||
|
if (shell == NULL || *shell == '\0') {
|
||||||
|
snprintf(buf, buf_size, "unknown");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find last slash (if available) and return
|
||||||
|
// the right part only (the name)
|
||||||
|
base = strrchr(shell, '/');
|
||||||
|
snprintf(buf, buf_size, "%s", base != NULL ? base + 1 : shell);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get_terminal(char *buf, size_t buf_size) {
|
||||||
|
const char *term_program = getenv("TERM_PROGRAM");
|
||||||
|
const char *term = getenv("TERM");
|
||||||
|
|
||||||
|
if (term_program != NULL && *term_program != '\0') {
|
||||||
|
snprintf(buf, buf_size, "%s", term_program);
|
||||||
|
} else if (term != NULL && *term != '\0') {
|
||||||
|
snprintf(buf, buf_size, "%s", term);
|
||||||
|
} else {
|
||||||
|
snprintf(buf, buf_size, "unknown");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get_desktop(char *buf, size_t buf_size) {
|
||||||
|
const char *desktop = getenv("XDG_CURRENT_DESKTOP");
|
||||||
|
const char *session = getenv("DESKTOP_SESSION");
|
||||||
|
const char *wayland = getenv("WAYLAND_DISPLAY");
|
||||||
|
const char *display = getenv("DISPLAY");
|
||||||
|
|
||||||
|
if (desktop != NULL && *desktop != '\0') {
|
||||||
|
if (wayland != NULL && *wayland != '\0') {
|
||||||
|
snprintf(buf, buf_size, "%s (Wayland)", desktop);
|
||||||
|
} else if (display != NULL && *display != '\0') {
|
||||||
|
snprintf(buf, buf_size, "%s (X11)", desktop);
|
||||||
|
} else {
|
||||||
|
snprintf(buf, buf_size, "%s", desktop);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session != NULL && *session != '\0') {
|
||||||
|
if (wayland != NULL && *wayland != '\0') {
|
||||||
|
snprintf(buf, buf_size, "%s (Wayland)", session);
|
||||||
|
} else if (display != NULL && *display != '\0') {
|
||||||
|
snprintf(buf, buf_size, "%s (X11)", session);
|
||||||
|
} else {
|
||||||
|
snprintf(buf, buf_size, "%s", session);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wayland != NULL && *wayland != '\0') {
|
||||||
|
snprintf(buf, buf_size, "Wayland");
|
||||||
|
} else if (display != NULL && *display != '\0') {
|
||||||
|
snprintf(buf, buf_size, "X11");
|
||||||
|
} else {
|
||||||
|
snprintf(buf, buf_size, "unknown");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get_init(char *buf, size_t buf_size) {
|
||||||
|
struct stat st;
|
||||||
|
char target[Z_PATH_MAX];
|
||||||
|
const char *base;
|
||||||
|
|
||||||
|
if (access("/run/systemd/system", F_OK) == 0) {
|
||||||
|
snprintf(buf, buf_size, "systemd");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t len = readlink("/sbin/init", target, sizeof(target) - 1);
|
||||||
|
if (len > 0) {
|
||||||
|
target[len] = '\0';
|
||||||
|
base = strrchr(target, '/');
|
||||||
|
base = base != NULL ? base + 1 : target;
|
||||||
|
|
||||||
|
if (strstr(base, "systemd") != NULL) {
|
||||||
|
snprintf(buf, buf_size, "systemd");
|
||||||
|
} else if (strstr(base, "openrc") != NULL) {
|
||||||
|
snprintf(buf, buf_size, "openrc");
|
||||||
|
} else if (strstr(base, "ruinit") != NULL) {
|
||||||
|
snprintf(buf, buf_size, "ruinit");
|
||||||
|
} else if (strstr(base, "s6") != NULL) {
|
||||||
|
snprintf(buf, buf_size, "s6");
|
||||||
|
} else if (strstr(base, "dinit") != NULL) {
|
||||||
|
snprintf(buf, buf_size, "dinit");
|
||||||
|
} else if (strstr(base, "busybox") != NULL) {
|
||||||
|
snprintf(buf, buf_size, "busybox init");
|
||||||
|
} else {
|
||||||
|
snprintf(buf, buf_size, "%s", base);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stat("/sbin/init", &st) == 0 && S_ISREG(st.st_mode) && access("/sbin/init", X_OK) == 0) {
|
||||||
|
snprintf(buf, buf_size, "sysvinit");
|
||||||
|
} else {
|
||||||
|
snprintf(buf, buf_size, "unknown");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool get_battery_value(const char *name, const char *file, char *buf, size_t buf_size) {
|
||||||
|
char path[PATH_MAX];
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), "/sys/class/power_supply/%s/%s", name, file);
|
||||||
|
FILE *fp = fopen(path, "r");
|
||||||
|
if (fp == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fgets(buf, (int)buf_size, fp) == NULL) {
|
||||||
|
fclose(fp);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
trim_whitespace(buf);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get_battery(char *buf, size_t buf_size) {
|
||||||
|
struct dirent *dir_entry;
|
||||||
|
|
||||||
|
DIR *dir = opendir("/sys/class/power_supply");
|
||||||
|
if (dir == NULL) {
|
||||||
|
snprintf(buf, buf_size, "unknown");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((dir_entry = readdir(dir)) != NULL) {
|
||||||
|
char capacity[32];
|
||||||
|
char status[64];
|
||||||
|
int percent;
|
||||||
|
|
||||||
|
if (strncmp(dir_entry->d_name, "BAT", 3) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!get_battery_value(dir_entry->d_name, "capacity", capacity, sizeof(capacity))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!get_battery_value(dir_entry->d_name, "status", status, sizeof(status))) {
|
||||||
|
snprintf(status, sizeof(status), "unknown");
|
||||||
|
}
|
||||||
|
|
||||||
|
percent = atoi(capacity);
|
||||||
|
snprintf(buf, buf_size, "%s%d%%%s [%s]",
|
||||||
|
get_battery_color(percent),
|
||||||
|
percent, RESET, status);
|
||||||
|
closedir(dir);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
|
snprintf(buf, buf_size, "unknown");
|
||||||
|
}
|
||||||
|
|
||||||
static size_t get_ips(char entries[][IFACE_ENTRY_LEN], size_t max_entries) {
|
static size_t get_ips(char entries[][IFACE_ENTRY_LEN], size_t max_entries) {
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
struct ifaddrs *ifa_list = NULL;
|
struct ifaddrs *ifa_list = NULL;
|
||||||
@@ -796,7 +980,12 @@ static void get_options(uint16_t options, const char *config_path) {
|
|||||||
{ "DISK", OPT_DISK },
|
{ "DISK", OPT_DISK },
|
||||||
{ "IP", OPT_IP },
|
{ "IP", OPT_IP },
|
||||||
{ "LOGO", OPT_LOGO },
|
{ "LOGO", OPT_LOGO },
|
||||||
{ "BARS", OPT_BARS }
|
{ "BARS", OPT_BARS },
|
||||||
|
{ "SHELL", OPT_SHELL },
|
||||||
|
{ "TERMINAL", OPT_TERMINAL },
|
||||||
|
{ "DESKTOP", OPT_DESKTOP },
|
||||||
|
{ "INIT", OPT_INIT },
|
||||||
|
{ "BATTERY", OPT_BATTERY }
|
||||||
};
|
};
|
||||||
|
|
||||||
if (config_path) {
|
if (config_path) {
|
||||||
@@ -806,7 +995,7 @@ static void get_options(uint16_t options, const char *config_path) {
|
|||||||
for (size_t idx = 0; idx < ARR_LEN(flags); idx++) {
|
for (size_t idx = 0; idx < ARR_LEN(flags); idx++) {
|
||||||
const bool enabled = (options & flags[idx].flag) != 0;
|
const bool enabled = (options & flags[idx].flag) != 0;
|
||||||
|
|
||||||
printf("%-6s : %s%s%s\n", flags[idx].name,
|
printf("%-8s : %s%s%s\n", flags[idx].name,
|
||||||
enabled ? C2 : C1,
|
enabled ? C2 : C1,
|
||||||
enabled ? "ON" : "OFF",
|
enabled ? "ON" : "OFF",
|
||||||
RESET);
|
RESET);
|
||||||
@@ -1001,6 +1190,36 @@ int main(int argc, char **argv) {
|
|||||||
line_count++;
|
line_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options & OPT_SHELL) {
|
||||||
|
lines[line_count].label = "Shell:";
|
||||||
|
get_shell(lines[line_count].value, sizeof(lines[line_count].value));
|
||||||
|
line_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options & OPT_TERMINAL) {
|
||||||
|
lines[line_count].label = "Terminal:";
|
||||||
|
get_terminal(lines[line_count].value, sizeof(lines[line_count].value));
|
||||||
|
line_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options & OPT_DESKTOP) {
|
||||||
|
lines[line_count].label = "Desktop:";
|
||||||
|
get_desktop(lines[line_count].value, sizeof(lines[line_count].value));
|
||||||
|
line_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options & OPT_INIT) {
|
||||||
|
lines[line_count].label = "Init:";
|
||||||
|
get_init(lines[line_count].value, sizeof(lines[line_count].value));
|
||||||
|
line_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options & OPT_BATTERY) {
|
||||||
|
lines[line_count].label = "Battery:";
|
||||||
|
get_battery(lines[line_count].value, sizeof(lines[line_count].value));
|
||||||
|
line_count++;
|
||||||
|
}
|
||||||
|
|
||||||
if (options & OPT_IP) {
|
if (options & OPT_IP) {
|
||||||
char interfaces[MAX_LOCAL_IPS][IFACE_ENTRY_LEN];
|
char interfaces[MAX_LOCAL_IPS][IFACE_ENTRY_LEN];
|
||||||
const size_t ifaces_count = get_ips(interfaces, MAX_LOCAL_IPS);
|
const size_t ifaces_count = get_ips(interfaces, MAX_LOCAL_IPS);
|
||||||
|
|||||||
Reference in New Issue
Block a user