Added Mint logo, fixed some bugs and added docs.
All checks were successful
build / clang-build (push) Successful in 22s
All checks were successful
build / clang-build (push) Successful in 22s
This commit is contained in:
14
.gitea/workflows/build.yml
Normal file
14
.gitea/workflows/build.yml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
name: build
|
||||||
|
on: [push,pull_request,workflow_dispatch]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
clang-build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install Clang
|
||||||
|
run: sudo apt update && sudo apt install -y clang
|
||||||
|
|
||||||
|
- name: Build Datum
|
||||||
|
run: clang zfetch.c -Wall -Wextra -Werror -pedantic-errors -fstack-protector-all -fsanitize=undefined -fsanitize=address -Wwrite-strings -o zfetch
|
||||||
102
README.md
102
README.md
@@ -1,2 +1,100 @@
|
|||||||
# zFetch
|
<div align="center">
|
||||||
Minimalistic system fetcher for Linux platform written in C99.
|
<h1>zFetch</h1>
|
||||||
|
<img src="imgs/preview.gif">
|
||||||
|
<h6><i>Lightweight system information fetcher for Linux.</i></h6>
|
||||||
|
|
||||||
|

|
||||||
|

|
||||||
|
</div>
|
||||||
|
|
||||||
|
**zFetch** is a lightweight system information fetcher for Linux written in C99.
|
||||||
|
Unlike other system fetchers, this tool focuses on providing a simple, easy-to-remember
|
||||||
|
interface and configuration syntax, extremely fast startup and a reasonable amount
|
||||||
|
of core features.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
zFetch consists on a single source file which can be compiled with any modern C
|
||||||
|
compiler (Clang/GCC) on a Linux-based system. In order to build it, you can just run
|
||||||
|
`gcc zfetch.c -o zfetch` or use the following Makefile rule:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ make clean all
|
||||||
|
rm -f *.o *.a zfetch
|
||||||
|
clang -Wall -Wextra -Werror -pedantic-errors -Wwrite-strings -std=c99 -O3 zfetch.c -o zfetch
|
||||||
|
```
|
||||||
|
|
||||||
|
In both cases, you will get a binary file named `zfetch` that you can move wherever you
|
||||||
|
want.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
As stated before, I've built zFetch to be extremely simple to use since I believe that system
|
||||||
|
fetchers play a paramount role on providing essential data to whoever has a lot of machines to manage.
|
||||||
|
|
||||||
|
In its most basic form, you can just invoke the program without any additional parameter and it will
|
||||||
|
run with all option enabled, that is:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
If you instead would like to granularly enable or disable some features,
|
||||||
|
you can do so by creating a configuration file in one of the following paths:
|
||||||
|
|
||||||
|
- `$HOME/.zfetch.conf`;
|
||||||
|
- `$HOME/.config/zfetch/conf` (**this takes precedence**).
|
||||||
|
|
||||||
|
Inside it, you can specify which option to enable and which one to disable:
|
||||||
|
|
||||||
|
```conf
|
||||||
|
HOST = 1
|
||||||
|
OS = 0
|
||||||
|
UPTIME = 1
|
||||||
|
CPU = 1
|
||||||
|
MEMORY = 1
|
||||||
|
DISK = 1
|
||||||
|
IP = 1
|
||||||
|
LOGO = 1
|
||||||
|
BARS = 0
|
||||||
|
```
|
||||||
|
|
||||||
|
Any other line will be considered invalid and silently skipped by the builtin parser.
|
||||||
|
To retrieve which options are currently enabled, you can run the program with the `-s` flag, that is:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ ./zfetch --list-opts # or -s
|
||||||
|
HOST : ON
|
||||||
|
OS : OFF
|
||||||
|
UPTIME : ON
|
||||||
|
CPU : ON
|
||||||
|
MEMORY : ON
|
||||||
|
DISK : ON
|
||||||
|
IP : ON
|
||||||
|
LOGO : ON
|
||||||
|
BARS : OFF
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also dynamically specify a different path by using the `-c` CLI argument:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ ./zfetch -c $PWD/config -s
|
||||||
|
Using custom config file: '/home/marco/Projects/zfetch/config'
|
||||||
|
HOST : OFF
|
||||||
|
OS : OFF
|
||||||
|
UPTIME : OFF
|
||||||
|
CPU : OFF
|
||||||
|
MEMORY : ON
|
||||||
|
DISK : ON
|
||||||
|
IP : ON
|
||||||
|
LOGO : OFF
|
||||||
|
BARS : ON
|
||||||
|
```
|
||||||
|
|
||||||
|
Finally, you can list all supported distribution, using the `--list-logos/-a` flag:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ /zfetch -a
|
||||||
|
Available logos: alpine, arch, debian, fedora, mint, gentoo, artix, linux, nixos, redhat, slackware, suse, ubuntu.
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[MIT](https://choosealicense.com/licenses/mit/)
|
||||||
BIN
imgs/ex1.png
Normal file
BIN
imgs/ex1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
BIN
imgs/preview.gif
Normal file
BIN
imgs/preview.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 126 KiB |
84
zfetch.c
84
zfetch.c
@@ -198,6 +198,17 @@ static const char *logo_ubuntu[] = {
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const char *logo_mint[] = {
|
||||||
|
C2 " __________",
|
||||||
|
C2 "|_ \\",
|
||||||
|
C2 " |" C7" | _____" C2 " |",
|
||||||
|
C2 " |" C7" | | | |" C2 " |",
|
||||||
|
C2 " |" C7" | | | |" C2 " |",
|
||||||
|
C2 " |" C7" \\_____/" C2 " |",
|
||||||
|
C2 " \\_________/",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
static const char *logo_suse[] = {
|
static const char *logo_suse[] = {
|
||||||
C2 " _______",
|
C2 " _______",
|
||||||
C2 "__| __ \\",
|
C2 "__| __ \\",
|
||||||
@@ -232,6 +243,7 @@ static const logo_entry_t available_logos[] = {
|
|||||||
{ C6 "arch" RESET, logo_arch },
|
{ C6 "arch" RESET, logo_arch },
|
||||||
{ C1 "debian" RESET, logo_debian },
|
{ C1 "debian" RESET, logo_debian },
|
||||||
{ C4 "fedora" RESET, logo_fedora },
|
{ C4 "fedora" RESET, logo_fedora },
|
||||||
|
{ C2 "mint" RESET, logo_mint },
|
||||||
{ C5 "gentoo" RESET, logo_gentoo },
|
{ C5 "gentoo" RESET, logo_gentoo },
|
||||||
{ C6 "artix" RESET, logo_artix },
|
{ C6 "artix" RESET, logo_artix },
|
||||||
{ C3 "linux" RESET, logo_linux },
|
{ C3 "linux" RESET, logo_linux },
|
||||||
@@ -440,6 +452,7 @@ static const char **get_logo(const char *id) {
|
|||||||
else if (STRCMP(id, "slackware")) { return logo_slackware; }
|
else if (STRCMP(id, "slackware")) { return logo_slackware; }
|
||||||
else if (STRCMP(id, "alpine")) { return logo_alpine; }
|
else if (STRCMP(id, "alpine")) { return logo_alpine; }
|
||||||
else if (STRCMP(id, "ubuntu")) { return logo_ubuntu; }
|
else if (STRCMP(id, "ubuntu")) { return logo_ubuntu; }
|
||||||
|
else if (STRCMP(id, "mint")) { return logo_mint; }
|
||||||
else if (STRCMP(id, "opensuse") || STRCMP(id, "opensuse-tumbleweed") ||
|
else if (STRCMP(id, "opensuse") || STRCMP(id, "opensuse-tumbleweed") ||
|
||||||
STRCMP(id, "opensuse-leap") || STRCMP(id, "sles") ||
|
STRCMP(id, "opensuse-leap") || STRCMP(id, "sles") ||
|
||||||
STRCMP(id, "suse")) { return logo_suse; }
|
STRCMP(id, "suse")) { return logo_suse; }
|
||||||
@@ -469,7 +482,7 @@ static const char *get_logo_accent(const char **logo) {
|
|||||||
return C5; // Magenta
|
return C5; // Magenta
|
||||||
} else if (logo == logo_linux || logo == logo_ubuntu) {
|
} else if (logo == logo_linux || logo == logo_ubuntu) {
|
||||||
return C3; // Yellow
|
return C3; // Yellow
|
||||||
} else if (logo == logo_suse) {
|
} else if (logo == logo_suse || logo == logo_mint) {
|
||||||
return C2; // Green
|
return C2; // Green
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -565,6 +578,35 @@ 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
|
||||||
*/
|
*/
|
||||||
@@ -589,16 +631,15 @@ static void get_hostname(char *buf, size_t buf_size) {
|
|||||||
static void get_uptime(char *buf, size_t buf_size) {
|
static void get_uptime(char *buf, size_t buf_size) {
|
||||||
FILE *fp = fopen("/proc/uptime", "r");
|
FILE *fp = fopen("/proc/uptime", "r");
|
||||||
uint64_t total = 0;
|
uint64_t total = 0;
|
||||||
uint64_t days, hours, minutes;
|
|
||||||
|
|
||||||
if (fp == NULL) {
|
if (fp == NULL) {
|
||||||
snprintf(buf, buf_size, "unknown");
|
snprintf(buf, buf_size, "unknown");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The /proc/uptime has two fields formatted as follows:
|
// The /proc/uptime file has two fields formatted as follows:
|
||||||
// <uptime_in_sec>.<fraction> <idle_in_sec>.<fraction>
|
// <uptime_in_sec>.<fraction> <idle_in_sec>.<fraction>
|
||||||
// We only read the seconds and ignore the fractional part
|
// We only read <uptime_in_sec> and ignore <fraction>
|
||||||
if (fscanf(fp, "%" SCNu64, &total) != 1) {
|
if (fscanf(fp, "%" SCNu64, &total) != 1) {
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
snprintf(buf, buf_size, "unknown");
|
snprintf(buf, buf_size, "unknown");
|
||||||
@@ -607,21 +648,19 @@ static void get_uptime(char *buf, size_t buf_size) {
|
|||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
days = total / 86400ULL;
|
const uint64_t days = total / 86400ULL;
|
||||||
hours = (total % 86400ULL) / 3600ULL;
|
const uint64_t hours = (total % 86400ULL) / 3600ULL;
|
||||||
minutes = (total % 3600ULL) / 60ULL;
|
const uint64_t minutes = (total % 3600ULL) / 60ULL;
|
||||||
|
const uint64_t seconds = total % 60ULL;
|
||||||
|
|
||||||
if (days > 0) {
|
size_t offset = 0;
|
||||||
snprintf(buf, buf_size, "%" PRIu64 " day%s, %" PRIu64 " hour%s, %" PRIu64 " min",
|
|
||||||
days, days == 1 ? "" : "s",
|
offset = fmt_uptime(buf, buf_size, offset, days, "day");
|
||||||
hours, hours == 1 ? "" : "s",
|
offset = fmt_uptime(buf, buf_size, offset, hours, "hour");
|
||||||
minutes);
|
offset = fmt_uptime(buf, buf_size, offset, minutes, "minute");
|
||||||
} else if (hours > 0) {
|
|
||||||
snprintf(buf, buf_size, "%" PRIu64 " hour%s, %" PRIu64 " min",
|
if (offset == 0) {
|
||||||
hours, hours == 1 ? "" : "s",
|
offset = fmt_uptime(buf, buf_size, offset, seconds, "second");
|
||||||
minutes);
|
|
||||||
} else {
|
|
||||||
snprintf(buf, buf_size, "%" PRIu64 " min", minutes);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -709,7 +748,7 @@ static size_t get_ips(char entries[][IFACE_ENTRY_LEN], size_t max_entries) {
|
|||||||
char ipv4[INET_ADDRSTRLEN];
|
char ipv4[INET_ADDRSTRLEN];
|
||||||
struct sockaddr_in *sin;
|
struct sockaddr_in *sin;
|
||||||
|
|
||||||
// Skip loopback, disabled interfaces and non-IPV4 interfaces
|
// Skip loopback, disabled interfaces and non-IPv4 interfaces
|
||||||
if (!ifa->ifa_addr) { continue; }
|
if (!ifa->ifa_addr) { continue; }
|
||||||
if (ifa->ifa_addr->sa_family != AF_INET) { continue; }
|
if (ifa->ifa_addr->sa_family != AF_INET) { continue; }
|
||||||
if (!(ifa->ifa_flags & IFF_UP)) { continue; }
|
if (!(ifa->ifa_flags & IFF_UP)) { continue; }
|
||||||
@@ -767,9 +806,9 @@ 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("%-11s %s%s%s\n", flags[idx].name,
|
printf("%-6s : %s%s%s\n", flags[idx].name,
|
||||||
enabled ? C2 : C1,
|
enabled ? C2 : C1,
|
||||||
enabled ? "enabled" : "disabled",
|
enabled ? "ON" : "OFF",
|
||||||
RESET);
|
RESET);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -865,7 +904,8 @@ int main(int argc, char **argv) {
|
|||||||
};
|
};
|
||||||
uint16_t options = 0;
|
uint16_t options = 0;
|
||||||
os_t os_release;
|
os_t os_release;
|
||||||
line_t lines[64];
|
// number of available options + max number of network interfaces
|
||||||
|
line_t lines[9 + IFACE_ENTRY_LEN];
|
||||||
size_t line_count = 0;
|
size_t line_count = 0;
|
||||||
bool list_logos = false, list_opts = false;
|
bool list_logos = false, list_opts = false;
|
||||||
int opt;
|
int opt;
|
||||||
|
|||||||
Reference in New Issue
Block a user