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