terminal.rs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722
  1. use alloc::collections::vec_deque::VecDeque;
  2. use alloc::sync::{Arc, Weak};
  3. use bitflags::bitflags;
  4. use eonix_log::ConsoleWrite;
  5. use eonix_sync::{Mutex, Proof};
  6. use posix_types::signal::Signal;
  7. use super::constants::ESRCH;
  8. use super::task::{ProcessList, Session, Thread};
  9. use super::user::{UserPointer, UserPointerMut};
  10. use crate::io::Buffer;
  11. use crate::kernel::constants::{EINTR, ENOTTY, EPERM};
  12. use crate::prelude::*;
  13. use crate::sync::CondVar;
  14. const BUFFER_SIZE: usize = 4096;
  15. const NCCS: usize = 19;
  16. // taken from linux kernel code
  17. /* c_cc characters */
  18. const VINTR: usize = 0;
  19. const VQUIT: usize = 1;
  20. const VERASE: usize = 2;
  21. const VKILL: usize = 3;
  22. const VEOF: usize = 4;
  23. #[allow(dead_code)]
  24. const VTIME: usize = 5;
  25. const VMIN: usize = 6;
  26. #[allow(dead_code)]
  27. const VSWTC: usize = 7;
  28. #[allow(dead_code)]
  29. const VSTART: usize = 8;
  30. #[allow(dead_code)]
  31. const VSTOP: usize = 9;
  32. const VSUSP: usize = 10;
  33. const VEOL: usize = 11;
  34. #[allow(dead_code)]
  35. const VREPRINT: usize = 12;
  36. #[allow(dead_code)]
  37. const VDISCARD: usize = 13;
  38. #[allow(dead_code)]
  39. const VWERASE: usize = 14;
  40. #[allow(dead_code)]
  41. const VLNEXT: usize = 15;
  42. const VEOL2: usize = 16;
  43. /* c_iflag bits */
  44. bitflags! {
  45. #[derive(Debug)]
  46. pub struct TermioIFlags: u16 {
  47. /// Ignore break condition
  48. const IGNBRK = 0x0001;
  49. /// Signal interrupt on break
  50. const BRKINT = 0x0002;
  51. /// Ignore characters with parity errors
  52. const IGNPAR = 0x0004;
  53. /// Mark parity and framing errors
  54. const PARMRK = 0x0008;
  55. /// Enable input parity check
  56. const INPCK = 0x0010;
  57. /// Strip 8th bit off characters
  58. const ISTRIP = 0x0020;
  59. /// Map NL to CR on input
  60. const INLCR = 0x0040;
  61. /// Ignore CR
  62. const IGNCR = 0x0080;
  63. /// Map CR to NL on input
  64. const ICRNL = 0x0100;
  65. const IUCLC = 0x0200;
  66. const IXON = 0x0400;
  67. /// Any character will restart after stop
  68. const IXANY = 0x0800;
  69. const IXOFF = 0x1000;
  70. const IMAXBEL = 0x2000;
  71. const IUTF8 = 0x4000;
  72. }
  73. #[derive(Debug)]
  74. pub struct TermioOFlags: u16 {
  75. /// Perform output processing
  76. const OPOST = 0x0001;
  77. const OLCUC = 0x0002;
  78. const ONLCR = 0x0004;
  79. const OCRNL = 0x0008;
  80. const ONOCR = 0x0010;
  81. const ONLRET = 0x0020;
  82. const OFILL = 0x0040;
  83. const OFDEL = 0x0080;
  84. }
  85. }
  86. bitflags! {
  87. #[derive(Debug)]
  88. pub struct TermioLFlags: u16 {
  89. const ISIG = 0x0001;
  90. const ICANON = 0x0002;
  91. const XCASE = 0x0004;
  92. const ECHO = 0x0008;
  93. const ECHOE = 0x0010;
  94. const ECHOK = 0x0020;
  95. const ECHONL = 0x0040;
  96. const NOFLSH = 0x0080;
  97. const TOSTOP = 0x0100;
  98. const ECHOCTL = 0x0200;
  99. const ECHOPRT = 0x0400;
  100. const ECHOKE = 0x0800;
  101. const FLUSHO = 0x1000;
  102. const PENDIN = 0x4000;
  103. const IEXTEN = 0x8000;
  104. }
  105. }
  106. /* c_cflag bit meaning */
  107. const B38400: u32 = 0x0000000f;
  108. const CS8: u32 = 0x00000030;
  109. const CREAD: u32 = 0x00000080;
  110. const HUPCL: u32 = 0x00000400;
  111. // line disciplines
  112. const N_TTY: u8 = 0;
  113. #[derive(Debug)]
  114. pub struct Termios {
  115. iflag: TermioIFlags,
  116. oflag: TermioOFlags,
  117. cflag: u32,
  118. lflag: TermioLFlags,
  119. line: u8,
  120. cc: [u8; NCCS],
  121. }
  122. macro_rules! CTRL {
  123. ('A') => {
  124. 0x01
  125. };
  126. ('B') => {
  127. 0x02
  128. };
  129. ('C') => {
  130. 0x03
  131. };
  132. ('D') => {
  133. 0x04
  134. };
  135. ('E') => {
  136. 0x05
  137. };
  138. ('F') => {
  139. 0x06
  140. };
  141. ('G') => {
  142. 0x07
  143. };
  144. ('H') => {
  145. 0x08
  146. };
  147. ('I') => {
  148. 0x09
  149. };
  150. ('J') => {
  151. 0x0A
  152. };
  153. ('K') => {
  154. 0x0B
  155. };
  156. ('L') => {
  157. 0x0C
  158. };
  159. ('M') => {
  160. 0x0D
  161. };
  162. ('N') => {
  163. 0x0E
  164. };
  165. ('O') => {
  166. 0x0F
  167. };
  168. ('P') => {
  169. 0x10
  170. };
  171. ('Q') => {
  172. 0x11
  173. };
  174. ('R') => {
  175. 0x12
  176. };
  177. ('S') => {
  178. 0x13
  179. };
  180. ('T') => {
  181. 0x14
  182. };
  183. ('U') => {
  184. 0x15
  185. };
  186. ('V') => {
  187. 0x16
  188. };
  189. ('W') => {
  190. 0x17
  191. };
  192. ('X') => {
  193. 0x18
  194. };
  195. ('Y') => {
  196. 0x19
  197. };
  198. ('Z') => {
  199. 0x1A
  200. };
  201. ('\\') => {
  202. 0x1c
  203. };
  204. }
  205. impl Termios {
  206. pub fn veof(&self) -> u8 {
  207. self.cc[VEOF]
  208. }
  209. pub fn veol(&self) -> u8 {
  210. self.cc[VEOL]
  211. }
  212. pub fn veol2(&self) -> u8 {
  213. self.cc[VEOL2]
  214. }
  215. pub fn vintr(&self) -> u8 {
  216. self.cc[VINTR]
  217. }
  218. pub fn vquit(&self) -> u8 {
  219. self.cc[VQUIT]
  220. }
  221. pub fn vsusp(&self) -> u8 {
  222. self.cc[VSUSP]
  223. }
  224. pub fn verase(&self) -> u8 {
  225. self.cc[VERASE]
  226. }
  227. pub fn vkill(&self) -> u8 {
  228. self.cc[VKILL]
  229. }
  230. pub fn echo(&self) -> bool {
  231. self.lflag.contains(TermioLFlags::ECHO)
  232. }
  233. pub fn echoe(&self) -> bool {
  234. self.lflag.contains(TermioLFlags::ECHOE)
  235. }
  236. pub fn echoctl(&self) -> bool {
  237. self.lflag.contains(TermioLFlags::ECHOCTL)
  238. }
  239. pub fn echoke(&self) -> bool {
  240. self.lflag.contains(TermioLFlags::ECHOKE)
  241. }
  242. pub fn echok(&self) -> bool {
  243. self.lflag.contains(TermioLFlags::ECHOK)
  244. }
  245. pub fn echonl(&self) -> bool {
  246. self.lflag.contains(TermioLFlags::ECHONL)
  247. }
  248. pub fn isig(&self) -> bool {
  249. self.lflag.contains(TermioLFlags::ISIG)
  250. }
  251. pub fn icanon(&self) -> bool {
  252. self.lflag.contains(TermioLFlags::ICANON)
  253. }
  254. pub fn iexten(&self) -> bool {
  255. self.lflag.contains(TermioLFlags::IEXTEN)
  256. }
  257. pub fn igncr(&self) -> bool {
  258. self.iflag.contains(TermioIFlags::IGNCR)
  259. }
  260. pub fn icrnl(&self) -> bool {
  261. self.iflag.contains(TermioIFlags::ICRNL)
  262. }
  263. pub fn inlcr(&self) -> bool {
  264. self.iflag.contains(TermioIFlags::INLCR)
  265. }
  266. pub fn noflsh(&self) -> bool {
  267. self.lflag.contains(TermioLFlags::NOFLSH)
  268. }
  269. pub fn new_standard() -> Self {
  270. let cc = core::array::from_fn(|idx| match idx {
  271. VINTR => CTRL!('C'),
  272. VQUIT => CTRL!('\\'),
  273. VERASE => 0x7f,
  274. VKILL => CTRL!('U'),
  275. VEOF => CTRL!('D'),
  276. VSUSP => CTRL!('Z'),
  277. VMIN => 1,
  278. _ => 0,
  279. });
  280. Self {
  281. iflag: TermioIFlags::ICRNL | TermioIFlags::IXOFF,
  282. oflag: TermioOFlags::OPOST | TermioOFlags::ONLCR,
  283. cflag: B38400 | CS8 | CREAD | HUPCL,
  284. lflag: TermioLFlags::ISIG
  285. | TermioLFlags::ICANON
  286. | TermioLFlags::ECHO
  287. | TermioLFlags::ECHOE
  288. | TermioLFlags::ECHOK
  289. | TermioLFlags::ECHOCTL
  290. | TermioLFlags::ECHOKE
  291. | TermioLFlags::IEXTEN,
  292. line: N_TTY,
  293. cc,
  294. }
  295. }
  296. fn get_user(&self) -> UserTermios {
  297. UserTermios {
  298. iflag: self.iflag.bits() as u32,
  299. oflag: self.oflag.bits() as u32,
  300. cflag: self.cflag,
  301. lflag: self.lflag.bits() as u32,
  302. line: self.line,
  303. cc: self.cc,
  304. }
  305. }
  306. }
  307. pub trait TerminalDevice: Send + Sync {
  308. fn write_direct(&self, data: &[u8]);
  309. fn write(&self, data: &[u8]);
  310. }
  311. struct TerminalInner {
  312. termio: Termios,
  313. buffer: VecDeque<u8>,
  314. }
  315. pub struct Terminal {
  316. inner: Mutex<TerminalInner>,
  317. session: Spin<Weak<Session>>,
  318. device: Arc<dyn TerminalDevice>,
  319. cv: CondVar,
  320. }
  321. #[repr(C)]
  322. #[derive(Debug, Clone, Copy)]
  323. pub struct UserWindowSize {
  324. row: u16,
  325. col: u16,
  326. xpixel: u16,
  327. ypixel: u16,
  328. }
  329. #[repr(C)]
  330. #[derive(Debug, Clone, Copy)]
  331. pub struct UserTermios {
  332. iflag: u32,
  333. oflag: u32,
  334. cflag: u32,
  335. lflag: u32,
  336. line: u8,
  337. cc: [u8; NCCS],
  338. }
  339. pub enum TerminalIORequest<'a> {
  340. GetProcessGroup(UserPointerMut<'a, u32>),
  341. SetProcessGroup(UserPointer<'a, u32>),
  342. GetWindowSize(UserPointerMut<'a, UserWindowSize>),
  343. GetTermios(UserPointerMut<'a, UserTermios>),
  344. SetTermios(UserPointer<'a, UserTermios>),
  345. }
  346. impl core::fmt::Debug for Terminal {
  347. fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
  348. f.debug_struct("Terminal").finish()
  349. }
  350. }
  351. impl Terminal {
  352. pub fn new(device: Arc<dyn TerminalDevice>) -> Arc<Self> {
  353. Arc::new(Self {
  354. inner: Mutex::new(TerminalInner {
  355. termio: Termios::new_standard(),
  356. buffer: VecDeque::with_capacity(BUFFER_SIZE),
  357. }),
  358. session: Spin::new(Weak::new()),
  359. cv: CondVar::new(),
  360. device,
  361. })
  362. }
  363. /// Clear the read buffer.
  364. fn clear_read_buffer(&self, inner: &mut TerminalInner) {
  365. inner.buffer.clear();
  366. }
  367. pub fn write(&self, data: &[u8]) {
  368. self.device.write(data);
  369. }
  370. fn erase(&self, inner: &mut TerminalInner, echo: bool) -> Option<u8> {
  371. let back = inner.buffer.back().copied();
  372. match back {
  373. None => return None,
  374. Some(b'\n') => return None,
  375. Some(back) if back == inner.termio.veof() => return None,
  376. Some(back) if back == inner.termio.veol() => return None,
  377. Some(back) if back == inner.termio.veol2() => return None,
  378. _ => {}
  379. }
  380. let back = inner.buffer.pop_back();
  381. if echo && inner.termio.echo() && inner.termio.echoe() {
  382. self.write(&[CTRL!('H'), b' ', CTRL!('H')]); // Backspace, Space, Backspace
  383. }
  384. return back;
  385. }
  386. fn echo_char(&self, inner: &mut TerminalInner, ch: u8) {
  387. match ch {
  388. b'\t' | b'\n' | CTRL!('Q') | CTRL!('S') | 32.. => self.write(&[ch]),
  389. _ if !inner.termio.echo() => self.write(&[ch]),
  390. _ if !inner.termio.echoctl() => self.write(&[ch]),
  391. _ if !inner.termio.iexten() => self.write(&[ch]),
  392. _ => self.write(&[b'^', ch + 0x40]),
  393. }
  394. }
  395. async fn signal(&self, inner: &mut TerminalInner, signal: Signal) {
  396. if let Some(session) = self.session() {
  397. session.raise_foreground(signal).await;
  398. }
  399. if !inner.termio.noflsh() {
  400. self.clear_read_buffer(inner);
  401. }
  402. }
  403. async fn echo_and_signal(
  404. &self,
  405. inner: &mut TerminalInner,
  406. ch: u8,
  407. signal: Signal,
  408. ) {
  409. self.echo_char(inner, ch);
  410. self.signal(inner, signal).await;
  411. }
  412. fn do_commit_char(&self, inner: &mut TerminalInner, ch: u8) {
  413. inner.buffer.push_back(ch);
  414. if inner.termio.echo() || (ch == b'\n' && inner.termio.echonl()) {
  415. self.echo_char(inner, ch);
  416. }
  417. // If ICANON is not set, we notify all waiting processes.
  418. // If ICANON is set but we have a new line, there are data ready, we notify as well.
  419. if ch == b'\n' || !inner.termio.icanon() {
  420. self.cv.notify_all();
  421. }
  422. }
  423. // TODO: Find a better way to handle this.
  424. pub async fn commit_char(&self, ch: u8) {
  425. let mut inner = self.inner.lock().await;
  426. if inner.termio.isig() {
  427. match ch {
  428. 0xff => {}
  429. ch if ch == inner.termio.vintr() => {
  430. return self
  431. .echo_and_signal(&mut inner, ch, Signal::SIGINT)
  432. .await
  433. }
  434. ch if ch == inner.termio.vquit() => {
  435. return self
  436. .echo_and_signal(&mut inner, ch, Signal::SIGQUIT)
  437. .await
  438. }
  439. ch if ch == inner.termio.vsusp() => {
  440. return self
  441. .echo_and_signal(&mut inner, ch, Signal::SIGTSTP)
  442. .await
  443. }
  444. _ => {}
  445. }
  446. }
  447. // If handled, the character is discarded.
  448. if inner.termio.icanon() {
  449. match ch {
  450. 0xff => {}
  451. ch if ch == inner.termio.veof() => return self.cv.notify_all(),
  452. ch if ch == inner.termio.verase() => {
  453. self.erase(&mut inner, true);
  454. return;
  455. }
  456. ch if ch == inner.termio.vkill() => {
  457. if inner.termio.echok() {
  458. while self.erase(&mut inner, false).is_some() {}
  459. self.write(&[b'\n']);
  460. } else if inner.termio.echoke() && inner.termio.iexten() {
  461. while self.erase(&mut inner, true).is_some() {}
  462. }
  463. return;
  464. }
  465. _ => {}
  466. }
  467. }
  468. match ch {
  469. b'\r' if inner.termio.igncr() => {}
  470. b'\r' if inner.termio.icrnl() => {
  471. return self.do_commit_char(&mut inner, b'\n')
  472. }
  473. b'\n' if inner.termio.inlcr() => {
  474. return self.do_commit_char(&mut inner, b'\r')
  475. }
  476. _ => self.do_commit_char(&mut inner, ch),
  477. }
  478. }
  479. pub async fn poll_in(&self) -> KResult<()> {
  480. let inner = self.inner.lock().await;
  481. if inner.buffer.is_empty() {
  482. let _inner = self.cv.wait(inner).await;
  483. if Thread::current().signal_list.has_pending_signal() {
  484. return Err(EINTR);
  485. }
  486. }
  487. Ok(())
  488. }
  489. pub async fn read(&self, buffer: &mut dyn Buffer) -> KResult<usize> {
  490. let mut tmp_buffer = [0u8; 32];
  491. let data = 'block: {
  492. if buffer.available() == 0 {
  493. break 'block &tmp_buffer[..0];
  494. }
  495. let mut inner = self.inner.lock().await;
  496. if inner.buffer.is_empty() {
  497. inner = self.cv.wait(inner).await;
  498. if Thread::current().signal_list.has_pending_signal() {
  499. return Err(EINTR);
  500. }
  501. }
  502. if inner.buffer.is_empty() {
  503. break 'block &tmp_buffer[..0];
  504. }
  505. let length = if inner.termio.icanon() {
  506. // Canonical mode, return data until we see a newline.
  507. // TODO!!: We should wait if we don't see one.
  508. inner
  509. .buffer
  510. .iter()
  511. .position(|&ch| ch == b'\n')
  512. .map(|pos| pos + 1)
  513. .unwrap_or(inner.buffer.len())
  514. } else {
  515. buffer.available().min(inner.buffer.len())
  516. };
  517. // TODO!!!!!!: Change this. We need to loop until we've got enough data.
  518. let length = length.min(tmp_buffer.len());
  519. for (ch, r) in inner
  520. .buffer
  521. .drain(..length)
  522. .zip(tmp_buffer.iter_mut().take(length))
  523. {
  524. *r = ch;
  525. }
  526. &tmp_buffer[..length]
  527. };
  528. buffer.fill(data).map(|result| result.allow_partial())
  529. }
  530. pub async fn ioctl(&self, request: TerminalIORequest<'_>) -> KResult<()> {
  531. match request {
  532. TerminalIORequest::GetProcessGroup(pgid_pointer) => {
  533. let Some(session) = self.session() else {
  534. return Err(ENOTTY);
  535. };
  536. let Some(pgroup) = session.foreground_pgroup() else {
  537. return Err(ENOTTY);
  538. };
  539. pgid_pointer.write(pgroup.pgid)
  540. }
  541. TerminalIORequest::SetProcessGroup(pgid) => {
  542. let pgid = pgid.read()?;
  543. let procs = ProcessList::get().read().await;
  544. let Some(session) = self.session() else {
  545. return Err(ENOTTY);
  546. };
  547. let Some(pgroup) = procs.try_find_pgroup(pgid) else {
  548. return Err(ESRCH);
  549. };
  550. session.set_foreground_pgroup(Some(&pgroup))?;
  551. Ok(())
  552. }
  553. TerminalIORequest::GetWindowSize(ptr) => {
  554. // TODO: Get the actual window size
  555. let window_size = UserWindowSize {
  556. row: 40,
  557. col: 80,
  558. xpixel: 0,
  559. ypixel: 0,
  560. };
  561. ptr.write(window_size)
  562. }
  563. TerminalIORequest::GetTermios(ptr) => {
  564. let termios = self.inner.lock().await.termio.get_user();
  565. ptr.write(termios)
  566. }
  567. TerminalIORequest::SetTermios(ptr) => {
  568. let user_termios = ptr.read()?;
  569. let mut inner = self.inner.lock().await;
  570. // TODO: We ignore unknown bits for now.
  571. inner.termio.iflag =
  572. TermioIFlags::from_bits_truncate(user_termios.iflag as u16);
  573. inner.termio.oflag =
  574. TermioOFlags::from_bits_truncate(user_termios.oflag as u16);
  575. inner.termio.lflag =
  576. TermioLFlags::from_bits_truncate(user_termios.lflag as u16);
  577. inner.termio.cflag = user_termios.cflag;
  578. inner.termio.line = user_termios.line;
  579. inner.termio.cc = user_termios.cc;
  580. Ok(())
  581. }
  582. }
  583. }
  584. pub fn session(&self) -> Option<Arc<Session>> {
  585. self.session.lock().upgrade()
  586. }
  587. /// Drop our current controlled session. The old session lose its controlling
  588. /// terminal and all processes in it will receive a SIGHUP and then SIGCONT.
  589. pub fn drop_session(&self, procs: Proof<'_, ProcessList>) {
  590. let session =
  591. core::mem::replace(&mut *self.session.lock(), Weak::new());
  592. let Some(old_session) = session.upgrade() else {
  593. return;
  594. };
  595. old_session._drop_control_terminal(procs);
  596. }
  597. /// Assign the `session` to this terminal.
  598. /// Drop the previous session if `forced` is true.
  599. pub async fn set_session(
  600. self: &Arc<Self>,
  601. session: &Arc<Session>,
  602. forced: bool,
  603. procs: Proof<'_, ProcessList>,
  604. ) -> KResult<()> {
  605. let mut cur_session = self.session.lock();
  606. // XXX: Holding spinlock for too long?
  607. if let Some(old_session) = cur_session.upgrade() {
  608. if old_session.sid == session.sid {
  609. return Ok(());
  610. }
  611. if !forced {
  612. return Err(EPERM);
  613. }
  614. // TODO: Check whether the caller has the CAP_SYS_ADMIN capability.
  615. // We've stolen the terminal from the old session.
  616. old_session._drop_control_terminal(procs);
  617. }
  618. *cur_session = Arc::downgrade(session);
  619. session._set_control_terminal(self, procs);
  620. Ok(())
  621. }
  622. }
  623. impl ConsoleWrite for Terminal {
  624. fn write(&self, s: &str) {
  625. self.device.write_direct(s.as_bytes());
  626. }
  627. }