[PATCH] Formalize input/output pipe checking
[splice.git] / ktee.c
1 /*
2  * A tee implementation using sys_tee. Stores stdin input in the given file
3  * and duplicates that to stdout.
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/types.h>
12 #include <errno.h>
13 #include <assert.h>
14 #include <limits.h>
15
16 #include "splice.h"
17
18 static int do_splice(int infd, int outfd, unsigned int len, char *msg)
19 {
20         while (len) {
21                 int written = splice(infd, NULL, outfd, NULL, len, 0);
22
23                 if (written <= 0)
24                         return error(msg);
25
26                 len -= written;
27         }
28
29         return 0;
30 }
31
32 static int usage(char *name)
33 {
34         fprintf(stderr, "... | %s: outfile\n", name);
35         return 1;
36 }
37
38 int main(int argc, char *argv[])
39 {
40         int fd;
41
42         if (argc < 2)
43                 return usage(argv[0]);
44
45         if (check_input_pipe())
46                 return usage(argv[0]);
47
48         fd = open(argv[1], O_WRONLY | O_CREAT | O_TRUNC, 0644);
49         if (fd < 0)
50                 return error("open output");
51
52         do {
53                 int tee_len = tee(STDIN_FILENO, STDOUT_FILENO, INT_MAX, SPLICE_F_NONBLOCK);
54
55                 if (tee_len < 0) {
56                         if (errno == EAGAIN) {
57                                 usleep(1000);
58                                 continue;
59                         }
60                         return error("tee");
61                 } else if (!tee_len)
62                         break;
63
64                 /*
65                  * Send output to file, also consumes input pipe.
66                  */
67                 if (do_splice(STDIN_FILENO, fd, tee_len, "splice-file"))
68                         break;
69         } while (1);
70
71         return 0;
72 }