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 //! ```
218 use crate::errno::Errno;
219 use crate::Result;
220 use cfg_if::cfg_if;
221 use libc::{self, c_int, tcflag_t};
222 use std::cell::{Ref, RefCell};
223 use std::convert::From;
224 use std::mem;
225 use std::os::unix::io::RawFd;
226
227 #[cfg(feature = "process")]
228 use 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)]
236 pub 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
256 impl 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.
get_libc_termios(&self) -> Ref<libc::termios>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.
get_libc_termios_mut(&mut self) -> *mut libc::termios287 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.
update_wrapper(&mut self)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
326 impl From<libc::termios> for Termios {
from(termios: libc::termios) -> Self327 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
345 impl From<Termios> for libc::termios {
from(termios: Termios) -> Self346 fn from(termios: Termios) -> Self {
347 termios.inner.into_inner()
348 }
349 }
350
351 libc_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 ))]
474 impl From<BaudRate> for u32 {
from(b: BaudRate) -> u32475 fn from(b: BaudRate) -> u32 {
476 b as u32
477 }
478 }
479
480 #[cfg(target_os = "haiku")]
481 impl From<BaudRate> for u8 {
from(b: BaudRate) -> u8482 fn from(b: BaudRate) -> u8 {
483 b as u8
484 }
485 }
486
487 // TODO: Add TCSASOFT, which will require treating this as a bitfield.
488 libc_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
504 libc_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
520 libc_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"))]
540 libc_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 ))]
608 impl SpecialCharacterIndices {
609 pub const VMIN: SpecialCharacterIndices = SpecialCharacterIndices::VEOF;
610 pub const VTIME: SpecialCharacterIndices = SpecialCharacterIndices::VEOL;
611 }
612
613 pub 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())))]
624 pub use libc::_POSIX_VDISABLE;
625
626 libc_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
652 libc_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
863 libc_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
943 libc_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
992 cfg_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.
cfmakeraw(termios: &mut Termios)1118 pub 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())))]
cfmakesane(termios: &mut Termios)1132 pub 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()`.
tcgetattr(fd: RawFd) -> Result<Termios>1146 pub 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.
tcsetattr(fd: RawFd, actions: SetArg, termios: &Termios) -> Result<()>1162 pub 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)).
tcdrain(fd: RawFd) -> Result<()>1172 pub 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`.
tcflow(fd: RawFd, action: FlowArg) -> Result<()>1181 pub 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`.
tcflush(fd: RawFd, action: FlushArg) -> Result<()>1190 pub 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.
tcsendbreak(fd: RawFd, duration: c_int) -> Result<()>1199 pub fn tcsendbreak(fd: RawFd, duration: c_int) -> Result<()> {
1200 Errno::result(unsafe { libc::tcsendbreak(fd, duration) }).map(drop)
1201 }
1202
1203 feature! {
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)).
1207 pub 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)]
1215 mod test {
1216 use super::*;
1217 use std::convert::TryFrom;
1218
1219 #[test]
try_from()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