1 #![deny(unsafe_op_in_unsafe_fn)]
3 use std
::ffi
::{OsStr, OsString}
;
4 use std
::future
::Future
;
6 use std
::io
::{stderr, stdout, Write}
;
7 use std
::os
::unix
::ffi
::OsStrExt
;
9 use anyhow
::{bail, format_err, Error}
;
10 use nix
::sys
::socket
::UnixAddr
;
30 use crate::io
::seq_packet
::SeqPacketListener
;
33 pub fn spawn(fut
: impl Future
<Output
= ()> + Send
+ '
static) {
37 fn usage(status
: i32, program
: &OsStr
, out
: &mut dyn Write
) -> ! {
38 let _
= out
.write_all("usage: ".as_bytes());
39 let _
= out
.write_all(program
.as_bytes());
40 let _
= out
.write_all(
42 "[options] SOCKET_PATH\n",
44 " -h, --help show this help message\n",
46 run as systemd daemon (use sd_notify() when ready to accept connections)\n",
50 std
::process
::exit(status
);
54 let mut args
= std
::env
::args_os();
55 let program
= args
.next().unwrap(); // program name always exists
57 let mut use_sd_notify
= false;
60 let mut nonopt_arg
= |arg
: OsString
| {
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());
71 for arg
in &mut args
{
72 if arg
== "-h" || arg
== "--help" {
73 usage(0, &program
, &mut stdout());
78 } else if arg
== "--system" {
81 if arg
.as_bytes().starts_with(b
"-") {
82 let _
= stderr().write_all(b
"unexpected option: ");
83 let _
= stderr().write_all(arg
.as_bytes());
84 let _
= stderr().write_all(b
"\n");
85 usage(1, &program
, &mut stderr());
92 for arg
in &mut args
{
96 let path
= match path
{
99 eprintln
!("missing path");
100 usage(1, &program
, &mut stderr());
104 let cpus
= num_cpus
::get();
106 let rt
= tokio
::runtime
::Builder
::new_multi_thread()
108 .worker_threads(cpus
.clamp(2, 4))
110 .expect("failed to spawn tokio runtime");
112 if let Err(err
) = rt
.block_on(do_main(use_sd_notify
, path
)) {
113 eprintln
!("error: {err}");
114 std
::process
::exit(1);
118 async
fn do_main(use_sd_notify
: bool
, socket_path
: OsString
) -> Result
<(), Error
> {
119 match std
::fs
::remove_file(&socket_path
) {
121 Err(ref e
) if e
.kind() == StdIo
::ErrorKind
::NotFound
=> (), // Ok
122 Err(e
) => bail
!("failed to remove previous socket: {}", e
),
126 UnixAddr
::new(socket_path
.as_os_str()).expect("cannot create struct sockaddr_un?");
128 let mut listener
= SeqPacketListener
::bind(&address
)
129 .map_err(|e
| format_err
!("failed to create listening socket: {}", e
))?
;
136 let client
= listener
.accept().await?
;
137 let client
= client
::Client
::new(client
);
138 spawn(client
.main());
142 #[link(name = "systemd")]
144 fn sd_notify(unset_environment
: libc
::c_int
, state
: *const libc
::c_char
) -> libc
::c_int
;
147 fn notify_systemd() -> StdIo
::Result
<()> {
148 let err
= unsafe { sd_notify(0, c_str!("READY=1\n").as_ptr()) }
;
152 Err(StdIo
::Error
::from_raw_os_error(-err
))