summaryrefslogtreecommitdiffstats
path: root/third_party/rust/libc/src/unix/solarish/compat.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/libc/src/unix/solarish/compat.rs')
-rw-r--r--third_party/rust/libc/src/unix/solarish/compat.rs220
1 files changed, 220 insertions, 0 deletions
diff --git a/third_party/rust/libc/src/unix/solarish/compat.rs b/third_party/rust/libc/src/unix/solarish/compat.rs
new file mode 100644
index 0000000000..cbf955a31e
--- /dev/null
+++ b/third_party/rust/libc/src/unix/solarish/compat.rs
@@ -0,0 +1,220 @@
+// Common functions that are unfortunately missing on illumos and
+// Solaris, but often needed by other crates.
+
+use core::cmp::min;
+use unix::solarish::*;
+
+const PTEM: &[u8] = b"ptem\0";
+const LDTERM: &[u8] = b"ldterm\0";
+
+pub unsafe fn cfmakeraw(termios: *mut ::termios) {
+ (*termios).c_iflag &=
+ !(IMAXBEL | IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
+ (*termios).c_oflag &= !OPOST;
+ (*termios).c_lflag &= !(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
+ (*termios).c_cflag &= !(CSIZE | PARENB);
+ (*termios).c_cflag |= CS8;
+
+ // By default, most software expects a pending read to block until at
+ // least one byte becomes available. As per termio(7I), this requires
+ // setting the MIN and TIME parameters appropriately.
+ //
+ // As a somewhat unfortunate artefact of history, the MIN and TIME slots
+ // in the control character array overlap with the EOF and EOL slots used
+ // for canonical mode processing. Because the EOF character needs to be
+ // the ASCII EOT value (aka Control-D), it has the byte value 4. When
+ // switching to raw mode, this is interpreted as a MIN value of 4; i.e.,
+ // reads will block until at least four bytes have been input.
+ //
+ // Other platforms with a distinct MIN slot like Linux and FreeBSD appear
+ // to default to a MIN value of 1, so we'll force that value here:
+ (*termios).c_cc[VMIN] = 1;
+ (*termios).c_cc[VTIME] = 0;
+}
+
+pub unsafe fn cfsetspeed(termios: *mut ::termios, speed: ::speed_t) -> ::c_int {
+ // Neither of these functions on illumos or Solaris actually ever
+ // return an error
+ ::cfsetispeed(termios, speed);
+ ::cfsetospeed(termios, speed);
+ 0
+}
+
+unsafe fn bail(fdm: ::c_int, fds: ::c_int) -> ::c_int {
+ let e = *___errno();
+ if fds >= 0 {
+ ::close(fds);
+ }
+ if fdm >= 0 {
+ ::close(fdm);
+ }
+ *___errno() = e;
+ return -1;
+}
+
+pub unsafe fn openpty(
+ amain: *mut ::c_int,
+ asubord: *mut ::c_int,
+ name: *mut ::c_char,
+ termp: *const termios,
+ winp: *const ::winsize,
+) -> ::c_int {
+ // Open the main pseudo-terminal device, making sure not to set it as the
+ // controlling terminal for this process:
+ let fdm = ::posix_openpt(O_RDWR | O_NOCTTY);
+ if fdm < 0 {
+ return -1;
+ }
+
+ // Set permissions and ownership on the subordinate device and unlock it:
+ if ::grantpt(fdm) < 0 || ::unlockpt(fdm) < 0 {
+ return bail(fdm, -1);
+ }
+
+ // Get the path name of the subordinate device:
+ let subordpath = ::ptsname(fdm);
+ if subordpath.is_null() {
+ return bail(fdm, -1);
+ }
+
+ // Open the subordinate device without setting it as the controlling
+ // terminal for this process:
+ let fds = ::open(subordpath, O_RDWR | O_NOCTTY);
+ if fds < 0 {
+ return bail(fdm, -1);
+ }
+
+ // Check if the STREAMS modules are already pushed:
+ let setup = ::ioctl(fds, I_FIND, LDTERM.as_ptr());
+ if setup < 0 {
+ return bail(fdm, fds);
+ } else if setup == 0 {
+ // The line discipline is not present, so push the appropriate STREAMS
+ // modules for the subordinate device:
+ if ::ioctl(fds, I_PUSH, PTEM.as_ptr()) < 0 || ::ioctl(fds, I_PUSH, LDTERM.as_ptr()) < 0 {
+ return bail(fdm, fds);
+ }
+ }
+
+ // If provided, set the terminal parameters:
+ if !termp.is_null() && ::tcsetattr(fds, TCSAFLUSH, termp) != 0 {
+ return bail(fdm, fds);
+ }
+
+ // If provided, set the window size:
+ if !winp.is_null() && ::ioctl(fds, TIOCSWINSZ, winp) < 0 {
+ return bail(fdm, fds);
+ }
+
+ // If the caller wants the name of the subordinate device, copy it out.
+ //
+ // Note that this is a terrible interface: there appears to be no standard
+ // upper bound on the copy length for this pointer. Nobody should pass
+ // anything but NULL here, preferring instead to use ptsname(3C) directly.
+ if !name.is_null() {
+ ::strcpy(name, subordpath);
+ }
+
+ *amain = fdm;
+ *asubord = fds;
+ 0
+}
+
+pub unsafe fn forkpty(
+ amain: *mut ::c_int,
+ name: *mut ::c_char,
+ termp: *const termios,
+ winp: *const ::winsize,
+) -> ::pid_t {
+ let mut fds = -1;
+
+ if openpty(amain, &mut fds, name, termp, winp) != 0 {
+ return -1;
+ }
+
+ let pid = ::fork();
+ if pid < 0 {
+ return bail(*amain, fds);
+ } else if pid > 0 {
+ // In the parent process, we close the subordinate device and return the
+ // process ID of the new child:
+ ::close(fds);
+ return pid;
+ }
+
+ // The rest of this function executes in the child process.
+
+ // Close the main side of the pseudo-terminal pair:
+ ::close(*amain);
+
+ // Use TIOCSCTTY to set the subordinate device as our controlling
+ // terminal. This will fail (with ENOTTY) if we are not the leader in
+ // our own session, so we call setsid() first. Finally, arrange for
+ // the pseudo-terminal to occupy the standard I/O descriptors.
+ if ::setsid() < 0
+ || ::ioctl(fds, TIOCSCTTY, 0) < 0
+ || ::dup2(fds, 0) < 0
+ || ::dup2(fds, 1) < 0
+ || ::dup2(fds, 2) < 0
+ {
+ // At this stage there are no particularly good ways to handle failure.
+ // Exit as abruptly as possible, using _exit() to avoid messing with any
+ // state still shared with the parent process.
+ ::_exit(EXIT_FAILURE);
+ }
+ // Close the inherited descriptor, taking care to avoid closing the standard
+ // descriptors by mistake:
+ if fds > 2 {
+ ::close(fds);
+ }
+
+ 0
+}
+
+pub unsafe fn getpwent_r(
+ pwd: *mut passwd,
+ buf: *mut ::c_char,
+ buflen: ::size_t,
+ result: *mut *mut passwd,
+) -> ::c_int {
+ let old_errno = *::___errno();
+ *::___errno() = 0;
+ *result = native_getpwent_r(
+ pwd,
+ buf,
+ min(buflen, ::c_int::max_value() as ::size_t) as ::c_int,
+ );
+
+ let ret = if (*result).is_null() {
+ *::___errno()
+ } else {
+ 0
+ };
+ *::___errno() = old_errno;
+
+ ret
+}
+
+pub unsafe fn getgrent_r(
+ grp: *mut ::group,
+ buf: *mut ::c_char,
+ buflen: ::size_t,
+ result: *mut *mut ::group,
+) -> ::c_int {
+ let old_errno = *::___errno();
+ *::___errno() = 0;
+ *result = native_getgrent_r(
+ grp,
+ buf,
+ min(buflen, ::c_int::max_value() as ::size_t) as ::c_int,
+ );
+
+ let ret = if (*result).is_null() {
+ *::___errno()
+ } else {
+ 0
+ };
+ *::___errno() = old_errno;
+
+ ret
+}