• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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