Home | History | Annotate | Download | only in stat
      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  * Test Name: stat03
     22  *
     23  * Test Description:
     24  *   Verify that,
     25  *   1) stat(2) returns -1 and sets errno to EACCES if search permission is
     26  *      denied on a component of the path prefix.
     27  *   2) stat(2) returns -1 and sets errno to ENOENT if the specified file
     28  *	does not exists or empty string.
     29  *   3) stat(2) returns -1 and sets errno to EFAULT if pathname points
     30  *	outside user's accessible address space.
     31  *   4) stat(2) returns -1 and sets errno to ENAMETOOLONG if the pathname
     32  *	component is too long.
     33  *   5) stat(2) returns -1 and sets errno to ENOTDIR if the directory
     34  *	component in pathname is not a directory.
     35  *
     36  * Expected Result:
     37  *  stat() should fail with return value -1 and set expected errno.
     38  *
     39  * Algorithm:
     40  *  Setup:
     41  *   Setup signal handling.
     42  *   Create temporary directory.
     43  *   Pause for SIGUSR1 if option specified.
     44  *
     45  *  Test:
     46  *   Loop if the proper options are given.
     47  *   Execute system call
     48  *   Check return code, if system call failed (return=-1)
     49  *   	if errno set == expected errno
     50  *   		Issue sys call fails with expected return value and errno.
     51  *   	Otherwise,
     52  *		Issue sys call fails with unexpected errno.
     53  *   Otherwise,
     54  *	Issue sys call returns unexpected value.
     55  *
     56  *  Cleanup:
     57  *   Print errno log and/or timing stats if options given
     58  *   Delete the temporary directory(s)/file(s) created.
     59  *
     60  * Usage:  <for command-line>
     61  *  stat03 [-c n] [-e] [-i n] [-I x] [-p x] [-t]
     62  *	where,  -c n : Run n copies concurrently.
     63  *		-e   : Turn on errno logging.
     64  *		-i n : Execute test n times.
     65  *		-I x : Execute test for x seconds.
     66  *		-P x : Pause for x seconds between iterations.
     67  *		-t   : Turn on syscall timing.
     68  *
     69  * History
     70  *	07/2001 John George
     71  *		-Ported
     72  *
     73  * Restrictions:
     74  *
     75  */
     76 
     77 #include <stdio.h>
     78 #include <stdlib.h>
     79 #include <unistd.h>
     80 #include <fcntl.h>
     81 #include <errno.h>
     82 #include <string.h>
     83 #include <signal.h>
     84 #include <sys/types.h>
     85 #include <sys/stat.h>
     86 #include <sys/mman.h>
     87 #include <pwd.h>
     88 
     89 #include "test.h"
     90 #include "safe_macros.h"
     91 
     92 #define MODE_RWX	S_IRWXU | S_IRWXG | S_IRWXO
     93 #define FILE_MODE	S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
     94 #define DIR_TEMP	"testdir_1"
     95 #define TEST_FILE1	"testdir_1/tfile_1"
     96 #define TEST_FILE2	"t_file/tfile_2"
     97 
     98 int no_setup();
     99 int setup1();			/* setup function to test chmod for EACCES */
    100 int setup2();			/* setup function to test chmod for ENOTDIR */
    101 int longpath_setup();		/* setup function to test chmod for ENAMETOOLONG */
    102 char nobody_uid[] = "nobody";
    103 struct passwd *ltpuser;
    104 
    105 char Longpathname[PATH_MAX + 2];
    106 char High_address_node[64];
    107 
    108 struct test_case_t {		/* test case struct. to hold ref. test cond's */
    109 	char *pathname;
    110 	char *desc;
    111 	int exp_errno;
    112 	int (*setupfunc) ();
    113 } Test_cases[] = {
    114 	{
    115 	TEST_FILE1, "No Search permissions to process", EACCES, setup1},
    116 #if !defined(UCLINUX)
    117 	{
    118 	High_address_node, "Address beyond address space", EFAULT, no_setup},
    119 	{
    120 	(char *)-1, "Negative address", EFAULT, no_setup},
    121 #endif
    122 	{
    123 	Longpathname, "Pathname too long", ENAMETOOLONG, longpath_setup}, {
    124 	"", "Pathname is empty", ENOENT, no_setup}, {
    125 	TEST_FILE2, "Path contains regular file", ENOTDIR, setup2}, {
    126 	NULL, NULL, 0, no_setup}
    127 };
    128 
    129 char *TCID = "stat03";
    130 int TST_TOTAL = ARRAY_SIZE(Test_cases);
    131 
    132 char *bad_addr = 0;
    133 
    134 void setup();			/* Main setup function for the tests */
    135 void cleanup();			/* cleanup function for the test */
    136 
    137 int main(int ac, char **av)
    138 {
    139 	struct stat stat_buf;	/* stat structure buffer */
    140 	int lc;
    141 	char *file_name;	/* ptr. for file name whose mode is modified */
    142 	char *test_desc;	/* test specific error message */
    143 	int ind;		/* counter to test different test conditions */
    144 
    145 	tst_parse_opts(ac, av, NULL, NULL);
    146 
    147 	/*
    148 	 * Invoke setup function to call individual test setup functions
    149 	 * to simulate test conditions.
    150 	 */
    151 	setup();
    152 
    153 	for (lc = 0; TEST_LOOPING(lc); lc++) {
    154 
    155 		tst_count = 0;
    156 
    157 		for (ind = 0; Test_cases[ind].desc != NULL; ind++) {
    158 			file_name = Test_cases[ind].pathname;
    159 			test_desc = Test_cases[ind].desc;
    160 
    161 #if !defined(UCLINUX)
    162 			if (file_name == High_address_node) {
    163 				file_name = (char *)get_high_address();
    164 			}
    165 #endif
    166 
    167 			/*
    168 			 * Call stat(2) to test different test conditions.
    169 			 * verify that it fails with -1 return value and
    170 			 * sets appropriate errno.
    171 			 */
    172 			TEST(stat(file_name, &stat_buf));
    173 
    174 			/* Check return code from stat(2) */
    175 			if (TEST_RETURN == -1) {
    176 				if (TEST_ERRNO == Test_cases[ind].exp_errno) {
    177 					tst_resm(TPASS,
    178 						 "stat() fails, %s, errno:%d",
    179 						 test_desc, TEST_ERRNO);
    180 				} else {
    181 					tst_resm(TFAIL,
    182 						 "stat() fails, %s, errno:%d, expected errno:%d",
    183 						 test_desc, TEST_ERRNO,
    184 						 Test_cases[ind].exp_errno);
    185 				}
    186 			} else {
    187 				tst_resm(TFAIL,
    188 					 "stat(2) returned %ld, expected -1, errno:%d",
    189 					 TEST_RETURN,
    190 					 Test_cases[ind].exp_errno);
    191 			}
    192 		}
    193 		tst_count++;	/* incr TEST_LOOP counter */
    194 	}
    195 
    196 	/*
    197 	 * Invoke cleanup() to delete the test directory/file(s) created
    198 	 * in the setup().
    199 	 */
    200 	cleanup();
    201 	tst_exit();
    202 
    203 }
    204 
    205 /*
    206  * void
    207  * setup(void) - performs all ONE TIME setup for this test.
    208  * 	Exit the test program on receipt of unexpected signals.
    209  *	Create a temporary directory and change directory to it.
    210  *	Invoke individual test setup functions according to the order
    211  *	set in struct. definition.
    212  */
    213 void setup(void)
    214 {
    215 	int ind;
    216 
    217 	tst_require_root();
    218 
    219 	/* Capture unexpected signals */
    220 	tst_sig(FORK, DEF_HANDLER, cleanup);
    221 
    222 	/* Switch to nobody user for correct error code collection */
    223 	ltpuser = getpwnam(nobody_uid);
    224 	if (setuid(ltpuser->pw_uid) == -1) {
    225 		tst_resm(TINFO, "setuid failed to "
    226 			 "to set the effective uid to %d", ltpuser->pw_uid);
    227 		perror("setuid");
    228 	}
    229 
    230 	/* Pause if that option was specified
    231 	 * TEST_PAUSE contains the code to fork the test with the -i option.
    232 	 * You want to make sure you do this before you create your temporary
    233 	 * directory.
    234 	 */
    235 	TEST_PAUSE;
    236 
    237 	/* Make a temp dir and cd to it */
    238 	tst_tmpdir();
    239 
    240 #if !defined(UCLINUX)
    241 	bad_addr = mmap(0, 1, PROT_NONE,
    242 			MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, 0, 0);
    243 	if (bad_addr == MAP_FAILED) {
    244 		tst_brkm(TBROK, cleanup, "mmap failed");
    245 	}
    246 	Test_cases[2].pathname = bad_addr;
    247 #endif
    248 
    249 	/* call individual setup functions */
    250 	for (ind = 0; Test_cases[ind].desc != NULL; ind++) {
    251 		Test_cases[ind].setupfunc();
    252 	}
    253 }
    254 
    255 /*
    256  * int
    257  * no_setup() - Some test conditions for stat(2) do not any setup.
    258  *              Hence, this function just returns 0.
    259  *  This function simply returns 0.
    260  */
    261 int no_setup(void)
    262 {
    263 	return 0;
    264 }
    265 
    266 /*
    267  * int
    268  * setup1() - setup function for a test condition for which stat(2)
    269  *	      returns -1 and sets errno to EACCES.
    270  *  Create a test directory under temporary directory and create a test file
    271  *  under this directory with mode "0666" permissions.
    272  *  Modify the mode permissions on test directory such that process will not
    273  *  have search permissions on test directory.
    274  *
    275  *  The function returns 0.
    276  */
    277 int setup1(void)
    278 {
    279 	int fd;			/* file handle for testfile */
    280 
    281 	/* Creat a test directory */
    282 	SAFE_MKDIR(cleanup, DIR_TEMP, MODE_RWX);
    283 
    284 	/* Creat a test file under above test directory */
    285 	if ((fd = open(TEST_FILE1, O_RDWR | O_CREAT, 0666)) == -1) {
    286 		tst_brkm(TBROK, cleanup,
    287 			 "open(%s, O_RDWR|O_CREAT, 0666) failed, errno=%d : %s",
    288 			 TEST_FILE1, errno, strerror(errno));
    289 	}
    290 	/* Close the test file */
    291 	SAFE_CLOSE(cleanup, fd);
    292 
    293 	/* Modify mode permissions on test directory */
    294 	SAFE_CHMOD(cleanup, DIR_TEMP, FILE_MODE);
    295 	return 0;
    296 }
    297 
    298 /*
    299  * int
    300  * setup2() - setup function for a test condition for which stat(2)
    301  *	     returns -1 and sets errno to ENOTDIR.
    302  *
    303  *  Create a test file under temporary directory so that test tries to
    304  *  change mode of a testfile "tfile_2" under "t_file" which happens to be
    305  *  another regular file.
    306  */
    307 int setup2(void)
    308 {
    309 	int fd;			/* File handle for test file */
    310 
    311 	/* Creat a test file under temporary directory */
    312 	if ((fd = open("t_file", O_RDWR | O_CREAT, MODE_RWX)) == -1) {
    313 		tst_brkm(TBROK, cleanup,
    314 			 "open(2) on t_file failed, errno=%d : %s",
    315 			 errno, strerror(errno));
    316 	}
    317 	/* Close the test file created above */
    318 	SAFE_CLOSE(cleanup, fd);
    319 	return 0;
    320 }
    321 
    322 /*
    323  * int
    324  * longpath_setup() - setup to create a node with a name length exceeding
    325  *                    the MAX. length of PATH_MAX.
    326  *   This function retruns 0.
    327  */
    328 int longpath_setup(void)
    329 {
    330 	int ind;		/* counter variable */
    331 
    332 	for (ind = 0; ind <= (PATH_MAX + 1); ind++) {
    333 		Longpathname[ind] = 'a';
    334 	}
    335 	return 0;
    336 }
    337 
    338 /*
    339  * void
    340  * cleanup() - Performs all ONE TIME cleanup for this test at
    341  *             completion or premature exit.
    342  *	Print test timing stats and errno log if test executed with options.
    343  *	Remove temporary directory and sub-directories/files under it
    344  *	created during setup().
    345  *	Exit the test program with normal exit code.
    346  */
    347 void cleanup(void)
    348 {
    349 
    350 	/* Restore mode permissions on test directory created in setup2() */
    351 	if (chmod(DIR_TEMP, MODE_RWX) < 0) {
    352 		tst_brkm(TFAIL, NULL, "chmod(2) of %s failed", DIR_TEMP);
    353 	}
    354 
    355 	tst_rmdir();
    356 }
    357