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