1 /*
2 * Copyright (c) International Business Machines Corp., 2001
3 * written by Wayne Boyer
4 * Copyright (c) 2013 Markos Chandras
5 * Copyright (c) 2013 Cyril Hrubis <chrubis@suse.cz>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
15 * the GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #define _GNU_SOURCE
23 #include <stdio.h>
24 #include <errno.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28
29 #include "test.h"
30 #include "safe_macros.h"
31 #include "getdents.h"
32
33 static void cleanup(void);
34 static void setup(void);
35
36 static void reset_flags(void);
37 static void check_flags(void);
38 static void set_flag(const char *name);
39
40 char *TCID = "getdents01";
41 int TST_TOTAL = 1;
42
43 static int longsyscall;
44
45 static option_t options[] = {
46 /* -l long option. Tests getdents64 */
47 {"l", &longsyscall, NULL},
48 {NULL, NULL, NULL}
49 };
50
help(void)51 static void help(void)
52 {
53 printf(" -l Test the getdents64 system call\n");
54 }
55
56 enum entry_type {
57 ENTRY_DIR,
58 ENTRY_FILE,
59 ENTRY_SYMLINK,
60 };
61
62 struct testcase {
63 const char *name;
64 enum entry_type type;
65 int create:1;
66 int found:1;
67 };
68
69 struct testcase testcases[] = {
70 {.name = ".", .create = 0, .type = ENTRY_DIR},
71 {.name = "..", .create = 0, .type = ENTRY_DIR},
72 {.name = "dir", .create = 1, .type = ENTRY_DIR},
73 {.name = "file", .create = 1, .type = ENTRY_FILE},
74 {.name = "symlink", .create = 1, .type = ENTRY_SYMLINK},
75 };
76
77 /*
78 * Big enough for dirp entires + data, the current size returned
79 * by kernel is 128 bytes.
80 */
81 #define BUFSIZE 512
82
main(int ac,char ** av)83 int main(int ac, char **av)
84 {
85 int lc;
86 int rval, fd;
87 struct linux_dirent64 *dirp64;
88 struct linux_dirent *dirp;
89 void *buf;
90
91 tst_parse_opts(ac, av, options, &help);
92
93 /* The buffer is allocated to make sure it's suitably aligned */
94 buf = malloc(BUFSIZE);
95
96 if (buf == NULL)
97 tst_brkm(TBROK, NULL, "malloc failed");
98
99 dirp64 = buf;
100 dirp = buf;
101
102 setup();
103
104 for (lc = 0; TEST_LOOPING(lc); lc++) {
105 const char *d_name;
106
107 tst_count = 0;
108
109 if ((fd = open(".", O_RDONLY)) == -1)
110 tst_brkm(TBROK, cleanup, "open of directory failed");
111
112 if (longsyscall)
113 rval = getdents64(fd, dirp64, BUFSIZE);
114 else
115 rval = getdents(fd, dirp, BUFSIZE);
116
117 if (rval < 0) {
118 if (errno == ENOSYS)
119 tst_resm(TCONF, "syscall not implemented");
120 else
121 tst_resm(TFAIL | TERRNO,
122 "getdents failed unexpectedly");
123 continue;
124 }
125
126 if (rval == 0) {
127 tst_resm(TFAIL,
128 "getdents failed - returned end of directory");
129 continue;
130 }
131
132 reset_flags();
133
134 do {
135 size_t d_reclen;
136
137 if (longsyscall) {
138 d_reclen = dirp64->d_reclen;
139 d_name = dirp64->d_name;
140 } else {
141 d_reclen = dirp->d_reclen;
142 d_name = dirp->d_name;
143 }
144
145 set_flag(d_name);
146
147 tst_resm(TINFO, "Found '%s'", d_name);
148
149 rval -= d_reclen;
150
151 if (longsyscall)
152 dirp64 = (void*)dirp64 + d_reclen;
153 else
154 dirp = (void*)dirp + d_reclen;
155
156 } while (rval > 0);
157
158 SAFE_CLOSE(cleanup, fd);
159
160 check_flags();
161 }
162
163 free(buf);
164
165 cleanup();
166 tst_exit();
167 }
168
reset_flags(void)169 static void reset_flags(void)
170 {
171 int i;
172
173 for (i = 0; i < ARRAY_SIZE(testcases); i++)
174 testcases[i].found = 0;
175 }
176
check_flags(void)177 static void check_flags(void)
178 {
179 int i, err = 0;
180
181 for (i = 0; i < ARRAY_SIZE(testcases); i++) {
182 if (!testcases[i].found) {
183 tst_resm(TINFO, "Entry '%s' not found", testcases[i].name);
184 err++;
185 }
186 }
187
188 if (err)
189 tst_resm(TFAIL, "Some entires not found");
190 else
191 tst_resm(TPASS, "All entires found");
192 }
193
set_flag(const char * name)194 static void set_flag(const char *name)
195 {
196 int i;
197
198 for (i = 0; i < ARRAY_SIZE(testcases); i++) {
199 if (!strcmp(name, testcases[i].name)) {
200 testcases[i].found = 1;
201 return;
202 }
203 }
204
205 tst_resm(TFAIL, "Unexpected entry '%s' found", name);
206 }
207
setup(void)208 static void setup(void)
209 {
210 int i;
211
212 tst_sig(NOFORK, DEF_HANDLER, cleanup);
213
214 tst_tmpdir();
215
216 for (i = 0; i < ARRAY_SIZE(testcases); i++) {
217
218 if (!testcases[i].create)
219 continue;
220
221 switch (testcases[i].type) {
222 case ENTRY_DIR:
223 SAFE_MKDIR(cleanup, testcases[i].name, 0777);
224 break;
225 case ENTRY_FILE:
226 SAFE_FILE_PRINTF(cleanup, testcases[i].name, " ");
227 break;
228 case ENTRY_SYMLINK:
229 SAFE_SYMLINK(cleanup, "nonexistent", testcases[i].name);
230 break;
231 }
232 }
233
234 TEST_PAUSE;
235 }
236
cleanup(void)237 static void cleanup(void)
238 {
239 tst_rmdir();
240 }
241