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
mod pty;
mod err;
use ::descriptor::Descriptor;
use ::libc;
pub use self::err::{ForkError, Result};
pub use self::pty::{Master, MasterError};
pub use self::pty::{Slave, SlaveError};
use std::ffi::CString;
#[derive(Debug)]
pub enum Fork {
Parent(libc::pid_t, Master),
Child(Slave),
}
impl Fork {
pub fn new(path: &'static str) -> Result<Self> {
match Master::new(CString::new(path).ok().unwrap_or_default().as_ptr()) {
Err(cause) => Err(ForkError::BadMaster(cause)),
Ok(master) => unsafe {
if let Some(cause) = master.grantpt().err().or(master.unlockpt().err()) {
Err(ForkError::BadMaster(cause))
} else {
match libc::fork() {
-1 => Err(ForkError::Failure),
0 => {
match master.ptsname() {
Err(cause) => Err(ForkError::BadMaster(cause)),
Ok(name) => Fork::from_pts(name),
}
}
pid => Ok(Fork::Parent(pid, master)),
}
}
},
}
}
fn from_pts(ptsname: *const ::libc::c_char) -> Result<Self> {
unsafe {
if libc::setsid() == -1 {
Err(ForkError::SetsidFail)
} else {
match Slave::new(ptsname) {
Err(cause) => Err(ForkError::BadSlave(cause)),
Ok(slave) => {
if let Some(cause) = slave.dup2(libc::STDIN_FILENO)
.err()
.or(slave.dup2(libc::STDOUT_FILENO)
.err()
.or(slave.dup2(libc::STDERR_FILENO).err())) {
Err(ForkError::BadSlave(cause))
} else {
Ok(Fork::Child(slave))
}
}
}
}
}
}
pub fn from_ptmx() -> Result<Self> {
Fork::new(::DEFAULT_PTMX)
}
pub fn wait(&self) -> Result<libc::pid_t> {
match *self {
Fork::Child(_) => Err(ForkError::IsChild),
Fork::Parent(pid, _) => {
loop {
unsafe {
match libc::waitpid(pid, &mut 0, 0) {
0 => continue,
-1 => return Err(ForkError::WaitpidFail),
_ => return Ok(pid),
}
}
}
}
}
}
pub fn is_parent(&self) -> Result<Master> {
match *self {
Fork::Child(_) => Err(ForkError::IsChild),
Fork::Parent(_, ref master) => Ok(master.clone()),
}
}
pub fn is_child(&self) -> Result<&Slave> {
match *self {
Fork::Parent(_, _) => Err(ForkError::IsParent),
Fork::Child(ref slave) => Ok(slave),
}
}
}
impl Drop for Fork {
fn drop(&mut self) {
match *self {
Fork::Parent(_, ref master) => Descriptor::drop(master),
_ => {}
}
}
}