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