Coverage Report

Created: 2024-04-26 06:25

/rust/registry/src/index.crates.io-6f17d22bba15001f/nix-0.26.2/src/sys/termios.rs
Line
Count
Source (jump to first uncovered line)
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
0
#[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.
261
0
    pub(crate) fn get_libc_termios(&self) -> Ref<libc::termios> {
262
0
        {
263
0
            let mut termios = self.inner.borrow_mut();
264
0
            termios.c_iflag = self.input_flags.bits();
265
0
            termios.c_oflag = self.output_flags.bits();
266
0
            termios.c_cflag = self.control_flags.bits();
267
0
            termios.c_lflag = self.local_flags.bits();
268
0
            termios.c_cc = self.control_chars;
269
0
            #[cfg(any(
270
0
                target_os = "linux",
271
0
                target_os = "android",
272
0
                target_os = "haiku",
273
0
            ))]
274
0
            {
275
0
                termios.c_line = self.line_discipline;
276
0
            }
277
0
        }
278
0
        self.inner.borrow()
279
0
    }
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
0
    pub(crate) unsafe fn get_libc_termios_mut(&mut self) -> *mut libc::termios {
288
0
        {
289
0
            let mut termios = self.inner.borrow_mut();
290
0
            termios.c_iflag = self.input_flags.bits();
291
0
            termios.c_oflag = self.output_flags.bits();
292
0
            termios.c_cflag = self.control_flags.bits();
293
0
            termios.c_lflag = self.local_flags.bits();
294
0
            termios.c_cc = self.control_chars;
295
0
            #[cfg(any(
296
0
                target_os = "linux",
297
0
                target_os = "android",
298
0
                target_os = "haiku",
299
0
            ))]
300
0
            {
301
0
                termios.c_line = self.line_discipline;
302
0
            }
303
0
        }
304
0
        self.inner.as_ptr()
305
0
    }
306
307
    /// Updates the wrapper values from the internal `libc::termios` data structure.
308
0
    pub(crate) fn update_wrapper(&mut self) {
309
0
        let termios = *self.inner.borrow_mut();
310
0
        self.input_flags = InputFlags::from_bits_truncate(termios.c_iflag);
311
0
        self.output_flags = OutputFlags::from_bits_truncate(termios.c_oflag);
312
0
        self.control_flags = ControlFlags::from_bits_truncate(termios.c_cflag);
313
0
        self.local_flags = LocalFlags::from_bits_truncate(termios.c_lflag);
314
0
        self.control_chars = termios.c_cc;
315
0
        #[cfg(any(
316
0
            target_os = "linux",
317
0
            target_os = "android",
318
0
            target_os = "haiku",
319
0
        ))]
320
0
        {
321
0
            self.line_discipline = termios.c_line;
322
0
        }
323
0
    }
324
}
325
326
impl From<libc::termios> for Termios {
327
0
    fn from(termios: libc::termios) -> Self {
328
0
        Termios {
329
0
            inner: RefCell::new(termios),
330
0
            input_flags: InputFlags::from_bits_truncate(termios.c_iflag),
331
0
            output_flags: OutputFlags::from_bits_truncate(termios.c_oflag),
332
0
            control_flags: ControlFlags::from_bits_truncate(termios.c_cflag),
333
0
            local_flags: LocalFlags::from_bits_truncate(termios.c_lflag),
334
0
            control_chars: termios.c_cc,
335
0
            #[cfg(any(
336
0
                target_os = "linux",
337
0
                target_os = "android",
338
0
                target_os = "haiku",
339
0
            ))]
340
0
            line_discipline: termios.c_line,
341
0
        }
342
0
    }
