terminal.rs 18 KB

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