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