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