• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  *   Copyright (c) International Business Machines  Corp., 2001
4  *
5  *   This program is free software;  you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation; either version 2 of the License, or
8  *   (at your option) any later version.
9  *
10  *   This program is distributed in the hope that it will be useful,
11  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
13  *   the GNU General Public License for more details.
14  *
15  *   You should have received a copy of the GNU General Public License
16  *   along with this program;  if not, write to the Free Software
17  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 /*
21  *	Testcase to check the basic functionality of the setrlimit system call.
22  *	Use the different commands like RLIMIT_NOFILE, RLIMIT_CORE,
23  *	RLIMIT_FSIZE, and, RLIMIT_NOFILE, and test for different test
24  *	conditions.
25  *
26  *	07/2001 Ported by Wayne Boyer
27  */
28 
29 #include <sys/types.h>
30 #include <sys/resource.h>
31 #include <sys/stat.h>
32 #include <sys/time.h>
33 #include <sys/wait.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include "test.h"
39 
40 char *TCID = "setrlimit01";
41 int TST_TOTAL = 1;
42 
43 static void setup(void);
44 static void cleanup(void);
45 static void test1(void);
46 static void test2(void);
47 static void test3(void);
48 static void test4(void);
49 static void sighandler(int);
50 
51 static char filename[40] = "";
52 static struct rlimit save_rlim, rlim, rlim1;
53 static int nofiles, fd, bytes, i, status;
54 static char *buf = "abcdefghijklmnopqrstuvwxyz";
55 static pid_t pid;
56 
main(int ac,char ** av)57 int main(int ac, char **av)
58 {
59 	int lc;
60 
61 	tst_parse_opts(ac, av, NULL, NULL);
62 
63 	setup();
64 
65 	for (lc = 0; TEST_LOOPING(lc); lc++) {
66 		tst_count = 0;
67 
68 		test1();
69 		test2();
70 		test3();
71 		/* reset saved conditions */
72 		if ((setrlimit(RLIMIT_NPROC, &save_rlim)) == -1) {
73 			tst_brkm(TBROK, cleanup, "setrlimit failed to reset "
74 				 "RLIMIT_NPROC, errno = %d", errno);
75 		}
76 		test4();
77 	}
78 
79 	cleanup();
80 	tst_exit();
81 }
82 
83 /*
84  * test1 - Test for RLIMIT_NOFILE
85  */
test1(void)86 static void test1(void)
87 {
88 	rlim.rlim_cur = 100;
89 	rlim.rlim_max = 100;
90 
91 	TEST(setrlimit(RLIMIT_NOFILE, &rlim));
92 
93 	if (TEST_RETURN == -1) {
94 		tst_resm(TFAIL, "setrlimit failed to set "
95 			 "RLIMIT_NOFILE, errno = %d", errno);
96 		return;
97 	}
98 
99 	nofiles = getdtablesize();
100 
101 	if (nofiles != 100) {
102 		tst_resm(TFAIL, "setrlimit failed, expected "
103 			 "100, got %d", nofiles);
104 		return;
105 	}
106 
107 	tst_resm(TPASS, "RLIMIT_NOFILE functionality is correct");
108 }
109 
110 /*
111  * test2 - Test for RLIMIT_FSIZE
112  */
test2(void)113 static void test2(void)
114 {
115 	/*
116 	 * Since we would be altering the filesize in the child,
117 	 * we need to "sync", ie. fflush the parent's write buffers
118 	 * here.  This is because the child will inherit the parent's
119 	 * write buffer, and while exitting it would try to fflush it.
120 	 * Since its filesize is truncated to only 10 bytes, the
121 	 * fflush attempt would fail, and the child would exit with
122 	 * an wired value!  So, it is essential to fflush the parent's
123 	 * write buffer HERE
124 	 */
125 	int pipefd[2];
126 	fflush(stdout);
127 	if (pipe(pipefd) == -1)
128 		tst_brkm(TBROK | TERRNO, NULL, "pipe creation failed");
129 
130 	/*
131 	 * Spawn a child process, and reduce the filesize to
132 	 * 10 by calling setrlimit(). We can't do this in the
133 	 * parent, because the parent needs a bigger filesize as its
134 	 * output will be saved to the logfile (instead of stdout)
135 	 * when the testcase (parent) is run from the driver.
136 	 */
137 	pid = FORK_OR_VFORK();
138 	if (pid == -1)
139 		tst_brkm(TBROK, cleanup, "fork() failed");
140 
141 	if (pid == 0) {
142 		close(pipefd[0]);	/* close unused read end */
143 		rlim.rlim_cur = 10;
144 		rlim.rlim_max = 10;
145 		if ((setrlimit(RLIMIT_FSIZE, &rlim)) == -1)
146 			exit(1);
147 
148 		fd = creat(filename, 0644);
149 		if (fd < 0)
150 			exit(2);
151 
152 		bytes = write(fd, buf, 26);
153 		if (bytes != 10) {
154 			if (write(pipefd[1], &bytes, sizeof(bytes))
155 			    < sizeof(bytes)) {
156 				perror("child: write to pipe failed");
157 			}
158 			close(pipefd[1]);	/* EOF */
159 			exit(3);
160 		}
161 		exit(0);	/* success */
162 	}
163 
164 	/* parent */
165 	if (waitpid(pid, &status, 0) == -1)
166 		tst_brkm(TBROK, cleanup, "waitpid() failed");
167 
168 	switch (WEXITSTATUS(status)) {
169 	case 0:
170 		tst_resm(TPASS, "RLIMIT_FSIZE test PASSED");
171 		break;
172 	case 1:
173 		tst_resm(TFAIL, "setrlimit failed to set "
174 			 "RLIMIT_FSIZE, errno = %d", errno);
175 		break;
176 	case 2:
177 		tst_resm(TFAIL, "creating testfile failed");
178 		break;
179 	case 3:
180 		close(pipefd[1]);	/* close unused write end */
181 		if (read(pipefd[0], &bytes, sizeof(bytes)) < sizeof(bytes))
182 			tst_resm(TFAIL, "parent: reading pipe failed");
183 
184 		close(pipefd[0]);
185 		tst_resm(TFAIL, "setrlimit failed, expected "
186 			 "10 got %d", bytes);
187 		break;
188 	default:
189 		tst_resm(TFAIL, "child returned bad exit status");
190 	}
191 }
192 
193 /*
194  * test3 - Test for RLIMIT_NPROC
195  */
test3(void)196 static void test3(void)
197 {
198 	if (getrlimit(RLIMIT_NPROC, &save_rlim) < 0)
199 		tst_brkm(TBROK, cleanup, "getrlimit failed, errno: %d", errno);
200 
201 	rlim.rlim_cur = 10;
202 	rlim.rlim_max = 10;
203 
204 	TEST(setrlimit(RLIMIT_NPROC, &rlim));
205 
206 	if (TEST_RETURN == -1) {
207 		tst_resm(TFAIL, "setrlimit failed to set "
208 			 "RLIMIT_NPROC, errno = %d", errno);
209 		return;
210 	}
211 
212 	if ((getrlimit(RLIMIT_NPROC, &rlim1)) == -1) {
213 		tst_brkm(TBROK, cleanup, "getrlimit failed to get "
214 			 "values for RLIMIT_NPROC, errno = %d", errno);
215 	}
216 
217 	if ((rlim1.rlim_cur != 10) && (rlim1.rlim_max != 10)) {
218 		tst_resm(TFAIL, "setrlimit did not set the proc "
219 			 "limit correctly");
220 		return;
221 	}
222 
223 	for (i = 0; i < 20; i++) {
224 		pid = FORK_OR_VFORK();
225 		if (pid == -1) {
226 			if (errno != EAGAIN) {
227 				tst_resm(TWARN, "Expected EAGAIN got %d",
228 					 errno);
229 			}
230 		} else if (pid == 0) {
231 			exit(0);
232 		}
233 	}
234 	waitpid(pid, &status, 0);
235 	if (WEXITSTATUS(status) != 0)
236 		tst_resm(TFAIL, "RLIMIT_NPROC functionality is not correct");
237 	else
238 		tst_resm(TPASS, "RLIMIT_NPROC functionality is correct");
239 }
240 
241 /*
242  * test4() - Test for RLIMIT_CORE by forking a child and
243  *           having it cause a segfault
244  */
test4(void)245 static void test4(void)
246 {
247 	rlim.rlim_cur = 10;
248 	rlim.rlim_max = 10;
249 
250 	TEST(setrlimit(RLIMIT_CORE, &rlim));
251 
252 	if (TEST_RETURN == -1) {
253 		tst_resm(TFAIL | TERRNO, "setrlimit failed to set RLIMIT_CORE");
254 		return;
255 	}
256 
257 	pid = FORK_OR_VFORK();
258 	if (pid == -1)
259 		tst_brkm(TBROK, cleanup, "fork() failed");
260 
261 	if (pid == 0) {		/* child */
262 		char *testbuf = NULL;
263 		strcpy(testbuf, "abcd");
264 		exit(0);
265 	}
266 	wait(&status);
267 
268 	if (access("core", F_OK) == 0) {
269 		tst_resm(TFAIL, "core dump dumped unexpectedly");
270 		return;
271 	} else if (errno != ENOENT) {
272 		tst_resm(TFAIL | TERRNO, "access failed unexpectedly");
273 		return;
274 	}
275 
276 	tst_resm(TPASS, "RLIMIT_CORE functionality is correct");
277 }
278 
279 /*
280  * sighandler() - catch sigsegv when generated by child in test #4
281  */
sighandler(int sig)282 static void sighandler(int sig)
283 {
284 	if (sig != SIGSEGV && sig != SIGXFSZ && sig != SIGTERM)
285 		tst_brkm(TBROK, NULL, "caught unexpected signal: %d", sig);
286 
287 	_exit(0);
288 }
289 
setup(void)290 static void setup(void)
291 {
292 	tst_require_root();
293 
294 	umask(0);
295 
296 	tst_sig(FORK, sighandler, cleanup);
297 
298 	TEST_PAUSE;
299 
300 	tst_tmpdir();
301 
302 	sprintf(filename, "setrlimit1.%d", getpid());
303 }
304 
cleanup(void)305 static void cleanup(void)
306 {
307 	unlink(filename);
308 	tst_rmdir();
309 }
310