Skip to content

Commit 1f0ea0d

Browse files
committed
add openpty and forkpty implementation for illumos systems
At time of writing, illumos systems do not provide an implementation of the openpty() and forkpty() wrappers provided on some other UNIX systems. While we expect to grow an implementation, it seems prudent to provide a compatibility routine here first to unblock illumos support in the popular nix crate.
1 parent e4a1f26 commit 1f0ea0d

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)