terminal.rs 18 KB

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