xref: /titanic_50/usr/src/cmd/zevadm/zevadm.c (revision 1ca5a13b91f7b1ae27d6dd26a0fd511ef5492d35)
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 
13 #define ZEV_DEVICE "/devices/pseudo/zev@0:ctrl"
14 
15 static char *zev_device = ZEV_DEVICE;
16 
17 static char *zev_op_name[] = {
18 	"ERROR",
19 	"MARK",
20 	"ZFS_MOUNT",
21 	"ZFS_UMOUNT",
22 	"ZVOL_WRITE",
23 	"ZVOL_TRUNCATE",
24 	"ZNODE_CLOSE_AFTER_UPDATE",
25 	"ZNODE_CREATE",
26 	"ZNODE_MKDIR",
27 	"ZNODE_MAKE_XATTR_DIR",
28 	"ZNODE_REMOVE",
29 	"ZNODE_RMDIR",
30 	"ZNODE_LINK",
31 	"ZNODE_SYMLINK",
32 	"ZNODE_RENAME",
33 	"ZNODE_WRITE",
34 	"ZNODE_TRUNCATE",
35 	"ZNODE_SETATTR",
36 	"ZNODE_ACL",
37 	NULL
38 };
39 
40 static int verbose = 0;
41 static int grep_friendly = 0;
42 
43 static void
44 zpf(char *fmt, ...)
45 {
46 	va_list	ap;
47 
48 	va_start(ap, fmt);
49 	vprintf(fmt, ap);
50 	va_end(ap);
51 	if (grep_friendly) {
52 		printf(" ");
53 	} else {
54 		printf("\n");
55 	}
56 }
57 
58 static void
59 znl(void)
60 {
61 	if (grep_friendly)
62 		printf("\n");
63 }
64 
65 static void
66 sig2hex_direct(const uint8_t *sig, char *hex)
67 {
68 	int     i;
69 
70 	for (i = 0; i < SHA1_DIGEST_LENGTH; ++i) {
71 		sprintf(hex + 2 * i, "%02x", sig[i]);
72 	}
73 	hex[SHA1_DIGEST_LENGTH * 2] = '\0';
74 }
75 
76 static int
77 zev_statistics(int fd)
78 {
79 	zev_statistics_t zs;
80 	if (ioctl(fd, ZEV_IOC_GET_GLOBAL_STATISTICS, &zs)) {
81 		perror("getting statistics data failed");
82 		return (EXIT_FAILURE);
83 	}
84 	printf("ZEV module state:\n");
85 
86 	printf("    queue length in bytes   : %lu\n", zs.zev_queue_len);
87 	printf("    queue length limit      : %lu\n", zs.zev_max_queue_len);
88 	printf("    bytes read from device  : %lu\n", zs.zev_bytes_read);
89 	printf("    module internal errors  : %lu\n\n", zs.zev_cnt_errors);
90 
91 	printf("    discarded events        : %lu\n",
92 	    zs.zev_cnt_discarded_events);
93 	printf("    discarded bytes         : %lu\n\n", zs.zev_bytes_discarded);
94 
95 	printf("ZFS event statistics:\n");
96 
97 	printf("    total ZFS events        : %lu\n", zs.zev_cnt_total_events);
98 	printf("    ZFS mount               : %lu\n", zs.zev_cnt_zfs_mount);
99 	printf("    ZFS umount              : %lu\n", zs.zev_cnt_zfs_umount);
100 	printf("    ZVOL write              : %lu\n", zs.zev_cnt_zvol_write);
101 	printf("    ZVOL truncate           : %lu\n", zs.zev_cnt_zvol_truncate);
102 	printf("    ZNODE close after update: %lu\n",
103 	    zs.zev_cnt_znode_close_after_update);
104 	printf("    ZNODE create            : %lu\n", zs.zev_cnt_znode_create);
105 	printf("    ZNODE remove            : %lu\n", zs.zev_cnt_znode_remove);
106 	printf("    ZNODE link              : %lu\n", zs.zev_cnt_znode_link);
107 	printf("    ZNODE symlink           : %lu\n", zs.zev_cnt_znode_symlink);
108 	printf("    ZNODE rename            : %lu\n", zs.zev_cnt_znode_rename);
109 	printf("    ZNODE write             : %lu\n", zs.zev_cnt_znode_write);
110 	printf("    ZNODE truncate          : %lu\n",
111 	    zs.zev_cnt_znode_truncate);
112 	printf("    ZNODE setattr           : %lu\n", zs.zev_cnt_znode_setattr);
113 	printf("    ZNODE acl               : %lu\n", zs.zev_cnt_znode_acl);
114 	return EXIT_SUCCESS;
115 }
116 
117 static void
118 zev_print_inode_info(char *name, zev_inode_info_t *info)
119 {
120 	zpf("  %s.inode: %llu", name, info->ino);
121 	zpf("  %s.gen: %llu", name, info->gen);
122 	zpf("  %s.mtime: %llu", name, info->mtime);
123 	zpf("  %s.ctime: %llu", name, info->ctime);
124 	zpf("  %s.size: %llu", name, info->size);
125 	zpf("  %s.mode: %llo", name, info->mode);
126 	zpf("  %s.links: %llu", name, info->links);
127 	zpf("  %s.type: %lu", name, info->type);
128 	zpf("  %s.flags: %lu", name, info->flags);
129 }
130 
131 static void
132 zev_print_mark_payload(zev_mark_t *rec)
133 {
134 	int i;
135 	int j;
136 	uint8_t *p;
137 	char c;
138 
139 	zpf("  payload:");
140 	p = (uint8_t *)ZEV_PAYLOAD(rec);
141 	for (i=0; i<rec->payload_len; i+=16) {
142 		printf("  ");
143 		for (j=i; j<rec->payload_len && j<i+16; j++) {
144 			printf("%02x ", p[j]);
145 			if (j == i + 7)
146 				printf(" ");
147 		}
148 		if (grep_friendly)
149 			continue;
150 		for (; j<i+16; j++) {
151 			printf("   ");
152 			if (j == i + 7)
153 				printf(" ");
154 		}
155 		printf("    ");
156 		for (j=i; j<rec->payload_len && j<i+16; j++) {
157 			c = '.';
158 			if (p[j] >= ' ' && p[j] <= '~')
159 				c = p[j];
160 			printf("%c", c);
161 			if (j == i + 7)
162 				printf(" ");
163 		}
164 		printf("\n");
165 	}
166 }
167 
168 static void
169 zev_print_error(char *buf)
170 {
171 	zev_error_t *rec = (zev_error_t *)buf;
172 	time_t op_time = rec->op_time;
173 	char *ct = ctime(&op_time); ct[24] = '\0';
174 
175 	if (verbose) {
176 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
177 		zpf("  guid: %llu", rec->guid);
178 		zpf("  failed.op: %s",
179 		    zev_op_name[rec->failed_op - ZEV_OP_MIN]);
180 		zpf("  message: %s", ZEV_ERRSTR(rec));
181 		znl();
182 	} else {
183 		printf("%s %s: failed_op=%s msg=%s\n",
184 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
185 		       zev_op_name[rec->failed_op - ZEV_OP_MIN],
186 		       ZEV_ERRSTR(rec));
187 	}
188 }
189 
190 static void
191 zev_print_mark(char *buf)
192 {
193 	zev_mark_t *rec = (zev_mark_t *)buf;
194 	time_t op_time = rec->op_time;
195 	char *ct = ctime(&op_time); ct[24] = '\0';
196 
197 	if (verbose) {
198 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
199 		zpf("  guid: %llu", rec->guid);
200 		zpf("  mark.id: %llu", rec->mark_id);
201 		zpf("  payload.len: %llu", rec->payload_len);
202 		if (rec->payload_len)
203 			zev_print_mark_payload(rec);
204 		znl();
205 	} else {
206 		printf("%s %s: guid=%llu mark_id=%lld payload_len=%ld\n",
207 		       ct, zev_op_name[rec->op - ZEV_OP_MIN], rec->guid,
208 		       rec->mark_id, rec->payload_len);
209 	}
210 }
211 
212 static void
213 zev_print_zfs_mount(char *buf)
214 {
215 	zev_zfs_mount_t *rec = (zev_zfs_mount_t *)buf;
216 	time_t op_time = rec->op_time;
217 	char *ct = ctime(&op_time); ct[24] = '\0';
218 
219 	if (verbose) {
220 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
221 		zpf("  guid: %llu", rec->guid);
222 		zpf("  dataset: %s", ZEV_DATASET(rec));
223 		zpf("  mountpoint: %s", ZEV_MOUNTPOINT(rec));
224 		zpf("  remount: %s", rec->remount ? "true" : "false");
225 		zev_print_inode_info("root", &rec->root);
226 		znl();
227 	} else {
228 		printf("%s %s: guid=%llu remount=%s dataset='%s' "
229 		       "mountpoint='%s'\n",
230 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
231 		       rec->guid,
232 		       rec->remount ? "true" : "false",
233 		       ZEV_DATASET(rec),
234 		       ZEV_MOUNTPOINT(rec));
235 	}
236 }
237 
238 static void
239 zev_print_zfs_umount(char *buf)
240 {
241 	zev_zfs_umount_t *rec = (zev_zfs_umount_t *)buf;
242 	time_t op_time = rec->op_time;
243 	char *ct = ctime(&op_time); ct[24] = '\0';
244 
245 	if (verbose) {
246 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
247 		zpf("  guid: %llu", rec->guid);
248 		znl();
249 	} else {
250 		printf("%s %s: guid=%llu\n",
251 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
252 		       rec->guid);
253 	}
254 }
255 
256 static void
257 zev_print_zvol_truncate(char *buf)
258 {
259 	zev_zvol_truncate_t *rec = (zev_zvol_truncate_t *)buf;
260 	time_t op_time = rec->op_time;
261 	char *ct = ctime(&op_time); ct[24] = '\0';
262 
263 	if (verbose) {
264 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
265 		zpf("  guid: %llu", rec->guid);
266 		zpf("  txg: %llu", rec->txg);
267 		zpf("  offset: %llu", rec->offset);
268 		zpf("  length: %llu", rec->length);
269 		znl();
270 	} else {
271 		printf("%s %s: guid=%llu offset=%llu length=%llu\n",
272 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
273 		       rec->guid,
274 		       rec->offset,
275 		       rec->length);
276 	}
277 }
278 
279 static void
280 zev_print_zvol_write(char *buf)
281 {
282 	zev_print_zvol_truncate(buf);
283 }
284 
285 static void
286 zev_print_znode_close_after_update(char *buf)
287 {
288 	zev_znode_close_after_update_t *rec =
289 	    (zev_znode_close_after_update_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 		zev_print_inode_info("file", &rec->file);
297 		znl();
298 	} else {
299 		printf("%s %s: guid=%llu file=%llu.%llu\n",
300 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
301 		       rec->guid,
302 		       rec->file.ino, rec->file.gen);
303 	}
304 }
305 
306 static void
307 zev_print_znode_create(char *buf)
308 {
309 	zev_znode_create_t *rec = (zev_znode_create_t *)buf;
310 	time_t op_time = rec->op_time;
311 	char *ct = ctime(&op_time); ct[24] = '\0';
312 	zev_sig_t *sig;
313 	char sigval[(SHA1_DIGEST_LENGTH * 2) + 1];
314 
315 	if (verbose) {
316 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
317 		zpf("  guid: %llu", rec->guid);
318 		zpf("  txg: %llu", rec->txg);
319 		zpf("  name: '%s'", ZEV_NAME(rec));
320 		sig = &rec->signature;
321 		sig2hex_direct(sig->value, sigval);
322 		zpf("  sig: level %d, offset %llu, value %s",
323 		    sig->level, sig->block_offset, sigval);
324 		zev_print_inode_info("file", &rec->file);
325 		zev_print_inode_info("parent", &rec->parent);
326 		znl();
327 	} else {
328 		printf("%s %s: guid=%llu parent=%llu.%llu file=%llu.%llu "
329 		       "file.mtime=%llu, parent.mtime=%llu, name='%s'\n",
330 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
331 		       rec->guid,
332 		       rec->parent.ino, rec->parent.gen,
333 		       rec->file.ino, rec->file.gen,
334 		       rec->file.mtime, rec->parent.mtime,
335 		       ZEV_NAME(rec));
336 	}
337 }
338 
339 static void
340 zev_print_znode_mkdir(char *buf)
341 {
342 	zev_print_znode_create(buf);
343 }
344 
345 static void
346 zev_print_znode_make_xattr_dir(char *buf)
347 {
348 	zev_print_znode_create(buf);
349 }
350 
351 static void
352 zev_print_znode_remove(char *buf)
353 {
354 	zev_znode_remove_t *rec = (zev_znode_remove_t *)buf;
355 	time_t op_time = rec->op_time;
356 	char *ct = ctime(&op_time); ct[24] = '\0';
357 
358 	if (verbose) {
359 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
360 		zpf("  guid: %llu", rec->guid);
361 		zpf("  txg: %llu", rec->txg);
362 		zpf("  file.name: '%s'", ZEV_NAME(rec));
363 		zev_print_inode_info("file", &rec->file);
364 		zev_print_inode_info("parent", &rec->parent);
365 		znl();
366 	} else {
367 		printf("%s %s: guid=%llu parent=%llu.%llu "
368 		       "file.mtime=%llu name='%s'\n",
369 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
370 		       rec->guid,
371 		       rec->parent.ino, rec->parent.gen,
372 		       rec->file.mtime,
373 		       ZEV_NAME(rec));
374 	}
375 }
376 
377 static void
378 zev_print_znode_rmdir(char *buf)
379 {
380 	zev_print_znode_remove(buf);
381 }
382 
383 static void
384 zev_print_znode_link(char *buf)
385 {
386 	zev_znode_link_t *rec = (zev_znode_link_t *)buf;
387 	time_t op_time = rec->op_time;
388 	char *ct = ctime(&op_time); ct[24] = '\0';
389 
390 	if (verbose) {
391 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
392 		zpf("  guid: %llu", rec->guid);
393 		zpf("  txg: %llu", rec->txg);
394 		zpf("  link.name: '%s'", ZEV_NAME(rec));
395 		zev_print_inode_info("file", &rec->file);
396 		zev_print_inode_info("parent", &rec->parent);
397 		znl();
398 	} else {
399 		printf("%s %s: parent=%llu.%llu file=%llu.%llu "
400 		       "file.ctime=%llu parent.ctime=%llu name='%s'\n",
401 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
402 		       rec->parent.ino, rec->parent.gen,
403 		       rec->file.ino, rec->file.gen,
404 		       rec->file.ctime, rec->parent.ctime,
405 		       ZEV_NAME(rec));
406 	}
407 }
408 
409 static void
410 zev_print_znode_symlink(char *buf)
411 {
412 	zev_znode_symlink_t *rec = (zev_znode_symlink_t *)buf;
413 	time_t op_time = rec->op_time;
414 	char *ct = ctime(&op_time); ct[24] = '\0';
415 	zev_sig_t *sig;
416 	char sigval[(SHA1_DIGEST_LENGTH * 2) + 1];
417 
418 	if (verbose) {
419 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
420 		zpf("  guid: %llu", rec->guid);
421 		zpf("  txg: %llu", rec->txg);
422 		zpf("  symlink.name: '%s'", ZEV_NAME(rec));
423 		zpf("  symlink.link: '%s'", ZEV_LINK(rec));
424 		sig = &rec->signature;
425 		sig2hex_direct(sig->value, sigval);
426 		zpf("  sig: level %d, offset %llu, value %s",
427 		    sig->level, sig->block_offset, sigval);
428 		zev_print_inode_info("file", &rec->file);
429 		zev_print_inode_info("parent", &rec->parent);
430 		znl();
431 	} else {
432 		printf("%s %s: parent=%llu.%llu file=%llu.%llu "
433 		       "name='%s' link='%s'\n",
434 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
435 		       rec->parent.ino, rec->parent.gen,
436 		       rec->file.ino, rec->file.gen,
437 		       ZEV_NAME(rec),
438 		       ZEV_LINK(rec));
439 	}
440 }
441 
442 static void
443 zev_print_znode_rename(char *buf)
444 {
445 	zev_znode_rename_t *rec = (zev_znode_rename_t *)buf;
446 	time_t op_time = rec->op_time;
447 	char *ct = ctime(&op_time); ct[24] = '\0';
448 
449 	if (verbose) {
450 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
451 		zpf("  guid: %llu", rec->guid);
452 		zpf("  txg: %llu", rec->txg);
453 		zpf("  file.srcname: '%s'", ZEV_SRCNAME(rec));
454 		zpf("  file.dstname: '%s'", ZEV_DSTNAME(rec));
455 		zev_print_inode_info("file", &rec->file);
456 		zev_print_inode_info("srcdir", &rec->srcdir);
457 		zev_print_inode_info("dstdir", &rec->dstdir);
458 		znl();
459 	} else {
460 		printf("%s %s: srcdir=%llu.%llu dstdir=%llu.%llu "
461 		       "file=%llu.%llu file.mtime=%llu, file.ctime=%llu, "
462 		       "srcdir.mtime=%llu, srcdir.ctime=%llu, "
463 		       "dstdir.mtime=%llu, dstdir.ctime=%llu, "
464 		       "srcname='%s' dstname='%s'\n",
465 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
466 		       rec->srcdir.ino, rec->srcdir.gen,
467 		       rec->dstdir.ino, rec->dstdir.gen,
468 		       rec->file.ino, rec->file.gen,
469 		       rec->file.mtime, rec->file.ctime,
470 		       rec->srcdir.mtime, rec->srcdir.ctime,
471 		       rec->dstdir.mtime, rec->dstdir.ctime,
472 		       ZEV_SRCNAME(rec),
473 		       ZEV_DSTNAME(rec));
474 	}
475 }
476 
477 static void
478 zev_print_znode_write(char *buf)
479 {
480 	zev_znode_write_t *rec = (zev_znode_write_t *)buf;
481 	time_t op_time = rec->op_time;
482 	char *ct = ctime(&op_time); ct[24] = '\0';
483 	zev_sig_t *sig;
484 	char sigval[(SHA1_DIGEST_LENGTH * 2) + 1];
485 	int i;
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("  offset: %llu", rec->offset);
492 		zpf("  length: %llu", rec->length);
493 		zev_print_inode_info("file", &rec->file);
494 		znl();
495 		for (i=0; i<rec->signature_cnt; i++) {
496 			sig = (zev_sig_t *)ZEV_SIGNATURES(rec);
497 			sig += i;
498 			sig2hex_direct(sig->value, sigval);
499 			zpf("  sig: level %d, offset %llu, value %s",
500 			    sig->level, sig->block_offset, sigval);
501 		}
502 	} else {
503 		printf("%s %s: file=%llu.%llu offset=%llu length=%llu\n",
504 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
505 		       rec->file.ino, rec->file.gen,
506 		       rec->offset, rec->length);
507 	}
508 }
509 
510 static void
511 zev_print_znode_truncate(char *buf)
512 {
513 	zev_print_znode_write(buf);
514 }
515 
516 static void
517 zev_print_znode_setattr(char *buf)
518 {
519 	zev_znode_setattr_t *rec = (zev_znode_setattr_t *)buf;
520 	time_t op_time = rec->op_time;
521 	char *ct = ctime(&op_time); ct[24] = '\0';
522 
523 	if (verbose) {
524 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
525 		zpf("  guid: %llu", rec->guid);
526 		zpf("  txg: %llu", rec->txg);
527 		zev_print_inode_info("file", &rec->file);
528 		znl();
529 	} else {
530 		printf("%s %s: file=%llu.%llu mtime=%llu\n",
531 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
532 		       rec->file.ino, rec->file.gen, rec->file.mtime);
533 	}
534 }
535 
536 static void
537 zev_print_znode_acl(char *buf)
538 {
539 	zev_print_znode_setattr(buf);
540 }
541 
542 static void
543 zev_print_event(char *buf, int len)
544 {
545 	int record_len;
546 	int op;
547 
548 	record_len = *(uint32_t *)buf;
549 	if (record_len != len) {
550 		fprintf(stderr, "record length mismatch: got %d, expected %d\n",
551 		        record_len, len);
552 		exit(1);
553 	}
554 	op = *((uint32_t *)buf + 1);
555 	if (op < ZEV_OP_MIN || op > ZEV_OP_MAX) {
556 		fprintf(stderr, "unknown op code: %d\n", op);
557 		exit(1);
558 	}
559 	switch (op) {
560 	case ZEV_OP_ERROR:
561 		zev_print_error(buf);
562 		break;
563 	case ZEV_OP_MARK:
564 		zev_print_mark(buf);
565 		break;
566 	case ZEV_OP_ZFS_MOUNT:
567 		zev_print_zfs_mount(buf);
568 		break;
569 	case ZEV_OP_ZFS_UMOUNT:
570 		zev_print_zfs_umount(buf);
571 		break;
572 	case ZEV_OP_ZVOL_TRUNCATE:
573 		zev_print_zvol_truncate(buf);
574 		break;
575 	case ZEV_OP_ZVOL_WRITE:
576 		zev_print_zvol_write(buf);
577 		break;
578 	case ZEV_OP_ZNODE_CLOSE_AFTER_UPDATE:
579 		zev_print_znode_close_after_update(buf);
580 		break;
581 	case ZEV_OP_ZNODE_CREATE:
582 		zev_print_znode_create(buf);
583 		break;
584 	case ZEV_OP_ZNODE_MKDIR:
585 		zev_print_znode_mkdir(buf);
586 		break;
587 	case ZEV_OP_ZNODE_MAKE_XATTR_DIR:
588 		zev_print_znode_make_xattr_dir(buf);
589 		break;
590 	case ZEV_OP_ZNODE_REMOVE:
591 		zev_print_znode_remove(buf);
592 		break;
593 	case ZEV_OP_ZNODE_RMDIR:
594 		zev_print_znode_rmdir(buf);
595 		break;
596 	case ZEV_OP_ZNODE_LINK:
597 		zev_print_znode_link(buf);
598 		break;
599 	case ZEV_OP_ZNODE_SYMLINK:
600 		zev_print_znode_symlink(buf);
601 		break;
602 	case ZEV_OP_ZNODE_RENAME:
603 		zev_print_znode_rename(buf);
604 		break;
605 	case ZEV_OP_ZNODE_WRITE:
606 		zev_print_znode_write(buf);
607 		break;
608 	case ZEV_OP_ZNODE_TRUNCATE:
609 		zev_print_znode_truncate(buf);
610 		break;
611 	case ZEV_OP_ZNODE_SETATTR:
612 		zev_print_znode_setattr(buf);
613 		break;
614 	case ZEV_OP_ZNODE_ACL:
615 		zev_print_znode_acl(buf);
616 		break;
617 	default:
618 		fprintf(stderr, "unhandled op code: %d\n", op);
619 		exit(1);
620 	}
621 }
622 
623 static int
624 zev_poll_events(int fd, int create_tmp_queue)
625 {
626 	struct pollfd pfd[1];
627 	int ret;
628 	char buf[4096];
629 	zev_event_t *ev;
630 	int off = 0;
631 	zev_ioctl_add_queue_t aq;
632 	int q_fd;
633 
634 	if (create_tmp_queue) {
635 		aq.zev_max_queue_len = 0;
636 		aq.zev_flags = ZEV_FL_BLOCK_WHILE_QUEUE_FULL;
637 		snprintf(aq.zev_name, ZEV_MAX_QUEUE_NAME_LEN,
638 			 "zevadm.%ld.%ld", time(NULL), getpid());
639 		aq.zev_namelen = strlen(aq.zev_name);
640 
641 		if (ioctl(fd, ZEV_IOC_ADD_QUEUE, &aq)) {
642 			perror("adding temporary queue failed");
643 			return (EXIT_FAILURE);
644 		}
645 
646 		snprintf(buf, sizeof(buf),
647 		         "/devices/pseudo/zev@0:%s", aq.zev_name);
648 		q_fd = open(buf, O_RDONLY);
649 		if (q_fd < 0) {
650 			perror("opening queue device failed");
651 			return (EXIT_FAILURE);
652 		}
653 	} else {
654 		q_fd = fd;
655 	}
656 
657 	while (1) {
658 		pfd[0].fd = q_fd;
659 		pfd[0].events = POLLIN;
660 		ret = poll(pfd, 1, 1000);
661 		if (ret < 0) {
662 			perror("poll failed");
663 			close(q_fd);
664 			return(EXIT_FAILURE);
665 		}
666 		if (!(pfd[0].revents & POLLIN))
667 			continue;
668 		/* data available */
669 		ret = read(q_fd, buf, sizeof(buf));
670 		if (ret < 0) {
671 			perror("read failed");
672 			close(q_fd);
673 			return(EXIT_FAILURE);
674 		}
675 		if (ret == 0)
676 			continue;
677 		while (ret > off) {
678 			ev = (zev_event_t *)(buf + off);
679 			zev_print_event(buf + off, ev->header.record_len);
680 			off += ev->header.record_len;
681 		}
682 		off = 0;
683 	}
684 	if (create_tmp_queue)
685 		close(q_fd);
686 	return EXIT_SUCCESS;
687 }
688 
689 static void
690 usage(char *progname)
691 {
692 	fprintf(stderr, "usage: %s [-d <dev>] [options]\n", progname);
693 	fprintf(stderr, "\n");
694 	fprintf(stderr, " Status information:\n");
695 	fprintf(stderr, "   -s                   show zev statistics\n");
696 	fprintf(stderr, "   -p                   poll for ZFS events\n");
697 	fprintf(stderr, "   -D                   print zev module debug "
698 	        "information\n");
699 	fprintf(stderr, "\n");
700 	fprintf(stderr, " Tune zev module settings:\n");
701 	fprintf(stderr, "   -Q <bytes>           set maximum event queue "
702 	        "length\n");
703 	fprintf(stderr, "   -m <pool>            mute pool, no events for "
704 	        "this pool\n");
705 	fprintf(stderr, "   -M <pool>            unmute pool\n");
706 	fprintf(stderr, "\n");
707 	fprintf(stderr, " Queue management:\n");
708 	fprintf(stderr, "   -l                   list queues\n");
709 	fprintf(stderr, "   -a <name>            add non-blocking queue\n");
710 	fprintf(stderr, "   -A <name>            add blocking queue\n");
711 	fprintf(stderr, "   -r <name>            remove queue\n");
712 	fprintf(stderr, "   -b <name>            make queue non-blocking "
713 	        "(default)\n");
714 	fprintf(stderr, "   -B <name>            make queue block when full\n");
715 	fprintf(stderr, "   -P <name>            display queue properties\n");
716 	fprintf(stderr, "   -L <name> <bytes>    set maximum event queue "
717 	        "length\n");
718 	fprintf(stderr, "   -t <name> <bytes>    set queue length poll "
719 	        "throttle\n");
720 	fprintf(stderr, "\n");
721 	fprintf(stderr, " Other options:\n");
722 	fprintf(stderr, "   -d <dev>             non-default device file. "
723 	        "('%s')\n", ZEV_DEVICE);
724 	fprintf(stderr, "   -q <name>            use device file for this "
725 		"queue name\n");
726 	fprintf(stderr, "   -k <guid>:<payload>  queue mark event\n");
727 	fprintf(stderr, "   -c <filename>        list file's content "
728 		"checksums\n");
729 	fprintf(stderr, "   -v                   verbose: additional output "
730 	        "for some operations\n");
731 	fprintf(stderr, "   -g                   grep-friendly event output, "
732 	        "one event per line\n");
733 	exit (EXIT_FAILURE);
734 }
735 
736 static int
737 zev_add_queue(int fd, char *arg, int blocking)
738 {
739 	zev_ioctl_add_queue_t aq;
740 	int namelen;
741 
742 	namelen = strlen(arg);
743 	if (namelen > ZEV_MAX_QUEUE_NAME_LEN) {
744 		fprintf(stderr, "queue name too long: %s\n", arg);
745 		return (EXIT_FAILURE);
746 	}
747 
748 	aq.zev_namelen = namelen;
749 	strcpy(aq.zev_name, arg);
750 	aq.zev_flags = ZEV_FL_PERSISTENT;
751 	if (blocking) {
752 		aq.zev_flags |= ZEV_FL_BLOCK_WHILE_QUEUE_FULL;
753 		aq.zev_max_queue_len = ZEV_MAX_QUEUE_LEN;
754 	} else {
755 		aq.zev_max_queue_len = (1024 * 1024);
756 	}
757 
758 	if (ioctl(fd, ZEV_IOC_ADD_QUEUE, &aq)) {
759 		perror("adding queue failed");
760 		return (EXIT_FAILURE);
761 	}
762 	return (0);
763 }
764 
765 static int
766 zev_remove_queue(int fd, char *arg)
767 {
768 	zev_ioctl_remove_queue_t aq;
769 	int namelen;
770 
771 	namelen = strlen(arg);
772 	if (namelen > ZEV_MAX_QUEUE_NAME_LEN) {
773 		fprintf(stderr, "queue name too long: %s\n", arg);
774 		return (EXIT_FAILURE);
775 	}
776 
777 	aq.zev_queue_name.zev_namelen = namelen;
778 	strcpy(aq.zev_queue_name.zev_name, arg);
779 
780 	if (ioctl(fd, ZEV_IOC_REMOVE_QUEUE, &aq)) {
781 		perror("removing queue failed");
782 		return (EXIT_FAILURE);
783 	}
784 	return (0);
785 }
786 
787 static int
788 zev_set_global_max_queue_len(int fd, char *arg)
789 {
790 	uint64_t maxqueuelen;
791 
792 	errno = 0;
793 	maxqueuelen = strtol(arg, (char **)NULL, 10);
794 	if (errno) {
795 		fprintf(stderr, "invalid queue length parameter: %s\n", arg);
796 		return (EXIT_FAILURE);
797 	}
798 	if (ioctl(fd, ZEV_IOC_SET_MAX_QUEUE_LEN, &maxqueuelen)) {
799 		perror("setting max queue length failed");
800 		return (EXIT_FAILURE);
801 	}
802 	return (0);
803 }
804 
805 static int
806 zev_mute_unmute_impl(int fd, char *poolname, int mute)
807 {
808 	zev_ioctl_poolarg_t pa;
809 	int len;
810 	int op = mute ? ZEV_IOC_MUTE_POOL : ZEV_IOC_UNMUTE_POOL;
811 	len = strlen(poolname);
812 	if (len <= 0 || len >= sizeof(pa.zev_poolname)) {
813 		fprintf(stderr, "invalid poolname: %s\n", poolname);
814 		return (EXIT_FAILURE);
815 	}
816 	strcpy(pa.zev_poolname, poolname);
817 	pa.zev_poolname_len = len;
818 	if (ioctl(fd, op, &pa)) {
819 		perror("muting pool data failed");
820 		return (EXIT_FAILURE);
821 	}
822 	return (0);
823 }
824 
825 int
826 zev_mute_pool(int fd, char *poolname)
827 {
828 	return zev_mute_unmute_impl(fd, poolname, 1);
829 }
830 
831 int
832 zev_unmute_pool(int fd, char *poolname)
833 {
834 	return zev_mute_unmute_impl(fd, poolname, 0);
835 }
836 
837 static int
838 zev_debug_info(int fd)
839 {
840 	zev_ioctl_debug_info_t di;
841 
842 	if (ioctl(fd, ZEV_IOC_GET_DEBUG_INFO, &di)) {
843 		perror("getting zev debug info failed");
844 		return (EXIT_FAILURE);
845 	}
846 
847 	printf("memory allocated: %llu bytes\n", di.zev_memory_allocated);
848 	printf("checksum cache size: %llu\n", di.zev_chksum_cache_size);
849 	printf("checksum cache hits: %llu\n", di.zev_chksum_cache_hits);
850 	printf("checksum cache misses: %llu\n", di.zev_chksum_cache_misses);
851 	return 0;
852 }
853 
854 static int
855 zev_mark(int fd, char *arg)
856 {
857 	zev_ioctl_mark_t *mark;
858 	uint64_t guid;
859 	int len;
860 	char *p;
861 
862 	p = strchr(arg, ':');
863 	if (!p) {
864 		fprintf(stderr, "expected value is <guid>:<payload>, "
865 		        "e.g. '123:hello'\n");
866 		exit (EXIT_FAILURE);
867 	}
868 	*p = '\n';
869 	p++;
870 
871 	errno = 0;
872 	guid = strtoll(arg, (char **)NULL, 10);
873 	if (errno) {
874 		fprintf(stderr, "guid must be a number.\n");
875 		exit (EXIT_FAILURE);
876 	}
877 
878 	len = strlen(p);
879 
880 	mark = malloc(sizeof(*mark) + len + 1);
881 	if (!mark) {
882 		fprintf(stderr, "can't allocate mark structure: %s\n",
883 		        strerror(errno));
884 		exit (EXIT_FAILURE);
885 	}
886 	mark->zev_guid = guid;
887 	mark->zev_mark_id = 0;
888 	mark->zev_payload_len = len;
889 	strcpy(ZEV_PAYLOAD(mark), p);
890 
891 	if (ioctl(fd, ZEV_IOC_MARK, mark)) {
892 		perror("queueing mark failed");
893 		return (EXIT_FAILURE);
894 	}
895 
896 	printf("mark id: %lu\n", mark->zev_mark_id);
897 	return (0);
898 }
899 
900 static int
901 zev_queue_blocking(int fd, char *arg, int block)
902 {
903 	zev_ioctl_get_queue_properties_t gqp;
904 
905 	gqp.zev_queue_name.zev_namelen = strlen(arg);
906 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
907 		fprintf(stderr, "queue name too long.\n");
908 		return EXIT_FAILURE;
909 	}
910 	strcpy(gqp.zev_queue_name.zev_name, arg);
911 
912 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
913 		perror("getting queue properties failed");
914 		return (EXIT_FAILURE);
915 	}
916 	if (block) {
917 		gqp.zev_flags |= ZEV_FL_BLOCK_WHILE_QUEUE_FULL;
918 	} else {
919 		gqp.zev_flags &= ~ZEV_FL_BLOCK_WHILE_QUEUE_FULL;
920 	}
921 	if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) {
922 		perror("setting queue properties failed");
923 		return (EXIT_FAILURE);
924 	}
925 	return (0);
926 }
927 
928 static int
929 zev_set_max_queue_len(int fd, char *arg, char *len)
930 {
931 	zev_ioctl_get_queue_properties_t gqp;
932 
933 	if (!len) {
934 		fprintf(stderr, "queue size parameter missing.\n");
935 		return EXIT_FAILURE;
936 	}
937 
938 	gqp.zev_queue_name.zev_namelen = strlen(arg);
939 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
940 		fprintf(stderr, "queue name too long.\n");
941 		return EXIT_FAILURE;
942 	}
943 	strcpy(gqp.zev_queue_name.zev_name, arg);
944 
945 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
946 		perror("getting queue properties failed");
947 		return (EXIT_FAILURE);
948 	}
949 	gqp.zev_max_queue_len = atol(len);
950 	if (gqp.zev_max_queue_len == 0 && strcmp("0", len)) {
951 		fprintf(stderr, "queue size parameter garbled.\n");
952 		return (EXIT_FAILURE);
953 	}
954 	if (gqp.zev_max_queue_len > ZEV_MAX_QUEUE_LEN) {
955 		fprintf(stderr, "queue size parameter out of bounds.\n");
956 		return (EXIT_FAILURE);
957 	}
958 
959 	if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) {
960 		perror("setting queue properties failed");
961 		return (EXIT_FAILURE);
962 	}
963 	return (0);
964 }
965 
966 static int
967 zev_set_poll_wakeup_queue_len(int fd, char *arg, char *len)
968 {
969 	zev_ioctl_get_queue_properties_t gqp;
970 
971 	if (!len) {
972 		fprintf(stderr, "poll throttle parameter missing.\n");
973 		return EXIT_FAILURE;
974 	}
975 
976 	gqp.zev_queue_name.zev_namelen = strlen(arg);
977 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
978 		fprintf(stderr, "queue name too long.\n");
979 		return EXIT_FAILURE;
980 	}
981 	strcpy(gqp.zev_queue_name.zev_name, arg);
982 
983 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
984 		perror("getting queue properties failed");
985 		return (EXIT_FAILURE);
986 	}
987 	gqp.zev_poll_wakeup_threshold = atol(len);
988 	if (gqp.zev_poll_wakeup_threshold == 0 && strcmp("0", len)) {
989 		fprintf(stderr, "poll throttle parameter garbled.\n");
990 		return (EXIT_FAILURE);
991 	}
992 	if (gqp.zev_poll_wakeup_threshold > ZEV_MAX_POLL_WAKEUP_QUEUE_LEN) {
993 		fprintf(stderr, "poll throttle parameter out of bounds.\n");
994 		return (EXIT_FAILURE);
995 	}
996 
997 	if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) {
998 		perror("setting queue properties failed");
999 		return (EXIT_FAILURE);
1000 	}
1001 	return (0);
1002 }
1003 
1004 static int
1005 zev_queue_properties(int fd, char *arg)
1006 {
1007 	zev_ioctl_get_queue_properties_t gqp;
1008 
1009 	gqp.zev_queue_name.zev_namelen = strlen(arg);
1010 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
1011 		fprintf(stderr, "queue name too long.\n");
1012 		return EXIT_FAILURE;
1013 	}
1014 	strcpy(gqp.zev_queue_name.zev_name, arg);
1015 
1016 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
1017 		perror("getting queue properties failed");
1018 		return (EXIT_FAILURE);
1019 	}
1020 
1021 	printf("queue        : %s\n", arg);
1022 	printf("max size     : %" PRIu64 "\n", gqp.zev_max_queue_len);
1023 	printf("poll throttle: %" PRIu64 "\n", gqp.zev_poll_wakeup_threshold);
1024 	printf("persistent   : %s\n",
1025 		gqp.zev_flags & ZEV_FL_PERSISTENT ? "yes" : "no");
1026 	printf("blocking     : %s\n",
1027 		gqp.zev_flags & ZEV_FL_BLOCK_WHILE_QUEUE_FULL ? "yes" : "no");
1028 
1029 	return (0);
1030 }
1031 
1032 static int
1033 zev_list_queues(int fd)
1034 {
1035 	zev_ioctl_get_queue_properties_t gqp;
1036 	zev_ioctl_get_queue_list_t gql;
1037 	zev_ioctl_get_queue_statistics_t gs;
1038 	uint64_t	i;
1039 	char		name[ZEV_MAX_QUEUE_NAME_LEN+1];
1040 
1041 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_LIST, &gql)) {
1042 		perror("getting queue list failed");
1043 		return (EXIT_FAILURE);
1044 	}
1045 
1046 	printf("Name                                     Size       "
1047 	       "Max Size   Wakeup Per Block\n");
1048 
1049 	for (i=0; i<gql.zev_n_queues; i++) {
1050 		strncpy(name, gql.zev_queue_name[i].zev_name,
1051 		        ZEV_MAX_QUEUE_NAME_LEN);
1052 		name[gql.zev_queue_name[i].zev_namelen] = '\0';
1053 
1054 		memcpy(gqp.zev_queue_name.zev_name,
1055 		    gql.zev_queue_name[i].zev_name, ZEV_MAX_QUEUE_NAME_LEN);
1056 		gqp.zev_queue_name.zev_namelen =
1057 		    gql.zev_queue_name[i].zev_namelen;
1058 
1059 		if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
1060 			if (errno == ENOENT)
1061 				continue;
1062 			perror("getting queue properties failed");
1063 			return (EXIT_FAILURE);
1064 		}
1065 
1066 		memcpy(gs.zev_queue_name.zev_name,
1067 		    gql.zev_queue_name[i].zev_name, ZEV_MAX_QUEUE_NAME_LEN);
1068 		gs.zev_queue_name.zev_namelen =
1069 		    gql.zev_queue_name[i].zev_namelen;
1070 
1071 		if (ioctl(fd, ZEV_IOC_GET_QUEUE_STATISTICS, &gs)) {
1072 			if (errno == ENOENT)
1073 				continue;
1074 			perror("getting statistics data failed");
1075 			return (EXIT_FAILURE);
1076 		}
1077 
1078 		printf("%-40s %-10" PRIu64 " %-10" PRIu64 " %-6" PRIu64
1079 		       " %-3s %-3s\n",
1080 			name,
1081 			gs.zev_statistics.zev_queue_len,
1082 			gqp.zev_max_queue_len,
1083 			gqp.zev_poll_wakeup_threshold,
1084 			gqp.zev_flags & ZEV_FL_PERSISTENT ? "yes" : "no",
1085 			gqp.zev_flags & ZEV_FL_BLOCK_WHILE_QUEUE_FULL ?
1086 				 "yes" : "no");
1087 	}
1088 
1089 	return (0);
1090 }
1091 
1092 static int
1093 zev_checksum(int dev_fd, char *filename)
1094 {
1095 	int fd;
1096 	offset_t off;
1097 	offset_t data;
1098 	zev_sig_t *sig;
1099 	char *buf;
1100 	zev_ioctl_get_signatures_t *gs;
1101 	int i;
1102 	char sigval[(SHA1_DIGEST_LENGTH * 2) + 1];
1103 	int buf_size;
1104 
1105 	/* control struct, one lv1 signature and up to 256 lv0 signatures */
1106 	buf_size = (1 + 256) * sizeof(zev_sig_t);
1107 	buf = malloc(sizeof(zev_ioctl_get_signatures_t) + buf_size);
1108 	if (!buf) {
1109 		perror("can't allocate checksum buffer");
1110 		return (EXIT_FAILURE);
1111 	}
1112 
1113 	fd = open(filename, O_RDONLY);
1114 	if (fd < 0) {
1115 		perror("can't open file");
1116 		return (EXIT_FAILURE);
1117 	}
1118 
1119 	gs = (zev_ioctl_get_signatures_t *)buf;
1120 	gs->zev_fd = fd;
1121 	gs->zev_bufsize = buf_size;
1122 
1123 	off = 0;
1124 	data = 0;
1125 	while (1) {
1126 		errno = 0;
1127 		data = llseek(fd, off, SEEK_DATA);
1128 		if (data < 0) {
1129 			if (errno == ENXIO)	/* no more data */
1130 				break;
1131 			perror("llseek failed");
1132 			goto err;
1133 		}
1134 		data = P2ALIGN(data, ZEV_L1_SIZE);
1135 		off = data + ZEV_L1_SIZE;
1136 
1137 		gs->zev_offset = data;
1138 		gs->zev_len = ZEV_L1_SIZE;
1139 
1140 		if (ioctl(dev_fd, ZEV_IOC_GET_FILE_SIGNATURES, gs)) {
1141 			perror("ioctl to get signatures failed");
1142 			goto err;
1143 		}
1144 
1145 		for (i=0; i<gs->zev_signature_cnt; i++) {
1146 			sig = (zev_sig_t *)ZEV_SIGNATURES(gs);
1147 			sig += i;
1148 			sig2hex_direct(sig->value, sigval);
1149 			printf("level %d, offset %llu, value %s\n",
1150 			       sig->level, sig->block_offset, sigval);
1151 		}
1152 	}
1153 
1154 	free(buf);
1155 	close(fd);
1156 	return 0;
1157 err:
1158 	free(buf);
1159 	close(fd);
1160 	return (EXIT_FAILURE);
1161 }
1162 
1163 int
1164 main(int argc, char **argv)
1165 {
1166 	int fd;
1167 	int c;
1168 	extern char *optarg;
1169 	int create_tmp_queue = 1;
1170 	char buf[MAXPATHLEN];
1171 
1172 	/* open device */
1173 	fd = open(zev_device, O_RDONLY);
1174 	if (fd < 0) {
1175 		perror("opening zev device failed");
1176 		return EXIT_FAILURE;
1177 	}
1178 	while ((c = getopt(argc, argv,
1179 	                   "gvspc:d:Dlk:L:q:Qt:m:M:a:A:r:P:b:B:h?")) != -1){
1180 		switch(c) {
1181 		case 'g':
1182 			grep_friendly++;
1183 			verbose++;
1184 			break;
1185 		case 'v':
1186 			verbose++;
1187 			break;
1188 		case 's':
1189 			return zev_statistics(fd);
1190 		case 'p':
1191 			return zev_poll_events(fd, create_tmp_queue);
1192 		case 'c':
1193 			return zev_checksum(fd, optarg);
1194 		case 'D':
1195 			return zev_debug_info(fd);
1196 		case 'd':
1197 			close(fd);
1198 			zev_device = optarg;
1199 			fd = open(zev_device, O_RDONLY);
1200 			if (fd < 0) {
1201 				perror("opening zev device failed");
1202 				return EXIT_FAILURE;
1203 			}
1204 			create_tmp_queue = 0;
1205 			break;
1206 		case 'q':
1207 			snprintf(buf, sizeof(buf),
1208 				 "/devices/pseudo/zev@0:%s", optarg);
1209 			close(fd);
1210 			zev_device = buf;
1211 			fd = open(zev_device, O_RDONLY);
1212 			if (fd < 0) {
1213 				perror("opening zev device failed");
1214 				return EXIT_FAILURE;
1215 			}
1216 			create_tmp_queue = 0;
1217 			break;
1218 		case 'l':
1219 			return zev_list_queues(fd);
1220 		case 'Q':
1221 			return zev_set_global_max_queue_len(fd, optarg);
1222 		case 'L':
1223 			return zev_set_max_queue_len(fd, optarg, argv[optind]);
1224 		case 't':
1225 			return zev_set_poll_wakeup_queue_len(fd, optarg,
1226 			                                     argv[optind]);
1227 		case 'm':
1228 			return zev_mute_pool(fd, optarg);
1229 		case 'M':
1230 			return zev_unmute_pool(fd, optarg);
1231 		case 'k':
1232 			return zev_mark(fd, optarg);
1233 		case 'a':
1234 			return zev_add_queue(fd, optarg, 0);
1235 		case 'A':
1236 			return zev_add_queue(fd, optarg, 1);
1237 		case 'r':
1238 			return zev_remove_queue(fd, optarg);
1239 		case 'b':
1240 			return zev_queue_blocking(fd, optarg, 0);
1241 		case 'B':
1242 			return zev_queue_blocking(fd, optarg, 1);
1243 		case 'P':
1244 			return zev_queue_properties(fd, optarg);
1245 		case 'h':
1246 		case '?':
1247 		default:
1248 			usage(argv[0]);
1249 		}
1250 	}
1251 	usage(argv[0]);
1252 	close(fd);
1253 	return EXIT_FAILURE;
1254 }
1255 
1256