##// 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 // Copyright 2018 Yuya Nishihara <yuya@tcha.org>
1 // Copyright 2018 Yuya Nishihara <yuya@tcha.org>
2 //
2 //
3 // This software may be used and distributed according to the terms of the
3 // This software may be used and distributed according to the terms of the
4 // GNU General Public License version 2 or any later version.
4 // GNU General Public License version 2 or any later version.
5
5
6 extern crate chg;
6 extern crate chg;
7 extern crate futures;
7 extern crate futures;
8 extern crate tokio;
8 extern crate tokio;
9 extern crate tokio_hglib;
9 extern crate tokio_hglib;
10
10
11 use chg::{ChgClientExt, ChgUiHandler};
11 use chg::{ChgClientExt, ChgUiHandler};
12 use chg::locator;
12 use chg::locator;
13 use chg::procutil;
13 use futures::sync::oneshot;
14 use futures::sync::oneshot;
14 use std::env;
15 use std::env;
15 use std::io;
16 use std::io;
16 use std::process;
17 use std::process;
17 use tokio::prelude::*;
18 use tokio::prelude::*;
18 use tokio_hglib::UnixClient;
19 use tokio_hglib::UnixClient;
19
20
20 fn main() {
21 fn main() {
21 let code = run().unwrap_or_else(|err| {
22 let code = run().unwrap_or_else(|err| {
22 eprintln!("chg: abort: {}", err);
23 eprintln!("chg: abort: {}", err);
23 255
24 255
24 });
25 });
25 process::exit(code);
26 process::exit(code);
26 }
27 }
27
28
28 fn run() -> io::Result<i32> {
29 fn run() -> io::Result<i32> {
29 let current_dir = env::current_dir()?;
30 let current_dir = env::current_dir()?;
30 let sock_path = locator::prepare_server_socket_path()?;
31 let sock_path = locator::prepare_server_socket_path()?;
31 let handler = ChgUiHandler::new();
32 let handler = ChgUiHandler::new();
32 let (result_tx, result_rx) = oneshot::channel();
33 let (result_tx, result_rx) = oneshot::channel();
33 let fut = UnixClient::connect(sock_path)
34 let fut = UnixClient::connect(sock_path)
34 .and_then(|client| {
35 .and_then(|client| {
35 client.set_current_dir(current_dir)
36 client.set_current_dir(current_dir)
36 })
37 })
37 .and_then(|client| {
38 .and_then(|client| {
38 client.attach_io(io::stdin(), io::stdout(), io::stderr())
39 client.attach_io(io::stdin(), io::stdout(), io::stderr())
39 })
40 })
40 .and_then(|client| {
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 client.run_command_chg(handler, env::args_os().skip(1))
48 client.run_command_chg(handler, env::args_os().skip(1))
42 })
49 })
43 .map(|(_client, _handler, code)| {
50 .map(|(_client, _handler, code)| {
51 procutil::restore_signal_handler_once()?;
44 Ok(code)
52 Ok(code)
45 })
53 })
46 .or_else(|err| Ok(Err(err))) // pass back error to caller
54 .or_else(|err| Ok(Err(err))) // pass back error to caller
47 .map(|res| result_tx.send(res).unwrap());
55 .map(|res| result_tx.send(res).unwrap());
48 tokio::run(fut);
56 tokio::run(fut);
49 result_rx.wait().unwrap_or(Err(io::Error::new(io::ErrorKind::Other,
57 result_rx.wait().unwrap_or(Err(io::Error::new(io::ErrorKind::Other,
50 "no exit code set")))
58 "no exit code set")))
51 }
59 }
@@ -1,43 +1,87
1 // Copyright 2018 Yuya Nishihara <yuya@tcha.org>
1 // Copyright 2018 Yuya Nishihara <yuya@tcha.org>
2 //
2 //
3 // This software may be used and distributed according to the terms of the
3 // This software may be used and distributed according to the terms of the
4 // GNU General Public License version 2 or any later version.
4 // GNU General Public License version 2 or any later version.
5
5
6 //! Low-level utility for signal and process handling.
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 use std::io;
9 use std::io;
10 use std::os::unix::io::RawFd;
10 use std::os::unix::io::RawFd;
11 use std::sync;
11
12
12 #[link(name = "procutil", kind = "static")]
13 #[link(name = "procutil", kind = "static")]
13 extern "C" {
14 extern "C" {
14 // sendfds.c
15 // sendfds.c
15 fn sendfds(sockfd: c_int, fds: *const c_int, fdlen: size_t) -> ssize_t;
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 /// Returns the effective uid of the current process.
23 /// Returns the effective uid of the current process.
19 pub fn get_effective_uid() -> u32 {
24 pub fn get_effective_uid() -> u32 {
20 unsafe { libc::geteuid() }
25 unsafe { libc::geteuid() }
21 }
26 }
22
27
23 /// Changes the given fd to blocking mode.
28 /// Changes the given fd to blocking mode.
24 pub fn set_blocking_fd(fd: RawFd) -> io::Result<()> {
29 pub fn set_blocking_fd(fd: RawFd) -> io::Result<()> {
25 let flags = unsafe { libc::fcntl(fd, libc::F_GETFL) };
30 let flags = unsafe { libc::fcntl(fd, libc::F_GETFL) };
26 if flags < 0 {
31 if flags < 0 {
27 return Err(io::Error::last_os_error());
32 return Err(io::Error::last_os_error());
28 }
33 }
29 let r = unsafe { libc::fcntl(fd, libc::F_SETFL, flags & !libc::O_NONBLOCK) };
34 let r = unsafe { libc::fcntl(fd, libc::F_SETFL, flags & !libc::O_NONBLOCK) };
30 if r < 0 {
35 if r < 0 {
31 return Err(io::Error::last_os_error())
36 return Err(io::Error::last_os_error())
32 }
37 }
33 Ok(())
38 Ok(())
34 }
39 }
35
40
36 /// Sends file descriptors via the given socket.
41 /// Sends file descriptors via the given socket.
37 pub fn send_raw_fds(sock_fd: RawFd, fds: &[RawFd]) -> io::Result<()> {
42 pub fn send_raw_fds(sock_fd: RawFd, fds: &[RawFd]) -> io::Result<()> {
38 let r = unsafe { sendfds(sock_fd, fds.as_ptr(), fds.len() as size_t) };
43 let r = unsafe { sendfds(sock_fd, fds.as_ptr(), fds.len() as size_t) };
39 if r < 0 {
44 if r < 0 {
40 return Err(io::Error::last_os_error());
45 return Err(io::Error::last_os_error());
41 }
46 }
42 Ok(())
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