From 2b248afd44d0779fa7df035aeae77d4166e4d739 Mon Sep 17 00:00:00 2001 From: Tulio A M Mendes Date: Tue, 10 Feb 2026 09:55:26 -0300 Subject: [PATCH] feat: multiple PTY pairs (up to 8 dynamic /dev/pts/N) Refactored PTY subsystem from single global pair to array of up to 8 pairs: - New pty_pair struct with per-pair buffers, waitqueues, session/pgrp - pty_alloc_pair() allocates new pairs dynamically - Inode encoding: masters=100+N, slaves=200+N - pty_get_master_node()/pty_get_slave_node() return per-pair fs_node_t - All _idx() variants for indexed pair access - Old single-pair API preserved as wrappers around pair 0 - devfs /dev/pts/ now lists all active pairs dynamically - syscall.c poll/nonblock/ioctl updated to use pty_is_master_ino/pty_is_slave_ino - cppcheck clean, 19/19 smoke tests pass --- include/pty.h | 38 +++++- src/kernel/devfs.c | 63 ++++------ src/kernel/pty.c | 276 +++++++++++++++++++++++++++++++------------ src/kernel/syscall.c | 25 ++-- 4 files changed, 273 insertions(+), 129 deletions(-) diff --git a/include/pty.h b/include/pty.h index cde5919..8289f72 100644 --- a/include/pty.h +++ b/include/pty.h @@ -2,21 +2,51 @@ #define PTY_H #include +#include "fs.h" + +#define PTY_MAX_PAIRS 8 +#define PTY_MASTER_INO_BASE 100 +#define PTY_SLAVE_INO_BASE 200 void pty_init(void); +int pty_alloc_pair(void); +int pty_pair_count(void); +int pty_pair_active(int idx); + int pty_master_read_kbuf(void* kbuf, uint32_t len); int pty_master_write_kbuf(const void* kbuf, uint32_t len); - int pty_slave_read_kbuf(void* kbuf, uint32_t len); int pty_slave_write_kbuf(const void* kbuf, uint32_t len); - int pty_master_can_read(void); int pty_master_can_write(void); - int pty_slave_can_read(void); int pty_slave_can_write(void); - int pty_slave_ioctl(uint32_t cmd, void* user_arg); +int pty_master_read_idx(int idx, void* kbuf, uint32_t len); +int pty_master_write_idx(int idx, const void* kbuf, uint32_t len); +int pty_slave_read_idx(int idx, void* kbuf, uint32_t len); +int pty_slave_write_idx(int idx, const void* kbuf, uint32_t len); +int pty_master_can_read_idx(int idx); +int pty_master_can_write_idx(int idx); +int pty_slave_can_read_idx(int idx); +int pty_slave_can_write_idx(int idx); +int pty_slave_ioctl_idx(int idx, uint32_t cmd, void* user_arg); + +fs_node_t* pty_get_master_node(int idx); +fs_node_t* pty_get_slave_node(int idx); + +static inline int pty_is_master_ino(uint32_t ino) { + return (ino >= PTY_MASTER_INO_BASE && ino < PTY_MASTER_INO_BASE + PTY_MAX_PAIRS); +} +static inline int pty_is_slave_ino(uint32_t ino) { + return (ino >= PTY_SLAVE_INO_BASE && ino < PTY_SLAVE_INO_BASE + PTY_MAX_PAIRS); +} +static inline int pty_ino_to_idx(uint32_t ino) { + if (pty_is_master_ino(ino)) return (int)(ino - PTY_MASTER_INO_BASE); + if (pty_is_slave_ino(ino)) return (int)(ino - PTY_SLAVE_INO_BASE); + return -1; +} + #endif diff --git a/src/kernel/devfs.c b/src/kernel/devfs.c index eec1583..444f176 100644 --- a/src/kernel/devfs.c +++ b/src/kernel/devfs.c @@ -20,7 +20,6 @@ static fs_node_t g_dev_console; static fs_node_t g_dev_tty; static fs_node_t g_dev_ptmx; static fs_node_t g_dev_pts_dir; -static fs_node_t g_dev_pts0; static uint32_t g_devfs_inited = 0; static uint32_t prng_state = 0x12345678; @@ -124,33 +123,19 @@ static uint32_t dev_tty_write(fs_node_t* node, uint32_t offset, uint32_t size, c } static uint32_t dev_ptmx_read(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer) { - (void)node; (void)offset; - int rc = pty_master_read_kbuf(buffer, size); + int idx = pty_ino_to_idx(node->inode); + if (idx < 0) idx = 0; + int rc = pty_master_read_idx(idx, buffer, size); if (rc < 0) return 0; return (uint32_t)rc; } static uint32_t dev_ptmx_write(fs_node_t* node, uint32_t offset, uint32_t size, const uint8_t* buffer) { - (void)node; - (void)offset; - int rc = pty_master_write_kbuf(buffer, size); - if (rc < 0) return 0; - return (uint32_t)rc; -} - -static uint32_t dev_pts0_read(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer) { - (void)node; (void)offset; - int rc = pty_slave_read_kbuf(buffer, size); - if (rc < 0) return 0; - return (uint32_t)rc; -} - -static uint32_t dev_pts0_write(fs_node_t* node, uint32_t offset, uint32_t size, const uint8_t* buffer) { - (void)node; - (void)offset; - int rc = pty_slave_write_kbuf(buffer, size); + int idx = pty_ino_to_idx(node->inode); + if (idx < 0) idx = 0; + int rc = pty_master_write_idx(idx, buffer, size); if (rc < 0) return 0; return (uint32_t)rc; } @@ -173,7 +158,15 @@ static struct fs_node* devfs_finddir_impl(struct fs_node* node, const char* name static struct fs_node* devfs_pts_finddir_impl(struct fs_node* node, const char* name) { (void)node; if (!name || name[0] == 0) return 0; - if (strcmp(name, "0") == 0) return &g_dev_pts0; + int count = pty_pair_count(); + for (int i = 0; i < count; i++) { + char num[4]; + num[0] = '0' + (char)i; + num[1] = '\0'; + if (strcmp(name, num) == 0) { + return pty_get_slave_node(i); + } + } return 0; } @@ -230,6 +223,7 @@ static int devfs_pts_readdir_impl(struct fs_node* node, uint32_t* inout_index, v if (!inout_index || !buf) return -1; if (buf_len < sizeof(struct vfs_dirent)) return -1; + int count = pty_pair_count(); uint32_t idx = *inout_index; uint32_t cap = buf_len / (uint32_t)sizeof(struct vfs_dirent); struct vfs_dirent* ents = (struct vfs_dirent*)buf; @@ -243,10 +237,13 @@ static int devfs_pts_readdir_impl(struct fs_node* node, uint32_t* inout_index, v e.d_ino = 5; e.d_type = FS_DIRECTORY; strcpy(e.d_name, "."); } else if (idx == 1) { e.d_ino = 1; e.d_type = FS_DIRECTORY; strcpy(e.d_name, ".."); - } else if (idx == 2) { - e.d_ino = 6; e.d_type = FS_CHARDEVICE; strcpy(e.d_name, "0"); } else { - break; + int pi = (int)(idx - 2); + if (pi >= count) break; + e.d_ino = PTY_SLAVE_INO_BASE + (uint32_t)pi; + e.d_type = FS_CHARDEVICE; + e.d_name[0] = '0' + (char)pi; + e.d_name[1] = '\0'; } e.d_reclen = (uint16_t)sizeof(e); @@ -328,13 +325,9 @@ static void devfs_init_once(void) { memset(&g_dev_ptmx, 0, sizeof(g_dev_ptmx)); strcpy(g_dev_ptmx.name, "ptmx"); g_dev_ptmx.flags = FS_CHARDEVICE; - g_dev_ptmx.inode = 4; - g_dev_ptmx.length = 0; + g_dev_ptmx.inode = PTY_MASTER_INO_BASE; g_dev_ptmx.read = &dev_ptmx_read; g_dev_ptmx.write = &dev_ptmx_write; - g_dev_ptmx.open = 0; - g_dev_ptmx.close = 0; - g_dev_ptmx.finddir = 0; memset(&g_dev_pts_dir, 0, sizeof(g_dev_pts_dir)); strcpy(g_dev_pts_dir.name, "pts"); @@ -348,16 +341,6 @@ static void devfs_init_once(void) { g_dev_pts_dir.finddir = &devfs_pts_finddir_impl; g_dev_pts_dir.readdir = &devfs_pts_readdir_impl; - memset(&g_dev_pts0, 0, sizeof(g_dev_pts0)); - strcpy(g_dev_pts0.name, "0"); - g_dev_pts0.flags = FS_CHARDEVICE; - g_dev_pts0.inode = 6; - g_dev_pts0.length = 0; - g_dev_pts0.read = &dev_pts0_read; - g_dev_pts0.write = &dev_pts0_write; - g_dev_pts0.open = 0; - g_dev_pts0.close = 0; - g_dev_pts0.finddir = 0; } fs_node_t* devfs_create_root(void) { diff --git a/src/kernel/pty.c b/src/kernel/pty.c index 5a4d6c2..14e1d01 100644 --- a/src/kernel/pty.c +++ b/src/kernel/pty.c @@ -4,6 +4,7 @@ #include "process.h" #include "spinlock.h" #include "uaccess.h" +#include "utils.h" #include "hal/cpu.h" @@ -12,27 +13,6 @@ #define PTY_BUF_CAP 1024 #define PTY_WAITQ_MAX 16 -static spinlock_t pty_lock = {0}; - -static uint8_t m2s_buf[PTY_BUF_CAP]; -static uint32_t m2s_head = 0; -static uint32_t m2s_tail = 0; - -static uint8_t s2m_buf[PTY_BUF_CAP]; -static uint32_t s2m_head = 0; -static uint32_t s2m_tail = 0; - -static struct process* m2s_waitq[PTY_WAITQ_MAX]; -static uint32_t m2s_wq_head = 0; -static uint32_t m2s_wq_tail = 0; - -static struct process* s2m_waitq[PTY_WAITQ_MAX]; -static uint32_t s2m_wq_head = 0; -static uint32_t s2m_wq_tail = 0; - -static uint32_t pty_session_id = 0; -static uint32_t pty_fg_pgrp = 0; - enum { SIGTTIN = 21, SIGTTOU = 22, @@ -43,6 +23,35 @@ enum { TTY_TIOCSPGRP = 0x5410, }; +struct pty_pair { + uint8_t m2s_buf[PTY_BUF_CAP]; + uint32_t m2s_head; + uint32_t m2s_tail; + + uint8_t s2m_buf[PTY_BUF_CAP]; + uint32_t s2m_head; + uint32_t s2m_tail; + + struct process* m2s_waitq[PTY_WAITQ_MAX]; + uint32_t m2s_wq_head; + uint32_t m2s_wq_tail; + + struct process* s2m_waitq[PTY_WAITQ_MAX]; + uint32_t s2m_wq_head; + uint32_t s2m_wq_tail; + + uint32_t session_id; + uint32_t fg_pgrp; + int active; + + fs_node_t master_node; + fs_node_t slave_node; +}; + +static spinlock_t pty_lock = {0}; +static struct pty_pair g_ptys[PTY_MAX_PAIRS]; +static int g_pty_count = 0; + static uint32_t rb_count(uint32_t head, uint32_t tail) { if (head >= tail) return head - tail; return (PTY_BUF_CAP - tail) + head; @@ -91,79 +100,147 @@ static void waitq_wake_one(struct process** q, uint32_t* head, uint32_t* tail) { } } +static uint32_t pty_master_read_fn(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer); +static uint32_t pty_master_write_fn(fs_node_t* node, uint32_t offset, uint32_t size, const uint8_t* buffer); +static uint32_t pty_slave_read_fn(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer); +static uint32_t pty_slave_write_fn(fs_node_t* node, uint32_t offset, uint32_t size, const uint8_t* buffer); + +static void pty_init_pair(int idx) { + struct pty_pair* p = &g_ptys[idx]; + memset(p, 0, sizeof(*p)); + p->active = 1; + + char name[8]; + memset(&p->master_node, 0, sizeof(p->master_node)); + strcpy(p->master_node.name, "ptmx"); + p->master_node.flags = FS_CHARDEVICE; + p->master_node.inode = PTY_MASTER_INO_BASE + (uint32_t)idx; + p->master_node.read = &pty_master_read_fn; + p->master_node.write = &pty_master_write_fn; + + memset(&p->slave_node, 0, sizeof(p->slave_node)); + name[0] = '0' + (char)idx; + name[1] = '\0'; + strcpy(p->slave_node.name, name); + p->slave_node.flags = FS_CHARDEVICE; + p->slave_node.inode = PTY_SLAVE_INO_BASE + (uint32_t)idx; + p->slave_node.read = &pty_slave_read_fn; + p->slave_node.write = &pty_slave_write_fn; +} + void pty_init(void) { spinlock_init(&pty_lock); - m2s_head = m2s_tail = 0; - s2m_head = s2m_tail = 0; - m2s_wq_head = m2s_wq_tail = 0; - s2m_wq_head = s2m_wq_tail = 0; - pty_session_id = 0; - pty_fg_pgrp = 0; + memset(g_ptys, 0, sizeof(g_ptys)); + g_pty_count = 0; + pty_init_pair(0); + g_pty_count = 1; +} + +int pty_alloc_pair(void) { + uintptr_t flags = spin_lock_irqsave(&pty_lock); + if (g_pty_count >= PTY_MAX_PAIRS) { + spin_unlock_irqrestore(&pty_lock, flags); + return -ENOMEM; + } + int idx = g_pty_count; + g_pty_count++; + spin_unlock_irqrestore(&pty_lock, flags); + pty_init_pair(idx); + return idx; +} + +int pty_pair_count(void) { + return g_pty_count; +} + +int pty_pair_active(int idx) { + if (idx < 0 || idx >= g_pty_count) return 0; + return g_ptys[idx].active; +} + +fs_node_t* pty_get_master_node(int idx) { + if (idx < 0 || idx >= g_pty_count) return NULL; + return &g_ptys[idx].master_node; +} + +fs_node_t* pty_get_slave_node(int idx) { + if (idx < 0 || idx >= g_pty_count) return NULL; + return &g_ptys[idx].slave_node; } -static int pty_jobctl_write_check(void) { - if (current_process && pty_session_id != 0 && current_process->session_id == pty_session_id && - pty_fg_pgrp != 0 && current_process->pgrp_id != pty_fg_pgrp) { +static int pty_jobctl_write_check(struct pty_pair* p) { + if (current_process && p->session_id != 0 && current_process->session_id == p->session_id && + p->fg_pgrp != 0 && current_process->pgrp_id != p->fg_pgrp) { (void)process_kill(current_process->pid, SIGTTOU); return -EINTR; } return 0; } -static int pty_jobctl_read_check(void) { +static int pty_jobctl_read_check(struct pty_pair* p) { if (!current_process) return -ECHILD; - if (pty_session_id != 0 && current_process->session_id == pty_session_id && - pty_fg_pgrp != 0 && current_process->pgrp_id != pty_fg_pgrp) { + if (p->session_id != 0 && current_process->session_id == p->session_id && + p->fg_pgrp != 0 && current_process->pgrp_id != p->fg_pgrp) { (void)process_kill(current_process->pid, SIGTTIN); return -EINTR; } return 0; } -int pty_master_can_read(void) { +int pty_master_can_read_idx(int idx) { + if (idx < 0 || idx >= g_pty_count) return 0; + struct pty_pair* p = &g_ptys[idx]; uintptr_t flags = spin_lock_irqsave(&pty_lock); - int ready = (rb_count(s2m_head, s2m_tail) != 0U) ? 1 : 0; + int ready = (rb_count(p->s2m_head, p->s2m_tail) != 0U) ? 1 : 0; spin_unlock_irqrestore(&pty_lock, flags); return ready; } -int pty_master_can_write(void) { +int pty_master_can_write_idx(int idx) { + if (idx < 0 || idx >= g_pty_count) return 0; + struct pty_pair* p = &g_ptys[idx]; uintptr_t flags = spin_lock_irqsave(&pty_lock); - int ready = (rb_free(m2s_head, m2s_tail) != 0U) ? 1 : 0; + int ready = (rb_free(p->m2s_head, p->m2s_tail) != 0U) ? 1 : 0; spin_unlock_irqrestore(&pty_lock, flags); return ready; } -int pty_slave_can_read(void) { +int pty_slave_can_read_idx(int idx) { + if (idx < 0 || idx >= g_pty_count) return 0; + struct pty_pair* p = &g_ptys[idx]; uintptr_t flags = spin_lock_irqsave(&pty_lock); - int ready = (rb_count(m2s_head, m2s_tail) != 0U) ? 1 : 0; + int ready = (rb_count(p->m2s_head, p->m2s_tail) != 0U) ? 1 : 0; spin_unlock_irqrestore(&pty_lock, flags); return ready; } -int pty_slave_can_write(void) { +int pty_slave_can_write_idx(int idx) { + if (idx < 0 || idx >= g_pty_count) return 0; + struct pty_pair* p = &g_ptys[idx]; uintptr_t flags = spin_lock_irqsave(&pty_lock); - int ready = (rb_free(s2m_head, s2m_tail) != 0U) ? 1 : 0; + int ready = (rb_free(p->s2m_head, p->s2m_tail) != 0U) ? 1 : 0; spin_unlock_irqrestore(&pty_lock, flags); return ready; } -int pty_master_read_kbuf(void* kbuf, uint32_t len) { +int pty_master_read_idx(int idx, void* kbuf, uint32_t len) { + if (idx < 0 || idx >= g_pty_count) return -ENODEV; + struct pty_pair* p = &g_ptys[idx]; if (!kbuf) return -EFAULT; if (len > 1024 * 1024) return -EINVAL; - int jc = pty_jobctl_read_check(); + int jc = pty_jobctl_read_check(p); if (jc < 0) return jc; while (1) { uintptr_t flags = spin_lock_irqsave(&pty_lock); - uint32_t avail = rb_count(s2m_head, s2m_tail); + uint32_t avail = rb_count(p->s2m_head, p->s2m_tail); if (avail != 0U) { uint32_t to_read = len; if (to_read > avail) to_read = avail; for (uint32_t i = 0; i < to_read; i++) { uint8_t c = 0; - (void)rb_pop(s2m_buf, &s2m_head, &s2m_tail, &c); + (void)rb_pop(p->s2m_buf, &p->s2m_head, &p->s2m_tail, &c); ((uint8_t*)kbuf)[i] = c; } spin_unlock_irqrestore(&pty_lock, flags); @@ -171,7 +248,7 @@ int pty_master_read_kbuf(void* kbuf, uint32_t len) { } if (current_process) { - if (waitq_push(s2m_waitq, &s2m_wq_head, &s2m_wq_tail, current_process) == 0) { + if (waitq_push(p->s2m_waitq, &p->s2m_wq_head, &p->s2m_wq_tail, current_process) == 0) { current_process->state = PROCESS_BLOCKED; } } @@ -182,11 +259,13 @@ int pty_master_read_kbuf(void* kbuf, uint32_t len) { } } -int pty_master_write_kbuf(const void* kbuf, uint32_t len) { +int pty_master_write_idx(int idx, const void* kbuf, uint32_t len) { + if (idx < 0 || idx >= g_pty_count) return -ENODEV; + struct pty_pair* p = &g_ptys[idx]; if (!kbuf) return -EFAULT; if (len > 1024 * 1024) return -EINVAL; - int jc = pty_jobctl_write_check(); + int jc = pty_jobctl_write_check(p); if (jc < 0) return jc; enum { SIGINT_NUM = 2, SIGQUIT_NUM = 3, SIGTSTP_NUM = 20 }; @@ -198,44 +277,46 @@ int pty_master_write_kbuf(const void* kbuf, uint32_t len) { if (ch == 0x03) sig = SIGINT_NUM; else if (ch == 0x1C) sig = SIGQUIT_NUM; else if (ch == 0x1A) sig = SIGTSTP_NUM; - if (sig && pty_fg_pgrp != 0) { - process_kill_pgrp(pty_fg_pgrp, sig); + if (sig && p->fg_pgrp != 0) { + process_kill_pgrp(p->fg_pgrp, sig); } } uintptr_t flags = spin_lock_irqsave(&pty_lock); - uint32_t free = rb_free(m2s_head, m2s_tail); + uint32_t free_space = rb_free(p->m2s_head, p->m2s_tail); uint32_t to_write = len; - if (to_write > free) to_write = free; + if (to_write > free_space) to_write = free_space; for (uint32_t i = 0; i < to_write; i++) { - rb_push(m2s_buf, &m2s_head, &m2s_tail, ((const uint8_t*)kbuf)[i]); + rb_push(p->m2s_buf, &p->m2s_head, &p->m2s_tail, ((const uint8_t*)kbuf)[i]); } if (to_write) { - waitq_wake_one(m2s_waitq, &m2s_wq_head, &m2s_wq_tail); + waitq_wake_one(p->m2s_waitq, &p->m2s_wq_head, &p->m2s_wq_tail); } spin_unlock_irqrestore(&pty_lock, flags); return (int)to_write; } -int pty_slave_read_kbuf(void* kbuf, uint32_t len) { +int pty_slave_read_idx(int idx, void* kbuf, uint32_t len) { + if (idx < 0 || idx >= g_pty_count) return -ENODEV; + struct pty_pair* p = &g_ptys[idx]; if (!kbuf) return -EFAULT; if (len > 1024 * 1024) return -EINVAL; - int jc = pty_jobctl_read_check(); + int jc = pty_jobctl_read_check(p); if (jc < 0) return jc; while (1) { uintptr_t flags = spin_lock_irqsave(&pty_lock); - uint32_t avail = rb_count(m2s_head, m2s_tail); + uint32_t avail = rb_count(p->m2s_head, p->m2s_tail); if (avail != 0U) { uint32_t to_read = len; if (to_read > avail) to_read = avail; for (uint32_t i = 0; i < to_read; i++) { uint8_t c = 0; - (void)rb_pop(m2s_buf, &m2s_head, &m2s_tail, &c); + (void)rb_pop(p->m2s_buf, &p->m2s_head, &p->m2s_tail, &c); ((uint8_t*)kbuf)[i] = c; } spin_unlock_irqrestore(&pty_lock, flags); @@ -243,7 +324,7 @@ int pty_slave_read_kbuf(void* kbuf, uint32_t len) { } if (current_process) { - if (waitq_push(m2s_waitq, &m2s_wq_head, &m2s_wq_tail, current_process) == 0) { + if (waitq_push(p->m2s_waitq, &p->m2s_wq_head, &p->m2s_wq_tail, current_process) == 0) { current_process->state = PROCESS_BLOCKED; } } @@ -254,41 +335,45 @@ int pty_slave_read_kbuf(void* kbuf, uint32_t len) { } } -int pty_slave_write_kbuf(const void* kbuf, uint32_t len) { +int pty_slave_write_idx(int idx, const void* kbuf, uint32_t len) { + if (idx < 0 || idx >= g_pty_count) return -ENODEV; + struct pty_pair* p = &g_ptys[idx]; if (!kbuf) return -EFAULT; if (len > 1024 * 1024) return -EINVAL; - int jc = pty_jobctl_write_check(); + int jc = pty_jobctl_write_check(p); if (jc < 0) return jc; uintptr_t flags = spin_lock_irqsave(&pty_lock); - uint32_t free = rb_free(s2m_head, s2m_tail); + uint32_t free_space = rb_free(p->s2m_head, p->s2m_tail); uint32_t to_write = len; - if (to_write > free) to_write = free; + if (to_write > free_space) to_write = free_space; for (uint32_t i = 0; i < to_write; i++) { - rb_push(s2m_buf, &s2m_head, &s2m_tail, ((const uint8_t*)kbuf)[i]); + rb_push(p->s2m_buf, &p->s2m_head, &p->s2m_tail, ((const uint8_t*)kbuf)[i]); } if (to_write) { - waitq_wake_one(s2m_waitq, &s2m_wq_head, &s2m_wq_tail); + waitq_wake_one(p->s2m_waitq, &p->s2m_wq_head, &p->s2m_wq_tail); } spin_unlock_irqrestore(&pty_lock, flags); return (int)to_write; } -int pty_slave_ioctl(uint32_t cmd, void* user_arg) { +int pty_slave_ioctl_idx(int idx, uint32_t cmd, void* user_arg) { + if (idx < 0 || idx >= g_pty_count) return -ENODEV; + struct pty_pair* p = &g_ptys[idx]; if (!user_arg) return -EFAULT; - if (current_process && pty_session_id == 0 && current_process->session_id != 0) { - pty_session_id = current_process->session_id; - pty_fg_pgrp = current_process->pgrp_id; + if (current_process && p->session_id == 0 && current_process->session_id != 0) { + p->session_id = current_process->session_id; + p->fg_pgrp = current_process->pgrp_id; } if (cmd == TTY_TIOCGPGRP) { if (user_range_ok(user_arg, sizeof(int)) == 0) return -EFAULT; - int fg = (int)pty_fg_pgrp; + int fg = (int)p->fg_pgrp; if (copy_to_user(user_arg, &fg, sizeof(fg)) < 0) return -EFAULT; return 0; } @@ -299,17 +384,60 @@ int pty_slave_ioctl(uint32_t cmd, void* user_arg) { if (copy_from_user(&fg, user_arg, sizeof(fg)) < 0) return -EFAULT; if (!current_process) return -EINVAL; - if (pty_session_id == 0) { + if (p->session_id == 0) { if (fg != 0) return -EPERM; - pty_fg_pgrp = 0; + p->fg_pgrp = 0; return 0; } - if (current_process->session_id != pty_session_id) return -EPERM; + if (current_process->session_id != p->session_id) return -EPERM; if (fg < 0) return -EINVAL; - pty_fg_pgrp = (uint32_t)fg; + p->fg_pgrp = (uint32_t)fg; return 0; } return -EINVAL; } + +static uint32_t pty_master_read_fn(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer) { + (void)offset; + int idx = pty_ino_to_idx(node->inode); + int rc = pty_master_read_idx(idx, buffer, size); + if (rc < 0) return 0; + return (uint32_t)rc; +} + +static uint32_t pty_master_write_fn(fs_node_t* node, uint32_t offset, uint32_t size, const uint8_t* buffer) { + (void)offset; + int idx = pty_ino_to_idx(node->inode); + int rc = pty_master_write_idx(idx, buffer, size); + if (rc < 0) return 0; + return (uint32_t)rc; +} + +static uint32_t pty_slave_read_fn(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer) { + (void)offset; + int idx = pty_ino_to_idx(node->inode); + int rc = pty_slave_read_idx(idx, buffer, size); + if (rc < 0) return 0; + return (uint32_t)rc; +} + +static uint32_t pty_slave_write_fn(fs_node_t* node, uint32_t offset, uint32_t size, const uint8_t* buffer) { + (void)offset; + int idx = pty_ino_to_idx(node->inode); + int rc = pty_slave_write_idx(idx, buffer, size); + if (rc < 0) return 0; + return (uint32_t)rc; +} + +int pty_master_can_read(void) { return pty_master_can_read_idx(0); } +int pty_master_can_write(void) { return pty_master_can_write_idx(0); } +int pty_slave_can_read(void) { return pty_slave_can_read_idx(0); } +int pty_slave_can_write(void) { return pty_slave_can_write_idx(0); } + +int pty_master_read_kbuf(void* kbuf, uint32_t len) { return pty_master_read_idx(0, kbuf, len); } +int pty_master_write_kbuf(const void* kbuf, uint32_t len) { return pty_master_write_idx(0, kbuf, len); } +int pty_slave_read_kbuf(void* kbuf, uint32_t len) { return pty_slave_read_idx(0, kbuf, len); } +int pty_slave_write_kbuf(const void* kbuf, uint32_t len) { return pty_slave_write_idx(0, kbuf, len); } +int pty_slave_ioctl(uint32_t cmd, void* user_arg) { return pty_slave_ioctl_idx(0, cmd, user_arg); } diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index 486dbf3..263cdc9 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -273,12 +273,14 @@ static int poll_wait_kfds(struct pollfd* kfds, uint32_t nfds, int32_t timeout) { } else if (n->inode == 3) { if ((kfds[i].events & POLLIN) && tty_can_read()) kfds[i].revents |= POLLIN; if ((kfds[i].events & POLLOUT) && tty_can_write()) kfds[i].revents |= POLLOUT; - } else if (n->inode == 4) { - if ((kfds[i].events & POLLIN) && pty_master_can_read()) kfds[i].revents |= POLLIN; - if ((kfds[i].events & POLLOUT) && pty_master_can_write()) kfds[i].revents |= POLLOUT; - } else if (n->inode == 6) { - if ((kfds[i].events & POLLIN) && pty_slave_can_read()) kfds[i].revents |= POLLIN; - if ((kfds[i].events & POLLOUT) && pty_slave_can_write()) kfds[i].revents |= POLLOUT; + } else if (pty_is_master_ino(n->inode)) { + int pi = pty_ino_to_idx(n->inode); + if ((kfds[i].events & POLLIN) && pty_master_can_read_idx(pi)) kfds[i].revents |= POLLIN; + if ((kfds[i].events & POLLOUT) && pty_master_can_write_idx(pi)) kfds[i].revents |= POLLOUT; + } else if (pty_is_slave_ino(n->inode)) { + int pi = pty_ino_to_idx(n->inode); + if ((kfds[i].events & POLLIN) && pty_slave_can_read_idx(pi)) kfds[i].revents |= POLLIN; + if ((kfds[i].events & POLLOUT) && pty_slave_can_write_idx(pi)) kfds[i].revents |= POLLOUT; } } else { // Regular files are always readable/writable (best-effort). @@ -1197,10 +1199,10 @@ static int syscall_read_impl(int fd, void* user_buf, uint32_t len) { if (f->node->flags == FS_CHARDEVICE) { if (f->node->inode == 3) { if (!tty_can_read()) return -EAGAIN; - } else if (f->node->inode == 4) { - if (!pty_master_can_read()) return -EAGAIN; - } else if (f->node->inode == 6) { - if (!pty_slave_can_read()) return -EAGAIN; + } else if (pty_is_master_ino(f->node->inode)) { + if (!pty_master_can_read_idx(pty_ino_to_idx(f->node->inode))) return -EAGAIN; + } else if (pty_is_slave_ino(f->node->inode)) { + if (!pty_slave_can_read_idx(pty_ino_to_idx(f->node->inode))) return -EAGAIN; } } } @@ -1306,7 +1308,8 @@ static int syscall_ioctl_impl(int fd, uint32_t cmd, void* user_arg) { fs_node_t* n = f->node; if (n->flags != FS_CHARDEVICE) return -ENOTTY; if (n->inode == 3) return tty_ioctl(cmd, user_arg); - if (n->inode == 6) return pty_slave_ioctl(cmd, user_arg); + if (pty_is_slave_ino(n->inode)) return pty_slave_ioctl_idx(pty_ino_to_idx(n->inode), cmd, user_arg); + if (pty_is_master_ino(n->inode)) return -ENOTTY; return -ENOTTY; } -- 2.43.0