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