Commit | Line | Data |
---|---|---|
d8525fbd | 1 | /* |
d633e577 JA |
2 | * A tee implementation using sys_tee. Stores stdin input in the given file |
3 | * and duplicates that to stdout. | |
d8525fbd JA |
4 | */ |
5 | #include <stdio.h> | |
6 | #include <stdlib.h> | |
7 | #include <unistd.h> | |
8 | #include <string.h> | |
9 | #include <fcntl.h> | |
10 | #include <string.h> | |
11 | #include <sys/stat.h> | |
12 | #include <sys/types.h> | |
13 | #include <errno.h> | |
14 | #include <assert.h> | |
15 | #include <limits.h> | |
16 | ||
17 | #include "splice.h" | |
18 | ||
19 | static int do_splice(int infd, int outfd, unsigned int len, char *msg) | |
20 | { | |
21 | while (len) { | |
22 | int written = splice(infd, NULL, outfd, NULL, len, 0); | |
23 | ||
24 | if (written <= 0) | |
25 | return error(msg); | |
26 | ||
27 | len -= written; | |
28 | } | |
29 | ||
30 | return 0; | |
31 | } | |
32 | ||
33 | int main(int argc, char *argv[]) | |
34 | { | |
35 | struct stat sb; | |
36 | int fd; | |
37 | ||
38 | if (argc < 2) { | |
39 | fprintf(stderr, "%s: outfile\n", argv[0]); | |
40 | return 1; | |
41 | } | |
42 | ||
43 | if (fstat(STDIN_FILENO, &sb) < 0) | |
44 | return error("stat"); | |
45 | if (!S_ISFIFO(sb.st_mode)) { | |
46 | fprintf(stderr, "stdout must be a pipe\n"); | |
47 | return 1; | |
48 | } | |
49 | ||
50 | fd = open(argv[1], O_WRONLY | O_CREAT | O_TRUNC, 0644); | |
51 | if (fd < 0) | |
52 | return error("open output"); | |
53 | ||
54 | do { | |
55 | int tee_len = tee(STDIN_FILENO, STDOUT_FILENO, INT_MAX, SPLICE_F_NONBLOCK); | |
56 | ||
57 | if (tee_len < 0) { | |
58 | if (errno == EAGAIN) { | |
59 | usleep(1000); | |
60 | continue; | |
61 | } | |
62 | return error("tee"); | |
63 | } else if (!tee_len) | |
64 | break; | |
65 | ||
66 | /* | |
67 | * Send output to file, also consumes input pipe. | |
68 | */ | |
69 | if (do_splice(STDIN_FILENO, fd, tee_len, "splice-file")) | |
70 | break; | |
71 | } while (1); | |
72 | ||
73 | return 0; | |
74 | } |