xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/splice/splice06.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2023 SUSE LLC <[email protected]>
4  */
5 
6 /*\
7  * [Description]
8  *
9  * This test is cover splice() on proc files.
10  *
11  */
12 
13 #define _GNU_SOURCE
14 
15 #include <stdio.h>
16 #include <errno.h>
17 #include <string.h>
18 #include <signal.h>
19 #include <sys/types.h>
20 #include <fcntl.h>
21 #include <ctype.h>
22 
23 #include "tst_test.h"
24 #include "lapi/splice.h"
25 
26 #define BUF_SIZE 100
27 #define PIPE_MAX_INIT_SIZE 65536
28 #define DOMAIN_INIT_NAME "LTP_INIT"
29 #define DOMAIN_TEST_NAME "LTP_TEST"
30 #define INTEGER_PROCFILE "/proc/sys/fs/pipe-max-size"
31 #define STRING_PROCFILE "/proc/sys/kernel/domainname"
32 static int pipe_max_test_size;
33 
format_str(char * str)34 static void format_str(char *str)
35 {
36 	int i;
37 
38 	for (i = 0; i < BUF_SIZE ; i++) {
39 		if (!isdigit(str[i])) {
40 			str[i] = '\0';
41 			break;
42 		}
43 	}
44 	if (i == BUF_SIZE)
45 		tst_brk(TBROK, "can not find nonnumeric character from input string");
46 }
47 
splice_read_num(const char * file)48 static int splice_read_num(const char *file)
49 {
50 	int pipes[2];
51 	int fd_in;
52 	int ret;
53 	int num;
54 	char buf[BUF_SIZE];
55 
56 	memset(buf, '\0', sizeof(buf));
57 	fd_in = SAFE_OPEN(file, O_RDONLY);
58 	SAFE_PIPE(pipes);
59 
60 	ret = splice(fd_in, NULL, pipes[1], NULL, BUF_SIZE - 1, 0);
61 	if (ret < 0)
62 		tst_brk(TBROK | TERRNO, "splice(fd_in, pipe) failed");
63 
64 	SAFE_READ(0, pipes[0], buf, BUF_SIZE);
65 
66 	/* Search for the first nonnumeric character and replace it with \0 */
67 	format_str(buf);
68 
69 	if (tst_parse_int(buf, &num, 0, INT_MAX))
70 		tst_brk(TBROK, "Invalid buffer num %s", buf);
71 
72 	SAFE_CLOSE(fd_in);
73 	SAFE_CLOSE(pipes[0]);
74 	SAFE_CLOSE(pipes[1]);
75 
76 	return num;
77 }
78 
splice_read_str(const char * file,char * dest)79 static char *splice_read_str(const char *file, char *dest)
80 {
81 	int pipes[2];
82 	int fd_in;
83 	int ret;
84 
85 	fd_in = SAFE_OPEN(file, O_RDONLY);
86 	SAFE_PIPE(pipes);
87 
88 	ret = splice(fd_in, NULL, pipes[1], NULL, BUF_SIZE, 0);
89 	if (ret < 0)
90 		tst_brk(TBROK | TERRNO, "splice(fd_in, pipe) failed");
91 
92 	SAFE_READ(0, pipes[0], dest, BUF_SIZE);
93 
94 	SAFE_CLOSE(fd_in);
95 	SAFE_CLOSE(pipes[0]);
96 	SAFE_CLOSE(pipes[1]);
97 
98 	return dest;
99 }
100 
101 
splice_write_num(const char * file,int num)102 static void splice_write_num(const char *file, int num)
103 {
104 	int pipes[2];
105 	int fd_out;
106 	int ret;
107 	char buf[BUF_SIZE];
108 
109 	memset(buf, '\0', sizeof(buf));
110 
111 	fd_out = SAFE_OPEN(file, O_WRONLY, 0777);
112 	SAFE_PIPE(pipes);
113 	sprintf(buf, "%d", num);
114 
115 	SAFE_WRITE(SAFE_WRITE_ALL, pipes[1], buf, strlen(buf));
116 
117 	ret = splice(pipes[0], NULL, fd_out, NULL, BUF_SIZE, 0);
118 	if (ret < 0)
119 		tst_brk(TBROK | TERRNO, "splice write failed");
120 
121 	SAFE_CLOSE(fd_out);
122 	SAFE_CLOSE(pipes[0]);
123 	SAFE_CLOSE(pipes[1]);
124 }
125 
splice_write_str(const char * file,char * dest)126 static void splice_write_str(const char *file, char *dest)
127 {
128 	int pipes[2];
129 	int fd_out;
130 	int ret;
131 
132 	fd_out = SAFE_OPEN(file, O_WRONLY, 0777);
133 	SAFE_PIPE(pipes);
134 
135 	SAFE_WRITE(SAFE_WRITE_ALL, pipes[1], dest, strlen(dest));
136 
137 	ret = splice(pipes[0], NULL, fd_out, NULL, BUF_SIZE, 0);
138 	if (ret < 0)
139 		tst_brk(TBROK | TERRNO, "splice write failed");
140 
141 	SAFE_CLOSE(fd_out);
142 	SAFE_CLOSE(pipes[0]);
143 	SAFE_CLOSE(pipes[1]);
144 }
145 
file_write_num(const char * file,int num)146 static void file_write_num(const char *file, int num)
147 {
148 	SAFE_FILE_PRINTF(file, "%d", num);
149 }
150 
file_write_str(const char * file,char * dest)151 static void file_write_str(const char *file, char *dest)
152 {
153 	SAFE_FILE_PRINTF(file, "%s", dest);
154 }
155 
file_read_num(const char * file)156 static int file_read_num(const char *file)
157 {
158 	int num;
159 
160 	SAFE_FILE_SCANF(file, "%d", &num);
161 
162 	return num;
163 }
164 
file_read_str(const char * file,char * dest)165 static char *file_read_str(const char *file, char *dest)
166 {
167 	SAFE_FILE_SCANF(file, "%s", dest);
168 	return dest;
169 }
170 
splice_test(void)171 static void splice_test(void)
172 {
173 
174 	char buf_file[BUF_SIZE];
175 	char buf_splice[BUF_SIZE];
176 
177 	if (file_read_num(INTEGER_PROCFILE) == splice_read_num(INTEGER_PROCFILE))
178 		tst_res(TPASS, "Read num through splice correctly");
179 	else
180 		tst_brk(TBROK | TERRNO, "Read num through splice failed");
181 
182 	splice_write_num(INTEGER_PROCFILE, pipe_max_test_size);
183 
184 	if (file_read_num(INTEGER_PROCFILE) == pipe_max_test_size)
185 		tst_res(TPASS, "Write num through splice correctly");
186 	else
187 		tst_brk(TBROK | TERRNO, "Write num through splice failed");
188 
189 	memset(buf_file, '\0', sizeof(buf_file));
190 	memset(buf_splice, '\0', sizeof(buf_splice));
191 
192 	file_read_str(STRING_PROCFILE, buf_file);
193 	splice_read_str(STRING_PROCFILE, buf_splice);
194 
195 	if (!strncmp(buf_file, buf_splice, strlen(buf_file)))
196 		tst_res(TPASS, "Read string through splice correctly");
197 	else
198 		tst_brk(TBROK | TERRNO, "Read string through splice failed");
199 
200 	memset(buf_file, '\0', sizeof(buf_file));
201 
202 	splice_write_str(STRING_PROCFILE, DOMAIN_TEST_NAME);
203 	file_read_str(STRING_PROCFILE, buf_file);
204 
205 	if (!strncmp(buf_file, DOMAIN_TEST_NAME, strlen(buf_file)))
206 		tst_res(TPASS, "Write string through splice correctly");
207 	else
208 		tst_brk(TBROK | TERRNO, "Write string through splice failed");
209 }
210 
setup(void)211 static void setup(void)
212 {
213 	pipe_max_test_size = getpagesize();
214 	file_write_str(STRING_PROCFILE, DOMAIN_INIT_NAME);
215 	file_write_num(STRING_PROCFILE, PIPE_MAX_INIT_SIZE);
216 }
217 
218 static struct tst_test test = {
219 	.min_kver = "5.11",
220 	.setup = setup,
221 	.test_all = splice_test,
222 	.needs_tmpdir = 1,
223 	.save_restore = (const struct tst_path_val[]) {
224 		{INTEGER_PROCFILE, NULL, TST_SR_TCONF},
225 		{STRING_PROCFILE, NULL, TST_SR_TCONF},
226 		{}
227 	},
228 };
229