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