The act of splicing can be seen as a way to connect two ends of a rope
through a kernel buffer, where that buffer is implemented as a pipe. It
provides a means to move data around without copying it to/from kernel/user
-address space.
+address space, basically a random kernel buffer that the user has full
+control over.
The
.BR splice ()
More data will be coming in a subsequent splice. This is a helpful hint when
the output descriptor refers to a socket, see also
.B MSG_MORE
-(see
+(see
.BR send (2)
and
.B TCP_CORK
.B EINVAL
Target file system doesn't support splicing, none of the descriptors refer
to a pipe or offset given for non-seekable device.
+.TP
+.B ENOMEM
+Ran out of memory.
.SH HISTORY
The
.BR vmsplice (2)
.PP
+Conceptually,
.BR tee ()
-doesn't copy any data around, it simply references the input data and
-links it to the output pipe.
+copies the data between the two pipes, in reality no real data copying
+takes place though. Under the covers,
+.BR tee ()
+assigns data in the output by merely grabbing a reference to the input.
.SH RETURN VALUE
Upon successful completion,
and
.I fd_out
do not both refer to a pipe.
+.TP
+.B ENOMEM
+Ran out of memory.
+
+.SH EXAMPLE
+The following example implements a basic
+.BR tee (1)
+program using the
+.BR tee (2)
+system call. To keep it simple, it has no real error handling.
+
+.nf
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/splice.h>
+
+int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+
+do {
+ /*
+ * tee stdin to stdout.
+ */
+ int len = tee(STDIN_FILENO, STDOUT_FILENO, INT_MAX, SPLICE_F_NONBLOCK);
+
+ if (len < 0) {
+ if (errno == EAGAIN)
+ continue;
+ perror("tee");
+ break;
+ } else if (!len)
+ break;
+
+ /*
+ * Consume stdin by splicing it to a file.
+ */
+ while (len) {
+ int slen = splice(STDIN_FILENO, NULL, fd, NULL, len, SPLICE_F_MOVE);
+ if (slen < 0) {
+ perror("splice");
+ break;
+ }
+ len -= slen;
+ }
+} while (1);
+
+close(fd);
+.fi
.SH HISTORY
The