]>
Commit | Line | Data |
---|---|---|
4032c669 WB |
1 | #![deny(unsafe_op_in_unsafe_fn)] |
2 | ||
d54e9e5a | 3 | use std::ffi::{OsStr, OsString}; |
9aa2a15a | 4 | use std::future::Future; |
8dd26985 | 5 | use std::io as StdIo; |
d54e9e5a WB |
6 | use std::io::{stderr, stdout, Write}; |
7 | use std::os::unix::ffi::OsStrExt; | |
9cffeac4 | 8 | |
8150a439 | 9 | use anyhow::{bail, format_err, Error}; |
b8cb8723 | 10 | use nix::sys::socket::UnixAddr; |
9cffeac4 | 11 | |
9aa2a15a WB |
12 | #[macro_use] |
13 | mod macros; | |
14 | ||
42f25756 | 15 | pub mod apparmor; |
738dbfbe | 16 | pub mod capability; |
e420f6f9 WB |
17 | pub mod client; |
18 | pub mod fork; | |
8dd26985 | 19 | pub mod io; |
9cffeac4 | 20 | pub mod lxcseccomp; |
e420f6f9 | 21 | pub mod nsfd; |
a22aece0 | 22 | pub mod poll_fn; |
3bbd1db0 | 23 | pub mod process; |
9cffeac4 | 24 | pub mod seccomp; |
e420f6f9 | 25 | pub mod sys_mknod; |
3e69a521 | 26 | pub mod sys_quotactl; |
c95be5f6 | 27 | pub mod syscall; |
9cffeac4 WB |
28 | pub mod tools; |
29 | ||
8dd26985 | 30 | use crate::io::seq_packet::SeqPacketListener; |
9aa2a15a | 31 | |
7d20b692 | 32 | #[track_caller] |
9aa2a15a | 33 | pub fn spawn(fut: impl Future<Output = ()> + Send + 'static) { |
5bd0c562 | 34 | tokio::spawn(fut); |
9aa2a15a WB |
35 | } |
36 | ||
86ee36e8 | 37 | fn usage(status: i32, program: &OsStr, out: &mut dyn Write) -> ! { |
d54e9e5a WB |
38 | let _ = out.write_all("usage: ".as_bytes()); |
39 | let _ = out.write_all(program.as_bytes()); | |
40 | let _ = out.write_all( | |
41 | concat!( | |
42 | "[options] SOCKET_PATH\n", | |
43 | "options:\n", | |
44 | " -h, --help show this help message\n", | |
45 | " --system \ | |
46 | run as systemd daemon (use sd_notify() when ready to accept connections)\n", | |
86ee36e8 WB |
47 | ) |
48 | .as_bytes(), | |
d54e9e5a WB |
49 | ); |
50 | std::process::exit(status); | |
51 | } | |
52 | ||
9aa2a15a | 53 | fn main() { |
d54e9e5a WB |
54 | let mut args = std::env::args_os(); |
55 | let program = args.next().unwrap(); // program name always exists | |
56 | ||
57 | let mut use_sd_notify = false; | |
58 | let mut path = None; | |
59 | ||
750b5cb3 WB |
60 | let mut nonopt_arg = |arg: OsString| { |
61 | if path.is_some() { | |
62 | let _ = stderr().write_all(b"unexpected extra parameter: "); | |
63 | let _ = stderr().write_all(arg.as_bytes()); | |
64 | let _ = stderr().write_all(b"\n"); | |
65 | usage(1, &program, &mut stderr()); | |
66 | } | |
67 | ||
68 | path = Some(arg); | |
69 | }; | |
70 | ||
d54e9e5a WB |
71 | for arg in &mut args { |
72 | if arg == "-h" || arg == "--help" { | |
73 | usage(0, &program, &mut stdout()); | |
74 | } | |
75 | ||
76 | if arg == "--" { | |
77 | break; | |
78 | } else if arg == "--system" { | |
79 | use_sd_notify = true; | |
80 | } else { | |
750b5cb3 | 81 | if arg.as_bytes().starts_with(b"-") { |
d54e9e5a WB |
82 | let _ = stderr().write_all(b"unexpected option: "); |
83 | let _ = stderr().write_all(arg.as_bytes()); | |
750b5cb3 | 84 | let _ = stderr().write_all(b"\n"); |
d54e9e5a WB |
85 | usage(1, &program, &mut stderr()); |
86 | } | |
87 | ||
750b5cb3 | 88 | nonopt_arg(arg); |
d54e9e5a WB |
89 | } |
90 | } | |
91 | ||
750b5cb3 WB |
92 | for arg in &mut args { |
93 | nonopt_arg(arg); | |
94 | } | |
750b5cb3 | 95 | |
d54e9e5a WB |
96 | let path = match path { |
97 | Some(path) => path, | |
98 | None => { | |
99 | eprintln!("missing path"); | |
100 | usage(1, &program, &mut stderr()); | |
101 | } | |
102 | }; | |
103 | ||
53d40cee WB |
104 | let cpus = num_cpus::get(); |
105 | ||
106 | let rt = tokio::runtime::Builder::new_multi_thread() | |
107 | .enable_all() | |
d463e3b4 | 108 | .worker_threads(cpus.clamp(2, 4)) |
53d40cee WB |
109 | .build() |
110 | .expect("failed to spawn tokio runtime"); | |
e420f6f9 | 111 | |
d54e9e5a | 112 | if let Err(err) = rt.block_on(do_main(use_sd_notify, path)) { |
d463e3b4 | 113 | eprintln!("error: {err}"); |
9cffeac4 WB |
114 | std::process::exit(1); |
115 | } | |
116 | } | |
117 | ||
d54e9e5a | 118 | async fn do_main(use_sd_notify: bool, socket_path: OsString) -> Result<(), Error> { |
571dbe03 | 119 | match std::fs::remove_file(&socket_path) { |
9cffeac4 | 120 | Ok(_) => (), |
8dd26985 | 121 | Err(ref e) if e.kind() == StdIo::ErrorKind::NotFound => (), // Ok |
9cffeac4 WB |
122 | Err(e) => bail!("failed to remove previous socket: {}", e), |
123 | } | |
124 | ||
571dbe03 | 125 | let address = |
b8cb8723 | 126 | UnixAddr::new(socket_path.as_os_str()).expect("cannot create struct sockaddr_un?"); |
9cffeac4 | 127 | |
8dd26985 | 128 | let mut listener = SeqPacketListener::bind(&address) |
9cffeac4 | 129 | .map_err(|e| format_err!("failed to create listening socket: {}", e))?; |
d54e9e5a WB |
130 | |
131 | if use_sd_notify { | |
132 | notify_systemd()?; | |
133 | } | |
134 | ||
9cffeac4 WB |
135 | loop { |
136 | let client = listener.accept().await?; | |
e420f6f9 | 137 | let client = client::Client::new(client); |
9aa2a15a | 138 | spawn(client.main()); |
9cffeac4 WB |
139 | } |
140 | } | |
d54e9e5a WB |
141 | |
142 | #[link(name = "systemd")] | |
143 | extern "C" { | |
144 | fn sd_notify(unset_environment: libc::c_int, state: *const libc::c_char) -> libc::c_int; | |
145 | } | |
146 | ||
147 | fn notify_systemd() -> StdIo::Result<()> { | |
148 | let err = unsafe { sd_notify(0, c_str!("READY=1\n").as_ptr()) }; | |
7bb69bd3 | 149 | if err >= 0 { |
d54e9e5a WB |
150 | Ok(()) |
151 | } else { | |
152 | Err(StdIo::Error::from_raw_os_error(-err)) | |
153 | } | |
154 | } |