1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * This is a test program that uses ioctls to the ZFS Unit Test driver 29 * to perform readdirs or lookups using flags not normally available 30 * to user-land programs. This allows testing of the flags' 31 * behavior outside of a complicated consumer, such as the SMB driver. 32 */ 33 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <unistd.h> 37 #include <stropts.h> 38 #include <errno.h> 39 #include <sys/stat.h> 40 #include <sys/types.h> 41 #include <sys/dirent.h> 42 #include <sys/attr.h> 43 #include <stddef.h> 44 #include <fcntl.h> 45 #include <string.h> 46 #include <time.h> 47 48 #define _KERNEL 49 50 #include <sys/fs/zut.h> 51 #include <sys/extdirent.h> 52 53 #undef _KERNEL 54 55 #define MAXBUF (64 * 1024) 56 #define BIGBUF 4096 57 #define LILBUF 64 58 59 #define DIRENT_NAMELEN(reclen) \ 60 ((reclen) - (offsetof(dirent_t, d_name[0]))) 61 62 static void 63 usage(char *pnam) 64 { 65 (void) fprintf(stderr, "Usage:\n %s -l [-is] dir-to-look-in " 66 "file-in-dir [xfile-on-file]\n", pnam); 67 (void) fprintf(stderr, " %s -i [-ls] dir-to-look-in " 68 "file-in-dir [xfile-on-file]\n", pnam); 69 (void) fprintf(stderr, " %s -s [-il] dir-to-look-in " 70 "file-in-dir [xfile-on-file]\n", pnam); 71 (void) fprintf(stderr, "\t Perform a lookup\n"); 72 (void) fprintf(stderr, "\t -l == lookup\n"); 73 (void) fprintf(stderr, "\t -i == request FIGNORECASE\n"); 74 (void) fprintf(stderr, "\t -s == request stat(2) and xvattr info\n"); 75 (void) fprintf(stderr, " %s -r [-ea] [-b buffer-size-in-bytes] " 76 "dir-to-look-in [file-in-dir]\n", pnam); 77 (void) fprintf(stderr, " %s -e [-ra] [-b buffer-size-in-bytes] " 78 "dir-to-look-in [file-in-dir]\n", pnam); 79 (void) fprintf(stderr, " %s -a [-re] [-b buffer-size-in-bytes] " 80 "dir-to-look-in [file-in-dir]\n", pnam); 81 (void) fprintf(stderr, "\t Perform a readdir\n"); 82 (void) fprintf(stderr, "\t -r == readdir\n"); 83 (void) fprintf(stderr, "\t -e == request extended entries\n"); 84 (void) fprintf(stderr, "\t -a == request access filtering\n"); 85 (void) fprintf(stderr, "\t -b == buffer size (default 4K)\n"); 86 (void) fprintf(stderr, " %s -A path\n", pnam); 87 (void) fprintf(stderr, "\t Look up _PC_ACCESS_FILTERING " 88 "for path with pathconf(2)\n"); 89 (void) fprintf(stderr, " %s -E path\n", pnam); 90 (void) fprintf(stderr, "\t Look up _PC_SATTR_EXISTS " 91 "for path with pathconf(2)\n"); 92 (void) fprintf(stderr, " %s -S path\n", pnam); 93 (void) fprintf(stderr, "\t Look up _PC_SATTR_EXISTS " 94 "for path with pathconf(2)\n"); 95 exit(EINVAL); 96 } 97 98 static void 99 print_extd_entries(zut_readdir_t *r) 100 { 101 struct edirent *eodp; 102 char *bufstart; 103 104 eodp = (edirent_t *)(uintptr_t)r->zr_buf; 105 bufstart = (char *)eodp; 106 while ((char *)eodp < bufstart + r->zr_bytes) { 107 char *blanks = " "; 108 int i = 0; 109 while (i < EDIRENT_NAMELEN(eodp->ed_reclen)) { 110 if (!eodp->ed_name[i]) 111 break; 112 (void) printf("%c", eodp->ed_name[i++]); 113 } 114 if (i < 16) 115 (void) printf("%.*s", 16 - i, blanks); 116 (void) printf("\t%x\n", eodp->ed_eflags); 117 eodp = (edirent_t *)((intptr_t)eodp + eodp->ed_reclen); 118 } 119 } 120 121 static void 122 print_entries(zut_readdir_t *r) 123 { 124 dirent64_t *dp; 125 char *bufstart; 126 127 dp = (dirent64_t *)r->zr_buf; 128 bufstart = (char *)dp; 129 while ((char *)dp < bufstart + r->zr_bytes) { 130 int i = 0; 131 while (i < DIRENT_NAMELEN(dp->d_reclen)) { 132 if (!dp->d_name[i]) 133 break; 134 (void) printf("%c", dp->d_name[i++]); 135 } 136 (void) printf("\n"); 137 dp = (dirent64_t *)((intptr_t)dp + dp->d_reclen); 138 } 139 } 140 141 static void 142 print_stats(struct stat64 *sb) 143 { 144 char timebuf[512]; 145 146 (void) printf("st_mode\t\t\t%04lo\n", (unsigned long)sb->st_mode); 147 (void) printf("st_ino\t\t\t%llu\n", (unsigned long long)sb->st_ino); 148 (void) printf("st_nlink\t\t%lu\n", (unsigned long)sb->st_nlink); 149 (void) printf("st_uid\t\t\t%d\n", sb->st_uid); 150 (void) printf("st_gid\t\t\t%d\n", sb->st_gid); 151 (void) printf("st_size\t\t\t%lld\n", (long long)sb->st_size); 152 (void) printf("st_blksize\t\t%ld\n", (long)sb->st_blksize); 153 (void) printf("st_blocks\t\t%lld\n", (long long)sb->st_blocks); 154 155 timebuf[0] = 0; 156 if (ctime_r(&sb->st_atime, timebuf, 512)) { 157 (void) printf("st_atime\t\t"); 158 (void) printf("%s", timebuf); 159 } 160 timebuf[0] = 0; 161 if (ctime_r(&sb->st_mtime, timebuf, 512)) { 162 (void) printf("st_mtime\t\t"); 163 (void) printf("%s", timebuf); 164 } 165 timebuf[0] = 0; 166 if (ctime_r(&sb->st_ctime, timebuf, 512)) { 167 (void) printf("st_ctime\t\t"); 168 (void) printf("%s", timebuf); 169 } 170 } 171 172 static void 173 print_xvs(uint64_t xvs) 174 { 175 uint_t bits; 176 int idx = 0; 177 178 if (xvs == 0) 179 return; 180 181 (void) printf("-------------------\n"); 182 (void) printf("Attribute bit(s) set:\n"); 183 (void) printf("-------------------\n"); 184 185 bits = xvs & ((1 << F_ATTR_ALL) - 1); 186 while (bits) { 187 uint_t rest = bits >> 1; 188 if (bits & 1) { 189 (void) printf("%s", attr_to_name((f_attr_t)idx)); 190 if (rest) 191 (void) printf(", "); 192 } 193 idx++; 194 bits = rest; 195 } 196 (void) printf("\n"); 197 } 198 199 int 200 main(int argc, char **argv) 201 { 202 zut_lookup_t lk = {0}; 203 zut_readdir_t rd = {0}; 204 boolean_t checking = B_FALSE; 205 boolean_t looking = B_FALSE; 206 boolean_t reading = B_FALSE; 207 boolean_t bflag = B_FALSE; 208 long rddir_bufsize = BIGBUF; 209 int error = 0; 210 int check; 211 int fd; 212 int c; 213 214 while ((c = getopt(argc, argv, "lisaerb:ASE")) != -1) { 215 switch (c) { 216 case 'l': 217 looking = B_TRUE; 218 break; 219 case 'i': 220 lk.zl_reqflags |= ZUT_IGNORECASE; 221 looking = B_TRUE; 222 break; 223 case 's': 224 lk.zl_reqflags |= ZUT_GETSTAT; 225 looking = B_TRUE; 226 break; 227 case 'a': 228 rd.zr_reqflags |= ZUT_ACCFILTER; 229 reading = B_TRUE; 230 break; 231 case 'e': 232 rd.zr_reqflags |= ZUT_EXTRDDIR; 233 reading = B_TRUE; 234 break; 235 case 'r': 236 reading = B_TRUE; 237 break; 238 case 'b': 239 reading = B_TRUE; 240 bflag = B_TRUE; 241 rddir_bufsize = strtol(optarg, NULL, 0); 242 break; 243 case 'A': 244 checking = B_TRUE; 245 check = _PC_ACCESS_FILTERING; 246 break; 247 case 'S': 248 checking = B_TRUE; 249 check = _PC_SATTR_ENABLED; 250 break; 251 case 'E': 252 checking = B_TRUE; 253 check = _PC_SATTR_EXISTS; 254 break; 255 case '?': 256 default: 257 usage(argv[0]); /* no return */ 258 } 259 } 260 261 if ((checking && looking) || (checking && reading) || 262 (looking && reading) || (!reading && bflag) || 263 (!checking && !reading && !looking)) 264 usage(argv[0]); /* no return */ 265 266 if (rddir_bufsize < LILBUF || rddir_bufsize > MAXBUF) { 267 (void) fprintf(stderr, "Sorry, buffer size " 268 "must be >= %d and less than or equal to %d bytes.\n", 269 LILBUF, MAXBUF); 270 exit(EINVAL); 271 } 272 273 if (checking) { 274 char pathbuf[MAXPATHLEN]; 275 long result; 276 277 if (argc - optind < 1) 278 usage(argv[0]); /* no return */ 279 (void) strlcpy(pathbuf, argv[optind], MAXPATHLEN); 280 result = pathconf(pathbuf, check); 281 (void) printf("pathconf(2) check for %s\n", pathbuf); 282 switch (check) { 283 case _PC_SATTR_ENABLED: 284 (void) printf("System attributes "); 285 if (result != 0) 286 (void) printf("Enabled\n"); 287 else 288 (void) printf("Not enabled\n"); 289 break; 290 case _PC_SATTR_EXISTS: 291 (void) printf("System attributes "); 292 if (result != 0) 293 (void) printf("Exist\n"); 294 else 295 (void) printf("Do not exist\n"); 296 break; 297 case _PC_ACCESS_FILTERING: 298 (void) printf("Access filtering "); 299 if (result != 0) 300 (void) printf("Available\n"); 301 else 302 (void) printf("Not available\n"); 303 break; 304 } 305 return (result); 306 } 307 308 if ((fd = open(ZUT_DEV, O_RDONLY)) < 0) { 309 perror(ZUT_DEV); 310 return (ENXIO); 311 } 312 313 if (reading) { 314 char *buf; 315 316 if (argc - optind < 1) 317 usage(argv[0]); /* no return */ 318 319 (void) strlcpy(rd.zr_dir, argv[optind], MAXPATHLEN); 320 if (argc - optind > 1) { 321 (void) strlcpy(rd.zr_file, argv[optind + 1], 322 MAXNAMELEN); 323 rd.zr_reqflags |= ZUT_XATTR; 324 } 325 326 if ((buf = malloc(rddir_bufsize)) == NULL) { 327 error = errno; 328 perror("malloc"); 329 (void) close(fd); 330 return (error); 331 } 332 333 rd.zr_buf = (uint64_t)(uintptr_t)buf; 334 rd.zr_buflen = rddir_bufsize; 335 336 while (!rd.zr_eof) { 337 int ierr; 338 339 if ((ierr = ioctl(fd, ZUT_IOC_READDIR, &rd)) != 0) { 340 (void) fprintf(stderr, 341 "IOCTL error: %s (%d)\n", 342 strerror(ierr), ierr); 343 free(buf); 344 (void) close(fd); 345 return (ierr); 346 } 347 if (rd.zr_retcode) { 348 (void) fprintf(stderr, 349 "readdir result: %s (%d)\n", 350 strerror(rd.zr_retcode), rd.zr_retcode); 351 free(buf); 352 (void) close(fd); 353 return (rd.zr_retcode); 354 } 355 if (rd.zr_reqflags & ZUT_EXTRDDIR) 356 print_extd_entries(&rd); 357 else 358 print_entries(&rd); 359 } 360 free(buf); 361 } else { 362 int ierr; 363 364 if (argc - optind < 2) 365 usage(argv[0]); /* no return */ 366 367 (void) strlcpy(lk.zl_dir, argv[optind], MAXPATHLEN); 368 (void) strlcpy(lk.zl_file, argv[optind + 1], MAXNAMELEN); 369 if (argc - optind > 2) { 370 (void) strlcpy(lk.zl_xfile, 371 argv[optind + 2], MAXNAMELEN); 372 lk.zl_reqflags |= ZUT_XATTR; 373 } 374 375 if ((ierr = ioctl(fd, ZUT_IOC_LOOKUP, &lk)) != 0) { 376 (void) fprintf(stderr, 377 "IOCTL error: %s (%d)\n", 378 strerror(ierr), ierr); 379 (void) close(fd); 380 return (ierr); 381 } 382 383 (void) printf("\nLookup of "); 384 if (lk.zl_reqflags & ZUT_XATTR) { 385 (void) printf("extended attribute \"%s\" of ", 386 lk.zl_xfile); 387 } 388 (void) printf("file \"%s\" ", lk.zl_file); 389 (void) printf("in directory \"%s\" ", lk.zl_dir); 390 if (lk.zl_retcode) { 391 (void) printf("failed: %s (%d)\n", 392 strerror(lk.zl_retcode), lk.zl_retcode); 393 (void) close(fd); 394 return (lk.zl_retcode); 395 } 396 397 (void) printf("succeeded.\n"); 398 if (lk.zl_reqflags & ZUT_IGNORECASE) { 399 (void) printf("----------------------------\n"); 400 (void) printf("dirent flags: 0x%0x\n", lk.zl_deflags); 401 (void) printf("real name: %s\n", lk.zl_real); 402 } 403 if (lk.zl_reqflags & ZUT_GETSTAT) { 404 (void) printf("----------------------------\n"); 405 print_stats(&lk.zl_statbuf); 406 print_xvs(lk.zl_xvattrs); 407 } 408 } 409 410 (void) close(fd); 411 return (0); 412 } 413