1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) International Business Machines Corp., 2006
4 * Copyright (c) 2014 Cyril Hrubis <chrubis@suse.cz>
5 * Author: Yi Yang <yyangcdl@cn.ibm.com>
6 */
7
8 #define _GNU_SOURCE
9
10 #include <errno.h>
11 #include <string.h>
12 #include <signal.h>
13 #include <sys/types.h>
14 #include <fcntl.h>
15
16 #include "tst_test.h"
17 #include "lapi/fcntl.h"
18 #include "lapi/tee.h"
19 #include "lapi/splice.h"
20
21 #define TEST_BLOCK_SIZE 1024
22
23 #define TESTFILE1 "tee_test_file_1"
24 #define TESTFILE2 "tee_test_file_2"
25
26 static int fd_in, fd_out;
27 static char buffer[TEST_BLOCK_SIZE];
28
check_file(void)29 static void check_file(void)
30 {
31 int i;
32 char teebuffer[TEST_BLOCK_SIZE];
33
34 fd_out = SAFE_OPEN(TESTFILE2, O_RDONLY);
35 SAFE_READ(1, fd_out, teebuffer, TEST_BLOCK_SIZE);
36
37 for (i = 0; i < TEST_BLOCK_SIZE; i++) {
38 if (buffer[i] != teebuffer[i])
39 break;
40 }
41
42 if (i < TEST_BLOCK_SIZE)
43 tst_res(TFAIL, "Wrong data read from the buffer at %i", i);
44 else
45 tst_res(TPASS, "Written data has been read back correctly");
46
47 SAFE_CLOSE(fd_out);
48 }
49
tee_test(void)50 static void tee_test(void)
51 {
52 int pipe1[2];
53 int pipe2[2];
54 int ret = 0;
55
56 fd_in = SAFE_OPEN(TESTFILE1, O_RDONLY);
57 fd_out = SAFE_OPEN(TESTFILE2, O_WRONLY | O_CREAT | O_TRUNC, 0777);
58
59 SAFE_PIPE(pipe1);
60 SAFE_PIPE(pipe2);
61
62 ret = splice(fd_in, NULL, pipe1[1], NULL, TEST_BLOCK_SIZE, 0);
63 if (ret < 0)
64 tst_brk(TBROK | TERRNO, "splice(fd_in, pipe1) failed");
65
66 ret = tee(pipe1[0], pipe2[1], TEST_BLOCK_SIZE, SPLICE_F_NONBLOCK);
67 if (ret < 0)
68 tst_brk(TBROK | TERRNO, "tee() failed");
69
70 ret = splice(pipe2[0], NULL, fd_out, NULL, TEST_BLOCK_SIZE, 0);
71 if (ret < 0)
72 tst_brk(TBROK | TERRNO, "splice(pipe2, fd_out) failed");
73
74 SAFE_CLOSE(pipe2[0]);
75 SAFE_CLOSE(pipe2[1]);
76 SAFE_CLOSE(pipe1[0]);
77 SAFE_CLOSE(pipe1[1]);
78 SAFE_CLOSE(fd_out);
79 SAFE_CLOSE(fd_in);
80
81 check_file();
82 }
83
setup(void)84 static void setup(void)
85 {
86 int i;
87
88 if (tst_fs_type(".") == TST_NFS_MAGIC) {
89 if ((tst_kvercmp(2, 6, 32)) < 0)
90 tst_brk(TCONF, "Cannot do tee on a file"
91 " on NFS filesystem before 2.6.32");
92 }
93
94 for (i = 0; i < TEST_BLOCK_SIZE; i++)
95 buffer[i] = i & 0xff;
96
97 fd_in = SAFE_OPEN(TESTFILE1, O_WRONLY | O_CREAT | O_TRUNC, 0777);
98 SAFE_WRITE(1, fd_in, buffer, TEST_BLOCK_SIZE);
99 SAFE_CLOSE(fd_in);
100 }
101
cleanup(void)102 static void cleanup(void)
103 {
104 if (fd_in > 0)
105 SAFE_CLOSE(fd_in);
106
107 if (fd_out > 0)
108 SAFE_CLOSE(fd_out);
109 }
110
111 static struct tst_test test = {
112 .setup = setup,
113 .cleanup = cleanup,
114 .test_all = tee_test,
115 .needs_tmpdir = 1,
116 .min_kver = "2.6.17",
117 };
118