]> git.proxmox.com Git - rustc.git/blame - vendor/libc/src/unix/solarish/compat.rs
New upstream version 1.67.1+dfsg1
[rustc.git] / vendor / libc / src / unix / solarish / compat.rs
CommitLineData
532ac7d7
XL
1// Common functions that are unfortunately missing on illumos and
2// Solaris, but often needed by other crates.
3
487cf647 4use core::cmp::min;
532ac7d7
XL
5use unix::solarish::*;
6
3dfed10e
XL
7const PTEM: &[u8] = b"ptem\0";
8const LDTERM: &[u8] = b"ldterm\0";
9
532ac7d7 10pub unsafe fn cfmakeraw(termios: *mut ::termios) {
cdc7bbd5
XL
11 (*termios).c_iflag &=
12 !(IMAXBEL | IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
ba9703b0
XL
13 (*termios).c_oflag &= !OPOST;
14 (*termios).c_lflag &= !(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
15 (*termios).c_cflag &= !(CSIZE | PARENB);
16 (*termios).c_cflag |= CS8;
17
18 // By default, most software expects a pending read to block until at
19 // least one byte becomes available. As per termio(7I), this requires
20 // setting the MIN and TIME parameters appropriately.
21 //
22 // As a somewhat unfortunate artefact of history, the MIN and TIME slots
23 // in the control character array overlap with the EOF and EOL slots used
24 // for canonical mode processing. Because the EOF character needs to be
25 // the ASCII EOT value (aka Control-D), it has the byte value 4. When
26 // switching to raw mode, this is interpreted as a MIN value of 4; i.e.,
27 // reads will block until at least four bytes have been input.
28 //
29 // Other platforms with a distinct MIN slot like Linux and FreeBSD appear
30 // to default to a MIN value of 1, so we'll force that value here:
31 (*termios).c_cc[VMIN] = 1;
32 (*termios).c_cc[VTIME] = 0;
532ac7d7
XL
33}
34
cdc7bbd5 35pub unsafe fn cfsetspeed(termios: *mut ::termios, speed: ::speed_t) -> ::c_int {
532ac7d7
XL
36 // Neither of these functions on illumos or Solaris actually ever
37 // return an error
38 ::cfsetispeed(termios, speed);
39 ::cfsetospeed(termios, speed);
40 0
41}
3dfed10e
XL
42
43unsafe fn bail(fdm: ::c_int, fds: ::c_int) -> ::c_int {
44 let e = *___errno();
45 if fds >= 0 {
46 ::close(fds);
47 }
48 if fdm >= 0 {
49 ::close(fdm);
50 }
51 *___errno() = e;
52 return -1;
53}
54
55pub unsafe fn openpty(
56 amain: *mut ::c_int,
57 asubord: *mut ::c_int,
58 name: *mut ::c_char,
59 termp: *const termios,
60 winp: *const ::winsize,
61) -> ::c_int {
62 // Open the main pseudo-terminal device, making sure not to set it as the
63 // controlling terminal for this process:
64 let fdm = ::posix_openpt(O_RDWR | O_NOCTTY);
65 if fdm < 0 {
66 return -1;
67 }
68
69 // Set permissions and ownership on the subordinate device and unlock it:
70 if ::grantpt(fdm) < 0 || ::unlockpt(fdm) < 0 {
71 return bail(fdm, -1);
72 }
73
74 // Get the path name of the subordinate device:
75 let subordpath = ::ptsname(fdm);
76 if subordpath.is_null() {
77 return bail(fdm, -1);
78 }
79
80 // Open the subordinate device without setting it as the controlling
81 // terminal for this process:
82 let fds = ::open(subordpath, O_RDWR | O_NOCTTY);
83 if fds < 0 {
84 return bail(fdm, -1);
85 }
86
87 // Check if the STREAMS modules are already pushed:
88 let setup = ::ioctl(fds, I_FIND, LDTERM.as_ptr());
89 if setup < 0 {
90 return bail(fdm, fds);
91 } else if setup == 0 {
92 // The line discipline is not present, so push the appropriate STREAMS
93 // modules for the subordinate device:
cdc7bbd5 94 if ::ioctl(fds, I_PUSH, PTEM.as_ptr()) < 0 || ::ioctl(fds, I_PUSH, LDTERM.as_ptr()) < 0 {
3dfed10e
XL
95 return bail(fdm, fds);
96 }
97 }
98
99 // If provided, set the terminal parameters:
100 if !termp.is_null() && ::tcsetattr(fds, TCSAFLUSH, termp) != 0 {
101 return bail(fdm, fds);
102 }
103
104 // If provided, set the window size:
105 if !winp.is_null() && ::ioctl(fds, TIOCSWINSZ, winp) < 0 {
106 return bail(fdm, fds);
107 }
108
109 // If the caller wants the name of the subordinate device, copy it out.
110 //
111 // Note that this is a terrible interface: there appears to be no standard
112 // upper bound on the copy length for this pointer. Nobody should pass
113 // anything but NULL here, preferring instead to use ptsname(3C) directly.
114 if !name.is_null() {
115 ::strcpy(name, subordpath);
116 }
117
118 *amain = fdm;
119 *asubord = fds;
120 0
121}
122
123pub unsafe fn forkpty(
124 amain: *mut ::c_int,
125 name: *mut ::c_char,
126 termp: *const termios,
127 winp: *const ::winsize,
128) -> ::pid_t {
129 let mut fds = -1;
130
131 if openpty(amain, &mut fds, name, termp, winp) != 0 {
132 return -1;
133 }
134
135 let pid = ::fork();
136 if pid < 0 {
137 return bail(*amain, fds);
138 } else if pid > 0 {
139 // In the parent process, we close the subordinate device and return the
140 // process ID of the new child:
141 ::close(fds);
142 return pid;
143 }
144
145 // The rest of this function executes in the child process.
146
147 // Close the main side of the pseudo-terminal pair:
148 ::close(*amain);
149
150 // Use TIOCSCTTY to set the subordinate device as our controlling
151 // terminal. This will fail (with ENOTTY) if we are not the leader in
152 // our own session, so we call setsid() first. Finally, arrange for
153 // the pseudo-terminal to occupy the standard I/O descriptors.
154 if ::setsid() < 0
155 || ::ioctl(fds, TIOCSCTTY, 0) < 0
156 || ::dup2(fds, 0) < 0
157 || ::dup2(fds, 1) < 0
158 || ::dup2(fds, 2) < 0
159 {
160 // At this stage there are no particularly good ways to handle failure.
161 // Exit as abruptly as possible, using _exit() to avoid messing with any
162 // state still shared with the parent process.
163 ::_exit(EXIT_FAILURE);
164 }
165 // Close the inherited descriptor, taking care to avoid closing the standard
166 // descriptors by mistake:
167 if fds > 2 {
168 ::close(fds);
169 }
170
171 0
172}
487cf647
FG
173
174pub unsafe fn getpwent_r(
175 pwd: *mut passwd,
176 buf: *mut ::c_char,
177 buflen: ::size_t,
178 result: *mut *mut passwd,
179) -> ::c_int {
180 let old_errno = *::___errno();
181 *::___errno() = 0;
182 *result = native_getpwent_r(
183 pwd,
184 buf,
185 min(buflen, ::c_int::max_value() as ::size_t) as ::c_int,
186 );
187
188 let ret = if (*result).is_null() {
189 *::___errno()
190 } else {
191 0
192 };
193 *::___errno() = old_errno;
194
195 ret
196}
197
198pub unsafe fn getgrent_r(
199 grp: *mut ::group,
200 buf: *mut ::c_char,
201 buflen: ::size_t,
202 result: *mut *mut ::group,
203) -> ::c_int {
204 let old_errno = *::___errno();
205 *::___errno() = 0;
206 *result = native_getgrent_r(
207 grp,
208 buf,
209 min(buflen, ::c_int::max_value() as ::size_t) as ::c_int,
210 );
211
212 let ret = if (*result).is_null() {
213 *::___errno()
214 } else {
215 0
216 };
217 *::___errno() = old_errno;
218
219 ret
220}