FEAT: VFS overhaul

This commit is contained in:
boreddevnl
2026-04-12 17:53:31 +02:00
parent 921e8a5658
commit 700839e6be
48 changed files with 1897 additions and 482 deletions

View File

@@ -14,7 +14,7 @@ int main(int argc, char **argv) {
printf("Manual for: %s\n", argv[1]);
printf("---------------------------\n");
strcpy(path, "A:/Library/man/");
strcpy(path, "/Library/man/");
strcat(path, argv[1]);
strcat(path, ".txt");

View File

@@ -9,15 +9,6 @@
#define MAX_ASCII_WIDTH 80
#define MAX_INFO_LINES 10
static char* strchr(const char *s, int c) {
while (*s != (char)c) {
if (!*s++) {
return 0;
}
}
return (char *)s;
}
static char* strncpy(char *dest, const char *src, size_t n) {
size_t i;
for (i = 0; i < n && src[i] != '\0'; i++) dest[i] = src[i];
@@ -117,7 +108,7 @@ static char* trim(char *str) {
}
static void set_config_defaults() {
strcpy(config.ascii_art_file, "A:/Library/art/boredos.txt");
strcpy(config.ascii_art_file, "/Library/art/boredos.txt");
strcpy(config.user_host_string, "root@boredos");
strcpy(config.separator, "------------");
strcpy(config.os_label, "OS");
@@ -160,7 +151,7 @@ static void parse_config(char* buffer) {
static void load_config() {
set_config_defaults();
int fd = sys_open("A:/Library/conf/sysfetch.cfg", "r");
int fd = sys_open("/Library/conf/sysfetch.cfg", "r");
if (fd < 0) return;
char *buffer = malloc(4096);
@@ -237,52 +228,82 @@ int main(int argc, char **argv) {
if (config.separator[0]) {
strcpy(info_lines[info_line_count++], config.separator);
}
os_info_t os_info;
sys_get_os_info(&os_info);
// Helper for proc parsing
auto int find_v(const char *b, const char *k) {
char *p = (char*)b; int kl = strlen(k);
while (*p) {
if (memcmp(p, k, kl) == 0 && p[kl] == ':') {
p += kl + 1; while (*p == ' ') p++; return atoi(p);
}
while (*p && *p != '\n') p++; if (*p == '\n') p++;
}
return 0;
}
int fd_v = sys_open("/proc/version", "r");
char v_buf[512];
if (fd_v >= 0) {
int b = sys_read(fd_v, v_buf, 511);
v_buf[b] = 0;
sys_close(fd_v);
} else strcpy(v_buf, "Unknown");
if (config.os_label[0]) {
strcpy(info_lines[info_line_count], config.os_label);
strcat(info_lines[info_line_count], ": ");
strcat(info_lines[info_line_count], os_info.os_name);
strcat(info_lines[info_line_count], " V");
strcat(info_lines[info_line_count], os_info.os_version);
strcat(info_lines[info_line_count], " '");
strcat(info_lines[info_line_count], os_info.os_codename);
strcat(info_lines[info_line_count], "'");
// Parse "BoredOS [codename] Version X.Y.Z"
strcat(info_lines[info_line_count], v_buf);
// Truncate at newline
char *nl = strchr(info_lines[info_line_count], '\n');
if (nl) *nl = 0;
info_line_count++;
}
if (config.kernel_label[0]) {
strcpy(info_lines[info_line_count], config.kernel_label);
strcat(info_lines[info_line_count], ": ");
strcat(info_lines[info_line_count], os_info.kernel_name);
strcat(info_lines[info_line_count], " V");
strcat(info_lines[info_line_count], os_info.kernel_version);
strcat(info_lines[info_line_count], " ");
strcat(info_lines[info_line_count], os_info.build_arch);
char *kstart = strchr(v_buf, '\n');
if (kstart) {
strcat(info_lines[info_line_count], kstart + 1);
char *knext = strchr(info_lines[info_line_count], '\n');
if (knext) *knext = 0;
} else strcat(info_lines[info_line_count], "Unknown");
info_line_count++;
}
if (config.uptime_label[0]) {
uint64_t ticks = sys_system(16, 0, 0, 0, 0);
int minutes = ticks / 3600; // 60Hz timer
strcpy(info_lines[info_line_count], config.uptime_label);
strcat(info_lines[info_line_count], ": ");
itoa(minutes, temp_buf);
strcat(info_lines[info_line_count], temp_buf);
strcat(info_lines[info_line_count++], " mins");
int fd_u = sys_open("/proc/uptime", "r");
if (fd_u >= 0) {
char u_buf[64];
int b = sys_read(fd_u, u_buf, 63);
u_buf[b] = 0;
sys_close(fd_u);
int sec = atoi(u_buf);
int mins = sec / 60;
strcpy(info_lines[info_line_count], config.uptime_label);
strcat(info_lines[info_line_count], ": ");
itoa(mins, temp_buf);
strcat(info_lines[info_line_count], temp_buf);
strcat(info_lines[info_line_count++], " mins");
}
}
if (config.shell_label[0]) {
strcpy(info_lines[info_line_count], config.shell_label);
strcat(info_lines[info_line_count++], ": bsh");
}
if (config.memory_label[0]) {
uint64_t mem[2];
if (sys_system(15, (uint64_t)mem, 0, 0, 0) == 0) {
int fd_m = sys_open("/proc/meminfo", "r");
if (fd_m >= 0) {
char m_buf[512];
int b = sys_read(fd_m, m_buf, 511);
m_buf[b] = 0;
sys_close(fd_m);
int total = find_v(m_buf, "MemTotal");
int used = find_v(m_buf, "MemUsed");
strcpy(info_lines[info_line_count], config.memory_label);
strcat(info_lines[info_line_count], ": ");
itoa((int)(mem[1] / 1024 / 1024), temp_buf);
itoa(used / 1024, temp_buf);
strcat(info_lines[info_line_count], temp_buf);
strcat(info_lines[info_line_count], "MiB / ");
itoa((int)(mem[0] / 1024 / 1024), temp_buf);
itoa(total / 1024, temp_buf);
strcat(info_lines[info_line_count], temp_buf);
strcat(info_lines[info_line_count++], "MiB");
}

View File

@@ -149,26 +149,12 @@ char *strrchr(const char *s, int c) {
if (c == 0) last = s;
return (char*)last;
}
char *strchr(const char *s, int c) {
while (*s) { if (*s == c) return (char*)s; s++; }
if (c == 0) return (char*)s;
return NULL;
}
char *strdup(const char *s) {
size_t len = strlen(s) + 1;
char *dup = malloc(len);
if (dup) memcpy(dup, s, len);
return dup;
}
char *strstr(const char *haystack, const char *needle) {
size_t n = strlen(needle);
if (!n) return (char *)haystack;
while (*haystack) {
if (!strncmp(haystack, needle, n)) return (char *)haystack;
haystack++;
}
return NULL;
}
int toupper(int c) { return (c >= 'a' && c <= 'z') ? c - 32 : c; }
int tolower(int c) { return (c >= 'A' && c <= 'Z') ? c + 32 : c; }

View File

@@ -39,8 +39,19 @@ void DG_SleepMs(uint32_t ms) {
}
uint32_t DG_GetTicksMs(void) {
uint64_t ticks = sys_system(16, 0, 0, 0, 0); // SYSTEM_CMD_UPTIME = 16 (100Hz)
return (uint32_t)(ticks * 10);
int fd = sys_open("/proc/uptime", "r");
if (fd < 0) return 0;
char buf[128];
int bytes = sys_read(fd, buf, 127);
sys_close(fd);
if (bytes <= 0) return 0;
buf[bytes] = 0;
char *p = strstr(buf, "Raw_Ticks:");
if (!p) return 0;
uint32_t ticks = atoi(p + 10);
// 60Hz to ms: ticks * 1000 / 60 = ticks * 50 / 3
return (ticks * 50) / 3;
}
void DG_SetWindowTitle(const char * title) {
@@ -108,7 +119,7 @@ int DG_GetKey(int* pressed, unsigned char* key) {
int main(int argc, char** argv) {
(void)argc;
(void)argv;
char* fake_argv[] = {"doom", "-iwad", "A:/Library/DOOM/doom1.wad"};
char* fake_argv[] = {"doom", "-iwad", "/Library/DOOM/doom1.wad"};
doomgeneric_Create(3, fake_argv);
while (1) {

View File

@@ -95,36 +95,39 @@ static void about_paint(ui_window_t win) {
draw_ascii_logo(win, 14, offset_y);
int fh = ui_get_font_height();
os_info_t os_info;
sys_get_os_info(&os_info);
char os_name_str[128];
os_name_str[0] = 0;
strcat(os_name_str, os_info.os_name);
strcat(os_name_str, " '");
strcat(os_name_str, os_info.os_codename);
strcat(os_name_str, "'");
int fd_v = sys_open("/proc/version", "r");
char v_buf[1024]; v_buf[0] = 0;
if (fd_v >= 0) {
int b = sys_read(fd_v, v_buf, 1023);
v_buf[b] = 0;
sys_close(fd_v);
}
char os_version_str[128];
os_version_str[0] = 0;
strcat(os_version_str, os_info.os_name);
strcat(os_version_str, " Version ");
strcat(os_version_str, os_info.os_version);
char kernel_version_str[128];
kernel_version_str[0] = 0;
strcat(kernel_version_str, os_info.kernel_name);
strcat(kernel_version_str, " Version ");
strcat(kernel_version_str, os_info.kernel_version);
strcat(kernel_version_str, " ");
strcat(kernel_version_str, os_info.build_arch);
char os_name_str[128] = "Unknown OS";
char os_version_str[128] = "Unknown Version";
char kernel_version_str[128] = "Unknown Kernel";
char build_date_str[128] = "Unknown Build";
char build_date_str[128];
build_date_str[0] = 0;
strcat(build_date_str, "Build Date: ");
strcat(build_date_str, os_info.build_date);
strcat(build_date_str, " ");
strcat(build_date_str, os_info.build_time);
if (v_buf[0]) {
char *line1 = v_buf;
char *line2 = strchr(line1, '\n'); if (line2) { *line2 = 0; line2++; }
char *line3 = line2 ? strchr(line2, '\n') : NULL; if (line3) { *line3 = 0; line3++; }
strcpy(os_name_str, line1);
if (line2) {
strcpy(os_version_str, line2);
}
if (line3) {
strcpy(kernel_version_str, line3);
char *line4 = strchr(line3, '\n');
if (line4) {
*line4 = 0; line4++;
strcpy(build_date_str, line4);
char *line5 = strchr(build_date_str, '\n');
if (line5) *line5 = 0;
}
}
}
ui_draw_string(win, offset_x, offset_y + 105, os_name_str, 0xFFFFFFFF);
ui_draw_string(win, offset_x, offset_y + 105 + fh, os_version_str, 0xFFFFFFFF);

View File

@@ -32,19 +32,6 @@ static int win_h = 960;
static char history_stack[HISTORY_MAX][512];
static int history_count = 0;
static char* strstr(const char* haystack, const char* needle) {
if (!*needle) return (char*)haystack;
for (; *haystack; haystack++) {
const char *h = haystack;
const char *n = needle;
while (*h && *n && *h == *n) {
h++; n++;
}
if (!*n) return (char*)haystack;
}
return NULL;
}
static char* str_istrstr(const char* haystack, const char* needle) {
if (!*needle) return (char*)haystack;
for (; *haystack; haystack++) {

View File

@@ -37,7 +37,7 @@ static void notepad_ensure_cursor_visible(int h) {
}
static void notepad_load_state() {
int fd = sys_open("A:/tmp/notepad_state.txt", "r");
int fd = sys_open("/tmp/notepad_state.txt", "r");
if (fd >= 0) {
sys_serial_write("Notepad: Loading state...\n");
buf_len = sys_read(fd, buffer, NOTEPAD_BUF_SIZE - 1);
@@ -50,8 +50,8 @@ static void notepad_load_state() {
static void notepad_save_state() {
// Ensure dir exists
sys_mkdir("A:/tmp");
int fd = sys_open("A:/tmp/notepad_state.txt", "w");
sys_mkdir("/tmp");
int fd = sys_open("/tmp/notepad_state.txt", "w");
if (fd >= 0) {
sys_write_fs(fd, buffer, buf_len);
sys_close(fd);

View File

@@ -28,7 +28,7 @@ static uint32_t *canvas_buffer = NULL;
static uint32_t current_color = COLOR_BLACK;
static int last_mx = -1;
static int last_my = -1;
static char current_file_path[256] = "/Desktop/drawing.pnt";
static char current_file_path[256] = "/root/Desktop/drawing.pnt";
static void paint_strcpy(char *dest, const char *src) {
while (*src) *dest++ = *src++;

View File

@@ -84,7 +84,7 @@ int main(int argc, char **argv) {
uint64_t dt[6] = {0};
syscall2(SYS_GUI, GUI_CMD_GET_DATETIME, (uint64_t)dt);
strcpy(g_filename, "/Desktop/screenshot-");
strcpy(g_filename, "/root/Desktop/screenshot-");
append_num((int)dt[0], 4); // Year
append_num((int)dt[1], 2); // Month
append_num((int)dt[2], 2); // Day
@@ -110,7 +110,7 @@ int main(int argc, char **argv) {
// Show notification
char notif[256] = "Saved ";
strcat(notif, g_filename + 9); // Skip "/Desktop/"
strcat(notif, g_filename + 14); // Skip "/root/Desktop/"
syscall2(SYS_GUI, GUI_CMD_SHOW_NOTIFICATION, (uint64_t)notif);
} else {
res = 0;

View File

@@ -32,38 +32,111 @@ static uint64_t kernel_ticks_prev = 0;
static uint64_t total_mem_system = 0;
static uint64_t used_mem_system = 0;
static char cpu_model_name[64] = "Unknown CPU";
static int cpu_cores = 1;
typedef struct {
size_t total_memory;
size_t used_memory;
size_t available_memory;
size_t allocated_blocks;
size_t free_blocks;
size_t largest_free_block;
size_t smallest_free_block;
size_t fragmentation_percent;
size_t peak_memory_used;
} MemStats;
static int find_value(const char *buf, const char *key) {
char *p = (char*)buf;
int key_len = strlen(key);
while (*p) {
if (memcmp(p, key, key_len) == 0 && p[key_len] == ':') {
p += key_len + 1;
while (*p == ' ') p++;
return atoi(p);
}
while (*p && *p != '\n') p++;
if (*p == '\n') p++;
}
return 0;
}
static void find_string(const char *buf, const char *key, char *out, int max_len) {
char *p = (char*)buf;
int key_len = strlen(key);
while (*p) {
if (memcmp(p, key, key_len) == 0 && p[key_len] == ':') {
p += key_len + 1;
while (*p == ' ') p++;
int i = 0;
while (*p && *p != '\n' && i < max_len - 1) {
out[i++] = *p++;
}
out[i] = 0;
return;
}
while (*p && *p != '\n') p++;
if (*p == '\n') p++;
}
strcpy(out, "Unknown");
}
static void update_proc_list(void) {
proc_count = sys_system(SYSTEM_CMD_PROCESS_LIST, (uint64_t)proc_list, 32, 0, 0);
uint64_t uptime_now = sys_system(SYSTEM_CMD_UPTIME, 0, 0, 0, 0);
FAT32_FileInfo entries[64];
int count = sys_list("/proc", entries, 64);
if (count < 0) return;
proc_count = 0;
uint64_t user_ticks_now = 0;
for (int i = 0; i < proc_count; i++) {
if (proc_list[i].pid != 0) {
user_ticks_now += proc_list[i].ticks;
for (int i = 0; i < count; i++) {
if (entries[i].is_directory) {
// Check if name is numeric (PID)
bool numeric = true;
for (int j = 0; entries[i].name[j]; j++) {
if (entries[i].name[j] < '0' || entries[i].name[j] > '9') {
numeric = false;
break;
}
}
if (!numeric) continue;
int pid = atoi(entries[i].name);
char path[64];
strcpy(path, "/proc/");
strcat(path, entries[i].name);
strcat(path, "/status");
int fd = sys_open(path, "r");
if (fd >= 0) {
char buf[512];
int bytes = sys_read(fd, buf, 511);
sys_close(fd);
if (bytes > 0) {
buf[bytes] = 0;
proc_list[proc_count].pid = pid;
find_string(buf, "Name", proc_list[proc_count].name, 64);
proc_list[proc_count].used_memory = (size_t)find_value(buf, "Memory") * 1024;
uint64_t ticks = (uint64_t)find_value(buf, "Ticks");
proc_list[proc_count].ticks = ticks;
proc_list[proc_count].is_idle = find_value(buf, "Idle") == 1;
if (!proc_list[proc_count].is_idle) user_ticks_now += ticks;
proc_count++;
if (proc_count >= 32) break;
}
}
}
}
// Global stats
int fd_u = sys_open("/proc/uptime", "r");
uint64_t uptime_now = 0;
if (fd_u >= 0) {
char buf[256];
int bytes = sys_read(fd_u, buf, 255);
sys_close(fd_u);
if (bytes > 0) {
buf[bytes] = 0;
uptime_now = (uint64_t)find_value(buf, "Raw_Ticks");
}
}
if (uptime_prev > 0) {
uint64_t total_delta = uptime_now - uptime_prev;
if (total_delta > 0) {
uint64_t used_delta = user_ticks_now - kernel_ticks_prev; // Reusing the global state variable for prev user_ticks
// On a 4 CPU system, theoretically used_delta can be 4x total_delta
int usage = (int)((used_delta * 100) / (total_delta * 4));
uint64_t used_delta = user_ticks_now - kernel_ticks_prev;
int cores = cpu_cores > 0 ? cpu_cores : 1;
int usage = (int)((used_delta * 100) / (total_delta * cores));
if (usage > 100) usage = 100;
cpu_history[history_idx] = usage;
}
@@ -72,11 +145,18 @@ static void update_proc_list(void) {
uptime_prev = uptime_now;
kernel_ticks_prev = user_ticks_now;
MemStats stats;
sys_system(SYSTEM_CMD_MEMINFO, (uint64_t)&stats, 0, 0, 0);
total_mem_system = stats.total_memory;
used_mem_system = stats.used_memory;
mem_history[history_idx] = (int)(stats.used_memory / 1024);
int fd_m = sys_open("/proc/meminfo", "r");
if (fd_m >= 0) {
char buf[1024];
int bytes = sys_read(fd_m, buf, 1023);
sys_close(fd_m);
if (bytes > 0) {
buf[bytes] = 0;
total_mem_system = (uint64_t)find_value(buf, "MemTotal") * 1024;
used_mem_system = (uint64_t)find_value(buf, "MemUsed") * 1024;
mem_history[history_idx] = (int)(used_mem_system / 1024);
}
}
history_idx = (history_idx + 1) % GRAPH_POINTS;
}
@@ -168,9 +248,12 @@ static void draw_taskman(void) {
// Memory Graph Area
ui_draw_string(win_taskman, 205, 10, "MEMORY", COLOR_MEM);
char mem_pct_label[16];
int current_mem_pct = 0;
if (total_mem_system > 0) current_mem_pct = (int)((used_mem_system * 100) / total_mem_system);
itoa(current_mem_pct, mem_pct_label);
int current_mem_pct_x10 = 0;
if (total_mem_system > 0) current_mem_pct_x10 = (int)((used_mem_system * 1000) / total_mem_system);
itoa(current_mem_pct_x10 / 10, mem_pct_label);
strcat(mem_pct_label, ".");
char frac[4]; itoa(current_mem_pct_x10 % 10, frac);
strcat(mem_pct_label, frac);
strcat(mem_pct_label, "%");
ui_draw_string(win_taskman, 340, 10, mem_pct_label, COLOR_MEM);
@@ -255,8 +338,18 @@ static void draw_taskman(void) {
int main(void) {
win_taskman = ui_window_create("Task Manager", 100, 100, 400, 480);
// Fetch CPU model
sys_system(SYSTEM_CMD_GET_CPU_MODEL, (uint64_t)cpu_model_name, 0, 0, 0);
int fd_c = sys_open("/proc/cpuinfo", "r");
if (fd_c >= 0) {
char buf[1024];
int bytes = sys_read(fd_c, buf, 1023);
sys_close(fd_c);
if (bytes > 0) {
buf[bytes] = 0;
find_string(buf, "Processor", cpu_model_name, 64);
int cores = find_value(buf, "Cores");
if (cores > 0) cpu_cores = cores;
}
}
for(int i=0; i<GRAPH_POINTS; i++) { cpu_history[i] = 0; mem_history[i] = 0; }

View File

@@ -202,9 +202,27 @@ char* strcat(char *dest, const char *src) {
return ret;
}
char *strchr(const char *s, int c) {
while (*s != (char)c) {
if (!*s++) return NULL;
}
return (char *)s;
}
char *strstr(const char *haystack, const char *needle) {
size_t needle_len = strlen(needle);
if (!needle_len) return (char *)haystack;
while (*haystack) {
if (memcmp(haystack, needle, needle_len) == 0) return (char *)haystack;
haystack++;
}
return NULL;
}
int atoi(const char *nptr) {
int res = 0;
int sign = 1;
while (*nptr == ' ' || *nptr == '\t' || *nptr == '\n' || *nptr == '\r') nptr++;
if (*nptr == '-') {
sign = -1;
nptr++;

View File

@@ -11,11 +11,9 @@ void* realloc(void* ptr, size_t size);
void *memset(void *s, int c, size_t n);
void *memcpy(void *dest, const void *src, size_t n);
// String functions
size_t strlen(const char *s);
int strcmp(const char *s1, const char *s2);
char* strcpy(char *dest, const char *src);
char* strcat(char *dest, const char *src);
#include "string.h"
// Math/Utility functions
int atoi(const char *nptr);
void itoa(int n, char *buf);

View File

@@ -7,5 +7,11 @@ void *memmove(void *dest, const void *src, size_t n);
int memcmp(const void *s1, const void *s2, size_t n);
void *memcpy(void *dest, const void *src, size_t n);
void *memset(void *s, int c, size_t n);
char *strchr(const char *s, int c);
char *strstr(const char *haystack, const char *needle);
size_t strlen(const char *s);
int strcmp(const char *s1, const char *s2);
char* strcpy(char *dest, const char *src);
char* strcat(char *dest, const char *src);
#endif

View File

@@ -251,10 +251,6 @@ void sys_yield(void) {
syscall1(SYS_SYSTEM, SYSTEM_CMD_YIELD);
}
int sys_get_os_info(os_info_t *info) {
return (int)syscall5(SYS_SYSTEM, SYSTEM_CMD_GET_OS_INFO, (uint64_t)info, 0, 0, 0);
}
void sys_parallel_run(void (*fn)(void*), void **args, int count) {
syscall5(SYS_SYSTEM, SYSTEM_CMD_PARALLEL_RUN, (uint64_t)fn, (uint64_t)args, (uint64_t)count, 0);
}

View File

@@ -44,8 +44,6 @@
#define SYSTEM_CMD_REBOOT 12
#define SYSTEM_CMD_SHUTDOWN 13
#define SYSTEM_CMD_BEEP 14
#define SYSTEM_CMD_MEMINFO 15
#define SYSTEM_CMD_UPTIME 16
#define SYSTEM_CMD_PCI_LIST 17
#define SYSTEM_CMD_NETWORK_DHCP 18
#define SYSTEM_CMD_NETWORK_GET_MAC 19
@@ -69,13 +67,10 @@
#define SYSTEM_CMD_DNS_LOOKUP 37
#define SYSTEM_CMD_SET_DNS 38
#define SYSTEM_CMD_NET_UNLOCK 39
#define SYSTEM_CMD_PROCESS_LIST 44
#define SYSTEM_CMD_GET_CPU_MODEL 45
#define SYSTEM_CMD_SLEEP 46
#define SYSTEM_CMD_SET_RAW_MODE 41
#define SYSTEM_CMD_TCP_RECV_NB 42
#define SYSTEM_CMD_YIELD 43
#define SYSTEM_CMD_GET_OS_INFO 49
#define SYSTEM_CMD_PARALLEL_RUN 50
// Internal assembly entry into Ring 0
@@ -137,6 +132,7 @@ typedef struct {
char name[64];
uint64_t ticks;
size_t used_memory;
uint32_t is_idle;
} ProcessInfo;
// Network API

View File

@@ -6,11 +6,18 @@
int main(int argc, char **argv) {
(void)argc; (void)argv;
uint64_t ticks = sys_system(16, 0, 0, 0, 0); // SYSTEM_CMD_UPTIME
uint64_t seconds = ticks / 100; // 100Hz timer assumed
uint64_t minutes = seconds / 60;
uint64_t hours = minutes / 60;
uint64_t days = hours / 24;
int fd = sys_open("/proc/uptime", "r");
if (fd < 0) return 1;
char buf[128];
int bytes = sys_read(fd, buf, 127);
sys_close(fd);
if (bytes <= 0) return 1;
buf[bytes] = 0;
int seconds = atoi(buf);
int minutes = seconds / 60;
int hours = minutes / 60;
int days = hours / 24;
printf("Uptime: %d days, %d hours, %d minutes, %d seconds\n",
(int)days, (int)(hours % 24), (int)(minutes % 60), (int)(seconds % 60));