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 
     91 #define MODE_RWX	S_IRWXU | S_IRWXG | S_IRWXO
     92 #define FILE_MODE	S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
     93 #define DIR_TEMP	"testdir_1"
     94 #define TEST_FILE1	"testdir_1/tfile_1"
     95 #define TEST_FILE2	"t_file/tfile_2"
     96 
     97 int no_setup();
     98 int setup1();			/* setup function to test chmod for EACCES */
     99 int setup2();			/* setup function to test chmod for ENOTDIR */
    100 int longpath_setup();		/* setup function to test chmod for ENAMETOOLONG */
    101 char nobody_uid[] = "nobody";
    102 struct passwd *ltpuser;
    103 
    104 char Longpathname[PATH_MAX + 2];
    105 char High_address_node[64];
    106 
    107 struct test_case_t {		/* test case struct. to hold ref. test cond's */
    108 	char *pathname;
    109 	char *desc;
    110 	int exp_errno;
    111 	int (*setupfunc) ();
    112 } Test_cases[] = {
    113 	{
    114 	TEST_FILE1, "No Search permissions to process", EACCES, setup1},
    115 #if !defined(UCLINUX)
    116 	{
    117 	High_address_node, "Address beyond address space", EFAULT, no_setup},
    118 	{
    119 	(char *)-1, "Negative address", EFAULT, no_setup},
    120 #endif
    121 	{
    122 	Longpathname, "Pathname too long", ENAMETOOLONG, longpath_setup}, {
    123 	"", "Pathname is empty", ENOENT, no_setup}, {
    124 	TEST_FILE2, "Path contains regular file", ENOTDIR, setup2}, {
    125 	NULL, NULL, 0, no_setup}
    126 };
    127 
    128 char *TCID = "stat03";
    129 int TST_TOTAL = ARRAY_SIZE(Test_cases);
    130 
    131 char *bad_addr = 0;
    132 
    133 void setup();			/* Main setup function for the tests */
    134 void cleanup();			/* cleanup function for the test */
    135 
    136 int main(int ac, char **av)
    137 {
    138 	struct stat stat_buf;	/* stat structure buffer */
    139 	int lc;
    140 	char *file_name;	/* ptr. for file name whose mode is modified */
    141 	char *test_desc;	/* test specific error message */
    142 	int ind;		/* counter to test different test conditions */
    143 
    144 	tst_parse_opts(ac, av, NULL, NULL);
    145 
    146 	/*
    147 	 * Invoke setup function to call individual test setup functions
    148 	 * to simulate test conditions.
    149 	 */
    150 	setup();
    151 
    152 	for (lc = 0; TEST_LOOPING(lc); lc++) {
    153 
    154 		tst_count = 0;
    155 
    156 		for (ind = 0; Test_cases[ind].desc != NULL; ind++) {
    157 			file_name = Test_cases[ind].pathname;
    158 			test_desc = Test_cases[ind].desc;
    159 
    160 #if !defined(UCLINUX)
    161 			if (file_name == High_address_node) {
    162 				file_name = (char *)get_high_address();
    163 			}
    164 #endif
    165 
    166 			/*
    167 			 * Call stat(2) to test different test conditions.
    168 			 * verify that it fails with -1 return value and
    169 			 * sets appropriate errno.
    170 			 */
    171 			TEST(stat(file_name, &stat_buf));
    172 
    173 			/* Check return code from stat(2) */
    174 			if (TEST_RETURN == -1) {
    175 				if (TEST_ERRNO == Test_cases[ind].exp_errno) {
    176 					tst_resm(TPASS,
    177 						 "stat() fails, %s, errno:%d",
    178 						 test_desc, TEST_ERRNO);
    179 				} else {
    180 					tst_resm(TFAIL,
    181 						 "stat() fails, %s, errno:%d, expected errno:%d",
    182 						 test_desc, TEST_ERRNO,
    183 						 Test_cases[ind].exp_errno);
    184 				}
    185 			} else {
    186 				tst_resm(TFAIL,
    187 					 "stat(2) returned %ld, expected -1, errno:%d",
    188 					 TEST_RETURN,
    189 					 Test_cases[ind].exp_errno);
    190 			}
    191 		}
    192 		tst_count++;	/* incr TEST_LOOP counter */
    193 	}
    194 
    195 	/*
    196 	 * Invoke cleanup() to delete the test directory/file(s) created
    197 	 * in the setup().
    198 	 */
    199 	cleanup();
    200 	tst_exit();
    201 
    202 }
    203 
    204 /*
    205  * void
    206  * setup(void) - performs all ONE TIME setup for this test.
    207  * 	Exit the test program on receipt of unexpected signals.
    208  *	Create a temporary directory and change directory to it.
    209  *	Invoke individual test setup functions according to the order
    210  *	set in struct. definition.
    211  */
    212 void setup(void)
    213 {
    214 	int ind;
    215 
    216 	tst_require_root();
    217 
    218 	/* Capture unexpected signals */
    219 	tst_sig(FORK, DEF_HANDLER, cleanup);
    220 
    221 	/* Switch to nobody user for correct error code collection */
    222 	ltpuser = getpwnam(nobody_uid);
    223 	if (setuid(ltpuser->pw_uid) == -1) {
    224 		tst_resm(TINFO, "setuid failed to "
    225 			 "to set the effective uid to %d", ltpuser->pw_uid);
    226 		perror("setuid");
    227 	}
    228 
    229 	/* Pause if that option was specified
    230 	 * TEST_PAUSE contains the code to fork the test with the -i option.
    231 	 * You want to make sure you do this before you create your temporary
    232 	 * directory.
    233 	 */
    234 	TEST_PAUSE;
    235 
    236 	/* Make a temp dir and cd to it */
    237 	tst_tmpdir();
    238 
    239 #if !defined(UCLINUX)
    240 	bad_addr = mmap(0, 1, PROT_NONE,
    241 			MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, 0, 0);
    242 	if (bad_addr == MAP_FAILED) {
    243 		tst_brkm(TBROK, cleanup, "mmap failed");
    244 	}
    245 	Test_cases[2].pathname = bad_addr;
    246 #endif
    247 
    248 	/* call individual setup functions */
    249 	for (ind = 0; Test_cases[ind].desc != NULL; ind++) {
    250 		Test_cases[ind].setupfunc();
    251 	}
    252 }
    253 
    254 /*
    255  * int
    256  * no_setup() - Some test conditions for stat(2) do not any setup.
    257  *              Hence, this function just returns 0.
    258  *  This function simply returns 0.
    259  */
    260 int no_setup(void)
    261 {
    262 	return 0;
    263 }
    264 
    265 /*
    266  * int
    267  * setup1() - setup function for a test condition for which stat(2)
    268  *	      returns -1 and sets errno to EACCES.
    269  *  Create a test directory under temporary directory and create a test file
    270  *  under this directory with mode "0666" permissions.
    271  *  Modify the mode permissions on test directory such that process will not
    272  *  have search permissions on test directory.
    273  *
    274  *  The function returns 0.
    275  */
    276 int setup1(void)
    277 {
    278 	int fd;			/* file handle for testfile */
    279 
    280 	/* Creat a test directory */
    281 	if (mkdir(DIR_TEMP, MODE_RWX) < 0) {
    282 		tst_brkm(TBROK, cleanup, "mkdir(2) of %s failed", DIR_TEMP);
    283 	}
    284 
    285 	/* Creat a test file under above test directory */
    286 	if ((fd = open(TEST_FILE1, O_RDWR | O_CREAT, 0666)) == -1) {
    287 		tst_brkm(TBROK, cleanup,
    288 			 "open(%s, O_RDWR|O_CREAT, 0666) failed, errno=%d : %s",
    289 			 TEST_FILE1, errno, strerror(errno));
    290 	}
    291 	/* Close the test file */
    292 	if (close(fd) == -1) {
    293 		tst_brkm(TBROK, cleanup,
    294 			 "close(%s) Failed, errno=%d : %s",
    295 			 TEST_FILE1, errno, strerror(errno));
    296 	}
    297 
    298 	/* Modify mode permissions on test directory */
    299 	if (chmod(DIR_TEMP, FILE_MODE) < 0) {
    300 		tst_brkm(TBROK, cleanup, "chmod(2) of %s failed", DIR_TEMP);
    301 	}
    302 	return 0;
    303 }
    304 
    305 /*
    306  * int
    307  * setup2() - setup function for a test condition for which stat(2)
    308  *	     returns -1 and sets errno to ENOTDIR.
    309  *
    310  *  Create a test file under temporary directory so that test tries to
    311  *  change mode of a testfile "tfile_2" under "t_file" which happens to be
    312  *  another regular file.
    313  */
    314 int setup2(void)
    315 {
    316 	int fd;			/* File handle for test file */
    317 
    318 	/* Creat a test file under temporary directory */
    319 	if ((fd = open("t_file", O_RDWR | O_CREAT, MODE_RWX)) == -1) {
    320 		tst_brkm(TBROK, cleanup,
    321 			 "open(2) on t_file failed, errno=%d : %s",
    322 			 errno, strerror(errno));
    323 	}
    324 	/* Close the test file created above */
    325 	if (close(fd) == -1) {
    326 		tst_brkm(TBROK, cleanup,
    327 			 "close(t_file) Failed, errno=%d : %s",
    328 			 errno, strerror(errno));
    329 	}
    330 	return 0;
    331 }
    332 
    333 /*
    334  * int
    335  * longpath_setup() - setup to create a node with a name length exceeding
    336  *                    the MAX. length of PATH_MAX.
    337  *   This function retruns 0.
    338  */
    339 int longpath_setup(void)
    340 {
    341 	int ind;		/* counter variable */
    342 
    343 	for (ind = 0; ind <= (PATH_MAX + 1); ind++) {
    344 		Longpathname[ind] = 'a';
    345 	}
    346 	return 0;
    347 }
    348 
    349 /*
    350  * void
    351  * cleanup() - Performs all ONE TIME cleanup for this test at
    352  *             completion or premature exit.
    353  *	Print test timing stats and errno log if test executed with options.
    354  *	Remove temporary directory and sub-directories/files under it
    355  *	created during setup().
    356  *	Exit the test program with normal exit code.
    357  */
    358 void cleanup(void)
    359 {
    360 
    361 	/* Restore mode permissions on test directory created in setup2() */
    362 	if (chmod(DIR_TEMP, MODE_RWX) < 0) {
    363 		tst_brkm(TFAIL, NULL, "chmod(2) of %s failed", DIR_TEMP);
    364 	}
    365 
    366 	tst_rmdir();
    367 }
    368