• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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