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