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