1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
//! allow sub-programs to invoke arbitrary user-defined functions via a unix socket
use std::ffi::OsStr;
use std::fs;
use std::io;
use std::io::Write;
use std::os::unix::ffi::OsStrExt;
use std::os::unix::net::SocketAncillary;
use std::os::unix::net::UnixListener;
use std::os::unix::net::UnixStream;
use std::path::PathBuf;
use std::process::exit;
use std::sync::Arc;
use std::sync::Mutex;
use std::thread;
use crate::Session;
fn handle_server(session: Arc<Mutex<Session>>, stream: UnixStream) -> io::Result<()> {
todo!()
}
fn handle_client(stream: UnixStream) -> io::Result<()> {
todo!()
}
fn user_function_res(sock: &OsStr) -> io::Result<()> {
let sock = UnixStream::connect(sock)?;
let mut ancillary_buffer = [0; 128];
let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]);
ancillary.add_fds(&[0, 1, 2]);
let buf = [0; 8];
let mut bufs = &mut [io::IoSlice::new(&buf[..])][..];
sock.send_vectored_with_ancillary(bufs, &mut ancillary)?;
todo!()
}
pub fn maybe_run_defined_function() {
if let Some(program_name) = std::env::args_os().next() {
let program_name = program_name.as_bytes();
if !program_name.contains(&b'/') && program_name != b"pish" {
if let Some(socket) = std::env::var_os("PISH_SOCKET") {
if let Ok(stream) = UnixStream::connect(socket) {
let _ = handle_client(stream);
}
exit(-1);
}
}
}
}
fn unique_string() -> String {
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use std::process;
use std::time::{SystemTime, UNIX_EPOCH};
let pid = process::id();
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_nanos();
let mut hasher = DefaultHasher::new();
pid.hash(&mut hasher);
now.hash(&mut hasher);
let hash = hasher.finish();
let hex = format!("{:016x}", hash);
hex[..12.min(hex.len())].to_string()
}
fn unique_socket_path() -> PathBuf {
let mut socket_name = b"pish-cmd-".to_vec();
socket_name.extend_from_slice(&unique_string().as_bytes());
socket_name.extend_from_slice(b".sock");
let socket_path = crate::basedir::data_dir().join(OsStr::from_bytes(&socket_name));
socket_path
}
pub struct SocketRunning {
path: PathBuf,
}
#[must_use]
pub struct SocketDropper {
session: Arc<Mutex<Session>>,
}
impl Drop for SocketDropper {
fn drop(&mut self) {
// mark socket for closing by `take`ing the socket_running value
let session = &self.session;
let Ok(mut se) = session.lock() else { return };
let Some(sr) = se.socket_running.take() else {
return;
};
// connect to the socket for a brief moment to make it check that it should terminate
if let Ok(mut con) = UnixStream::connect(&sr.path) {
let _ = write!(con, "please shut down :))");
};
}
}
pub fn listen(session: Arc<Mutex<Session>>) -> SocketDropper {
let path = unique_socket_path();
{
let mut se = session.lock().unwrap();
assert!(se.socket_running.is_none());
se.socket_running = Some(SocketRunning { path: path.clone() });
}
let se = session.clone();
thread::spawn(move || {
struct SocketRemover(PathBuf);
impl Drop for SocketRemover {
fn drop(&mut self) {
let _ = fs::remove_file(&self.0);
}
}
let _socket_remover = SocketRemover(path.clone());
let listener = UnixListener::bind(path).unwrap();
let mut it = listener.incoming();
while let Some(stream) = it.next() {
match se.lock() {
Err(_) => break,
Ok(se) if se.socket_running.is_none() => break,
_ => (),
}
if let Ok(stream) = stream {
let se = se.clone();
thread::spawn(move || handle_server(se, stream));
}
}
});
SocketDropper { session }
}
|