mirror of
https://github.com/Lennart1978/drinfo.git
synced 2026-11-09 16:20:50 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1b2df4f3fa | ||
|
|
589e1d7b32 | ||
|
|
e495d158a2 | ||
|
|
30d6ad50d8 | ||
|
|
d11a083db9 | ||
|
|
0f75769eb4 | ||
|
|
825c49a796 | ||
|
|
04a196dab6 | ||
|
|
9f04f782b0 | ||
|
|
7267af7a57 | ||
|
|
8ada6ea6f1 | ||
|
|
f715474b61 | ||
|
|
835be26eda | ||
|
|
767340195f |
No files matched your search
@@ -12,9 +12,12 @@ clean:
|
|||||||
rm -f $(TARGET)
|
rm -f $(TARGET)
|
||||||
|
|
||||||
install: $(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
|
||||||
|
sudo mandb > /dev/null 2>&1
|
||||||
|
|
||||||
uninstall:
|
uninstall:
|
||||||
sudo rm -f /usr/local/bin/$(TARGET)
|
sudo rm -f /usr/local/bin/$(TARGET)
|
||||||
|
sudo rm -f /usr/share/man/man1/$(TARGET).1
|
||||||
|
|
||||||
.PHONY: all clean install uninstall
|
.PHONY: all clean install uninstall
|
||||||
@@ -10,20 +10,43 @@ A lightweight command-line tool to monitor disk usage on Linux systems with beau
|
|||||||
- **Colorful Progress Bars**: Visual representation of disk usage with gradient colors (green → yellow → red)
|
- **Colorful Progress Bars**: Visual representation of disk usage with gradient colors (green → yellow → red)
|
||||||
- **Human-Readable Sizes**: Displays sizes in B, KB, MB, GB, TB format
|
- **Human-Readable Sizes**: Displays sizes in B, KB, MB, GB, TB format
|
||||||
- **Terminal Responsive**: Adapts to terminal width for optimal display
|
- **Terminal Responsive**: Adapts to terminal width for optimal display
|
||||||
- **Detailed Information**: Shows mount point, filesystem type, device path, and usage statistics
|
- **Detailed Information**: Shows mount point, filesystem type, device path, UUID, label, mount options, used, available and inodes + SMART status (only as root)
|
||||||
|
- **JSON Output**: Export drive information in JSON format for easy parsing
|
||||||
|
- **Sorting**: Sort drives by size, usage, mount point, or name
|
||||||
|
- **No Color Mode**: Disable ANSI colors for scripts or logs
|
||||||
|
|
||||||
## Build
|
## Usage
|
||||||
|
|
||||||
|
```bash
|
||||||
|
drinfo [OPTIONS]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
- `-h, --help`: Show help message
|
||||||
|
- `-v, --version`: Show program version
|
||||||
|
- `-j, --json`: Output in JSON format
|
||||||
|
- `-n, --no-color`: Disable color output
|
||||||
|
- `-s, --sort TYPE`: Sort drives by TYPE (`size`, `usage`, `mount`, `name`)
|
||||||
|
|
||||||
|
## Build executable: drinfo
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
make
|
make
|
||||||
```
|
```
|
||||||
|
|
||||||
## install
|
## install with man page
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo make install
|
sudo make install
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Uninstall
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo make uninstall
|
||||||
|
```
|
||||||
|
|
||||||
## Screenshot
|
## Screenshot
|
||||||
|
|
||||||

|

|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
.TH DRINFO 1 "November 2025" "Version 1.2.0" "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 mount point, filesystem type, device path,
|
||||||
|
UUID, label, mount options, used, available and inodes + SMART status (only as root).
|
||||||
|
.P
|
||||||
|
It provides a visual representation of disk usage with gradient colored progress bars (green -> yellow -> red).
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
.BR -h , --help
|
||||||
|
Show help message and exit.
|
||||||
|
.TP
|
||||||
|
.BR -v , --version
|
||||||
|
Show program version and exit.
|
||||||
|
.TP
|
||||||
|
.BR -j , --json
|
||||||
|
Output drive information in JSON format. This is useful for parsing the output in scripts or other programs.
|
||||||
|
.TP
|
||||||
|
.BR -n , --no-color
|
||||||
|
Disable ANSI color codes in the output. Use this option when redirecting output to a file or when running in a terminal that does not support colors.
|
||||||
|
.TP
|
||||||
|
.BR -s , --sort \ \fITYPE\fP
|
||||||
|
Sort the drives by the specified \fITYPE\fP. Available types are:
|
||||||
|
.RS
|
||||||
|
.TP
|
||||||
|
.B size
|
||||||
|
Sort by total size (descending). This is the default.
|
||||||
|
.TP
|
||||||
|
.B usage
|
||||||
|
Sort by usage percentage (descending).
|
||||||
|
.TP
|
||||||
|
.B mount
|
||||||
|
Sort alphabetically by mount point.
|
||||||
|
.TP
|
||||||
|
.B name
|
||||||
|
Sort alphabetically by device name.
|
||||||
|
.RE
|
||||||
|
|
||||||
|
.SH AUTHOR
|
||||||
|
Lennart Martens <monkeynator78@gmail.com>
|
||||||
|
|
||||||
|
.SH LICENSE
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
.SH SEE ALSO
|
||||||
|
.BR df (1),
|
||||||
|
.BR lsblk (8)
|
||||||
@@ -11,10 +11,14 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
|
||||||
// Constants for terminal and display
|
// Constants for terminal and display
|
||||||
#define TERM_FALLBACK_WIDTH 80
|
#define TERM_FALLBACK_WIDTH 80
|
||||||
#define VERSION "1.0.0"
|
#define VERSION "1.2.0"
|
||||||
#define COLOR_BUFFER_SIZE 32
|
#define COLOR_BUFFER_SIZE 32
|
||||||
#define MAX_UNITS 5
|
#define MAX_UNITS 5
|
||||||
#define BYTES_PER_KB 1024.0
|
#define BYTES_PER_KB 1024.0
|
||||||
@@ -39,7 +43,7 @@
|
|||||||
#define BARLINE_BUFFER_EXTRA 16
|
#define BARLINE_BUFFER_EXTRA 16
|
||||||
|
|
||||||
// Constants for terminal width calculations
|
// Constants for terminal width calculations
|
||||||
#define TERMINAL_WIDTH_PERCENTAGE 80
|
#define TERMINAL_WIDTH_PERCENTAGE 4
|
||||||
#define TERMINAL_WIDTH_DIVISOR 5
|
#define TERMINAL_WIDTH_DIVISOR 5
|
||||||
#define MAX_BOX_WIDTH 120
|
#define MAX_BOX_WIDTH 120
|
||||||
#define MIN_BOX_WIDTH 40
|
#define MIN_BOX_WIDTH 40
|
||||||
@@ -67,15 +71,99 @@
|
|||||||
#define BACKGROUND_COLOR_FORMAT "\033[48;2;%d;%d;%dm"
|
#define BACKGROUND_COLOR_FORMAT "\033[48;2;%d;%d;%dm"
|
||||||
#define BLUE_TEXT_FORMAT "\033[38;2;%d;%d;%dm"
|
#define BLUE_TEXT_FORMAT "\033[38;2;%d;%d;%dm"
|
||||||
#define RESET_FORMAT "\033[0m"
|
#define RESET_FORMAT "\033[0m"
|
||||||
#define BOLD_YELLOW_FORMAT "\033[1;33m"
|
|
||||||
#define RESET_COLOR_FORMAT "\033[0m"
|
|
||||||
|
|
||||||
// Constants for file system types
|
// Constants for file system types
|
||||||
#define MOUNT_TABLE_PATH "/proc/mounts"
|
#define MOUNT_TABLE_PATH "/proc/mounts"
|
||||||
#define GVFS_BASE_PATH "/run/user/%d/gvfs"
|
#define GVFS_BASE_PATH "/run/user/%d/gvfs"
|
||||||
|
|
||||||
|
// Maximum number of drives to handle
|
||||||
|
#define MAX_DRIVES 100
|
||||||
|
|
||||||
|
// Global options
|
||||||
|
bool opt_json = false;
|
||||||
|
bool opt_no_color = false;
|
||||||
|
enum { SORT_SIZE, SORT_USAGE, SORT_MOUNT, SORT_NAME } opt_sort = SORT_SIZE;
|
||||||
|
|
||||||
|
// Color strings (can be disabled)
|
||||||
|
const char *c_bold_yellow = "\033[1;33m";
|
||||||
|
const char *c_reset = "\033[0m";
|
||||||
|
|
||||||
|
// 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",
|
||||||
|
"fuse.portal"};
|
||||||
|
|
||||||
|
// 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 uuid[128];
|
||||||
|
char label[128];
|
||||||
|
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];
|
||||||
|
char mount_options[MAX_TEMP_BUFFER_LENGTH];
|
||||||
|
unsigned long long total_inodes;
|
||||||
|
unsigned long long used_inodes;
|
||||||
|
double inode_usage;
|
||||||
|
} drive_info_t;
|
||||||
|
|
||||||
char colorbuf[COLOR_BUFFER_SIZE]; // For bar colors
|
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 compare drives by usage (descending order)
|
||||||
|
int compare_drives_by_usage(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->usage_percent > drive_a->usage_percent)
|
||||||
|
return 1;
|
||||||
|
if (drive_b->usage_percent < drive_a->usage_percent)
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to compare drives by mount point (alphabetical)
|
||||||
|
int compare_drives_by_mount(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;
|
||||||
|
return strcmp(drive_a->mount_point, drive_b->mount_point);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to compare drives by device name (alphabetical)
|
||||||
|
int compare_drives_by_name(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;
|
||||||
|
return strcmp(drive_a->device, drive_b->device);
|
||||||
|
}
|
||||||
|
|
||||||
// Function to display help text
|
// Function to display help text
|
||||||
void show_help(const char *program_name)
|
void show_help(const char *program_name)
|
||||||
{
|
{
|
||||||
@@ -86,6 +174,9 @@ void show_help(const char *program_name)
|
|||||||
printf("Options:\n");
|
printf("Options:\n");
|
||||||
printf(" -h, --help Show this help message\n");
|
printf(" -h, --help Show this help message\n");
|
||||||
printf(" -v, --version Show program version\n");
|
printf(" -v, --version Show program version\n");
|
||||||
|
printf(" -j, --json Output in JSON format\n");
|
||||||
|
printf(" -n, --no-color Disable color output\n");
|
||||||
|
printf(" -s, --sort TYPE Sort drives by TYPE (size, usage, mount, name)\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("This program is licensed under the MIT License.\n");
|
printf("This program is licensed under the MIT License.\n");
|
||||||
printf("https://github.com/lennart1978/drinfo\n");
|
printf("https://github.com/lennart1978/drinfo\n");
|
||||||
@@ -140,7 +231,7 @@ double calculate_usage_percent(unsigned long long total, unsigned long long avai
|
|||||||
return ((double)used / total) * PERCENTAGE_MULTIPLIER;
|
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*
|
// Check for /dev/sd*, /dev/nvme*, /dev/hd*
|
||||||
return (strncmp(fsname, "/dev/sd", DEV_SD_PREFIX_LEN) == 0 ||
|
return (strncmp(fsname, "/dev/sd", DEV_SD_PREFIX_LEN) == 0 ||
|
||||||
@@ -148,7 +239,7 @@ int is_physical_device(const char *fsname)
|
|||||||
strncmp(fsname, "/dev/hd", DEV_HD_PREFIX_LEN) == 0);
|
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
|
// Check for network file systems
|
||||||
return (strncmp(fsname, "//", NETWORK_PATH_PREFIX_LEN) == 0 || // SMB/CIFS shares
|
return (strncmp(fsname, "//", NETWORK_PATH_PREFIX_LEN) == 0 || // SMB/CIFS shares
|
||||||
@@ -156,7 +247,7 @@ int is_network_device(const char *fsname)
|
|||||||
strstr(fsname, ":") != NULL); // NFS and other network protocols
|
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
|
// Check for network file system types
|
||||||
return (strcmp(fstype, "nfs") == 0 ||
|
return (strcmp(fstype, "nfs") == 0 ||
|
||||||
@@ -170,7 +261,7 @@ int is_network_filesystem(const char *fstype)
|
|||||||
strncmp(fstype, "fuse.", FUSE_PREFIX_LEN) == 0); // Other FUSE-based network file systems
|
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
|
// Filter out AppImages and temporary mounts
|
||||||
return (strstr(fsname, ".AppImage") != NULL ||
|
return (strstr(fsname, ".AppImage") != NULL ||
|
||||||
@@ -181,6 +272,11 @@ int is_appimage_or_temp(const char *fsname, const char *mountpoint)
|
|||||||
// Helper for true-color gradient (red-yellow-green)
|
// Helper for true-color gradient (red-yellow-green)
|
||||||
void get_bar_color(int idx, int max, char *buffer, size_t size)
|
void get_bar_color(int idx, int max, char *buffer, size_t size)
|
||||||
{
|
{
|
||||||
|
if (opt_no_color) {
|
||||||
|
buffer[0] = '\0';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// New gradient: 0% = green (0,255,0), 50% = yellow (255,255,0), 100% = red (255,0,0)
|
// New gradient: 0% = green (0,255,0), 50% = yellow (255,255,0), 100% = red (255,0,0)
|
||||||
float ratio = (float)idx / (float)(max - 1);
|
float ratio = (float)idx / (float)(max - 1);
|
||||||
int r, g, b;
|
int r, g, b;
|
||||||
@@ -218,28 +314,15 @@ int visible_length(const char *s)
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adjusted: calculate max visible line length for block
|
|
||||||
int max_visible_line_length(const char *lines[], int n)
|
|
||||||
{
|
|
||||||
int max = 0;
|
|
||||||
for (int i = 0; i < n; ++i)
|
|
||||||
{
|
|
||||||
int len = visible_length(lines[i]);
|
|
||||||
if (len > max)
|
|
||||||
max = len;
|
|
||||||
}
|
|
||||||
return max;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to check if a directory contains cloud storage
|
// 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);
|
DIR *dir = opendir(path);
|
||||||
if (!dir)
|
if (!dir)
|
||||||
return 0;
|
return false;
|
||||||
|
|
||||||
struct dirent *entry;
|
struct dirent *entry;
|
||||||
int has_cloud_storage = 0;
|
bool has_cloud_storage = false;
|
||||||
|
|
||||||
while ((entry = readdir(dir)) != NULL)
|
while ((entry = readdir(dir)) != NULL)
|
||||||
{
|
{
|
||||||
@@ -254,7 +337,7 @@ int is_cloud_storage_directory(const char *path)
|
|||||||
strstr(entry->d_name, "onedrive") != NULL ||
|
strstr(entry->d_name, "onedrive") != NULL ||
|
||||||
strstr(entry->d_name, "mega") != NULL))
|
strstr(entry->d_name, "mega") != NULL))
|
||||||
{
|
{
|
||||||
has_cloud_storage = 1;
|
has_cloud_storage = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -263,8 +346,88 @@ int is_cloud_storage_directory(const char *path)
|
|||||||
return has_cloud_storage;
|
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 *uuid,
|
||||||
|
const char *label,
|
||||||
|
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,
|
||||||
|
const char *mount_options,
|
||||||
|
unsigned long long total_inodes,
|
||||||
|
unsigned long long used_inodes,
|
||||||
|
double inode_usage)
|
||||||
|
{
|
||||||
|
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';
|
||||||
|
if (uuid)
|
||||||
|
{
|
||||||
|
strncpy(drive->uuid, uuid, sizeof(drive->uuid) - 1);
|
||||||
|
drive->uuid[sizeof(drive->uuid) - 1] = '\0';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
drive->uuid[0] = '\0';
|
||||||
|
}
|
||||||
|
if (label)
|
||||||
|
{
|
||||||
|
strncpy(drive->label, label, sizeof(drive->label) - 1);
|
||||||
|
drive->label[sizeof(drive->label) - 1] = '\0';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
drive->label[0] = '\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';
|
||||||
|
}
|
||||||
|
if (mount_options)
|
||||||
|
{
|
||||||
|
strncpy(drive->mount_options, mount_options, sizeof(drive->mount_options) - 1);
|
||||||
|
drive->mount_options[sizeof(drive->mount_options) - 1] = '\0';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
drive->mount_options[0] = '\0';
|
||||||
|
}
|
||||||
|
drive->total_inodes = total_inodes;
|
||||||
|
drive->used_inodes = used_inodes;
|
||||||
|
drive->inode_usage = inode_usage;
|
||||||
|
}
|
||||||
|
|
||||||
// Function to get cloud storage info from GVFS
|
// 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);
|
DIR *dir = opendir(gvfs_path);
|
||||||
if (!dir)
|
if (!dir)
|
||||||
@@ -272,7 +435,7 @@ void get_cloud_storage_info(const char *gvfs_path, int *drive_count)
|
|||||||
|
|
||||||
struct dirent *entry;
|
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
|
// Use stat if d_type is not available
|
||||||
struct stat st;
|
struct stat st;
|
||||||
@@ -324,7 +487,7 @@ void get_cloud_storage_info(const char *gvfs_path, int *drive_count)
|
|||||||
int text_length = strlen(percent_text);
|
int text_length = strlen(percent_text);
|
||||||
int text_start = filled_length > text_length ? (filled_length - text_length) / 2 : 0;
|
int text_start = filled_length > text_length ? (filled_length - text_length) / 2 : 0;
|
||||||
|
|
||||||
// Create progress bar (same logic as before)
|
// Create progress bar
|
||||||
size_t bar_bufsize = bar_length * MAX_BAR_BUFFER_MULTIPLIER + 1;
|
size_t bar_bufsize = bar_length * MAX_BAR_BUFFER_MULTIPLIER + 1;
|
||||||
char *bar = malloc(bar_bufsize);
|
char *bar = malloc(bar_bufsize);
|
||||||
if (!bar)
|
if (!bar)
|
||||||
@@ -337,22 +500,35 @@ void get_cloud_storage_info(const char *gvfs_path, int *drive_count)
|
|||||||
{
|
{
|
||||||
if (i >= text_start && i < text_start + text_length && i < filled_length)
|
if (i >= text_start && i < text_start + text_length && i < filled_length)
|
||||||
{
|
{
|
||||||
|
if (!opt_no_color) {
|
||||||
get_bar_color(i, bar_length, colorbuf, sizeof(colorbuf));
|
get_bar_color(i, bar_length, colorbuf, sizeof(colorbuf));
|
||||||
int r, g, b;
|
int r, g, b;
|
||||||
sscanf(colorbuf, COLOR_FORMAT, &r, &g, &b);
|
sscanf(colorbuf, COLOR_FORMAT, &r, &g, &b);
|
||||||
char tmp[MAX_TEMP_BUFFER_LENGTH];
|
char tmp[MAX_TEMP_BUFFER_LENGTH];
|
||||||
snprintf(tmp, sizeof(tmp), BACKGROUND_COLOR_FORMAT BLUE_TEXT_FORMAT "%c" RESET_FORMAT, r, g, b, BLUE_TEXT_R, BLUE_TEXT_G, BLUE_TEXT_B, percent_text[i - text_start]);
|
snprintf(tmp, sizeof(tmp), BACKGROUND_COLOR_FORMAT BLUE_TEXT_FORMAT "%c" RESET_FORMAT, r, g, b, BLUE_TEXT_R, BLUE_TEXT_G, BLUE_TEXT_B, percent_text[i - text_start]);
|
||||||
strncat(bar, tmp, bar_bufsize - strlen(bar) - 1);
|
strncat(bar, tmp, bar_bufsize - strlen(bar) - 1);
|
||||||
|
} else {
|
||||||
|
char tmp[2] = {percent_text[i - text_start], '\0'};
|
||||||
|
strncat(bar, tmp, bar_bufsize - strlen(bar) - 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (i < filled_length)
|
else if (i < filled_length)
|
||||||
{
|
{
|
||||||
|
if (!opt_no_color) {
|
||||||
get_bar_color(i, bar_length, colorbuf, sizeof(colorbuf));
|
get_bar_color(i, bar_length, colorbuf, sizeof(colorbuf));
|
||||||
strncat(bar, colorbuf, bar_bufsize - strlen(bar) - 1);
|
strncat(bar, colorbuf, bar_bufsize - strlen(bar) - 1);
|
||||||
strncat(bar, "█" RESET_FORMAT, bar_bufsize - strlen(bar) - 1);
|
strncat(bar, "█" RESET_FORMAT, bar_bufsize - strlen(bar) - 1);
|
||||||
|
} else {
|
||||||
|
strncat(bar, "█", bar_bufsize - strlen(bar) - 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (!opt_no_color) {
|
||||||
strncat(bar, "\033[48;2;64;64;64m\033[38;2;160;160;160m░\033[0m", bar_bufsize - strlen(bar) - 1);
|
strncat(bar, "\033[48;2;64;64;64m\033[38;2;160;160;160m░\033[0m", bar_bufsize - strlen(bar) - 1);
|
||||||
|
} else {
|
||||||
|
strncat(bar, "░", bar_bufsize - strlen(bar) - 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,20 +551,16 @@ void get_cloud_storage_info(const char *gvfs_path, int *drive_count)
|
|||||||
service_name = "MEGA";
|
service_name = "MEGA";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output
|
// Store information in drive_info_t structure
|
||||||
printf(" " BOLD_YELLOW_FORMAT "Network Drive %d (%s)" RESET_COLOR_FORMAT "\n", *drive_count + 1, service_name);
|
drive_info_t *drive = &drives[*drive_count];
|
||||||
printf(" Mount point: %s\n", full_path);
|
fill_drive_info(drive, full_path, "fuse.gvfsd-fuse", entry->d_name,
|
||||||
printf(" Filesystem: %s\n", "fuse.gvfsd-fuse");
|
NULL, NULL,
|
||||||
printf(" Device: %s\n", entry->d_name);
|
total_str, used_str, available_str,
|
||||||
printf(" Total size: %s\n", total_str);
|
total_bytes, used_bytes, available_bytes,
|
||||||
printf(" Used: %s\n", used_str);
|
usage_percent, "Network Drive", bar, true, service_name, NULL,
|
||||||
printf(" Available: %s\n", available_str);
|
(unsigned long long)fs_info.f_blocks, (unsigned long long)fs_info.f_files,
|
||||||
|
(double)fs_info.f_files / (double)fs_info.f_blocks);
|
||||||
|
|
||||||
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)++;
|
(*drive_count)++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -396,58 +568,194 @@ void get_cloud_storage_info(const char *gvfs_path, int *drive_count)
|
|||||||
closedir(dir);
|
closedir(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
void get_uuid_and_label(const char *device, char *uuid, size_t uuid_size, char *label, size_t label_size)
|
||||||
{
|
{
|
||||||
if (argc > 1)
|
uuid[0] = '\0';
|
||||||
|
label[0] = '\0';
|
||||||
|
|
||||||
|
char resolved_device[PATH_MAX];
|
||||||
|
if (!realpath(device, resolved_device))
|
||||||
{
|
{
|
||||||
if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0)
|
// Wenn das Gerät nicht auflösbar ist, abbrechen
|
||||||
{
|
return;
|
||||||
show_help(argv[0]);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
else if (strcmp(argv[1], "-v") == 0 || strcmp(argv[1], "--version") == 0)
|
|
||||||
|
// UUID suchen
|
||||||
|
DIR *uuid_dir = opendir("/dev/disk/by-uuid/");
|
||||||
|
if (uuid_dir)
|
||||||
{
|
{
|
||||||
show_version();
|
struct dirent *entry;
|
||||||
return 0;
|
char full_path[PATH_MAX];
|
||||||
|
char resolved_link[PATH_MAX];
|
||||||
|
while ((entry = readdir(uuid_dir)) != NULL)
|
||||||
|
{
|
||||||
|
if (entry->d_name[0] == '.')
|
||||||
|
continue;
|
||||||
|
snprintf(full_path, sizeof(full_path), "/dev/disk/by-uuid/%s", entry->d_name);
|
||||||
|
if (realpath(full_path, resolved_link))
|
||||||
|
{
|
||||||
|
if (strcmp(resolved_link, resolved_device) == 0)
|
||||||
|
{
|
||||||
|
strncpy(uuid, entry->d_name, uuid_size - 1);
|
||||||
|
uuid[uuid_size - 1] = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir(uuid_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Label suchen
|
||||||
|
DIR *label_dir = opendir("/dev/disk/by-label/");
|
||||||
|
if (label_dir)
|
||||||
|
{
|
||||||
|
struct dirent *entry;
|
||||||
|
char full_path[PATH_MAX];
|
||||||
|
char resolved_link[PATH_MAX];
|
||||||
|
while ((entry = readdir(label_dir)) != NULL)
|
||||||
|
{
|
||||||
|
if (entry->d_name[0] == '.')
|
||||||
|
continue;
|
||||||
|
snprintf(full_path, sizeof(full_path), "/dev/disk/by-label/%s", entry->d_name);
|
||||||
|
if (realpath(full_path, resolved_link))
|
||||||
|
{
|
||||||
|
if (strcmp(resolved_link, resolved_device) == 0)
|
||||||
|
{
|
||||||
|
strncpy(label, entry->d_name, label_size - 1);
|
||||||
|
label[label_size - 1] = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir(label_dir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\n");
|
// Helper function: Query SMART status (only for root and physical devices)
|
||||||
|
void get_smart_status(const char *device, char *status, size_t status_size)
|
||||||
|
{
|
||||||
|
status[0] = '\0';
|
||||||
|
if (geteuid() != 0)
|
||||||
|
return;
|
||||||
|
// Allow all /dev/sd*, /dev/nvme*, /dev/hd* (including partitions)
|
||||||
|
if (!(
|
||||||
|
strncmp(device, "/dev/sd", 7) == 0 ||
|
||||||
|
strncmp(device, "/dev/nvme", 9) == 0 ||
|
||||||
|
strncmp(device, "/dev/hd", 7) == 0))
|
||||||
|
return;
|
||||||
|
|
||||||
|
char cmd[256], line[256];
|
||||||
|
snprintf(cmd, sizeof(cmd), "smartctl -H %s 2>/dev/null", device);
|
||||||
|
FILE *fp = popen(cmd, "r");
|
||||||
|
if (!fp)
|
||||||
|
return;
|
||||||
|
while (fgets(line, sizeof(line), fp))
|
||||||
|
{
|
||||||
|
if (strstr(line, "SMART overall-health self-assessment test result") || strstr(line, "SMART Health Status"))
|
||||||
|
{
|
||||||
|
char *p = strchr(line, ':');
|
||||||
|
if (p)
|
||||||
|
{
|
||||||
|
p++;
|
||||||
|
while (*p == ' ' || *p == '\t')
|
||||||
|
p++;
|
||||||
|
strncpy(status, p, status_size - 1);
|
||||||
|
status[status_size - 1] = '\0';
|
||||||
|
char *nl = strchr(status, '\n');
|
||||||
|
if (nl)
|
||||||
|
*nl = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (strstr(line, "PASSED"))
|
||||||
|
{
|
||||||
|
strncpy(status, "PASSED", status_size - 1);
|
||||||
|
status[status_size - 1] = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (strstr(line, "FAILED"))
|
||||||
|
{
|
||||||
|
strncpy(status, "FAILED", status_size - 1);
|
||||||
|
status[status_size - 1] = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (strstr(line, "UNKNOWN"))
|
||||||
|
{
|
||||||
|
strncpy(status, "UNKNOWN", status_size - 1);
|
||||||
|
status[status_size - 1] = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (strstr(line, "NOT AVAILABLE"))
|
||||||
|
{
|
||||||
|
strncpy(status, "NOT AVAILABLE", status_size - 1);
|
||||||
|
status[status_size - 1] = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_json(drive_info_t *drives, int count) {
|
||||||
|
printf("[\n");
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
drive_info_t *d = &drives[i];
|
||||||
|
printf(" {\n");
|
||||||
|
printf(" \"device\": \"%s\",\n", d->device);
|
||||||
|
printf(" \"mount_point\": \"%s\",\n", d->mount_point);
|
||||||
|
printf(" \"filesystem\": \"%s\",\n", d->filesystem);
|
||||||
|
printf(" \"total_bytes\": %llu,\n", d->total_bytes);
|
||||||
|
printf(" \"used_bytes\": %llu,\n", d->used_bytes);
|
||||||
|
printf(" \"available_bytes\": %llu,\n", d->available_bytes);
|
||||||
|
printf(" \"usage_percent\": %.1f,\n", d->usage_percent);
|
||||||
|
printf(" \"type\": \"%s\",\n", d->drive_type);
|
||||||
|
printf(" \"is_cloud\": %s,\n", d->is_cloud_storage ? "true" : "false");
|
||||||
|
printf(" \"cloud_service\": \"%s\",\n", d->cloud_service_name);
|
||||||
|
printf(" \"uuid\": \"%s\",\n", d->uuid);
|
||||||
|
printf(" \"label\": \"%s\",\n", d->label);
|
||||||
|
printf(" \"mount_options\": \"%s\",\n", d->mount_options);
|
||||||
|
printf(" \"total_inodes\": %llu,\n", d->total_inodes);
|
||||||
|
printf(" \"used_inodes\": %llu,\n", d->used_inodes);
|
||||||
|
printf(" \"inode_usage\": %.1f\n", d->inode_usage);
|
||||||
|
if (i < count - 1) printf(" },\n");
|
||||||
|
else printf(" }\n");
|
||||||
|
}
|
||||||
|
printf("]\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void discover_drives(drive_info_t *drives, int *drive_count) {
|
||||||
|
*drive_count = 0;
|
||||||
|
|
||||||
// Open the mount table
|
// Open the mount table
|
||||||
FILE *mtab = setmntent(MOUNT_TABLE_PATH, "r");
|
FILE *mtab = setmntent(MOUNT_TABLE_PATH, "r");
|
||||||
if (mtab == NULL)
|
if (mtab == NULL)
|
||||||
{
|
{
|
||||||
perror("Error opening mount table");
|
perror("Error opening mount table");
|
||||||
return 1;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct mntent *entry;
|
struct mntent *entry;
|
||||||
int drive_count = 0;
|
|
||||||
|
|
||||||
// Loop through all mount points
|
// Loop through all mount points and collect drive information
|
||||||
while ((entry = getmntent(mtab)) != NULL)
|
while ((entry = getmntent(mtab)) != NULL && *drive_count < MAX_DRIVES)
|
||||||
{
|
{
|
||||||
// Skip special file systems
|
// Skip special file systems
|
||||||
if (strcmp(entry->mnt_type, "proc") == 0 ||
|
const int skip_count = sizeof(skip_filesystems) / sizeof(skip_filesystems[0]);
|
||||||
strcmp(entry->mnt_type, "sysfs") == 0 ||
|
|
||||||
strcmp(entry->mnt_type, "devpts") == 0 ||
|
bool should_skip = false;
|
||||||
strcmp(entry->mnt_type, "tmpfs") == 0 ||
|
for (int i = 0; i < skip_count; i++)
|
||||||
strcmp(entry->mnt_type, "devtmpfs") == 0 ||
|
{
|
||||||
strcmp(entry->mnt_type, "securityfs") == 0 ||
|
if (strcmp(entry->mnt_type, skip_filesystems[i]) == 0)
|
||||||
strcmp(entry->mnt_type, "cgroup") == 0 ||
|
{
|
||||||
strcmp(entry->mnt_type, "cgroup2") == 0 ||
|
should_skip = true;
|
||||||
strcmp(entry->mnt_type, "pstore") == 0 ||
|
break;
|
||||||
strcmp(entry->mnt_type, "efivarfs") == 0 ||
|
}
|
||||||
strcmp(entry->mnt_type, "autofs") == 0 ||
|
}
|
||||||
strcmp(entry->mnt_type, "debugfs") == 0 ||
|
|
||||||
strcmp(entry->mnt_type, "tracefs") == 0 ||
|
if (should_skip)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show physical drives and network drives
|
// Show physical drives and network drives
|
||||||
if (!is_physical_device(entry->mnt_fsname) &&
|
if (!is_physical_device(entry->mnt_fsname) &&
|
||||||
!is_network_device(entry->mnt_fsname) &&
|
!is_network_device(entry->mnt_fsname) &&
|
||||||
@@ -480,6 +788,12 @@ int main(int argc, char *argv[])
|
|||||||
format_bytes(used_bytes, used_str, sizeof(used_str));
|
format_bytes(used_bytes, used_str, sizeof(used_str));
|
||||||
format_bytes(available_bytes, available_str, sizeof(available_str));
|
format_bytes(available_bytes, available_str, sizeof(available_str));
|
||||||
|
|
||||||
|
// Inode-Infos
|
||||||
|
unsigned long long total_inodes = fs_info.f_files;
|
||||||
|
unsigned long long free_inodes = fs_info.f_favail;
|
||||||
|
unsigned long long used_inodes = total_inodes > 0 ? total_inodes - free_inodes : 0;
|
||||||
|
double inode_usage = (total_inodes > 0) ? ((double)used_inodes / total_inodes) * 100.0 : 0.0;
|
||||||
|
|
||||||
// Target width: 80% of terminal width or max. 120 characters
|
// Target width: 80% of terminal width or max. 120 characters
|
||||||
int terminal_width = get_terminal_width();
|
int terminal_width = get_terminal_width();
|
||||||
int box_width = terminal_width * TERMINAL_WIDTH_PERCENTAGE / TERMINAL_WIDTH_DIVISOR;
|
int box_width = terminal_width * TERMINAL_WIDTH_PERCENTAGE / TERMINAL_WIDTH_DIVISOR;
|
||||||
@@ -506,47 +820,50 @@ int main(int argc, char *argv[])
|
|||||||
if (!bar)
|
if (!bar)
|
||||||
{
|
{
|
||||||
perror("malloc");
|
perror("malloc");
|
||||||
exit(1);
|
continue;
|
||||||
}
|
}
|
||||||
bar[0] = '\0';
|
bar[0] = '\0';
|
||||||
for (int i = 0; i < bar_length; i++)
|
for (int i = 0; i < bar_length; i++)
|
||||||
{
|
{
|
||||||
if (i >= text_start && i < text_start + text_length && i < filled_length)
|
if (i >= text_start && i < text_start + text_length && i < filled_length)
|
||||||
{
|
{
|
||||||
|
if (!opt_no_color) {
|
||||||
get_bar_color(i, bar_length, colorbuf, sizeof(colorbuf));
|
get_bar_color(i, bar_length, colorbuf, sizeof(colorbuf));
|
||||||
int r, g, b;
|
int r, g, b;
|
||||||
sscanf(colorbuf, COLOR_FORMAT, &r, &g, &b);
|
sscanf(colorbuf, COLOR_FORMAT, &r, &g, &b);
|
||||||
char tmp[MAX_TEMP_BUFFER_LENGTH];
|
char tmp[MAX_TEMP_BUFFER_LENGTH];
|
||||||
snprintf(tmp, sizeof(tmp), BACKGROUND_COLOR_FORMAT BLUE_TEXT_FORMAT "%c" RESET_FORMAT, r, g, b, BLUE_TEXT_R, BLUE_TEXT_G, BLUE_TEXT_B, percent_text[i - text_start]);
|
snprintf(tmp, sizeof(tmp), BACKGROUND_COLOR_FORMAT BLUE_TEXT_FORMAT "%c" RESET_FORMAT, r, g, b, BLUE_TEXT_R, BLUE_TEXT_G, BLUE_TEXT_B, percent_text[i - text_start]);
|
||||||
strncat(bar, tmp, bar_bufsize - strlen(bar) - 1);
|
strncat(bar, tmp, bar_bufsize - strlen(bar) - 1);
|
||||||
|
} else {
|
||||||
|
char tmp[2] = {percent_text[i - text_start], '\0'};
|
||||||
|
strncat(bar, tmp, bar_bufsize - strlen(bar) - 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (i < filled_length)
|
else if (i < filled_length)
|
||||||
{
|
{
|
||||||
|
if (!opt_no_color) {
|
||||||
get_bar_color(i, bar_length, colorbuf, sizeof(colorbuf));
|
get_bar_color(i, bar_length, colorbuf, sizeof(colorbuf));
|
||||||
strncat(bar, colorbuf, bar_bufsize - strlen(bar) - 1);
|
strncat(bar, colorbuf, bar_bufsize - strlen(bar) - 1);
|
||||||
strncat(bar, "█" RESET_FORMAT, bar_bufsize - strlen(bar) - 1);
|
strncat(bar, "█" RESET_FORMAT, bar_bufsize - strlen(bar) - 1);
|
||||||
|
} else {
|
||||||
|
strncat(bar, "█", bar_bufsize - strlen(bar) - 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (!opt_no_color) {
|
||||||
strncat(bar, "\033[48;2;64;64;64m\033[38;2;160;160;160m░\033[0m", bar_bufsize - strlen(bar) - 1);
|
strncat(bar, "\033[48;2;64;64;64m\033[38;2;160;160;160m░\033[0m", bar_bufsize - strlen(bar) - 1);
|
||||||
|
} else {
|
||||||
|
strncat(bar, "░", 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;
|
const char *drive_type;
|
||||||
if (is_physical_device(entry->mnt_fsname))
|
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))
|
else if (is_network_filesystem(entry->mnt_type) || is_network_device(entry->mnt_fsname))
|
||||||
{
|
{
|
||||||
@@ -556,21 +873,21 @@ int main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
drive_type = "Other Drive";
|
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);
|
// UUID und Label ermitteln
|
||||||
free(barline);
|
char uuid[128], label[128];
|
||||||
drive_count++;
|
get_uuid_and_label(entry->mnt_fsname, uuid, sizeof(uuid), label, sizeof(label));
|
||||||
|
|
||||||
|
// 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,
|
||||||
|
uuid, label,
|
||||||
|
total_str, used_str, available_str,
|
||||||
|
total_bytes, used_bytes, available_bytes,
|
||||||
|
usage_percent, drive_type, bar, false, NULL, entry->mnt_opts,
|
||||||
|
total_inodes, used_inodes, inode_usage);
|
||||||
|
|
||||||
|
(*drive_count)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
endmntent(mtab);
|
endmntent(mtab);
|
||||||
@@ -580,7 +897,144 @@ int main(int argc, char *argv[])
|
|||||||
snprintf(gvfs_path, sizeof(gvfs_path), GVFS_BASE_PATH, getuid());
|
snprintf(gvfs_path, sizeof(gvfs_path), GVFS_BASE_PATH, getuid());
|
||||||
if (is_cloud_storage_directory(gvfs_path))
|
if (is_cloud_storage_directory(gvfs_path))
|
||||||
{
|
{
|
||||||
get_cloud_storage_info(gvfs_path, &drive_count);
|
get_cloud_storage_info(gvfs_path, drives, drive_count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
static struct option long_options[] = {
|
||||||
|
{"help", no_argument, 0, 'h'},
|
||||||
|
{"version", no_argument, 0, 'v'},
|
||||||
|
{"json", no_argument, 0, 'j'},
|
||||||
|
{"no-color", no_argument, 0, 'n'},
|
||||||
|
{"sort", required_argument, 0, 's'},
|
||||||
|
{0, 0, 0, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
int opt;
|
||||||
|
int option_index = 0;
|
||||||
|
|
||||||
|
while ((opt = getopt_long(argc, argv, "hvjns:", long_options, &option_index)) != -1)
|
||||||
|
{
|
||||||
|
switch (opt)
|
||||||
|
{
|
||||||
|
case 'h':
|
||||||
|
show_help(argv[0]);
|
||||||
|
return 0;
|
||||||
|
case 'v':
|
||||||
|
show_version();
|
||||||
|
return 0;
|
||||||
|
case 'j':
|
||||||
|
opt_json = true;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
opt_no_color = true;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
if (strcmp(optarg, "size") == 0) opt_sort = SORT_SIZE;
|
||||||
|
else if (strcmp(optarg, "usage") == 0) opt_sort = SORT_USAGE;
|
||||||
|
else if (strcmp(optarg, "mount") == 0) opt_sort = SORT_MOUNT;
|
||||||
|
else if (strcmp(optarg, "name") == 0) opt_sort = SORT_NAME;
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "Invalid sort option: %s\n", optarg);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opt_no_color) {
|
||||||
|
c_bold_yellow = "";
|
||||||
|
c_reset = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!opt_json) {
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array to store all drive information
|
||||||
|
drive_info_t drives[MAX_DRIVES];
|
||||||
|
int drive_count = 0;
|
||||||
|
|
||||||
|
discover_drives(drives, &drive_count);
|
||||||
|
|
||||||
|
// Sort drives
|
||||||
|
switch (opt_sort) {
|
||||||
|
case SORT_SIZE:
|
||||||
|
qsort(drives, drive_count, sizeof(drive_info_t), compare_drives_by_capacity);
|
||||||
|
break;
|
||||||
|
case SORT_USAGE:
|
||||||
|
qsort(drives, drive_count, sizeof(drive_info_t), compare_drives_by_usage);
|
||||||
|
break;
|
||||||
|
case SORT_MOUNT:
|
||||||
|
qsort(drives, drive_count, sizeof(drive_info_t), compare_drives_by_mount);
|
||||||
|
break;
|
||||||
|
case SORT_NAME:
|
||||||
|
qsort(drives, drive_count, sizeof(drive_info_t), compare_drives_by_name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opt_json) {
|
||||||
|
print_json(drives, drive_count);
|
||||||
|
} else {
|
||||||
|
// 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(" %sNetwork Drive %d (%s)%s\n", c_bold_yellow, i + 1, drive->cloud_service_name, c_reset);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf(" %s%s %d%s\n", c_bold_yellow, drive->drive_type, i + 1, c_reset);
|
||||||
|
}
|
||||||
|
printf(" Mount point: %s\n", drive->mount_point);
|
||||||
|
printf(" Filesystem: %s\n", drive->filesystem);
|
||||||
|
printf(" Device: %s\n", drive->device);
|
||||||
|
printf(" UUID: %s\n", drive->uuid[0] ? drive->uuid : "-");
|
||||||
|
printf(" Label: %s\n", drive->label[0] ? drive->label : "-");
|
||||||
|
printf(" Mount options: %s\n", drive->mount_options);
|
||||||
|
printf(" Total size: %s\n", drive->total_str);
|
||||||
|
printf(" Used: %s\n", drive->used_str);
|
||||||
|
printf(" Available: %s\n", drive->available_str);
|
||||||
|
printf(" Inodes: %llu/%llu (%.1f%% used)\n", drive->used_inodes, drive->total_inodes, drive->inode_usage);
|
||||||
|
|
||||||
|
// SMART status only for root and physical devices
|
||||||
|
if (geteuid() == 0 && !drive->is_cloud_storage && strcmp(drive->drive_type, "Local Drive") == 0)
|
||||||
|
{
|
||||||
|
char smart_status[128];
|
||||||
|
get_smart_status(drive->device, smart_status, sizeof(smart_status));
|
||||||
|
if (smart_status[0])
|
||||||
|
{
|
||||||
|
printf(" SMART: %s\n", smart_status);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf(" SMART: No data\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
if (drive_count == 0)
|
||||||
@@ -591,6 +1045,7 @@ int main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
printf("A total of %d drives found.\n", drive_count);
|
printf("A total of %d drives found.\n", drive_count);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 321 KiB After Width: | Height: | Size: 244 KiB |
Reference in new issue
Block a user