access05.c revision 43088e16aa60d69e3ec5a69cdd8bdd45b8891127
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20/*
21 * Test Name: access05
22 *
23 * Test Description:
24 *  Verify that,
25 *   1. access() fails with -1 return value and sets errno to EACCES
26 *      if the permission bits of the file mode do not permit the
27 *	 requested (Read/Write/Execute) access.
28 *   2. access() fails with -1 return value and sets errno to EINVAL
29 *	if the specified access mode argument is invalid.
30 *   3. access() fails with -1 return value and sets errno to EFAULT
31 *	if the pathname points outside allocate address space for the
32 *	process.
33 *   4. access() fails with -1 return value and sets errno to ENOENT
34 *	if the specified file doesn't exist (or pathname is NULL).
35 *   5. access() fails with -1 return value and sets errno to ENAMETOOLONG
36 *      if the pathname size is > PATH_MAX characters.
37 *
38 * Expected Result:
39 *  access() should fail with return value -1 and set expected errno.
40 *
41 * Algorithm:
42 *  Setup:
43 *   Setup signal handling.
44 *   Create temporary directory.
45 *   Pause for SIGUSR1 if option specified.
46 *
47 *  Test:
48 *   Loop if the proper options are given.
49 *   Execute system call
50 *   Check return code, if system call failed (return=-1)
51 *	if errno set == expected errno
52 *		Issue sys call fails with expected return value and errno.
53 *	Otherwise,
54 *		Issue sys call fails with unexpected errno.
55 *   Otherwise,
56 *	Issue sys call returns unexpected value.
57 *
58 *  Cleanup:
59 *   Print errno log and/or timing stats if options given
60 *   Delete the temporary directory(s)/file(s) created.
61 *
62 * Usage:  <for command-line>
63 *  access05 [-c n] [-e] [-i n] [-I x] [-P x] [-t]
64 *     where,  -c n : Run n copies concurrently.
65 *             -e   : Turn on errno logging.
66 *	       -i n : Execute test n times.
67 *	       -I x : Execute test for x seconds.
68 *	       -P x : Pause for x seconds between iterations.
69 *	       -t   : Turn on syscall timing.
70 *
71 * HISTORY
72 *	07/2001 Ported by Wayne Boyer
73 *
74 * RESTRICTIONS:
75 *  This test should be run by 'non-super-user' only.
76 *
77 */
78
79#include <stdio.h>
80#include <errno.h>
81#include <unistd.h>
82#include <fcntl.h>
83#include <string.h>
84#include <signal.h>
85#include <sys/types.h>
86#include <sys/stat.h>
87#include <sys/mman.h>
88#include <pwd.h>
89
90#include "test.h"
91#include "usctest.h"
92
93#define INV_OK		-1
94#define TEST_FILE1	"test_file1"
95#define TEST_FILE2	"test_file2"
96#define TEST_FILE3	"test_file3"
97#define TEST_FILE4	"test_file4"
98
99#define FILE_MODE	S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
100
101int no_setup();
102int setup1();			/* setup() to test access() for EACCES */
103int setup2();			/* setup() to test access() for EACCES */
104int setup3();			/* setup() to test access() for EACCES */
105int setup4();			/* setup() to test access() for EINVAL */
106int longpath_setup();		/* setup function to test access() for ENAMETOOLONG */
107
108#if !defined(UCLINUX)
109char *get_high_address();	/* function from ltp-lib        */
110char High_address_node[64];
111#endif
112
113char Longpathname[PATH_MAX + 2];
114
115struct test_case_t {		/* test case structure */
116	char *pathname;
117	int a_mode;
118	char *desc;
119	int exp_errno;
120	int (*setupfunc) ();
121} Test_cases[] = {
122	{
123	TEST_FILE1, R_OK, "Read Access denied on file", EACCES, setup1}, {
124	TEST_FILE2, W_OK, "Write Access denied on file", EACCES, setup2}, {
125	TEST_FILE3, X_OK, "Execute Access denied on file", EACCES, setup3},
126	{
127	TEST_FILE4, INV_OK, "Access mode invalid", EINVAL, setup4},
128#if !defined(UCLINUX)
129	{
130	(char *)-1, R_OK, "Negative address", EFAULT, no_setup}, {
131	High_address_node, R_OK, "Address beyond address space", EFAULT,
132		    no_setup},
133#endif
134	{
135	"", W_OK, "Pathname is empty", ENOENT, no_setup}, {
136	Longpathname, R_OK, "Pathname too long", ENAMETOOLONG, longpath_setup},
137	{
138	NULL, 0, NULL, 0, no_setup}
139};
140
141char *TCID = "access05";	/* Test program identifier.    */
142int TST_TOTAL = 8;		/* Total number of test cases. */
143extern int Tst_count;		/* Test Case counter for tst_* routines */
144int exp_enos[] = { EACCES, EFAULT, EINVAL, ENOENT, ENAMETOOLONG, 0 };
145
146char nobody_uid[] = "nobody";
147struct passwd *ltpuser;
148
149void setup();			/* Main setup function of test */
150void cleanup();			/* cleanup function for the test */
151
152char *bad_addr = 0;
153
154int main(int ac, char **av)
155{
156	int lc;			/* loop counter */
157	char *msg;		/* message returned from parse_opts */
158	char *file_name;	/* name of the testfile */
159	char *test_desc;	/* test specific message */
160	int access_mode;	/* specified access mode for testfile */
161	int ind;		/* counter for testcase looping */
162
163	/* Parse standard options given to run the test. */
164	msg = parse_opts(ac, av, (option_t *) NULL, NULL);
165	if (msg != NULL) {
166		tst_brkm(TBROK, tst_exit, "OPTION PARSING ERROR - %s", msg);
167	}
168
169	/* Perform global setup for test */
170	setup();
171
172	/* set the expected errnos... */
173	TEST_EXP_ENOS(exp_enos);
174
175	/* Check looping state if -i option given */
176	for (lc = 0; TEST_LOOPING(lc); lc++) {
177		/* Reset Tst_count in case we are looping. */
178		Tst_count = 0;
179
180		for (ind = 0; Test_cases[ind].desc != NULL; ind++) {
181			file_name = Test_cases[ind].pathname;
182			access_mode = Test_cases[ind].a_mode;
183			test_desc = Test_cases[ind].desc;
184
185#if !defined(UCLINUX)
186			if (file_name == High_address_node) {
187				file_name = get_high_address();
188			}
189#endif
190
191			/*
192			 * Call access(2) to test different test conditions.
193			 * verify that it fails with -1 return value and
194			 * sets appropriate errno.
195			 */
196			TEST(access(file_name, access_mode));
197
198			if (TEST_RETURN != -1) {
199				tst_resm(TFAIL, "access() returned %ld, "
200					 "expected -1, errno:%d", TEST_RETURN,
201					 Test_cases[ind].exp_errno);
202				continue;
203			}
204
205			TEST_ERROR_LOG(TEST_ERRNO);
206
207			/*
208			 * Call a function to verify whether
209			 * the specified file has specified
210			 * access mode.
211			 */
212			if (TEST_ERRNO == Test_cases[ind].exp_errno) {
213				tst_resm(TPASS|TTERRNO, "access() fails, %s",
214					 test_desc);
215			} else {
216				tst_resm(TFAIL|TTERRNO, "access() fails %s (expected errno %d)",
217					 test_desc, Test_cases[ind].exp_errno);
218			}
219		}		/* Test Case Looping */
220	}			/* End for TEST_LOOPING */
221
222	/* Call cleanup() to undo setup done for the test. */
223	cleanup();
224
225	return 0;
226 /*NOTREACHED*/}
227
228/*
229 * setup() - performs all ONE TIME setup for this test.
230 *
231 *  Create a temporary directory and change directory to it.
232 *  Call individual test specific setup functions.
233 */
234void setup()
235{
236	int ind;		/* counter for testsetup functions */
237
238	/* capture signals */
239	tst_sig(NOFORK, DEF_HANDLER, cleanup);
240
241	/* Switch to nobody user for correct error code collection */
242	if (geteuid() != 0) {
243		tst_brkm(TBROK, tst_exit, "Test must be run as root");
244	}
245	ltpuser = getpwnam(nobody_uid);
246	if (setuid(ltpuser->pw_uid) == -1)
247		tst_resm(TINFO|TERRNO, "setuid(%d) failed", ltpuser->pw_uid);
248
249	/* Pause if that option was specified */
250	TEST_PAUSE;
251
252	/* make a temp directory and cd to it */
253	tst_tmpdir();
254
255#if !defined(UCLINUX)
256	bad_addr = mmap(0, 1, PROT_NONE,
257			MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, 0, 0);
258	if (bad_addr == MAP_FAILED) {
259		tst_brkm(TBROK|TERRNO, cleanup, "mmap failed");
260	}
261	Test_cases[5].pathname = bad_addr;
262#endif
263
264	/* call individual setup functions */
265	for (ind = 0; Test_cases[ind].desc != NULL; ind++) {
266		Test_cases[ind].setupfunc();
267	}
268}
269
270/*
271 * no_setup() - some test conditions do not need any setup.
272 *		Hence, this function simply returns 0.
273 */
274int no_setup()
275{
276	return 0;
277}
278
279int setup_file(const char *file, mode_t perms)
280{
281	int fd;		/* file handle for testfile */
282
283	/* Creat a test file under above directory created */
284	fd = open(file, O_RDWR | O_CREAT, FILE_MODE);
285	if (fd == -1)
286		tst_brkm(TBROK|TERRNO, cleanup,
287			 "open(%s, O_RDWR|O_CREAT, %#o) failed",
288			 file, FILE_MODE);
289
290	/* Close the testfile created above */
291	if (close(fd) == -1)
292		tst_brkm(TBROK|TERRNO, cleanup, "close(%s) failed", file);
293
294	/* Change mode permissions on testfile */
295	if (chmod(file, perms) < 0)
296		tst_brkm(TBROK|TERRNO, cleanup, "chmod(%s, %#o) failed",
297			 file, perms);
298
299	return 0;
300}
301
302/*
303 * setup1() - Setup function to test access() for return value -1
304 *	      and errno EACCES when read access denied for specified
305 *	      testfile.
306 *
307 *   Creat/open a testfile and close it.
308 *   Deny read access permissions on testfile.
309 *   This function returns 0.
310 */
311int setup1()
312{
313	return setup_file(TEST_FILE1, 0333);
314}
315
316/*
317 * setup2() - Setup function to test access() for return value -1 and
318 *	      errno EACCES when write access denied on testfile.
319 *
320 *   Creat/open a testfile and close it.
321 *   Deny write access permissions on testfile.
322 *   This function returns 0.
323 */
324int setup2()
325{
326	return setup_file(TEST_FILE2, 0555);
327}
328
329/*
330 * setup3() - Setup function to test access() for return value -1 and
331 *	      errno EACCES when execute access denied on testfile.
332 *
333 *   Creat/open a testfile and close it.
334 *   Deny search access permissions on testfile.
335 *   This function returns 0.
336 */
337int setup3()
338{
339	return setup_file(TEST_FILE3, 0666);
340}
341
342/*
343 * setup4() - Setup function to test access() for return value -1
344 *	      and errno EINVAL when specified access mode argument is
345 *	      invalid.
346 *
347 *   Creat/open a testfile and close it.
348 *   This function returns 0.
349 */
350int setup4()
351{
352	return setup_file(TEST_FILE4, FILE_MODE);
353}
354
355/*
356 * longpath_setup() - setup to create a node with a name length exceeding
357 *		      the MAX. length of PATH_MAX.
358 */
359int longpath_setup()
360{
361	int ind;
362
363	for (ind = 0; ind <= (PATH_MAX + 1); ind++) {
364		Longpathname[ind] = 'a';
365	}
366
367	return 0;
368}
369
370/*
371 * cleanup() - performs all ONE TIME cleanup for this test at
372 *             completion or premature exit.
373 *
374 *  Remove the test directory and testfile created in the setup.
375 */
376void cleanup()
377{
378	/*
379	 * print timing stats if that option was specified.
380	 * print errno log if that option was specified.
381	 */
382	TEST_CLEANUP;
383
384	/*
385	 * Delete the test directory/file and temporary directory
386	 * created in the setup.
387	 */
388	tst_rmdir();
389
390	/* exit with return code appropriate for results */
391	tst_exit();
392}
393