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
main(int ac,char ** av)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 */
setup(void)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 */
no_setup(void)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 */
setup1(void)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 */
setup2(void)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 */
longpath_setup(void)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 */
setup3(void)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 */
cleanup(void)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