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 "linux_syscall_numbers.h"
39
40#define TEST_FILE	"test_file"
41#define SYMLINK_FILE	"symlink_file"
42#define BUFF_SIZE	256
43
44static int file_fd, dir_fd;
45
46static 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
58char *TCID = "readlinkat02";
59int TST_TOTAL = ARRAY_SIZE(test_cases);
60static void setup(void);
61static void cleanup(void);
62static void readlinkat_verify(const struct test_case_t *);
63
64int 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
82static 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
97static 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
116static void cleanup(void)
117{
118	close(dir_fd);
119	close(file_fd);
120
121	tst_rmdir();
122}
123