343
}
344
345
impl From<Termios> for libc::termios {
346
0
    fn from(termios: Termios) -> Self {
347
0
        termios.inner.into_inner()
348
0
    }
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 {
475
    fn from(b: BaudRate) -> u32 {
476
        b as u32
477
    }
478
}
479
480
#[cfg(target_os = "haiku")]
481
impl 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.
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
0
        pub fn cfgetispeed(termios: &Termios) -> BaudRate {
1062
0
            let inner_termios = termios.get_libc_termios();
1063
0
            unsafe { libc::cfgetispeed(&*inner_termios) }.try_into().unwrap()
1064
0
        }
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
0
        pub fn cfgetospeed(termios: &Termios) -> BaudRate {
1071
0
            let inner_termios = termios.get_libc_termios();
1072
0
            unsafe { libc::cfgetospeed(&*inner_termios) }.try_into().unwrap()
1073
0
        }
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
0
        pub fn cfsetispeed(termios: &mut Termios, baud: BaudRate) -> Result<()> {
1080
0
            let inner_termios = unsafe { termios.get_libc_termios_mut() };
1081
0
            let res = unsafe { libc::cfsetispeed(inner_termios, baud as libc::speed_t) };
1082
0
            termios.update_wrapper();
1083
0
            Errno::result(res).map(drop)
1084
0
        }
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
0
        pub fn cfsetospeed(termios: &mut Termios, baud: BaudRate) -> Result<()> {
1091
0
            let inner_termios = unsafe { termios.get_libc_termios_mut() };
1092
0
            let res = unsafe { libc::cfsetospeed(inner_termios, baud as libc::speed_t) };
1093
0
            termios.update_wrapper();
1094
0
            Errno::result(res).map(drop)
1095
0
        }
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
0
        pub fn cfsetspeed(termios: &mut Termios, baud: BaudRate) -> Result<()> {
1104
0
            let inner_termios = unsafe { termios.get_libc_termios_mut() };
1105
0
            let res = unsafe { libc::cfsetspeed(inner_termios, baud as libc::speed_t) };
1106
0
            termios.update_wrapper();
1107
0
            Errno::result(res).map(drop)
1108
0
        }
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.
1118
0
pub fn cfmakeraw(termios: &mut Termios) {
1119
0
    let inner_termios = unsafe { termios.get_libc_termios_mut() };
1120
0
    unsafe {
1121
0
        libc::cfmakeraw(inner_termios);
1122
0
    }
1123
0
    termios.update_wrapper();
1124
0
}
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())))]
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()`.
1146
0
pub fn tcgetattr(fd: RawFd) -> Result<Termios> {
1147
0
    let mut termios = mem::MaybeUninit::uninit();
1148
0
1149
0
    let res = unsafe { libc::tcgetattr(fd, termios.as_mut_ptr()) };
1150
0
1151
0
    Errno::result(res)?;
1152
1153
0
    unsafe { Ok(termios.assume_init().into()) }
1154
0
}
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.
1162
0
pub fn tcsetattr(fd: RawFd, actions: SetArg, termios: &Termios) -> Result<()> {
1163
0
    let inner_termios = termios.get_libc_termios();
1164
0
    Errno::result(unsafe {
1165
0
        libc::tcsetattr(fd, actions as c_int, &*inner_termios)
1166
0
    })
1167
0
    .map(drop)
1168
0
}
1169
1170
/// Block until all output data is written (see
1171
/// [tcdrain(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcdrain.html)).
1172
0
pub fn tcdrain(fd: RawFd) -> Result<()> {
1173
0
    Errno::result(unsafe { libc::tcdrain(fd) }).map(drop)
1174
0
}
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`.
1181
0
pub fn tcflow(fd: RawFd, action: FlowArg) -> Result<()> {
1182
0
    Errno::result(unsafe { libc::tcflow(fd, action as c_int) }).map(drop)
1183
0
}
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`.
1190
0
pub fn tcflush(fd: RawFd, action: FlushArg) -> Result<()> {
1191
0
    Errno::result(unsafe { libc::tcflush(fd, action as c_int) }).map(drop)
1192
0
}
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.
1199
0
pub fn tcsendbreak(fd: RawFd, duration: c_int) -> Result<()> {
1200
0
    Errno::result(unsafe { libc::tcsendbreak(fd, duration) }).map(drop)
1201
0
}
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
0
pub fn tcgetsid(fd: RawFd) -> Result<Pid> {
1208
0
    let res = unsafe { libc::tcgetsid(fd) };
1209
0
1210
0
    Errno::result(res).map(Pid::from_raw)
1211
0
}
1212
}
1213
1214
#[cfg(test)]
1215
mod 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
}