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