1/*
2 * Copyright (c) Wipro Technologies Ltd, 2002.  All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
12 * You should have received a copy of the GNU General Public License along
13 * with this program; if not, write the Free Software Foundation, Inc.,
14 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
15 *
16 */
17/**************************************************************************
18 *
19 *    TEST IDENTIFIER	: mlockall02
20 *
21 *    EXECUTED BY	: root / superuser
22 *
23 *    TEST TITLE	: Test for checking basic error conditions for
24 *    			   mlockall(2)
25 *
26 *    TEST CASE TOTAL	: 3
27 *
28 *    AUTHOR		: Nirmala Devi Dhanasekar <nirmala.devi@wipro.com>
29 *
30 *    SIGNALS
31 * 	Uses SIGUSR1 to pause before test if option set.
32 * 	(See the parse_opts(3) man page).
33 *
34 *    DESCRIPTION
35 * 	Check for basic errors returned by mount(2) system call.
36 *$
37 * 	Verify that mount(2) returns -1 and sets errno to
38 *
39 *	1) ENOMEM - If process exceed maximum  number of locked pages.
40 *	2) EPERM  - If not super user
41 *	3) EINVAL - Unknown flags were specified.
42 *
43 * 	Setup:
44 *	  Setup signal handling.
45 *	  Pause for SIGUSR1 if option specified.
46 *
47 * 	Test:
48 *	 Loop if the proper options are given.
49 *	  Do necessary setup for each test.
50 *	  Execute system call
51 *	  Check return code, if system call failed and errno == expected errno
52 *		Issue sys call passed with expected return value and errno.
53 *	  Otherwise,
54 *		Issue sys call failed to produce expected error.
55 *	  Do cleanup for each test.
56 *
57 * 	Cleanup:
58 * 	  Print errno log and/or timing stats if options given
59 *
60 * USAGE:  <for command-line>
61 *  mlockall02 [-c n] [-e] [-i n] [-I x] [-p x] [-t]
62 *		where,
63 *			-c n : Run n copies concurrently
64 *			-e   : Turn on errno logging.
65 *			-h   : Show this help screen
66 *			-i n : Execute test n times.
67 *			-I x : Execute test for x seconds.
68 *			-p   : Pause for SIGUSR1 before starting
69 *			-P x : Pause for x seconds between iterations.
70 *			-t   : Turn on syscall timing.
71 *
72 * RESTRICTIONS
73 *	Test must run as root.
74 *****************************************************************************/
75#include <errno.h>
76#include <unistd.h>
77#include <pwd.h>
78#include <sys/mman.h>
79#include "test.h"
80#include "safe_macros.h"
81#include <sys/resource.h>
82
83void setup();
84int setup_test(int);
85void cleanup_test(int);
86void cleanup();
87
88char *TCID = "mlockall02";
89int TST_TOTAL = 3;
90
91struct test_case_t {
92	int flag;		/* flag value                   */
93	int error;		/* error description            */
94	char *edesc;		/* Expected error no            */
95} TC[] = {
96	{
97	MCL_CURRENT, ENOMEM, "Process exceeds max locked pages"}, {
98	MCL_CURRENT, EPERM, "Not a superuser"}, {
99	0, EINVAL, "Unknown flag"}
100};
101
102#if !defined(UCLINUX)
103
104int main(int ac, char **av)
105{
106	int lc, i;
107
108	tst_parse_opts(ac, av, NULL, NULL);
109
110	setup();
111
112	/* check looping state */
113	for (lc = 0; TEST_LOOPING(lc); lc++) {
114
115		tst_count = 0;
116
117		for (i = 0; i < TST_TOTAL; i++) {
118
119			if (setup_test(i)) {
120				tst_resm(TFAIL, "mlockall() Failed while setup "
121					 "for checking error %s", TC[i].edesc);
122				continue;
123			}
124
125			TEST(mlockall(TC[i].flag));
126
127			/* check return code */
128			if (TEST_RETURN == -1) {
129				if (TEST_ERRNO != TC[i].error)
130					tst_brkm(TFAIL, cleanup,
131						 "mlock() Failed with wrong "
132						 "errno, expected errno=%s, "
133						 "got errno=%d : %s",
134						 TC[i].edesc, TEST_ERRNO,
135						 strerror(TEST_ERRNO));
136				else
137					tst_resm(TPASS,
138						 "expected failure - errno "
139						 "= %d : %s",
140						 TEST_ERRNO,
141						 strerror(TEST_ERRNO));
142			} else {
143				if (i <= 1)
144					tst_resm(TCONF,
145						 "mlockall02 did not BEHAVE as expected.");
146				else
147					tst_brkm(TFAIL, cleanup,
148						 "mlock() Failed, expected "
149						 "return value=-1, got %ld",
150						 TEST_RETURN);
151			}
152			cleanup_test(i);
153		}
154	}
155
156	/* cleanup and exit */
157	cleanup();
158
159	tst_exit();
160}
161
162/*
163 * setup() - performs all ONE TIME setup for this test.
164 */
165void setup(void)
166{
167
168	tst_require_root();
169
170	tst_sig(FORK, DEF_HANDLER, cleanup);
171
172	TEST_PAUSE;
173
174	return;
175}
176
177int setup_test(int i)
178{
179	struct rlimit rl;
180	char nobody_uid[] = "nobody";
181	struct passwd *ltpuser;
182
183	switch (i) {
184	case 0:
185		rl.rlim_max = 10;
186		rl.rlim_cur = 7;
187
188		if (setrlimit(RLIMIT_MEMLOCK, &rl) != 0) {
189			tst_resm(TWARN, "setrlimit failed to set the "
190				 "resource for RLIMIT_MEMLOCK to check "
191				 "for mlockall error %s\n", TC[i].edesc);
192			return 1;
193		}
194		ltpuser = getpwnam(nobody_uid);
195		if (seteuid(ltpuser->pw_uid) == -1) {
196			tst_brkm(TBROK, cleanup, "seteuid() "
197				"failed to change euid to %d "
198				"errno = %d : %s",
199				ltpuser->pw_uid, TEST_ERRNO,
200				strerror(TEST_ERRNO));
201				return 1;
202		}
203		return 0;
204	case 1:
205		rl.rlim_max = 0;
206		rl.rlim_cur = 0;
207		if (setrlimit(RLIMIT_MEMLOCK, &rl) != 0) {
208			tst_resm(TWARN, "setrlimit failed to "
209				"set the resource for "
210				"RLIMIT_MEMLOCK to check for "
211				"mlockall error %s\n", TC[i].edesc);
212				return 1;
213		}
214		ltpuser = getpwnam(nobody_uid);
215		if (seteuid(ltpuser->pw_uid) == -1) {
216			tst_brkm(TBROK, cleanup, "seteuid() failed to "
217				 "change euid to %d errno = %d : %s",
218				 ltpuser->pw_uid, TEST_ERRNO,
219				 strerror(TEST_ERRNO));
220			return 1;
221		}
222		return 0;
223	}
224	return 0;
225}
226
227void cleanup_test(int i)
228{
229	struct rlimit rl;
230
231	switch (i) {
232	case 0:
233		seteuid(0);
234
235		rl.rlim_max = -1;
236		rl.rlim_cur = -1;
237
238		if (setrlimit(RLIMIT_MEMLOCK, &rl) != 0) {
239			tst_brkm(TFAIL, cleanup,
240				 "setrlimit failed to reset the "
241				 "resource for RLIMIT_MEMLOCK while "
242				 "checking for mlockall error %s\n",
243				 TC[i].edesc);
244		}
245		return;
246	case 1:
247		SAFE_SETEUID(cleanup, 0);
248		return;
249
250	}
251}
252
253/*
254 * cleanup() - performs all ONE TIME cleanup for this test at
255 *		completion or premature exit.
256 */
257void cleanup(void)
258{
259	return;
260}
261
262#else
263
264int main(void)
265{
266	tst_resm(TINFO, "test is not available on uClinux");
267	tst_exit();
268}
269
270#endif /* if !defined(UCLINUX) */
271