From 8504270eaebc09e20837ed9cfe973532cb1120b0 Mon Sep 17 00:00:00 2001 From: ryuukumar Date: Sat, 16 May 2026 13:05:50 +0530 Subject: [PATCH 1/3] Add ioctl in libcos --- lib/cos/include/arch/x86_64-cos/syscalls.h | 1 + lib/cos/include/sys/ioctl.h | 29 ++++++++++++++++++++++ lib/cos/src/ioctl.c | 13 ++++++++++ 3 files changed, 43 insertions(+) create mode 100644 lib/cos/include/sys/ioctl.h create mode 100644 lib/cos/src/ioctl.c diff --git a/lib/cos/include/arch/x86_64-cos/syscalls.h b/lib/cos/include/arch/x86_64-cos/syscalls.h index f133a36..4c96c3c 100644 --- a/lib/cos/include/arch/x86_64-cos/syscalls.h +++ b/lib/cos/include/arch/x86_64-cos/syscalls.h @@ -16,6 +16,7 @@ #define SYSCALL_SYS_FORK 57 #define SYSCALL_SCHED_YIELD 158 +#define SYSCALL_SYS_IOCTL 241 #define SYSCALL_SYS_GETCWD 242 #define SYSCALL_SYS_CHDIR 243 #define SYSCALL_SYS_FCNTL 244 diff --git a/lib/cos/include/sys/ioctl.h b/lib/cos/include/sys/ioctl.h new file mode 100644 index 0000000..d69b56f --- /dev/null +++ b/lib/cos/include/sys/ioctl.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +#define TIOCGWINSZ 0x5413 /* get window size */ +#define TIOCSWINSZ 0x5414 /* set window size */ +#define TCGETS 0x5401 /* get termios */ +#define TCSETS 0x5402 /* set termios */ +#define TCSETSW 0x5403 +#define TCSETSF 0x5404 +#define TIOCGPGRP 0x540F /* get foreground process group */ +#define TIOCSPGRP 0x5410 /* set foreground process group */ + +struct winsize { + unsigned short ws_row; + unsigned short ws_col; + unsigned short ws_xpixel; + unsigned short ws_ypixel; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +int ioctl (int fd, unsigned long request, ...); + +#ifdef __cplusplus +} +#endif diff --git a/lib/cos/src/ioctl.c b/lib/cos/src/ioctl.c new file mode 100644 index 0000000..b645fc5 --- /dev/null +++ b/lib/cos/src/ioctl.c @@ -0,0 +1,13 @@ +#include +#include +#include + +int ioctl (int fd, unsigned long request, ...) { + va_list args; + va_start (args, request); + void* arg = va_arg (args, void*); + va_end (args); + + return (int)syscall_ret ( + (long)syscall3 (SYSCALL_SYS_IOCTL, (long)fd, (long)request, (long)arg)); +} From ed214823466079c2c5902c3549ad59660550643c Mon Sep 17 00:00:00 2001 From: ryuukumar Date: Sat, 16 May 2026 13:22:01 +0530 Subject: [PATCH 2/3] Route ioctl and implement TIOCGWINSZ --- kernel/include/kernel/con/con.h | 3 +++ kernel/include/kernel/fs/ioctl.h | 17 +++++++++++++++++ kernel/include/kernel/fs/vfs.h | 3 +++ kernel/include/kernel/syscall.h | 1 + kernel/src/kernel/con/con.c | 15 +++++++++++++++ kernel/src/kernel/fs/chardev/chardev.c | 10 ++++++++++ kernel/src/kernel/fs/vfs/ioctl.c | 16 ++++++++++++++++ kernel/src/kernel/fs/vfs/vfs.c | 1 + 8 files changed, 66 insertions(+) create mode 100644 kernel/include/kernel/fs/ioctl.h create mode 100644 kernel/src/kernel/fs/vfs/ioctl.c diff --git a/kernel/include/kernel/con/con.h b/kernel/include/kernel/con/con.h index d9e98e6..09027fd 100644 --- a/kernel/include/kernel/con/con.h +++ b/kernel/include/kernel/con/con.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -14,6 +15,8 @@ int con_update (void); void con_scrollup (size_t howmuch); void con_scrolldown (size_t howmuch); +int con_tiocgwinsz (winsize_t* ptr); + int add_char (unsigned char c); void init_con (size_t screen_width, size_t screen_height, size_t x_padding, size_t y_padding, size_t char_spacing, size_t line_padding, size_t font_multiplier); diff --git a/kernel/include/kernel/fs/ioctl.h b/kernel/include/kernel/fs/ioctl.h new file mode 100644 index 0000000..88c3fee --- /dev/null +++ b/kernel/include/kernel/fs/ioctl.h @@ -0,0 +1,17 @@ +#pragma once + +#define TIOCGWINSZ 0x5413 +#define TIOCSWINSZ 0x5414 +#define TCGETS 0x5401 +#define TCSETS 0x5402 +#define TCSETSW 0x5403 +#define TCSETSF 0x5404 +#define TIOCGPGRP 0x540F +#define TIOCSPGRP 0x5410 + +typedef struct { + unsigned short ws_row; + unsigned short ws_col; + unsigned short ws_xpixel; + unsigned short ws_ypixel; +} winsize_t; diff --git a/kernel/include/kernel/fs/vfs.h b/kernel/include/kernel/fs/vfs.h index 55af944..14db054 100644 --- a/kernel/include/kernel/fs/vfs.h +++ b/kernel/include/kernel/fs/vfs.h @@ -45,6 +45,7 @@ typedef struct { int (*seek) (inode*, file*, size_t, int); int (*getdents) (inode*, file*, void*, size_t); int (*fstat) (inode*, file*, stat*); + int (*ioctl) (inode*, file*, uint64_t, uint64_t); } file_operations; struct inode { @@ -85,6 +86,7 @@ int do_close (struct file* fd); int do_getdents (struct file* f, void* buf, size_t count); int do_fstat (struct file* fd, stat* buf); int do_stat (const char* restrict path, stat* restrict buf); +int do_ioctl (struct file* fd, uint64_t req, uint64_t arg); uint64_t sys_read (uint64_t fd, uint64_t buf, uint64_t size); uint64_t sys_write (uint64_t fd, uint64_t buf, uint64_t size); @@ -97,6 +99,7 @@ uint64_t sys_getdents (uint64_t fd, uint64_t buf, uint64_t count); uint64_t sys_getcwd (uint64_t buf, uint64_t size, uint64_t arg3); uint64_t sys_fstat (uint64_t fd, uint64_t buf, uint64_t arg3); uint64_t sys_stat (uint64_t path, uint64_t buf, uint64_t arg3); +uint64_t sys_ioctl (uint64_t fd, uint64_t req, uint64_t arg); inode* get_absolute_root (void); void init_vfs (inode* absolute_root); diff --git a/kernel/include/kernel/syscall.h b/kernel/include/kernel/syscall.h index 2f93a79..a9d7ab8 100644 --- a/kernel/include/kernel/syscall.h +++ b/kernel/include/kernel/syscall.h @@ -19,6 +19,7 @@ // The following will have numbers changed +#define SYSCALL_SYS_IOCTL 241 #define SYSCALL_SYS_GETCWD 242 #define SYSCALL_SYS_CHDIR 243 #define SYSCALL_SYS_FCNTL 244 diff --git a/kernel/src/kernel/con/con.c b/kernel/src/kernel/con/con.c index 22ff2e3..94b3807 100644 --- a/kernel/src/kernel/con/con.c +++ b/kernel/src/kernel/con/con.c @@ -1,6 +1,7 @@ #include #include #include +#include static console_t* console = nullptr; static bool update_flag = true; @@ -33,6 +34,20 @@ void con_scrolldown (size_t howmuch) { write_to_gfx (&console); } +int con_tiocgwinsz (winsize_t* ptr) { + if (!ptr) return -EINVAL; + + console_parameters_t params = console_getparams (&console); + ptr->ws_col = params.width; + ptr->ws_row = params.height; + ptr->ws_xpixel = (unsigned short)(params.width * (params.glyph_width + params.char_spacing) * + params.font_size); + ptr->ws_ypixel = (unsigned short)(params.height * (params.glyph_height + params.line_spacing) * + params.font_size); + + return 0; +} + int add_char (unsigned char c) { int error = 0; console_parameters_t params = console_getparams (&console); diff --git a/kernel/src/kernel/fs/chardev/chardev.c b/kernel/src/kernel/fs/chardev/chardev.c index 5109536..0c38a76 100644 --- a/kernel/src/kernel/fs/chardev/chardev.c +++ b/kernel/src/kernel/fs/chardev/chardev.c @@ -1,9 +1,11 @@ +#include "kernel/fs/vfs.h" #include #include #include #include #include #include +#include #include #include #include @@ -73,6 +75,13 @@ static int chardev_fstat (inode* node, file* f, stat* buf) { return 0; } +static int chardev_ioctl (inode* node, file* f, uint64_t request, uint64_t argument) { + (void)node, (void)f; + if (request == TIOCGWINSZ) return con_tiocgwinsz ((winsize_t*)argument); + + return -ENOSYS; +} + void init_tty1 (inode* absolute_root) { inode* dev_dir = nullptr; int error = do_mkdir ("dev", &dev_dir, absolute_root); @@ -89,6 +98,7 @@ void init_tty1 (inode* absolute_root) { tty1_fops->write = stdout_write; tty1_fops->read = stdin_read; tty1_fops->fstat = chardev_fstat; + tty1_fops->ioctl = chardev_ioctl; chardev_info_t* tty1_info = kmalloc (sizeof (chardev_info_t)); kmemset (tty1_info, 0, sizeof (chardev_info_t)); diff --git a/kernel/src/kernel/fs/vfs/ioctl.c b/kernel/src/kernel/fs/vfs/ioctl.c new file mode 100644 index 0000000..67097a7 --- /dev/null +++ b/kernel/src/kernel/fs/vfs/ioctl.c @@ -0,0 +1,16 @@ +#include +#include +#include +#include + +int do_ioctl (struct file* fd, uint64_t req, uint64_t arg) { + if (!fd) return -EINVAL; + if (!fd->f_fops || !fd->f_fops->ioctl) return -ENOSYS; + return fd->f_fops->ioctl (fd->f_inode, fd, req, arg); +} + +uint64_t sys_ioctl (uint64_t fd, uint64_t req, uint64_t arg) { + process* current = get_current_process (); + if (fd >= MAX_FDS || !current || !current->p_fds[fd]) return -EINVAL; + return do_ioctl (current->p_fds[fd], req, arg); +} diff --git a/kernel/src/kernel/fs/vfs/vfs.c b/kernel/src/kernel/fs/vfs/vfs.c index 35db6dc..a83ade4 100644 --- a/kernel/src/kernel/fs/vfs/vfs.c +++ b/kernel/src/kernel/fs/vfs/vfs.c @@ -24,4 +24,5 @@ void init_vfs (inode* absolute_root) { register_syscall (SYSCALL_SYS_STAT, sys_stat); register_syscall (SYSCALL_SYS_CHDIR, sys_chdir); register_syscall (SYSCALL_SYS_GETCWD, sys_getcwd); + register_syscall (SYSCALL_SYS_IOCTL, sys_ioctl); } \ No newline at end of file From dd1e9fd0dec9d6ad267bcaf3f7d671e8aac46431 Mon Sep 17 00:00:00 2001 From: ryuukumar Date: Sat, 16 May 2026 13:34:40 +0530 Subject: [PATCH 3/3] Update ls implementation to use ioctl to set layout --- user/cosh/src/builtin/ls.c | 53 +++++++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/user/cosh/src/builtin/ls.c b/user/cosh/src/builtin/ls.c index af4bfa7..d57c36c 100644 --- a/user/cosh/src/builtin/ls.c +++ b/user/cosh/src/builtin/ls.c @@ -1,6 +1,10 @@ #include #include #include +#include +#include +#include +#include int builtin_ls (int argc, char** argv) { const char* path = (argc >= 2) ? argv[1] : "."; @@ -11,10 +15,53 @@ int builtin_ls (int argc, char** argv) { return -1; } - struct dirent* entry; - while ((entry = readdir (dir)) != NULL) - printf ("%s\n", entry->d_name); + size_t count = 0, cap = 64; + char** names = malloc (cap * sizeof (char*)); + if (!names) { + closedir (dir); + return -1; + } + size_t max_len = 0; + struct dirent* entry; + while ((entry = readdir (dir)) != NULL) { + if (count == cap) { + cap *= 2; + char** tmp = realloc (names, cap * sizeof (char*)); + if (!tmp) break; + names = tmp; + } + names[count] = strdup (entry->d_name); + if (!names[count]) break; + size_t len = strlen (entry->d_name); + if (len > max_len) max_len = len; + count++; + } closedir (dir); + + unsigned short term_cols = 80; + struct winsize ws; + if (ioctl (STDOUT_FILENO, TIOCGWINSZ, &ws) == 0 && ws.ws_col > 0) term_cols = ws.ws_col; + + size_t col_width = max_len + 2; + size_t ncols = term_cols / col_width; + if (ncols == 0) ncols = 1; + size_t nrows = (count + ncols - 1) / ncols; + + for (size_t row = 0; row < nrows; row++) { + for (size_t col = 0; col < ncols; col++) { + size_t idx = col * nrows + row; + if (idx >= count) break; + int last = (col + 1 == ncols) || ((col + 1) * nrows + row >= count); + if (last) + printf ("%s\n", names[idx]); + else + printf ("%-*s", (int)col_width, names[idx]); + } + } + + for (size_t i = 0; i < count; i++) + free (names[i]); + free (names); return 0; } \ No newline at end of file