mirror of
https://github.com/Lennart1978/drinfo.git
synced 2026-11-09 16:20:50 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d11a083db9 | ||
|
|
0f75769eb4 | ||
|
|
825c49a796 | ||
|
|
04a196dab6 | ||
|
|
9f04f782b0 |
No files matched your search
@@ -12,7 +12,8 @@ clean:
|
||||
rm -f $(TARGET)
|
||||
|
||||
install: $(TARGET)
|
||||
sudo cp $(TARGET) /usr/local/bin/
|
||||
install -Dm755 drinfo /usr/local/bin/drinfo
|
||||
install -Dm644 drinfo.1 /usr/share/man/man1/drinfo.1
|
||||
|
||||
uninstall:
|
||||
sudo rm -f /usr/local/bin/$(TARGET)
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
.TH DRINFO 1 "June 2024" "Version 1.0.2" "User Commands"
|
||||
.SH NAME
|
||||
drinfo \- display information about drives and their storage usage
|
||||
.SH SYNOPSIS
|
||||
.B drinfo
|
||||
.RI [ OPTION ]
|
||||
.SH DESCRIPTION
|
||||
.B drinfo
|
||||
lists all detected local and network drives and shows their storage usage graphically in the terminal.
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.BR -h , --help
|
||||
Show help message and exit.
|
||||
.TP
|
||||
.BR -v , --version
|
||||
Show program version and exit.
|
||||
|
||||
.SH AUTHOR
|
||||
Lennart Martens <monkeynator78@gmail.com>
|
||||
|
||||
.SH LICENSE
|
||||
MIT License
|
||||
|
||||
.SH SEE ALSO
|
||||
.BR df (1),
|
||||
.BR lsblk (8)
|
||||
@@ -11,10 +11,11 @@
|
||||
#include <time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// Constants for terminal and display
|
||||
#define TERM_FALLBACK_WIDTH 80
|
||||
#define VERSION "1.0.1"
|
||||
#define VERSION "1.0.2"
|
||||
#define COLOR_BUFFER_SIZE 32
|
||||
#define MAX_UNITS 5
|
||||
#define BYTES_PER_KB 1024.0
|
||||
@@ -74,8 +75,49 @@
|
||||
#define MOUNT_TABLE_PATH "/proc/mounts"
|
||||
#define GVFS_BASE_PATH "/run/user/%d/gvfs"
|
||||
|
||||
// Maximum number of drives to handle
|
||||
#define MAX_DRIVES 100
|
||||
|
||||
// Constants for file system types to skip
|
||||
const char *skip_filesystems[] = {
|
||||
"proc", "sysfs", "devpts", "tmpfs", "devtmpfs", "securityfs",
|
||||
"cgroup", "cgroup2", "pstore", "efivarfs", "autofs", "debugfs",
|
||||
"tracefs", "configfs", "fusectl", "fuse.gvfsd-fuse", "binfmt_misc"};
|
||||
|
||||
// Structure to hold drive information
|
||||
typedef struct
|
||||
{
|
||||
char mount_point[MAX_PATH_LENGTH];
|
||||
char filesystem[MAX_SIZE_STR_LENGTH];
|
||||
char device[MAX_PATH_LENGTH];
|
||||
char total_str[MAX_SIZE_STR_LENGTH];
|
||||
char used_str[MAX_SIZE_STR_LENGTH];
|
||||
char available_str[MAX_SIZE_STR_LENGTH];
|
||||
unsigned long long total_bytes;
|
||||
unsigned long long used_bytes;
|
||||
unsigned long long available_bytes;
|
||||
double usage_percent;
|
||||
const char *drive_type;
|
||||
char *progress_bar;
|
||||
bool is_cloud_storage;
|
||||
char cloud_service_name[MAX_SIZE_STR_LENGTH];
|
||||
} drive_info_t;
|
||||
|
||||
char colorbuf[COLOR_BUFFER_SIZE]; // For bar colors
|
||||
|
||||
// Function to compare drives by total capacity (descending order)
|
||||
int compare_drives_by_capacity(const void *a, const void *b)
|
||||
{
|
||||
const drive_info_t *drive_a = (const drive_info_t *)a;
|
||||
const drive_info_t *drive_b = (const drive_info_t *)b;
|
||||
|
||||
if (drive_b->total_bytes > drive_a->total_bytes)
|
||||
return 1;
|
||||
if (drive_b->total_bytes < drive_a->total_bytes)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Function to display help text
|
||||
void show_help(const char *program_name)
|
||||
{
|
||||
@@ -140,7 +182,7 @@ double calculate_usage_percent(unsigned long long total, unsigned long long avai
|
||||
return ((double)used / total) * PERCENTAGE_MULTIPLIER;
|
||||
}
|
||||
|
||||
int is_physical_device(const char *fsname)
|
||||
bool is_physical_device(const char *fsname)
|
||||
{
|
||||
// Check for /dev/sd*, /dev/nvme*, /dev/hd*
|
||||
return (strncmp(fsname, "/dev/sd", DEV_SD_PREFIX_LEN) == 0 ||
|
||||
@@ -148,7 +190,7 @@ int is_physical_device(const char *fsname)
|
||||
strncmp(fsname, "/dev/hd", DEV_HD_PREFIX_LEN) == 0);
|
||||
}
|
||||
|
||||
int is_network_device(const char *fsname)
|
||||
bool is_network_device(const char *fsname)
|
||||
{
|
||||
// Check for network file systems
|
||||
return (strncmp(fsname, "//", NETWORK_PATH_PREFIX_LEN) == 0 || // SMB/CIFS shares
|
||||
@@ -156,7 +198,7 @@ int is_network_device(const char *fsname)
|
||||
strstr(fsname, ":") != NULL); // NFS and other network protocols
|
||||
}
|
||||
|
||||
int is_network_filesystem(const char *fstype)
|
||||
bool is_network_filesystem(const char *fstype)
|
||||
{
|
||||
// Check for network file system types
|
||||
return (strcmp(fstype, "nfs") == 0 ||
|
||||
@@ -170,7 +212,7 @@ int is_network_filesystem(const char *fstype)
|
||||
strncmp(fstype, "fuse.", FUSE_PREFIX_LEN) == 0); // Other FUSE-based network file systems
|
||||
}
|
||||
|
||||
int is_appimage_or_temp(const char *fsname, const char *mountpoint)
|
||||
bool is_appimage_or_temp(const char *fsname, const char *mountpoint)
|
||||
{
|
||||
// Filter out AppImages and temporary mounts
|
||||
return (strstr(fsname, ".AppImage") != NULL ||
|
||||
@@ -232,14 +274,14 @@ int max_visible_line_length(const char *lines[], int n)
|
||||
}
|
||||
|
||||
// Function to check if a directory contains cloud storage
|
||||
int is_cloud_storage_directory(const char *path)
|
||||
bool is_cloud_storage_directory(const char *path)
|
||||
{
|
||||
DIR *dir = opendir(path);
|
||||
if (!dir)
|
||||
return 0;
|
||||
return false;
|
||||
|
||||
struct dirent *entry;
|
||||
int has_cloud_storage = 0;
|
||||
bool has_cloud_storage = false;
|
||||
|
||||
while ((entry = readdir(dir)) != NULL)
|
||||
{
|
||||
@@ -254,7 +296,7 @@ int is_cloud_storage_directory(const char *path)
|
||||
strstr(entry->d_name, "onedrive") != NULL ||
|
||||
strstr(entry->d_name, "mega") != NULL))
|
||||
{
|
||||
has_cloud_storage = 1;
|
||||
has_cloud_storage = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -263,8 +305,52 @@ int is_cloud_storage_directory(const char *path)
|
||||
return has_cloud_storage;
|
||||
}
|
||||
|
||||
// Function to fill drive_info_t structure with common data
|
||||
void fill_drive_info(drive_info_t *drive,
|
||||
const char *mount_point,
|
||||
const char *filesystem,
|
||||
const char *device,
|
||||
const char *total_str,
|
||||
const char *used_str,
|
||||
const char *available_str,
|
||||
unsigned long long total_bytes,
|
||||
unsigned long long used_bytes,
|
||||
unsigned long long available_bytes,
|
||||
double usage_percent,
|
||||
const char *drive_type,
|
||||
char *progress_bar,
|
||||
bool is_cloud_storage,
|
||||
const char *cloud_service_name)
|
||||
{
|
||||
strncpy(drive->mount_point, mount_point, sizeof(drive->mount_point) - 1);
|
||||
drive->mount_point[sizeof(drive->mount_point) - 1] = '\0';
|
||||
strncpy(drive->filesystem, filesystem, sizeof(drive->filesystem) - 1);
|
||||
drive->filesystem[sizeof(drive->filesystem) - 1] = '\0';
|
||||
strncpy(drive->device, device, sizeof(drive->device) - 1);
|
||||
drive->device[sizeof(drive->device) - 1] = '\0';
|
||||
snprintf(drive->total_str, sizeof(drive->total_str), "%s", total_str);
|
||||
snprintf(drive->used_str, sizeof(drive->used_str), "%s", used_str);
|
||||
snprintf(drive->available_str, sizeof(drive->available_str), "%s", available_str);
|
||||
drive->total_bytes = total_bytes;
|
||||
drive->used_bytes = used_bytes;
|
||||
drive->available_bytes = available_bytes;
|
||||
drive->usage_percent = usage_percent;
|
||||
drive->drive_type = drive_type;
|
||||
drive->progress_bar = progress_bar;
|
||||
drive->is_cloud_storage = is_cloud_storage;
|
||||
if (cloud_service_name)
|
||||
{
|
||||
strncpy(drive->cloud_service_name, cloud_service_name, sizeof(drive->cloud_service_name) - 1);
|
||||
drive->cloud_service_name[sizeof(drive->cloud_service_name) - 1] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
drive->cloud_service_name[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
// Function to get cloud storage info from GVFS
|
||||
void get_cloud_storage_info(const char *gvfs_path, int *drive_count)
|
||||
void get_cloud_storage_info(const char *gvfs_path, drive_info_t *drives, int *drive_count)
|
||||
{
|
||||
DIR *dir = opendir(gvfs_path);
|
||||
if (!dir)
|
||||
@@ -272,7 +358,7 @@ void get_cloud_storage_info(const char *gvfs_path, int *drive_count)
|
||||
|
||||
struct dirent *entry;
|
||||
|
||||
while ((entry = readdir(dir)) != NULL)
|
||||
while ((entry = readdir(dir)) != NULL && *drive_count < MAX_DRIVES)
|
||||
{
|
||||
// Use stat if d_type is not available
|
||||
struct stat st;
|
||||
@@ -375,20 +461,13 @@ void get_cloud_storage_info(const char *gvfs_path, int *drive_count)
|
||||
service_name = "MEGA";
|
||||
}
|
||||
|
||||
// Output
|
||||
printf(" " BOLD_YELLOW_FORMAT "Network Drive %d (%s)" RESET_COLOR_FORMAT "\n", *drive_count + 1, service_name);
|
||||
printf(" Mount point: %s\n", full_path);
|
||||
printf(" Filesystem: %s\n", "fuse.gvfsd-fuse");
|
||||
printf(" Device: %s\n", entry->d_name);
|
||||
printf(" Total size: %s\n", total_str);
|
||||
printf(" Used: %s\n", used_str);
|
||||
printf(" Available: %s\n", available_str);
|
||||
// Store information in drive_info_t structure
|
||||
drive_info_t *drive = &drives[*drive_count];
|
||||
fill_drive_info(drive, full_path, "fuse.gvfsd-fuse", entry->d_name,
|
||||
total_str, used_str, available_str,
|
||||
total_bytes, used_bytes, available_bytes,
|
||||
usage_percent, "Network Drive", bar, true, service_name);
|
||||
|
||||
int bar_visible_len = visible_length(bar);
|
||||
int bar_padding = content_width - bar_visible_len;
|
||||
printf(" %s%*s\n", bar, bar_padding, "");
|
||||
|
||||
free(bar);
|
||||
(*drive_count)++;
|
||||
}
|
||||
}
|
||||
@@ -413,6 +492,11 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
// Array to store all drive information
|
||||
drive_info_t drives[MAX_DRIVES];
|
||||
int drive_count = 0;
|
||||
|
||||
// Open the mount table
|
||||
FILE *mtab = setmntent(MOUNT_TABLE_PATH, "r");
|
||||
if (mtab == NULL)
|
||||
@@ -422,32 +506,28 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
struct mntent *entry;
|
||||
int drive_count = 0;
|
||||
|
||||
// Loop through all mount points
|
||||
while ((entry = getmntent(mtab)) != NULL)
|
||||
// Loop through all mount points and collect drive information
|
||||
while ((entry = getmntent(mtab)) != NULL && drive_count < MAX_DRIVES)
|
||||
{
|
||||
// Skip special file systems
|
||||
if (strcmp(entry->mnt_type, "proc") == 0 ||
|
||||
strcmp(entry->mnt_type, "sysfs") == 0 ||
|
||||
strcmp(entry->mnt_type, "devpts") == 0 ||
|
||||
strcmp(entry->mnt_type, "tmpfs") == 0 ||
|
||||
strcmp(entry->mnt_type, "devtmpfs") == 0 ||
|
||||
strcmp(entry->mnt_type, "securityfs") == 0 ||
|
||||
strcmp(entry->mnt_type, "cgroup") == 0 ||
|
||||
strcmp(entry->mnt_type, "cgroup2") == 0 ||
|
||||
strcmp(entry->mnt_type, "pstore") == 0 ||
|
||||
strcmp(entry->mnt_type, "efivarfs") == 0 ||
|
||||
strcmp(entry->mnt_type, "autofs") == 0 ||
|
||||
strcmp(entry->mnt_type, "debugfs") == 0 ||
|
||||
strcmp(entry->mnt_type, "tracefs") == 0 ||
|
||||
strcmp(entry->mnt_type, "configfs") == 0 ||
|
||||
strcmp(entry->mnt_type, "fusectl") == 0 ||
|
||||
strcmp(entry->mnt_type, "fuse.gvfsd-fuse") == 0 ||
|
||||
strcmp(entry->mnt_type, "binfmt_misc") == 0)
|
||||
const int skip_count = sizeof(skip_filesystems) / sizeof(skip_filesystems[0]);
|
||||
|
||||
bool should_skip = false;
|
||||
for (int i = 0; i < skip_count; i++)
|
||||
{
|
||||
if (strcmp(entry->mnt_type, skip_filesystems[i]) == 0)
|
||||
{
|
||||
should_skip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (should_skip)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Show physical drives and network drives
|
||||
if (!is_physical_device(entry->mnt_fsname) &&
|
||||
!is_network_device(entry->mnt_fsname) &&
|
||||
@@ -506,7 +586,7 @@ int main(int argc, char *argv[])
|
||||
if (!bar)
|
||||
{
|
||||
perror("malloc");
|
||||
exit(1);
|
||||
continue;
|
||||
}
|
||||
bar[0] = '\0';
|
||||
for (int i = 0; i < bar_length; i++)
|
||||
@@ -531,22 +611,12 @@ int main(int argc, char *argv[])
|
||||
strncat(bar, "\033[48;2;64;64;64m\033[38;2;160;160;160m░\033[0m", bar_bufsize - strlen(bar) - 1);
|
||||
}
|
||||
}
|
||||
size_t barline_bufsize = bar_bufsize + BARLINE_BUFFER_EXTRA;
|
||||
char *barline = malloc(barline_bufsize);
|
||||
if (!barline)
|
||||
{
|
||||
perror("malloc");
|
||||
free(bar);
|
||||
exit(1);
|
||||
}
|
||||
snprintf(barline, barline_bufsize, "[%-*s]", bar_length, ""); // Placeholder for padding
|
||||
snprintf(barline, barline_bufsize, "[%-*s]", bar_length, ""); // for padding
|
||||
|
||||
// Content
|
||||
// Determine drive type
|
||||
const char *drive_type;
|
||||
if (is_physical_device(entry->mnt_fsname))
|
||||
{
|
||||
drive_type = "Physical Drive";
|
||||
drive_type = "Local Drive";
|
||||
}
|
||||
else if (is_network_filesystem(entry->mnt_type) || is_network_device(entry->mnt_fsname))
|
||||
{
|
||||
@@ -556,20 +626,14 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
drive_type = "Other Drive";
|
||||
}
|
||||
printf(" " BOLD_YELLOW_FORMAT "%s %d" RESET_COLOR_FORMAT "\n", drive_type, drive_count + 1);
|
||||
printf(" Mount point: %s\n", entry->mnt_dir);
|
||||
printf(" Filesystem: %s\n", entry->mnt_type);
|
||||
printf(" Device: %s\n", entry->mnt_fsname);
|
||||
printf(" Total size: %s\n", total_str);
|
||||
printf(" Used: %s\n", used_str);
|
||||
printf(" Available: %s\n", available_str);
|
||||
// Progress bar
|
||||
int bar_visible_len = visible_length(bar);
|
||||
int bar_padding = content_width - bar_visible_len;
|
||||
printf(" %s%*s\n", bar, bar_padding, "");
|
||||
|
||||
free(bar);
|
||||
free(barline);
|
||||
// Store information in drive_info_t structure
|
||||
drive_info_t *drive = &drives[drive_count];
|
||||
fill_drive_info(drive, entry->mnt_dir, entry->mnt_type, entry->mnt_fsname,
|
||||
total_str, used_str, available_str,
|
||||
total_bytes, used_bytes, available_bytes,
|
||||
usage_percent, drive_type, bar, false, NULL);
|
||||
|
||||
drive_count++;
|
||||
}
|
||||
|
||||
@@ -580,7 +644,48 @@ int main(int argc, char *argv[])
|
||||
snprintf(gvfs_path, sizeof(gvfs_path), GVFS_BASE_PATH, getuid());
|
||||
if (is_cloud_storage_directory(gvfs_path))
|
||||
{
|
||||
get_cloud_storage_info(gvfs_path, &drive_count);
|
||||
get_cloud_storage_info(gvfs_path, drives, &drive_count);
|
||||
}
|
||||
|
||||
// Sort drives by capacity (largest first)
|
||||
qsort(drives, drive_count, sizeof(drive_info_t), compare_drives_by_capacity);
|
||||
|
||||
// Display sorted drives
|
||||
for (int i = 0; i < drive_count; i++)
|
||||
{
|
||||
drive_info_t *drive = &drives[i];
|
||||
|
||||
// Display drive information
|
||||
if (drive->is_cloud_storage)
|
||||
{
|
||||
printf(" " BOLD_YELLOW_FORMAT "Network Drive %d (%s)" RESET_COLOR_FORMAT "\n", i + 1, drive->cloud_service_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf(" " BOLD_YELLOW_FORMAT "%s %d" RESET_COLOR_FORMAT "\n", drive->drive_type, i + 1);
|
||||
}
|
||||
printf(" Mount point: %s\n", drive->mount_point);
|
||||
printf(" Filesystem: %s\n", drive->filesystem);
|
||||
printf(" Device: %s\n", drive->device);
|
||||
printf(" Total size: %s\n", drive->total_str);
|
||||
printf(" Used: %s\n", drive->used_str);
|
||||
printf(" Available: %s\n", drive->available_str);
|
||||
|
||||
// Progress bar
|
||||
int terminal_width = get_terminal_width();
|
||||
int box_width = terminal_width * TERMINAL_WIDTH_PERCENTAGE / TERMINAL_WIDTH_DIVISOR;
|
||||
if (box_width > MAX_BOX_WIDTH)
|
||||
box_width = MAX_BOX_WIDTH;
|
||||
if (box_width < MIN_BOX_WIDTH)
|
||||
box_width = MIN_BOX_WIDTH;
|
||||
int content_width = box_width - FRAME_PADDING;
|
||||
|
||||
int bar_visible_len = visible_length(drive->progress_bar);
|
||||
int bar_padding = content_width - bar_visible_len;
|
||||
printf(" %s%*s\n", drive->progress_bar, bar_padding, "");
|
||||
|
||||
// Free allocated memory
|
||||
free(drive->progress_bar);
|
||||
}
|
||||
|
||||
if (drive_count == 0)
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 321 KiB After Width: | Height: | Size: 330 KiB |
Reference in new issue
Block a user