1 /*
2 * Copyright (c) International Business Machines Corp., 2001
3 * 07/2001 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 * Description:
21 * 1) create a directory tstdir1, create a file under it.
22 * call rmdir(tstdir1), verify the return value is -1
23 * and the errno is ENOTEMPTY.
24 * 2) create a directory with long path, call rmdir(tstdir1),
25 * verify the return value is -1 and the errno is ENAMETOOLONG.
26 * 3) pass a pathname containing non-exist directory component
27 * to rmdir(), verify the return value is -1 and the errno
28 * is ENOENT.
29 * 4) pass a pathname containing a file component to rmdir(),
30 * verify the return value is -1 and the errno is ENOTDIR.
31 * 5) attempt to pass an invalid pathname with an address
32 * pointing outside the address space of the process, as the
33 * argument to rmdir(), verify the return value is -1 and
34 * the errno is EFAULT.
35 * 6) attempt to pass an invalid pathname with NULL, as the
36 * argument to rmdir(), verify the return value is -1 and
37 * the errno is EFAULT.
38 * 7) pass a pathname with too many symbolic links to rmdir(),
39 * verify the return value is -1 and the errno is ELOOP.
40 * 8) pass a pathname which refers to a directory on a read-only
41 * file system to rmdir(), verify the return value is -1 and
42 * the errno is EROFS.
43 * 9) pass a pathname which is currently used as a mount point
44 * to rmdir(), verify the return value is -1 and the errno is
45 * EBUSY.
46 */
47
48 #include <errno.h>
49 #include <sys/stat.h>
50 #include <sys/types.h>
51 #include <sys/mman.h>
52 #include <fcntl.h>
53 #include <unistd.h>
54 #include <pwd.h>
55 #include <sys/mount.h>
56
57 #include "test.h"
58 #include "safe_macros.h"
59
60 #define DIR_MODE (S_IRWXU | S_IRWXG | S_IRWXO)
61 #define FILE_MODE (S_IRWXU | S_IRWXG | S_IRWXO)
62
63 #define TESTDIR "testdir"
64 #define TESTDIR2 "nosuchdir/testdir2"
65 #define TESTDIR3 "testfile2/testdir3"
66 #define TESTDIR4 "/loopdir"
67 #define MNTPOINT "mntpoint"
68 #define TESTDIR5 "mntpoint/testdir5"
69 #define TESTFILE "testdir/testfile"
70 #define TESTFILE2 "testfile2"
71
72 static char longpathname[PATH_MAX + 2];
73 static char looppathname[sizeof(TESTDIR4) * 43] = ".";
74
75 static const char *device;
76 static int mount_flag;
77
78 static struct test_case_t {
79 char *dir;
80 int exp_errno;
81 } test_cases[] = {
82 {TESTDIR, ENOTEMPTY},
83 {longpathname, ENAMETOOLONG},
84 {TESTDIR2, ENOENT},
85 {TESTDIR3, ENOTDIR},
86 #if !defined(UCLINUX)
87 {(char *)-1, EFAULT},
88 #endif
89 {NULL, EFAULT},
90 {looppathname, ELOOP},
91 {TESTDIR5, EROFS},
92 {MNTPOINT, EBUSY},
93 };
94
95 static void setup(void);
96 static void rmdir_verify(struct test_case_t *tc);
97 static void cleanup(void);
98
99 char *TCID = "rmdir02";
100 int TST_TOTAL = ARRAY_SIZE(test_cases);
101
main(int ac,char ** av)102 int main(int ac, char **av)
103 {
104 int i, lc;
105
106 tst_parse_opts(ac, av, NULL, NULL);
107
108 setup();
109
110 for (lc = 0; TEST_LOOPING(lc); lc++) {
111 tst_count = 0;
112
113 for (i = 0; i < TST_TOTAL; i++)
114 rmdir_verify(&test_cases[i]);
115 }
116
117 cleanup();
118 tst_exit();
119 }
120
setup(void)121 static void setup(void)
122 {
123 int i;
124 const char *fs_type;
125
126 tst_require_root();
127
128 tst_sig(NOFORK, DEF_HANDLER, cleanup);
129
130 TEST_PAUSE;
131
132 tst_tmpdir();
133
134 fs_type = tst_dev_fs_type();
135 device = tst_acquire_device(cleanup);
136
137 if (!device)
138 tst_brkm(TCONF, cleanup, "Failed to acquire device");
139
140 tst_mkfs(cleanup, device, fs_type, NULL, NULL);
141 SAFE_MKDIR(cleanup, MNTPOINT, DIR_MODE);
142 SAFE_MOUNT(cleanup, device, MNTPOINT, fs_type, 0, NULL);
143 SAFE_MKDIR(cleanup, TESTDIR5, DIR_MODE);
144 SAFE_MOUNT(cleanup, device, MNTPOINT, fs_type, MS_REMOUNT | MS_RDONLY,
145 NULL);
146 mount_flag = 1;
147
148 SAFE_MKDIR(cleanup, TESTDIR, DIR_MODE);
149 SAFE_TOUCH(cleanup, TESTFILE, FILE_MODE, NULL);
150
151 memset(longpathname, 'a', PATH_MAX + 1);
152
153 SAFE_TOUCH(cleanup, TESTFILE2, FILE_MODE, NULL);
154
155 #if !defined(UCLINUX)
156 test_cases[4].dir = SAFE_MMAP(cleanup, 0, 1, PROT_NONE,
157 MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
158 #endif
159
160 /*
161 * NOTE: the ELOOP test is written based on that the
162 * consecutive symlinks limit in kernel is hardwired
163 * to 40.
164 */
165 SAFE_MKDIR(cleanup, "loopdir", DIR_MODE);
166 SAFE_SYMLINK(cleanup, "../loopdir", "loopdir/loopdir");
167 for (i = 0; i < 43; i++)
168 strcat(looppathname, TESTDIR4);
169 }
170
rmdir_verify(struct test_case_t * tc)171 static void rmdir_verify(struct test_case_t *tc)
172 {
173 TEST(rmdir(tc->dir));
174
175 if (TEST_RETURN != -1) {
176 tst_resm(TFAIL, "rmdir() returned %ld, "
177 "expected -1, errno:%d", TEST_RETURN,
178 tc->exp_errno);
179 return;
180 }
181
182 if (TEST_ERRNO == tc->exp_errno) {
183 tst_resm(TPASS | TTERRNO, "rmdir() failed as expected");
184 } else {
185 tst_resm(TFAIL | TTERRNO,
186 "rmdir() failed unexpectedly; expected: %d - %s",
187 tc->exp_errno, strerror(tc->exp_errno));
188 }
189 }
190
cleanup(void)191 static void cleanup(void)
192 {
193 if (mount_flag && tst_umount(MNTPOINT) == -1)
194 tst_resm(TWARN | TERRNO, "umount %s failed", MNTPOINT);
195
196 if (device)
197 tst_release_device(device);
198
199 tst_rmdir();
200 }
201