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