implemented system monitor
simple system monitor to view cpu usage, ram and so on. this is not a finished implementation but i just made refreshing work fine. used alternative screen buffer, and buffered output which build the entire display in memory and then outputs once. there are still many bugs, like the list isnt displaying processes sorted, or maybe not working at all. some of the border characters are misaligned, and there is alot more usefull info that could be added. if there is anything in specific that you would want to see in this command, or in the program in general, just hit me up on github and request it, and ill add it as fast as i can. --marcus
This commit is contained in:
BIN
autocorrect.o
BIN
autocorrect.o
Binary file not shown.
BIN
bookmarks.o
BIN
bookmarks.o
Binary file not shown.
@@ -38,7 +38,7 @@ char *builtin_str[] = {
|
||||
"bookmark", "bookmarks", "goto", "unbookmark", "focus_timer",
|
||||
"weather", "grep", "grep-text", "ripgrep", "fzf",
|
||||
"clip", "echo", "theme", "loc", "git_status",
|
||||
"gg", "ls", "stats",
|
||||
"gg", "ls", "stats", "monitor",
|
||||
};
|
||||
|
||||
// Array of function pointers to built-in command implementations
|
||||
@@ -53,7 +53,7 @@ int (*builtin_func[])(char **) = {
|
||||
&lsh_ripgrep, &lsh_fzf_native, &lsh_clip, &lsh_echo,
|
||||
&lsh_theme, &lsh_loc, &lsh_git_status, &lsh_gg,
|
||||
lsh_dir,
|
||||
&lsh_stats,
|
||||
&lsh_stats, &builtin_monitor,
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#define BUILTINS_H
|
||||
|
||||
#include "common.h"
|
||||
#include "system_monitor.h"
|
||||
#include <time.h>
|
||||
|
||||
// Syntax highlighting definitions using ANSI colors
|
||||
@@ -85,9 +86,8 @@ void lsh_add_to_history(const char *command);
|
||||
// Get number of builtin commands
|
||||
int lsh_num_builtins(void);
|
||||
|
||||
|
||||
// Expose the builtin command strings and function pointers
|
||||
extern char *builtin_str[];
|
||||
// Expose the builtin command strings and function pointers
|
||||
extern char *builtin_str[];
|
||||
extern int (*builtin_func[])(char **);
|
||||
|
||||
/**
|
||||
|
||||
BIN
builtins.o
BIN
builtins.o
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
fzf_native.o
BIN
fzf_native.o
Binary file not shown.
Binary file not shown.
BIN
line_reader.o
BIN
line_reader.o
Binary file not shown.
BIN
ps_command.o
BIN
ps_command.o
Binary file not shown.
Binary file not shown.
390
system_monitor.c
Normal file
390
system_monitor.c
Normal file
@@ -0,0 +1,390 @@
|
||||
#include "system_monitor.h"
|
||||
#include "common.h"
|
||||
|
||||
static struct termios old_termios;
|
||||
|
||||
int builtin_monitor(char **args) {
|
||||
SystemStats stats;
|
||||
ProcessInfo processes[50];
|
||||
int proc_count;
|
||||
int refresh_rate = 1; // seconds
|
||||
|
||||
if (args[1] != NULL && strcmp(args[1], "--help") == 0) {
|
||||
printf("monitor: Real-time system monitoring dashboard\n");
|
||||
printf("Usage: monitor [refresh_rate]\n");
|
||||
printf("Press 'q' to quit, 'r' to refresh immediately\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (args[1] != NULL) {
|
||||
refresh_rate = atoi(args[1]);
|
||||
if (refresh_rate < 1) refresh_rate = 1;
|
||||
}
|
||||
|
||||
// Setup terminal for raw input
|
||||
tcgetattr(STDIN_FILENO, &old_termios);
|
||||
struct termios new_termios = old_termios;
|
||||
new_termios.c_lflag &= ~(ICANON | ECHO);
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &new_termios);
|
||||
|
||||
// Make stdin non-blocking
|
||||
int flags = fcntl(STDIN_FILENO, F_GETFL, 0);
|
||||
fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);
|
||||
|
||||
// Enter alternative screen buffer
|
||||
printf("\033[?1049h");
|
||||
hide_cursor();
|
||||
fflush(stdout);
|
||||
|
||||
while (1) {
|
||||
get_system_stats(&stats);
|
||||
proc_count = get_process_info(processes, 50);
|
||||
display_dashboard(&stats, processes, proc_count);
|
||||
|
||||
// Check for user input
|
||||
if (kbhit()) {
|
||||
char c = getchar();
|
||||
if (c == 'q' || c == 'Q') break;
|
||||
if (c == 'r' || c == 'R') continue; // refresh immediately
|
||||
}
|
||||
|
||||
sleep(refresh_rate);
|
||||
}
|
||||
|
||||
// Restore terminal
|
||||
show_cursor();
|
||||
// Exit alternative screen buffer
|
||||
printf("\033[?1049l");
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &old_termios);
|
||||
fcntl(STDIN_FILENO, F_SETFL, flags);
|
||||
fflush(stdout);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void display_dashboard(SystemStats *stats, ProcessInfo *processes, int proc_count) {
|
||||
char buffer[256];
|
||||
char display_buffer[8192]; // Large buffer for entire display
|
||||
char progress_buf[50];
|
||||
char mem_used_str[32], mem_total_str[32];
|
||||
char disk_read_str[32], disk_write_str[32];
|
||||
char net_rx_str[32], net_tx_str[32];
|
||||
|
||||
time_t now = time(NULL);
|
||||
struct tm *tm_info = localtime(&now);
|
||||
|
||||
// Format all the data first
|
||||
float mem_percent = (float)stats->memory_used / stats->memory_total * 100;
|
||||
format_bytes(stats->memory_used, mem_used_str);
|
||||
format_bytes(stats->memory_total, mem_total_str);
|
||||
format_bytes(stats->disk_read, disk_read_str);
|
||||
format_bytes(stats->disk_write, disk_write_str);
|
||||
format_bytes(stats->net_rx, net_rx_str);
|
||||
format_bytes(stats->net_tx, net_tx_str);
|
||||
|
||||
// Build entire display in buffer
|
||||
int pos = sprintf(display_buffer, "\033[H"); // Move to home position
|
||||
|
||||
pos += sprintf(display_buffer + pos,
|
||||
"╔══════════════════════════════════════════════════════════════════════════════╗\n"
|
||||
"║ SYSTEM MONITOR DASHBOARD ║\n"
|
||||
"║ %02d:%02d:%02d %02d/%02d/%04d ║\n"
|
||||
"╠══════════════════════════════════════════════════════════════════════════════╣\n",
|
||||
tm_info->tm_hour, tm_info->tm_min, tm_info->tm_sec,
|
||||
tm_info->tm_mday, tm_info->tm_mon + 1, tm_info->tm_year + 1900);
|
||||
|
||||
// CPU Usage
|
||||
format_progress_bar((int)stats->cpu_percent, 40, progress_buf);
|
||||
pos += sprintf(display_buffer + pos, "║ CPU Usage: %s %5.1f%% ║\n", progress_buf, stats->cpu_percent);
|
||||
|
||||
// Memory Usage
|
||||
format_progress_bar((int)mem_percent, 40, progress_buf);
|
||||
pos += sprintf(display_buffer + pos, "║ Memory: %s %5.1f%% ║\n", progress_buf, mem_percent);
|
||||
pos += sprintf(display_buffer + pos, "║ Used: %-15s / %-15s ║\n",
|
||||
mem_used_str, mem_total_str);
|
||||
|
||||
pos += sprintf(display_buffer + pos,
|
||||
"║ Disk I/O: Read: %-20s ║\n"
|
||||
"║ Write: %-20s ║\n"
|
||||
"║ Network: RX: %-20s ║\n"
|
||||
"║ TX: %-20s ║\n"
|
||||
"╠══════════════════════════════════════════════════════════════════════════════╣\n"
|
||||
"║ TOP PROCESSES ║\n"
|
||||
"╠═══════╦══════════════════════════════╦═══════╦══════════╦═══════════════════╣\n"
|
||||
"║ PID ║ NAME ║ STATE ║ CPU%% ║ MEMORY ║\n"
|
||||
"╠═══════╬══════════════════════════════╬═══════╬══════════╬═══════════════════╣\n",
|
||||
disk_read_str, disk_write_str, net_rx_str, net_tx_str);
|
||||
|
||||
for (int i = 0; i < proc_count && i < 10; i++) {
|
||||
format_bytes(processes[i].memory, buffer);
|
||||
pos += sprintf(display_buffer + pos, "║ %5d ║ %-28s ║ %c ║ %6.1f%% ║ %17s ║\n",
|
||||
processes[i].pid,
|
||||
processes[i].name,
|
||||
processes[i].state,
|
||||
processes[i].cpu_percent,
|
||||
buffer);
|
||||
}
|
||||
|
||||
pos += sprintf(display_buffer + pos,
|
||||
"╚═══════╩══════════════════════════════╩═══════╩══════════╩═══════════════════╝\n"
|
||||
"Press 'q' to quit, 'r' to refresh ");
|
||||
|
||||
// Output entire buffer at once
|
||||
printf("%s", display_buffer);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void get_system_stats(SystemStats *stats) {
|
||||
FILE *fp;
|
||||
char buffer[1024];
|
||||
static unsigned long prev_idle = 0, prev_total = 0;
|
||||
static unsigned long prev_disk_read = 0, prev_disk_write = 0;
|
||||
static unsigned long prev_net_rx = 0, prev_net_tx = 0;
|
||||
|
||||
// CPU Usage
|
||||
fp = fopen("/proc/stat", "r");
|
||||
if (fp) {
|
||||
fgets(buffer, sizeof(buffer), fp);
|
||||
unsigned long user, nice, system, idle, iowait, irq, softirq;
|
||||
sscanf(buffer, "cpu %lu %lu %lu %lu %lu %lu %lu",
|
||||
&user, &nice, &system, &idle, &iowait, &irq, &softirq);
|
||||
|
||||
unsigned long total = user + nice + system + idle + iowait + irq + softirq;
|
||||
unsigned long total_diff = total - prev_total;
|
||||
unsigned long idle_diff = idle - prev_idle;
|
||||
|
||||
if (total_diff > 0) {
|
||||
stats->cpu_percent = 100.0 * (total_diff - idle_diff) / total_diff;
|
||||
} else {
|
||||
stats->cpu_percent = 0.0;
|
||||
}
|
||||
|
||||
prev_total = total;
|
||||
prev_idle = idle;
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
// Memory Usage - Read from /proc/meminfo for accuracy
|
||||
fp = fopen("/proc/meminfo", "r");
|
||||
if (fp) {
|
||||
unsigned long mem_total = 0, mem_free = 0, mem_available = 0;
|
||||
unsigned long buffers = 0, cached = 0;
|
||||
|
||||
while (fgets(buffer, sizeof(buffer), fp)) {
|
||||
if (sscanf(buffer, "MemTotal: %lu kB", &mem_total) == 1) {
|
||||
stats->memory_total = mem_total * 1024;
|
||||
} else if (sscanf(buffer, "MemAvailable: %lu kB", &mem_available) == 1) {
|
||||
// MemAvailable accounts for buffers/cache that can be reclaimed
|
||||
stats->memory_used = (mem_total - mem_available) * 1024;
|
||||
} else if (sscanf(buffer, "MemFree: %lu kB", &mem_free) == 1) {
|
||||
// Fallback if MemAvailable is not available
|
||||
if (mem_available == 0) {
|
||||
mem_free = mem_free;
|
||||
}
|
||||
} else if (sscanf(buffer, "Buffers: %lu kB", &buffers) == 1) {
|
||||
// For fallback calculation
|
||||
} else if (sscanf(buffer, "Cached: %lu kB", &cached) == 1) {
|
||||
// For fallback calculation
|
||||
}
|
||||
}
|
||||
|
||||
// If MemAvailable wasn't found, calculate manually
|
||||
if (mem_available == 0 && mem_total > 0) {
|
||||
stats->memory_used = (mem_total - mem_free - buffers - cached) * 1024;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
// Disk I/O
|
||||
fp = fopen("/proc/diskstats", "r");
|
||||
if (fp) {
|
||||
unsigned long read_sectors = 0, write_sectors = 0;
|
||||
while (fgets(buffer, sizeof(buffer), fp)) {
|
||||
unsigned long r_sectors, w_sectors;
|
||||
char device[32];
|
||||
if (sscanf(buffer, "%*d %*d %31s %*d %*d %lu %*d %*d %*d %lu",
|
||||
device, &r_sectors, &w_sectors) == 3) {
|
||||
if (strncmp(device, "sd", 2) == 0 || strncmp(device, "nvme", 4) == 0) {
|
||||
read_sectors += r_sectors;
|
||||
write_sectors += w_sectors;
|
||||
}
|
||||
}
|
||||
}
|
||||
stats->disk_read = (read_sectors - prev_disk_read) * 512;
|
||||
stats->disk_write = (write_sectors - prev_disk_write) * 512;
|
||||
prev_disk_read = read_sectors;
|
||||
prev_disk_write = write_sectors;
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
// Network I/O
|
||||
fp = fopen("/proc/net/dev", "r");
|
||||
if (fp) {
|
||||
fgets(buffer, sizeof(buffer), fp); // skip header
|
||||
fgets(buffer, sizeof(buffer), fp); // skip header
|
||||
|
||||
unsigned long rx_bytes = 0, tx_bytes = 0;
|
||||
while (fgets(buffer, sizeof(buffer), fp)) {
|
||||
char interface[32];
|
||||
unsigned long rx, tx;
|
||||
if (sscanf(buffer, " %31[^:]: %lu %*d %*d %*d %*d %*d %*d %*d %lu",
|
||||
interface, &rx, &tx) == 3) {
|
||||
if (strcmp(interface, "lo") != 0) { // skip loopback
|
||||
rx_bytes += rx;
|
||||
tx_bytes += tx;
|
||||
}
|
||||
}
|
||||
}
|
||||
stats->net_rx = rx_bytes - prev_net_rx;
|
||||
stats->net_tx = tx_bytes - prev_net_tx;
|
||||
prev_net_rx = rx_bytes;
|
||||
prev_net_tx = tx_bytes;
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
int get_process_info(ProcessInfo *processes, int max_processes) {
|
||||
DIR *proc_dir;
|
||||
struct dirent *entry;
|
||||
FILE *fp;
|
||||
char path[256];
|
||||
char buffer[1024];
|
||||
int count = 0;
|
||||
|
||||
proc_dir = opendir("/proc");
|
||||
if (!proc_dir) return 0;
|
||||
|
||||
while ((entry = readdir(proc_dir)) != NULL && count < max_processes) {
|
||||
if (!isdigit(entry->d_name[0])) continue;
|
||||
|
||||
int pid = atoi(entry->d_name);
|
||||
processes[count].pid = pid;
|
||||
|
||||
// Get process name and state
|
||||
snprintf(path, sizeof(path), "/proc/%d/stat", pid);
|
||||
fp = fopen(path, "r");
|
||||
if (fp) {
|
||||
if (fgets(buffer, sizeof(buffer), fp)) {
|
||||
char *name_start = strchr(buffer, '(');
|
||||
char *name_end = strrchr(buffer, ')');
|
||||
if (name_start && name_end) {
|
||||
int name_len = name_end - name_start - 1;
|
||||
if (name_len > 255) name_len = 255;
|
||||
strncpy(processes[count].name, name_start + 1, name_len);
|
||||
processes[count].name[name_len] = '\0';
|
||||
|
||||
char *state_pos = name_end + 2;
|
||||
processes[count].state = *state_pos;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
// Get memory usage
|
||||
snprintf(path, sizeof(path), "/proc/%d/status", pid);
|
||||
fp = fopen(path, "r");
|
||||
if (fp) {
|
||||
while (fgets(buffer, sizeof(buffer), fp)) {
|
||||
if (strncmp(buffer, "VmRSS:", 6) == 0) {
|
||||
unsigned long mem_kb;
|
||||
sscanf(buffer, "VmRSS: %lu kB", &mem_kb);
|
||||
processes[count].memory = mem_kb * 1024;
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
processes[count].cpu_percent = 0.0; // Simplified for this example
|
||||
count++;
|
||||
}
|
||||
|
||||
closedir(proc_dir);
|
||||
|
||||
// Sort by memory usage (descending)
|
||||
for (int i = 0; i < count - 1; i++) {
|
||||
for (int j = i + 1; j < count; j++) {
|
||||
if (processes[i].memory < processes[j].memory) {
|
||||
ProcessInfo temp = processes[i];
|
||||
processes[i] = processes[j];
|
||||
processes[j] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void clear_screen(void) {
|
||||
printf("\033[2J\033[H");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void move_cursor(int row, int col) {
|
||||
printf("\033[%d;%dH", row, col);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void hide_cursor(void) {
|
||||
printf("\033[?25l");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void show_cursor(void) {
|
||||
printf("\033[?25h");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
int kbhit(void) {
|
||||
int ch = getchar();
|
||||
if (ch != EOF) {
|
||||
ungetc(ch, stdin);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void draw_progress_bar(int percentage, int width) {
|
||||
int filled = (percentage * width) / 100;
|
||||
printf("[");
|
||||
for (int i = 0; i < width; i++) {
|
||||
if (i < filled) {
|
||||
printf("█");
|
||||
} else {
|
||||
printf(" ");
|
||||
}
|
||||
}
|
||||
printf("]");
|
||||
}
|
||||
|
||||
void format_progress_bar(int percentage, int width, char *buffer) {
|
||||
int filled = (percentage * width) / 100;
|
||||
int pos = 0;
|
||||
buffer[pos++] = '[';
|
||||
for (int i = 0; i < width; i++) {
|
||||
if (i < filled) {
|
||||
buffer[pos++] = '#'; // Use # instead of Unicode block
|
||||
} else {
|
||||
buffer[pos++] = ' ';
|
||||
}
|
||||
}
|
||||
buffer[pos++] = ']';
|
||||
buffer[pos] = '\0';
|
||||
}
|
||||
|
||||
void format_bytes(unsigned long bytes, char *buffer) {
|
||||
const char *units[] = {"B", "KB", "MB", "GB", "TB"};
|
||||
int unit = 0;
|
||||
double size = bytes;
|
||||
|
||||
while (size >= 1024 && unit < 4) {
|
||||
size /= 1024;
|
||||
unit++;
|
||||
}
|
||||
|
||||
if (unit == 0) {
|
||||
snprintf(buffer, 64, "%lu %s", bytes, units[unit]);
|
||||
} else {
|
||||
snprintf(buffer, 64, "%.1f %s", size, units[unit]);
|
||||
}
|
||||
}
|
||||
49
system_monitor.h
Normal file
49
system_monitor.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#ifndef SYSTEM_MONITOR_H
|
||||
#define SYSTEM_MONITOR_H
|
||||
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include <termios.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
|
||||
typedef struct {
|
||||
float cpu_percent;
|
||||
unsigned long memory_used;
|
||||
unsigned long memory_total;
|
||||
unsigned long disk_read;
|
||||
unsigned long disk_write;
|
||||
unsigned long net_rx;
|
||||
unsigned long net_tx;
|
||||
int process_count;
|
||||
} SystemStats;
|
||||
|
||||
typedef struct {
|
||||
int pid;
|
||||
char name[256];
|
||||
float cpu_percent;
|
||||
unsigned long memory;
|
||||
char state;
|
||||
} ProcessInfo;
|
||||
|
||||
int builtin_monitor(char **args);
|
||||
void display_dashboard(SystemStats *stats, ProcessInfo *processes,
|
||||
int proc_count);
|
||||
void get_system_stats(SystemStats *stats);
|
||||
int get_process_info(ProcessInfo *processes, int max_processes);
|
||||
void clear_screen(void);
|
||||
void move_cursor(int row, int col);
|
||||
void hide_cursor(void);
|
||||
void show_cursor(void);
|
||||
int kbhit(void);
|
||||
void draw_progress_bar(int percentage, int width);
|
||||
void format_progress_bar(int percentage, int width, char *buffer);
|
||||
void format_bytes(unsigned long bytes, char *buffer);
|
||||
|
||||
#endif
|
||||
BIN
system_monitor.o
Normal file
BIN
system_monitor.o
Normal file
Binary file not shown.
BIN
tab_complete.o
BIN
tab_complete.o
Binary file not shown.
Reference in New Issue
Block a user