1//! An interface for controlling asynchronous communication ports 2//! 3//! This interface provides a safe wrapper around the termios subsystem defined by POSIX. The 4//! underlying types are all implemented in libc for most platforms and either wrapped in safer 5//! types here or exported directly. 6//! 7//! If you are unfamiliar with the `termios` API, you should first read the 8//! [API documentation](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/termios.h.html) and 9//! then come back to understand how `nix` safely wraps it. 10//! 11//! It should be noted that this API incurs some runtime overhead above the base `libc` definitions. 12//! As this interface is not used with high-bandwidth information, this should be fine in most 13//! cases. The primary cost when using this API is that the `Termios` datatype here duplicates the 14//! standard fields of the underlying `termios` struct and uses safe type wrappers for those fields. 15//! This means that when crossing the FFI interface to the underlying C library, data is first 16//! copied into the underlying `termios` struct, then the operation is done, and the data is copied 17//! back (with additional sanity checking) into the safe wrapper types. The `termios` struct is 18//! relatively small across all platforms (on the order of 32-64 bytes). 19//! 20//! The following examples highlight some of the API use cases such that users coming from using C 21//! or reading the standard documentation will understand how to use the safe API exposed here. 22//! 23//! Example disabling processing of the end-of-file control character: 24//! 25//! ``` 26//! # use self::nix::sys::termios::SpecialCharacterIndices::VEOF; 27//! # use self::nix::sys::termios::{_POSIX_VDISABLE, Termios}; 28//! # let mut termios: Termios = unsafe { std::mem::zeroed() }; 29//! termios.control_chars[VEOF as usize] = _POSIX_VDISABLE; 30//! ``` 31//! 32//! The flags within `Termios` are defined as bitfields using the `bitflags` crate. This provides 33//! an interface for working with bitfields that is similar to working with the raw unsigned 34//! integer types but offers type safety because of the internal checking that values will always 35//! be a valid combination of the defined flags. 36//! 37//! An example showing some of the basic operations for interacting with the control flags: 38//! 39//! ``` 40//! # use self::nix::sys::termios::{ControlFlags, Termios}; 41//! # let mut termios: Termios = unsafe { std::mem::zeroed() }; 42//! termios.control_flags & ControlFlags::CSIZE == ControlFlags::CS5; 43//! termios.control_flags |= ControlFlags::CS5; 44//! ``` 45//! 46//! # Baud rates 47//! 48//! This API is not consistent across platforms when it comes to `BaudRate`: Android and Linux both 49//! only support the rates specified by the `BaudRate` enum through their termios API while the BSDs 50//! support arbitrary baud rates as the values of the `BaudRate` enum constants are the same integer 51//! value of the constant (`B9600` == `9600`). Therefore the `nix::termios` API uses the following 52//! conventions: 53//! 54//! * `cfgetispeed()` - Returns `u32` on BSDs, `BaudRate` on Android/Linux 55//! * `cfgetospeed()` - Returns `u32` on BSDs, `BaudRate` on Android/Linux 56//! * `cfsetispeed()` - Takes `u32` or `BaudRate` on BSDs, `BaudRate` on Android/Linux 57//! * `cfsetospeed()` - Takes `u32` or `BaudRate` on BSDs, `BaudRate` on Android/Linux 58//! * `cfsetspeed()` - Takes `u32` or `BaudRate` on BSDs, `BaudRate` on Android/Linux 59//! 60//! The most common use case of specifying a baud rate using the enum will work the same across 61//! platforms: 62//! 63//! ```rust 64//! # use nix::sys::termios::{BaudRate, cfsetispeed, cfsetospeed, cfsetspeed, Termios}; 65//! # fn main() { 66//! # let mut t: Termios = unsafe { std::mem::zeroed() }; 67//! cfsetispeed(&mut t, BaudRate::B9600).unwrap(); 68//! cfsetospeed(&mut t, BaudRate::B9600).unwrap(); 69//! cfsetspeed(&mut t, BaudRate::B9600).unwrap(); 70//! # } 71//! ``` 72//! 73//! Additionally round-tripping baud rates is consistent across platforms: 74//! 75//! ```rust 76//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetispeed, cfsetspeed, Termios}; 77//! # fn main() { 78//! # let mut t: Termios = unsafe { std::mem::zeroed() }; 79//! # cfsetspeed(&mut t, BaudRate::B9600).unwrap(); 80//! let speed = cfgetispeed(&t); 81//! assert_eq!(speed, cfgetospeed(&t)); 82//! cfsetispeed(&mut t, speed).unwrap(); 83//! # } 84//! ``` 85//! 86//! On non-BSDs, `cfgetispeed()` and `cfgetospeed()` both return a `BaudRate`: 87//! 88#![cfg_attr( 89 any( 90 target_os = "freebsd", 91 target_os = "dragonfly", 92 target_os = "ios", 93 target_os = "macos", 94 target_os = "netbsd", 95 target_os = "openbsd" 96 ), 97 doc = " ```rust,ignore" 98)] 99#![cfg_attr( 100 not(any( 101 target_os = "freebsd", 102 target_os = "dragonfly", 103 target_os = "ios", 104 target_os = "macos", 105 target_os = "netbsd", 106 target_os = "openbsd" 107 )), 108 doc = " ```rust" 109)] 110//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetspeed, Termios}; 111//! # fn main() { 112//! # let mut t: Termios = unsafe { std::mem::zeroed() }; 113//! # cfsetspeed(&mut t, BaudRate::B9600); 114//! assert_eq!(cfgetispeed(&t), BaudRate::B9600); 115//! assert_eq!(cfgetospeed(&t), BaudRate::B9600); 116//! # } 117//! ``` 118//! 119//! But on the BSDs, `cfgetispeed()` and `cfgetospeed()` both return `u32`s: 120//! 121#![cfg_attr( 122 any( 123 target_os = "freebsd", 124 target_os = "dragonfly", 125 target_os = "ios", 126 target_os = "macos", 127 target_os = "netbsd", 128 target_os = "openbsd" 129 ), 130 doc = " ```rust" 131)] 132#![cfg_attr( 133 not(any( 134 target_os = "freebsd", 135 target_os = "dragonfly", 136 target_os = "ios", 137 target_os = "macos", 138 target_os = "netbsd", 139 target_os = "openbsd" 140 )), 141 doc = " ```rust,ignore" 142)] 143//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetspeed, Termios}; 144//! # fn main() { 145//! # let mut t: Termios = unsafe { std::mem::zeroed() }; 146//! # cfsetspeed(&mut t, 9600u32); 147//! assert_eq!(cfgetispeed(&t), 9600u32); 148//! assert_eq!(cfgetospeed(&t), 9600u32); 149//! # } 150//! ``` 151//! 152//! It's trivial to convert from a `BaudRate` to a `u32` on BSDs: 153//! 154#![cfg_attr( 155 any( 156 target_os = "freebsd", 157 target_os = "dragonfly", 158 target_os = "ios", 159 target_os = "macos", 160 target_os = "netbsd", 161 target_os = "openbsd" 162 ), 163 doc = " ```rust" 164)] 165#![cfg_attr( 166 not(any( 167 target_os = "freebsd", 168 target_os = "dragonfly", 169 target_os = "ios", 170 target_os = "macos", 171 target_os = "netbsd", 172 target_os = "openbsd" 173 )), 174 doc = " ```rust,ignore" 175)] 176//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfsetspeed, Termios}; 177//! # fn main() { 178//! # let mut t: Termios = unsafe { std::mem::zeroed() }; 179//! # cfsetspeed(&mut t, 9600u32); 180//! assert_eq!(cfgetispeed(&t), BaudRate::B9600.into()); 181//! assert_eq!(u32::from(BaudRate::B9600), 9600u32); 182//! # } 183//! ``` 184//! 185//! And on BSDs you can specify arbitrary baud rates (**note** this depends on hardware support) 186//! by specifying baud rates directly using `u32`s: 187//! 188#![cfg_attr( 189 any( 190 target_os = "freebsd", 191 target_os = "dragonfly", 192 target_os = "ios", 193 target_os = "macos", 194 target_os = "netbsd", 195 target_os = "openbsd" 196 ), 197 doc = " ```rust" 198)] 199#![cfg_attr( 200 not(any( 201 target_os = "freebsd", 202 target_os = "dragonfly", 203 target_os = "ios", 204 target_os = "macos", 205 target_os = "netbsd", 206 target_os = "openbsd" 207 )), 208 doc = " ```rust,ignore" 209)] 210//! # use nix::sys::termios::{cfsetispeed, cfsetospeed, cfsetspeed, Termios}; 211//! # fn main() { 212//! # let mut t: Termios = unsafe { std::mem::zeroed() }; 213//! cfsetispeed(&mut t, 9600u32); 214//! cfsetospeed(&mut t, 9600u32); 215//! cfsetspeed(&mut t, 9600u32); 216//! # } 217//! ``` 218use crate::errno::Errno; 219use crate::Result; 220use cfg_if::cfg_if; 221use libc::{self, c_int, tcflag_t}; 222use std::cell::{Ref, RefCell}; 223use std::convert::From; 224use std::mem; 225use std::os::unix::io::RawFd; 226 227#[cfg(feature = "process")] 228use crate::unistd::Pid; 229 230/// Stores settings for the termios API 231/// 232/// This is a wrapper around the `libc::termios` struct that provides a safe interface for the 233/// standard fields. The only safe way to obtain an instance of this struct is to extract it from 234/// an open port using `tcgetattr()`. 235#[derive(Clone, Debug, Eq, PartialEq)] 236pub struct Termios { 237 inner: RefCell<libc::termios>, 238 /// Input mode flags (see `termios.c_iflag` documentation) 239 pub input_flags: InputFlags, 240 /// Output mode flags (see `termios.c_oflag` documentation) 241 pub output_flags: OutputFlags, 242 /// Control mode flags (see `termios.c_cflag` documentation) 243 pub control_flags: ControlFlags, 244 /// Local mode flags (see `termios.c_lflag` documentation) 245 pub local_flags: LocalFlags, 246 /// Control characters (see `termios.c_cc` documentation) 247 pub control_chars: [libc::cc_t; NCCS], 248 /// Line discipline (see `termios.c_line` documentation) 249 #[cfg(any(target_os = "linux", target_os = "android",))] 250 pub line_discipline: libc::cc_t, 251 /// Line discipline (see `termios.c_line` documentation) 252 #[cfg(target_os = "haiku")] 253 pub line_discipline: libc::c_char, 254} 255 256impl Termios { 257 /// Exposes an immutable reference to the underlying `libc::termios` data structure. 258 /// 259 /// This is not part of `nix`'s public API because it requires additional work to maintain type 260 /// safety. 261 pub(crate) fn get_libc_termios(&self) -> Ref<libc::termios> { 262 { 263 let mut termios = self.inner.borrow_mut(); 264 termios.c_iflag = self.input_flags.bits(); 265 termios.c_oflag = self.output_flags.bits(); 266 termios.c_cflag = self.control_flags.bits(); 267 termios.c_lflag = self.local_flags.bits(); 268 termios.c_cc = self.control_chars; 269 #[cfg(any( 270 target_os = "linux", 271 target_os = "android", 272 target_os = "haiku", 273 ))] 274 { 275 termios.c_line = self.line_discipline; 276 } 277 } 278 self.inner.borrow() 279 } 280 281 /// Exposes the inner `libc::termios` datastore within `Termios`. 282 /// 283 /// This is unsafe because if this is used to modify the inner `libc::termios` struct, it will 284 /// not automatically update the safe wrapper type around it. In this case it should also be 285 /// paired with a call to `update_wrapper()` so that the wrapper-type and internal 286 /// representation stay consistent. 287 pub(crate) unsafe fn get_libc_termios_mut(&mut self) -> *mut libc::termios { 288 { 289 let mut termios = self.inner.borrow_mut(); 290 termios.c_iflag = self.input_flags.bits(); 291 termios.c_oflag = self.output_flags.bits(); 292 termios.c_cflag = self.control_flags.bits(); 293 termios.c_lflag = self.local_flags.bits(); 294 termios.c_cc = self.control_chars; 295 #[cfg(any( 296 target_os = "linux", 297 target_os = "android", 298 target_os = "haiku", 299 ))] 300 { 301 termios.c_line = self.line_discipline; 302 } 303 } 304 self.inner.as_ptr() 305 } 306 307 /// Updates the wrapper values from the internal `libc::termios` data structure. 308 pub(crate) fn update_wrapper(&mut self) { 309 let termios = *self.inner.borrow_mut(); 310 self.input_flags = InputFlags::from_bits_truncate(termios.c_iflag); 311 self.output_flags = OutputFlags::from_bits_truncate(termios.c_oflag); 312 self.control_flags = ControlFlags::from_bits_truncate(termios.c_cflag); 313 self.local_flags = LocalFlags::from_bits_truncate(termios.c_lflag); 314 self.control_chars = termios.c_cc; 315 #[cfg(any( 316 target_os = "linux", 317 target_os = "android", 318 target_os = "haiku", 319 ))] 320 { 321 self.line_discipline = termios.c_line; 322 } 323 } 324} 325 326impl From<libc::termios> for Termios { 327 fn from(termios: libc::termios) -> Self { 328 Termios { 329 inner: RefCell::new(termios), 330 input_flags: InputFlags::from_bits_truncate(termios.c_iflag), 331 output_flags: OutputFlags::from_bits_truncate(termios.c_oflag), 332 control_flags: ControlFlags::from_bits_truncate(termios.c_cflag), 333 local_flags: LocalFlags::from_bits_truncate(termios.c_lflag), 334 control_chars: termios.c_cc, 335 #[cfg(any( 336 target_os = "linux", 337 target_os = "android", 338 target_os = "haiku", 339 ))] 340 line_discipline: termios.c_line, 341 } 342 } 343} 344 345impl From<Termios> for libc::termios { 346 fn from(termios: Termios) -> Self { 347 termios.inner.into_inner() 348 } 349} 350 351libc_enum! { 352 /// Baud rates supported by the system. 353 /// 354 /// For the BSDs, arbitrary baud rates can be specified by using `u32`s directly instead of this 355 /// enum. 356 /// 357 /// B0 is special and will disable the port. 358 #[cfg_attr(all(any(target_os = "haiku"), target_pointer_width = "64"), repr(u8))] 359 #[cfg_attr(all(any(target_os = "ios", target_os = "macos"), target_pointer_width = "64"), repr(u64))] 360 #[cfg_attr(not(all(any(target_os = "ios", target_os = "macos", target_os = "haiku"), target_pointer_width = "64")), repr(u32))] 361 #[non_exhaustive] 362 pub enum BaudRate { 363 B0, 364 B50, 365 B75, 366 B110, 367 B134, 368 B150, 369 B200, 370 B300, 371 B600, 372 B1200, 373 B1800, 374 B2400, 375 B4800, 376 #[cfg(any(target_os = "dragonfly", 377 target_os = "freebsd", 378 target_os = "macos", 379 target_os = "netbsd", 380 target_os = "openbsd"))] 381 #[cfg_attr(docsrs, doc(cfg(all())))] 382 B7200, 383 B9600, 384 #[cfg(any(target_os = "dragonfly", 385 target_os = "freebsd", 386 target_os = "macos", 387 target_os = "netbsd", 388 target_os = "openbsd"))] 389 #[cfg_attr(docsrs, doc(cfg(all())))] 390 B14400, 391 B19200, 392 #[cfg(any(target_os = "dragonfly", 393 target_os = "freebsd", 394 target_os = "macos", 395 target_os = "netbsd", 396 target_os = "openbsd"))] 397 #[cfg_attr(docsrs, doc(cfg(all())))] 398 B28800, 399 B38400, 400 B57600, 401 #[cfg(any(target_os = "dragonfly", 402 target_os = "freebsd", 403 target_os = "macos", 404 target_os = "netbsd", 405 target_os = "openbsd"))] 406 #[cfg_attr(docsrs, doc(cfg(all())))] 407 B76800, 408 B115200, 409 #[cfg(any(target_os = "illumos", target_os = "solaris"))] 410 #[cfg_attr(docsrs, doc(cfg(all())))] 411 B153600, 412 B230400, 413 #[cfg(any(target_os = "illumos", target_os = "solaris"))] 414 #[cfg_attr(docsrs, doc(cfg(all())))] 415 B307200, 416 #[cfg(any(target_os = "android", 417 target_os = "freebsd", 418 target_os = "illumos", 419 target_os = "linux", 420 target_os = "netbsd", 421 target_os = "solaris"))] 422 #[cfg_attr(docsrs, doc(cfg(all())))] 423 B460800, 424 #[cfg(any(target_os = "android", target_os = "linux"))] 425 #[cfg_attr(docsrs, doc(cfg(all())))] 426 B500000, 427 #[cfg(any(target_os = "android", target_os = "linux"))] 428 #[cfg_attr(docsrs, doc(cfg(all())))] 429 B576000, 430 #[cfg(any(target_os = "android", 431 target_os = "freebsd", 432 target_os = "illumos", 433 target_os = "linux", 434 target_os = "netbsd", 435 target_os = "solaris"))] 436 #[cfg_attr(docsrs, doc(cfg(all())))] 437 B921600, 438 #[cfg(any(target_os = "android", target_os = "linux"))] 439 #[cfg_attr(docsrs, doc(cfg(all())))] 440 B1000000, 441 #[cfg(any(target_os = "android", target_os = "linux"))] 442 #[cfg_attr(docsrs, doc(cfg(all())))] 443 B1152000, 444 #[cfg(any(target_os = "android", target_os = "linux"))] 445 #[cfg_attr(docsrs, doc(cfg(all())))] 446 B1500000, 447 #[cfg(any(target_os = "android", target_os = "linux"))] 448 #[cfg_attr(docsrs, doc(cfg(all())))] 449 B2000000, 450 #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] 451 #[cfg_attr(docsrs, doc(cfg(all())))] 452 B2500000, 453 #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] 454 #[cfg_attr(docsrs, doc(cfg(all())))] 455 B3000000, 456 #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] 457 #[cfg_attr(docsrs, doc(cfg(all())))] 458 B3500000, 459 #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))] 460 #[cfg_attr(docsrs, doc(cfg(all())))] 461 B4000000, 462 } 463 impl TryFrom<libc::speed_t> 464} 465 466#[cfg(any( 467 target_os = "freebsd", 468 target_os = "dragonfly", 469 target_os = "ios", 470 target_os = "macos", 471 target_os = "netbsd", 472 target_os = "openbsd" 473))] 474impl From<BaudRate> for u32 { 475 fn from(b: BaudRate) -> u32 { 476 b as u32 477 } 478} 479 480#[cfg(target_os = "haiku")] 481impl From<BaudRate> for u8 { 482 fn from(b: BaudRate) -> u8 { 483 b as u8 484 } 485} 486 487// TODO: Add TCSASOFT, which will require treating this as a bitfield. 488libc_enum! { 489 /// Specify when a port configuration change should occur. 490 /// 491 /// Used as an argument to `tcsetattr()` 492 #[repr(i32)] 493 #[non_exhaustive] 494 pub enum SetArg { 495 /// The change will occur immediately 496 TCSANOW, 497 /// The change occurs after all output has been written 498 TCSADRAIN, 499 /// Same as `TCSADRAIN`, but will also flush the input buffer 500 TCSAFLUSH, 501 } 502} 503 504libc_enum! { 505 /// Specify a combination of the input and output buffers to flush 506 /// 507 /// Used as an argument to `tcflush()`. 508 #[repr(i32)] 509 #[non_exhaustive] 510 pub enum FlushArg { 511 /// Flush data that was received but not read 512 TCIFLUSH, 513 /// Flush data written but not transmitted 514 TCOFLUSH, 515 /// Flush both received data not read and written data not transmitted 516 TCIOFLUSH, 517 } 518} 519 520libc_enum! { 521 /// Specify how transmission flow should be altered 522 /// 523 /// Used as an argument to `tcflow()`. 524 #[repr(i32)] 525 #[non_exhaustive] 526 pub enum FlowArg { 527 /// Suspend transmission 528 TCOOFF, 529 /// Resume transmission 530 TCOON, 531 /// Transmit a STOP character, which should disable a connected terminal device 532 TCIOFF, 533 /// Transmit a START character, which should re-enable a connected terminal device 534 TCION, 535 } 536} 537 538// TODO: Make this usable directly as a slice index. 539#[cfg(not(target_os = "haiku"))] 540libc_enum! { 541 /// Indices into the `termios.c_cc` array for special characters. 542 #[repr(usize)] 543 #[non_exhaustive] 544 pub enum SpecialCharacterIndices { 545 VDISCARD, 546 #[cfg(any(target_os = "dragonfly", 547 target_os = "freebsd", 548 target_os = "illumos", 549 target_os = "macos", 550 target_os = "netbsd", 551 target_os = "openbsd", 552 target_os = "solaris"))] 553 #[cfg_attr(docsrs, doc(cfg(all())))] 554 VDSUSP, 555 VEOF, 556 VEOL, 557 VEOL2, 558 VERASE, 559 #[cfg(any(target_os = "dragonfly", 560 target_os = "freebsd", 561 target_os = "illumos", 562 target_os = "solaris"))] 563 #[cfg_attr(docsrs, doc(cfg(all())))] 564 VERASE2, 565 VINTR, 566 VKILL, 567 VLNEXT, 568 #[cfg(not(any(all(target_os = "linux", target_arch = "sparc64"), 569 target_os = "illumos", target_os = "solaris")))] 570 #[cfg_attr(docsrs, doc(cfg(all())))] 571 VMIN, 572 VQUIT, 573 VREPRINT, 574 VSTART, 575 #[cfg(any(target_os = "dragonfly", 576 target_os = "freebsd", 577 target_os = "illumos", 578 target_os = "macos", 579 target_os = "netbsd", 580 target_os = "openbsd", 581 target_os = "solaris"))] 582 #[cfg_attr(docsrs, doc(cfg(all())))] 583 VSTATUS, 584 VSTOP, 585 VSUSP, 586 #[cfg(target_os = "linux")] 587 #[cfg_attr(docsrs, doc(cfg(all())))] 588 VSWTC, 589 #[cfg(any(target_os = "haiku", target_os = "illumos", target_os = "solaris"))] 590 #[cfg_attr(docsrs, doc(cfg(all())))] 591 VSWTCH, 592 #[cfg(not(any(all(target_os = "linux", target_arch = "sparc64"), 593 target_os = "illumos", target_os = "solaris")))] 594 #[cfg_attr(docsrs, doc(cfg(all())))] 595 VTIME, 596 VWERASE, 597 #[cfg(target_os = "dragonfly")] 598 #[cfg_attr(docsrs, doc(cfg(all())))] 599 VCHECKPT, 600 } 601} 602 603#[cfg(any( 604 all(target_os = "linux", target_arch = "sparc64"), 605 target_os = "illumos", 606 target_os = "solaris" 607))] 608impl SpecialCharacterIndices { 609 pub const VMIN: SpecialCharacterIndices = SpecialCharacterIndices::VEOF; 610 pub const VTIME: SpecialCharacterIndices = SpecialCharacterIndices::VEOL; 611} 612 613pub use libc::NCCS; 614#[cfg(any( 615 target_os = "android", 616 target_os = "dragonfly", 617 target_os = "freebsd", 618 target_os = "linux", 619 target_os = "macos", 620 target_os = "netbsd", 621 target_os = "openbsd" 622))] 623#[cfg_attr(docsrs, doc(cfg(all())))] 624pub use libc::_POSIX_VDISABLE; 625 626libc_bitflags! { 627 /// Flags for configuring the input mode of a terminal 628 pub struct InputFlags: tcflag_t { 629 IGNBRK; 630 BRKINT; 631 IGNPAR; 632 PARMRK; 633 INPCK; 634 ISTRIP; 635 INLCR; 636 IGNCR; 637 ICRNL; 638 IXON; 639 IXOFF; 640 #[cfg(not(target_os = "redox"))] 641 #[cfg_attr(docsrs, doc(cfg(all())))] 642 IXANY; 643 #[cfg(not(any(target_os = "redox", target_os = "haiku")))] 644 #[cfg_attr(docsrs, doc(cfg(all())))] 645 IMAXBEL; 646 #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))] 647 #[cfg_attr(docsrs, doc(cfg(all())))] 648 IUTF8; 649 } 650} 651 652libc_bitflags! { 653 /// Flags for configuring the output mode of a terminal 654 pub struct OutputFlags: tcflag_t { 655 OPOST; 656 #[cfg(any(target_os = "android", 657 target_os = "haiku", 658 target_os = "linux", 659 target_os = "openbsd"))] 660 #[cfg_attr(docsrs, doc(cfg(all())))] 661 OLCUC; 662 ONLCR; 663 OCRNL as tcflag_t; 664 ONOCR as tcflag_t; 665 ONLRET as tcflag_t; 666 #[cfg(any(target_os = "android", 667 target_os = "haiku", 668 target_os = "ios", 669 target_os = "linux", 670 target_os = "macos"))] 671 #[cfg_attr(docsrs, doc(cfg(all())))] 672 OFILL as tcflag_t; 673 #[cfg(any(target_os = "android", 674 target_os = "haiku", 675 target_os = "ios", 676 target_os = "linux", 677 target_os = "macos"))] 678 #[cfg_attr(docsrs, doc(cfg(all())))] 679 OFDEL as tcflag_t; 680 #[cfg(any(target_os = "android", 681 target_os = "haiku", 682 target_os = "ios", 683 target_os = "linux", 684 target_os = "macos"))] 685 #[cfg_attr(docsrs, doc(cfg(all())))] 686 NL0 as tcflag_t; 687 #[cfg(any(target_os = "android", 688 target_os = "haiku", 689 target_os = "ios", 690 target_os = "linux", 691 target_os = "macos"))] 692 #[cfg_attr(docsrs, doc(cfg(all())))] 693 NL1 as tcflag_t; 694 #[cfg(any(target_os = "android", 695 target_os = "haiku", 696 target_os = "ios", 697 target_os = "linux", 698 target_os = "macos"))] 699 #[cfg_attr(docsrs, doc(cfg(all())))] 700 CR0 as tcflag_t; 701 #[cfg(any(target_os = "android", 702 target_os = "haiku", 703 target_os = "ios", 704 target_os = "linux", 705 target_os = "macos"))] 706 #[cfg_attr(docsrs, doc(cfg(all())))] 707 CR1 as tcflag_t; 708 #[cfg(any(target_os = "android", 709 target_os = "haiku", 710 target_os = "ios", 711 target_os = "linux", 712 target_os = "macos"))] 713 #[cfg_attr(docsrs, doc(cfg(all())))] 714 CR2 as tcflag_t; 715 #[cfg(any(target_os = "android", 716 target_os = "haiku", 717 target_os = "ios", 718 target_os = "linux", 719 target_os = "macos"))] 720 #[cfg_attr(docsrs, doc(cfg(all())))] 721 CR3 as tcflag_t; 722 #[cfg(any(target_os = "android", 723 target_os = "freebsd", 724 target_os = "haiku", 725 target_os = "ios", 726 target_os = "linux", 727 target_os = "macos"))] 728 #[cfg_attr(docsrs, doc(cfg(all())))] 729 TAB0 as tcflag_t; 730 #[cfg(any(target_os = "android", 731 target_os = "haiku", 732 target_os = "ios", 733 target_os = "linux", 734 target_os = "macos"))] 735 #[cfg_attr(docsrs, doc(cfg(all())))] 736 TAB1 as tcflag_t; 737 #[cfg(any(target_os = "android", 738 target_os = "haiku", 739 target_os = "ios", 740 target_os = "linux", 741 target_os = "macos"))] 742 #[cfg_attr(docsrs, doc(cfg(all())))] 743 TAB2 as tcflag_t; 744 #[cfg(any(target_os = "android", 745 target_os = "freebsd", 746 target_os = "haiku", 747 target_os = "ios", 748 target_os = "linux", 749 target_os = "macos"))] 750 #[cfg_attr(docsrs, doc(cfg(all())))] 751 TAB3 as tcflag_t; 752 #[cfg(any(target_os = "android", target_os = "linux"))] 753 #[cfg_attr(docsrs, doc(cfg(all())))] 754 XTABS; 755 #[cfg(any(target_os = "android", 756 target_os = "haiku", 757 target_os = "ios", 758 target_os = "linux", 759 target_os = "macos"))] 760 #[cfg_attr(docsrs, doc(cfg(all())))] 761 BS0 as tcflag_t; 762 #[cfg(any(target_os = "android", 763 target_os = "haiku", 764 target_os = "ios", 765 target_os = "linux", 766 target_os = "macos"))] 767 #[cfg_attr(docsrs, doc(cfg(all())))] 768 BS1 as tcflag_t; 769 #[cfg(any(target_os = "android", 770 target_os = "haiku", 771 target_os = "ios", 772 target_os = "linux", 773 target_os = "macos"))] 774 #[cfg_attr(docsrs, doc(cfg(all())))] 775 VT0 as tcflag_t; 776 #[cfg(any(target_os = "android", 777 target_os = "haiku", 778 target_os = "ios", 779 target_os = "linux", 780 target_os = "macos"))] 781 #[cfg_attr(docsrs, doc(cfg(all())))] 782 VT1 as tcflag_t; 783 #[cfg(any(target_os = "android", 784 target_os = "haiku", 785 target_os = "ios", 786 target_os = "linux", 787 target_os = "macos"))] 788 #[cfg_attr(docsrs, doc(cfg(all())))] 789 FF0 as tcflag_t; 790 #[cfg(any(target_os = "android", 791 target_os = "haiku", 792 target_os = "ios", 793 target_os = "linux", 794 target_os = "macos"))] 795 #[cfg_attr(docsrs, doc(cfg(all())))] 796 FF1 as tcflag_t; 797 #[cfg(any(target_os = "freebsd", 798 target_os = "dragonfly", 799 target_os = "ios", 800 target_os = "macos", 801 target_os = "netbsd", 802 target_os = "openbsd"))] 803 #[cfg_attr(docsrs, doc(cfg(all())))] 804 OXTABS; 805 #[cfg(any(target_os = "freebsd", 806 target_os = "dragonfly", 807 target_os = "macos", 808 target_os = "netbsd", 809 target_os = "openbsd"))] 810 #[cfg_attr(docsrs, doc(cfg(all())))] 811 ONOEOT as tcflag_t; 812 813 // Bitmasks for use with OutputFlags to select specific settings 814 // These should be moved to be a mask once https://github.com/rust-lang-nursery/bitflags/issues/110 815 // is resolved. 816 817 #[cfg(any(target_os = "android", 818 target_os = "haiku", 819 target_os = "ios", 820 target_os = "linux", 821 target_os = "macos"))] 822 #[cfg_attr(docsrs, doc(cfg(all())))] 823 NLDLY as tcflag_t; // FIXME: Datatype needs to be corrected in libc for mac 824 #[cfg(any(target_os = "android", 825 target_os = "haiku", 826 target_os = "ios", 827 target_os = "linux", 828 target_os = "macos"))] 829 #[cfg_attr(docsrs, doc(cfg(all())))] 830 CRDLY as tcflag_t; 831 #[cfg(any(target_os = "android", 832 target_os = "freebsd", 833 target_os = "haiku", 834 target_os = "ios", 835 target_os = "linux", 836 target_os = "macos"))] 837 #[cfg_attr(docsrs, doc(cfg(all())))] 838 TABDLY as tcflag_t; 839 #[cfg(any(target_os = "android", 840 target_os = "haiku", 841 target_os = "ios", 842 target_os = "linux", 843 target_os = "macos"))] 844 #[cfg_attr(docsrs, doc(cfg(all())))] 845 BSDLY as tcflag_t; 846 #[cfg(any(target_os = "android", 847 target_os = "haiku", 848 target_os = "ios", 849 target_os = "linux", 850 target_os = "macos"))] 851 #[cfg_attr(docsrs, doc(cfg(all())))] 852 VTDLY as tcflag_t; 853 #[cfg(any(target_os = "android", 854 target_os = "haiku", 855 target_os = "ios", 856 target_os = "linux", 857 target_os = "macos"))] 858 #[cfg_attr(docsrs, doc(cfg(all())))] 859 FFDLY as tcflag_t; 860 } 861} 862 863libc_bitflags! { 864 /// Flags for setting the control mode of a terminal 865 pub struct ControlFlags: tcflag_t { 866 #[cfg(any(target_os = "dragonfly", 867 target_os = "freebsd", 868 target_os = "ios", 869 target_os = "macos", 870 target_os = "netbsd", 871 target_os = "openbsd"))] 872 #[cfg_attr(docsrs, doc(cfg(all())))] 873 CIGNORE; 874 CS5; 875 CS6; 876 CS7; 877 CS8; 878 CSTOPB; 879 CREAD; 880 PARENB; 881 PARODD; 882 HUPCL; 883 CLOCAL; 884 #[cfg(not(target_os = "redox"))] 885 #[cfg_attr(docsrs, doc(cfg(all())))] 886 CRTSCTS; 887 #[cfg(any(target_os = "android", target_os = "linux"))] 888 #[cfg_attr(docsrs, doc(cfg(all())))] 889 CBAUD; 890 #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "mips"))))] 891 #[cfg_attr(docsrs, doc(cfg(all())))] 892 CMSPAR; 893 #[cfg(any(target_os = "android", 894 all(target_os = "linux", 895 not(any(target_arch = "powerpc", target_arch = "powerpc64")))))] 896 CIBAUD; 897 #[cfg(any(target_os = "android", target_os = "linux"))] 898 #[cfg_attr(docsrs, doc(cfg(all())))] 899 CBAUDEX; 900 #[cfg(any(target_os = "dragonfly", 901 target_os = "freebsd", 902 target_os = "macos", 903 target_os = "netbsd", 904 target_os = "openbsd"))] 905 #[cfg_attr(docsrs, doc(cfg(all())))] 906 MDMBUF; 907 #[cfg(any(target_os = "netbsd", target_os = "openbsd"))] 908 #[cfg_attr(docsrs, doc(cfg(all())))] 909 CHWFLOW; 910 #[cfg(any(target_os = "dragonfly", 911 target_os = "freebsd", 912 target_os = "netbsd", 913 target_os = "openbsd"))] 914 #[cfg_attr(docsrs, doc(cfg(all())))] 915 CCTS_OFLOW; 916 #[cfg(any(target_os = "dragonfly", 917 target_os = "freebsd", 918 target_os = "netbsd", 919 target_os = "openbsd"))] 920 #[cfg_attr(docsrs, doc(cfg(all())))] 921 CRTS_IFLOW; 922 #[cfg(any(target_os = "dragonfly", 923 target_os = "freebsd"))] 924 #[cfg_attr(docsrs, doc(cfg(all())))] 925 CDTR_IFLOW; 926 #[cfg(any(target_os = "dragonfly", 927 target_os = "freebsd"))] 928 #[cfg_attr(docsrs, doc(cfg(all())))] 929 CDSR_OFLOW; 930 #[cfg(any(target_os = "dragonfly", 931 target_os = "freebsd"))] 932 #[cfg_attr(docsrs, doc(cfg(all())))] 933 CCAR_OFLOW; 934 935 // Bitmasks for use with ControlFlags to select specific settings 936 // These should be moved to be a mask once https://github.com/rust-lang-nursery/bitflags/issues/110 937 // is resolved. 938 939 CSIZE; 940 } 941} 942 943libc_bitflags! { 944 /// Flags for setting any local modes 945 pub struct LocalFlags: tcflag_t { 946 #[cfg(not(target_os = "redox"))] 947 #[cfg_attr(docsrs, doc(cfg(all())))] 948 ECHOKE; 949 ECHOE; 950 ECHOK; 951 ECHO; 952 ECHONL; 953 #[cfg(not(target_os = "redox"))] 954 #[cfg_attr(docsrs, doc(cfg(all())))] 955 ECHOPRT; 956 #[cfg(not(target_os = "redox"))] 957 #[cfg_attr(docsrs, doc(cfg(all())))] 958 ECHOCTL; 959 ISIG; 960 ICANON; 961 #[cfg(any(target_os = "freebsd", 962 target_os = "dragonfly", 963 target_os = "ios", 964 target_os = "macos", 965 target_os = "netbsd", 966 target_os = "openbsd"))] 967 #[cfg_attr(docsrs, doc(cfg(all())))] 968 ALTWERASE; 969 IEXTEN; 970 #[cfg(not(any(target_os = "redox", target_os = "haiku")))] 971 #[cfg_attr(docsrs, doc(cfg(all())))] 972 EXTPROC; 973 TOSTOP; 974 #[cfg(not(target_os = "redox"))] 975 #[cfg_attr(docsrs, doc(cfg(all())))] 976 FLUSHO; 977 #[cfg(any(target_os = "freebsd", 978 target_os = "dragonfly", 979 target_os = "ios", 980 target_os = "macos", 981 target_os = "netbsd", 982 target_os = "openbsd"))] 983 #[cfg_attr(docsrs, doc(cfg(all())))] 984 NOKERNINFO; 985 #[cfg(not(target_os = "redox"))] 986 #[cfg_attr(docsrs, doc(cfg(all())))] 987 PENDIN; 988 NOFLSH; 989 } 990} 991 992cfg_if! { 993 if #[cfg(any(target_os = "freebsd", 994 target_os = "dragonfly", 995 target_os = "ios", 996 target_os = "macos", 997 target_os = "netbsd", 998 target_os = "openbsd"))] { 999 /// Get input baud rate (see 1000 /// [cfgetispeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetispeed.html)). 1001 /// 1002 /// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure. 1003 // The cast is not unnecessary on all platforms. 1004 #[allow(clippy::unnecessary_cast)] 1005 pub fn cfgetispeed(termios: &Termios) -> u32 { 1006 let inner_termios = termios.get_libc_termios(); 1007 unsafe { libc::cfgetispeed(&*inner_termios) as u32 } 1008 } 1009 1010 /// Get output baud rate (see 1011 /// [cfgetospeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetospeed.html)). 1012 /// 1013 /// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure. 1014 // The cast is not unnecessary on all platforms. 1015 #[allow(clippy::unnecessary_cast)] 1016 pub fn cfgetospeed(termios: &Termios) -> u32 { 1017 let inner_termios = termios.get_libc_termios(); 1018 unsafe { libc::cfgetospeed(&*inner_termios) as u32 } 1019 } 1020 1021 /// Set input baud rate (see 1022 /// [cfsetispeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetispeed.html)). 1023 /// 1024 /// `cfsetispeed()` sets the intput baud rate in the given `Termios` structure. 1025 pub fn cfsetispeed<T: Into<u32>>(termios: &mut Termios, baud: T) -> Result<()> { 1026 let inner_termios = unsafe { termios.get_libc_termios_mut() }; 1027 let res = unsafe { libc::cfsetispeed(inner_termios, baud.into() as libc::speed_t) }; 1028 termios.update_wrapper(); 1029 Errno::result(res).map(drop) 1030 } 1031 1032 /// Set output baud rate (see 1033 /// [cfsetospeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetospeed.html)). 1034 /// 1035 /// `cfsetospeed()` sets the output baud rate in the given termios structure. 1036 pub fn cfsetospeed<T: Into<u32>>(termios: &mut Termios, baud: T) -> Result<()> { 1037 let inner_termios = unsafe { termios.get_libc_termios_mut() }; 1038 let res = unsafe { libc::cfsetospeed(inner_termios, baud.into() as libc::speed_t) }; 1039 termios.update_wrapper(); 1040 Errno::result(res).map(drop) 1041 } 1042 1043 /// Set both the input and output baud rates (see 1044 /// [termios(3)](https://www.freebsd.org/cgi/man.cgi?query=cfsetspeed)). 1045 /// 1046 /// `cfsetspeed()` sets the input and output baud rate in the given termios structure. Note that 1047 /// this is part of the 4.4BSD standard and not part of POSIX. 1048 pub fn cfsetspeed<T: Into<u32>>(termios: &mut Termios, baud: T) -> Result<()> { 1049 let inner_termios = unsafe { termios.get_libc_termios_mut() }; 1050 let res = unsafe { libc::cfsetspeed(inner_termios, baud.into() as libc::speed_t) }; 1051 termios.update_wrapper(); 1052 Errno::result(res).map(drop) 1053 } 1054 } else { 1055 use std::convert::TryInto; 1056 1057 /// Get input baud rate (see 1058 /// [cfgetispeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetispeed.html)). 1059 /// 1060 /// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure. 1061 pub fn cfgetispeed(termios: &Termios) -> BaudRate { 1062 let inner_termios = termios.get_libc_termios(); 1063 unsafe { libc::cfgetispeed(&*inner_termios) }.try_into().unwrap() 1064 } 1065 1066 /// Get output baud rate (see 1067 /// [cfgetospeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetospeed.html)). 1068 /// 1069 /// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure. 1070 pub fn cfgetospeed(termios: &Termios) -> BaudRate { 1071 let inner_termios = termios.get_libc_termios(); 1072 unsafe { libc::cfgetospeed(&*inner_termios) }.try_into().unwrap() 1073 } 1074 1075 /// Set input baud rate (see 1076 /// [cfsetispeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetispeed.html)). 1077 /// 1078 /// `cfsetispeed()` sets the intput baud rate in the given `Termios` structure. 1079 pub fn cfsetispeed(termios: &mut Termios, baud: BaudRate) -> Result<()> { 1080 let inner_termios = unsafe { termios.get_libc_termios_mut() }; 1081 let res = unsafe { libc::cfsetispeed(inner_termios, baud as libc::speed_t) }; 1082 termios.update_wrapper(); 1083 Errno::result(res).map(drop) 1084 } 1085 1086 /// Set output baud rate (see 1087 /// [cfsetospeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetospeed.html)). 1088 /// 1089 /// `cfsetospeed()` sets the output baud rate in the given `Termios` structure. 1090 pub fn cfsetospeed(termios: &mut Termios, baud: BaudRate) -> Result<()> { 1091 let inner_termios = unsafe { termios.get_libc_termios_mut() }; 1092 let res = unsafe { libc::cfsetospeed(inner_termios, baud as libc::speed_t) }; 1093 termios.update_wrapper(); 1094 Errno::result(res).map(drop) 1095 } 1096 1097 /// Set both the input and output baud rates (see 1098 /// [termios(3)](https://www.freebsd.org/cgi/man.cgi?query=cfsetspeed)). 1099 /// 1100 /// `cfsetspeed()` sets the input and output baud rate in the given `Termios` structure. Note that 1101 /// this is part of the 4.4BSD standard and not part of POSIX. 1102 #[cfg(not(target_os = "haiku"))] 1103 pub fn cfsetspeed(termios: &mut Termios, baud: BaudRate) -> Result<()> { 1104 let inner_termios = unsafe { termios.get_libc_termios_mut() }; 1105 let res = unsafe { libc::cfsetspeed(inner_termios, baud as libc::speed_t) }; 1106 termios.update_wrapper(); 1107 Errno::result(res).map(drop) 1108 } 1109 } 1110} 1111 1112/// Configures the port to something like the "raw" mode of the old Version 7 terminal driver (see 1113/// [termios(3)](https://man7.org/linux/man-pages/man3/termios.3.html)). 1114/// 1115/// `cfmakeraw()` configures the termios structure such that input is available character-by- 1116/// character, echoing is disabled, and all special input and output processing is disabled. Note 1117/// that this is a non-standard function, but is available on Linux and BSDs. 1118pub fn cfmakeraw(termios: &mut Termios) { 1119 let inner_termios = unsafe { termios.get_libc_termios_mut() }; 1120 unsafe { 1121 libc::cfmakeraw(inner_termios); 1122 } 1123 termios.update_wrapper(); 1124} 1125 1126/// Configures the port to "sane" mode (like the configuration of a newly created terminal) (see 1127/// [tcsetattr(3)](https://www.freebsd.org/cgi/man.cgi?query=tcsetattr)). 1128/// 1129/// Note that this is a non-standard function, available on FreeBSD. 1130#[cfg(target_os = "freebsd")] 1131#[cfg_attr(docsrs, doc(cfg(all())))] 1132pub fn cfmakesane(termios: &mut Termios) { 1133 let inner_termios = unsafe { termios.get_libc_termios_mut() }; 1134 unsafe { 1135 libc::cfmakesane(inner_termios); 1136 } 1137 termios.update_wrapper(); 1138} 1139 1140/// Return the configuration of a port 1141/// [tcgetattr(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetattr.html)). 1142/// 1143/// `tcgetattr()` returns a `Termios` structure with the current configuration for a port. Modifying 1144/// this structure *will not* reconfigure the port, instead the modifications should be done to 1145/// the `Termios` structure and then the port should be reconfigured using `tcsetattr()`. 1146pub fn tcgetattr(fd: RawFd) -> Result<Termios> { 1147 let mut termios = mem::MaybeUninit::uninit(); 1148 1149 let res = unsafe { libc::tcgetattr(fd, termios.as_mut_ptr()) }; 1150 1151 Errno::result(res)?; 1152 1153 unsafe { Ok(termios.assume_init().into()) } 1154} 1155 1156/// Set the configuration for a terminal (see 1157/// [tcsetattr(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetattr.html)). 1158/// 1159/// `tcsetattr()` reconfigures the given port based on a given `Termios` structure. This change 1160/// takes affect at a time specified by `actions`. Note that this function may return success if 1161/// *any* of the parameters were successfully set, not only if all were set successfully. 1162pub fn tcsetattr(fd: RawFd, actions: SetArg, termios: &Termios) -> Result<()> { 1163 let inner_termios = termios.get_libc_termios(); 1164 Errno::result(unsafe { 1165 libc::tcsetattr(fd, actions as c_int, &*inner_termios) 1166 }) 1167 .map(drop) 1168} 1169 1170/// Block until all output data is written (see 1171/// [tcdrain(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcdrain.html)). 1172pub fn tcdrain(fd: RawFd) -> Result<()> { 1173 Errno::result(unsafe { libc::tcdrain(fd) }).map(drop) 1174} 1175 1176/// Suspend or resume the transmission or reception of data (see 1177/// [tcflow(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcflow.html)). 1178/// 1179/// `tcflow()` suspends of resumes the transmission or reception of data for the given port 1180/// depending on the value of `action`. 1181pub fn tcflow(fd: RawFd, action: FlowArg) -> Result<()> { 1182 Errno::result(unsafe { libc::tcflow(fd, action as c_int) }).map(drop) 1183} 1184 1185/// Discard data in the output or input queue (see 1186/// [tcflush(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcflush.html)). 1187/// 1188/// `tcflush()` will discard data for a terminal port in the input queue, output queue, or both 1189/// depending on the value of `action`. 1190pub fn tcflush(fd: RawFd, action: FlushArg) -> Result<()> { 1191 Errno::result(unsafe { libc::tcflush(fd, action as c_int) }).map(drop) 1192} 1193 1194/// Send a break for a specific duration (see 1195/// [tcsendbreak(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsendbreak.html)). 1196/// 1197/// When using asynchronous data transmission `tcsendbreak()` will transmit a continuous stream 1198/// of zero-valued bits for an implementation-defined duration. 1199pub fn tcsendbreak(fd: RawFd, duration: c_int) -> Result<()> { 1200 Errno::result(unsafe { libc::tcsendbreak(fd, duration) }).map(drop) 1201} 1202 1203feature! { 1204#![feature = "process"] 1205/// Get the session controlled by the given terminal (see 1206/// [tcgetsid(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetsid.html)). 1207pub fn tcgetsid(fd: RawFd) -> Result<Pid> { 1208 let res = unsafe { libc::tcgetsid(fd) }; 1209 1210 Errno::result(res).map(Pid::from_raw) 1211} 1212} 1213 1214#[cfg(test)] 1215mod test { 1216 use super::*; 1217 use std::convert::TryFrom; 1218 1219 #[test] 1220 fn try_from() { 1221 assert_eq!(Ok(BaudRate::B0), BaudRate::try_from(libc::B0)); 1222 #[cfg(not(target_os = "haiku"))] 1223 BaudRate::try_from(999999999).expect_err("assertion failed"); 1224 #[cfg(target_os = "haiku")] 1225 BaudRate::try_from(99).expect_err("assertion failed"); 1226 } 1227} 1228