##// END OF EJS Templates
rust-chg: install signal handlers to forward signals to server...
Yuya Nishihara -
r40156:89742f1f default
parent child Browse files
Show More
@@ -1,51 +1,59
1 1 // Copyright 2018 Yuya Nishihara <yuya@tcha.org>
2 2 //
3 3 // This software may be used and distributed according to the terms of the
4 4 // GNU General Public License version 2 or any later version.
5 5
6 6 extern crate chg;
7 7 extern crate futures;
8 8 extern crate tokio;
9 9 extern crate tokio_hglib;
10 10
11 11 use chg::{ChgClientExt, ChgUiHandler};
12 12 use chg::locator;
13 use chg::procutil;
13 14 use futures::sync::oneshot;
14 15 use std::env;
15 16 use std::io;
16 17 use std::process;
17 18 use tokio::prelude::*;
18 19 use tokio_hglib::UnixClient;
19 20
20 21 fn main() {
21 22 let code = run().unwrap_or_else(|err| {
22 23 eprintln!("chg: abort: {}", err);
23 24 255
24 25 });
25 26 process::exit(code);
26 27 }
27 28
28 29 fn run() -> io::Result<i32> {
29 30 let current_dir = env::current_dir()?;
30 31 let sock_path = locator::prepare_server_socket_path()?;
31 32 let handler = ChgUiHandler::new();
32 33 let (result_tx, result_rx) = oneshot::channel();
33 34 let fut = UnixClient::connect(sock_path)
34 35 .and_then(|client| {
35 36 client.set_current_dir(current_dir)
36 37 })
37 38 .and_then(|client| {
38 39 client.attach_io(io::stdin(), io::stdout(), io::stderr())
39 40 })
40 41 .and_then(|client| {
42 let pid = client.server_spec().process_id.unwrap();
43 let pgid = client.server_spec().process_group_id;
44 procutil::setup_signal_handler_once(pid, pgid)?;
45 Ok(client)
46 })
47 .and_then(|client| {
41 48 client.run_command_chg(handler, env::args_os().skip(1))
42 49 })
43 50 .map(|(_client, _handler, code)| {
51 procutil::restore_signal_handler_once()?;
44 52 Ok(code)
45 53 })
46 54 .or_else(|err| Ok(Err(err))) // pass back error to caller
47 55 .map(|res| result_tx.send(res).unwrap());
48 56 tokio::run(fut);
49 57 result_rx.wait().unwrap_or(Err(io::Error::new(io::ErrorKind::Other,
50 58 "no exit code set")))
51 59 }
@@ -1,43 +1,87
1 1 // Copyright 2018 Yuya Nishihara <yuya@tcha.org>
2 2 //
3 3 // This software may be used and distributed according to the terms of the
4 4 // GNU General Public License version 2 or any later version.
5 5
6 6 //! Low-level utility for signal and process handling.
7 7
8 use libc::{self, c_int, size_t, ssize_t};
8 use libc::{self, c_int, pid_t, size_t, ssize_t};
9 9 use std::io;
10 10 use std::os::unix::io::RawFd;
11 use std::sync;
11 12
12 13 #[link(name = "procutil", kind = "static")]
13 14 extern "C" {
14 15 // sendfds.c
15 16 fn sendfds(sockfd: c_int, fds: *const c_int, fdlen: size_t) -> ssize_t;
17
18 // sighandlers.c
19 fn setupsignalhandler(pid: pid_t, pgid: pid_t) -> c_int;
20 fn restoresignalhandler() -> c_int;
16 21 }
17 22
18 23 /// Returns the effective uid of the current process.
19 24 pub fn get_effective_uid() -> u32 {
20 25 unsafe { libc::geteuid() }
21 26 }
22 27
23 28 /// Changes the given fd to blocking mode.
24 29 pub fn set_blocking_fd(fd: RawFd) -> io::Result<()> {
25 30 let flags = unsafe { libc::fcntl(fd, libc::F_GETFL) };
26 31 if flags < 0 {
27 32 return Err(io::Error::last_os_error());
28 33 }
29 34 let r = unsafe { libc::fcntl(fd, libc::F_SETFL, flags & !libc::O_NONBLOCK) };
30 35 if r < 0 {
31 36 return Err(io::Error::last_os_error())
32 37 }
33 38 Ok(())
34 39 }
35 40
36 41 /// Sends file descriptors via the given socket.
37 42 pub fn send_raw_fds(sock_fd: RawFd, fds: &[RawFd]) -> io::Result<()> {
38 43 let r = unsafe { sendfds(sock_fd, fds.as_ptr(), fds.len() as size_t) };
39 44 if r < 0 {
40 45 return Err(io::Error::last_os_error());
41 46 }
42 47 Ok(())
43 48 }
49
50 static SETUP_SIGNAL_HANDLER: sync::Once = sync::Once::new();
51 static RESTORE_SIGNAL_HANDLER: sync::Once = sync::Once::new();
52
53 /// Installs signal handlers to forward signals to the server.
54 ///
55 /// # Safety
56 ///
57 /// This touches global states, and thus synchronized as a one-time
58 /// initialization function.
59 pub fn setup_signal_handler_once(pid: u32, pgid: Option<u32>) -> io::Result<()> {
60 let pid_signed = pid as i32;
61 let pgid_signed = pgid.map(|n| n as i32).unwrap_or(0);
62 let mut r = 0;
63 SETUP_SIGNAL_HANDLER.call_once(|| {
64 r = unsafe { setupsignalhandler(pid_signed, pgid_signed) };
65 });
66 if r < 0 {
67 return Err(io::Error::last_os_error());
68 }
69 Ok(())
70 }
71
72 /// Restores the original signal handlers.
73 ///
74 /// # Safety
75 ///
76 /// This touches global states, and thus synchronized as a one-time
77 /// initialization function.
78 pub fn restore_signal_handler_once() -> io::Result<()> {
79 let mut r = 0;
80 RESTORE_SIGNAL_HANDLER.call_once(|| {
81 r = unsafe { restoresignalhandler() };
82 });
83 if r < 0 {
84 return Err(io::Error::last_os_error());
85 }
86 Ok(())
87 }
General Comments 0
You need to be logged in to leave comments. Login now