1 /****************************************************************************
2 *
3 * Copyright (c) International Business Machines Corp., 2006
4 * Author Yi Yang <yyangcdl@cn.ibm.com>
5 * Copyright (c) 2014 Cyril Hrubis <chrubis@suse.cz>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
15 * the GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 *
21 * DESCRIPTION
22 * This test case will verify basic function of tee(2)
23 * added by kernel 2.6.17 or up.
24 *
25 ***************************************************************************/
26
27 #define _GNU_SOURCE
28
29 #include <errno.h>
30 #include <string.h>
31 #include <signal.h>
32 #include <sys/types.h>
33 #include <fcntl.h>
34 #include <sys/syscall.h>
35
36 #include "test.h"
37 #include "linux_syscall_numbers.h"
38 #include "safe_macros.h"
39 #include "lapi/fcntl.h"
40 #include "lapi/tee.h"
41 #include "lapi/splice.h"
42
43 static void tee_test(void);
44 static void setup(void);
45 static void cleanup(void);
46
47 #define TEST_BLOCK_SIZE 1024
48
49 #define TESTFILE1 "tee_test_file_1"
50 #define TESTFILE2 "tee_test_file_2"
51
52 static int fd_in, fd_out;
53 static char buffer[TEST_BLOCK_SIZE];
54
55 char *TCID = "tee01";
56 int TST_TOTAL = 1;
57
main(int ac,char ** av)58 int main(int ac, char **av)
59 {
60 int lc;
61
62 tst_parse_opts(ac, av, NULL, NULL);
63
64 setup();
65
66 for (lc = 0; TEST_LOOPING(lc); lc++)
67 tee_test();
68
69 cleanup();
70 tst_exit();
71 }
72
check_file(void)73 static void check_file(void)
74 {
75 int i;
76 char teebuffer[TEST_BLOCK_SIZE];
77
78 fd_out = SAFE_OPEN(cleanup, TESTFILE2, O_RDONLY);
79 SAFE_READ(cleanup, 1, fd_out, teebuffer, TEST_BLOCK_SIZE);
80
81 for (i = 0; i < TEST_BLOCK_SIZE; i++) {
82 if (buffer[i] != teebuffer[i])
83 break;
84 }
85
86 if (i < TEST_BLOCK_SIZE)
87 tst_resm(TFAIL, "Wrong data read from the buffer at %i", i);
88 else
89 tst_resm(TPASS, "Written data has been read back correctly");
90
91 close(fd_out);
92 fd_out = 0;
93 }
94
tee_test(void)95 static void tee_test(void)
96 {
97 int pipe1[2];
98 int pipe2[2];
99 int ret = 0;
100
101 fd_in = SAFE_OPEN(cleanup, TESTFILE1, O_RDONLY);
102 fd_out = SAFE_OPEN(cleanup, TESTFILE2, O_WRONLY | O_CREAT | O_TRUNC, 0777);
103
104 SAFE_PIPE(cleanup, pipe1);
105 SAFE_PIPE(cleanup, pipe2);
106
107 ret = splice(fd_in, NULL, pipe1[1], NULL, TEST_BLOCK_SIZE, 0);
108 if (ret < 0)
109 tst_brkm(TBROK | TERRNO, cleanup, "splice(fd_in, pipe1) failed");
110
111 ret = tee(pipe1[0], pipe2[1], TEST_BLOCK_SIZE, SPLICE_F_NONBLOCK);
112 if (ret < 0)
113 tst_brkm(TBROK | TERRNO, cleanup, "tee() failed");
114
115 ret = splice(pipe2[0], NULL, fd_out, NULL, TEST_BLOCK_SIZE, 0);
116 if (ret < 0)
117 tst_brkm(TBROK | TERRNO, cleanup, "splice(pipe2, fd_out) failed");
118
119 close(pipe2[0]);
120 close(pipe2[1]);
121 close(pipe1[0]);
122 close(pipe1[1]);
123 close(fd_out);
124 close(fd_in);
125
126 fd_out = 0;
127 fd_in = 0;
128
129 check_file();
130 }
131
setup(void)132 static void setup(void)
133 {
134 int i;
135
136 if ((tst_kvercmp(2, 6, 17)) < 0) {
137 tst_brkm(TCONF, cleanup, "This test can only run on kernels "
138 "that are 2.6.17 or higher");
139 }
140
141 tst_sig(NOFORK, DEF_HANDLER, cleanup);
142
143 TEST_PAUSE;
144
145 tst_tmpdir();
146
147 if (tst_fs_type(cleanup, ".") == TST_NFS_MAGIC) {
148 if ((tst_kvercmp(2, 6, 32)) < 0)
149 tst_brkm(TCONF, cleanup, "Cannot do tee on a file"
150 " on NFS filesystem before 2.6.32");
151 }
152
153 for (i = 0; i < TEST_BLOCK_SIZE; i++)
154 buffer[i] = i & 0xff;
155
156 fd_in = SAFE_OPEN(cleanup, TESTFILE1, O_WRONLY | O_CREAT | O_TRUNC, 0777);
157 SAFE_WRITE(cleanup, 1, fd_in, buffer, TEST_BLOCK_SIZE);
158 SAFE_CLOSE(cleanup, fd_in);
159 fd_in = 0;
160 }
161
cleanup(void)162 static void cleanup(void)
163 {
164 if (fd_in > 0 && close(fd_in))
165 tst_resm(TWARN, "Failed to close fd_in");
166
167 if (fd_out > 0 && close(fd_out))
168 tst_resm(TWARN, "Failed to close fd_out");
169
170 tst_rmdir();
171 }
172