1 /*
2  * Copyright (c) 2014 Fujitsu Ltd.
3  * Author: Zeng Linggang <zenglg.jy@cn.fujitsu.com>
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 the
13  * GNU Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  *
19  */
20 /*
21  * Test Description:
22  *  Verify that,
23  *   1. bufsiz is 0, EINVAL should be returned.
24  *   2. The named file is not a symbolic link, EINVAL should be returned.
25  *   3. The component of the path prefix is not a directory, ENOTDIR should be
26  *	returned.
27  *   4. pathname is relative and dirfd is a file descriptor referring to a file
28  *	other than a directory, ENOTDIR should be returned.
29  */
30 
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <errno.h>
34 
35 #include "test.h"
36 #include "safe_macros.h"
37 #include "lapi/readlinkat.h"
38 #include "lapi/syscalls.h"
39 
40 #define TEST_FILE	"test_file"
41 #define SYMLINK_FILE	"symlink_file"
42 #define BUFF_SIZE	256
43 
44 static int file_fd, dir_fd;
45 
46 static struct test_case_t {
47 	int *dirfd;
48 	const char *pathname;
49 	size_t bufsiz;
50 	int exp_errno;
51 } test_cases[] = {
52 	{&dir_fd, SYMLINK_FILE, 0, EINVAL},
53 	{&dir_fd, TEST_FILE, BUFF_SIZE, EINVAL},
54 	{&file_fd, SYMLINK_FILE, BUFF_SIZE, ENOTDIR},
55 	{&dir_fd, "test_file/test_file", BUFF_SIZE, ENOTDIR},
56 };
57 
58 char *TCID = "readlinkat02";
59 int TST_TOTAL = ARRAY_SIZE(test_cases);
60 static void setup(void);
61 static void cleanup(void);
62 static void readlinkat_verify(const struct test_case_t *);
63 
main(int argc,char ** argv)64 int main(int argc, char **argv)
65 {
66 	int i, lc;
67 
68 	tst_parse_opts(argc, argv, NULL, NULL);
69 
70 	setup();
71 
72 	for (lc = 0; TEST_LOOPING(lc); lc++) {
73 		tst_count = 0;
74 		for (i = 0; i < TST_TOTAL; i++)
75 			readlinkat_verify(&test_cases[i]);
76 	}
77 
78 	cleanup();
79 	tst_exit();
80 }
81 
setup(void)82 static void setup(void)
83 {
84 	tst_sig(NOFORK, DEF_HANDLER, cleanup);
85 
86 	TEST_PAUSE;
87 
88 	tst_tmpdir();
89 
90 	dir_fd = SAFE_OPEN(cleanup, "./", O_RDONLY);
91 
92 	file_fd = SAFE_OPEN(cleanup, TEST_FILE, O_RDWR | O_CREAT, 0644);
93 
94 	SAFE_SYMLINK(cleanup, TEST_FILE, SYMLINK_FILE);
95 }
96 
readlinkat_verify(const struct test_case_t * test)97 static void readlinkat_verify(const struct test_case_t *test)
98 {
99 	char buf[BUFF_SIZE];
100 	TEST(readlinkat(*test->dirfd, test->pathname, buf, test->bufsiz));
101 
102 	if (TEST_RETURN != -1) {
103 		tst_resm(TFAIL, "readlinkat succeeded unexpectedly");
104 		return;
105 	}
106 
107 	if (TEST_ERRNO == test->exp_errno) {
108 		tst_resm(TPASS | TTERRNO, "readlinkat failed as expected");
109 	} else {
110 		tst_resm(TFAIL | TTERRNO,
111 			 "readlinkat failed unexpectedly; expected: %d - %s",
112 			 test->exp_errno, strerror(test->exp_errno));
113 	}
114 }
115 
cleanup(void)116 static void cleanup(void)
117 {
118 	close(dir_fd);
119 	close(file_fd);
120 
121 	tst_rmdir();
122 }
123