Initial commit
[splice.git] / ktee.c
CommitLineData
d8525fbd
JA
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
22static 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
36int 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}