zlook.c revision 9749:105f407a2680
1235783Skib/* 2235783Skib * CDDL HEADER START 3235783Skib * 4235783Skib * The contents of this file are subject to the terms of the 5235783Skib * Common Development and Distribution License (the "License"). 6235783Skib * You may not use this file except in compliance with the License. 7235783Skib * 8235783Skib * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9235783Skib * or http://www.opensolaris.org/os/licensing. 10235783Skib * See the License for the specific language governing permissions 11235783Skib * and limitations under the License. 12235783Skib * 13235783Skib * When distributing Covered Code, include this CDDL HEADER in each 14235783Skib * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15235783Skib * If applicable, add the following below this CDDL HEADER, with the 16235783Skib * fields enclosed by brackets "[]" replaced with your own identifying 17235783Skib * information: Portions Copyright [yyyy] [name of copyright owner] 18235783Skib * 19235783Skib * CDDL HEADER END 20235783Skib */ 21235783Skib 22235783Skib/* 23235783Skib * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24235783Skib * Use is subject to license terms. 25235783Skib */ 26235783Skib 27235783Skib/* 28235783Skib * This is a test program that uses ioctls to the ZFS Unit Test driver 29235783Skib * to perform readdirs or lookups using flags not normally available 30235783Skib * to user-land programs. This allows testing of the flags' 31235783Skib * behavior outside of a complicated consumer, such as the SMB driver. 32235783Skib */ 33235783Skib 34235783Skib#include <stdio.h> 35235783Skib#include <stdlib.h> 36235783Skib#include <unistd.h> 37235783Skib#include <stropts.h> 38235783Skib#include <errno.h> 39235783Skib#include <sys/stat.h> 40235783Skib#include <sys/types.h> 41235783Skib#include <sys/dirent.h> 42235783Skib#include <sys/attr.h> 43235783Skib#include <stddef.h> 44235783Skib#include <fcntl.h> 45235783Skib#include <string.h> 46235783Skib#include <time.h> 47235783Skib 48235783Skib#define _KERNEL 49235783Skib 50235783Skib#include <sys/fs/zut.h> 51235783Skib#include <sys/extdirent.h> 52235783Skib 53235783Skib#undef _KERNEL 54235783Skib 55235783Skib#define MAXBUF (64 * 1024) 56235783Skib#define BIGBUF 4096 57235783Skib#define LILBUF 64 58235783Skib 59235783Skib#define DIRENT_NAMELEN(reclen) \ 60235783Skib ((reclen) - (offsetof(dirent_t, d_name[0]))) 61235783Skib 62235783Skibstatic void 63235783Skibusage(char *pnam) 64235783Skib{ 65235783Skib (void) fprintf(stderr, "Usage:\n %s -l [-is] dir-to-look-in " 66235783Skib "file-in-dir [xfile-on-file]\n", pnam); 67235783Skib (void) fprintf(stderr, " %s -i [-ls] dir-to-look-in " 68235783Skib "file-in-dir [xfile-on-file]\n", pnam); 69235783Skib (void) fprintf(stderr, " %s -s [-il] dir-to-look-in " 70235783Skib "file-in-dir [xfile-on-file]\n", pnam); 71235783Skib (void) fprintf(stderr, "\t Perform a lookup\n"); 72235783Skib (void) fprintf(stderr, "\t -l == lookup\n"); 73235783Skib (void) fprintf(stderr, "\t -i == request FIGNORECASE\n"); 74235783Skib (void) fprintf(stderr, "\t -s == request stat(2) and xvattr info\n"); 75235783Skib (void) fprintf(stderr, " %s -r [-ea] [-b buffer-size-in-bytes] " 76235783Skib "dir-to-look-in [file-in-dir]\n", pnam); 77235783Skib (void) fprintf(stderr, " %s -e [-ra] [-b buffer-size-in-bytes] " 78235783Skib "dir-to-look-in [file-in-dir]\n", pnam); 79235783Skib (void) fprintf(stderr, " %s -a [-re] [-b buffer-size-in-bytes] " 80235783Skib "dir-to-look-in [file-in-dir]\n", pnam); 81235783Skib (void) fprintf(stderr, "\t Perform a readdir\n"); 82235783Skib (void) fprintf(stderr, "\t -r == readdir\n"); 83235783Skib (void) fprintf(stderr, "\t -e == request extended entries\n"); 84235783Skib (void) fprintf(stderr, "\t -a == request access filtering\n"); 85235783Skib (void) fprintf(stderr, "\t -b == buffer size (default 4K)\n"); 86235783Skib (void) fprintf(stderr, " %s -A path\n", pnam); 87235783Skib (void) fprintf(stderr, "\t Look up _PC_ACCESS_FILTERING " 88235783Skib "for path with pathconf(2)\n"); 89235783Skib (void) fprintf(stderr, " %s -E path\n", pnam); 90235783Skib (void) fprintf(stderr, "\t Look up _PC_SATTR_EXISTS " 91235783Skib "for path with pathconf(2)\n"); 92235783Skib (void) fprintf(stderr, " %s -S path\n", pnam); 93235783Skib (void) fprintf(stderr, "\t Look up _PC_SATTR_EXISTS " 94235783Skib "for path with pathconf(2)\n"); 95235783Skib exit(EINVAL); 96235783Skib} 97235783Skib 98235783Skibstatic void 99235783Skibprint_extd_entries(zut_readdir_t *r) 100235783Skib{ 101235783Skib struct edirent *eodp; 102235783Skib char *bufstart; 103235783Skib 104235783Skib eodp = (edirent_t *)(uintptr_t)r->zr_buf; 105235783Skib bufstart = (char *)eodp; 106235783Skib while ((char *)eodp < bufstart + r->zr_bytes) { 107235783Skib char *blanks = " "; 108235783Skib int i = 0; 109235783Skib while (i < EDIRENT_NAMELEN(eodp->ed_reclen)) { 110235783Skib if (!eodp->ed_name[i]) 111235783Skib break; 112235783Skib (void) printf("%c", eodp->ed_name[i++]); 113235783Skib } 114235783Skib if (i < 16) 115235783Skib (void) printf("%.*s", 16 - i, blanks); 116235783Skib (void) printf("\t%x\n", eodp->ed_eflags); 117235783Skib eodp = (edirent_t *)((intptr_t)eodp + eodp->ed_reclen); 118235783Skib } 119235783Skib} 120235783Skib 121235783Skibstatic void 122235783Skibprint_entries(zut_readdir_t *r) 123235783Skib{ 124235783Skib dirent64_t *dp; 125235783Skib char *bufstart; 126235783Skib 127235783Skib dp = (dirent64_t *)r->zr_buf; 128235783Skib bufstart = (char *)dp; 129235783Skib while ((char *)dp < bufstart + r->zr_bytes) { 130235783Skib int i = 0; 131235783Skib while (i < DIRENT_NAMELEN(dp->d_reclen)) { 132235783Skib if (!dp->d_name[i]) 133235783Skib break; 134235783Skib (void) printf("%c", dp->d_name[i++]); 135235783Skib } 136235783Skib (void) printf("\n"); 137235783Skib dp = (dirent64_t *)((intptr_t)dp + dp->d_reclen); 138235783Skib } 139235783Skib} 140235783Skib 141235783Skibstatic void 142235783Skibprint_stats(struct stat64 *sb) 143235783Skib{ 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 172static void 173print_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 199int 200main(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