• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************
2  *
3  *   Copyright (c) International Business Machines  Corp., 2006
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  * NAME
20  *      symlinkat01.c
21  *
22  * DESCRIPTION
23  *	This test case will verify basic function of symlinkat
24  *	added by kernel 2.6.16 or up.
25  *
26  * Author
27  *	Yi Yang <yyangcdl@cn.ibm.com>
28  *
29  * History
30  *      08/25/2006      Created first by Yi Yang <yyangcdl@cn.ibm.com>
31  *
32  *****************************************************************************/
33 
34 #define _GNU_SOURCE
35 
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <sys/time.h>
39 #include <fcntl.h>
40 #include <error.h>
41 #include <stdlib.h>
42 #include <errno.h>
43 #include <string.h>
44 #include <signal.h>
45 #include "test.h"
46 #include "rmobj.h"
47 #include "linux_syscall_numbers.h"
48 
49 #define MYRETCODE -999
50 #ifndef AT_FDCWD
51 #define AT_FDCWD -100
52 #endif
53 
54 struct test_struct;
55 static void setup();
56 static void cleanup();
57 static void setup_every_copy();
58 static void mysymlinkat_test(struct test_struct *desc);
59 
60 #define TEST_DIR1 "olddir"
61 #define TEST_DIR2 "newdir"
62 #define TEST_DIR3 "deldir"
63 #define TEST_FILE1 "oldfile"
64 #define TEST_FILE2 "newfile"
65 #define TEST_FIFO "fifo"
66 
67 static char dpathname[256] = "%s/" TEST_DIR2 "/" TEST_FILE1;
68 static int olddirfd, newdirfd = -1, cwd_fd = AT_FDCWD, stdinfd = 0, crapfd =
69     -1, deldirfd;
70 
71 struct test_struct {
72 	const char *oldfn;
73 	int *newfd;
74 	const char *newfn;
75 	const char *referencefn1;
76 	const char *referencefn2;
77 	int expected_errno;
78 } test_desc[] = {
79 	/* relative paths */
80 	{
81 	"../" TEST_DIR1 "/" TEST_FILE1, &newdirfd, TEST_FILE1,
82 		    TEST_DIR1 "/" TEST_FILE1, TEST_DIR2 "/" TEST_FILE1, 0},
83 	    /* abs path at dst */
84 	{
85 	"../" TEST_DIR1 "/" TEST_FILE1, &newdirfd, dpathname,
86 		    TEST_DIR1 "/" TEST_FILE1, TEST_DIR2 "/" TEST_FILE1, 0},
87 	    /* relative paths to cwd */
88 	{
89 	"../" TEST_DIR1 "/" TEST_FILE1, &cwd_fd,
90 		    TEST_DIR2 "/" TEST_FILE1, TEST_DIR1 "/" TEST_FILE1,
91 		    TEST_DIR2 "/" TEST_FILE1, 0},
92 	    /* abs path */
93 	{
94 	"../" TEST_DIR1 "/" TEST_FILE1, &cwd_fd, dpathname,
95 		    TEST_DIR1 "/" TEST_FILE1, TEST_DIR2 "/" TEST_FILE1, 0},
96 	    /* relative paths to invalid */
97 	{
98 	"../" TEST_DIR1 "/" TEST_FILE1, &stdinfd,
99 		    TEST_DIR2 "/" TEST_FILE1, 0, 0, ENOTDIR},
100 	    /* abs path at dst */
101 	{
102 	"../" TEST_DIR1 "/" TEST_FILE1, &stdinfd, dpathname,
103 		    TEST_DIR1 "/" TEST_FILE1, TEST_DIR2 "/" TEST_FILE1, 0},
104 	    /* relative paths to crap */
105 	{
106 	"../" TEST_DIR1 "/" TEST_FILE1, &crapfd,
107 		    TEST_DIR2 "/" TEST_FILE1, 0, 0, EBADF},
108 	    /* abs path at dst */
109 	{
110 	"../" TEST_DIR1 "/" TEST_FILE1, &crapfd, dpathname,
111 		    TEST_DIR1 "/" TEST_FILE1, TEST_DIR2 "/" TEST_FILE1, 0},
112 	    /* relative paths to deleted */
113 	{
114 	"../" TEST_DIR1 "/" TEST_FILE1, &deldirfd,
115 		    TEST_DIR2 "/" TEST_FILE1, 0, 0, ENOENT},
116 	    /* abs path at dst */
117 	{
118 	"../" TEST_DIR1 "/" TEST_FILE1, &deldirfd, dpathname,
119 		    TEST_DIR1 "/" TEST_FILE1, TEST_DIR2 "/" TEST_FILE1, 0},
120 	    /* fifo link */
121 	    /*      { TEST_FIFO, &newdirfd, TEST_FILE1, TEST_DIR1"/"TEST_FIFO, TEST_DIR2"/"TEST_FILE1, 0 }, */
122 };
123 
124 char *TCID = "symlinkat01";
125 int TST_TOTAL = sizeof(test_desc) / sizeof(*test_desc);
126 
127 #define SUCCEED_OR_DIE(syscall, message, ...)														\
128 	(errno = 0,																														\
129 		({int ret=syscall(__VA_ARGS__);																			\
130 			if (ret==-1)																												\
131 				tst_brkm(TBROK, cleanup, message, __VA_ARGS__, strerror(errno)); \
132 			ret;}))
133 
mysymlinkat(const char * oldfilename,int newdirfd,const char * newfilename)134 static int mysymlinkat(const char *oldfilename,
135 		       int newdirfd, const char *newfilename)
136 {
137 	return ltp_syscall(__NR_symlinkat, oldfilename, newdirfd, newfilename);
138 }
139 
main(int ac,char ** av)140 int main(int ac, char **av)
141 {
142 	int lc;
143 	int i;
144 
145 	/* Disable test if the version of the kernel is less than 2.6.16 */
146 	if ((tst_kvercmp(2, 6, 16)) < 0) {
147 		tst_resm(TWARN, "This test can only run on kernels that are ");
148 		tst_resm(TWARN, "2.6.16 and higher");
149 		exit(0);
150 	}
151 
152 	tst_parse_opts(ac, av, NULL, NULL);
153 
154 	setup();
155 
156 	for (lc = 0; TEST_LOOPING(lc); lc++) {
157 
158 		tst_count = 0;
159 
160 		for (i = 0; i < TST_TOTAL; i++) {
161 			setup_every_copy();
162 			mysymlinkat_test(&test_desc[i]);
163 
164 		}
165 
166 	}
167 
168 	cleanup();
169 	tst_exit();
170 }
171 
setup_every_copy(void)172 static void setup_every_copy(void)
173 {
174 	close(newdirfd);
175 	rmobj(TEST_DIR2, NULL);
176 
177 	SUCCEED_OR_DIE(mkdir, "mkdir(%s, %o) failed: %s", TEST_DIR2, 0700);
178 	newdirfd =
179 	    SUCCEED_OR_DIE(open, "open(%s, 0x%x) failed: %s", TEST_DIR2,
180 			   O_DIRECTORY);
181 }
182 
mysymlinkat_test(struct test_struct * desc)183 static void mysymlinkat_test(struct test_struct *desc)
184 {
185 	int fd;
186 
187 	TEST(mysymlinkat(desc->oldfn, *desc->newfd, desc->newfn));
188 
189 	/* check return code */
190 	if (TEST_ERRNO == desc->expected_errno) {
191 		if (TEST_RETURN == 0 && desc->referencefn1 != NULL) {
192 			int tnum = rand(), vnum = ~tnum;
193 			int len;
194 			fd = SUCCEED_OR_DIE(open,
195 					    "open(%s, 0x%x) failed: %s",
196 					    desc->referencefn1, O_RDWR);
197 			if ((len =
198 			     write(fd, &tnum,
199 				   sizeof(tnum))) != sizeof(tnum))
200 				tst_brkm(TBROK, cleanup,
201 					 "write() failed: expected %zu, returned %d; error: %s",
202 					 sizeof(tnum), len,
203 					 strerror(errno));
204 			SUCCEED_OR_DIE(close, "close(%d) failed: %s",
205 				       fd);
206 
207 			fd = SUCCEED_OR_DIE(open,
208 					    "open(%s, 0x%x) failed: %s",
209 					    desc->referencefn2,
210 					    O_RDONLY);
211 			if ((len =
212 			     read(fd, &vnum,
213 				  sizeof(vnum))) != sizeof(tnum))
214 				tst_brkm(TBROK, cleanup,
215 					 "read() failed: expected %zu, returned %d; error: %s",
216 					 sizeof(vnum), len,
217 					 strerror(errno));
218 			SUCCEED_OR_DIE(close, "close(%d) failed: %s",
219 				       fd);
220 
221 			if (tnum == vnum)
222 				tst_resm(TPASS, "Test passed");
223 			else
224 				tst_resm(TFAIL,
225 					 "The link file's content isn't as same as the original file's "
226 					 "although symlinkat returned 0");
227 		} else {
228 			tst_resm(TPASS,
229 				 "symlinkat() returned the expected  errno %d: %s",
230 				 TEST_ERRNO, strerror(TEST_ERRNO));
231 		}
232 	} else {
233 		tst_resm(TFAIL,
234 			 TEST_RETURN ==
235 			 0 ? "symlinkat() surprisingly succeeded" :
236 			 "symlinkat() Failed, errno=%d : %s", TEST_ERRNO,
237 			 strerror(TEST_ERRNO));
238 	}
239 }
240 
setup(void)241 static void setup(void)
242 {
243 	char *tmp;
244 
245 	tst_sig(NOFORK, DEF_HANDLER, cleanup);
246 
247 	tst_tmpdir();
248 
249 	SUCCEED_OR_DIE(mkdir, "mkdir(%s, %o) failed: %s", TEST_DIR1, 0700);
250 	SUCCEED_OR_DIE(mkdir, "mkdir(%s, %o) failed: %s", TEST_DIR3, 0700);
251 	olddirfd =
252 	    SUCCEED_OR_DIE(open, "open(%s, 0x%x) failed: %s", TEST_DIR1,
253 			   O_DIRECTORY);
254 	deldirfd =
255 	    SUCCEED_OR_DIE(open, "open(%s, 0x%x) failed: %s", TEST_DIR3,
256 			   O_DIRECTORY);
257 	SUCCEED_OR_DIE(rmdir, "rmdir(%s) failed: %s", TEST_DIR3);
258 	SUCCEED_OR_DIE(close, "close(%d) failed: %s",
259 		       SUCCEED_OR_DIE(open, "open(%s, 0x%x, %o) failed: %s",
260 				      TEST_DIR1 "/" TEST_FILE1,
261 				      O_CREAT | O_EXCL, 0600));
262 
263 	/* gratuitous memory leak here */
264 	tmp = strdup(dpathname);
265 	snprintf(dpathname, sizeof(dpathname), tmp, get_current_dir_name());
266 
267 	TEST_PAUSE;
268 }
269 
cleanup(void)270 static void cleanup(void)
271 {
272 	tst_rmdir();
273 }
274