starnix_core/device/
terminal.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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
27// CANON_MAX_BYTES is the number of bytes that fit into a single line of
28// terminal input in canonical mode. See https://github.com/google/gvisor/blob/master/pkg/sentry/fs/tty/line_discipline.go
29const CANON_MAX_BYTES: usize = 4096;
30
31// NON_CANON_MAX_BYTES is the maximum number of bytes that can be read at
32// a time in non canonical mode.
33const NON_CANON_MAX_BYTES: usize = CANON_MAX_BYTES - 1;
34
35// WAIT_BUFFER_MAX_BYTES is the maximum size of a wait buffer. It is based on
36// https://github.com/google/gvisor/blob/master/pkg/sentry/fsimpl/devpts/queue.go
37const WAIT_BUFFER_MAX_BYTES: usize = 131072;
38
39const SPACES_PER_TAB: usize = 8;
40
41// DISABLED_CHAR is used to indicate that a control character is disabled.
42const DISABLED_CHAR: u8 = 0;
43
44const BACKSPACE_CHAR: u8 = 8; // \b
45
46/// The offset in ASCII between a control character and it's character name.
47/// For example, typing CTRL-C on a keyboard generates the value
48/// b'C' - CONTROL_OFFSET
49const CONTROL_OFFSET: u8 = 0x40;
50
51/// Global state of the devpts filesystem.
52pub struct TtyState {
53    /// The terminal objects indexed by their identifier.
54    pub terminals: RwLock<HashMap<u32, Weak<Terminal>>>,
55
56    /// The set of available terminal identifier.
57    pts_ids_set: Mutex<PtsIdsSet>,
58}
59
60impl TtyState {
61    /// Returns the next available terminal.
62    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    /// Release the terminal identifier into the set of available identifier.
74    pub fn release_terminal(&self, id: u32) -> Result<(), Errno> {
75        // We need to remove this terminal id from the set of terminals before we release the
76        // identifier. Otherwise, the id might be reused for a new terminal and we'll remove
77        // the *new* terminal with that identifier instead of the old one.
78        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    /// |true| is the terminal is locked.
98    #[derivative(Default(value = "true"))]
99    pub locked: bool,
100
101    /// Terminal size.
102    pub window_size: uapi::winsize,
103
104    /// Terminal configuration.
105    #[derivative(Default(value = "get_default_termios()"))]
106    termios: uapi::termios,
107
108    /// Location in a row of the cursor. Needed to handle certain special characters like
109    /// backspace.
110    column: usize,
111
112    /// The number of active references to the main part of the terminal. Starts as `None`. The
113    /// main part of the terminal is considered closed when this is `Some(0)`.
114    main_references: Option<u32>,
115
116    /// The number of active references to the replica part of the terminal. Starts as `None`. The
117    /// replica part of the terminal is considered closed when this is `Some(0)`.
118    replica_references: Option<u32>,
119
120    /// Input queue of the terminal. Data flow from the main side to the replica side.
121    ///
122    /// This option is never empty in the steady state of the terminal. Mutating methods on Queue
123    /// need a mutable borrow of this object. As rust borrow checker prevents multiple mutable
124    /// borrows, the queue is instead moved to the stack, the mutating method is called and the
125    /// queue is moved back to this object. This is safe because:
126    /// - Moving the queue to the stack requires a write lock on the terminal, which ensure
127    /// exclusive access to this object, so no other thread will try to access the queue.
128    /// - The methods on the queue that calls back to this object won't try to access the same
129    /// queue.
130    #[derivative(Default(value = "Queue::input_queue()"))]
131    input_queue: Option<Queue>,
132    /// Output queue of the terminal. Data flow from the replica side to the main side.
133    ///
134    /// This option is never empty in the steady state of the terminal. Mutating methods on Queue
135    /// need a mutable borrow of this object. As rust borrow checker prevents multiple mutable
136    /// borrows, the queue is instead moved to the stack, the mutating method is called and the
137    /// queue is moved back to this object. This is safe because:
138    /// - Moving the queue to the stack requires a write lock on the terminal, which ensure
139    /// exclusive access to this object, so no other thread will try to access the queue.
140    /// - The methods on the queue that calls back to this object won't try to access the same
141    /// queue.
142    #[derivative(Default(value = "Queue::output_queue()"))]
143    output_queue: Option<Queue>,
144
145    /// Wait queue for the main side of the terminal.
146    main_wait_queue: WaitQueue,
147
148    /// Wait queue for the replica side of the terminal.
149    replica_wait_queue: WaitQueue,
150
151    /// The controller for the terminal.
152    pub controller: Option<TerminalController>,
153}
154
155/// State of a given terminal. This object handles both the main and the replica terminal.
156#[derive(Derivative)]
157#[derivative(Debug)]
158pub struct Terminal {
159    /// Weak self to allow cloning.
160    weak_self: Weak<Self>,
161
162    /// The global devpts state.
163    #[derivative(Debug = "ignore")]
164    state: Arc<TtyState>,
165
166    /// The root of the devpts fs responsible for this terminal.
167    pub dev_pts_root: DirEntryHandle,
168
169    /// The owner of the terminal.
170    pub fscred: FsCred,
171
172    /// The identifier of the terminal.
173    pub id: u32,
174
175    /// The mutable state of the Terminal.
176    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    /// Sets the terminal configuration.
201    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    /// `close` implementation of the main side of the terminal.
210    pub fn main_close(&self) {
211        // Remove the entry in the file system.
212        let id = FsString::from(self.id.to_string());
213        // The child is not a directory, the mount doesn't matter.
214        self.dev_pts_root.remove_child(id.as_ref(), &Mounts::new());
215        self.write().main_close();
216    }
217
218    /// Called when a new reference to the main side of this terminal is made.
219    pub fn main_open(&self) {
220        self.write().main_open();
221    }
222
223    /// `wait_async` implementation of the main side of the terminal.
224    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    /// `query_events` implementation of the main side of the terminal.
234    pub fn main_query_events(&self) -> FdEvents {
235        self.read().main_query_events()
236    }
237
238    /// `read` implementation of the main side of the terminal.
239    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    /// `write` implementation of the main side of the terminal.
251    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    /// `close` implementation of the replica side of the terminal.
265    pub fn replica_close(&self) {
266        self.write().replica_close();
267    }
268
269    /// Called when a new reference to the replica side of this terminal is made.
270    pub fn replica_open(&self) {
271        self.write().replica_open();
272    }
273
274    /// `wait_async` implementation of the replica side of the terminal.
275    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    /// `query_events` implementation of the replica side of the terminal.
285    pub fn replica_query_events(&self) -> FdEvents {
286        self.read().replica_query_events()
287    }
288
289    /// `read` implementation of the replica side of the terminal.
290    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    /// `write` implementation of the replica side of the terminal.
302    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    /// Send the pending signals to the associated foreground process groups if they exist.
314    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
344/// Macro to help working with the terminal queues. This macro will handle moving the queue to the
345/// stack, calling the method on it, moving it back to the terminal and returning the result.
346///
347/// See the comments on `input_queue` and `output_queue` for the reason.
348///
349/// This expect to be called with a single method call to either the input or output queue, on
350/// self. Example:
351/// ```
352/// let bytes = with_queue!(self.output_queue.read(self, current_task, data))?;
353/// ```
354macro_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/// Keep track of the signals to send when handling terminal content.
366#[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    /// Add the given signal to the list of signal to send to the associate process group.
377    fn add(&mut self, signal: Signal) {
378        self.signals.push(signal);
379    }
380
381    /// Append all pending signals in `other` to `self`.
382    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/// Represents the type of erase operation that can be performed on terminal input.
392#[derive(Debug, PartialEq)]
393enum EraseType {
394    /// Erase a single character (typically triggered by backspace)
395    Character,
396    /// Erase a word (typically triggered by Ctrl+W)
397    Word,
398    /// Erase the entire line (typically triggered by Ctrl+U)
399    Line,
400}
401
402#[apply(state_implementation!)]
403impl TerminalMutableState<Base = Terminal> {
404    /// Returns the terminal configuration.
405    pub fn termios(&self) -> &uapi::termios {
406        &self.termios
407    }
408
409    /// Returns the number of available bytes to read from the side of the terminal described by
410    /// `is_main`.
411    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    /// Sets the terminal configuration.
417    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    /// `close` implementation of the main side of the terminal.
430    pub fn main_close(&mut self) {
431        self.main_references = self.main_references.map(|v| v - 1);
432        self.notify_waiters();
433    }
434
435    /// Called when a new reference to the main side of this terminal is made.
436    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    /// `wait_async` implementation of the main side of the terminal.
445    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    /// `query_events` implementation of the main side of the terminal.
455    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    /// `read` implementation of the main side of the terminal.
463    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    /// `write` implementation of the main side of the terminal.
473    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    /// `close` implementation of the replica side of the terminal.
480    pub fn replica_close(&mut self) {
481        self.replica_references = self.replica_references.map(|v| v - 1);
482        self.notify_waiters();
483    }
484
485    /// Called when a new reference to the replica side of this terminal is made.
486    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    /// `wait_async` implementation of the replica side of the terminal.
495    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    /// `query_events` implementation of the replica side of the terminal.
505    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    /// `read` implementation of the replica side of the terminal.
513    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    /// `write` implementation of the replica side of the terminal.
523    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    /// Returns the input_queue. The Option is always filled, see `input_queue` description.
535    fn input_queue(&self) -> &Queue {
536        self.input_queue.as_ref().unwrap()
537    }
538
539    /// Returns the output_queue. The Option is always filled, see `output_queue` description.
540    fn output_queue(&self) -> &Queue {
541        self.output_queue.as_ref().unwrap()
542    }
543
544    /// Notify any waiters if the state of the terminal changes.
545    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    /// Return whether a signal must be send when receiving `byte`, and if yes, which.
557    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    /// Transform the given `buffer` according to the terminal configuration and append it to the
565    /// read buffer of the `queue`. The given queue is the input or output queue depending on
566    /// `is_input`. The transformation method might update the other queue, but in the case, it is
567    /// guaranteed that it won't have to update the initial one recursively. The transformation
568    /// might also update the state of the terminal.
569    ///
570    /// Returns the number of bytes extracted from the queue, as well as the pending signals
571    /// following the handling of the buffer.
572    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    /// Transformation method for the output queue. See `transform`.
586    fn transform_output(&mut self, queue: &mut Queue, original_buffer: &[RawByte]) -> usize {
587        let mut buffer = original_buffer;
588
589        // transform_output is effectively always in noncanonical mode, as the
590        // main termios never has ICANON set.
591
592        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    /// Transformation method for the input queue. See `transform`.
656    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 there's a line waiting to be read in canonical mode, don't write
664        // anything else to the read buffer.
665        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            // It is guaranteed that character_bytes has at least one element.
681            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            // In canonical mode, we discard non-terminating characters
703            // after the first 4095.
704            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 we get EOF, make the buffer available for reading.
723            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            // Anything written to the read buffer will have to be echoed.
761            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                // If this bit is set and the ICANON bit is also set, then the
799                // newline ('\n') character is echoed even if the ECHO bit is not set.
800                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 we finish a line, make it available for reading.
809            if self.termios.has_local_flags(ICANON) && self.termios.is_terminating(&character_bytes)
810            {
811                queue.readable = true;
812                break;
813            }
814        }
815        // In noncanonical mode, everything is readable.
816        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/// The controlling session of a terminal. Is is associated to a single side of the terminal,
831/// either main or replica.
832#[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
847/// Helper trait for termios to help parse the configuration.
848trait 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        // All terminating characters are 1 byte.
886        if character_bytes.len() != 1 {
887            return false;
888        }
889        let c = character_bytes[0];
890
891        // Is this the user-set EOF character?
892        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
921/// Returns the number of bytes of the next character in `buffer`.
922///
923/// Depending on `termios`, this might consider ASCII or UTF8 encoding.
924///
925/// This will return 1 if the encoding is UTF8 and the first bytes of buffer are not a valid utf8
926/// sequence.
927fn 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        /// Whether the first codepoint has been decoded. Contains `None` until either the first
935        /// character has been decoded, or until the sequence is considered invalid. When not None,
936        /// it contains `true` if a character has been correctly decoded.
937        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        // If this bit is set and the ECHO bit is also set, echo
975        // control characters with ‘^’ followed by the corresponding
976        // text character. Thus, control-A echoes as ‘^A’. This is
977        // usually the preferred mode for interactive input, because
978        // echoing a control character back to the terminal could have
979        // some undesired effect on the terminal.
980        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    // Required method
994    fn add_assign(&mut self, rhs: Self) {
995        self.bytes += rhs.bytes;
996        self.characters += rhs.characters;
997    }
998}
999
1000/// Returns size of the last character in `buffer`.
1001///
1002/// Depending on `termios`, this might consider ASCII or UTF8 encoding.
1003fn 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
1021/// Returns size of the last word in `buffer`.
1022///
1023/// Depending on `termios`, this might consider ASCII or UTF8 encoding.
1024fn 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
1056/// Returns size of the last line in `buffer`.
1057///
1058/// Depending on `termios`, this might consider ASCII or UTF8 encoding.
1059fn 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
1081/// Alias used to mark bytes in the queues that have not yet been processed and pushed into the
1082/// read buffer. See `Queue`.
1083type RawByte = u8;
1084
1085/// Queue represents one of the input or output queues between a pty main and replica. Bytes
1086/// written to a queue are added to the read buffer until it is full, at which point they are
1087/// written to the wait buffer. Bytes are processed (i.e. undergo termios transformations) as they
1088/// are added to the read buffer. The read buffer is readable when its length is nonzero and
1089/// readable is true.
1090#[derive(Debug, Default)]
1091pub struct Queue {
1092    /// The buffer of data ready to be read when readable is true. This data has been processed.
1093    read_buffer: Vec<u8>,
1094
1095    /// Data that can't fit into readBuf. It is put here until it can be loaded into the read
1096    /// buffer. Contains data that hasn't been processed.
1097    wait_buffers: VecDeque<Vec<RawByte>>,
1098
1099    /// The length of the data in `wait_buffers`.
1100    total_wait_buffer_length: usize,
1101
1102    /// Whether the read buffer can be read from. In canonical mode, there can be an unterminated
1103    /// line in the read buffer, so readable must be checked.
1104    readable: bool,
1105
1106    /// Whether this queue in the input queue. Needed to know how to transform received data.
1107    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    /// Returns whether the queue is ready to be written to.
1120    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    /// Returns whether the queue is ready to be read from.
1129    fn read_readyness(&self) -> FdEvents {
1130        if self.readable { FdEvents::POLLIN } else { FdEvents::empty() }
1131    }
1132
1133    /// Returns the number of bytes ready to be read.
1134    fn readable_size(&self) -> usize {
1135        if self.readable { self.read_buffer.len() } else { 0 }
1136    }
1137
1138    /// Read from the queue into `data`. Returns the number of bytes copied.
1139    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 everything has been read, this queue is no longer readable.
1151        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    /// Writes to the queue from `data`. Returns the number of bytes copied.
1161    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    /// Writes the given `buffer` to the queue.
1178    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    /// Pushes the given buffer into the wait_buffers, and process the wait_buffers.
1187    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    /// Processes the wait_buffers, filling the read buffer.
1198    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    /// Called when the queue is moved from canonical mode, to non canonical mode.
1215    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
1224// Returns the ASCII representation of the given char. This will assert if the character is not
1225// ascii.
1226fn get_ascii(c: char) -> u8 {
1227    let mut dest: [u8; 1] = [0];
1228    c.encode_utf8(&mut dest);
1229    dest[0]
1230}
1231
1232// Returns the control character associated with the given letter.
1233fn get_control_character(c: char) -> cc_t {
1234    get_ascii(c) - get_ascii('A') + 1
1235}
1236
1237// Returns the default control characters of a terminal.
1238fn get_default_control_characters() -> [cc_t; 19usize] {
1239    [
1240        get_control_character('C'),  // VINTR = ^C
1241        get_control_character('\\'), // VQUIT = ^\
1242        get_ascii('\x7f'),           // VERASE = DEL
1243        get_control_character('U'),  // VKILL = ^U
1244        get_control_character('D'),  // VEOF = ^D
1245        0,                           // VTIME
1246        1,                           // VMIN
1247        0,                           // VSWTC
1248        get_control_character('Q'),  // VSTART = ^Q
1249        get_control_character('S'),  // VSTOP = ^S
1250        get_control_character('Z'),  // VSUSP = ^Z
1251        0,                           // VEOL
1252        get_control_character('R'),  // VREPRINT = ^R
1253        get_control_character('O'),  // VDISCARD = ^O
1254        get_control_character('W'),  // VWERASE = ^W
1255        get_control_character('V'),  // VLNEXT = ^V
1256        0,                           // VEOL2
1257        0,                           // Remaining data in the array,
1258        0,                           // Remaining data in the array,
1259    ]
1260}
1261
1262// Returns the default replica terminal configuration.
1263fn 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}