1/*
2 * Copyright (c) International Business Machines  Corp., 2001
3 *    Ported by Wayne Boyer
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 Foundation,
17 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20/*
21 * DESCRIPTION
22 *	Testcase to check creat(2) sets the following errnos correctly:
23 *	1.	EISDIR
24 *	2.	ENAMETOOLONG
25 *	3.	ENOENT
26 *	4.	ENOTDIR
27 *	5.	EFAULT
28 *	6.	EACCES
29 *	7.	ELOOP
30 *	8.	EROFS
31 *
32 *
33 * ALGORITHM
34 *	1.	Attempt to creat(2) an existing directory, and test for
35 *		EISDIR
36 *	2.	Attempt to creat(2) a file whose name is more than
37 *		VFS_MAXNAMLEN and test for ENAMETOOLONG.
38 *	3.	Attempt to creat(2) a file inside a directory which doesn't
39 *		exist, and test for ENOENT
40 *	4.	Attempt to creat(2) a file, the pathname of which comprises
41 *		a component which is a file, test for ENOTDIR.
42 *	5.	Attempt to creat(2) a file with a bad address
43 *		and test for EFAULT
44 *	6.	Attempt to creat(2) a file in a directory with no
45 *		execute permission and test for EACCES
46 *	7.	Attempt to creat(2) a file which links the other file that
47 *		links the former and test for ELOOP
48 *	8.	Attempt to creat(2) a file in a Read-only file system
49 *		and test for EROFS
50 */
51
52#include <errno.h>
53#include <string.h>
54#include <pwd.h>
55#include <sys/mman.h>
56#include <sys/types.h>
57#include <sys/stat.h>
58#include <sys/mount.h>
59
60#include "tst_test.h"
61
62#define	TEST_FILE	"test_dir"
63#define	NO_DIR		"testfile/testdir"
64#define	NOT_DIR		"file1/testdir"
65#define	TEST6_FILE	"dir6/file6"
66#define	TEST7_FILE	"file7"
67#define	TEST8_FILE	"mntpoint/tmp"
68
69#define	MODE1		0444
70#define	MODE2		0666
71
72static void setup(void);
73static void cleanup(void);
74static void test6_setup(void);
75static void test6_cleanup(void);
76#if !defined(UCLINUX)
77static void bad_addr_setup(int);
78#endif
79
80static struct passwd *ltpuser;
81static char long_name[PATH_MAX+2];
82static const char *device;
83static int mount_flag;
84
85static struct test_case_t {
86	char *fname;
87	int mode;
88	int error;
89	void (*setup)();
90	void (*cleanup)(void);
91} tcases[] = {
92	{TEST_FILE, MODE1, EISDIR, NULL, NULL},
93	{long_name, MODE1, ENAMETOOLONG, NULL, NULL},
94	{NO_DIR, MODE1, ENOENT, NULL, NULL},
95	{NOT_DIR, MODE1, ENOTDIR, NULL, NULL},
96#if !defined(UCLINUX)
97	{NULL, MODE1, EFAULT, bad_addr_setup, NULL},
98#endif
99	{TEST6_FILE, MODE1, EACCES, test6_setup, test6_cleanup},
100	{TEST7_FILE, MODE1, ELOOP, NULL, NULL},
101	{TEST8_FILE, MODE1, EROFS, NULL, NULL},
102};
103
104static void verify_creat(unsigned int i)
105{
106	if (tcases[i].setup != NULL)
107		tcases[i].setup(i);
108
109	TEST(creat(tcases[i].fname, tcases[i].mode));
110
111	if (tcases[i].cleanup != NULL)
112		tcases[i].cleanup();
113
114	if (TEST_RETURN != -1) {
115		tst_res(TFAIL, "call succeeded unexpectedly");
116		return;
117	}
118
119	if (TEST_ERRNO == tcases[i].error) {
120		tst_res(TPASS | TTERRNO, "got expected failure");
121		return;
122	}
123
124	tst_res(TFAIL | TTERRNO, "expected %s",
125	         tst_strerrno(tcases[i].error));
126}
127
128
129static void setup(void)
130{
131	ltpuser = SAFE_GETPWNAM("nobody");
132
133	SAFE_MKDIR(TEST_FILE, MODE2);
134
135	memset(long_name, 'a', PATH_MAX+1);
136
137	SAFE_TOUCH("file1", MODE1, NULL);
138
139	SAFE_MKDIR("dir6", MODE2);
140
141	SAFE_SYMLINK(TEST7_FILE, "test_file_eloop2");
142	SAFE_SYMLINK("test_file_eloop2", TEST7_FILE);
143
144	SAFE_MKFS(tst_device->dev, tst_device->fs_type, NULL, NULL);
145
146	SAFE_MKDIR("mntpoint", 0777);
147	SAFE_MOUNT(tst_device->dev, "mntpoint", tst_device->fs_type,
148	           MS_RDONLY, NULL);
149	mount_flag = 1;
150}
151
152#if !defined(UCLINUX)
153static void bad_addr_setup(int i)
154{
155	if (tcases[i].fname)
156		return;
157
158	tcases[i].fname = SAFE_MMAP(0, 1, PROT_NONE,
159	                            MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
160}
161#endif
162
163static void test6_setup(void)
164{
165	SAFE_SETEUID(ltpuser->pw_uid);
166}
167
168static void test6_cleanup(void)
169{
170	SAFE_SETEUID(0);
171}
172
173static void cleanup(void)
174{
175	if (mount_flag && tst_umount("mntpoint") < 0)
176		tst_brk(TBROK | TERRNO, "umount device:%s failed", device);
177}
178
179static struct tst_test test = {
180	.tid = "creat06",
181	.tcnt = ARRAY_SIZE(tcases),
182	.test = verify_creat,
183	.needs_root = 1,
184	.needs_tmpdir = 1,
185	.needs_device = 1,
186	.cleanup = cleanup,
187	.setup = setup,
188};
189