1use crate::fs::devpts::{DEVPTS_COUNT, get_device_type_for_pts};
6use crate::mutable_state::{state_accessor, state_implementation};
7use crate::task::{EventHandler, ProcessGroup, Session, WaitCanceler, WaitQueue, Waiter};
8use crate::vfs::buffers::{InputBuffer, InputBufferExt as _, OutputBuffer};
9use crate::vfs::{DirEntryHandle, FsString, Mounts};
10use derivative::Derivative;
11use macro_rules_attribute::apply;
12use starnix_logging::track_stub;
13use starnix_sync::{LockBefore, Locked, Mutex, ProcessGroupState, RwLock};
14use starnix_uapi::auth::FsCred;
15use starnix_uapi::device_type::DeviceType;
16use starnix_uapi::errors::Errno;
17use starnix_uapi::signals::{SIGINT, SIGQUIT, SIGSTOP, Signal};
18use starnix_uapi::vfs::FdEvents;
19use starnix_uapi::{
20 ECHO, ECHOCTL, ECHOE, ECHOK, ECHOKE, ECHONL, ECHOPRT, ICANON, ICRNL, IEXTEN, IGNCR, INLCR,
21 ISIG, IUTF8, OCRNL, ONLCR, ONLRET, ONOCR, OPOST, TABDLY, VEOF, VEOL, VEOL2, VERASE, VINTR,
22 VKILL, VQUIT, VSUSP, VWERASE, XTABS, cc_t, error, tcflag_t, uapi,
23};
24use std::collections::{BTreeSet, HashMap, VecDeque};
25use std::sync::{Arc, Weak};
26
27const CANON_MAX_BYTES: usize = 4096;
30
31const NON_CANON_MAX_BYTES: usize = CANON_MAX_BYTES - 1;
34
35const WAIT_BUFFER_MAX_BYTES: usize = 131072;
38
39const SPACES_PER_TAB: usize = 8;
40
41const DISABLED_CHAR: u8 = 0;
43
44const BACKSPACE_CHAR: u8 = 8; const CONTROL_OFFSET: u8 = 0x40;
50
51pub struct TtyState {
53 pub terminals: RwLock<HashMap<u32, Weak<Terminal>>>,
55
56 pts_ids_set: Mutex<PtsIdsSet>,
58}
59
60impl TtyState {
61 pub fn get_next_terminal(
63 self: &Arc<Self>,
64 dev_pts_root: DirEntryHandle,
65 creds: FsCred,
66 ) -> Result<Arc<Terminal>, Errno> {
67 let id = self.pts_ids_set.lock().acquire()?;
68 let terminal = Terminal::new(self.clone(), dev_pts_root, creds, id);
69 assert!(self.terminals.write().insert(id, Arc::downgrade(&terminal)).is_none());
70 Ok(terminal)
71 }
72
73 pub fn release_terminal(&self, id: u32) -> Result<(), Errno> {
75 assert!(self.terminals.write().remove(&id).is_some());
79 self.pts_ids_set.lock().release(id);
80 Ok(())
81 }
82}
83
84impl Default for TtyState {
85 fn default() -> Self {
86 Self {
87 terminals: RwLock::new(HashMap::new()),
88 pts_ids_set: Mutex::new(PtsIdsSet::new(DEVPTS_COUNT)),
89 }
90 }
91}
92
93#[derive(Derivative)]
94#[derivative(Default)]
95#[derivative(Debug)]
96pub struct TerminalMutableState {
97 #[derivative(Default(value = "true"))]
99 pub locked: bool,
100
101 pub window_size: uapi::winsize,
103
104 #[derivative(Default(value = "get_default_termios()"))]
106 termios: uapi::termios,
107
108 column: usize,
111
112 main_references: Option<u32>,
115
116 replica_references: Option<u32>,
119
120 #[derivative(Default(value = "Queue::input_queue()"))]
131 input_queue: Option<Queue>,
132 #[derivative(Default(value = "Queue::output_queue()"))]
143 output_queue: Option<Queue>,
144
145 main_wait_queue: WaitQueue,
147
148 replica_wait_queue: WaitQueue,
150
151 pub controller: Option<TerminalController>,
153}
154
155#[derive(Derivative)]
157#[derivative(Debug)]
158pub struct Terminal {
159 weak_self: Weak<Self>,
161
162 #[derivative(Debug = "ignore")]
164 state: Arc<TtyState>,
165
166 pub dev_pts_root: DirEntryHandle,
168
169 pub fscred: FsCred,
171
172 pub id: u32,
174
175 mutable_state: RwLock<TerminalMutableState>,
177}
178
179impl Terminal {
180 pub fn new(
181 state: Arc<TtyState>,
182 dev_pts_root: DirEntryHandle,
183 fscred: FsCred,
184 id: u32,
185 ) -> Arc<Self> {
186 Arc::new_cyclic(|weak_self| Self {
187 weak_self: weak_self.clone(),
188 state,
189 dev_pts_root,
190 fscred,
191 id,
192 mutable_state: RwLock::new(Default::default()),
193 })
194 }
195
196 pub fn to_owned(&self) -> Arc<Terminal> {
197 self.weak_self.upgrade().expect("This should never be called while releasing the terminal")
198 }
199
200 pub fn set_termios<L>(&self, locked: &mut Locked<L>, termios: uapi::termios)
202 where
203 L: LockBefore<ProcessGroupState>,
204 {
205 let signals = self.write().set_termios(termios);
206 self.send_signals(locked, signals);
207 }
208
209 pub fn main_close(&self) {
211 let id = FsString::from(self.id.to_string());
213 self.dev_pts_root.remove_child(id.as_ref(), &Mounts::new());
215 self.write().main_close();
216 }
217
218 pub fn main_open(&self) {
220 self.write().main_open();
221 }
222
223 pub fn main_wait_async(
225 &self,
226 waiter: &Waiter,
227 events: FdEvents,
228 handler: EventHandler,
229 ) -> WaitCanceler {
230 self.read().main_wait_async(waiter, events, handler)
231 }
232
233 pub fn main_query_events(&self) -> FdEvents {
235 self.read().main_query_events()
236 }
237
238 pub fn main_read<L>(
240 &self,
241 _locked: &mut Locked<L>,
242 data: &mut dyn OutputBuffer,
243 ) -> Result<usize, Errno>
244 where
245 L: LockBefore<ProcessGroupState>,
246 {
247 self.write().main_read(data)
248 }
249
250 pub fn main_write<L>(
252 &self,
253 locked: &mut Locked<L>,
254 data: &mut dyn InputBuffer,
255 ) -> Result<usize, Errno>
256 where
257 L: LockBefore<ProcessGroupState>,
258 {
259 let (bytes, signals) = self.write().main_write(data)?;
260 self.send_signals(locked, signals);
261 Ok(bytes)
262 }
263
264 pub fn replica_close(&self) {
266 self.write().replica_close();
267 }
268
269 pub fn replica_open(&self) {
271 self.write().replica_open();
272 }
273
274 pub fn replica_wait_async(
276 &self,
277 waiter: &Waiter,
278 events: FdEvents,
279 handler: EventHandler,
280 ) -> WaitCanceler {
281 self.read().replica_wait_async(waiter, events, handler)
282 }
283
284 pub fn replica_query_events(&self) -> FdEvents {
286 self.read().replica_query_events()
287 }
288
289 pub fn replica_read<L>(
291 &self,
292 _locked: &mut Locked<L>,
293 data: &mut dyn OutputBuffer,
294 ) -> Result<usize, Errno>
295 where
296 L: LockBefore<ProcessGroupState>,
297 {
298 self.write().replica_read(data)
299 }
300
301 pub fn replica_write<L>(
303 &self,
304 _locked: &mut Locked<L>,
305 data: &mut dyn InputBuffer,
306 ) -> Result<usize, Errno>
307 where
308 L: LockBefore<ProcessGroupState>,
309 {
310 self.write().replica_write(data)
311 }
312
313 fn send_signals<L>(&self, locked: &mut Locked<L>, signals: PendingSignals)
315 where
316 L: LockBefore<ProcessGroupState>,
317 {
318 let signals = signals.signals();
319 if !signals.is_empty() {
320 let process_group = {
321 let terminal_state = self.read();
322 let Some(controller) = terminal_state.controller.as_ref() else {
323 return;
324 };
325 let Some(session) = controller.session.upgrade() else {
326 return;
327 };
328 let Some(process_group) = session.read().get_foreground_process_group() else {
329 return;
330 };
331 process_group
332 };
333 process_group.send_signals(locked, signals);
334 }
335 }
336
337 pub fn device(&self) -> DeviceType {
338 get_device_type_for_pts(self.id)
339 }
340
341 state_accessor!(Terminal, mutable_state);
342}
343
344macro_rules! with_queue {
355 ($self_:tt . $name:ident . $fn:ident ( $($param:expr),*$(,)?)) => {
356 {
357 let mut queue = $self_.$name . take().unwrap();
358 let result = queue.$fn( $($param),* );
359 $self_.$name = Some(queue);
360 result
361 }
362 };
363}
364
365#[must_use]
367pub struct PendingSignals {
368 signals: Vec<Signal>,
369}
370
371impl PendingSignals {
372 pub fn new() -> Self {
373 Self { signals: vec![] }
374 }
375
376 fn add(&mut self, signal: Signal) {
378 self.signals.push(signal);
379 }
380
381 fn append(&mut self, mut other: Self) {
383 self.signals.append(&mut other.signals);
384 }
385
386 pub fn signals(&self) -> &[Signal] {
387 &self.signals[..]
388 }
389}
390
391#[derive(Debug, PartialEq)]
393enum EraseType {
394 Character,
396 Word,
398 Line,
400}
401
402#[apply(state_implementation!)]
403impl TerminalMutableState<Base = Terminal> {
404 pub fn termios(&self) -> &uapi::termios {
406 &self.termios
407 }
408
409 pub fn get_available_read_size(&self, is_main: bool) -> usize {
412 let queue = if is_main { self.output_queue() } else { self.input_queue() };
413 queue.readable_size()
414 }
415
416 fn set_termios(&mut self, termios: uapi::termios) -> PendingSignals {
418 let old_canon_enabled = self.termios.has_local_flags(ICANON);
419 self.termios = termios;
420 if old_canon_enabled && !self.termios.has_local_flags(ICANON) {
421 let signals = with_queue!(self.input_queue.on_canon_disabled(self.as_mut()));
422 self.notify_waiters();
423 signals
424 } else {
425 PendingSignals::new()
426 }
427 }
428
429 pub fn main_close(&mut self) {
431 self.main_references = self.main_references.map(|v| v - 1);
432 self.notify_waiters();
433 }
434
435 pub fn main_open(&mut self) {
437 self.main_references = Some(self.main_references.unwrap_or(0) + 1);
438 }
439
440 pub fn is_main_closed(&self) -> bool {
441 matches!(self.main_references, Some(0))
442 }
443
444 fn main_wait_async(
446 &self,
447 waiter: &Waiter,
448 events: FdEvents,
449 handler: EventHandler,
450 ) -> WaitCanceler {
451 self.main_wait_queue.wait_async_fd_events(waiter, events, handler)
452 }
453
454 fn main_query_events(&self) -> FdEvents {
456 if self.is_replica_closed() && self.output_queue().readable_size() == 0 {
457 return FdEvents::POLLOUT | FdEvents::POLLHUP;
458 }
459 self.output_queue().read_readyness() | self.input_queue().write_readyness()
460 }
461
462 fn main_read(&mut self, data: &mut dyn OutputBuffer) -> Result<usize, Errno> {
464 if self.is_replica_closed() && self.output_queue().readable_size() == 0 {
465 return error!(EIO);
466 }
467 let result = with_queue!(self.output_queue.read(self.as_mut(), data))?;
468 self.notify_waiters();
469 Ok(result)
470 }
471
472 fn main_write(&mut self, data: &mut dyn InputBuffer) -> Result<(usize, PendingSignals), Errno> {
474 let result = with_queue!(self.input_queue.write(self.as_mut(), data))?;
475 self.notify_waiters();
476 Ok(result)
477 }
478
479 pub fn replica_close(&mut self) {
481 self.replica_references = self.replica_references.map(|v| v - 1);
482 self.notify_waiters();
483 }
484
485 pub fn replica_open(&mut self) {
487 self.replica_references = Some(self.replica_references.unwrap_or(0) + 1);
488 }
489
490 fn is_replica_closed(&self) -> bool {
491 matches!(self.replica_references, Some(0))
492 }
493
494 fn replica_wait_async(
496 &self,
497 waiter: &Waiter,
498 events: FdEvents,
499 handler: EventHandler,
500 ) -> WaitCanceler {
501 self.replica_wait_queue.wait_async_fd_events(waiter, events, handler)
502 }
503
504 fn replica_query_events(&self) -> FdEvents {
506 if self.is_main_closed() {
507 return FdEvents::POLLIN | FdEvents::POLLOUT | FdEvents::POLLERR | FdEvents::POLLHUP;
508 }
509 self.input_queue().read_readyness() | self.output_queue().write_readyness()
510 }
511
512 fn replica_read(&mut self, data: &mut dyn OutputBuffer) -> Result<usize, Errno> {
514 if self.is_main_closed() {
515 return Ok(0);
516 }
517 let result = with_queue!(self.input_queue.read(self.as_mut(), data))?;
518 self.notify_waiters();
519 Ok(result)
520 }
521
522 fn replica_write(&mut self, data: &mut dyn InputBuffer) -> Result<usize, Errno> {
524 if self.is_main_closed() {
525 return error!(EIO);
526 }
527 let (read_from_userspace, signals) =
528 with_queue!(self.output_queue.write(self.as_mut(), data))?;
529 assert!(signals.signals().is_empty());
530 self.notify_waiters();
531 Ok(read_from_userspace)
532 }
533
534 fn input_queue(&self) -> &Queue {
536 self.input_queue.as_ref().unwrap()
537 }
538
539 fn output_queue(&self) -> &Queue {
541 self.output_queue.as_ref().unwrap()
542 }
543
544 fn notify_waiters(&mut self) {
546 let main_events = self.main_query_events();
547 if main_events.bits() != 0 {
548 self.main_wait_queue.notify_fd_events(main_events);
549 }
550 let replica_events = self.replica_query_events();
551 if replica_events.bits() != 0 {
552 self.replica_wait_queue.notify_fd_events(replica_events);
553 }
554 }
555
556 fn handle_signals(&mut self, byte: RawByte) -> Option<Signal> {
558 if !self.termios.has_local_flags(ISIG) {
559 return None;
560 }
561 self.termios.signal(byte)
562 }
563
564 fn transform(
573 &mut self,
574 is_input: bool,
575 queue: &mut Queue,
576 buffer: &[RawByte],
577 ) -> (usize, PendingSignals) {
578 if is_input {
579 self.transform_input(queue, buffer)
580 } else {
581 (self.transform_output(queue, buffer), PendingSignals::new())
582 }
583 }
584
585 fn transform_output(&mut self, queue: &mut Queue, original_buffer: &[RawByte]) -> usize {
587 let mut buffer = original_buffer;
588
589 if !self.termios.has_output_flags(OPOST) {
593 queue.read_buffer.extend_from_slice(buffer);
594 if !queue.read_buffer.is_empty() {
595 queue.readable = true;
596 }
597 return buffer.len();
598 }
599
600 let mut return_value = 0;
601 while !buffer.is_empty() {
602 let size = compute_next_character_size(buffer, &self.termios);
603 let mut character_bytes = buffer[..size].to_vec();
604 return_value += size;
605 buffer = &buffer[size..];
606 match character_bytes[0] {
607 b'\n' => {
608 if self.termios.has_output_flags(ONLRET) {
609 self.column = 0;
610 }
611 if self.termios.has_output_flags(ONLCR) {
612 queue.read_buffer.extend_from_slice(&[b'\r', b'\n']);
613 continue;
614 }
615 }
616 b'\r' => {
617 if self.termios.has_output_flags(ONOCR) && self.column == 0 {
618 continue;
619 }
620 if self.termios.has_output_flags(OCRNL) {
621 character_bytes[0] = b'\n';
622 if self.termios.has_output_flags(ONLRET) {
623 self.column = 0;
624 }
625 } else {
626 self.column = 0;
627 }
628 }
629 b'\t' => {
630 let spaces = SPACES_PER_TAB - self.column % SPACES_PER_TAB;
631 if self.termios.c_oflag & TABDLY == XTABS {
632 self.column += spaces;
633 queue.read_buffer.extend(std::iter::repeat(b' ').take(SPACES_PER_TAB));
634 continue;
635 }
636 self.column += spaces;
637 }
638 BACKSPACE_CHAR => {
639 if self.column > 0 {
640 self.column -= 1;
641 }
642 }
643 _ => {
644 self.column += 1;
645 }
646 }
647 queue.read_buffer.append(&mut character_bytes);
648 }
649 if !queue.read_buffer.is_empty() {
650 queue.readable = true;
651 }
652 return_value
653 }
654
655 fn transform_input(
657 &mut self,
658 queue: &mut Queue,
659 original_buffer: &[RawByte],
660 ) -> (usize, PendingSignals) {
661 let mut buffer = original_buffer;
662
663 if self.termios.has_local_flags(ICANON) && queue.readable {
666 return (0, PendingSignals::new());
667 }
668
669 let max_bytes = if self.termios.has_local_flags(ICANON) {
670 CANON_MAX_BYTES
671 } else {
672 NON_CANON_MAX_BYTES
673 };
674
675 let mut return_value = 0;
676 let mut signals = PendingSignals::new();
677 while !buffer.is_empty() && queue.read_buffer.len() < CANON_MAX_BYTES {
678 let size = compute_next_character_size(buffer, &self.termios);
679 let mut character_bytes = buffer[..size].to_vec();
680 if let Some(signal) = self.handle_signals(character_bytes[0]) {
682 signals.add(signal);
683 }
684 match character_bytes[0] {
685 b'\r' => {
686 if self.termios.has_input_flags(IGNCR) {
687 buffer = &buffer[size..];
688 return_value += size;
689 continue;
690 }
691 if self.termios.has_input_flags(ICRNL) {
692 character_bytes[0] = b'\n';
693 }
694 }
695 b'\n' => {
696 if self.termios.has_input_flags(INLCR) {
697 character_bytes[0] = b'\r'
698 }
699 }
700 _ => {}
701 }
702 if self.termios.has_local_flags(ICANON)
705 && queue.read_buffer.len() + size >= max_bytes
706 && !self.termios.is_terminating(&character_bytes)
707 {
708 buffer = &buffer[size..];
709 return_value += size;
710 continue;
711 }
712
713 if queue.read_buffer.len() + size > max_bytes {
714 break;
715 }
716
717 buffer = &buffer[size..];
718 return_value += size;
719
720 let first_byte = character_bytes[0];
721
722 if self.termios.has_local_flags(ICANON) && self.termios.is_eof(first_byte) {
724 queue.readable = true;
725 break;
726 }
727
728 let mut maybe_erase_span = None;
729 let mut erase_type = None;
730 if self.termios.has_local_flags(ICANON) {
731 if self.termios.is_erase(first_byte) {
732 maybe_erase_span =
733 Some(compute_last_character_span(&queue.read_buffer[..], &self.termios));
734 erase_type = Some(EraseType::Character);
735 } else if self.termios.is_werase(first_byte) {
736 maybe_erase_span =
737 Some(compute_last_word_span(&queue.read_buffer[..], &self.termios));
738 erase_type = Some(EraseType::Word);
739 }
740 if self.termios.is_kill(first_byte) {
741 maybe_erase_span =
742 Some(compute_last_line_span(&queue.read_buffer[..], &self.termios));
743 erase_type = Some(EraseType::Line);
744 }
745 }
746
747 if let Some(erase_span) = maybe_erase_span {
748 if erase_span.bytes == 0 {
749 continue;
750 }
751 queue.read_buffer.truncate(queue.read_buffer.len() - erase_span.bytes);
752 } else {
753 queue.read_buffer.extend_from_slice(&character_bytes);
754 }
755
756 if self.termios.has_local_flags(ECHOPRT) {
757 track_stub!(TODO("https://fxbug.dev/322874329"), "terminal ECHOPRT");
758 }
759
760 let mut echo_bytes = vec![];
762 if self.termios.has_local_flags(ECHO) {
763 if let Some(erase_span) = maybe_erase_span {
764 match erase_type {
765 Some(EraseType::Character) | Some(EraseType::Word) => {
766 if self.termios.has_local_flags(ECHOE) {
767 echo_bytes = generate_erase_echo(&erase_span);
768 }
769 }
770 Some(EraseType::Line) => {
771 if self.termios.has_local_flags(ECHOKE) {
772 echo_bytes = generate_erase_echo(&erase_span);
773 } else if self.termios.has_local_flags(ECHOK) {
774 if let Some(control_character_echo) =
775 generate_control_character_echo(first_byte)
776 {
777 echo_bytes = control_character_echo;
778 }
779 echo_bytes.push(b'\n');
780 }
781 }
782 None => {
783 unreachable!("Erase type should be Some when maybe_erase_span is Some")
784 }
785 }
786 }
787 if echo_bytes.is_empty() && self.termios.has_local_flags(ECHOCTL) {
788 if let Some(control_character_echo) =
789 generate_control_character_echo(first_byte)
790 {
791 echo_bytes = control_character_echo;
792 }
793 }
794 if echo_bytes.is_empty() {
795 echo_bytes = character_bytes.clone();
796 }
797 } else if self.termios.has_local_flags(ECHONL) && first_byte == b'\n' {
798 echo_bytes = character_bytes.clone();
801 }
802
803 if !echo_bytes.is_empty() {
804 signals
805 .append(with_queue!(self.output_queue.write_bytes(self.as_mut(), &echo_bytes)));
806 }
807
808 if self.termios.has_local_flags(ICANON) && self.termios.is_terminating(&character_bytes)
810 {
811 queue.readable = true;
812 break;
813 }
814 }
815 if !self.termios.has_local_flags(ICANON) && !queue.read_buffer.is_empty() {
817 queue.readable = true;
818 }
819
820 (return_value, signals)
821 }
822}
823
824impl Drop for Terminal {
825 fn drop(&mut self) {
826 self.state.release_terminal(self.id).unwrap()
827 }
828}
829
830#[derive(Debug)]
833pub struct TerminalController {
834 pub session: Weak<Session>,
835}
836
837impl TerminalController {
838 pub fn new(session: &Arc<Session>) -> Option<Self> {
839 Some(Self { session: Arc::downgrade(&session) })
840 }
841
842 pub fn get_foreground_process_group(&self) -> Option<Arc<ProcessGroup>> {
843 self.session.upgrade().and_then(|session| session.read().get_foreground_process_group())
844 }
845}
846
847trait TermIOS {
849 fn has_input_flags(&self, flags: tcflag_t) -> bool;
850 fn has_output_flags(&self, flags: tcflag_t) -> bool;
851 fn has_local_flags(&self, flags: tcflag_t) -> bool;
852 fn is_eof(&self, c: RawByte) -> bool;
853 fn is_erase(&self, c: RawByte) -> bool;
854 fn is_werase(&self, c: RawByte) -> bool;
855 fn is_kill(&self, c: RawByte) -> bool;
856 fn is_terminating(&self, character_bytes: &[RawByte]) -> bool;
857 fn signal(&self, c: RawByte) -> Option<Signal>;
858}
859
860impl TermIOS for uapi::termios {
861 fn has_input_flags(&self, flags: tcflag_t) -> bool {
862 self.c_iflag & flags == flags
863 }
864 fn has_output_flags(&self, flags: tcflag_t) -> bool {
865 self.c_oflag & flags == flags
866 }
867 fn has_local_flags(&self, flags: tcflag_t) -> bool {
868 self.c_lflag & flags == flags
869 }
870 fn is_eof(&self, c: RawByte) -> bool {
871 c == self.c_cc[VEOF as usize] && self.c_cc[VEOF as usize] != DISABLED_CHAR
872 }
873 fn is_erase(&self, c: RawByte) -> bool {
874 c == self.c_cc[VERASE as usize] && self.c_cc[VERASE as usize] != DISABLED_CHAR
875 }
876 fn is_werase(&self, c: RawByte) -> bool {
877 c == self.c_cc[VWERASE as usize]
878 && self.c_cc[VWERASE as usize] != DISABLED_CHAR
879 && self.has_local_flags(IEXTEN)
880 }
881 fn is_kill(&self, c: RawByte) -> bool {
882 c == self.c_cc[VKILL as usize] && self.c_cc[VKILL as usize] != DISABLED_CHAR
883 }
884 fn is_terminating(&self, character_bytes: &[RawByte]) -> bool {
885 if character_bytes.len() != 1 {
887 return false;
888 }
889 let c = character_bytes[0];
890
891 if self.is_eof(c) {
893 return true;
894 }
895
896 if c == DISABLED_CHAR {
897 return false;
898 }
899 if c == b'\n' || c == self.c_cc[VEOL as usize] {
900 return true;
901 }
902 if c == self.c_cc[VEOL2 as usize] {
903 return self.has_local_flags(IEXTEN);
904 }
905 false
906 }
907 fn signal(&self, c: RawByte) -> Option<Signal> {
908 if c == self.c_cc[VINTR as usize] {
909 return Some(SIGINT);
910 }
911 if c == self.c_cc[VQUIT as usize] {
912 return Some(SIGQUIT);
913 }
914 if c == self.c_cc[VSUSP as usize] {
915 return Some(SIGSTOP);
916 }
917 None
918 }
919}
920
921fn compute_next_character_size(buffer: &[RawByte], termios: &uapi::termios) -> usize {
928 if !termios.has_input_flags(IUTF8) {
929 return 1;
930 }
931
932 #[derive(Default)]
933 struct Receiver {
934 done: Option<bool>,
938 }
939
940 impl utf8parse::Receiver for Receiver {
941 fn codepoint(&mut self, _c: char) {
942 self.done = Some(true);
943 }
944 fn invalid_sequence(&mut self) {
945 self.done = Some(false);
946 }
947 }
948
949 let mut byte_count = 0;
950 let mut receiver = Receiver::default();
951 let mut parser = utf8parse::Parser::new();
952 while receiver.done.is_none() && byte_count < buffer.len() {
953 parser.advance(&mut receiver, buffer[byte_count]);
954 byte_count += 1;
955 }
956 if receiver.done == Some(true) { byte_count } else { 1 }
957}
958
959fn is_ascii(c: RawByte) -> bool {
960 c & 0x80 == 0
961}
962
963fn is_utf8_start(c: RawByte) -> bool {
964 c & 0xC0 == 0xC0
965}
966
967fn generate_erase_echo(erase_span: &BufferSpan) -> Vec<RawByte> {
968 let erase_echo = [BACKSPACE_CHAR, b' ', BACKSPACE_CHAR];
969 erase_echo.iter().cycle().take(erase_echo.len() * erase_span.characters).map(|c| *c).collect()
970}
971
972fn generate_control_character_echo(c: RawByte) -> Option<Vec<RawByte>> {
973 if matches!(c, 0..=0x8 | 0xB..=0xC | 0xE..=0x1F) {
974 Some(vec![b'^', c + CONTROL_OFFSET])
981 } else {
982 None
983 }
984}
985
986#[derive(Default, Debug, Clone, Copy)]
987struct BufferSpan {
988 bytes: usize,
989 characters: usize,
990}
991
992impl std::ops::AddAssign<Self> for BufferSpan {
993 fn add_assign(&mut self, rhs: Self) {
995 self.bytes += rhs.bytes;
996 self.characters += rhs.characters;
997 }
998}
999
1000fn compute_last_character_span(buffer: &[RawByte], termios: &uapi::termios) -> BufferSpan {
1004 if buffer.is_empty() {
1005 return BufferSpan::default();
1006 }
1007 if termios.has_input_flags(IUTF8) {
1008 let mut bytes = 0;
1009 for c in buffer.iter().rev() {
1010 bytes += 1;
1011 if is_ascii(*c) || is_utf8_start(*c) {
1012 return BufferSpan { bytes, characters: 1 };
1013 }
1014 }
1015 BufferSpan::default()
1016 } else {
1017 BufferSpan { bytes: 1, characters: 1 }
1018 }
1019}
1020
1021fn compute_last_word_span(buffer: &[RawByte], termios: &uapi::termios) -> BufferSpan {
1025 fn is_whitespace(c: RawByte) -> bool {
1026 c == b' ' || c == b'\t'
1027 }
1028
1029 let mut in_word = false;
1030 let mut word_span = BufferSpan::default();
1031 let mut remaining = buffer.len();
1032 loop {
1033 let span = compute_last_character_span(&buffer[..remaining], termios);
1034 if span.bytes == 0 {
1035 break;
1036 }
1037 if span.bytes == 1 {
1038 let c = buffer[remaining - 1];
1039 if in_word {
1040 if is_whitespace(c) {
1041 break;
1042 }
1043 } else {
1044 if !is_whitespace(c) {
1045 in_word = true;
1046 }
1047 }
1048 }
1049 remaining -= span.bytes;
1050 word_span += span;
1051 }
1052
1053 word_span
1054}
1055
1056fn compute_last_line_span(buffer: &[RawByte], termios: &uapi::termios) -> BufferSpan {
1060 let mut line_span = BufferSpan::default();
1061 let mut remaining = buffer.len();
1062
1063 loop {
1064 let span = compute_last_character_span(&buffer[..remaining], termios);
1065 if span.bytes == 0 {
1066 break;
1067 }
1068 if span.bytes == 1 {
1069 let c = buffer[remaining - 1];
1070 if c == b'\n' {
1071 break;
1072 }
1073 }
1074 remaining -= span.bytes;
1075 line_span += span;
1076 }
1077
1078 line_span
1079}
1080
1081type RawByte = u8;
1084
1085#[derive(Debug, Default)]
1091pub struct Queue {
1092 read_buffer: Vec<u8>,
1094
1095 wait_buffers: VecDeque<Vec<RawByte>>,
1098
1099 total_wait_buffer_length: usize,
1101
1102 readable: bool,
1105
1106 is_input: bool,
1108}
1109
1110impl Queue {
1111 fn output_queue() -> Option<Self> {
1112 Some(Queue { is_input: false, ..Default::default() })
1113 }
1114
1115 fn input_queue() -> Option<Self> {
1116 Some(Queue { is_input: true, ..Default::default() })
1117 }
1118
1119 fn write_readyness(&self) -> FdEvents {
1121 if self.total_wait_buffer_length < WAIT_BUFFER_MAX_BYTES {
1122 FdEvents::POLLOUT
1123 } else {
1124 FdEvents::empty()
1125 }
1126 }
1127
1128 fn read_readyness(&self) -> FdEvents {
1130 if self.readable { FdEvents::POLLIN } else { FdEvents::empty() }
1131 }
1132
1133 fn readable_size(&self) -> usize {
1135 if self.readable { self.read_buffer.len() } else { 0 }
1136 }
1137
1138 pub fn read(
1140 &mut self,
1141 terminal: TerminalStateMutRef<'_>,
1142 data: &mut dyn OutputBuffer,
1143 ) -> Result<usize, Errno> {
1144 if !self.readable {
1145 return error!(EAGAIN);
1146 }
1147 let max_bytes_to_write = std::cmp::min(self.read_buffer.len(), CANON_MAX_BYTES);
1148 let written_to_userspace = data.write(&self.read_buffer[..max_bytes_to_write])?;
1149 self.read_buffer.drain(0..written_to_userspace);
1150 if self.read_buffer.is_empty() {
1152 self.readable = false;
1153 }
1154
1155 let signals = self.drain_waiting_buffer(terminal);
1156 assert!(signals.signals().is_empty());
1157 Ok(written_to_userspace)
1158 }
1159
1160 pub fn write(
1162 &mut self,
1163 terminal: TerminalStateMutRef<'_>,
1164 data: &mut dyn InputBuffer,
1165 ) -> Result<(usize, PendingSignals), Errno> {
1166 let room = WAIT_BUFFER_MAX_BYTES - self.total_wait_buffer_length;
1167 let data_length = data.available();
1168 if room == 0 && data_length > 0 {
1169 return error!(EAGAIN);
1170 }
1171 let buffer = data.read_to_vec_exact(std::cmp::min(room, data_length))?;
1172 let read_from_userspace = buffer.len();
1173 let signals = self.push_to_waiting_buffer(terminal, buffer);
1174 Ok((read_from_userspace, signals))
1175 }
1176
1177 fn write_bytes(
1179 &mut self,
1180 terminal: TerminalStateMutRef<'_>,
1181 buffer: &[RawByte],
1182 ) -> PendingSignals {
1183 self.push_to_waiting_buffer(terminal, buffer.to_vec())
1184 }
1185
1186 fn push_to_waiting_buffer(
1188 &mut self,
1189 terminal: TerminalStateMutRef<'_>,
1190 buffer: Vec<RawByte>,
1191 ) -> PendingSignals {
1192 self.total_wait_buffer_length += buffer.len();
1193 self.wait_buffers.push_back(buffer);
1194 self.drain_waiting_buffer(terminal)
1195 }
1196
1197 fn drain_waiting_buffer(&mut self, mut terminal: TerminalStateMutRef<'_>) -> PendingSignals {
1199 let mut total = 0;
1200 let mut signals_to_return = PendingSignals::new();
1201 while let Some(wait_buffer) = self.wait_buffers.pop_front() {
1202 let (count, signals) = terminal.transform(self.is_input, self, &wait_buffer);
1203 total += count;
1204 signals_to_return.append(signals);
1205 if count != wait_buffer.len() {
1206 self.wait_buffers.push_front(wait_buffer[count..].to_vec());
1207 break;
1208 }
1209 }
1210 self.total_wait_buffer_length -= total;
1211 signals_to_return
1212 }
1213
1214 fn on_canon_disabled(&mut self, terminal: TerminalStateMutRef<'_>) -> PendingSignals {
1216 let signals = self.drain_waiting_buffer(terminal);
1217 if !self.read_buffer.is_empty() {
1218 self.readable = true;
1219 }
1220 signals
1221 }
1222}
1223
1224fn get_ascii(c: char) -> u8 {
1227 let mut dest: [u8; 1] = [0];
1228 c.encode_utf8(&mut dest);
1229 dest[0]
1230}
1231
1232fn get_control_character(c: char) -> cc_t {
1234 get_ascii(c) - get_ascii('A') + 1
1235}
1236
1237fn get_default_control_characters() -> [cc_t; 19usize] {
1239 [
1240 get_control_character('C'), get_control_character('\\'), get_ascii('\x7f'), get_control_character('U'), get_control_character('D'), 0, 1, 0, get_control_character('Q'), get_control_character('S'), get_control_character('Z'), 0, get_control_character('R'), get_control_character('O'), get_control_character('W'), get_control_character('V'), 0, 0, 0, ]
1260}
1261
1262fn get_default_termios() -> uapi::termios {
1264 uapi::termios {
1265 c_iflag: uapi::ICRNL | uapi::IXON,
1266 c_oflag: uapi::OPOST | uapi::ONLCR,
1267 c_cflag: uapi::B38400 | uapi::CS8 | uapi::CREAD,
1268 c_lflag: uapi::ISIG
1269 | uapi::ICANON
1270 | uapi::ECHO
1271 | uapi::ECHOE
1272 | uapi::ECHOK
1273 | uapi::ECHOCTL
1274 | uapi::ECHOKE
1275 | uapi::IEXTEN,
1276 c_line: 0,
1277 c_cc: get_default_control_characters(),
1278 }
1279}
1280
1281#[derive(Debug)]
1282struct PtsIdsSet {
1283 pts_count: u32,
1284 next_id: u32,
1285 reclaimed_ids: BTreeSet<u32>,
1286}
1287
1288impl PtsIdsSet {
1289 fn new(pts_count: u32) -> Self {
1290 Self { pts_count, next_id: 0, reclaimed_ids: BTreeSet::new() }
1291 }
1292
1293 fn release(&mut self, id: u32) {
1294 assert!(self.reclaimed_ids.insert(id))
1295 }
1296
1297 fn acquire(&mut self) -> Result<u32, Errno> {
1298 match self.reclaimed_ids.iter().next() {
1299 Some(e) => {
1300 let value = *e;
1301 self.reclaimed_ids.remove(&value);
1302 Ok(value)
1303 }
1304 None => {
1305 if self.next_id < self.pts_count {
1306 let id = self.next_id;
1307 self.next_id += 1;
1308 Ok(id)
1309 } else {
1310 error!(ENOSPC)
1311 }
1312 }
1313 }
1314 }
1315}
1316
1317#[cfg(test)]
1318mod tests {
1319 use super::*;
1320
1321 #[::fuchsia::test]
1322 fn test_ascii_conversion() {
1323 assert_eq!(get_ascii(' '), 32);
1324 }
1325
1326 #[::fuchsia::test]
1327 fn test_control_character() {
1328 assert_eq!(get_control_character('C'), 3);
1329 }
1330
1331 #[::fuchsia::test]
1332 #[should_panic]
1333 fn test_invalid_ascii_conversion() {
1334 get_ascii('é');
1335 }
1336
1337 #[::fuchsia::test]
1338 fn test_compute_next_character_size_non_utf8() {
1339 let termios = get_default_termios();
1340 for i in 0..=255 {
1341 let array: &[u8] = &[i, 0xa9, 0];
1342 assert_eq!(compute_next_character_size(array, &termios), 1);
1343 }
1344 }
1345
1346 #[::fuchsia::test]
1347 fn test_compute_next_character_size_utf8() {
1348 let mut termios = get_default_termios();
1349 termios.c_iflag |= IUTF8;
1350 for i in 0..128 {
1351 let array: &[RawByte] = &[i, 0xa9, 0];
1352 assert_eq!(compute_next_character_size(array, &termios), 1);
1353 }
1354 let array: &[RawByte] = &[0xc2, 0xa9, 0];
1355 assert_eq!(compute_next_character_size(array, &termios), 2);
1356 let array: &[RawByte] = &[0xc2, 255, 0];
1357 assert_eq!(compute_next_character_size(array, &termios), 1);
1358 }
1359}