1extern crate mach;
2extern crate uuid;
3
4pub use mach::port::mach_port_t;
6
7use std::ffi::CString;
8use std::io::{Error, ErrorKind, Result};
9use std::mem;
10use std::ops::Drop;
11use std::os::unix::process::CommandExt;
12use std::process::{Command, Child};
13
14use mach::bootstrap::bootstrap_look_up;
15use mach::kern_return::{kern_return_t, KERN_SUCCESS};
16use mach::port::{MACH_PORT_NULL, MACH_PORT_RIGHT_RECEIVE};
17use mach::mach_port::{mach_port_allocate, mach_port_deallocate, mach_port_insert_right};
18use mach::message::{MACH_MSG_TYPE_MAKE_SEND, MACH_MSGH_BITS, MACH_MSG_TYPE_COPY_SEND,
19 MACH_MSGH_BITS_COMPLEX, MACH_RCV_MSG, MACH_MSG_TIMEOUT_NONE, mach_msg_send,
20 mach_msg, mach_msg_header_t, mach_msg_body_t, mach_msg_port_descriptor_t,
21 mach_msg_trailer_t};
22use mach::task::{TASK_BOOTSTRAP_PORT, task_get_special_port};
23use mach::traps::mach_task_self;
24use uuid::Uuid;
25
26macro_rules! ktry {
29 ($e:expr) => {{
30 let kr = $e;
31 if kr != KERN_SUCCESS {
32 return Err(Error::new(ErrorKind::Other,
33 format!("`{}` failed with return code {:x}",
34 stringify!($e), kr)));
35 }
36 }}
37}
38
39struct MachPort(mach_port_t);
41
42impl Drop for MachPort {
43 fn drop(&mut self) {
44 unsafe {
46 mach_port_deallocate(mach_task_self(), self.0);
47 }
48 }
49}
50
51#[allow(dead_code)]
53struct SendMessage {
54 header: mach_msg_header_t,
55 body: mach_msg_body_t,
56 task_port: mach_msg_port_descriptor_t,
57}
58
59#[allow(dead_code)]
61struct RecvMessage {
62 header: mach_msg_header_t,
63 body: mach_msg_body_t,
64 task_port: mach_msg_port_descriptor_t,
65 trailer: mach_msg_trailer_t,
67}
68
69extern "C" {
70 fn bootstrap_register2(bp: mach_port_t,
72 service_name: *const i8,
73 sp: mach_port_t,
74 flags: u64)
75 -> kern_return_t;
76}
79
80pub trait CommandSpawnWithTask {
83 fn spawn_get_task_port(&mut self) -> Result<(Child, mach_port_t)>;
86}
87
88impl CommandSpawnWithTask for Command {
89 fn spawn_get_task_port(&mut self) -> Result<(Child, mach_port_t)> {
90 let port = unsafe {
92 let mut port: mach_port_t = mem::uninitialized();
93 ktry!(mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &mut port));
94 let port = MachPort(port);
95
96 ktry!(mach_port_insert_right(mach_task_self(),
98 port.0,
99 port.0,
100 MACH_MSG_TYPE_MAKE_SEND));
101 port
102 };
103
104 let uuid = Uuid::new_v4().simple().to_string();
106 let name = CString::new(uuid).or(Err(Error::new(ErrorKind::Other, "CString")))?;
107 unsafe {
108 let mut bootstrap_port = mem::uninitialized();
109 ktry!(task_get_special_port(mach_task_self(),
110 TASK_BOOTSTRAP_PORT,
111 &mut bootstrap_port));
112 ktry!(bootstrap_register2(bootstrap_port, name.as_ptr(), port.0, 0));
113 }
114
115 let child = self.before_exec(move || {
116 unsafe {
117 let mut bootstrap_port: mach_port_t = mem::uninitialized();
120 ktry!(task_get_special_port(mach_task_self(),
121 TASK_BOOTSTRAP_PORT,
122 &mut bootstrap_port));
123
124 let mut parent_port: mach_port_t = mem::uninitialized();
125 ktry!(bootstrap_look_up(bootstrap_port, name.as_ptr(), &mut parent_port));
126 let parent_port = MachPort(parent_port);
127 let mut msg = SendMessage {
129 header: mach_msg_header_t {
130 msgh_bits: MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0) |
131 MACH_MSGH_BITS_COMPLEX,
132 msgh_size: mem::size_of::<SendMessage>() as u32,
133 msgh_remote_port: parent_port.0,
134 msgh_local_port: MACH_PORT_NULL,
135 msgh_voucher_port: MACH_PORT_NULL,
136 msgh_id: 0,
137 },
138 body: mach_msg_body_t { msgh_descriptor_count: 1 },
139 task_port: mach_msg_port_descriptor_t::new(mach_task_self(),
140 MACH_MSG_TYPE_COPY_SEND),
141 };
142 ktry!(mach_msg_send(&mut msg.header));
143 }
144 Ok(())
145 })
146 .spawn()?;
147 let child_task_port = unsafe {
149 let mut msg: RecvMessage = mem::uninitialized();
150 ktry!(mach_msg(&mut msg.header,
154 MACH_RCV_MSG,
155 0,
156 mem::size_of::<RecvMessage>() as u32,
157 port.0,
158 MACH_MSG_TIMEOUT_NONE,
159 MACH_PORT_NULL));
160 msg.task_port.name
163 };
164 Ok((child, child_task_port))
165 }
166}