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(bsd, doc = " ```rust,ignore")]
89 #![cfg_attr(not(bsd), doc = " ```rust")]
90 //! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetspeed, Termios};
91 //! # fn main() {
92 //! # let mut t: Termios = unsafe { std::mem::zeroed() };
93 //! # cfsetspeed(&mut t, BaudRate::B9600);
94 //! assert_eq!(cfgetispeed(&t), BaudRate::B9600);
95 //! assert_eq!(cfgetospeed(&t), BaudRate::B9600);
96 //! # }
97 //! ```
98 //!
99 //! But on the BSDs, `cfgetispeed()` and `cfgetospeed()` both return `u32`s:
100 //!
101 #![cfg_attr(bsd, doc = " ```rust")]
102 #![cfg_attr(not(bsd), doc = " ```rust,ignore")]
103 //! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetspeed, Termios};
104 //! # fn main() {
105 //! # let mut t: Termios = unsafe { std::mem::zeroed() };
106 //! # cfsetspeed(&mut t, 9600u32);
107 //! assert_eq!(cfgetispeed(&t), 9600u32);
108 //! assert_eq!(cfgetospeed(&t), 9600u32);
109 //! # }
110 //! ```
111 //!
112 //! It's trivial to convert from a `BaudRate` to a `u32` on BSDs:
113 //!
114 #![cfg_attr(bsd, doc = " ```rust")]
115 #![cfg_attr(not(bsd), doc = " ```rust,ignore")]
116 //! # use nix::sys::termios::{BaudRate, cfgetispeed, cfsetspeed, Termios};
117 //! # fn main() {
118 //! # let mut t: Termios = unsafe { std::mem::zeroed() };
119 //! # cfsetspeed(&mut t, 9600u32);
120 //! assert_eq!(cfgetispeed(&t), BaudRate::B9600.into());
121 //! assert_eq!(u32::from(BaudRate::B9600), 9600u32);
122 //! # }
123 //! ```
124 //!
125 //! And on BSDs you can specify arbitrary baud rates (**note** this depends on hardware support)
126 //! by specifying baud rates directly using `u32`s:
127 //!
128 #![cfg_attr(bsd, doc = " ```rust")]
129 #![cfg_attr(not(bsd), doc = " ```rust,ignore")]
130 //! # use nix::sys::termios::{cfsetispeed, cfsetospeed, cfsetspeed, Termios};
131 //! # fn main() {
132 //! # let mut t: Termios = unsafe { std::mem::zeroed() };
133 //! cfsetispeed(&mut t, 9600u32);
134 //! cfsetospeed(&mut t, 9600u32);
135 //! cfsetspeed(&mut t, 9600u32);
136 //! # }
137 //! ```
138 use crate::errno::Errno;
139 use crate::Result;
140 use cfg_if::cfg_if;
141 use libc::{self, c_int, tcflag_t};
142 use std::cell::{Ref, RefCell};
143 use std::convert::From;
144 use std::mem;
145 use std::os::unix::io::{AsFd, AsRawFd};
146
147 #[cfg(feature = "process")]
148 use crate::unistd::Pid;
149
150 /// Stores settings for the termios API
151 ///
152 /// This is a wrapper around the `libc::termios` struct that provides a safe interface for the
153 /// standard fields. The only safe way to obtain an instance of this struct is to extract it from
154 /// an open port using `tcgetattr()`.
155 #[derive(Clone, Debug, Eq, PartialEq)]
156 pub struct Termios {
157 inner: RefCell<libc::termios>,
158 /// Input mode flags (see `termios.c_iflag` documentation)
159 pub input_flags: InputFlags,
160 /// Output mode flags (see `termios.c_oflag` documentation)
161 pub output_flags: OutputFlags,
162 /// Control mode flags (see `termios.c_cflag` documentation)
163 pub control_flags: ControlFlags,
164 /// Local mode flags (see `termios.c_lflag` documentation)
165 pub local_flags: LocalFlags,
166 /// Control characters (see `termios.c_cc` documentation)
167 pub control_chars: [libc::cc_t; NCCS],
168 /// Line discipline (see `termios.c_line` documentation)
169 #[cfg(linux_android)]
170 pub line_discipline: libc::cc_t,
171 /// Line discipline (see `termios.c_line` documentation)
172 #[cfg(target_os = "haiku")]
173 pub line_discipline: libc::c_char,
174 }
175
176 impl Termios {
177 /// Exposes an immutable reference to the underlying `libc::termios` data structure.
178 ///
179 /// This is not part of `nix`'s public API because it requires additional work to maintain type
180 /// safety.
get_libc_termios(&self) -> Ref<libc::termios>181 pub(crate) fn get_libc_termios(&self) -> Ref<libc::termios> {
182 {
183 let mut termios = self.inner.borrow_mut();
184 termios.c_iflag = self.input_flags.bits();
185 termios.c_oflag = self.output_flags.bits();
186 termios.c_cflag = self.control_flags.bits();
187 termios.c_lflag = self.local_flags.bits();
188 termios.c_cc = self.control_chars;
189 #[cfg(any(linux_android, target_os = "haiku"))]
190 {
191 termios.c_line = self.line_discipline;
192 }
193 }
194 self.inner.borrow()
195 }
196
197 /// Exposes the inner `libc::termios` datastore within `Termios`.
198 ///
199 /// This is unsafe because if this is used to modify the inner `libc::termios` struct, it will
200 /// not automatically update the safe wrapper type around it. In this case it should also be
201 /// paired with a call to `update_wrapper()` so that the wrapper-type and internal
202 /// representation stay consistent.
get_libc_termios_mut(&mut self) -> *mut libc::termios203 pub(crate) unsafe fn get_libc_termios_mut(&mut self) -> *mut libc::termios {
204 {
205 let mut termios = self.inner.borrow_mut();
206 termios.c_iflag = self.input_flags.bits();
207 termios.c_oflag = self.output_flags.bits();
208 termios.c_cflag = self.control_flags.bits();
209 termios.c_lflag = self.local_flags.bits();
210 termios.c_cc = self.control_chars;
211 #[cfg(any(linux_android, target_os = "haiku"))]
212 {
213 termios.c_line = self.line_discipline;
214 }
215 }
216 self.inner.as_ptr()
217 }
218
219 /// Updates the wrapper values from the internal `libc::termios` data structure.
update_wrapper(&mut self)220 pub(crate) fn update_wrapper(&mut self) {
221 let termios = *self.inner.borrow_mut();
222 self.input_flags = InputFlags::from_bits_truncate(termios.c_iflag);
223 self.output_flags = OutputFlags::from_bits_truncate(termios.c_oflag);
224 self.control_flags = ControlFlags::from_bits_retain(termios.c_cflag);
225 self.local_flags = LocalFlags::from_bits_truncate(termios.c_lflag);
226 self.control_chars = termios.c_cc;
227 #[cfg(any(linux_android, target_os = "haiku"))]
228 {
229 self.line_discipline = termios.c_line;
230 }
231 }
232 }
233
234 impl From<libc::termios> for Termios {
from(termios: libc::termios) -> Self235 fn from(termios: libc::termios) -> Self {
236 Termios {
237 inner: RefCell::new(termios),
238 input_flags: InputFlags::from_bits_truncate(termios.c_iflag),
239 output_flags: OutputFlags::from_bits_truncate(termios.c_oflag),
240 control_flags: ControlFlags::from_bits_truncate(termios.c_cflag),
241 local_flags: LocalFlags::from_bits_truncate(termios.c_lflag),
242 control_chars: termios.c_cc,
243 #[cfg(any(linux_android, target_os = "haiku"))]
244 line_discipline: termios.c_line,
245 }
246 }
247 }
248
249 impl From<Termios> for libc::termios {
from(termios: Termios) -> Self250 fn from(termios: Termios) -> Self {
251 termios.inner.into_inner()
252 }
253 }
254
255 libc_enum! {
256 /// Baud rates supported by the system.
257 ///
258 /// For the BSDs, arbitrary baud rates can be specified by using `u32`s directly instead of this
259 /// enum.
260 ///
261 /// B0 is special and will disable the port.
262 #[cfg_attr(target_os = "haiku", repr(u8))]
263 #[cfg_attr(target_os = "hurd", repr(i32))]
264 #[cfg_attr(all(apple_targets, target_pointer_width = "64"), repr(u64))]
265 #[cfg_attr(all(
266 not(all(apple_targets, target_pointer_width = "64")),
267 not(target_os = "haiku"),
268 not(target_os = "hurd")
269 ), repr(u32))]
270 #[non_exhaustive]
271 pub enum BaudRate {
272 B0,
273 B50,
274 B75,
275 B110,
276 B134,
277 B150,
278 B200,
279 B300,
280 B600,
281 B1200,
282 B1800,
283 B2400,
284 B4800,
285 #[cfg(bsd)]
286 B7200,
287 B9600,
288 #[cfg(bsd)]
289 B14400,
290 B19200,
291 #[cfg(bsd)]
292 B28800,
293 B38400,
294 #[cfg(not(target_os = "aix"))]
295 B57600,
296 #[cfg(bsd)]
297 B76800,
298 #[cfg(not(target_os = "aix"))]
299 B115200,
300 #[cfg(solarish)]
301 B153600,
302 #[cfg(not(target_os = "aix"))]
303 B230400,
304 #[cfg(solarish)]
305 B307200,
306 #[cfg(any(linux_android,
307 solarish,
308 target_os = "freebsd",
309 target_os = "netbsd"))]
310 B460800,
311 #[cfg(linux_android)]
312 B500000,
313 #[cfg(linux_android)]
314 B576000,
315 #[cfg(any(linux_android,
316 solarish,
317 target_os = "freebsd",
318 target_os = "netbsd"))]
319 B921600,
320 #[cfg(linux_android)]
321 B1000000,
322 #[cfg(linux_android)]
323 B1152000,
324 #[cfg(linux_android)]
325 B1500000,
326 #[cfg(linux_android)]
327 B2000000,
328 #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
329 B2500000,
330 #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
331 B3000000,
332 #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
333 B3500000,
334 #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
335 B4000000,
336 }
337 impl TryFrom<libc::speed_t>
338 }
339
340 #[cfg(bsd)]
341 impl From<BaudRate> for u32 {
from(b: BaudRate) -> u32342 fn from(b: BaudRate) -> u32 {
343 b as u32
344 }
345 }
346
347 #[cfg(target_os = "haiku")]
348 impl From<BaudRate> for u8 {
from(b: BaudRate) -> u8349 fn from(b: BaudRate) -> u8 {
350 b as u8
351 }
352 }
353
354 // TODO: Add TCSASOFT, which will require treating this as a bitfield.
355 libc_enum! {
356 /// Specify when a port configuration change should occur.
357 ///
358 /// Used as an argument to `tcsetattr()`
359 #[repr(i32)]
360 #[non_exhaustive]
361 pub enum SetArg {
362 /// The change will occur immediately
363 TCSANOW,
364 /// The change occurs after all output has been written
365 TCSADRAIN,
366 /// Same as `TCSADRAIN`, but will also flush the input buffer
367 TCSAFLUSH,
368 }
369 }
370
371 libc_enum! {
372 /// Specify a combination of the input and output buffers to flush
373 ///
374 /// Used as an argument to `tcflush()`.
375 #[repr(i32)]
376 #[non_exhaustive]
377 pub enum FlushArg {
378 /// Flush data that was received but not read
379 TCIFLUSH,
380 /// Flush data written but not transmitted
381 TCOFLUSH,
382 /// Flush both received data not read and written data not transmitted
383 TCIOFLUSH,
384 }
385 }
386
387 libc_enum! {
388 /// Specify how transmission flow should be altered
389 ///
390 /// Used as an argument to `tcflow()`.
391 #[repr(i32)]
392 #[non_exhaustive]
393 pub enum FlowArg {
394 /// Suspend transmission
395 TCOOFF,
396 /// Resume transmission
397 TCOON,
398 /// Transmit a STOP character, which should disable a connected terminal device
399 TCIOFF,
400 /// Transmit a START character, which should re-enable a connected terminal device
401 TCION,
402 }
403 }
404
405 // TODO: Make this usable directly as a slice index.
406 libc_enum! {
407 /// Indices into the `termios.c_cc` array for special characters.
408 #[repr(usize)]
409 #[non_exhaustive]
410 pub enum SpecialCharacterIndices {
411 #[cfg(not(any(target_os = "aix", target_os = "haiku")))]
412 VDISCARD,
413 #[cfg(any(bsd,
414 solarish,
415 target_os = "aix"))]
416 VDSUSP,
417 VEOF,
418 VEOL,
419 VEOL2,
420 VERASE,
421 #[cfg(any(freebsdlike, solarish))]
422 VERASE2,
423 VINTR,
424 VKILL,
425 #[cfg(not(target_os = "haiku"))]
426 VLNEXT,
427 #[cfg(not(any(all(target_os = "linux", target_arch = "sparc64"),
428 solarish, target_os = "aix", target_os = "haiku")))]
429 VMIN,
430 VQUIT,
431 #[cfg(not(target_os = "haiku"))]
432 VREPRINT,
433 VSTART,
434 #[cfg(any(bsd, solarish))]
435 VSTATUS,
436 VSTOP,
437 VSUSP,
438 #[cfg(target_os = "linux")]
439 VSWTC,
440 #[cfg(any(solarish, target_os = "haiku"))]
441 VSWTCH,
442 #[cfg(not(any(all(target_os = "linux", target_arch = "sparc64"),
443 solarish, target_os = "aix", target_os = "haiku")))]
444 VTIME,
445 #[cfg(not(any(target_os = "aix", target_os = "haiku")))]
446 VWERASE,
447 #[cfg(target_os = "dragonfly")]
448 VCHECKPT,
449 }
450 }
451
452 #[cfg(any(
453 all(target_os = "linux", target_arch = "sparc64"),
454 solarish,
455 target_os = "aix",
456 target_os = "haiku",
457 ))]
458 impl SpecialCharacterIndices {
459 pub const VMIN: SpecialCharacterIndices = SpecialCharacterIndices::VEOF;
460 pub const VTIME: SpecialCharacterIndices = SpecialCharacterIndices::VEOL;
461 }
462
463 pub use libc::NCCS;
464 #[cfg(any(linux_android, target_os = "aix", bsd))]
465 pub use libc::_POSIX_VDISABLE;
466
467 libc_bitflags! {
468 /// Flags for configuring the input mode of a terminal
469 pub struct InputFlags: tcflag_t {
470 IGNBRK;
471 BRKINT;
472 IGNPAR;
473 PARMRK;
474 INPCK;
475 ISTRIP;
476 INLCR;
477 IGNCR;
478 ICRNL;
479 IXON;
480 IXOFF;
481 #[cfg(not(target_os = "redox"))]
482 IXANY;
483 #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
484 IMAXBEL;
485 #[cfg(any(linux_android, apple_targets))]
486 IUTF8;
487 }
488 }
489
490 libc_bitflags! {
491 /// Flags for configuring the output mode of a terminal
492 pub struct OutputFlags: tcflag_t {
493 OPOST;
494 #[cfg(any(linux_android,
495 target_os = "haiku",
496 target_os = "openbsd"))]
497 OLCUC;
498 ONLCR;
499 OCRNL as tcflag_t;
500 ONOCR as tcflag_t;
501 ONLRET as tcflag_t;
502 #[cfg(any(linux_android,
503 target_os = "haiku",
504 apple_targets))]
505 OFDEL as tcflag_t;
506 #[cfg(any(linux_android,
507 target_os = "haiku",
508 apple_targets))]
509 NL0 as tcflag_t;
510 #[cfg(any(linux_android,
511 target_os = "haiku",
512 apple_targets))]
513 NL1 as tcflag_t;
514 #[cfg(any(linux_android,
515 target_os = "haiku",
516 apple_targets))]
517 CR0 as tcflag_t;
518 #[cfg(any(linux_android,
519 target_os = "haiku",
520 apple_targets))]
521 CR1 as tcflag_t;
522 #[cfg(any(linux_android,
523 target_os = "haiku",
524 apple_targets))]
525 CR2 as tcflag_t;
526 #[cfg(any(linux_android,
527 target_os = "haiku",
528 apple_targets))]
529 CR3 as tcflag_t;
530 #[cfg(any(linux_android,
531 target_os = "freebsd",
532 target_os = "haiku",
533 apple_targets))]
534 TAB0 as tcflag_t;
535 #[cfg(any(linux_android,
536 target_os = "haiku",
537 apple_targets))]
538 TAB1 as tcflag_t;
539 #[cfg(any(linux_android,
540 target_os = "haiku",
541 apple_targets))]
542 TAB2 as tcflag_t;
543 #[cfg(any(linux_android,
544 target_os = "freebsd",
545 target_os = "haiku",
546 apple_targets))]
547 TAB3 as tcflag_t;
548 #[cfg(linux_android)]
549 XTABS;
550 #[cfg(any(linux_android,
551 target_os = "haiku",
552 apple_targets))]
553 BS0 as tcflag_t;
554 #[cfg(any(linux_android,
555 target_os = "haiku",
556 apple_targets))]
557 BS1 as tcflag_t;
558 #[cfg(any(linux_android,
559 target_os = "haiku",
560 apple_targets))]
561 VT0 as tcflag_t;
562 #[cfg(any(linux_android,
563 target_os = "haiku",
564 apple_targets))]
565 VT1 as tcflag_t;
566 #[cfg(any(linux_android,
567 target_os = "haiku",
568 apple_targets))]
569 FF0 as tcflag_t;
570 #[cfg(any(linux_android,
571 target_os = "haiku",
572 apple_targets))]
573 FF1 as tcflag_t;
574 #[cfg(bsd)]
575 OXTABS;
576 #[cfg(bsd)]
577 ONOEOT as tcflag_t;
578
579 // Bitmasks for use with OutputFlags to select specific settings
580 // These should be moved to be a mask once https://github.com/rust-lang-nursery/bitflags/issues/110
581 // is resolved.
582
583 #[cfg(any(linux_android,
584 target_os = "haiku",
585 apple_targets))]
586 NLDLY as tcflag_t; // FIXME: Datatype needs to be corrected in libc for mac
587 #[cfg(any(linux_android,
588 target_os = "haiku",
589 apple_targets))]
590 CRDLY as tcflag_t;
591 #[cfg(any(linux_android,
592 target_os = "freebsd",
593 target_os = "haiku",
594 apple_targets))]
595 TABDLY as tcflag_t;
596 #[cfg(any(linux_android,
597 target_os = "haiku",
598 apple_targets))]
599 BSDLY as tcflag_t;
600 #[cfg(any(linux_android,
601 target_os = "haiku",
602 apple_targets))]
603 VTDLY as tcflag_t;
604 #[cfg(any(linux_android,
605 target_os = "haiku",
606 apple_targets))]
607 FFDLY as tcflag_t;
608 }
609 }
610
611 libc_bitflags! {
612 /// Flags for setting the control mode of a terminal
613 pub struct ControlFlags: tcflag_t {
614 #[cfg(bsd)]
615 CIGNORE;
616 CS5;
617 CS6;
618 CS7;
619 CS8;
620 CSTOPB;
621 CREAD;
622 PARENB;
623 PARODD;
624 HUPCL;
625 CLOCAL;
626 #[cfg(not(any(target_os = "redox", target_os = "aix")))]
627 CRTSCTS;
628 #[cfg(linux_android)]
629 CBAUD;
630 #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "mips"))))]
631 CMSPAR;
632 #[cfg(any(target_os = "android",
633 all(target_os = "linux",
634 not(any(target_arch = "powerpc", target_arch = "powerpc64")))))]
635 CIBAUD;
636 #[cfg(linux_android)]
637 CBAUDEX;
638 #[cfg(bsd)]
639 MDMBUF;
640 #[cfg(netbsdlike)]
641 CHWFLOW;
642 #[cfg(any(freebsdlike, netbsdlike))]
643 CCTS_OFLOW;
644 #[cfg(any(freebsdlike, netbsdlike))]
645 CRTS_IFLOW;
646 #[cfg(freebsdlike)]
647 CDTR_IFLOW;
648 #[cfg(freebsdlike)]
649 CDSR_OFLOW;
650 #[cfg(freebsdlike)]
651 CCAR_OFLOW;
652
653 // Bitmasks for use with ControlFlags to select specific settings
654 // These should be moved to be a mask once https://github.com/rust-lang-nursery/bitflags/issues/110
655 // is resolved.
656
657 CSIZE;
658 }
659 }
660
661 libc_bitflags! {
662 /// Flags for setting any local modes
663 pub struct LocalFlags: tcflag_t {
664 #[cfg(not(target_os = "redox"))]
665 ECHOKE;
666 ECHOE;
667 ECHOK;
668 ECHO;
669 ECHONL;
670 #[cfg(not(target_os = "redox"))]
671 ECHOPRT;
672 #[cfg(not(target_os = "redox"))]
673 ECHOCTL;
674 ISIG;
675 ICANON;
676 #[cfg(bsd)]
677 ALTWERASE;
678 IEXTEN;
679 #[cfg(not(any(target_os = "redox", target_os = "haiku", target_os = "aix")))]
680 EXTPROC;
681 TOSTOP;
682 #[cfg(not(target_os = "redox"))]
683 FLUSHO;
684 #[cfg(bsd)]
685 NOKERNINFO;
686 #[cfg(not(target_os = "redox"))]
687 PENDIN;
688 NOFLSH;
689 }
690 }
691
692 cfg_if! {
693 if #[cfg(bsd)] {
694 /// Get input baud rate (see
695 /// [cfgetispeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetispeed.html)).
696 ///
697 /// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure.
698 // The cast is not unnecessary on all platforms.
699 #[allow(clippy::unnecessary_cast)]
700 pub fn cfgetispeed(termios: &Termios) -> u32 {
701 let inner_termios = termios.get_libc_termios();
702 unsafe { libc::cfgetispeed(&*inner_termios) as u32 }
703 }
704
705 /// Get output baud rate (see
706 /// [cfgetospeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetospeed.html)).
707 ///
708 /// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure.
709 // The cast is not unnecessary on all platforms.
710 #[allow(clippy::unnecessary_cast)]
711 pub fn cfgetospeed(termios: &Termios) -> u32 {
712 let inner_termios = termios.get_libc_termios();
713 unsafe { libc::cfgetospeed(&*inner_termios) as u32 }
714 }
715
716 /// Set input baud rate (see
717 /// [cfsetispeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetispeed.html)).
718 ///
719 /// `cfsetispeed()` sets the intput baud rate in the given `Termios` structure.
720 pub fn cfsetispeed<T: Into<u32>>(termios: &mut Termios, baud: T) -> Result<()> {
721 let inner_termios = unsafe { termios.get_libc_termios_mut() };
722 let res = unsafe { libc::cfsetispeed(inner_termios, baud.into() as libc::speed_t) };
723 termios.update_wrapper();
724 Errno::result(res).map(drop)
725 }
726
727 /// Set output baud rate (see
728 /// [cfsetospeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetospeed.html)).
729 ///
730 /// `cfsetospeed()` sets the output baud rate in the given termios structure.
731 pub fn cfsetospeed<T: Into<u32>>(termios: &mut Termios, baud: T) -> Result<()> {
732 let inner_termios = unsafe { termios.get_libc_termios_mut() };
733 let res = unsafe { libc::cfsetospeed(inner_termios, baud.into() as libc::speed_t) };
734 termios.update_wrapper();
735 Errno::result(res).map(drop)
736 }
737
738 /// Set both the input and output baud rates (see
739 /// [termios(3)](https://www.freebsd.org/cgi/man.cgi?query=cfsetspeed)).
740 ///
741 /// `cfsetspeed()` sets the input and output baud rate in the given termios structure. Note that
742 /// this is part of the 4.4BSD standard and not part of POSIX.
743 pub fn cfsetspeed<T: Into<u32>>(termios: &mut Termios, baud: T) -> Result<()> {
744 let inner_termios = unsafe { termios.get_libc_termios_mut() };
745 let res = unsafe { libc::cfsetspeed(inner_termios, baud.into() as libc::speed_t) };
746 termios.update_wrapper();
747 Errno::result(res).map(drop)
748 }
749 } else {
750 use std::convert::TryInto;
751
752 /// Get input baud rate (see
753 /// [cfgetispeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetispeed.html)).
754 ///
755 /// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure.
756 pub fn cfgetispeed(termios: &Termios) -> BaudRate {
757 let inner_termios = termios.get_libc_termios();
758 unsafe { libc::cfgetispeed(&*inner_termios) }.try_into().unwrap()
759 }
760
761 /// Get output baud rate (see
762 /// [cfgetospeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetospeed.html)).
763 ///
764 /// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure.
765 pub fn cfgetospeed(termios: &Termios) -> BaudRate {
766 let inner_termios = termios.get_libc_termios();
767 unsafe { libc::cfgetospeed(&*inner_termios) }.try_into().unwrap()
768 }
769
770 /// Set input baud rate (see
771 /// [cfsetispeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetispeed.html)).
772 ///
773 /// `cfsetispeed()` sets the intput baud rate in the given `Termios` structure.
774 pub fn cfsetispeed(termios: &mut Termios, baud: BaudRate) -> Result<()> {
775 let inner_termios = unsafe { termios.get_libc_termios_mut() };
776 let res = unsafe { libc::cfsetispeed(inner_termios, baud as libc::speed_t) };
777 termios.update_wrapper();
778 Errno::result(res).map(drop)
779 }
780
781 /// Set output baud rate (see
782 /// [cfsetospeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetospeed.html)).
783 ///
784 /// `cfsetospeed()` sets the output baud rate in the given `Termios` structure.
785 pub fn cfsetospeed(termios: &mut Termios, baud: BaudRate) -> Result<()> {
786 let inner_termios = unsafe { termios.get_libc_termios_mut() };
787 let res = unsafe { libc::cfsetospeed(inner_termios, baud as libc::speed_t) };
788 termios.update_wrapper();
789 Errno::result(res).map(drop)
790 }
791
792 /// Set both the input and output baud rates (see
793 /// [termios(3)](https://www.freebsd.org/cgi/man.cgi?query=cfsetspeed)).
794 ///
795 /// `cfsetspeed()` sets the input and output baud rate in the given `Termios` structure. Note that
796 /// this is part of the 4.4BSD standard and not part of POSIX.
797 #[cfg(not(target_os = "haiku"))]
798 pub fn cfsetspeed(termios: &mut Termios, baud: BaudRate) -> Result<()> {
799 let inner_termios = unsafe { termios.get_libc_termios_mut() };
800 let res = unsafe { libc::cfsetspeed(inner_termios, baud as libc::speed_t) };
801 termios.update_wrapper();
802 Errno::result(res).map(drop)
803 }
804 }
805 }
806
807 /// Configures the port to something like the "raw" mode of the old Version 7 terminal driver (see
808 /// [termios(3)](https://man7.org/linux/man-pages/man3/termios.3.html)).
809 ///
810 /// `cfmakeraw()` configures the termios structure such that input is available character-by-
811 /// character, echoing is disabled, and all special input and output processing is disabled. Note
812 /// that this is a non-standard function, but is available on Linux and BSDs.
cfmakeraw(termios: &mut Termios)813 pub fn cfmakeraw(termios: &mut Termios) {
814 let inner_termios = unsafe { termios.get_libc_termios_mut() };
815 unsafe {
816 libc::cfmakeraw(inner_termios);
817 }
818 termios.update_wrapper();
819 }
820
821 /// Configures the port to "sane" mode (like the configuration of a newly created terminal) (see
822 /// [tcsetattr(3)](https://www.freebsd.org/cgi/man.cgi?query=tcsetattr)).
823 ///
824 /// Note that this is a non-standard function, available on FreeBSD.
825 #[cfg(target_os = "freebsd")]
cfmakesane(termios: &mut Termios)826 pub fn cfmakesane(termios: &mut Termios) {
827 let inner_termios = unsafe { termios.get_libc_termios_mut() };
828 unsafe {
829 libc::cfmakesane(inner_termios);
830 }
831 termios.update_wrapper();
832 }
833
834 /// Return the configuration of a port
835 /// [tcgetattr(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetattr.html)).
836 ///
837 /// `tcgetattr()` returns a `Termios` structure with the current configuration for a port. Modifying
838 /// this structure *will not* reconfigure the port, instead the modifications should be done to
839 /// the `Termios` structure and then the port should be reconfigured using `tcsetattr()`.
tcgetattr<Fd: AsFd>(fd: Fd) -> Result<Termios>840 pub fn tcgetattr<Fd: AsFd>(fd: Fd) -> Result<Termios> {
841 let mut termios = mem::MaybeUninit::uninit();
842
843 let res = unsafe {
844 libc::tcgetattr(fd.as_fd().as_raw_fd(), termios.as_mut_ptr())
845 };
846
847 Errno::result(res)?;
848
849 unsafe { Ok(termios.assume_init().into()) }
850 }
851
852 /// Set the configuration for a terminal (see
853 /// [tcsetattr(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetattr.html)).
854 ///
855 /// `tcsetattr()` reconfigures the given port based on a given `Termios` structure. This change
856 /// takes affect at a time specified by `actions`. Note that this function may return success if
857 /// *any* of the parameters were successfully set, not only if all were set successfully.
tcsetattr<Fd: AsFd>( fd: Fd, actions: SetArg, termios: &Termios, ) -> Result<()>858 pub fn tcsetattr<Fd: AsFd>(
859 fd: Fd,
860 actions: SetArg,
861 termios: &Termios,
862 ) -> Result<()> {
863 let inner_termios = termios.get_libc_termios();
864 Errno::result(unsafe {
865 libc::tcsetattr(
866 fd.as_fd().as_raw_fd(),
867 actions as c_int,
868 &*inner_termios,
869 )
870 })
871 .map(drop)
872 }
873
874 /// Block until all output data is written (see
875 /// [tcdrain(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcdrain.html)).
tcdrain<Fd: AsFd>(fd: Fd) -> Result<()>876 pub fn tcdrain<Fd: AsFd>(fd: Fd) -> Result<()> {
877 Errno::result(unsafe { libc::tcdrain(fd.as_fd().as_raw_fd()) }).map(drop)
878 }
879
880 /// Suspend or resume the transmission or reception of data (see
881 /// [tcflow(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcflow.html)).
882 ///
883 /// `tcflow()` suspends of resumes the transmission or reception of data for the given port
884 /// depending on the value of `action`.
tcflow<Fd: AsFd>(fd: Fd, action: FlowArg) -> Result<()>885 pub fn tcflow<Fd: AsFd>(fd: Fd, action: FlowArg) -> Result<()> {
886 Errno::result(unsafe {
887 libc::tcflow(fd.as_fd().as_raw_fd(), action as c_int)
888 })
889 .map(drop)
890 }
891
892 /// Discard data in the output or input queue (see
893 /// [tcflush(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcflush.html)).
894 ///
895 /// `tcflush()` will discard data for a terminal port in the input queue, output queue, or both
896 /// depending on the value of `action`.
tcflush<Fd: AsFd>(fd: Fd, action: FlushArg) -> Result<()>897 pub fn tcflush<Fd: AsFd>(fd: Fd, action: FlushArg) -> Result<()> {
898 Errno::result(unsafe {
899 libc::tcflush(fd.as_fd().as_raw_fd(), action as c_int)
900 })
901 .map(drop)
902 }
903
904 /// Send a break for a specific duration (see
905 /// [tcsendbreak(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsendbreak.html)).
906 ///
907 /// When using asynchronous data transmission `tcsendbreak()` will transmit a continuous stream
908 /// of zero-valued bits for an implementation-defined duration.
tcsendbreak<Fd: AsFd>(fd: Fd, duration: c_int) -> Result<()>909 pub fn tcsendbreak<Fd: AsFd>(fd: Fd, duration: c_int) -> Result<()> {
910 Errno::result(unsafe {
911 libc::tcsendbreak(fd.as_fd().as_raw_fd(), duration)
912 })
913 .map(drop)
914 }
915
916 feature! {
917 #![feature = "process"]
918 /// Get the session controlled by the given terminal (see
919 /// [tcgetsid(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetsid.html)).
920 pub fn tcgetsid<Fd: AsFd>(fd: Fd) -> Result<Pid> {
921 let res = unsafe { libc::tcgetsid(fd.as_fd().as_raw_fd()) };
922
923 Errno::result(res).map(Pid::from_raw)
924 }
925 }
926