1 use std
::ffi
::{OsStr, OsString}
;
2 use std
::future
::Future
;
4 use std
::io
::{stderr, stdout, Write}
;
5 use std
::os
::unix
::ffi
::OsStrExt
;
7 use anyhow
::{bail, format_err, Error}
;
8 use nix
::sys
::socket
::SockAddr
;
29 use crate::io
::seq_packet
::SeqPacketListener
;
31 pub fn spawn(fut
: impl Future
<Output
= ()> + Send
+ '
static) {
35 fn usage(status
: i32, program
: &OsStr
, out
: &mut dyn Write
) -> ! {
36 let _
= out
.write_all("usage: ".as_bytes());
37 let _
= out
.write_all(program
.as_bytes());
38 let _
= out
.write_all(
40 "[options] SOCKET_PATH\n",
42 " -h, --help show this help message\n",
44 run as systemd daemon (use sd_notify() when ready to accept connections)\n",
48 std
::process
::exit(status
);
52 let mut args
= std
::env
::args_os();
53 let program
= args
.next().unwrap(); // program name always exists
55 let mut use_sd_notify
= false;
58 let mut nonopt_arg
= |arg
: OsString
| {
60 let _
= stderr().write_all(b
"unexpected extra parameter: ");
61 let _
= stderr().write_all(arg
.as_bytes());
62 let _
= stderr().write_all(b
"\n");
63 usage(1, &program
, &mut stderr());
69 for arg
in &mut args
{
70 if arg
== "-h" || arg
== "--help" {
71 usage(0, &program
, &mut stdout());
76 } else if arg
== "--system" {
79 if arg
.as_bytes().starts_with(b
"-") {
80 let _
= stderr().write_all(b
"unexpected option: ");
81 let _
= stderr().write_all(arg
.as_bytes());
82 let _
= stderr().write_all(b
"\n");
83 usage(1, &program
, &mut stderr());
90 for arg
in &mut args
{
95 let path
= match path
{
98 eprintln
!("missing path");
99 usage(1, &program
, &mut stderr());
103 let rt
= tokio
::runtime
::Runtime
::new().expect("failed to spawn tokio runtime");
105 if let Err(err
) = rt
.block_on(do_main(use_sd_notify
, path
)) {
106 eprintln
!("error: {}", err
);
107 std
::process
::exit(1);
111 async
fn do_main(use_sd_notify
: bool
, socket_path
: OsString
) -> Result
<(), Error
> {
112 match std
::fs
::remove_file(&socket_path
) {
114 Err(ref e
) if e
.kind() == StdIo
::ErrorKind
::NotFound
=> (), // Ok
115 Err(e
) => bail
!("failed to remove previous socket: {}", e
),
119 SockAddr
::new_unix(socket_path
.as_os_str()).expect("cannot create struct sockaddr_un?");
121 let mut listener
= SeqPacketListener
::bind(&address
)
122 .map_err(|e
| format_err
!("failed to create listening socket: {}", e
))?
;
129 let client
= listener
.accept().await?
;
130 let client
= client
::Client
::new(client
);
131 spawn(client
.main());
135 #[link(name = "systemd")]
137 fn sd_notify(unset_environment
: libc
::c_int
, state
: *const libc
::c_char
) -> libc
::c_int
;
140 fn notify_systemd() -> StdIo
::Result
<()> {
141 let err
= unsafe { sd_notify(0, c_str!("READY=1\n").as_ptr()) }
;
145 Err(StdIo
::Error
::from_raw_os_error(-err
))