xref: /titanic_41/usr/src/cmd/zevadm/zevadm.c (revision 4526c1a75b3bdab802592cc2c97e78323086bf0f)
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <stdlib.h>
4 #include <fcntl.h>
5 #include <stropts.h>
6 #include <poll.h>
7 #include <string.h>
8 #include <sys/fs/zev.h>
9 #include <errno.h>
10 #include <sys/sysmacros.h>
11 #include <stdarg.h>
12 #include <sys/avl.h>
13 #include <sys/stat.h>
14 
15 #define ZEV_DEVICE "/devices/pseudo/zev@0:ctrl"
16 
17 #if !defined(offsetof)
18 #define	offsetof(s, m)	((size_t)(&(((s *)0)->m)))
19 #endif
20 
21 static char *zev_device = ZEV_DEVICE;
22 static int do_flush = 0;
23 
24 static char *zev_op_name[] = {
25 	"ERROR",
26 	"MARK",
27 	"ZFS_MOUNT",
28 	"ZFS_UMOUNT",
29 	"ZVOL_WRITE",
30 	"ZVOL_TRUNCATE",
31 	"ZNODE_CLOSE_AFTER_UPDATE",
32 	"ZNODE_CREATE",
33 	"ZNODE_MKDIR",
34 	"ZNODE_MAKE_XATTR_DIR",
35 	"ZNODE_REMOVE",
36 	"ZNODE_RMDIR",
37 	"ZNODE_LINK",
38 	"ZNODE_SYMLINK",
39 	"ZNODE_RENAME",
40 	"ZNODE_WRITE",
41 	"ZNODE_TRUNCATE",
42 	"ZNODE_SETATTR",
43 	"ZNODE_ACL",
44 	NULL
45 };
46 
47 #define MD_STATISTICS			1
48 #define MD_POLL_EVENTS			2
49 #define MD_CHECKSUMS			3
50 #define MD_DEBUG_INFO			4
51 #define MD_LIST_QUEUES			5
52 #define MD_SET_GLOBAL_MAX_QUEUE_LEN	6
53 #define MD_SET_MAX_QUEUE_LEN		7
54 #define MD_SET_POLL_WAKEUP_QUEUE_LEN	8
55 #define MD_MUTE_POOL			9
56 #define MD_UNMUTE_POOL			10
57 #define MD_MARK				11
58 #define MD_ADD_QUEUE			12
59 #define MD_ADD_BLOCKING_QUEUE		13
60 #define MD_REMOVE_QUEUE			14
61 #define MD_QUEUE_BLOCKING		15
62 #define MD_QUEUE_NONBLOCKING		16
63 #define MD_QUEUE_PROPERTIES		17
64 #define MD_ZEVSTAT			18
65 #define MD_ZEV_REPORT			19
66 #define MD_DUMP_SPOOL			20
67 #define MD_GET_ZEV_VERSION		21
68 
69 static int verbose = 0;
70 static int grep_friendly = 0;
71 
72 static void
73 zpf(char *fmt, ...)
74 {
75 	va_list	ap;
76 
77 	va_start(ap, fmt);
78 	vprintf(fmt, ap);
79 	va_end(ap);
80 	if (grep_friendly) {
81 		printf(" ");
82 	} else {
83 		printf("\n");
84 	}
85 }
86 
87 static void
88 znl(void)
89 {
90 	if (grep_friendly)
91 		printf("\n");
92 }
93 
94 static void
95 sig2hex_direct(const uint8_t *sig, char *hex)
96 {
97 	int     i;
98 
99 	for (i = 0; i < SHA1_DIGEST_LENGTH; ++i) {
100 		sprintf(hex + 2 * i, "%02x", sig[i]);
101 	}
102 	hex[SHA1_DIGEST_LENGTH * 2] = '\0';
103 }
104 
105 static int
106 zev_statistics(int fd)
107 {
108 	zev_statistics_t zs;
109 	if (ioctl(fd, ZEV_IOC_GET_GLOBAL_STATISTICS, &zs)) {
110 		perror("getting statistics data failed");
111 		return (EXIT_FAILURE);
112 	}
113 	printf("ZEV module state:\n");
114 
115 	printf("    queue length in bytes   : %lu\n", zs.zev_queue_len);
116 	printf("    queue length limit      : %lu\n", zs.zev_max_queue_len);
117 	printf("    bytes read from device  : %lu\n", zs.zev_bytes_read);
118 	printf("    module internal errors  : %lu\n\n", zs.zev_cnt_errors);
119 
120 	printf("    discarded events        : %lu\n",
121 	    zs.zev_cnt_discarded_events);
122 	printf("    discarded bytes         : %lu\n\n", zs.zev_bytes_discarded);
123 
124 	printf("ZFS event statistics:\n");
125 
126 	printf("    total ZFS events        : %lu\n", zs.zev_cnt_total_events);
127 	printf("    ZFS mount               : %lu\n", zs.zev_cnt_zfs_mount);
128 	printf("    ZFS umount              : %lu\n", zs.zev_cnt_zfs_umount);
129 	printf("    ZVOL write              : %lu\n", zs.zev_cnt_zvol_write);
130 	printf("    ZVOL truncate           : %lu\n", zs.zev_cnt_zvol_truncate);
131 	printf("    ZNODE close after update: %lu\n",
132 	    zs.zev_cnt_znode_close_after_update);
133 	printf("    ZNODE create            : %lu\n", zs.zev_cnt_znode_create);
134 	printf("    ZNODE remove            : %lu\n", zs.zev_cnt_znode_remove);
135 	printf("    ZNODE link              : %lu\n", zs.zev_cnt_znode_link);
136 	printf("    ZNODE symlink           : %lu\n", zs.zev_cnt_znode_symlink);
137 	printf("    ZNODE rename            : %lu\n", zs.zev_cnt_znode_rename);
138 	printf("    ZNODE write             : %lu\n", zs.zev_cnt_znode_write);
139 	printf("    ZNODE truncate          : %lu\n",
140 	    zs.zev_cnt_znode_truncate);
141 	printf("    ZNODE setattr           : %lu\n", zs.zev_cnt_znode_setattr);
142 	printf("    ZNODE acl               : %lu\n", zs.zev_cnt_znode_acl);
143 	return EXIT_SUCCESS;
144 }
145 
146 static void
147 zev_print_inode_info(char *name, zev_inode_info_t *info)
148 {
149 	zpf("  %s.inode: %llu", name, info->ino);
150 	zpf("  %s.gen: %llu", name, info->gen);
151 	zpf("  %s.mtime: %llu", name, info->mtime);
152 	zpf("  %s.ctime: %llu", name, info->ctime);
153 	zpf("  %s.size: %llu", name, info->size);
154 	zpf("  %s.mode: %llo", name, info->mode);
155 	zpf("  %s.links: %llu", name, info->links);
156 	zpf("  %s.type: %lu", name, info->type);
157 	zpf("  %s.flags: %lu", name, info->flags);
158 }
159 
160 static void
161 zev_print_mark_payload(zev_mark_t *rec)
162 {
163 	int i;
164 	int j;
165 	uint8_t *p;
166 	char c;
167 
168 	zpf("  payload:");
169 	p = (uint8_t *)ZEV_PAYLOAD(rec);
170 	for (i=0; i<rec->payload_len; i+=16) {
171 		printf("  ");
172 		for (j=i; j<rec->payload_len && j<i+16; j++) {
173 			printf("%02x ", p[j]);
174 			if (j == i + 7)
175 				printf(" ");
176 		}
177 		if (grep_friendly)
178 			continue;
179 		for (; j<i+16; j++) {
180 			printf("   ");
181 			if (j == i + 7)
182 				printf(" ");
183 		}
184 		printf("    ");
185 		for (j=i; j<rec->payload_len && j<i+16; j++) {
186 			c = '.';
187 			if (p[j] >= ' ' && p[j] <= '~')
188 				c = p[j];
189 			printf("%c", c);
190 			if (j == i + 7)
191 				printf(" ");
192 		}
193 		printf("\n");
194 	}
195 }
196 
197 static void
198 zev_print_error(char *buf)
199 {
200 	zev_error_t *rec = (zev_error_t *)buf;
201 	time_t op_time = rec->op_time;
202 	char *ct = ctime(&op_time); ct[24] = '\0';
203 
204 	if (verbose) {
205 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
206 		zpf("  guid: %llu", rec->guid);
207 		zpf("  failed.op: %s",
208 		    zev_op_name[rec->failed_op - ZEV_OP_MIN]);
209 		zpf("  message: %s", ZEV_ERRSTR(rec));
210 		znl();
211 	} else {
212 		printf("%s %s: failed_op=%s msg=%s\n",
213 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
214 		       zev_op_name[rec->failed_op - ZEV_OP_MIN],
215 		       ZEV_ERRSTR(rec));
216 	}
217 }
218 
219 static void
220 zev_print_mark(char *buf)
221 {
222 	zev_mark_t *rec = (zev_mark_t *)buf;
223 	time_t op_time = rec->op_time;
224 	char *ct = ctime(&op_time); ct[24] = '\0';
225 
226 	if (verbose) {
227 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
228 		zpf("  guid: %llu", rec->guid);
229 		zpf("  mark.id: %llu", rec->mark_id);
230 		zpf("  payload.len: %llu", rec->payload_len);
231 		if (rec->payload_len)
232 			zev_print_mark_payload(rec);
233 		znl();
234 	} else {
235 		printf("%s %s: guid=%llu mark_id=%lld payload_len=%ld "
236 		       "payload=\"%.*s\"\n",
237 		       ct, zev_op_name[rec->op - ZEV_OP_MIN], rec->guid,
238 		       rec->mark_id, rec->payload_len,
239 		       rec->payload_len, (char *)(rec + 1));
240 	}
241 }
242 
243 static void
244 zev_print_zfs_mount(char *buf)
245 {
246 	zev_zfs_mount_t *rec = (zev_zfs_mount_t *)buf;
247 	time_t op_time = rec->op_time;
248 	char *ct = ctime(&op_time); ct[24] = '\0';
249 
250 	if (verbose) {
251 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
252 		zpf("  guid: %llu", rec->guid);
253 		zpf("  txg: %llu", rec->txg);
254 		zpf("  dataset: %s", ZEV_DATASET(rec));
255 		zpf("  mountpoint: %s", ZEV_MOUNTPOINT(rec));
256 		zpf("  remount: %s", rec->remount ? "true" : "false");
257 		zev_print_inode_info("root", &rec->root);
258 		znl();
259 	} else {
260 		printf("%s %s: guid=%llu remount=%s dataset='%s' "
261 		       "mountpoint='%s'\n",
262 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
263 		       rec->guid,
264 		       rec->remount ? "true" : "false",
265 		       ZEV_DATASET(rec),
266 		       ZEV_MOUNTPOINT(rec));
267 	}
268 }
269 
270 static void
271 zev_print_zfs_umount(char *buf)
272 {
273 	zev_zfs_umount_t *rec = (zev_zfs_umount_t *)buf;
274 	time_t op_time = rec->op_time;
275 	char *ct = ctime(&op_time); ct[24] = '\0';
276 
277 	if (verbose) {
278 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
279 		zpf("  guid: %llu", rec->guid);
280 		zpf("  txg: %llu", rec->txg);
281 		zev_print_inode_info("covered", &rec->covered);
282 		znl();
283 	} else {
284 		printf("%s %s: guid=%llu\n",
285 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
286 		       rec->guid);
287 	}
288 }
289 
290 static void
291 zev_print_zvol_truncate(char *buf)
292 {
293 	zev_zvol_truncate_t *rec = (zev_zvol_truncate_t *)buf;
294 	time_t op_time = rec->op_time;
295 	char *ct = ctime(&op_time); ct[24] = '\0';
296 
297 	if (verbose) {
298 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
299 		zpf("  guid: %llu", rec->guid);
300 		zpf("  txg: %llu", rec->txg);
301 		zpf("  offset: %llu", rec->offset);
302 		zpf("  length: %llu", rec->length);
303 		znl();
304 	} else {
305 		printf("%s %s: guid=%llu offset=%llu length=%llu\n",
306 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
307 		       rec->guid,
308 		       rec->offset,
309 		       rec->length);
310 	}
311 }
312 
313 static void
314 zev_print_zvol_write(char *buf)
315 {
316 	zev_print_zvol_truncate(buf);
317 }
318 
319 static void
320 zev_print_znode_close_after_update(char *buf)
321 {
322 	zev_znode_close_after_update_t *rec =
323 	    (zev_znode_close_after_update_t *)buf;
324 	time_t op_time = rec->op_time;
325 	char *ct = ctime(&op_time); ct[24] = '\0';
326 
327 	if (verbose) {
328 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
329 		zpf("  guid: %llu", rec->guid);
330 		zev_print_inode_info("file", &rec->file);
331 		znl();
332 	} else {
333 		printf("%s %s: guid=%llu file=%llu.%llu\n",
334 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
335 		       rec->guid,
336 		       rec->file.ino, rec->file.gen);
337 	}
338 }
339 
340 static void
341 zev_print_znode_create(char *buf)
342 {
343 	zev_znode_create_t *rec = (zev_znode_create_t *)buf;
344 	time_t op_time = rec->op_time;
345 	char *ct = ctime(&op_time); ct[24] = '\0';
346 	zev_sig_t *sig;
347 	char sigval[(SHA1_DIGEST_LENGTH * 2) + 1];
348 
349 	if (verbose) {
350 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
351 		zpf("  guid: %llu", rec->guid);
352 		zpf("  txg: %llu", rec->txg);
353 		zpf("  name: '%s'", ZEV_NAME(rec));
354 		sig = &rec->signature;
355 		sig2hex_direct(sig->value, sigval);
356 		zpf("  sig: level %d, offset %llu, value %s",
357 		    sig->level, sig->block_offset, sigval);
358 		zev_print_inode_info("file", &rec->file);
359 		zev_print_inode_info("parent", &rec->parent);
360 		znl();
361 	} else {
362 		printf("%s %s: guid=%llu parent=%llu.%llu file=%llu.%llu "
363 		       "file.mtime=%llu, parent.mtime=%llu, name='%s'\n",
364 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
365 		       rec->guid,
366 		       rec->parent.ino, rec->parent.gen,
367 		       rec->file.ino, rec->file.gen,
368 		       rec->file.mtime, rec->parent.mtime,
369 		       ZEV_NAME(rec));
370 	}
371 }
372 
373 static void
374 zev_print_znode_mkdir(char *buf)
375 {
376 	zev_print_znode_create(buf);
377 }
378 
379 static void
380 zev_print_znode_make_xattr_dir(char *buf)
381 {
382 	zev_print_znode_create(buf);
383 }
384 
385 static void
386 zev_print_znode_remove(char *buf)
387 {
388 	zev_znode_remove_t *rec = (zev_znode_remove_t *)buf;
389 	time_t op_time = rec->op_time;
390 	char *ct = ctime(&op_time); ct[24] = '\0';
391 
392 	if (verbose) {
393 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
394 		zpf("  guid: %llu", rec->guid);
395 		zpf("  txg: %llu", rec->txg);
396 		zpf("  file.name: '%s'", ZEV_NAME(rec));
397 		zev_print_inode_info("file", &rec->file);
398 		zev_print_inode_info("parent", &rec->parent);
399 		znl();
400 	} else {
401 		printf("%s %s: guid=%llu parent=%llu.%llu "
402 		       "file.mtime=%llu name='%s'\n",
403 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
404 		       rec->guid,
405 		       rec->parent.ino, rec->parent.gen,
406 		       rec->file.mtime,
407 		       ZEV_NAME(rec));
408 	}
409 }
410 
411 static void
412 zev_print_znode_rmdir(char *buf)
413 {
414 	zev_print_znode_remove(buf);
415 }
416 
417 static void
418 zev_print_znode_link(char *buf)
419 {
420 	zev_znode_link_t *rec = (zev_znode_link_t *)buf;
421 	time_t op_time = rec->op_time;
422 	char *ct = ctime(&op_time); ct[24] = '\0';
423 
424 	if (verbose) {
425 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
426 		zpf("  guid: %llu", rec->guid);
427 		zpf("  txg: %llu", rec->txg);
428 		zpf("  link.name: '%s'", ZEV_NAME(rec));
429 		zev_print_inode_info("file", &rec->file);
430 		zev_print_inode_info("parent", &rec->parent);
431 		znl();
432 	} else {
433 		printf("%s %s: parent=%llu.%llu file=%llu.%llu "
434 		       "file.ctime=%llu parent.ctime=%llu name='%s'\n",
435 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
436 		       rec->parent.ino, rec->parent.gen,
437 		       rec->file.ino, rec->file.gen,
438 		       rec->file.ctime, rec->parent.ctime,
439 		       ZEV_NAME(rec));
440 	}
441 }
442 
443 static void
444 zev_print_znode_symlink(char *buf)
445 {
446 	zev_znode_symlink_t *rec = (zev_znode_symlink_t *)buf;
447 	time_t op_time = rec->op_time;
448 	char *ct = ctime(&op_time); ct[24] = '\0';
449 	zev_sig_t *sig;
450 	char sigval[(SHA1_DIGEST_LENGTH * 2) + 1];
451 
452 	if (verbose) {
453 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
454 		zpf("  guid: %llu", rec->guid);
455 		zpf("  txg: %llu", rec->txg);
456 		zpf("  symlink.name: '%s'", ZEV_NAME(rec));
457 		zpf("  symlink.link: '%s'", ZEV_LINK(rec));
458 		sig = &rec->signature;
459 		sig2hex_direct(sig->value, sigval);
460 		zpf("  sig: level %d, offset %llu, value %s",
461 		    sig->level, sig->block_offset, sigval);
462 		zev_print_inode_info("file", &rec->file);
463 		zev_print_inode_info("parent", &rec->parent);
464 		znl();
465 	} else {
466 		printf("%s %s: parent=%llu.%llu file=%llu.%llu "
467 		       "name='%s' link='%s'\n",
468 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
469 		       rec->parent.ino, rec->parent.gen,
470 		       rec->file.ino, rec->file.gen,
471 		       ZEV_NAME(rec),
472 		       ZEV_LINK(rec));
473 	}
474 }
475 
476 static void
477 zev_print_znode_rename(char *buf)
478 {
479 	zev_znode_rename_t *rec = (zev_znode_rename_t *)buf;
480 	time_t op_time = rec->op_time;
481 	char *ct = ctime(&op_time); ct[24] = '\0';
482 
483 	if (verbose) {
484 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
485 		zpf("  guid: %llu", rec->guid);
486 		zpf("  txg: %llu", rec->txg);
487 		zpf("  file.srcname: '%s'", ZEV_SRCNAME(rec));
488 		zpf("  file.dstname: '%s'", ZEV_DSTNAME(rec));
489 		zev_print_inode_info("file", &rec->file);
490 		if (rec->clobbered_file.ino)
491 			zev_print_inode_info("clobbered_file",
492 			                     &rec->clobbered_file);
493 		zev_print_inode_info("srcdir", &rec->srcdir);
494 		zev_print_inode_info("dstdir", &rec->dstdir);
495 		znl();
496 	} else {
497 		printf("%s %s: srcdir=%llu.%llu dstdir=%llu.%llu "
498 		       "file=%llu.%llu file.mtime=%llu, file.ctime=%llu, "
499 		       "srcdir.mtime=%llu, srcdir.ctime=%llu, "
500 		       "dstdir.mtime=%llu, dstdir.ctime=%llu, "
501 		       "srcname='%s' dstname='%s'\n",
502 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
503 		       rec->srcdir.ino, rec->srcdir.gen,
504 		       rec->dstdir.ino, rec->dstdir.gen,
505 		       rec->file.ino, rec->file.gen,
506 		       rec->file.mtime, rec->file.ctime,
507 		       rec->srcdir.mtime, rec->srcdir.ctime,
508 		       rec->dstdir.mtime, rec->dstdir.ctime,
509 		       ZEV_SRCNAME(rec),
510 		       ZEV_DSTNAME(rec));
511 	}
512 }
513 
514 static void
515 zev_print_znode_write(char *buf)
516 {
517 	zev_znode_write_t *rec = (zev_znode_write_t *)buf;
518 	time_t op_time = rec->op_time;
519 	char *ct = ctime(&op_time); ct[24] = '\0';
520 	zev_sig_t *sig;
521 	char sigval[(SHA1_DIGEST_LENGTH * 2) + 1];
522 	int i;
523 
524 	if (verbose) {
525 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
526 		zpf("  guid: %llu", rec->guid);
527 		zpf("  txg: %llu", rec->txg);
528 		zpf("  offset: %llu", rec->offset);
529 		zpf("  length: %llu", rec->length);
530 		zev_print_inode_info("file", &rec->file);
531 		znl();
532 		for (i=0; i<rec->signature_cnt; i++) {
533 			sig = (zev_sig_t *)ZEV_SIGNATURES(rec);
534 			sig += i;
535 			sig2hex_direct(sig->value, sigval);
536 			zpf("  sig: level %d, offset %llu, value %s",
537 			    sig->level, sig->block_offset, sigval);
538 		}
539 	} else {
540 		printf("%s %s: file=%llu.%llu offset=%llu length=%llu\n",
541 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
542 		       rec->file.ino, rec->file.gen,
543 		       rec->offset, rec->length);
544 	}
545 }
546 
547 static void
548 zev_print_znode_truncate(char *buf)
549 {
550 	zev_print_znode_write(buf);
551 }
552 
553 static void
554 zev_print_znode_setattr(char *buf)
555 {
556 	zev_znode_setattr_t *rec = (zev_znode_setattr_t *)buf;
557 	time_t op_time = rec->op_time;
558 	char *ct = ctime(&op_time); ct[24] = '\0';
559 
560 	if (verbose) {
561 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
562 		zpf("  guid: %llu", rec->guid);
563 		zpf("  txg: %llu", rec->txg);
564 		zev_print_inode_info("file", &rec->file);
565 		znl();
566 	} else {
567 		printf("%s %s: file=%llu.%llu mtime=%llu\n",
568 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
569 		       rec->file.ino, rec->file.gen, rec->file.mtime);
570 	}
571 }
572 
573 static void
574 zev_print_znode_acl(char *buf)
575 {
576 	zev_print_znode_setattr(buf);
577 }
578 
579 static void
580 zev_print_event(char *buf, int len)
581 {
582 	int record_len;
583 	int op;
584 
585 	record_len = *(uint32_t *)buf;
586 	if (record_len != len) {
587 		fprintf(stderr, "record length mismatch: got %d, expected %d\n",
588 		        record_len, len);
589 		exit(1);
590 	}
591 	op = *((uint32_t *)buf + 1);
592 	if (op < ZEV_OP_MIN || op > ZEV_OP_MAX) {
593 		fprintf(stderr, "unknown op code: %d\n", op);
594 		exit(1);
595 	}
596 	switch (op) {
597 	case ZEV_OP_ERROR:
598 		zev_print_error(buf);
599 		break;
600 	case ZEV_OP_MARK:
601 		zev_print_mark(buf);
602 		break;
603 	case ZEV_OP_ZFS_MOUNT:
604 		zev_print_zfs_mount(buf);
605 		break;
606 	case ZEV_OP_ZFS_UMOUNT:
607 		zev_print_zfs_umount(buf);
608 		break;
609 	case ZEV_OP_ZVOL_TRUNCATE:
610 		zev_print_zvol_truncate(buf);
611 		break;
612 	case ZEV_OP_ZVOL_WRITE:
613 		zev_print_zvol_write(buf);
614 		break;
615 	case ZEV_OP_ZNODE_CLOSE_AFTER_UPDATE:
616 		zev_print_znode_close_after_update(buf);
617 		break;
618 	case ZEV_OP_ZNODE_CREATE:
619 		zev_print_znode_create(buf);
620 		break;
621 	case ZEV_OP_ZNODE_MKDIR:
622 		zev_print_znode_mkdir(buf);
623 		break;
624 	case ZEV_OP_ZNODE_MAKE_XATTR_DIR:
625 		zev_print_znode_make_xattr_dir(buf);
626 		break;
627 	case ZEV_OP_ZNODE_REMOVE:
628 		zev_print_znode_remove(buf);
629 		break;
630 	case ZEV_OP_ZNODE_RMDIR:
631 		zev_print_znode_rmdir(buf);
632 		break;
633 	case ZEV_OP_ZNODE_LINK:
634 		zev_print_znode_link(buf);
635 		break;
636 	case ZEV_OP_ZNODE_SYMLINK:
637 		zev_print_znode_symlink(buf);
638 		break;
639 	case ZEV_OP_ZNODE_RENAME:
640 		zev_print_znode_rename(buf);
641 		break;
642 	case ZEV_OP_ZNODE_WRITE:
643 		zev_print_znode_write(buf);
644 		break;
645 	case ZEV_OP_ZNODE_TRUNCATE:
646 		zev_print_znode_truncate(buf);
647 		break;
648 	case ZEV_OP_ZNODE_SETATTR:
649 		zev_print_znode_setattr(buf);
650 		break;
651 	case ZEV_OP_ZNODE_ACL:
652 		zev_print_znode_acl(buf);
653 		break;
654 	default:
655 		fprintf(stderr, "unhandled op code: %d\n", op);
656 		exit(1);
657 	}
658 	if (do_flush)
659 		fflush(stdout);
660 }
661 
662 static int
663 zev_poll_events(int fd, int create_tmp_queue)
664 {
665 	struct pollfd pfd[1];
666 	int ret;
667 	char buf[4096];
668 	zev_event_t *ev;
669 	int off = 0;
670 	int q_fd;
671 
672 	if (create_tmp_queue) {
673 		snprintf(buf, sizeof(buf),
674 		         "/devices/pseudo/zev@0:%s", ZEV_TMPQUEUE_DEVICE_NAME);
675 		q_fd = open(buf, O_RDONLY);
676 		if (q_fd < 0) {
677 			perror("opening queue device failed");
678 			return (EXIT_FAILURE);
679 		}
680 	} else {
681 		q_fd = fd;
682 	}
683 
684 	while (1) {
685 		pfd[0].fd = q_fd;
686 		pfd[0].events = POLLIN;
687 		ret = poll(pfd, 1, 1000);
688 		if (ret < 0) {
689 			perror("poll failed");
690 			close(q_fd);
691 			return(EXIT_FAILURE);
692 		}
693 		if (!(pfd[0].revents & POLLIN))
694 			continue;
695 		/* data available */
696 		ret = read(q_fd, buf, sizeof(buf));
697 		if (ret < 0) {
698 			perror("read failed");
699 			close(q_fd);
700 			return(EXIT_FAILURE);
701 		}
702 		if (ret == 0)
703 			continue;
704 		while (ret > off) {
705 			ev = (zev_event_t *)(buf + off);
706 			zev_print_event(buf + off, ev->header.record_len);
707 			off += ev->header.record_len;
708 		}
709 		off = 0;
710 	}
711 	if (create_tmp_queue)
712 		close(q_fd);
713 	return EXIT_SUCCESS;
714 }
715 
716 static int
717 zev_dump_spool(int fd)
718 {
719 	int len;
720 	char buf[4096];
721 	int off = 0;
722 
723 	while (1) {
724 		len = read(fd, buf + off, sizeof(buf) - off);
725 		if (len == -1) {
726 			fprintf(stderr, "reading from spool failed: %s\n",
727 				strerror(errno));
728 			return EXIT_FAILURE;
729 		}
730 		if (len == 0)
731 			break;
732 
733 		len += off;
734 		off = 0;
735 		while (len > off + sizeof(uint32_t)) {
736 			uint32_t evlen;
737 			char *mp;
738 			zev_event_t *ev;
739 
740 			ev = (zev_event_t *)(buf + off);
741 			evlen = ev->header.record_len;
742 			if (len < off + evlen + 1)
743 				break;
744 			mp = buf + off + evlen;
745 			if (!memchr(mp, 0, len - off - evlen))
746 				break;
747 			zev_print_event(buf + off, ev->header.record_len);
748 			off += ev->header.record_len + strlen(mp) + 1;
749 		}
750 
751 		memmove(buf, buf + off, len - off);
752 		off = len - off;
753 	}
754 
755 	return EXIT_SUCCESS;
756 }
757 
758 static void
759 usage(char *progname)
760 {
761 	fprintf(stderr, "usage: %s [-d <dev>] [options]\n", progname);
762 	fprintf(stderr, "\n");
763 	fprintf(stderr, " Status information:\n");
764 	fprintf(stderr, "   -s                   show zev statistics\n");
765 	fprintf(stderr, "   -p                   poll for ZFS events\n");
766 	fprintf(stderr, "   -f <name>            dump events from spool\n");
767 	fprintf(stderr, "   -D                   print zev module debug "
768 	        "information\n");
769 	fprintf(stderr, "   -T <interval> <cnt>  zevstat mode\n");
770 	fprintf(stderr, "   -R <base filename>   zevreport mode\n");
771 	fprintf(stderr, "\n");
772 	fprintf(stderr, " Tune zev module settings:\n");
773 	fprintf(stderr, "   -Q <bytes>           set maximum event queue "
774 	        "length\n");
775 	fprintf(stderr, "   -m <pool>            mute pool, no events for "
776 	        "this pool\n");
777 	fprintf(stderr, "   -M <pool>            unmute pool\n");
778 	fprintf(stderr, "\n");
779 	fprintf(stderr, " Queue management:\n");
780 	fprintf(stderr, "   -l                   list queues\n");
781 	fprintf(stderr, "   -a <name>            add non-blocking queue\n");
782 	fprintf(stderr, "   -A <name>            add blocking queue\n");
783 	fprintf(stderr, "   -r <name>            remove queue\n");
784 	fprintf(stderr, "   -b <name>            make queue non-blocking "
785 	        "(default)\n");
786 	fprintf(stderr, "   -B <name>            make queue block when full\n");
787 	fprintf(stderr, "   -P <name>            display queue properties\n");
788 	fprintf(stderr, "   -L <name> <bytes>    set maximum event queue "
789 	        "length\n");
790 	fprintf(stderr, "   -t <name> <bytes>    set queue length poll "
791 	        "throttle\n");
792 	fprintf(stderr, "\n");
793 	fprintf(stderr, " Other options:\n");
794 	fprintf(stderr, "   -d <dev>             non-default device file. "
795 	        "('%s')\n", ZEV_DEVICE);
796 	fprintf(stderr, "   -q <name>            use device file for this "
797 		"queue name\n");
798 	fprintf(stderr, "   -k <guid>:<payload>  queue mark event\n");
799 	fprintf(stderr, "   -c <filename>        list file's content "
800 		"checksums\n");
801 	fprintf(stderr, "   -v                   verbose: additional output "
802 	        "for some operations\n");
803 	fprintf(stderr, "   -g                   grep-friendly event output, "
804 	        "one event per line\n");
805 	fprintf(stderr, "   -V                   query zev module version\n");
806 	fprintf(stderr, "   -F                   flush output after each line\n");
807 	exit (EXIT_FAILURE);
808 }
809 
810 static void
811 zevstat_usage(char *progname)
812 {
813 	fprintf(stderr, "usage: %s [-v] <interval> [count]\n", progname);
814 	fprintf(stderr, "   -v   verbose, show counters for all event types\n");
815 	exit (EXIT_FAILURE);
816 }
817 
818 static void
819 zevreport_usage(char *progname)
820 {
821 	fprintf(stderr, "usage: %s <output base filename>\n", progname);
822 	exit (EXIT_FAILURE);
823 }
824 
825 static int
826 zev_add_queue(int fd, char *arg, int blocking)
827 {
828 	zev_ioctl_add_queue_t aq;
829 	int namelen;
830 
831 	namelen = strlen(arg);
832 	if (namelen > ZEV_MAX_QUEUE_NAME_LEN) {
833 		fprintf(stderr, "queue name too long: %s\n", arg);
834 		return (EXIT_FAILURE);
835 	}
836 
837 	aq.zev_namelen = namelen;
838 	strcpy(aq.zev_name, arg);
839 	aq.zev_flags = ZEV_FL_PERSISTENT | ZEV_FL_INITIALLY_EMPTY;
840 	if (blocking) {
841 		aq.zev_flags |= ZEV_FL_BLOCK_WHILE_QUEUE_FULL;
842 		aq.zev_max_queue_len = ZEV_MAX_QUEUE_LEN;
843 	} else {
844 		aq.zev_max_queue_len = (1024 * 1024);
845 	}
846 
847 	if (ioctl(fd, ZEV_IOC_ADD_QUEUE, &aq)) {
848 		perror("adding queue failed");
849 		return (EXIT_FAILURE);
850 	}
851 	return (0);
852 }
853 
854 static int
855 zev_remove_queue(int fd, char *arg)
856 {
857 	zev_ioctl_remove_queue_t aq;
858 	int namelen;
859 
860 	namelen = strlen(arg);
861 	if (namelen > ZEV_MAX_QUEUE_NAME_LEN) {
862 		fprintf(stderr, "queue name too long: %s\n", arg);
863 		return (EXIT_FAILURE);
864 	}
865 
866 	aq.zev_queue_name.zev_namelen = namelen;
867 	strcpy(aq.zev_queue_name.zev_name, arg);
868 
869 	if (ioctl(fd, ZEV_IOC_REMOVE_QUEUE, &aq)) {
870 		perror("removing queue failed");
871 		return (EXIT_FAILURE);
872 	}
873 	return (0);
874 }
875 
876 static int
877 zev_set_global_max_queue_len(int fd, char *arg)
878 {
879 	uint64_t maxqueuelen;
880 
881 	if (!arg) {
882 		fprintf(stderr, "missing queue length parameter\n");
883 		return (EXIT_FAILURE);
884 	}
885 
886 	errno = 0;
887 	maxqueuelen = strtol(arg, (char **)NULL, 10);
888 	if (errno) {
889 		fprintf(stderr, "invalid queue length parameter: %s\n", arg);
890 		return (EXIT_FAILURE);
891 	}
892 	if (ioctl(fd, ZEV_IOC_SET_MAX_QUEUE_LEN, &maxqueuelen)) {
893 		perror("setting max queue length failed");
894 		return (EXIT_FAILURE);
895 	}
896 	return (0);
897 }
898 
899 static int
900 zev_mute_unmute_impl(int fd, char *poolname, int mute)
901 {
902 	zev_ioctl_poolarg_t pa;
903 	int len;
904 	int op = mute ? ZEV_IOC_MUTE_POOL : ZEV_IOC_UNMUTE_POOL;
905 	len = strlen(poolname);
906 	if (len <= 0 || len >= sizeof(pa.zev_poolname)) {
907 		fprintf(stderr, "invalid poolname: %s\n", poolname);
908 		return (EXIT_FAILURE);
909 	}
910 	strcpy(pa.zev_poolname, poolname);
911 	pa.zev_poolname_len = len;
912 	if (ioctl(fd, op, &pa)) {
913 		perror("muting pool data failed");
914 		return (EXIT_FAILURE);
915 	}
916 	return (0);
917 }
918 
919 int
920 zev_mute_pool(int fd, char *poolname)
921 {
922 	return zev_mute_unmute_impl(fd, poolname, 1);
923 }
924 
925 int
926 zev_unmute_pool(int fd, char *poolname)
927 {
928 	return zev_mute_unmute_impl(fd, poolname, 0);
929 }
930 
931 static int
932 zev_debug_info(int fd)
933 {
934 	zev_ioctl_debug_info_t di;
935 
936 	if (ioctl(fd, ZEV_IOC_GET_DEBUG_INFO, &di)) {
937 		perror("getting zev debug info failed");
938 		return (EXIT_FAILURE);
939 	}
940 
941 	printf("memory allocated: %llu bytes\n", di.zev_memory_allocated);
942 	printf("checksum cache size: %llu\n", di.zev_chksum_cache_size);
943 	printf("checksum cache hits: %llu\n", di.zev_chksum_cache_hits);
944 	printf("checksum cache misses: %llu\n", di.zev_chksum_cache_misses);
945 	return 0;
946 }
947 
948 static int
949 zev_mark(int fd, char *arg)
950 {
951 	zev_ioctl_mark_t *mark;
952 	uint64_t guid;
953 	int len;
954 	char *p;
955 
956 	p = strchr(arg, ':');
957 	if (!p) {
958 		fprintf(stderr, "expected value is <guid>:<payload>, "
959 		        "e.g. '123:hello'\n");
960 		exit (EXIT_FAILURE);
961 	}
962 	*p = '\n';
963 	p++;
964 
965 	errno = 0;
966 	guid = strtoll(arg, (char **)NULL, 10);
967 	if (errno) {
968 		fprintf(stderr, "guid must be a number.\n");
969 		exit (EXIT_FAILURE);
970 	}
971 
972 	len = strlen(p);
973 
974 	mark = malloc(sizeof(*mark) + len + 1);
975 	if (!mark) {
976 		fprintf(stderr, "can't allocate mark structure: %s\n",
977 		        strerror(errno));
978 		exit (EXIT_FAILURE);
979 	}
980 	mark->zev_guid = guid;
981 	mark->zev_mark_id = 0;
982 	mark->zev_payload_len = len;
983 	strcpy(ZEV_PAYLOAD(mark), p);
984 
985 	if (ioctl(fd, ZEV_IOC_MARK, mark)) {
986 		perror("queueing mark failed");
987 		return (EXIT_FAILURE);
988 	}
989 
990 	printf("mark id: %lu\n", mark->zev_mark_id);
991 	return (0);
992 }
993 
994 static int
995 zev_queue_blocking(int fd, char *arg, int block)
996 {
997 	zev_ioctl_get_queue_properties_t gqp;
998 
999 	gqp.zev_queue_name.zev_namelen = strlen(arg);
1000 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
1001 		fprintf(stderr, "queue name too long.\n");
1002 		return EXIT_FAILURE;
1003 	}
1004 	strcpy(gqp.zev_queue_name.zev_name, arg);
1005 
1006 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
1007 		perror("getting queue properties failed");
1008 		return (EXIT_FAILURE);
1009 	}
1010 	if (block) {
1011 		gqp.zev_flags |= ZEV_FL_BLOCK_WHILE_QUEUE_FULL;
1012 	} else {
1013 		gqp.zev_flags &= ~ZEV_FL_BLOCK_WHILE_QUEUE_FULL;
1014 	}
1015 	if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) {
1016 		perror("setting queue properties failed");
1017 		return (EXIT_FAILURE);
1018 	}
1019 	return (0);
1020 }
1021 
1022 static int
1023 zev_set_max_queue_len(int fd, char *arg, char *len)
1024 {
1025 	zev_ioctl_get_queue_properties_t gqp;
1026 
1027 	if (!len) {
1028 		fprintf(stderr, "queue size parameter missing.\n");
1029 		return EXIT_FAILURE;
1030 	}
1031 
1032 	gqp.zev_queue_name.zev_namelen = strlen(arg);
1033 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
1034 		fprintf(stderr, "queue name too long.\n");
1035 		return EXIT_FAILURE;
1036 	}
1037 	strcpy(gqp.zev_queue_name.zev_name, arg);
1038 
1039 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
1040 		perror("getting queue properties failed");
1041 		return (EXIT_FAILURE);
1042 	}
1043 	gqp.zev_max_queue_len = atol(len);
1044 	if (gqp.zev_max_queue_len == 0 && strcmp("0", len)) {
1045 		fprintf(stderr, "queue size parameter garbled.\n");
1046 		return (EXIT_FAILURE);
1047 	}
1048 	if (gqp.zev_max_queue_len > ZEV_MAX_QUEUE_LEN) {
1049 		fprintf(stderr, "queue size parameter out of bounds.\n");
1050 		return (EXIT_FAILURE);
1051 	}
1052 
1053 	if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) {
1054 		perror("setting queue properties failed");
1055 		return (EXIT_FAILURE);
1056 	}
1057 	return (0);
1058 }
1059 
1060 static int
1061 zev_set_poll_wakeup_queue_len(int fd, char *arg, char *len)
1062 {
1063 	zev_ioctl_get_queue_properties_t gqp;
1064 
1065 	if (!len) {
1066 		fprintf(stderr, "poll throttle parameter missing.\n");
1067 		return EXIT_FAILURE;
1068 	}
1069 
1070 	gqp.zev_queue_name.zev_namelen = strlen(arg);
1071 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
1072 		fprintf(stderr, "queue name too long.\n");
1073 		return EXIT_FAILURE;
1074 	}
1075 	strcpy(gqp.zev_queue_name.zev_name, arg);
1076 
1077 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
1078 		perror("getting queue properties failed");
1079 		return (EXIT_FAILURE);
1080 	}
1081 	gqp.zev_poll_wakeup_threshold = atol(len);
1082 	if (gqp.zev_poll_wakeup_threshold == 0 && strcmp("0", len)) {
1083 		fprintf(stderr, "poll throttle parameter garbled.\n");
1084 		return (EXIT_FAILURE);
1085 	}
1086 	if (gqp.zev_poll_wakeup_threshold > ZEV_MAX_POLL_WAKEUP_QUEUE_LEN) {
1087 		fprintf(stderr, "poll throttle parameter out of bounds.\n");
1088 		return (EXIT_FAILURE);
1089 	}
1090 
1091 	if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) {
1092 		perror("setting queue properties failed");
1093 		return (EXIT_FAILURE);
1094 	}
1095 	return (0);
1096 }
1097 
1098 static int
1099 zev_queue_properties(int fd, char *arg)
1100 {
1101 	zev_ioctl_get_queue_properties_t gqp;
1102 
1103 	gqp.zev_queue_name.zev_namelen = strlen(arg);
1104 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
1105 		fprintf(stderr, "queue name too long.\n");
1106 		return EXIT_FAILURE;
1107 	}
1108 	strcpy(gqp.zev_queue_name.zev_name, arg);
1109 
1110 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
1111 		perror("getting queue properties failed");
1112 		return (EXIT_FAILURE);
1113 	}
1114 
1115 	printf("queue        : %s\n", arg);
1116 	printf("max size     : %" PRIu64 "\n", gqp.zev_max_queue_len);
1117 	printf("poll throttle: %" PRIu64 "\n", gqp.zev_poll_wakeup_threshold);
1118 	printf("persistent   : %s\n",
1119 		gqp.zev_flags & ZEV_FL_PERSISTENT ? "yes" : "no");
1120 	printf("blocking     : %s\n",
1121 		gqp.zev_flags & ZEV_FL_BLOCK_WHILE_QUEUE_FULL ? "yes" : "no");
1122 
1123 	return (0);
1124 }
1125 
1126 static int
1127 zev_list_queues(int fd)
1128 {
1129 	zev_ioctl_get_queue_properties_t gqp;
1130 	zev_ioctl_get_queue_list_t gql;
1131 	zev_ioctl_get_queue_statistics_t gs;
1132 	uint64_t	i;
1133 	char		name[ZEV_MAX_QUEUE_NAME_LEN+1];
1134 	zev_statistics_t zs;
1135 
1136 	if (ioctl(fd, ZEV_IOC_GET_GLOBAL_STATISTICS, &zs)) {
1137 		perror("getting statistics data failed");
1138 		return (EXIT_FAILURE);
1139 	}
1140 
1141 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_LIST, &gql)) {
1142 		perror("getting queue list failed");
1143 		return (EXIT_FAILURE);
1144 	}
1145 
1146 	printf("Name                                     Size       "
1147 	       "Size%% Max Size   Per Block\n");
1148 
1149 	for (i=0; i<gql.zev_n_queues; i++) {
1150 		strncpy(name, gql.zev_queue_name[i].zev_name,
1151 		        ZEV_MAX_QUEUE_NAME_LEN);
1152 		name[gql.zev_queue_name[i].zev_namelen] = '\0';
1153 
1154 		memcpy(gqp.zev_queue_name.zev_name,
1155 		    gql.zev_queue_name[i].zev_name, ZEV_MAX_QUEUE_NAME_LEN);
1156 		gqp.zev_queue_name.zev_namelen =
1157 		    gql.zev_queue_name[i].zev_namelen;
1158 
1159 		if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
1160 			if (errno == ENOENT)
1161 				continue;
1162 			perror("getting queue properties failed");
1163 			return (EXIT_FAILURE);
1164 		}
1165 
1166 		memcpy(gs.zev_queue_name.zev_name,
1167 		    gql.zev_queue_name[i].zev_name, ZEV_MAX_QUEUE_NAME_LEN);
1168 		gs.zev_queue_name.zev_namelen =
1169 		    gql.zev_queue_name[i].zev_namelen;
1170 
1171 		if (ioctl(fd, ZEV_IOC_GET_QUEUE_STATISTICS, &gs)) {
1172 			if (errno == ENOENT)
1173 				continue;
1174 			perror("getting statistics data failed");
1175 			return (EXIT_FAILURE);
1176 		}
1177 
1178 		if (gqp.zev_max_queue_len == 0) {
1179 			gqp.zev_max_queue_len = zs.zev_max_queue_len;
1180 		}
1181 		printf("%-40s %-10" PRIu64 " %5.1f %-10" PRIu64
1182 		       " %-3s %-3s\n",
1183 			name,
1184 			gs.zev_statistics.zev_queue_len * 100.0 /
1185 				gqp.zev_max_queue_len,
1186 			gs.zev_statistics.zev_queue_len,
1187 			gqp.zev_max_queue_len,
1188 			gqp.zev_flags & ZEV_FL_PERSISTENT ? "yes" : "no",
1189 			gqp.zev_flags & ZEV_FL_BLOCK_WHILE_QUEUE_FULL ?
1190 				 "yes" : "no");
1191 	}
1192 
1193 	return (0);
1194 }
1195 
1196 static int
1197 zev_checksum(int dev_fd, char *filename)
1198 {
1199 	int fd;
1200 	offset_t off;
1201 	offset_t data;
1202 	zev_sig_t *sig;
1203 	char *buf;
1204 	zev_ioctl_get_signatures_t *gs;
1205 	int i;
1206 	char sigval[(SHA1_DIGEST_LENGTH * 2) + 1];
1207 	int buf_size;
1208 
1209 	/* control struct, one lv1 signature and up to 256 lv0 signatures */
1210 	buf_size = (1 + 256) * sizeof(zev_sig_t);
1211 	buf = malloc(sizeof(zev_ioctl_get_signatures_t) + buf_size);
1212 	if (!buf) {
1213 		perror("can't allocate checksum buffer");
1214 		return (EXIT_FAILURE);
1215 	}
1216 
1217 	fd = open(filename, O_RDONLY);
1218 	if (fd < 0) {
1219 		perror("can't open file");
1220 		return (EXIT_FAILURE);
1221 	}
1222 
1223 	gs = (zev_ioctl_get_signatures_t *)buf;
1224 	gs->zev_fd = fd;
1225 	gs->zev_bufsize = buf_size;
1226 
1227 	off = 0;
1228 	data = 0;
1229 	while (1) {
1230 		errno = 0;
1231 		data = llseek(fd, off, SEEK_DATA);
1232 		if (data < 0) {
1233 			if (errno == ENXIO)	/* no more data */
1234 				break;
1235 			perror("llseek failed");
1236 			goto err;
1237 		}
1238 		data = P2ALIGN(data, ZEV_L1_SIZE);
1239 		off = data + ZEV_L1_SIZE;
1240 
1241 		gs->zev_offset = data;
1242 		gs->zev_len = ZEV_L1_SIZE;
1243 
1244 		if (ioctl(dev_fd, ZEV_IOC_GET_FILE_SIGNATURES, gs)) {
1245 			perror("ioctl to get signatures failed");
1246 			goto err;
1247 		}
1248 
1249 		for (i=0; i<gs->zev_signature_cnt; i++) {
1250 			sig = (zev_sig_t *)ZEV_SIGNATURES(gs);
1251 			sig += i;
1252 			sig2hex_direct(sig->value, sigval);
1253 			printf("level %d, offset %llu, value %s\n",
1254 			       sig->level, sig->block_offset, sigval);
1255 		}
1256 	}
1257 
1258 	free(buf);
1259 	close(fd);
1260 	return 0;
1261 err:
1262 	free(buf);
1263 	close(fd);
1264 	return (EXIT_FAILURE);
1265 }
1266 
1267 typedef struct zevstat {
1268 	uint64_t	ns_start;
1269 	uint64_t	events[ZEV_OP_MIN + ZEV_OP_MAX];
1270 	uint64_t	guids;
1271 	uint64_t	total_events;
1272 	uint64_t	total_guids;
1273 	avl_tree_t	guids_interval;
1274 	avl_tree_t	guids_runtime;
1275 } zevstat_t;
1276 
1277 typedef struct zev_guidtrack_t {
1278 	uint64_t	guid;
1279 	avl_node_t	avl_interval;
1280 	avl_node_t	avl_runtime;
1281 } zev_guidtrack_t;
1282 
1283 zevstat_t zevstat;
1284 
1285 static void
1286 zev_eventstat(char *buf, int len)
1287 {
1288 	zev_header_t *rec = (zev_header_t *)buf;
1289 	zev_guidtrack_t *gt;
1290 	zev_guidtrack_t *gt_int;
1291 	zev_guidtrack_t to_find;
1292 	avl_index_t where;
1293 
1294 	zevstat.total_events++;
1295 	zevstat.events[rec->op]++;
1296 
1297 	to_find.guid = rec->guid;
1298 	gt = avl_find(&zevstat.guids_runtime, &to_find, &where);
1299 	if (!gt) {
1300 		gt = malloc(sizeof(*gt));
1301 		if (!gt) {
1302 			perror("can't get guid tracking record");
1303 			exit (EXIT_FAILURE);
1304 		}
1305 		gt->guid = rec->guid;
1306 		avl_insert(&zevstat.guids_runtime, gt, where);
1307 	}
1308 	gt_int = avl_find(&zevstat.guids_interval, &to_find, &where);
1309 	if (!gt_int)
1310 		avl_insert(&zevstat.guids_interval, gt, where);
1311 }
1312 
1313 static void
1314 zev_eventstat_interval(FILE *out)
1315 {
1316 	uint64_t events;
1317 	int i;
1318 	zev_guidtrack_t *gt;
1319 
1320 	events = 0;
1321 	for (i = ZEV_OP_MIN; i <= ZEV_OP_MAX; i++) {
1322 		events += zevstat.events[i];
1323 	}
1324 
1325 	if (verbose) {
1326 		fprintf(out, "%u  %6llu  %6llu %6llu %6llu  ",
1327 		        time(NULL),
1328 		        events,
1329 		        zevstat.total_events,
1330 		        avl_numnodes(&zevstat.guids_interval),
1331 		        avl_numnodes(&zevstat.guids_runtime));
1332 		for (i = ZEV_OP_MIN; i <= ZEV_OP_MAX; i++)
1333 			fprintf(out, "%6llu ", zevstat.events[i]);
1334 		fprintf(out, "\n");
1335 	} else {
1336 		fprintf(out, "%u  %6llu  %6llu %6llu %6llu\n",
1337 		        time(NULL),
1338 		        events,
1339 		        zevstat.total_events,
1340 		        avl_numnodes(&zevstat.guids_interval),
1341 		        avl_numnodes(&zevstat.guids_runtime));
1342 	}
1343 	memset(&zevstat.events, 0, sizeof(zevstat.events));
1344 	zevstat.guids = 0;
1345 	while (gt = avl_first(&zevstat.guids_interval))
1346 		avl_remove(&zevstat.guids_interval, gt);
1347 	fflush(out);
1348 }
1349 
1350 static int
1351 zev_evcompar(const void *a, const void *b)
1352 {
1353 	const zev_guidtrack_t *ga = a;
1354 	const zev_guidtrack_t *gb = b;
1355 
1356 	if (ga->guid > gb->guid)
1357 		return 1;
1358 	if (ga->guid < gb->guid)
1359 		return -1;
1360 	return 0;
1361 }
1362 
1363 static int
1364 zev_zevstat(int fd, char *s_interval, char *s_count, char *outfile)
1365 {
1366 	uint64_t interval = 1000;
1367 	uint64_t ms;
1368 	uint64_t t_until;
1369 	uint64_t t_now;
1370 	int cnt = -1;
1371 	struct pollfd pfd[1];
1372 	int ret;
1373 	char buf[4096];
1374 	zev_event_t *ev;
1375 	int off = 0;
1376 	zev_ioctl_add_queue_t aq;
1377 	int q_fd;
1378 	zev_guidtrack_t *gt;
1379 	FILE *out = stdout;
1380 	struct stat st;
1381 	char filename[MAXPATHLEN];
1382 	int retry;
1383 
1384 	if (outfile) {
1385 		retry = 0;
1386 		strncpy(filename, outfile, sizeof(filename));
1387 		while (stat(filename, &st) == 0) {
1388 			/* file exists */
1389 			snprintf(filename, sizeof(filename),
1390 			         "%s.%d", outfile, retry);
1391 			retry++;
1392 		}
1393 		out = fopen(filename, "wb+");
1394 		if (!out) {
1395 			perror("opening output file failed");
1396 			return (EXIT_FAILURE);
1397 		}
1398 	}
1399 
1400 	memset(&zevstat, 0, sizeof(zevstat));
1401 	avl_create(&zevstat.guids_runtime, zev_evcompar,
1402 	           sizeof(zev_guidtrack_t),
1403 	           offsetof(zev_guidtrack_t, avl_runtime));
1404 	avl_create(&zevstat.guids_interval, zev_evcompar,
1405 	           sizeof(zev_guidtrack_t),
1406 	           offsetof(zev_guidtrack_t, avl_interval));
1407 
1408 	if (s_interval) {
1409 		interval = atol(s_interval);
1410 		if (interval == 0) {
1411 			fprintf(stderr, "invalid interval.\n");
1412 			return (EXIT_FAILURE);
1413 		}
1414 		interval *= 1000;
1415 	}
1416 	if (s_count) {
1417 		cnt = atol(s_count);
1418 		if (interval == 0) {
1419 			fprintf(stderr, "invalid count.\n");
1420 			return (EXIT_FAILURE);
1421 		}
1422 	}
1423 
1424 	aq.zev_max_queue_len = 1024 * 1024;
1425 	aq.zev_flags = ZEV_FL_INITIALLY_EMPTY;
1426 	snprintf(aq.zev_name, ZEV_MAX_QUEUE_NAME_LEN,
1427 		 "zevstat.%ld.%ld", time(NULL), getpid());
1428 	aq.zev_namelen = strlen(aq.zev_name);
1429 
1430 	if (ioctl(fd, ZEV_IOC_ADD_QUEUE, &aq)) {
1431 		perror("adding temporary queue failed");
1432 		return (EXIT_FAILURE);
1433 	}
1434 
1435 	snprintf(buf, sizeof(buf),
1436 		 "/devices/pseudo/zev@0:%s", aq.zev_name);
1437 	q_fd = open(buf, O_RDONLY);
1438 	if (q_fd < 0) {
1439 		perror("opening queue device failed");
1440 		return (EXIT_FAILURE);
1441 	}
1442 
1443 	pfd[0].fd = q_fd;
1444 	pfd[0].events = POLLIN;
1445 
1446 	/* drain queue */
1447 	while ((ret = poll(pfd, 1, 0)) > 0) {
1448 		if (read(q_fd, buf, sizeof(buf)) < 0) {
1449 			perror("read failed");
1450 			close(q_fd);
1451 			return(EXIT_FAILURE);
1452 		}
1453 	}
1454 	if (ret < 0) {
1455 		perror("poll failed");
1456 		close(q_fd);
1457 		return(EXIT_FAILURE);
1458 	}
1459 
1460 	fprintf(out, "timestamp   events tevents  guids tguids");
1461 	if (verbose) {
1462 		fprintf(out, "   error   mark  mount umount zvol_w ");
1463 		fprintf(out, "zvol_t  close create  mkdir mxattr ");
1464 		fprintf(out, "remove  rmdir   link symlnk rename  ");
1465 		fprintf(out, "write  trunc setatt    acl");
1466 	}
1467 	fprintf(out, "\n");
1468 	while (cnt) {
1469 		t_until = gethrtime() + (interval * 1000000);
1470 		ms = interval;
1471 		do {
1472 			ret = poll(pfd, 1, ms);
1473 			t_now = gethrtime();
1474 			if (t_now < t_until) {
1475 				ms = t_until - t_now;
1476 				ms /= 1000000ull;
1477 			}
1478 			if (ret < 0) {
1479 				perror("poll failed");
1480 				close(q_fd);
1481 				return(EXIT_FAILURE);
1482 			}
1483 			if (!(pfd[0].revents & POLLIN))
1484 				continue;
1485 			/* data available */
1486 			ret = read(q_fd, buf, sizeof(buf));
1487 			if (ret < 0) {
1488 				perror("read failed");
1489 				close(q_fd);
1490 				return(EXIT_FAILURE);
1491 			}
1492 			if (ret == 0)
1493 				continue;
1494 			while (ret > off) {
1495 				ev = (zev_event_t *)(buf + off);
1496 				zev_eventstat(buf + off, ev->header.record_len);
1497 				off += ev->header.record_len;
1498 			}
1499 			off = 0;
1500 		} while ((t_now) < t_until && (ms > 0));
1501 		zev_eventstat_interval(out);
1502 		if (cnt > 0)
1503 			cnt--;
1504 	}
1505 	close(q_fd);
1506 	if (outfile)
1507 		fclose(out);
1508 	while (gt = avl_first(&zevstat.guids_interval))
1509 		avl_remove(&zevstat.guids_interval, gt);
1510 	while (gt = avl_first(&zevstat.guids_runtime)) {
1511 		avl_remove(&zevstat.guids_runtime, gt);
1512 		free(gt);
1513 	}
1514 	return EXIT_SUCCESS;
1515 }
1516 
1517 static int
1518 zev_report(int fd, char *basename)
1519 {
1520 	char filename[MAXPATHLEN];
1521 	char count[10];
1522 	time_t now;
1523 	time_t midnight;
1524 	struct tm tm;
1525 	int minutes;
1526 	int ret;
1527 
1528 	verbose++;
1529 	while (1) {
1530 		now = time(NULL);
1531 		localtime_r(&now, &tm);
1532 		snprintf(filename, sizeof(filename), "%s.%04d-%02d-%02d",
1533 		         basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
1534 		tm.tm_sec = 0;
1535 		tm.tm_min = 0;
1536 		tm.tm_hour = 0;
1537 		tm.tm_mday++;  /* works for Jan 32nd, Feb 30th, etc. */
1538 		midnight = mktime(&tm);
1539 		if (now % 60)
1540 			sleep(60 - (now % 60));
1541 		minutes = (midnight - time(NULL)) / 60;
1542 		snprintf(count, sizeof(count), "%d", minutes);
1543 		ret = zev_zevstat(fd, "60", count, filename);
1544 		if (ret)
1545 			return EXIT_FAILURE;
1546 	}
1547 	return EXIT_SUCCESS; /* never reached */
1548 }
1549 
1550 static int
1551 zev_get_zev_version(int fd)
1552 {
1553 	zev_ioctl_get_zev_version vi;
1554 
1555 	if (ioctl(fd, ZEV_IOC_GET_ZEV_VERSION, &vi)) {
1556 		perror("getting zev cersion info failed");
1557 		return (EXIT_FAILURE);
1558 	}
1559 
1560 	printf("zev major version: %llu\n", vi.zev_major_version);
1561 	printf("zev minor version: %llu\n", vi.zev_minor_version);
1562 	return 0;
1563 }
1564 
1565 static void
1566 zev_sigint(int sig)
1567 {
1568 	fflush(stdout);
1569 }
1570 
1571 int
1572 main(int argc, char **argv)
1573 {
1574 	int fd;
1575 	int c;
1576 	extern char *optarg;
1577 	int create_tmp_queue = 1;
1578 	char buf[MAXPATHLEN];
1579 	int mode = 0;
1580 	char *arg = NULL;
1581 	char *arg2 = NULL;
1582 	char *p;
1583 
1584 	sigset(SIGINT, zev_sigint);
1585 
1586 	/* open device */
1587 	fd = open(zev_device, O_RDONLY);
1588 	if (fd < 0) {
1589 		perror("opening zev device failed");
1590 		return EXIT_FAILURE;
1591 	}
1592 
1593 	p = strrchr(argv[0], '/');
1594 	if (!p) {
1595 		p = argv[0];
1596 	} else {
1597 		p++;
1598 	}
1599 	if (!strcmp(p, "zevstat")) {
1600 		mode = MD_ZEVSTAT;
1601 		if (argc < 2)
1602 			zevstat_usage(argv[0]);
1603 		if (!strcmp(argv[1], "-v")) {
1604 			if (argc < 3)
1605 				zevstat_usage(argv[0]);
1606 			verbose++;
1607 			arg = argv[2];
1608 			arg2 = argv[3];
1609 		} else {
1610 			arg = argv[1];
1611 			arg2 = argv[2];
1612 		}
1613 		return zev_zevstat(fd, arg, arg2, NULL);
1614 	} else if(!strcmp(p, "zevreport")) {
1615 		mode = MD_ZEV_REPORT;
1616 		if (argc != 2)
1617 			zevreport_usage(argv[0]);
1618 		return zev_report(fd, argv[1]);
1619 	}
1620 
1621 	while ((c = getopt(argc, argv,
1622 	   "a:A:b:B:c:d:Df:Fghk:lL:m:M:pP:q:Q:r:R:st:T:vV?")) != -1) {
1623 		switch(c) {
1624 		case 'g':
1625 			grep_friendly++;
1626 			verbose++;
1627 			break;
1628 		case 'v':
1629 			verbose++;
1630 			break;
1631 		case 's':
1632 			mode = MD_STATISTICS;
1633 			break;
1634 		case 'p':
1635 			mode = MD_POLL_EVENTS;
1636 			break;
1637 		case 'c':
1638 			mode = MD_CHECKSUMS;
1639 			arg = optarg;
1640 			break;
1641 		case 'D':
1642 			mode = MD_DEBUG_INFO;
1643 			break;
1644 		case 'd':
1645 			close(fd);
1646 			zev_device = optarg;
1647 			fd = open(zev_device, O_RDONLY);
1648 			if (fd < 0) {
1649 				perror("opening zev device failed");
1650 				return EXIT_FAILURE;
1651 			}
1652 			create_tmp_queue = 0;
1653 			break;
1654 		case 'q':
1655 			snprintf(buf, sizeof(buf),
1656 				 "/devices/pseudo/zev@0:%s", optarg);
1657 			close(fd);
1658 			zev_device = buf;
1659 			fd = open(zev_device, O_RDONLY);
1660 			if (fd < 0) {
1661 				perror("opening zev device failed");
1662 				return EXIT_FAILURE;
1663 			}
1664 			create_tmp_queue = 0;
1665 			break;
1666 		case 'f':
1667 			fd = open(optarg, O_RDONLY);
1668 			if (fd < 0) {
1669 				perror("opening spool file failed");
1670 				return EXIT_FAILURE;
1671 			}
1672 			mode = MD_DUMP_SPOOL;
1673 			break;
1674 		case 'l':
1675 			mode = MD_LIST_QUEUES;
1676 			break;
1677 		case 'Q':
1678 			mode = MD_SET_GLOBAL_MAX_QUEUE_LEN;
1679 			arg = optarg;
1680 			break;
1681 		case 'L':
1682 			mode = MD_SET_MAX_QUEUE_LEN;
1683 			arg = optarg;
1684 			arg2 = argv[optind];
1685 			break;
1686 		case 'T':
1687 			mode = MD_ZEVSTAT;
1688 			arg = optarg;
1689 			arg2 = argv[optind];
1690 			break;
1691 		case 'R':
1692 			mode = MD_ZEV_REPORT;
1693 			arg = optarg;
1694 			break;
1695 		case 't':
1696 			mode = MD_SET_POLL_WAKEUP_QUEUE_LEN;
1697 			arg = optarg;
1698 			arg2 = argv[optind];
1699 			break;
1700 		case 'm':
1701 			mode = MD_MUTE_POOL;
1702 			arg = optarg;
1703 			break;
1704 		case 'M':
1705 			mode = MD_UNMUTE_POOL;
1706 			arg = optarg;
1707 			break;
1708 		case 'k':
1709 			mode = MD_MARK;
1710 			arg = optarg;
1711 			break;
1712 		case 'a':
1713 			mode = MD_ADD_QUEUE;
1714 			arg = optarg;
1715 			break;
1716 		case 'A':
1717 			mode = MD_ADD_BLOCKING_QUEUE;
1718 			arg = optarg;
1719 			break;
1720 		case 'r':
1721 			mode = MD_REMOVE_QUEUE;
1722 			arg = optarg;
1723 			break;
1724 		case 'b':
1725 			mode = MD_QUEUE_BLOCKING;
1726 			arg = optarg;
1727 			break;
1728 		case 'B':
1729 			mode = MD_QUEUE_NONBLOCKING;
1730 			arg = optarg;
1731 			break;
1732 		case 'P':
1733 			mode = MD_QUEUE_PROPERTIES;
1734 			arg = optarg;
1735 			break;
1736 		case 'V':
1737 			mode = MD_GET_ZEV_VERSION;
1738 			break;
1739 		case 'F':
1740 			do_flush = 1;
1741 			break;
1742 		case 'h':
1743 		case '?':
1744 		default:
1745 			usage(argv[0]);
1746 		}
1747 	}
1748 
1749 	switch (mode) {
1750 	case MD_STATISTICS:
1751 		return zev_statistics(fd);
1752 	case MD_POLL_EVENTS:
1753 		return zev_poll_events(fd, create_tmp_queue);
1754 	case MD_DUMP_SPOOL:
1755 		return zev_dump_spool(fd);
1756 	case MD_CHECKSUMS:
1757 		return zev_checksum(fd, arg);
1758 	case MD_DEBUG_INFO:
1759 		return zev_debug_info(fd);
1760 	case MD_LIST_QUEUES:
1761 		return zev_list_queues(fd);
1762 	case MD_SET_GLOBAL_MAX_QUEUE_LEN:
1763 		return zev_set_global_max_queue_len(fd, arg);
1764 	case MD_SET_MAX_QUEUE_LEN:
1765 		return zev_set_max_queue_len(fd, arg, arg2);
1766 	case MD_SET_POLL_WAKEUP_QUEUE_LEN:
1767 		return zev_set_poll_wakeup_queue_len(fd, arg, arg2);
1768 	case MD_ZEVSTAT:
1769 		return zev_zevstat(fd, arg, arg2, NULL);
1770 	case MD_ZEV_REPORT:
1771 		return zev_report(fd, arg);
1772 	case MD_MUTE_POOL:
1773 		return zev_mute_pool(fd, arg);
1774 	case MD_UNMUTE_POOL:
1775 		return zev_unmute_pool(fd, arg);
1776 	case MD_MARK:
1777 		return zev_mark(fd, arg);
1778 	case MD_ADD_QUEUE:
1779 		return zev_add_queue(fd, arg, 0);
1780 	case MD_ADD_BLOCKING_QUEUE:
1781 		return zev_add_queue(fd, arg, 1);
1782 	case MD_REMOVE_QUEUE:
1783 		return zev_remove_queue(fd, arg);
1784 	case MD_QUEUE_BLOCKING:
1785 		return zev_queue_blocking(fd, arg, 0);
1786 	case MD_QUEUE_NONBLOCKING:
1787 		return zev_queue_blocking(fd, arg, 1);
1788 	case MD_QUEUE_PROPERTIES:
1789 		return zev_queue_properties(fd, arg);
1790 	case MD_GET_ZEV_VERSION:
1791 		return zev_get_zev_version(fd);
1792 	default:
1793 		close(fd);
1794 		usage(argv[0]);
1795 		return EXIT_FAILURE;
1796 	};
1797 }
1798 
1799