Home | History | Annotate | Download | only in mknod
      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: mknod06
     22  *
     23  * Test Description:
     24  * Verify that,
     25  *   1) mknod(2) returns -1 and sets errno to EEXIST if specified path
     26  *	already exists.
     27  *   2) mknod(2) returns -1 and sets errno to EFAULT if pathname points
     28  *	outside user's accessible address space.
     29  *   3) mknod(2) returns -1 and sets errno to ENOENT if the directory
     30  *	component in pathname does not exist.
     31  *   4) mknod(2) returns -1 and sets errno to ENAMETOOLONG if the pathname
     32  *	component was too long.
     33  *   5) mknod(2) returns -1 and sets errno to ENOTDIR if the directory
     34  *	component in pathname is not a directory.
     35  *
     36  * Expected Result:
     37  *  mknod() 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  *  mknod06 [-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 Ported by Wayne Boyer
     71  *
     72  * RESTRICTIONS:
     73  *  This test should be executed by super-user (root) only.
     74  */
     75 
     76 #include <stdio.h>
     77 #include <stdlib.h>
     78 #include <unistd.h>
     79 #include <errno.h>
     80 #include <string.h>
     81 #include <signal.h>
     82 #include <sys/types.h>
     83 #include <sys/stat.h>
     84 #include <sys/param.h>
     85 #include <sys/mman.h>
     86 
     87 #include "test.h"
     88 
     89 #define MODE_RWX		S_IFIFO | S_IRWXU | S_IRWXG | S_IRWXO
     90 
     91 int setup1();			/* setup function to test mknod for EEXIST */
     92 int setup3();			/* setup function to test mknod for ENOTDIR */
     93 int longpath_setup();		/* setup function to test mknod for ENAMETOOLONG */
     94 int no_setup();			/* simply returns 0 to the caller */
     95 char Longpathname[PATH_MAX + 2];
     96 char High_address_node[64];
     97 
     98 struct test_case_t {		/* test case struct. to hold ref. test cond's */
     99 	char *pathname;
    100 	char *desc;
    101 	int exp_errno;
    102 	int (*setupfunc) ();
    103 } Test_cases[] = {
    104 	{
    105 	"tnode_1", "Specified node already exists", EEXIST, setup1},
    106 #if !defined(UCLINUX)
    107 	{
    108 	(char *)-1, "Negative address", EFAULT, no_setup}, {
    109 	High_address_node, "Address beyond address space", EFAULT,
    110 		    no_setup},
    111 #endif
    112 	{
    113 	"testdir_2/tnode_2", "Non-existent file", ENOENT, no_setup}, {
    114 	"", "Pathname is empty", ENOENT, no_setup}, {
    115 	Longpathname, "Pathname too long", ENAMETOOLONG, longpath_setup}, {
    116 	"tnode/tnode_3", "Path contains regular file", ENOTDIR, setup3}, {
    117 	NULL, NULL, 0, no_setup}
    118 };
    119 
    120 char *TCID = "mknod06";
    121 int TST_TOTAL = ARRAY_SIZE(Test_cases);
    122 #if !defined(UCLINUX)
    123 extern char *get_high_address();
    124 #else
    125 #endif
    126 
    127 char *bad_addr = 0;
    128 
    129 void setup();			/* setup function for the tests */
    130 void cleanup();			/* cleanup function for the tests */
    131 
    132 int main(int ac, char **av)
    133 {
    134 	int lc;
    135 	char *node_name;	/* ptr. for node name created */
    136 	char *test_desc;	/* test specific error message */
    137 	int ind;		/* counter to test different test conditions */
    138 
    139 	tst_parse_opts(ac, av, NULL, NULL);
    140 
    141 	/*
    142 	 * Invoke setup function to call individual test setup functions
    143 	 * for the test which run as root/super-user.
    144 	 */
    145 	setup();
    146 
    147 	for (lc = 0; TEST_LOOPING(lc); lc++) {
    148 
    149 		tst_count = 0;
    150 
    151 		for (ind = 0; Test_cases[ind].desc != NULL; ind++) {
    152 			node_name = Test_cases[ind].pathname;
    153 			test_desc = Test_cases[ind].desc;
    154 
    155 #if !defined(UCLINUX)
    156 			if (node_name == High_address_node) {
    157 				node_name = get_high_address();
    158 			}
    159 #endif
    160 
    161 			/*
    162 			 * Call mknod(2) to test different test conditions.
    163 			 * verify that it fails with -1 return value and
    164 			 * sets appropriate errno.
    165 			 */
    166 			TEST(mknod(node_name, MODE_RWX, 0));
    167 
    168 			/* Check return code from mknod(2) */
    169 			if (TEST_RETURN != -1) {
    170 				tst_resm(TFAIL,
    171 					 "mknod() returned %ld, expected "
    172 					 "-1, errno:%d", TEST_RETURN,
    173 					 Test_cases[ind].exp_errno);
    174 				continue;
    175 			}
    176 
    177 			if (TEST_ERRNO == Test_cases[ind].exp_errno) {
    178 				tst_resm(TPASS, "mknod() fails, %s, errno:%d",
    179 					 test_desc, TEST_ERRNO);
    180 			} else {
    181 				tst_resm(TFAIL, "mknod() fails, %s, errno:%d, "
    182 					 "expected errno:%d", test_desc,
    183 					 TEST_ERRNO, Test_cases[ind].exp_errno);
    184 			}
    185 		}
    186 
    187 	}
    188 
    189 	/*
    190 	 * Invoke cleanup() to delete the test directories created
    191 	 * in the setup().
    192 	 */
    193 	cleanup();
    194 
    195 	tst_exit();
    196 }
    197 
    198 /*
    199  * setup(void) - performs all ONE TIME setup for this test.
    200  * 	Exit the test program on receipt of unexpected signals.
    201  *	Create a temporary directory used to hold test directories and nodes
    202  *	created and change the directory to it.
    203  *	Invoke individual test setup functions according to the order
    204  *	set in struct. definition.
    205  */
    206 void setup(void)
    207 {
    208 	int ind;
    209 
    210 	tst_require_root();
    211 
    212 	/* Capture unexpected signals */
    213 	tst_sig(NOFORK, DEF_HANDLER, cleanup);
    214 
    215 	TEST_PAUSE;
    216 
    217 	/* Make a temp dir and cd to it */
    218 	tst_tmpdir();
    219 
    220 #if !defined(UCLINUX)
    221 	bad_addr = mmap(0, 1, PROT_NONE,
    222 			MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, 0, 0);
    223 	if (bad_addr == MAP_FAILED) {
    224 		tst_brkm(TBROK, cleanup, "mmap failed");
    225 	}
    226 	Test_cases[2].pathname = bad_addr;
    227 #endif
    228 	/* call individual setup functions */
    229 	for (ind = 0; Test_cases[ind].desc != NULL; ind++) {
    230 		Test_cases[ind].setupfunc();
    231 	}
    232 }
    233 
    234 /*
    235  * no_setup() - Some test conditions for mknod(2) do not any setup.
    236  *		Hence, this function just returns 0.
    237  */
    238 int no_setup(void)
    239 {
    240 	return 0;
    241 }
    242 
    243 /*
    244  * longpath_setup() - setup to create a node with a name length exceeding
    245  *		      the MAX. length of PATH_MAX.
    246  *   This function retruns 0.
    247  */
    248 int longpath_setup(void)
    249 {
    250 	int ind;		/* counter variable */
    251 
    252 	for (ind = 0; ind <= (PATH_MAX + 1); ind++) {
    253 		Longpathname[ind] = 'a';
    254 	}
    255 	return 0;
    256 }
    257 
    258 /*
    259  * setup1() - setup function for a test condition for which mknod(2)
    260  *	      returns -1 and sets errno to EEXIST.
    261  *  This function creates a node using mknod(2) and tries to create
    262  *  same node in the test and fails with above errno.
    263  *  This function returns 0.
    264  */
    265 int setup1(void)
    266 {
    267 	/* Create a node using mknod */
    268 	if (mknod("tnode_1", MODE_RWX, 0) < 0) {
    269 		tst_brkm(TBROK, cleanup, "Fails to create node in setup1()");
    270 	}
    271 
    272 	return 0;
    273 }
    274 
    275 /*
    276  * setup3() - setup function for a test condition for which mknod(2)
    277  *	      returns -1 and sets errno to ENOTDIR.
    278  *  This function creates a node under temporary directory and the
    279  *  test attempts to create another node under under this node and fails
    280  *  with ENOTDIR as the node created here is a regular file.
    281  *  This function returns 0.
    282  */
    283 int setup3(void)
    284 {
    285 	/* Create a node using mknod */
    286 	if (mknod("tnode", MODE_RWX, 0) < 0) {
    287 		tst_brkm(TBROK, cleanup, "Fails to create node in setup3()");
    288 	}
    289 
    290 	return 0;
    291 }
    292 
    293 /*
    294  * cleanup() - Performs all ONE TIME cleanup for this test at
    295  *             completion or premature exit.
    296  *	Print test timing stats and errno log if test executed with options.
    297  *	Remove temporary directory and sub-directories/files under it
    298  *	created during setup().
    299  *	Exit the test program with normal exit code.
    300  */
    301 void cleanup(void)
    302 {
    303 
    304 	tst_rmdir();
    305 
    306 }
    307