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