misc: getty open consumer channel to get events
Signed-off-by: Anhad Singh <andypythonappdeveloper@gmail.com>
This commit is contained in:
Generated
+62
-5
@@ -140,6 +140,12 @@ dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.139"
|
||||
@@ -158,6 +164,18 @@ version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
|
||||
|
||||
[[package]]
|
||||
name = "orbclient"
|
||||
version = "0.3.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "221d488cd70617f1bd599ed8ceb659df2147d9393717954d82a0f5e8032a6ab1"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"redox_syscall 0.3.5",
|
||||
"sdl2",
|
||||
"sdl2-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox-daemon"
|
||||
version = "0.1.0"
|
||||
@@ -165,7 +183,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21e31c834277709c7ff3eb74959fe62be4b45b1189ba9d41fd3744cd3a9c554f"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"redox_syscall 0.2.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -189,13 +207,22 @@ dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_termios"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8440d8acb4fd3d277125b4bd01a6f38aee8d814b3b5fc09b3f2b825d37d3fe8f"
|
||||
dependencies = [
|
||||
"redox_syscall",
|
||||
"redox_syscall 0.2.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -205,7 +232,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"redox_syscall",
|
||||
"redox_syscall 0.2.16",
|
||||
"rust-argon2",
|
||||
]
|
||||
|
||||
@@ -221,6 +248,29 @@ dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sdl2"
|
||||
version = "0.35.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7959277b623f1fb9e04aea73686c3ca52f01b2145f8ea16f4ff30d8b7623b1a"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"sdl2-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sdl2-sys"
|
||||
version = "0.35.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3586be2cf6c0a8099a79a12b4084357aa9b3e0b0d7980e3b67aaf7a9d55f9f0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"version-compare",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
@@ -235,7 +285,7 @@ checksum = "077185e2eac69c3f8379a4298e1e07cd36beb962290d4a51199acf0fdc10607e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"numtoa",
|
||||
"redox_syscall",
|
||||
"redox_syscall 0.2.16",
|
||||
"redox_termios",
|
||||
]
|
||||
|
||||
@@ -260,9 +310,10 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"extra",
|
||||
"orbclient",
|
||||
"redox-daemon",
|
||||
"redox_liner",
|
||||
"redox_syscall",
|
||||
"redox_syscall 0.2.16",
|
||||
"redox_termios",
|
||||
"redox_users",
|
||||
"termion",
|
||||
@@ -274,6 +325,12 @@ version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||
|
||||
[[package]]
|
||||
name = "version-compare"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
|
||||
@@ -53,6 +53,7 @@ path = "src/bin/usermod.rs"
|
||||
[dependencies]
|
||||
clap = "2.33.0"
|
||||
extra = { git = "https://gitlab.redox-os.org/redox-os/libextra.git" }
|
||||
orbclient = "0.3.45"
|
||||
redox-daemon = "0.1"
|
||||
redox_liner = "0.5.1"
|
||||
redox_syscall = "0.2.12"
|
||||
|
||||
+227
-53
@@ -1,18 +1,24 @@
|
||||
#[macro_use]
|
||||
extern crate clap;
|
||||
extern crate extra;
|
||||
extern crate orbclient;
|
||||
extern crate redox_termios;
|
||||
extern crate syscall;
|
||||
extern crate extra;
|
||||
|
||||
use std::str;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::{self, ErrorKind, Read, Write, Stderr};
|
||||
use std::os::unix::io::{FromRawFd, RawFd};
|
||||
use std::io::{self, ErrorKind, Read, Stderr, Write};
|
||||
use std::process::{Child, Command, Stdio};
|
||||
use std::str;
|
||||
|
||||
use std::os::fd::AsRawFd;
|
||||
use std::os::unix::io::{FromRawFd, RawFd};
|
||||
|
||||
use orbclient::{Event, EventOption};
|
||||
|
||||
use extra::io::fail;
|
||||
|
||||
const _MAN_PAGE: &'static str = /* @MANSTART{getty} */ r#"
|
||||
const _MAN_PAGE: &'static str = /* @MANSTART{getty} */
|
||||
r#"
|
||||
NAME
|
||||
getty - set terminal mode
|
||||
|
||||
@@ -39,8 +45,92 @@ AUTHOR
|
||||
const DEFAULT_COLS: u32 = 80;
|
||||
const DEFAULT_LINES: u32 = 30;
|
||||
|
||||
pub fn handle(event_file: &mut File, tty_fd: RawFd, master_fd: RawFd, process: &mut Child) {
|
||||
let handle_event = |event_id: usize| {
|
||||
fn process_events(ctrl: &mut bool, events: &[Event]) -> Vec<u8> {
|
||||
let mut buf = vec![];
|
||||
|
||||
for event in events.iter() {
|
||||
if let EventOption::Key(key_event) = event.to_option() {
|
||||
if key_event.scancode == 0x1D {
|
||||
*ctrl = key_event.pressed;
|
||||
} else if key_event.pressed {
|
||||
match key_event.scancode {
|
||||
0x0E => {
|
||||
// Backspace
|
||||
buf.extend_from_slice(b"\x7F");
|
||||
}
|
||||
0x47 => {
|
||||
// Home
|
||||
buf.extend_from_slice(b"\x1B[H");
|
||||
}
|
||||
0x48 => {
|
||||
// Up
|
||||
buf.extend_from_slice(b"\x1B[A");
|
||||
}
|
||||
0x49 => {
|
||||
// Page up
|
||||
buf.extend_from_slice(b"\x1B[5~");
|
||||
}
|
||||
0x4B => {
|
||||
// Left
|
||||
buf.extend_from_slice(b"\x1B[D");
|
||||
}
|
||||
0x4D => {
|
||||
// Right
|
||||
buf.extend_from_slice(b"\x1B[C");
|
||||
}
|
||||
0x4F => {
|
||||
// End
|
||||
buf.extend_from_slice(b"\x1B[F");
|
||||
}
|
||||
0x50 => {
|
||||
// Down
|
||||
buf.extend_from_slice(b"\x1B[B");
|
||||
}
|
||||
0x51 => {
|
||||
// Page down
|
||||
buf.extend_from_slice(b"\x1B[6~");
|
||||
}
|
||||
0x52 => {
|
||||
// Insert
|
||||
buf.extend_from_slice(b"\x1B[2~");
|
||||
}
|
||||
0x53 => {
|
||||
// Delete
|
||||
buf.extend_from_slice(b"\x1B[3~");
|
||||
}
|
||||
_ => {
|
||||
let c = match key_event.character {
|
||||
c @ 'A'..='Z' if *ctrl => ((c as u8 - b'A') + b'\x01') as char,
|
||||
c @ 'a'..='z' if *ctrl => ((c as u8 - b'a') + b'\x01') as char,
|
||||
c => c,
|
||||
};
|
||||
|
||||
if c != '\0' {
|
||||
let mut b = [0; 4];
|
||||
buf.extend_from_slice(c.encode_utf8(&mut b).as_bytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buf
|
||||
}
|
||||
|
||||
pub fn handle(
|
||||
event_file: &mut File,
|
||||
tty_fd: RawFd,
|
||||
consumer_fd: RawFd,
|
||||
master_fd: RawFd,
|
||||
process: &mut Child,
|
||||
) {
|
||||
// tty_fd => Display
|
||||
// master_fd => PTY
|
||||
// consumer_fd => Either(`input:consumer/{#VT}`, $DEVICE)
|
||||
|
||||
let mut ctrl = false;
|
||||
let mut handle_event = |event_id: usize| {
|
||||
if event_id as RawFd == tty_fd {
|
||||
let mut packet = [0; 4096];
|
||||
loop {
|
||||
@@ -48,9 +138,10 @@ pub fn handle(event_file: &mut File, tty_fd: RawFd, master_fd: RawFd, process: &
|
||||
Ok(0) => return,
|
||||
Ok(count) => count,
|
||||
Err(ref err) if err.errno == syscall::EAGAIN => break,
|
||||
Err(_) => panic!("getty: failed to read from TTY")
|
||||
Err(_) => panic!("getty: failed to read from TTY"),
|
||||
};
|
||||
syscall::write(master_fd as usize, &packet[..count]).expect("getty: failed to write master PTY");
|
||||
syscall::write(master_fd as usize, &packet[..count])
|
||||
.expect("getty: failed to write master PTY");
|
||||
}
|
||||
} else if event_id as RawFd == master_fd {
|
||||
let mut packet = [0; 4096];
|
||||
@@ -59,9 +150,35 @@ pub fn handle(event_file: &mut File, tty_fd: RawFd, master_fd: RawFd, process: &
|
||||
Ok(0) => return,
|
||||
Ok(count) => count,
|
||||
Err(ref err) if err.errno == syscall::EAGAIN => break,
|
||||
Err(_) => panic!("getty: failed to read from master TTY")
|
||||
Err(_) => panic!("getty: failed to read from master TTY"),
|
||||
};
|
||||
syscall::write(tty_fd as usize, &packet[1..count]).expect("getty: failed to write to TTY");
|
||||
syscall::write(tty_fd as usize, &packet[1..count])
|
||||
.expect("getty: failed to write to TTY");
|
||||
if packet[0] & 1 == 1 {
|
||||
let _ = syscall::fsync(tty_fd as usize);
|
||||
}
|
||||
}
|
||||
} else if event_id as RawFd == consumer_fd {
|
||||
let mut packet = [0; 4096];
|
||||
loop {
|
||||
let count = match syscall::read(consumer_fd as usize, &mut packet) {
|
||||
Ok(0) => return,
|
||||
Ok(count) => count,
|
||||
Err(ref err) if err.errno == syscall::EAGAIN => break,
|
||||
Err(_) => panic!("getty: failed to read from master TTY"),
|
||||
};
|
||||
|
||||
let events = unsafe {
|
||||
core::slice::from_raw_parts(
|
||||
packet.as_ptr() as *const Event,
|
||||
count / core::mem::size_of::<Event>(),
|
||||
)
|
||||
};
|
||||
|
||||
let buf = process_events(&mut ctrl, events);
|
||||
syscall::write(master_fd as usize, buf.as_slice())
|
||||
.expect("getty: failed to write to TTY");
|
||||
|
||||
if packet[0] & 1 == 1 {
|
||||
let _ = syscall::fsync(tty_fd as usize);
|
||||
}
|
||||
@@ -73,21 +190,24 @@ pub fn handle(event_file: &mut File, tty_fd: RawFd, master_fd: RawFd, process: &
|
||||
|
||||
handle_event(tty_fd as usize);
|
||||
handle_event(master_fd as usize);
|
||||
handle_event(consumer_fd as usize);
|
||||
|
||||
'events: loop {
|
||||
let mut sys_event = syscall::Event::default();
|
||||
event_file.read(&mut sys_event).expect("getty: failed to read event file");
|
||||
event_file
|
||||
.read(&mut sys_event)
|
||||
.expect("getty: failed to read event file");
|
||||
handle_event(sys_event.id);
|
||||
|
||||
match process.try_wait() {
|
||||
Ok(status) => match status {
|
||||
Some(_code) => break 'events,
|
||||
None => ()
|
||||
None => (),
|
||||
},
|
||||
Err(err) => match err.kind() {
|
||||
ErrorKind::WouldBlock => (),
|
||||
_ => panic!("getty: failed to wait on child: {:?}", err)
|
||||
}
|
||||
_ => panic!("getty: failed to wait on child: {:?}", err),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,22 +216,31 @@ pub fn handle(event_file: &mut File, tty_fd: RawFd, master_fd: RawFd, process: &
|
||||
}
|
||||
|
||||
pub fn getpty(columns: u32, lines: u32) -> (RawFd, String) {
|
||||
let master = syscall::open("pty:", syscall::O_CLOEXEC | syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("getty: failed to create PTY");
|
||||
let master = syscall::open(
|
||||
"pty:",
|
||||
syscall::O_CLOEXEC | syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK,
|
||||
)
|
||||
.expect("getty: failed to create PTY");
|
||||
|
||||
if let Ok(winsize_fd) = syscall::dup(master, b"winsize") {
|
||||
let _ = syscall::write(winsize_fd, &redox_termios::Winsize {
|
||||
ws_row: lines as u16,
|
||||
ws_col: columns as u16
|
||||
});
|
||||
let _ = syscall::write(
|
||||
winsize_fd,
|
||||
&redox_termios::Winsize {
|
||||
ws_row: lines as u16,
|
||||
ws_col: columns as u16,
|
||||
},
|
||||
);
|
||||
let _ = syscall::close(winsize_fd);
|
||||
}
|
||||
|
||||
let mut buf: [u8; 4096] = [0; 4096];
|
||||
let count = syscall::fpath(master, &mut buf).unwrap();
|
||||
(master as RawFd, unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) })
|
||||
(master as RawFd, unsafe {
|
||||
String::from_utf8_unchecked(Vec::from(&buf[..count]))
|
||||
})
|
||||
}
|
||||
|
||||
fn daemon(tty_fd: RawFd, clear: bool, stderr: &mut Stderr) {
|
||||
fn daemon(tty_fd: RawFd, consumer_fd: RawFd, clear: bool, stderr: &mut Stderr) {
|
||||
let (columns, lines) = {
|
||||
let mut path = [0; 4096];
|
||||
if let Ok(count) = syscall::fpath(tty_fd as usize, &mut path) {
|
||||
@@ -134,17 +263,21 @@ fn daemon(tty_fd: RawFd, clear: bool, stderr: &mut Stderr) {
|
||||
.open("event:")
|
||||
.expect("getty: failed to open event file");
|
||||
|
||||
event_file.write(&syscall::Event {
|
||||
id: tty_fd as usize,
|
||||
flags: syscall::flag::EVENT_READ,
|
||||
data: 0
|
||||
}).expect("getty: failed to fevent TTY");
|
||||
event_file
|
||||
.write(&syscall::Event {
|
||||
id: consumer_fd as usize,
|
||||
flags: syscall::flag::EVENT_READ,
|
||||
data: 0,
|
||||
})
|
||||
.expect("getty: failed to fevent TTY");
|
||||
|
||||
event_file.write(&syscall::Event {
|
||||
id: master_fd as usize,
|
||||
flags: syscall::flag::EVENT_READ,
|
||||
data: 0
|
||||
}).expect("getty: failed to fevent master PTY");
|
||||
event_file
|
||||
.write(&syscall::Event {
|
||||
id: master_fd as usize,
|
||||
flags: syscall::flag::EVENT_READ,
|
||||
data: 0,
|
||||
})
|
||||
.expect("getty: failed to fevent master PTY");
|
||||
|
||||
loop {
|
||||
if clear {
|
||||
@@ -152,29 +285,36 @@ fn daemon(tty_fd: RawFd, clear: bool, stderr: &mut Stderr) {
|
||||
}
|
||||
let _ = syscall::fsync(tty_fd as usize);
|
||||
|
||||
let slave_stdin = syscall::open(&pty, syscall::O_CLOEXEC | syscall::O_RDONLY).expect("getty: failed to open slave stdin");
|
||||
let slave_stdout = syscall::open(&pty, syscall::O_CLOEXEC | syscall::O_WRONLY).expect("getty: failed to open slave stdout");
|
||||
let slave_stderr = syscall::open(&pty, syscall::O_CLOEXEC | syscall::O_WRONLY).expect("getty: failed to open slave stderr");
|
||||
let slave_stdin = syscall::open(&pty, syscall::O_CLOEXEC | syscall::O_RDONLY)
|
||||
.expect("getty: failed to open slave stdin");
|
||||
let slave_stdout = syscall::open(&pty, syscall::O_CLOEXEC | syscall::O_WRONLY)
|
||||
.expect("getty: failed to open slave stdout");
|
||||
let slave_stderr = syscall::open(&pty, syscall::O_CLOEXEC | syscall::O_WRONLY)
|
||||
.expect("getty: failed to open slave stderr");
|
||||
|
||||
let mut command = Command::new("login");
|
||||
unsafe {
|
||||
command
|
||||
.stdin(Stdio::from_raw_fd(slave_stdin as RawFd))
|
||||
.stdout(Stdio::from_raw_fd(slave_stdout as RawFd))
|
||||
.stderr(Stdio::from_raw_fd(slave_stderr as RawFd))
|
||||
.env("COLUMNS", format!("{}", columns))
|
||||
.env("LINES", format!("{}", lines))
|
||||
.env("TERM", "xterm-256color")
|
||||
.env("TTY", &pty);
|
||||
.stdin(Stdio::from_raw_fd(slave_stdin as RawFd))
|
||||
.stdout(Stdio::from_raw_fd(slave_stdout as RawFd))
|
||||
.stderr(Stdio::from_raw_fd(slave_stderr as RawFd))
|
||||
.env("COLUMNS", format!("{}", columns))
|
||||
.env("LINES", format!("{}", lines))
|
||||
.env("TERM", "xterm-256color")
|
||||
.env("TTY", &pty);
|
||||
}
|
||||
|
||||
match command.spawn() {
|
||||
Ok(mut process) => {
|
||||
handle(&mut event_file, tty_fd, master_fd, &mut process);
|
||||
},
|
||||
Err(err) => {
|
||||
fail(&format!("getty: failed to execute login: {}", err), stderr)
|
||||
handle(
|
||||
&mut event_file,
|
||||
tty_fd,
|
||||
consumer_fd,
|
||||
master_fd,
|
||||
&mut process,
|
||||
);
|
||||
}
|
||||
Err(err) => fail(&format!("getty: failed to execute login: {}", err), stderr),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -187,19 +327,53 @@ pub fn main() {
|
||||
(about: "Set terminal mode")
|
||||
(@arg TTY: +required "")
|
||||
(@arg NO_CLEAR: -J --("no-clear") "Do not clear the screen before forking")
|
||||
).get_matches();
|
||||
)
|
||||
.get_matches();
|
||||
|
||||
let clear = !args.is_present("NO_CLEAR");
|
||||
|
||||
let tty = args.value_of("TTY").unwrap();
|
||||
let tty_fd = match syscall::open(tty, syscall::O_CLOEXEC | syscall::flag::O_RDWR | syscall::flag::O_NONBLOCK) {
|
||||
Ok(fd) => fd,
|
||||
Err(err) => fail(&format!("getty: failed to open TTY {}: {}", tty, err), &mut stderr),
|
||||
let vt = args.value_of("TTY").unwrap();
|
||||
|
||||
let mut buf = [0; 1024];
|
||||
let (vt_path, consumer) = if vt.parse::<usize>().is_ok() {
|
||||
let consumer =
|
||||
File::open(format!("input:consumer/{vt}")).expect("getty: failed to open consumer");
|
||||
|
||||
let written = syscall::fpath(consumer.as_raw_fd() as usize, &mut buf)
|
||||
.expect("getty: failed to get the display");
|
||||
assert!(written <= buf.len());
|
||||
|
||||
(
|
||||
core::str::from_utf8(&buf[..written])
|
||||
.expect("getty: UTF-8 validation failed for the display path"),
|
||||
consumer,
|
||||
)
|
||||
} else {
|
||||
(vt, File::open(vt).expect("getty: failed to open display"))
|
||||
};
|
||||
|
||||
let tty_fd = match syscall::open(
|
||||
vt_path,
|
||||
syscall::O_CLOEXEC | syscall::flag::O_RDWR | syscall::flag::O_NONBLOCK,
|
||||
) {
|
||||
Ok(fd) => fd,
|
||||
Err(err) => fail(
|
||||
&format!("getty: failed to open TTY {}: {}", vt_path, err),
|
||||
&mut stderr,
|
||||
),
|
||||
};
|
||||
|
||||
let consumer_fd = consumer.as_raw_fd();
|
||||
|
||||
redox_daemon::Daemon::new(|d| {
|
||||
d.ready().expect("getty: failed to notify ");
|
||||
daemon(tty_fd as RawFd, clear, &mut stderr);
|
||||
daemon(tty_fd as RawFd, consumer_fd, clear, &mut stderr);
|
||||
std::process::exit(0);
|
||||
}).unwrap_or_else(|err| fail(&format!("getty: failed to fork login: {}", err), &mut stderr));
|
||||
})
|
||||
.unwrap_or_else(|err| {
|
||||
fail(
|
||||
&format!("getty: failed to fork login: {}", err),
|
||||
&mut stderr,
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user