tee/tee.rs
1// Copyright (c) 2020 Xu Shaohua <shaohua@biofan.org>. All rights reserved.
2// Use of this source is governed by Apache-2.0 License that can be found
3// in the LICENSE file.
4
5/// This code is rewritten of tee(2) example code.
6/// ```C
7/// #define _GNU_SOURCE
8/// #include <errno.h>
9/// #include <fcntl.h>
10/// #include <limits.h>
11/// #include <stdio.h>
12/// #include <stdlib.h>
13/// #include <unistd.h>
14///
15/// int main(int argc, char *argv[]) {
16/// int fd;
17/// int len, slen;
18///
19/// if (argc != 2) {
20/// fprintf(stderr, "Usage: %s <file>\n", argv[0]);
21/// exit(EXIT_FAILURE);
22/// }
23///
24/// fd = open(argv[1], O_WRONLY | O_CREAT | O_TRUNC, 0644);
25/// if (fd == -1) {
26/// perror("open");
27/// exit(EXIT_FAILURE);
28/// }
29///
30/// do {
31/// /*
32/// * tee stdin to stdout.
33/// */
34/// len = tee(STDIN_FILENO, STDOUT_FILENO, INT_MAX, SPLICE_F_NONBLOCK);
35///
36/// if (len < 0) {
37/// if (errno == EAGAIN)
38/// continue;
39/// perror("tee");
40/// exit(EXIT_FAILURE);
41/// } else if (len == 0)
42/// break;
43///
44/// /*
45/// * Consume stdin by splicing it to a file.
46/// */
47/// while (len > 0) {
48/// slen = splice(STDIN_FILENO, NULL, fd, NULL, len, SPLICE_F_MOVE);
49/// if (slen < 0) {
50/// perror("splice");
51/// break;
52/// }
53/// len -= slen;
54/// }
55/// } while (1);
56///
57/// close(fd);
58/// exit(EXIT_SUCCESS);
59/// }
60/// ```
61fn main() {
62 let output_file = "/tmp/nc-splice";
63 let ret = unsafe {
64 nc::openat(
65 nc::AT_FDCWD,
66 output_file,
67 nc::O_WRONLY | nc::O_CREAT | nc::O_TRUNC,
68 0o644,
69 )
70 };
71 assert!(ret.is_ok());
72 let fd = ret.unwrap();
73
74 // Tee stdin to stdout
75 loop {
76 let stdin_fileno = 0;
77 let stdout_fileno = 1;
78 let ret = unsafe {
79 nc::tee(
80 stdin_fileno,
81 stdout_fileno,
82 usize::MAX,
83 nc::SPLICE_F_NONBLOCK,
84 )
85 };
86 let mut tee_len = match ret {
87 Ok(0) => break,
88 Err(nc::EAGAIN) => continue,
89 Err(errno) => {
90 eprintln!("tee error: {}", nc::strerror(errno));
91 unsafe { nc::exit(1) };
92 }
93 Ok(len) => len,
94 };
95
96 // Consume stdin by splicing it to a file.
97 while tee_len > 0 {
98 let ret = unsafe {
99 nc::splice(
100 stdin_fileno,
101 None,
102 fd,
103 None,
104 tee_len as usize,
105 nc::SPLICE_F_MOVE,
106 )
107 };
108 match ret {
109 Err(errno) => {
110 eprintln!("splice error: {}", nc::strerror(errno));
111 break;
112 }
113 Ok(len) => tee_len -= len,
114 }
115 }
116 }
117
118 let ret = unsafe { nc::close(fd) };
119 assert!(ret.is_ok());
120}