• 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 #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