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
91 #define MODE_RWX S_IRWXU | S_IRWXG | S_IRWXO
92 #define FILE_MODE S_IRUSR | S_IRGRP | S_IROTH
93 #define DIR_TEMP "testdir_1"
94 #define TESTFILE "testfile"
95 #define TEST_FILE1 "testdir_1/tfile_1"
96 #define SYM_FILE1 "testdir_1/sfile_1"
97 #define TEST_FILE2 "tfile_2"
98 #define SYM_FILE2 "sfile_2"
99 #define TEST_FILE3 "tfile_3"
100 #define SYM_FILE3 "t_file/sfile_3"
101
102 char *TCID = "symlink03";
103 int TST_TOTAL = 1;
104
105 char *bad_addr = 0;
106
107 int no_setup();
108 int setup1(); /* setup function to test symlink for EACCES */
109 int setup2(); /* setup function to test symlink for EEXIST */
110 int setup3(); /* setup function to test symlink for ENOTDIR */
111 int longpath_setup(); /* setup function to test chmod for ENAMETOOLONG */
112
113 char Longpathname[PATH_MAX + 2];
114 char High_address_node[64];
115
116 struct test_case_t { /* test case struct. to hold ref. test cond's */
117 char *file;
118 char *link;
119 char *desc;
120 int exp_errno;
121 int (*setupfunc) ();
122 } Test_cases[] = {
123 {
124 TEST_FILE1, SYM_FILE1, "No Search permissions to process",
125 EACCES, setup1}, {
126 TEST_FILE2, SYM_FILE2, "Specified symlink already exists",
127 EEXIST, setup2},
128 #if !defined(UCLINUX)
129 {
130 TESTFILE, High_address_node, "Address beyond address space",
131 EFAULT, no_setup},
132 #endif
133 {
134 TESTFILE, (char *)-1, "Negative address", EFAULT, no_setup}, {
135 TESTFILE, Longpathname, "Symlink path too long", ENAMETOOLONG,
136 longpath_setup}, {
137 TESTFILE, "", "Symlink Pathname is empty", ENOENT, no_setup}, {
138 TEST_FILE3, SYM_FILE3, "Symlink Path contains regular file",
139 ENOTDIR, setup3}, {
140 NULL, NULL, NULL, 0, no_setup}
141 };
142
143 char nobody_uid[] = "nobody";
144 struct passwd *ltpuser;
145
146 void setup();
147 void cleanup();
148
main(int ac,char ** av)149 int main(int ac, char **av)
150 {
151 int lc;
152 char *test_file; /* testfile name */
153 char *sym_file; /* symbolic link file name */
154 char *test_desc; /* test specific error message */
155 int ind; /* counter to test different test conditions */
156
157 tst_parse_opts(ac, av, NULL, NULL);
158
159 /*
160 * Invoke setup function to call individual test setup functions
161 * to simulate test conditions.
162 */
163 setup();
164
165 for (lc = 0; TEST_LOOPING(lc); lc++) {
166
167 tst_count = 0;
168
169 for (ind = 0; Test_cases[ind].desc != NULL; ind++) {
170 test_file = Test_cases[ind].file;
171 sym_file = Test_cases[ind].link;
172 test_desc = Test_cases[ind].desc;
173 #if !defined(UCLINUX)
174 if (sym_file == High_address_node) {
175 sym_file = (char *)get_high_address();
176 }
177 #endif
178 /*
179 * Call symlink(2) to test different test conditions.
180 * verify that it fails with -1 return value and sets
181 * appropriate errno.
182 */
183 TEST(symlink(test_file, sym_file));
184
185 if (TEST_RETURN == -1) {
186 /*
187 * Perform functional verification if
188 * test executed without (-f) option.
189 */
190 if (TEST_ERRNO == Test_cases[ind].exp_errno) {
191 tst_resm(TPASS, "symlink() Fails, %s, "
192 "errno=%d", test_desc,
193 TEST_ERRNO);
194 } else {
195 tst_resm(TFAIL, "symlink() Fails, %s, "
196 "errno=%d, expected errno=%d",
197 test_desc, TEST_ERRNO,
198 Test_cases[ind].exp_errno);
199 }
200 } else {
201 tst_resm(TFAIL, "symlink() returned %ld, "
202 "expected -1, errno:%d", TEST_RETURN,
203 Test_cases[ind].exp_errno);
204 }
205 }
206
207 tst_count++; /* incr. TEST_LOOP counter */
208 }
209
210 cleanup();
211 tst_exit();
212
213 }
214
215 /*
216 * void
217 * setup() - performs all ONE TIME setup for this test.
218 * Create a temporary directory and change directory to it.
219 * Call test specific setup functions.
220 */
setup(void)221 void setup(void)
222 {
223 int ind;
224
225 tst_require_root();
226
227 tst_sig(NOFORK, DEF_HANDLER, cleanup);
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 /* Switch to nobody user for correct error code collection */
237 ltpuser = getpwnam(nobody_uid);
238 if (setuid(ltpuser->pw_uid) == -1)
239 tst_resm(TINFO | TERRNO, "setuid(%d) failed", ltpuser->pw_uid);
240
241 tst_tmpdir();
242
243 #if !defined(UCLINUX)
244 bad_addr = mmap(0, 1, PROT_NONE,
245 MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, 0, 0);
246 if (bad_addr == MAP_FAILED) {
247 tst_brkm(TBROK, cleanup, "mmap failed");
248 }
249 Test_cases[3].link = bad_addr;
250 #endif
251
252 /* call individual setup functions */
253 for (ind = 0; Test_cases[ind].desc != NULL; ind++) {
254 Test_cases[ind].setupfunc();
255 }
256 }
257
258 /*
259 * int
260 * no_setup() - Some test conditions for mknod(2) do not any setup.
261 * Hence, this function just returns 0.
262 * This function simply returns 0.
263 */
no_setup(void)264 int no_setup(void)
265 {
266 return 0;
267 }
268
269 /*
270 * int
271 * setup1() - setup function for a test condition for which symlink(2)
272 * returns -1 and sets errno to EACCES.
273 * Create a test directory under temporary directory and create a test file
274 * under this directory with mode "0666" permissions.
275 * Modify the mode permissions on test directory such that process will not
276 * have search permissions on test directory.
277 *
278 * The function returns 0.
279 */
setup1(void)280 int setup1(void)
281 {
282 int fd; /* file handle for testfile */
283
284 if (mkdir(DIR_TEMP, MODE_RWX) < 0) {
285 tst_brkm(TBROK, cleanup, "mkdir(2) of %s failed", DIR_TEMP);
286 }
287
288 if ((fd = open(TEST_FILE1, O_RDWR | O_CREAT, 0666)) == -1) {
289 tst_brkm(TBROK, cleanup,
290 "open(%s, O_RDWR|O_CREAT, 0666) failed, errno=%d : %s",
291 TEST_FILE1, errno, strerror(errno));
292 }
293 if (close(fd) == -1) {
294 tst_brkm(TBROK, cleanup,
295 "close(%s) Failed, errno=%d : %s",
296 TEST_FILE1, errno, strerror(errno));
297 }
298
299 /* Modify mode permissions on test directory */
300 if (chmod(DIR_TEMP, FILE_MODE) < 0) {
301 tst_brkm(TBROK, cleanup, "chmod(2) of %s failed", DIR_TEMP);
302 }
303 return 0;
304 }
305
306 /*
307 * int
308 * setup2() - EEXIST
309 */
setup2(void)310 int setup2(void)
311 {
312 int fd; /* file handle for testfile */
313
314 if ((fd = open(TEST_FILE2, O_RDWR | O_CREAT, 0666)) == -1) {
315 tst_brkm(TBROK, cleanup,
316 "open(%s, O_RDWR|O_CREAT, 0666) failed, errno=%d : %s",
317 TEST_FILE1, errno, strerror(errno));
318 }
319 if (close(fd) == -1) {
320 tst_brkm(TBROK, cleanup,
321 "close(%s) Failed, errno=%d : %s",
322 TEST_FILE2, errno, strerror(errno));
323 }
324
325 if (symlink(TEST_FILE2, SYM_FILE2) < 0) {
326 tst_brkm(TBROK, cleanup,
327 "symlink() Fails to create %s in setup2, error=%d",
328 SYM_FILE2, 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 */
longpath_setup(void)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 * int
351 * setup3() - setup function for a test condition for which symlink(2)
352 * returns -1 and sets errno to ENOTDIR.
353 *
354 * Create a symlink file under temporary directory so that test tries to
355 * create symlink file "tfile_3" under "t_file" which happens to be
356 * another symlink file.
357 */
setup3(void)358 int setup3(void)
359 {
360 int fd; /* file handle for testfile */
361
362 /* Creat/open a testfile and close it */
363 if ((fd = open("t_file", O_RDWR | O_CREAT, MODE_RWX)) == -1) {
364 tst_brkm(TBROK, cleanup,
365 "open(2) on t_file failed, errno=%d : %s",
366 errno, strerror(errno));
367 }
368 if (close(fd) == -1) {
369 tst_brkm(TBROK, cleanup, "close(t_file) Failed, errno=%d : %s",
370 errno, strerror(errno));
371 }
372 return 0;
373 }
374
375 /*
376 * void
377 * cleanup() - performs all ONE TIME cleanup for this test at
378 * completion or premature exit.
379 * Restore the mode permissions on test directory.
380 * Remove the temporary directory created in the setup.
381 */
cleanup(void)382 void cleanup(void)
383 {
384
385 /* Restore mode permissions on test directory created in setup2() */
386 if (chmod(DIR_TEMP, MODE_RWX) < 0) {
387 tst_brkm(TBROK, NULL, "chmod(2) of %s failed", DIR_TEMP);
388 }
389
390 tst_rmdir();
391
392 }
393