Skip to main content

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;
12
13use line_discipline::{LineDiscipline, PendingSignals};
14use starnix_sync::{
15    DeviceTerminalsLock, LockBefore, LockDepMutex, LockDepRwLock, Locked, ProcessGroupState,
16    PtsIdsSetLock,
17};
18use starnix_uapi::auth::FsCred;
19use starnix_uapi::device_id::DeviceId;
20use starnix_uapi::errors::Errno;
21use starnix_uapi::vfs::FdEvents;
22use starnix_uapi::{error, uapi};
23use std::collections::{BTreeSet, HashMap};
24use std::sync::{Arc, Weak};
25
26/// Global state of the devpts filesystem.
27pub struct TtyState {
28    /// The terminal objects indexed by their identifier.
29    pub terminals: LockDepRwLock<HashMap<u32, Weak<Terminal>>, DeviceTerminalsLock>,
30
31    /// The set of available terminal identifier.
32    pts_ids_set: LockDepMutex<PtsIdsSet, PtsIdsSetLock>,
33}
34
35impl TtyState {
36    /// Returns the next available terminal.
37    pub fn get_next_terminal(
38        self: &Arc<Self>,
39        dev_pts_root: DirEntryHandle,
40        creds: FsCred,
41    ) -> Result<Arc<Terminal>, Errno> {
42        let id = self.pts_ids_set.lock().acquire()?;
43        let terminal = Terminal::new(self.clone(), dev_pts_root, creds, id);
44        assert!(self.terminals.write().insert(id, Arc::downgrade(&terminal)).is_none());
45        Ok(terminal)
46    }
47
48    /// Release the terminal identifier into the set of available identifier.
49    pub fn release_terminal(&self, id: u32) -> Result<(), Errno> {
50        // We need to remove this terminal id from the set of terminals before we release the
51        // identifier. Otherwise, the id might be reused for a new terminal and we'll remove
52        // the *new* terminal with that identifier instead of the old one.
53        assert!(self.terminals.write().remove(&id).is_some());
54        self.pts_ids_set.lock().release(id);
55        Ok(())
56    }
57}
58
59impl Default for TtyState {
60    fn default() -> Self {
61        Self { terminals: Default::default(), pts_ids_set: PtsIdsSet::new(DEVPTS_COUNT).into() }
62    }
63}
64
65#[derive(Derivative)]
66#[derivative(Default)]
67#[derivative(Debug)]
68pub struct TerminalMutableState {
69    pub line_discipline: LineDiscipline,
70
71    /// Wait queue for the main side of the terminal.
72    main_wait_queue: WaitQueue,
73
74    /// Wait queue for the replica side of the terminal.
75    replica_wait_queue: WaitQueue,
76
77    /// The controller for the terminal.
78    pub controller: Option<TerminalController>,
79}
80
81/// State of a given terminal. This object handles both the main and the replica terminal.
82#[derive(Derivative)]
83#[derivative(Debug)]
84pub struct Terminal {
85    /// Weak self to allow cloning.
86    weak_self: Weak<Self>,
87
88    /// The global devpts state.
89    #[derivative(Debug = "ignore")]
90    state: Arc<TtyState>,
91
92    /// The root of the devpts fs responsible for this terminal.
93    pub dev_pts_root: DirEntryHandle,
94
95    /// The owner of the terminal.
96    pub fscred: FsCred,
97
98    /// The identifier of the terminal.
99    pub id: u32,
100
101    /// The mutable state of the Terminal.
102    mutable_state:
103        starnix_sync::LockDepRwLock<TerminalMutableState, starnix_sync::TerminalMutableStateLock>,
104}
105
106impl Terminal {
107    pub fn new(
108        state: Arc<TtyState>,
109        dev_pts_root: DirEntryHandle,
110        fscred: FsCred,
111        id: u32,
112    ) -> Arc<Self> {
113        Arc::new_cyclic(|weak_self| Self {
114            weak_self: weak_self.clone(),
115            state,
116            dev_pts_root,
117            fscred,
118            id,
119            mutable_state: Default::default(),
120        })
121    }
122
123    pub fn to_owned(&self) -> Arc<Terminal> {
124        self.weak_self.upgrade().expect("This should never be called while releasing the terminal")
125    }
126
127    /// Sets the terminal configuration.
128    pub fn set_termios<L>(&self, locked: &mut Locked<L>, termios: uapi::termios2)
129    where
130        L: LockBefore<ProcessGroupState>,
131    {
132        let signals = self.write().set_termios(termios);
133        self.send_signals(locked, signals);
134    }
135
136    pub fn flush(&self, is_main: bool, arg: u32) -> Result<(), Errno> {
137        self.write().flush(is_main, arg)
138    }
139
140    /// `close` implementation of the main side of the terminal.
141    pub fn main_close(&self) {
142        // Remove the entry in the file system.
143        let id = FsString::from(self.id.to_string());
144        // The child is not a directory, the mount doesn't matter.
145        self.dev_pts_root.remove_child(id.as_ref(), &Mounts::new());
146        self.write().main_close();
147    }
148
149    /// Called when a new reference to the main side of this terminal is made.
150    pub fn main_open(&self) {
151        self.write().main_open();
152    }
153
154    /// `wait_async` implementation of the main side of the terminal.
155    pub fn main_wait_async(
156        &self,
157        waiter: &Waiter,
158        events: FdEvents,
159        handler: EventHandler,
160    ) -> WaitCanceler {
161        self.read().main_wait_async(waiter, events, handler)
162    }
163
164    /// `query_events` implementation of the main side of the terminal.
165    pub fn main_query_events(&self) -> FdEvents {
166        self.read().main_query_events()
167    }
168
169    /// `read` implementation of the main side of the terminal.
170    pub fn main_read<L>(
171        &self,
172        _locked: &mut Locked<L>,
173        data: &mut dyn OutputBuffer,
174    ) -> Result<usize, Errno>
175    where
176        L: LockBefore<ProcessGroupState>,
177    {
178        self.write().main_read(data)
179    }
180
181    /// `write` implementation of the main side of the terminal.
182    pub fn main_write<L>(
183        &self,
184        locked: &mut Locked<L>,
185        data: &mut dyn InputBuffer,
186    ) -> Result<usize, Errno>
187    where
188        L: LockBefore<ProcessGroupState>,
189    {
190        let (bytes, signals) = self.write().main_write(data)?;
191        self.send_signals(locked, signals);
192        Ok(bytes)
193    }
194
195    /// `close` implementation of the replica side of the terminal.
196    pub fn replica_close(&self) {
197        self.write().replica_close();
198    }
199
200    /// Called when a new reference to the replica side of this terminal is made.
201    pub fn replica_open(&self) {
202        self.write().replica_open();
203    }
204
205    /// `wait_async` implementation of the replica side of the terminal.
206    pub fn replica_wait_async(
207        &self,
208        waiter: &Waiter,
209        events: FdEvents,
210        handler: EventHandler,
211    ) -> WaitCanceler {
212        self.read().replica_wait_async(waiter, events, handler)
213    }
214
215    /// `query_events` implementation of the replica side of the terminal.
216    pub fn replica_query_events(&self) -> FdEvents {
217        self.read().replica_query_events()
218    }
219
220    /// `read` implementation of the replica side of the terminal.
221    pub fn replica_read<L>(
222        &self,
223        _locked: &mut Locked<L>,
224        data: &mut dyn OutputBuffer,
225    ) -> Result<usize, Errno>
226    where
227        L: LockBefore<ProcessGroupState>,
228    {
229        self.write().replica_read(data)
230    }
231
232    /// `write` implementation of the replica side of the terminal.
233    pub fn replica_write<L>(
234        &self,
235        _locked: &mut Locked<L>,
236        data: &mut dyn InputBuffer,
237    ) -> Result<usize, Errno>
238    where
239        L: LockBefore<ProcessGroupState>,
240    {
241        self.write().replica_write(data)
242    }
243
244    /// Send the pending signals to the associated foreground process groups if they exist.
245    fn send_signals<L>(&self, locked: &mut Locked<L>, signals: PendingSignals)
246    where
247        L: LockBefore<ProcessGroupState>,
248    {
249        let signals = signals.signals();
250        if !signals.is_empty() {
251            let process_group = {
252                let terminal_state = self.read();
253                let Some(controller) = terminal_state.controller.as_ref() else {
254                    return;
255                };
256                let Some(session) = controller.session.upgrade() else {
257                    return;
258                };
259                let Some(process_group) = session.read().get_foreground_process_group() else {
260                    return;
261                };
262                process_group
263            };
264            process_group.send_signals(locked, signals);
265        }
266    }
267
268    pub fn device(&self) -> DeviceId {
269        get_device_type_for_pts(self.id)
270    }
271
272    state_accessor!(Terminal, mutable_state);
273}
274
275struct InputBufferWrapper<'a>(&'a mut dyn crate::vfs::buffers::InputBuffer);
276
277impl<'a> line_discipline::InputBuffer for InputBufferWrapper<'a> {
278    fn available(&self) -> usize {
279        self.0.available()
280    }
281    fn read_to_vec_exact(&mut self, size: usize) -> Result<Vec<u8>, Errno> {
282        self.0.read_to_vec_exact(size)
283    }
284}
285
286struct OutputBufferWrapper<'a>(&'a mut dyn crate::vfs::buffers::OutputBuffer);
287
288impl<'a> line_discipline::OutputBuffer for OutputBufferWrapper<'a> {
289    fn write(&mut self, data: &[u8]) -> Result<usize, Errno> {
290        self.0.write(data)
291    }
292}
293
294#[apply(state_implementation!)]
295impl TerminalMutableState<Base = Terminal> {
296    /// Returns the terminal configuration.
297    pub fn termios(&self) -> &uapi::termios2 {
298        self.line_discipline.termios()
299    }
300
301    pub fn set_packet_mode(&mut self, enabled: bool) {
302        if enabled != self.line_discipline.is_packet_mode_enabled() {
303            self.line_discipline.set_packet_mode(enabled);
304            self.notify_waiters();
305        }
306    }
307
308    /// Returns the number of available bytes to read from the side of the terminal described by
309    /// `is_main`.
310    pub fn get_available_read_size(&self, is_main: bool) -> usize {
311        self.line_discipline.get_available_read_size(is_main)
312    }
313
314    /// Sets the terminal configuration.
315    fn set_termios(&mut self, termios: uapi::termios2) -> PendingSignals {
316        let old_canon_enabled = self.line_discipline.is_canon_enabled();
317        let signals = self.line_discipline.set_termios(termios);
318        let canon_disabled = old_canon_enabled && !self.line_discipline.is_canon_enabled();
319        if canon_disabled || self.line_discipline.has_packet_mode_pending_events() {
320            self.notify_waiters();
321        }
322        signals
323    }
324
325    pub fn flush(&mut self, is_main: bool, arg: u32) -> Result<(), Errno> {
326        self.line_discipline.flush(is_main, arg)?;
327        self.main_wait_queue
328            .notify_fd_events(FdEvents::POLLIN | FdEvents::POLLOUT | FdEvents::POLLHUP);
329        self.replica_wait_queue
330            .notify_fd_events(FdEvents::POLLIN | FdEvents::POLLOUT | FdEvents::POLLHUP);
331        Ok(())
332    }
333
334    /// `close` implementation of the main side of the terminal.
335    pub fn main_close(&mut self) {
336        self.line_discipline.main_close();
337        self.notify_waiters();
338    }
339
340    /// Called when a new reference to the main side of this terminal is made.
341    pub fn main_open(&mut self) {
342        self.line_discipline.main_open();
343    }
344
345    pub fn is_main_closed(&self) -> bool {
346        self.line_discipline.is_main_closed()
347    }
348
349    /// `wait_async` implementation of the main side of the terminal.
350    fn main_wait_async(
351        &self,
352        waiter: &Waiter,
353        events: FdEvents,
354        handler: EventHandler,
355    ) -> WaitCanceler {
356        self.main_wait_queue.wait_async_fd_events(waiter, events, handler)
357    }
358
359    /// `query_events` implementation of the main side of the terminal.
360    fn main_query_events(&self) -> FdEvents {
361        self.line_discipline.main_query_events()
362    }
363
364    /// `read` implementation of the main side of the terminal.
365    fn main_read(&mut self, data: &mut dyn OutputBuffer) -> Result<usize, Errno> {
366        let mut wrapper = OutputBufferWrapper(data);
367        let result = self.line_discipline.main_read(&mut wrapper)?;
368        self.notify_waiters();
369        Ok(result)
370    }
371
372    /// `write` implementation of the main side of the terminal.
373    fn main_write(&mut self, data: &mut dyn InputBuffer) -> Result<(usize, PendingSignals), Errno> {
374        let mut wrapper = InputBufferWrapper(data);
375        let (result, signals) = self.line_discipline.main_write(&mut wrapper)?;
376        self.notify_waiters();
377        Ok((result, signals))
378    }
379
380    /// `close` implementation of the replica side of the terminal.
381    pub fn replica_close(&mut self) {
382        self.line_discipline.replica_close();
383        self.notify_waiters();
384    }
385
386    /// Called when a new reference to the replica side of this terminal is made.
387    pub fn replica_open(&mut self) {
388        self.line_discipline.replica_open();
389    }
390
391    /// `wait_async` implementation of the replica side of the terminal.
392    fn replica_wait_async(
393        &self,
394        waiter: &Waiter,
395        events: FdEvents,
396        handler: EventHandler,
397    ) -> WaitCanceler {
398        self.replica_wait_queue.wait_async_fd_events(waiter, events, handler)
399    }
400
401    /// `query_events` implementation of the replica side of the terminal.
402    fn replica_query_events(&self) -> FdEvents {
403        self.line_discipline.replica_query_events()
404    }
405
406    /// `read` implementation of the replica side of the terminal.
407    fn replica_read(&mut self, data: &mut dyn OutputBuffer) -> Result<usize, Errno> {
408        let mut wrapper = OutputBufferWrapper(data);
409        let result = self.line_discipline.replica_read(&mut wrapper)?;
410        self.notify_waiters();
411        Ok(result)
412    }
413
414    /// `write` implementation of the replica side of the terminal.
415    fn replica_write(&mut self, data: &mut dyn InputBuffer) -> Result<usize, Errno> {
416        let mut wrapper = InputBufferWrapper(data);
417        let result = self.line_discipline.replica_write(&mut wrapper)?;
418        self.notify_waiters();
419        Ok(result)
420    }
421
422    /// Notify any waiters if the state of the terminal changes.
423    fn notify_waiters(&mut self) {
424        let main_events = self.line_discipline.main_query_events();
425        if main_events.bits() != 0 {
426            self.main_wait_queue.notify_fd_events(main_events);
427        }
428        let replica_events = self.line_discipline.replica_query_events();
429        if replica_events.bits() != 0 {
430            self.replica_wait_queue.notify_fd_events(replica_events);
431        }
432    }
433}
434
435impl Drop for Terminal {
436    fn drop(&mut self) {
437        self.state.release_terminal(self.id).unwrap()
438    }
439}
440
441/// The controlling session of a terminal. Is is associated to a single side of the terminal,
442/// either main or replica.
443#[derive(Debug)]
444pub struct TerminalController {
445    pub session: Weak<Session>,
446}
447
448impl TerminalController {
449    pub fn new(session: &Arc<Session>) -> Option<Self> {
450        Some(Self { session: Arc::downgrade(&session) })
451    }
452
453    pub fn get_foreground_process_group(&self) -> Option<Arc<ProcessGroup>> {
454        self.session.upgrade().and_then(|session| session.read().get_foreground_process_group())
455    }
456}
457
458#[derive(Debug)]
459struct PtsIdsSet {
460    pts_count: u32,
461    next_id: u32,
462    reclaimed_ids: BTreeSet<u32>,
463}
464
465impl PtsIdsSet {
466    fn new(pts_count: u32) -> Self {
467        Self { pts_count, next_id: 0, reclaimed_ids: BTreeSet::new() }
468    }
469
470    fn release(&mut self, id: u32) {
471        assert!(self.reclaimed_ids.insert(id))
472    }
473
474    fn acquire(&mut self) -> Result<u32, Errno> {
475        match self.reclaimed_ids.iter().next() {
476            Some(e) => {
477                let value = *e;
478                self.reclaimed_ids.remove(&value);
479                Ok(value)
480            }
481            None => {
482                if self.next_id < self.pts_count {
483                    let id = self.next_id;
484                    self.next_id += 1;
485                    Ok(id)
486                } else {
487                    error!(ENOSPC)
488                }
489            }
490        }
491    }
492}