Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

clean up around the tty. #89

Merged
merged 1 commit into from
Jun 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/cgroups/v2/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ impl Manager {
Ok(controllers)
}

fn write_controllers(path: &Path, controllers: &Vec<String>) -> Result<()> {
fn write_controllers(path: &Path, controllers: &[String]) -> Result<()> {
for controller in controllers {
common::write_cgroup_file_str(path.join(CGROUP_SUBTREE_CONTROL), controller)?;
}
Expand Down
19 changes: 8 additions & 11 deletions src/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub struct Create {
bundle: PathBuf,
/// Unix socket (file) path , which will receive file descriptor of the writing end of the pseudoterminal
#[clap(short, long)]
console_socket: Option<String>,
console_socket: Option<PathBuf>,
/// name of the container instance to be started
pub container_id: String,
}
Expand Down Expand Up @@ -86,16 +86,13 @@ impl Create {
let mut notify_socket: NotifyListener = NotifyListener::new(&container_dir)?;
// convert path of root file system of the container to absolute path
let rootfs = fs::canonicalize(&spec.root.path)?;

// if socket file path is given in commandline options,
// get file descriptors of console and console socket
let (csocketfd, _consolefd) = {
if let Some(console_socket) = &self.console_socket {
let (csocketfd, consolefd) =
tty::load_console_sockets(&container_dir, console_socket)?;
(Some(csocketfd), Some(consolefd))
} else {
(None, None)
}
// get file descriptors of console socket
let csocketfd = if let Some(console_socket) = &self.console_socket {
Some(tty::setup_console_socket(&container_dir, console_socket)?)
} else {
None
};

let process = run_container(
Expand Down Expand Up @@ -162,7 +159,7 @@ fn run_container<P: AsRef<Path>>(

// set up tty if specified
if let Some(csocketfd) = csocketfd {
tty::ready(csocketfd)?;
tty::setup_console(csocketfd)?;
}

// set namespaces
Expand Down
1 change: 0 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
//! Container Runtime written in Rust, inspired by [railcar](https://github.com/oracle/railcar)
//! This crate provides a container runtime which can be used by a high-level container runtime to run containers.

use procfs;
use std::fs;
use std::path::{Path, PathBuf};

Expand Down
2 changes: 1 addition & 1 deletion src/namespaces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//! Process (processes in a namespace have two PIDs, one for the global PID,
//! which is used by the main system and the second one is for the child within the process tree),
//! Interprocess Communication (Control or communication between processes),
//! Network (which network devices can be seen by the processes in the namespace), User (User configs),
//! Network (which network devices can be seen by the processes in the namespace), User (User configs),
//! UTS (hostname and domain information, processes will think they're running on servers with different names),
//! Cgroup (Resource limits, execution priority etc.)

Expand Down
77 changes: 33 additions & 44 deletions src/tty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,44 +6,21 @@ use std::path::Path;

use anyhow::{bail, Result};
use nix::errno::Errno;
use nix::fcntl;
use nix::sys::socket;
use nix::sys::stat;
use nix::sys::uio;
use nix::unistd::{close, setsid};

use crate::stdio;
use crate::stdio::FileDescriptor;

pub fn ready(console_fd: FileDescriptor) -> Result<()> {
let openpty_result = nix::pty::openpty(None, None)?;
let data: &[u8] = b"/dev/ptmx";
let iov = [nix::sys::uio::IoVec::from_slice(data)];
let fds = [openpty_result.master];
let cmsg = socket::ControlMessage::ScmRights(&fds);
socket::sendmsg(
console_fd.as_raw_fd(),
&iov,
&[cmsg],
socket::MsgFlags::empty(),
None,
)?;
// TODO: Handling when there isn't console-socket.

setsid()?;
if unsafe { libc::ioctl(openpty_result.slave, libc::TIOCSCTTY) } < 0 {
log::warn!("could not TIOCSCTTY");
};
let slave = FileDescriptor::from(openpty_result.slave);
stdio::connect_stdio(&slave, &slave, &slave).expect("could not dup tty to stderr");
close(console_fd.as_raw_fd())?;
Ok(())
}

pub fn load_console_sockets(
pub fn setup_console_socket(
container_dir: &Path,
console_socket: &str,
) -> Result<(FileDescriptor, FileDescriptor)> {
let csocket = "console-stdout";
symlink(console_socket, container_dir.join(csocket))?;
console_socket_path: &Path,
) -> Result<FileDescriptor> {
let csocket = "console-socket";
symlink(console_socket_path, container_dir.join(csocket))?;

let mut csocketfd = socket::socket(
socket::AddressFamily::Unix,
Expand All @@ -63,19 +40,31 @@ pub fn load_console_sockets(
}
Ok(()) => csocketfd,
};
let console = "console";
let consolefd = match fcntl::open(
&*console,
fcntl::OFlag::O_NOCTTY | fcntl::OFlag::O_RDWR,
stat::Mode::empty(),
) {
Err(e) => {
if e != ::nix::Error::Sys(Errno::ENOENT) {
bail!("failed to open {}", console);
}
-1
}
Ok(fd) => fd,
Ok(csocketfd.into())
}

pub fn setup_console(console_fd: FileDescriptor) -> Result<()> {
// You can also access pty master, but it is better to use the API.
// ref. https://github.com/containerd/containerd/blob/261c107ffc4ff681bc73988f64e3f60c32233b37/vendor/github.com/containerd/go-runc/console.go#L139-L154
let openpty_result = nix::pty::openpty(None, None)?;
let pty_name: &[u8] = b"/dev/ptmx";
let iov = [uio::IoVec::from_slice(pty_name)];
let fds = [openpty_result.master];
let cmsg = socket::ControlMessage::ScmRights(&fds);
socket::sendmsg(
console_fd.as_raw_fd(),
&iov,
&[cmsg],
socket::MsgFlags::empty(),
None,
)?;

setsid()?;
if unsafe { libc::ioctl(openpty_result.slave, libc::TIOCSCTTY) } < 0 {
log::warn!("could not TIOCSCTTY");
};
Ok((csocketfd.into(), consolefd.into()))
let slave = FileDescriptor::from(openpty_result.slave);
stdio::connect_stdio(&slave, &slave, &slave).expect("could not dup tty to stderr");
close(console_fd.as_raw_fd())?;
Ok(())
}
11 changes: 4 additions & 7 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,10 @@ pub fn do_exec(path: impl AsRef<Path>, args: &[String], envs: &[String]) -> Resu
env::vars().for_each(|(key, _value)| std::env::remove_var(key));
// set env vars
envs.iter().for_each(|e| {
let mut split = e.split("=");
match split.next() {
Some(key) => {
let value: String = split.collect::<Vec<&str>>().join("=");
env::set_var(key, value)
}
None => {}
let mut split = e.split('=');
if let Some(key) = split.next() {
let value: String = split.collect::<Vec<&str>>().join("=");
env::set_var(key, value)
};
});

Expand Down