Skip to content

Commit ab3c229

Browse files
authored
Merge pull request #1854 from jclulow/illumos-openpty
add openpty and forkpty implementation for illumos systems
2 parents bce30bc + 1f0ea0d commit ab3c229

File tree

3 files changed

+175
-0
lines changed

3 files changed

+175
-0
lines changed

libc-test/build.rs

+1
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,7 @@ fn test_solarish(target: &str) {
725725
"sys/socket.h",
726726
"sys/stat.h",
727727
"sys/statvfs.h",
728+
"sys/stropts.h",
728729
"sys/shm.h",
729730
"sys/time.h",
730731
"sys/times.h",

src/unix/solarish/compat.rs

+136
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33

44
use unix::solarish::*;
55

6+
const PTEM: &[u8] = b"ptem\0";
7+
const LDTERM: &[u8] = b"ldterm\0";
8+
69
pub unsafe fn cfmakeraw(termios: *mut ::termios) {
710
(*termios).c_iflag &= !(IMAXBEL
811
| IGNBRK
@@ -45,3 +48,136 @@ pub unsafe fn cfsetspeed(
4548
::cfsetospeed(termios, speed);
4649
0
4750
}
51+
52+
unsafe fn bail(fdm: ::c_int, fds: ::c_int) -> ::c_int {
53+
let e = *___errno();
54+
if fds >= 0 {
55+
::close(fds);
56+
}
57+
if fdm >= 0 {
58+
::close(fdm);
59+
}
60+
*___errno() = e;
61+
return -1;
62+
}
63+
64+
pub unsafe fn openpty(
65+
amain: *mut ::c_int,
66+
asubord: *mut ::c_int,
67+
name: *mut ::c_char,
68+
termp: *const termios,
69+
winp: *const ::winsize,
70+
) -> ::c_int {
71+
// Open the main pseudo-terminal device, making sure not to set it as the
72+
// controlling terminal for this process:
73+
let fdm = ::posix_openpt(O_RDWR | O_NOCTTY);
74+
if fdm < 0 {
75+
return -1;
76+
}
77+
78+
// Set permissions and ownership on the subordinate device and unlock it:
79+
if ::grantpt(fdm) < 0 || ::unlockpt(fdm) < 0 {
80+
return bail(fdm, -1);
81+
}
82+
83+
// Get the path name of the subordinate device:
84+
let subordpath = ::ptsname(fdm);
85+
if subordpath.is_null() {
86+
return bail(fdm, -1);
87+
}
88+
89+
// Open the subordinate device without setting it as the controlling
90+
// terminal for this process:
91+
let fds = ::open(subordpath, O_RDWR | O_NOCTTY);
92+
if fds < 0 {
93+
return bail(fdm, -1);
94+
}
95+
96+
// Check if the STREAMS modules are already pushed:
97+
let setup = ::ioctl(fds, I_FIND, LDTERM.as_ptr());
98+
if setup < 0 {
99+
return bail(fdm, fds);
100+
} else if setup == 0 {
101+
// The line discipline is not present, so push the appropriate STREAMS
102+
// modules for the subordinate device:
103+
if ::ioctl(fds, I_PUSH, PTEM.as_ptr()) < 0
104+
|| ::ioctl(fds, I_PUSH, LDTERM.as_ptr()) < 0
105+
{
106+
return bail(fdm, fds);
107+
}
108+
}
109+
110+
// If provided, set the terminal parameters:
111+
if !termp.is_null() && ::tcsetattr(fds, TCSAFLUSH, termp) != 0 {
112+
return bail(fdm, fds);
113+
}
114+
115+
// If provided, set the window size:
116+
if !winp.is_null() && ::ioctl(fds, TIOCSWINSZ, winp) < 0 {
117+
return bail(fdm, fds);
118+
}
119+
120+
// If the caller wants the name of the subordinate device, copy it out.
121+
//
122+
// Note that this is a terrible interface: there appears to be no standard
123+
// upper bound on the copy length for this pointer. Nobody should pass
124+
// anything but NULL here, preferring instead to use ptsname(3C) directly.
125+
if !name.is_null() {
126+
::strcpy(name, subordpath);
127+
}
128+
129+
*amain = fdm;
130+
*asubord = fds;
131+
0
132+
}
133+
134+
pub unsafe fn forkpty(
135+
amain: *mut ::c_int,
136+
name: *mut ::c_char,
137+
termp: *const termios,
138+
winp: *const ::winsize,
139+
) -> ::pid_t {
140+
let mut fds = -1;
141+
142+
if openpty(amain, &mut fds, name, termp, winp) != 0 {
143+
return -1;
144+
}
145+
146+
let pid = ::fork();
147+
if pid < 0 {
148+
return bail(*amain, fds);
149+
} else if pid > 0 {
150+
// In the parent process, we close the subordinate device and return the
151+
// process ID of the new child:
152+
::close(fds);
153+
return pid;
154+
}
155+
156+
// The rest of this function executes in the child process.
157+
158+
// Close the main side of the pseudo-terminal pair:
159+
::close(*amain);
160+
161+
// Use TIOCSCTTY to set the subordinate device as our controlling
162+
// terminal. This will fail (with ENOTTY) if we are not the leader in
163+
// our own session, so we call setsid() first. Finally, arrange for
164+
// the pseudo-terminal to occupy the standard I/O descriptors.
165+
if ::setsid() < 0
166+
|| ::ioctl(fds, TIOCSCTTY, 0) < 0
167+
|| ::dup2(fds, 0) < 0
168+
|| ::dup2(fds, 1) < 0
169+
|| ::dup2(fds, 2) < 0
170+
{
171+
// At this stage there are no particularly good ways to handle failure.
172+
// Exit as abruptly as possible, using _exit() to avoid messing with any
173+
// state still shared with the parent process.
174+
::_exit(EXIT_FAILURE);
175+
}
176+
// Close the inherited descriptor, taking care to avoid closing the standard
177+
// descriptors by mistake:
178+
if fds > 2 {
179+
::close(fds);
180+
}
181+
182+
0
183+
}

src/unix/solarish/mod.rs

+38
Original file line numberDiff line numberDiff line change
@@ -1949,6 +1949,44 @@ pub const VLNEXT: usize = 15;
19491949
pub const VSTATUS: usize = 16;
19501950
pub const VERASE2: usize = 17;
19511951

1952+
// <sys/stropts.h>
1953+
const STR: ::c_int = (b'S' as ::c_int) << 8;
1954+
pub const I_NREAD: ::c_int = STR | 0o1;
1955+
pub const I_PUSH: ::c_int = STR | 0o2;
1956+
pub const I_POP: ::c_int = STR | 0o3;
1957+
pub const I_LOOK: ::c_int = STR | 0o4;
1958+
pub const I_FLUSH: ::c_int = STR | 0o5;
1959+
pub const I_SRDOPT: ::c_int = STR | 0o6;
1960+
pub const I_GRDOPT: ::c_int = STR | 0o7;
1961+
pub const I_STR: ::c_int = STR | 0o10;
1962+
pub const I_SETSIG: ::c_int = STR | 0o11;
1963+
pub const I_GETSIG: ::c_int = STR | 0o12;
1964+
pub const I_FIND: ::c_int = STR | 0o13;
1965+
pub const I_LINK: ::c_int = STR | 0o14;
1966+
pub const I_UNLINK: ::c_int = STR | 0o15;
1967+
pub const I_PEEK: ::c_int = STR | 0o17;
1968+
pub const I_FDINSERT: ::c_int = STR | 0o20;
1969+
pub const I_SENDFD: ::c_int = STR | 0o21;
1970+
pub const I_RECVFD: ::c_int = STR | 0o16;
1971+
pub const I_SWROPT: ::c_int = STR | 0o23;
1972+
pub const I_GWROPT: ::c_int = STR | 0o24;
1973+
pub const I_LIST: ::c_int = STR | 0o25;
1974+
pub const I_PLINK: ::c_int = STR | 0o26;
1975+
pub const I_PUNLINK: ::c_int = STR | 0o27;
1976+
pub const I_ANCHOR: ::c_int = STR | 0o30;
1977+
pub const I_FLUSHBAND: ::c_int = STR | 0o34;
1978+
pub const I_CKBAND: ::c_int = STR | 0o35;
1979+
pub const I_GETBAND: ::c_int = STR | 0o36;
1980+
pub const I_ATMARK: ::c_int = STR | 0o37;
1981+
pub const I_SETCLTIME: ::c_int = STR | 0o40;
1982+
pub const I_GETCLTIME: ::c_int = STR | 0o41;
1983+
pub const I_CANPUT: ::c_int = STR | 0o42;
1984+
pub const I_SERROPT: ::c_int = STR | 0o43;
1985+
pub const I_GERROPT: ::c_int = STR | 0o44;
1986+
pub const I_ESETSIG: ::c_int = STR | 0o45;
1987+
pub const I_EGETSIG: ::c_int = STR | 0o46;
1988+
pub const __I_PUSH_NOCTTY: ::c_int = STR | 0o47;
1989+
19521990
// 3SOCKET flags
19531991
pub const SOCK_CLOEXEC: ::c_int = 0x080000;
19541992
pub const SOCK_NONBLOCK: ::c_int = 0x100000;

0 commit comments

Comments
 (0)