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