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