]> git.proxmox.com Git - pve-lxc-syscalld.git/blobdiff - src/main.rs
update to tokio 1.0
[pve-lxc-syscalld.git] / src / main.rs
index 301a6ae651d335d2b3d30f55302883facad53f37..ca4366d81b3f41dfc9e84ec0121938d22b762f7b 100644 (file)
@@ -1,7 +1,10 @@
+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 anyhow::{bail, format_err, Error};
 use nix::sys::socket::SockAddr;
 
 #[macro_use]
@@ -11,7 +14,6 @@ pub mod apparmor;
 pub mod capability;
 pub mod client;
 pub mod error;
-pub mod executor;
 pub mod fork;
 pub mod io;
 pub mod lxcseccomp;
@@ -26,34 +28,87 @@ pub mod tools;
 
 use crate::io::seq_packet::SeqPacketListener;
 
-static mut EXECUTOR: *mut executor::ThreadPool = std::ptr::null_mut();
-
-pub fn executor() -> &'static executor::ThreadPool {
-    unsafe { &*EXECUTOR }
+pub fn spawn(fut: impl Future<Output = ()> + Send + 'static) {
+    tokio::spawn(fut);
 }
 
-pub fn spawn(fut: impl Future<Output = ()> + Send + 'static) {
-    executor().spawn_ok(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() {
-    let mut executor = executor::ThreadPool::new().expect("spawning worker threadpool");
-    unsafe {
-        EXECUTOR = &mut executor;
+    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);
     }
-    std::sync::atomic::fence(std::sync::atomic::Ordering::Release);
+    drop(nonopt_arg);
 
-    if let Err(err) = executor.run(do_main()) {
+    let path = match path {
+        Some(path) => path,
+        None => {
+            eprintln!("missing path");
+            usage(1, &program, &mut stderr());
+        }
+    };
+
+    let 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);
     }
 }
 
-async fn do_main() -> Result<(), Error> {
-    let socket_path = std::env::args_os()
-        .nth(1)
-        .ok_or_else(|| format_err!("missing parameter: socket path to listen on"))?;
-
+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() == StdIo::ErrorKind::NotFound => (), // Ok
@@ -65,9 +120,28 @@ async fn do_main() -> Result<(), Error> {
 
     let mut listener = SeqPacketListener::bind(&address)
         .map_err(|e| format_err!("failed to create listening socket: {}", e))?;
+
+    if use_sd_notify {
+        notify_systemd()?;
+    }
+
     loop {
         let client = listener.accept().await?;
         let client = client::Client::new(client);
         spawn(client.main());
     }
 }
+
+#[link(name = "systemd")]
+extern "C" {
+    fn sd_notify(unset_environment: libc::c_int, state: *const libc::c_char) -> libc::c_int;
+}
+
+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))
+    }
+}