-#![feature(async_await)]
-
-use std::io;
+use std::ffi::{OsStr, OsString};
+use std::future::Future;
+use std::io as StdIo;
+use std::io::{stderr, stdout, Write};
+use std::os::unix::ffi::OsStrExt;
use failure::{bail, format_err, Error};
use nix::sys::socket::SockAddr;
+#[macro_use]
+mod macros;
+
+pub mod apparmor;
+pub mod capability;
+pub mod client;
+pub mod error;
+pub mod fork;
+pub mod io;
pub mod lxcseccomp;
+pub mod nsfd;
+pub mod poll_fn;
+pub mod process;
pub mod seccomp;
-pub mod socket;
+pub mod sys_mknod;
+pub mod sys_quotactl;
+pub mod syscall;
pub mod tools;
-use socket::{AsyncSeqPacketSocket, SeqPacketListener};
+use crate::io::seq_packet::SeqPacketListener;
-const SOCKET_DIR: &'static str = "/run/pve";
-const SOCKET_PATH: &'static str = "/run/pve/lxc-syscalld.sock";
+pub fn spawn(fut: impl Future<Output = ()> + Send + 'static) {
+ tokio::spawn(fut);
+}
+
+fn usage(status: i32, program: &OsStr, out: &mut dyn Write) -> ! {
+ let _ = out.write_all("usage: ".as_bytes());
+ let _ = out.write_all(program.as_bytes());
+ let _ = out.write_all(
+ concat!(
+ "[options] SOCKET_PATH\n",
+ "options:\n",
+ " -h, --help show this help message\n",
+ " --system \
+ run as systemd daemon (use sd_notify() when ready to accept connections)\n",
+ )
+ .as_bytes(),
+ );
+ std::process::exit(status);
+}
fn main() {
- if let Err(err) = run() {
+ let mut args = std::env::args_os();
+ let program = args.next().unwrap(); // program name always exists
+
+ let mut use_sd_notify = false;
+ let mut path = None;
+
+ let mut nonopt_arg = |arg: OsString| {
+ if path.is_some() {
+ let _ = stderr().write_all(b"unexpected extra parameter: ");
+ let _ = stderr().write_all(arg.as_bytes());
+ let _ = stderr().write_all(b"\n");
+ usage(1, &program, &mut stderr());
+ }
+
+ path = Some(arg);
+ };
+
+ for arg in &mut args {
+ if arg == "-h" || arg == "--help" {
+ usage(0, &program, &mut stdout());
+ }
+
+ if arg == "--" {
+ break;
+ } else if arg == "--system" {
+ use_sd_notify = true;
+ } else {
+ if arg.as_bytes().starts_with(b"-") {
+ let _ = stderr().write_all(b"unexpected option: ");
+ let _ = stderr().write_all(arg.as_bytes());
+ let _ = stderr().write_all(b"\n");
+ usage(1, &program, &mut stderr());
+ }
+
+ nonopt_arg(arg);
+ }
+ }
+
+ for arg in &mut args {
+ nonopt_arg(arg);
+ }
+ drop(nonopt_arg);
+
+ let path = match path {
+ Some(path) => path,
+ None => {
+ eprintln!("missing path");
+ usage(1, &program, &mut stderr());
+ }
+ };
+
+ let mut rt = tokio::runtime::Runtime::new().expect("failed to spawn tokio runtime");
+
+ if let Err(err) = rt.block_on(do_main(use_sd_notify, path)) {
eprintln!("error: {}", err);
std::process::exit(1);
}
}
-fn run() -> Result<(), Error> {
- let _ = std::fs::create_dir(SOCKET_DIR);
-
- match std::fs::remove_file(SOCKET_PATH) {
+async fn do_main(use_sd_notify: bool, socket_path: OsString) -> Result<(), Error> {
+ match std::fs::remove_file(&socket_path) {
Ok(_) => (),
- Err(ref e) if e.kind() == io::ErrorKind::NotFound => (), // Ok
+ Err(ref e) if e.kind() == StdIo::ErrorKind::NotFound => (), // Ok
Err(e) => bail!("failed to remove previous socket: {}", e),
}
- tokio::run(async_run());
+ let address =
+ SockAddr::new_unix(socket_path.as_os_str()).expect("cannot create struct sockaddr_un?");
- Ok(())
-}
+ let mut listener = SeqPacketListener::bind(&address)
+ .map_err(|e| format_err!("failed to create listening socket: {}", e))?;
-async fn async_run() {
- if let Err(err) = async_run_do().await {
- eprintln!("error accepting clients, bailing out: {}", err);
+ if use_sd_notify {
+ notify_systemd()?;
}
-}
-async fn async_run_do() -> Result<(), Error> {
- let address = SockAddr::new_unix(SOCKET_PATH).expect("cannot create struct sockaddr_un?");
-
- let mut listener = SeqPacketListener::bind(&address)
- .map_err(|e| format_err!("failed to create listening socket: {}", e))?;
loop {
let client = listener.accept().await?;
- tokio::spawn(handle_client(client));
+ let client = client::Client::new(client);
+ spawn(client.main());
}
}
-async fn handle_client(client: AsyncSeqPacketSocket) {
- if let Err(err) = handle_client_do(client).await {
- eprintln!(
- "error communicating with client, dropping connection: {}",
- err
- );
- }
+#[link(name = "systemd")]
+extern "C" {
+ fn sd_notify(unset_environment: libc::c_int, state: *const libc::c_char) -> libc::c_int;
}
-async fn handle_client_do(mut client: AsyncSeqPacketSocket) -> Result<(), Error> {
- let mut msgbuf = lxcseccomp::ProxyMessageBuffer::new(64)
- .map_err(|e| format_err!("failed to allocate proxy message buffer: {}", e))?;
-
- loop {
- let (size, _fds) = client.recv_fds(unsafe { msgbuf.new_mut() }, 1).await?;
- if size == 0 {
- println!("client disconnected");
- break;
- }
-
- msgbuf.set_len(size)?;
-
- let req = msgbuf.request();
- println!("Received request for syscall {}", req.data.nr);
-
- let resp = msgbuf.response_mut();
- resp.val = 0;
- resp.error = -libc::ENOENT;
-
- client.sendmsg(msgbuf.as_buf_no_cookie()).await?;
+fn notify_systemd() -> StdIo::Result<()> {
+ let err = unsafe { sd_notify(0, c_str!("READY=1\n").as_ptr()) };
+ if err >= 0 {
+ Ok(())
+ } else {
+ Err(StdIo::Error::from_raw_os_error(-err))
}
-
- Ok(())
}