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