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 (at) 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 #include <stdio.h> 23 #include <errno.h> 24 #include <sys/types.h> 25 #include <sys/stat.h> 26 #include <fcntl.h> 27 28 #include "test.h" 29 #include "safe_macros.h" 30 #include "getdents.h" 31 32 static void cleanup(void); 33 static void setup(void); 34 35 static void reset_flags(void); 36 static void check_flags(void); 37 static void set_flag(const char *name); 38 39 char *TCID = "getdents01"; 40 int TST_TOTAL = 1; 41 42 static int longsyscall; 43 44 static option_t options[] = { 45 /* -l long option. Tests getdents64 */ 46 {"l", &longsyscall, NULL}, 47 {NULL, NULL, NULL} 48 }; 49 50 static void help(void) 51 { 52 printf(" -l Test the getdents64 system call\n"); 53 } 54 55 enum entry_type { 56 ENTRY_DIR, 57 ENTRY_FILE, 58 ENTRY_SYMLINK, 59 }; 60 61 struct testcase { 62 const char *name; 63 enum entry_type type; 64 int create:1; 65 int found:1; 66 }; 67 68 struct testcase testcases[] = { 69 {.name = ".", .create = 0, .type = ENTRY_DIR}, 70 {.name = "..", .create = 0, .type = ENTRY_DIR}, 71 {.name = "dir", .create = 1, .type = ENTRY_DIR}, 72 {.name = "file", .create = 1, .type = ENTRY_FILE}, 73 {.name = "symlink", .create = 1, .type = ENTRY_SYMLINK}, 74 }; 75 76 /* 77 * Big enough for dirp entires + data, the current size returned 78 * by kernel is 128 bytes. 79 */ 80 #define BUFSIZE 512 81 82 int main(int ac, char **av) 83 { 84 int lc; 85 int rval, fd; 86 struct linux_dirent64 *dirp64; 87 struct linux_dirent *dirp; 88 void *buf; 89 90 tst_parse_opts(ac, av, options, &help); 91 92 /* The buffer is allocated to make sure it's suitably aligned */ 93 buf = malloc(BUFSIZE); 94 95 if (buf == NULL) 96 tst_brkm(TBROK, NULL, "malloc failed"); 97 98 dirp64 = buf; 99 dirp = buf; 100 101 setup(); 102 103 for (lc = 0; TEST_LOOPING(lc); lc++) { 104 const char *d_name; 105 106 tst_count = 0; 107 108 if ((fd = open(".", O_RDONLY)) == -1) 109 tst_brkm(TBROK, cleanup, "open of directory failed"); 110 111 if (longsyscall) 112 rval = getdents64(fd, dirp64, BUFSIZE); 113 else 114 rval = getdents(fd, dirp, BUFSIZE); 115 116 if (rval < 0) { 117 if (errno == ENOSYS) 118 tst_resm(TCONF, "syscall not implemented"); 119 else 120 tst_resm(TFAIL | TERRNO, 121 "getdents failed unexpectedly"); 122 continue; 123 } 124 125 if (rval == 0) { 126 tst_resm(TFAIL, 127 "getdents failed - returned end of directory"); 128 continue; 129 } 130 131 reset_flags(); 132 133 do { 134 size_t d_reclen; 135 136 if (longsyscall) { 137 d_reclen = dirp64->d_reclen; 138 d_name = dirp64->d_name; 139 } else { 140 d_reclen = dirp->d_reclen; 141 d_name = dirp->d_name; 142 } 143 144 set_flag(d_name); 145 146 tst_resm(TINFO, "Found '%s'", d_name); 147 148 rval -= d_reclen; 149 150 if (longsyscall) 151 dirp64 = (void*)dirp64 + d_reclen; 152 else 153 dirp = (void*)dirp + d_reclen; 154 155 } while (rval > 0); 156 157 if (close(fd) == -1) 158 tst_brkm(TBROK | TERRNO, cleanup, "Directory close failed"); 159 160 check_flags(); 161 } 162 163 free(buf); 164 165 cleanup(); 166 tst_exit(); 167 } 168 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 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 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 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 237 static void cleanup(void) 238 { 239 tst_rmdir(); 240 } 241