1#![allow(dead_code, clippy::needless_range_loop)]
22
23#[allow(unused_imports)]
24use alloc::{collections::VecDeque, format, sync::Arc, vec::Vec};
25use core::sync::atomic::{AtomicU32, AtomicU64, Ordering};
26
27#[cfg(not(target_arch = "aarch64"))]
28use spin::RwLock;
29
30#[cfg(target_arch = "aarch64")]
31use super::bare_lock::RwLock;
32use crate::{error::KernelError, process::ProcessId, sync::once_lock::GlobalState};
33
34const PTY_BUFFER_SIZE: usize = 4096;
36
37pub mod termios {
39 pub const VINTR: u8 = 0; pub const VQUIT: u8 = 1; pub const VERASE: u8 = 2; pub const VKILL: u8 = 3; pub const VEOF: u8 = 4; pub const VEOL: u8 = 5; pub const VSUSP: u8 = 6; pub const VINTR_CHAR: u8 = 3; pub const VEOF_CHAR: u8 = 4; pub const VSUSP_CHAR: u8 = 26; }
50
51#[derive(Debug, Clone, Copy)]
53pub struct TermiosFlags {
54 pub echo: bool,
56
57 pub canonical: bool,
59
60 pub isig: bool,
62
63 pub opost: bool,
65}
66
67impl Default for TermiosFlags {
68 fn default() -> Self {
69 Self {
70 echo: true,
71 canonical: true,
72 isig: true,
73 opost: true,
74 }
75 }
76}
77
78#[derive(Debug, Clone, Copy)]
80pub struct Winsize {
81 pub rows: u16,
82 pub cols: u16,
83 pub xpixel: u16,
84 pub ypixel: u16,
85}
86
87impl Default for Winsize {
88 fn default() -> Self {
89 Self {
90 rows: 24,
91 cols: 80,
92 xpixel: 0,
93 ypixel: 0,
94 }
95 }
96}
97
98pub struct PtyMaster {
100 id: u32,
102
103 input_buffer: RwLock<VecDeque<u8>>,
105
106 output_buffer: RwLock<VecDeque<u8>>,
108
109 winsize: RwLock<Winsize>,
111
112 flags: RwLock<TermiosFlags>,
114
115 controller: RwLock<Option<ProcessId>>,
117
118 foreground_pgid: AtomicU64,
123}
124
125impl PtyMaster {
126 pub fn new(id: u32) -> Self {
128 Self {
129 id,
130 input_buffer: RwLock::new(VecDeque::with_capacity(PTY_BUFFER_SIZE)),
131 output_buffer: RwLock::new(VecDeque::with_capacity(PTY_BUFFER_SIZE)),
132 winsize: RwLock::new(Winsize::default()),
133 flags: RwLock::new(TermiosFlags::default()),
134 controller: RwLock::new(None),
135 foreground_pgid: AtomicU64::new(0),
136 }
137 }
138
139 pub fn id(&self) -> u32 {
141 self.id
142 }
143
144 pub fn read(&self, buffer: &mut [u8]) -> Result<usize, KernelError> {
146 let mut output = self.output_buffer.write();
147 let bytes_to_read = buffer.len().min(output.len());
148
149 for i in 0..bytes_to_read {
150 buffer[i] = output.pop_front().expect("output buffer underrun");
152 }
153
154 Ok(bytes_to_read)
155 }
156
157 pub fn write(&self, data: &[u8]) -> Result<usize, KernelError> {
159 let mut input = self.input_buffer.write();
160 let flags = self.flags.read();
161
162 for &byte in data {
163 if flags.isig {
165 if byte == termios::VINTR_CHAR {
166 self.send_signal_to_foreground_group(2);
168 continue;
169 }
170
171 if byte == termios::VSUSP_CHAR {
172 self.send_signal_to_foreground_group(20);
174 continue;
175 }
176 }
177
178 if input.len() < PTY_BUFFER_SIZE {
179 input.push_back(byte);
180 } else {
181 return Err(KernelError::ResourceExhausted {
182 resource: "pty_input_buffer",
183 });
184 }
185 }
186
187 Ok(data.len())
188 }
189
190 fn send_signal_to_foreground_group(&self, signal: i32) {
194 let fg_pgid = self.foreground_pgid.load(Ordering::Acquire);
195
196 if fg_pgid != 0 {
197 crate::process::table::PROCESS_TABLE.for_each(|proc| {
199 let proc_pgid = proc.pgid.load(Ordering::Acquire);
200 if proc_pgid == fg_pgid && proc.is_alive() {
201 if let Err(_e) = proc.send_signal(signal as usize) {
202 crate::println!(
203 "[PTY] Warning: failed to send signal {} to PID {}: {:?}",
204 signal,
205 proc.pid.0,
206 _e
207 );
208 }
209 }
210 });
211 } else if let Some(pid) = *self.controller.read() {
212 let process_server = crate::services::process_server::get_process_server();
214 if let Err(_e) = process_server.send_signal(pid, signal) {
215 crate::println!(
216 "[PTY] Warning: failed to send signal {} to PID {}: {:?}",
217 signal,
218 pid.0,
219 _e
220 );
221 }
222 }
223 }
224
225 pub fn set_winsize(&self, winsize: Winsize) {
227 *self.winsize.write() = winsize;
228 if let Some(pid) = *self.controller.read() {
230 let process_server = crate::services::process_server::get_process_server();
231 if let Err(_e) = process_server.send_signal(pid, 28) {
232 crate::println!(
233 "[PTY] Warning: failed to send SIGWINCH to PID {}: {:?}",
234 pid.0,
235 _e
236 );
237 }
238 }
239 }
240
241 pub fn get_winsize(&self) -> Winsize {
243 *self.winsize.read()
244 }
245
246 pub fn set_flags(&self, flags: TermiosFlags) {
248 *self.flags.write() = flags;
249 }
250
251 pub fn get_flags(&self) -> TermiosFlags {
253 *self.flags.read()
254 }
255
256 pub fn set_controller(&self, pid: ProcessId) {
262 *self.controller.write() = Some(pid);
263 }
264
265 pub fn get_controller(&self) -> Option<ProcessId> {
267 *self.controller.read()
268 }
269
270 pub fn set_foreground_pgid(&self, pgid: u64) {
277 self.foreground_pgid.store(pgid, Ordering::Release);
278 }
279
280 pub fn get_foreground_pgid(&self) -> u64 {
284 self.foreground_pgid.load(Ordering::Acquire)
285 }
286}
287
288pub struct PtySlave {
290 id: u32,
292
293 master_id: u32,
295}
296
297impl PtySlave {
298 pub fn new(id: u32, master_id: u32) -> Self {
300 Self { id, master_id }
301 }
302
303 pub fn id(&self) -> u32 {
305 self.id
306 }
307
308 pub fn master_id(&self) -> u32 {
310 self.master_id
311 }
312
313 pub fn read(&self, buffer: &mut [u8]) -> Result<usize, KernelError> {
315 if let Some(master) = get_pty_master(self.master_id) {
317 let mut input = master.input_buffer.write();
318 let bytes_to_read = buffer.len().min(input.len());
319
320 for i in 0..bytes_to_read {
321 buffer[i] = input.pop_front().expect("input buffer underrun");
323 }
324
325 Ok(bytes_to_read)
326 } else {
327 Err(KernelError::NotFound {
328 resource: "pty_master",
329 id: self.master_id as u64,
330 })
331 }
332 }
333
334 pub fn write(&self, data: &[u8]) -> Result<usize, KernelError> {
336 if let Some(master) = get_pty_master(self.master_id) {
338 let mut output = master.output_buffer.write();
339 let flags = master.flags.read();
340
341 for &byte in data {
342 if flags.opost && byte == b'\n' {
344 if output.len() < PTY_BUFFER_SIZE - 1 {
346 output.push_back(b'\r');
347 output.push_back(b'\n');
348 }
349 } else if output.len() < PTY_BUFFER_SIZE {
350 output.push_back(byte);
351 } else {
352 return Err(KernelError::ResourceExhausted {
353 resource: "pty_output_buffer",
354 });
355 }
356 }
357
358 Ok(data.len())
359 } else {
360 Err(KernelError::NotFound {
361 resource: "pty_master",
362 id: self.master_id as u64,
363 })
364 }
365 }
366}
367
368pub struct PtyManager {
370 masters: RwLock<Vec<Arc<PtyMaster>>>,
372
373 next_id: AtomicU32,
375}
376
377impl PtyManager {
378 pub fn new() -> Self {
380 Self {
381 masters: RwLock::new(Vec::new()),
382 next_id: AtomicU32::new(0),
383 }
384 }
385
386 pub fn create_pty(&self) -> Result<(u32, u32), KernelError> {
388 let id = self.next_id.fetch_add(1, Ordering::Relaxed);
389
390 let master = Arc::new(PtyMaster::new(id));
391 let master_id = master.id();
392
393 self.masters.write().push(master);
394
395 println!(
396 "[PTY] Created PTY pair: master={}, slave={}",
397 master_id, master_id
398 );
399
400 Ok((master_id, master_id))
401 }
402
403 pub fn get_master(&self, id: u32) -> Option<Arc<PtyMaster>> {
405 self.masters.read().iter().find(|m| m.id == id).cloned()
406 }
407
408 pub fn has_pty(&self, id: u32) -> bool {
410 self.masters.read().iter().any(|m| m.id == id)
411 }
412
413 pub fn close_pty(&self, id: u32) -> Result<(), KernelError> {
415 let mut masters = self.masters.write();
416 if let Some(pos) = masters.iter().position(|m| m.id == id) {
417 masters.remove(pos);
418 println!("[PTY] Closed PTY {}", id);
419 Ok(())
420 } else {
421 Err(KernelError::NotFound {
422 resource: "pty",
423 id: id as u64,
424 })
425 }
426 }
427
428 pub fn count(&self) -> usize {
430 self.masters.read().len()
431 }
432}
433
434impl Default for PtyManager {
435 fn default() -> Self {
436 Self::new()
437 }
438}
439
440static PTY_MANAGER: GlobalState<PtyManager> = GlobalState::new();
442
443pub fn init() -> Result<(), KernelError> {
445 let manager = PtyManager::new();
446 PTY_MANAGER
447 .init(manager)
448 .map_err(|_| KernelError::InvalidState {
449 expected: "uninitialized",
450 actual: "initialized",
451 })?;
452
453 println!("[PTY] Pseudo-terminal system initialized");
454 Ok(())
455}
456
457pub fn with_pty_manager<R, F: FnOnce(&PtyManager) -> R>(f: F) -> Option<R> {
459 PTY_MANAGER.with(f)
460}
461
462fn get_pty_master(id: u32) -> Option<Arc<PtyMaster>> {
464 PTY_MANAGER.with(|manager| manager.get_master(id)).flatten()
465}
466
467use super::{DirEntry, Metadata, NodeType, Permissions, VfsNode};
472
473pub struct PtyMasterNode {
479 master: Arc<PtyMaster>,
481}
482
483impl PtyMasterNode {
484 pub fn new(master: Arc<PtyMaster>) -> Self {
486 Self { master }
487 }
488
489 pub fn pty_id(&self) -> u32 {
491 self.master.id()
492 }
493}
494
495impl VfsNode for PtyMasterNode {
496 fn node_type(&self) -> NodeType {
497 NodeType::CharDevice
498 }
499
500 fn read(&self, _offset: usize, buffer: &mut [u8]) -> Result<usize, KernelError> {
502 self.master.read(buffer)
503 }
504
505 fn write(&self, _offset: usize, data: &[u8]) -> Result<usize, KernelError> {
507 self.master.write(data)
508 }
509
510 fn metadata(&self) -> Result<Metadata, KernelError> {
511 Ok(Metadata {
512 node_type: NodeType::CharDevice,
513 size: 0,
514 permissions: Permissions::from_mode(0o620),
515 uid: 0,
516 gid: 5, created: 0,
518 modified: 0,
519 accessed: 0,
520 inode: 0x9000_0000 | self.master.id() as u64,
521 })
522 }
523
524 fn readdir(&self) -> Result<Vec<DirEntry>, KernelError> {
525 Err(KernelError::FsError(crate::error::FsError::NotADirectory))
526 }
527
528 fn lookup(&self, _name: &str) -> Result<Arc<dyn VfsNode>, KernelError> {
529 Err(KernelError::FsError(crate::error::FsError::NotADirectory))
530 }
531
532 fn create(
533 &self,
534 _name: &str,
535 _permissions: Permissions,
536 ) -> Result<Arc<dyn VfsNode>, KernelError> {
537 Err(KernelError::FsError(crate::error::FsError::NotADirectory))
538 }
539
540 fn mkdir(
541 &self,
542 _name: &str,
543 _permissions: Permissions,
544 ) -> Result<Arc<dyn VfsNode>, KernelError> {
545 Err(KernelError::FsError(crate::error::FsError::NotADirectory))
546 }
547
548 fn unlink(&self, _name: &str) -> Result<(), KernelError> {
549 Err(KernelError::FsError(crate::error::FsError::NotADirectory))
550 }
551
552 fn truncate(&self, _size: usize) -> Result<(), KernelError> {
553 Err(KernelError::PermissionDenied {
554 operation: "truncate PTY master",
555 })
556 }
557}
558
559pub struct PtySlaveNode {
566 slave: PtySlave,
568}
569
570impl PtySlaveNode {
571 pub fn new(slave: PtySlave) -> Self {
573 Self { slave }
574 }
575
576 pub fn pty_id(&self) -> u32 {
578 self.slave.id()
579 }
580
581 pub fn pts_path(&self) -> alloc::string::String {
583 format!("/dev/pts/{}", self.slave.id())
584 }
585}
586
587impl VfsNode for PtySlaveNode {
588 fn node_type(&self) -> NodeType {
589 NodeType::CharDevice
590 }
591
592 fn read(&self, _offset: usize, buffer: &mut [u8]) -> Result<usize, KernelError> {
594 self.slave.read(buffer)
595 }
596
597 fn write(&self, _offset: usize, data: &[u8]) -> Result<usize, KernelError> {
600 self.slave.write(data)
601 }
602
603 fn metadata(&self) -> Result<Metadata, KernelError> {
604 Ok(Metadata {
605 node_type: NodeType::CharDevice,
606 size: 0,
607 permissions: Permissions::from_mode(0o620),
608 uid: 0,
609 gid: 5, created: 0,
611 modified: 0,
612 accessed: 0,
613 inode: 0x9100_0000 | self.slave.id() as u64,
614 })
615 }
616
617 fn readdir(&self) -> Result<Vec<DirEntry>, KernelError> {
618 Err(KernelError::FsError(crate::error::FsError::NotADirectory))
619 }
620
621 fn lookup(&self, _name: &str) -> Result<Arc<dyn VfsNode>, KernelError> {
622 Err(KernelError::FsError(crate::error::FsError::NotADirectory))
623 }
624
625 fn create(
626 &self,
627 _name: &str,
628 _permissions: Permissions,
629 ) -> Result<Arc<dyn VfsNode>, KernelError> {
630 Err(KernelError::FsError(crate::error::FsError::NotADirectory))
631 }
632
633 fn mkdir(
634 &self,
635 _name: &str,
636 _permissions: Permissions,
637 ) -> Result<Arc<dyn VfsNode>, KernelError> {
638 Err(KernelError::FsError(crate::error::FsError::NotADirectory))
639 }
640
641 fn unlink(&self, _name: &str) -> Result<(), KernelError> {
642 Err(KernelError::FsError(crate::error::FsError::NotADirectory))
643 }
644
645 fn truncate(&self, _size: usize) -> Result<(), KernelError> {
646 Err(KernelError::PermissionDenied {
647 operation: "truncate PTY slave",
648 })
649 }
650}
651
652#[cfg(test)]
653mod tests {
654 use super::*;
655
656 #[test]
657 fn test_pty_creation() {
658 let mut manager = PtyManager::new();
659 let result = manager.create_pty();
660 assert!(result.is_ok());
661 }
662
663 #[test]
664 fn test_pty_read_write() {
665 let master = PtyMaster::new(0);
666 let slave = PtySlave::new(0, 0);
667
668 let data = b"Hello PTY!";
670 assert!(master.write(data).is_ok());
671
672 }
675
676 #[test]
677 fn test_winsize() {
678 let master = PtyMaster::new(0);
679 let winsize = Winsize {
680 rows: 30,
681 cols: 100,
682 xpixel: 800,
683 ypixel: 600,
684 };
685
686 master.set_winsize(winsize);
687 let retrieved = master.get_winsize();
688
689 assert_eq!(retrieved.rows, 30);
690 assert_eq!(retrieved.cols, 100);
691 }
692}