terminal.rs 18 KB

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