1 /******************************************************************************
2  *
3  * Copyright (c) International Business Machines  Corp., 2007
4  *  Created by <rsalveti@linux.vnet.ibm.com>
5  *
6  * This program is free software;  you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY;  without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
14  * the GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program;  if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  *
20  ******************************************************************************/
21 
22 /*
23  * This test case checks whether swapon(2) system call returns:
24  *  - EPERM when there are more than MAX_SWAPFILES already in use.
25  *
26  */
27 
28 #include <sys/types.h>
29 #include <unistd.h>
30 #include <errno.h>
31 #include <stdlib.h>
32 #include <sys/wait.h>
33 #include <sys/stat.h>
34 #include <sys/utsname.h>
35 #include <fcntl.h>
36 #include <pwd.h>
37 #include <string.h>
38 #include <signal.h>
39 #include "test.h"
40 #include "lapi/syscalls.h"
41 #include "swaponoff.h"
42 #include "libswapon.h"
43 
44 static void setup(void);
45 static void cleanup(void);
46 static int setup_swap(void);
47 static int clean_swap(void);
48 static int check_and_swapoff(const char *filename);
49 
50 char *TCID = "swapon03";
51 int TST_TOTAL = 1;
52 
53 static int swapfiles;
54 
55 static long fs_type;
56 
57 int testfiles = 3;
58 static struct swap_testfile_t {
59 	char *filename;
60 } swap_testfiles[] = {
61 	{"firstswapfile"},
62 	{"secondswapfile"},
63 	{"thirdswapfile"}
64 };
65 
66 int expected_errno = EPERM;
67 
main(int ac,char ** av)68 int main(int ac, char **av)
69 {
70 	int lc;
71 
72 	tst_parse_opts(ac, av, NULL, NULL);
73 
74 	setup();
75 
76 	for (lc = 0; TEST_LOOPING(lc); lc++) {
77 		tst_count = 0;
78 
79 		if (setup_swap() < 0) {
80 			clean_swap();
81 			tst_brkm(TBROK, cleanup,
82 				 "Setup failed, quitting the test");
83 		}
84 
85 		TEST(ltp_syscall(__NR_swapon, swap_testfiles[0].filename, 0));
86 
87 		if ((TEST_RETURN == -1) && (TEST_ERRNO == expected_errno)) {
88 			tst_resm(TPASS, "swapon(2) got expected failure (%d),",
89 				 expected_errno);
90 		} else if (TEST_RETURN < 0) {
91 			tst_resm(TFAIL | TTERRNO,
92 				 "swapon(2) failed to produce expected error "
93 				 "(%d). System reboot recommended.",
94 				 expected_errno);
95 		} else {
96 			/* Probably the system supports MAX_SWAPFILES > 30,
97 			 * let's try with MAX_SWAPFILES == 32 */
98 
99 			/* Call swapon sys call once again for 32
100 			 * now we can't receive an error */
101 			TEST(ltp_syscall
102 			     (__NR_swapon, swap_testfiles[1].filename, 0));
103 
104 			/* Check return code (now we're expecting success) */
105 			if (TEST_RETURN < 0) {
106 				tst_resm(TFAIL | TTERRNO,
107 					 "swapon(2) got an unexpected failure");
108 			} else {
109 				/* Call swapon sys call once again for 33
110 				 * now we have to receive an error */
111 				TEST(ltp_syscall
112 				     (__NR_swapon, swap_testfiles[2].filename,
113 				      0));
114 
115 				/* Check return code (should be an error) */
116 				if ((TEST_RETURN == -1)
117 				    && (TEST_ERRNO == expected_errno)) {
118 					tst_resm(TPASS,
119 						 "swapon(2) got expected failure;"
120 						 " Got errno = %d, probably your"
121 						 " MAX_SWAPFILES is 32",
122 						 expected_errno);
123 				} else {
124 					tst_resm(TFAIL,
125 						 "swapon(2) failed to produce"
126 						 " expected error: %d, got %s."
127 						 " System reboot after execution of LTP"
128 						 " test suite is recommended.",
129 						 expected_errno,
130 						 strerror(TEST_ERRNO));
131 				}
132 
133 			}
134 		}
135 
136 		if (clean_swap() < 0)
137 			tst_brkm(TBROK, cleanup,
138 				 "Cleanup failed, quitting the test");
139 
140 	}
141 
142 	cleanup();
143 	tst_exit();
144 
145 }
146 
147 /*
148  * Create 33 and activate 30 swapfiles.
149  */
setup_swap(void)150 static int setup_swap(void)
151 {
152 	pid_t pid;
153 	int j, fd;
154 	int status;
155 	int res = 0;
156 	char filename[15];
157 	char buf[BUFSIZ + 1];
158 
159 	/* Find out how many swapfiles (1 line per entry) already exist */
160 	swapfiles = 0;
161 
162 	if (seteuid(0) < 0) {
163 		tst_brkm(TFAIL | TERRNO, cleanup, "Failed to call seteuid");
164 	}
165 
166 	/* This includes the first (header) line */
167 	if ((fd = open("/proc/swaps", O_RDONLY)) == -1) {
168 		tst_brkm(TFAIL | TERRNO, cleanup,
169 			 "Failed to find out existing number of swap files");
170 	}
171 	do {
172 		char *p = buf;
173 		res = read(fd, buf, BUFSIZ);
174 		if (res < 0) {
175 			tst_brkm(TFAIL | TERRNO, cleanup,
176 				 "Failed to find out existing number of swap "
177 				 "files");
178 		}
179 		buf[res] = '\0';
180 		while ((p = strchr(p, '\n'))) {
181 			p++;
182 			swapfiles++;
183 		}
184 	} while (BUFSIZ <= res);
185 	close(fd);
186 	if (swapfiles)
187 		swapfiles--;	/* don't count the /proc/swaps header */
188 
189 	if (swapfiles < 0) {
190 		tst_brkm(TFAIL, cleanup,
191 			 "Failed to find existing number of swapfiles");
192 	}
193 
194 	/* Determine how many more files are to be created */
195 	swapfiles = MAX_SWAPFILES - swapfiles;
196 	if (swapfiles > MAX_SWAPFILES) {
197 		swapfiles = MAX_SWAPFILES;
198 	}
199 
200 	pid = FORK_OR_VFORK();
201 	if (pid == 0) {
202 		/*create and turn on remaining swapfiles */
203 		for (j = 0; j < swapfiles; j++) {
204 
205 			/* prepare filename for the iteration */
206 			if (sprintf(filename, "swapfile%02d", j + 2) < 0) {
207 				printf("sprintf() failed to create "
208 				       "filename");
209 				exit(1);
210 			}
211 
212 			/* Create the swapfile */
213 			make_swapfile(cleanup, filename);
214 
215 			/* turn on the swap file */
216 			res = ltp_syscall(__NR_swapon, filename, 0);
217 			if (res != 0) {
218 				if (fs_type == TST_BTRFS_MAGIC && errno == EINVAL)
219 					exit(2);
220 
221 				if (errno == EPERM) {
222 					printf("Successfully created %d "
223 					       "swapfiles\n", j);
224 					break;
225 				} else {
226 					printf("Failed to create "
227 					       "swapfile: %s\n", filename);
228 					exit(1);
229 				}
230 			}
231 		}
232 		exit(0);
233 	} else
234 		waitpid(pid, &status, 0);
235 
236 	switch (WEXITSTATUS(status)) {
237 	case 0:
238 	break;
239 	case 2:
240 		tst_brkm(TCONF, cleanup, "Swapfile on BTRFS not implemeted");
241 	break;
242 	default:
243 		tst_brkm(TFAIL, cleanup, "Failed to setup swaps");
244 	break;
245 	}
246 
247 	/* Create all needed extra swapfiles for testing */
248 	for (j = 0; j < testfiles; j++)
249 		make_swapfile(cleanup, swap_testfiles[j].filename);
250 
251 	return 0;
252 
253 }
254 
255 /*
256  * Turn off all swapfiles previously turned on
257  */
clean_swap(void)258 static int clean_swap(void)
259 {
260 	int j;
261 	char filename[FILENAME_MAX];
262 
263 	for (j = 0; j < swapfiles; j++) {
264 		if (snprintf(filename, sizeof(filename),
265 			     "swapfile%02d", j + 2) < 0) {
266 			tst_resm(TWARN, "sprintf() failed to create filename");
267 			tst_resm(TWARN, "Failed to turn off swap files. System"
268 				 " reboot after execution of LTP test"
269 				 " suite is recommended");
270 			return -1;
271 		}
272 		if (check_and_swapoff(filename) != 0) {
273 			tst_resm(TWARN, "Failed to turn off swap file %s.",
274 				 filename);
275 			return -1;
276 		}
277 	}
278 
279 	for (j = 0; j < testfiles; j++) {
280 		if (check_and_swapoff(swap_testfiles[j].filename) != 0) {
281 			tst_resm(TWARN, "Failed to turn off swap file %s.",
282 				 swap_testfiles[j].filename);
283 			return -1;
284 		}
285 	}
286 
287 	return 0;
288 }
289 
290 /*
291  * Check if the file is at /proc/swaps and remove it giving swapoff
292  */
check_and_swapoff(const char * filename)293 static int check_and_swapoff(const char *filename)
294 {
295 	char cmd_buffer[256];
296 	int rc = -1;
297 
298 	if (snprintf(cmd_buffer, sizeof(cmd_buffer),
299 		     "grep -q '%s.*file' /proc/swaps", filename) < 0) {
300 		tst_resm(TWARN,
301 			 "sprintf() failed to create the command string");
302 	} else {
303 
304 		rc = 0;
305 
306 		if (system(cmd_buffer) == 0) {
307 
308 			/* now we need to swapoff the file */
309 			if (ltp_syscall(__NR_swapoff, filename) != 0) {
310 
311 				tst_resm(TWARN, "Failed to turn off swap "
312 					 "file. system reboot after "
313 					 "execution of LTP test suite "
314 					 "is recommended");
315 				rc = -1;
316 
317 			}
318 
319 		}
320 	}
321 
322 	return rc;
323 }
324 
setup(void)325 static void setup(void)
326 {
327 	tst_sig(FORK, DEF_HANDLER, cleanup);
328 
329 	tst_require_root();
330 
331 	if (access("/proc/swaps", F_OK))
332 		tst_brkm(TCONF, NULL, "swap not supported by kernel");
333 
334 	tst_tmpdir();
335 
336 	switch ((fs_type = tst_fs_type(cleanup, "."))) {
337 	case TST_NFS_MAGIC:
338 	case TST_TMPFS_MAGIC:
339 		tst_brkm(TCONF, cleanup,
340 			 "Cannot do swapon on a file on %s filesystem",
341 			 tst_fs_type_name(fs_type));
342 	break;
343 	}
344 
345 	TEST_PAUSE;
346 }
347 
cleanup(void)348 static void cleanup(void)
349 {
350 	clean_swap();
351 
352 	tst_rmdir();
353 }
354