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