xref: /titanic_51/usr/src/cmd/zevadm/zevadm.c (revision d65b2fff7366993a85cb8782e3930b9fa4696e8c)
12bb8e5e2SAndreas Jaekel #include <stdio.h>
22bb8e5e2SAndreas Jaekel #include <unistd.h>
32bb8e5e2SAndreas Jaekel #include <stdlib.h>
42bb8e5e2SAndreas Jaekel #include <fcntl.h>
52bb8e5e2SAndreas Jaekel #include <stropts.h>
62bb8e5e2SAndreas Jaekel #include <poll.h>
72bb8e5e2SAndreas Jaekel #include <string.h>
82bb8e5e2SAndreas Jaekel #include <sys/fs/zev.h>
92bb8e5e2SAndreas Jaekel #include <errno.h>
10b9710123SAndreas Jaekel #include <sys/sysmacros.h>
11*d65b2fffSAndreas Jaekel #include <stdarg.h>
122bb8e5e2SAndreas Jaekel 
13e9a5e479SAndreas Jaekel #define ZEV_DEVICE "/devices/pseudo/zev@0:ctrl"
142bb8e5e2SAndreas Jaekel 
152bb8e5e2SAndreas Jaekel static char *zev_device = ZEV_DEVICE;
162bb8e5e2SAndreas Jaekel 
179193e9c2SAndreas Jaekel static char *zev_op_name[] = {
18*d65b2fffSAndreas Jaekel 	"ERROR",
19*d65b2fffSAndreas Jaekel 	"MARK",
20*d65b2fffSAndreas Jaekel 	"ZFS_MOUNT",
21*d65b2fffSAndreas Jaekel 	"ZFS_UMOUNT",
22*d65b2fffSAndreas Jaekel 	"ZVOL_WRITE",
23*d65b2fffSAndreas Jaekel 	"ZVOL_TRUNCATE",
24*d65b2fffSAndreas Jaekel 	"ZNODE_CLOSE_AFTER_UPDATE",
25*d65b2fffSAndreas Jaekel 	"ZNODE_CREATE",
26*d65b2fffSAndreas Jaekel 	"ZNODE_MKDIR",
27*d65b2fffSAndreas Jaekel 	"ZNODE_MAKE_XATTR_DIR",
28*d65b2fffSAndreas Jaekel 	"ZNODE_REMOVE",
29*d65b2fffSAndreas Jaekel 	"ZNODE_RMDIR",
30*d65b2fffSAndreas Jaekel 	"ZNODE_LINK",
31*d65b2fffSAndreas Jaekel 	"ZNODE_SYMLINK",
32*d65b2fffSAndreas Jaekel 	"ZNODE_RENAME",
33*d65b2fffSAndreas Jaekel 	"ZNODE_WRITE",
34*d65b2fffSAndreas Jaekel 	"ZNODE_TRUNCATE",
35*d65b2fffSAndreas Jaekel 	"ZNODE_SETATTR",
36*d65b2fffSAndreas Jaekel 	"ZNODE_ACL",
379193e9c2SAndreas Jaekel 	NULL
389193e9c2SAndreas Jaekel };
399193e9c2SAndreas Jaekel 
405e286361SAndreas Jaekel static int verbose = 0;
41*d65b2fffSAndreas Jaekel static int grep_friendly = 0;
42*d65b2fffSAndreas Jaekel 
43*d65b2fffSAndreas Jaekel static void
44*d65b2fffSAndreas Jaekel zpf(char *fmt, ...)
45*d65b2fffSAndreas Jaekel {
46*d65b2fffSAndreas Jaekel 	va_list	ap;
47*d65b2fffSAndreas Jaekel 
48*d65b2fffSAndreas Jaekel 	va_start(ap, fmt);
49*d65b2fffSAndreas Jaekel 	vprintf(fmt, ap);
50*d65b2fffSAndreas Jaekel 	va_end(ap);
51*d65b2fffSAndreas Jaekel 	if (grep_friendly) {
52*d65b2fffSAndreas Jaekel 		printf(" ");
53*d65b2fffSAndreas Jaekel 	} else {
54*d65b2fffSAndreas Jaekel 		printf("\n");
55*d65b2fffSAndreas Jaekel 	}
56*d65b2fffSAndreas Jaekel }
57*d65b2fffSAndreas Jaekel 
58*d65b2fffSAndreas Jaekel static void
59*d65b2fffSAndreas Jaekel znl(void)
60*d65b2fffSAndreas Jaekel {
61*d65b2fffSAndreas Jaekel 	if (grep_friendly)
62*d65b2fffSAndreas Jaekel 		printf("\n");
63*d65b2fffSAndreas Jaekel }
645e286361SAndreas Jaekel 
65e9a5e479SAndreas Jaekel static int
662bb8e5e2SAndreas Jaekel zev_statistics(int fd)
672bb8e5e2SAndreas Jaekel {
682bb8e5e2SAndreas Jaekel 	zev_statistics_t zs;
69e9a5e479SAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_GET_GLOBAL_STATISTICS, &zs)) {
702bb8e5e2SAndreas Jaekel 		perror("getting statistics data failed");
71e9a5e479SAndreas Jaekel 		return (EXIT_FAILURE);
722bb8e5e2SAndreas Jaekel 	}
732bb8e5e2SAndreas Jaekel 	printf("ZEV module state:\n");
742bb8e5e2SAndreas Jaekel 
752bb8e5e2SAndreas Jaekel 	printf("    queue length in bytes   : %lu\n", zs.zev_queue_len);
762bb8e5e2SAndreas Jaekel 	printf("    queue length limit      : %lu\n", zs.zev_max_queue_len);
772bb8e5e2SAndreas Jaekel 	printf("    bytes read from device  : %lu\n", zs.zev_bytes_read);
782bb8e5e2SAndreas Jaekel 	printf("    module internal errors  : %lu\n\n", zs.zev_cnt_errors);
792bb8e5e2SAndreas Jaekel 
80e9a5e479SAndreas Jaekel 	printf("    discarded events        : %lu\n",
81e9a5e479SAndreas Jaekel 	    zs.zev_cnt_discarded_events);
82e9a5e479SAndreas Jaekel 	printf("    discarded bytes         : %lu\n\n", zs.zev_bytes_discarded);
83e9a5e479SAndreas Jaekel 
842bb8e5e2SAndreas Jaekel 	printf("ZFS event statistics:\n");
852bb8e5e2SAndreas Jaekel 
862bb8e5e2SAndreas Jaekel 	printf("    total ZFS events        : %lu\n", zs.zev_cnt_total_events);
872bb8e5e2SAndreas Jaekel 	printf("    ZFS mount               : %lu\n", zs.zev_cnt_zfs_mount);
882bb8e5e2SAndreas Jaekel 	printf("    ZFS umount              : %lu\n", zs.zev_cnt_zfs_umount);
892bb8e5e2SAndreas Jaekel 	printf("    ZVOL write              : %lu\n", zs.zev_cnt_zvol_write);
902bb8e5e2SAndreas Jaekel 	printf("    ZVOL truncate           : %lu\n", zs.zev_cnt_zvol_truncate);
912bb8e5e2SAndreas Jaekel 	printf("    ZNODE close after update: %lu\n",
922bb8e5e2SAndreas Jaekel 	    zs.zev_cnt_znode_close_after_update);
932bb8e5e2SAndreas Jaekel 	printf("    ZNODE create            : %lu\n", zs.zev_cnt_znode_create);
942bb8e5e2SAndreas Jaekel 	printf("    ZNODE remove            : %lu\n", zs.zev_cnt_znode_remove);
952bb8e5e2SAndreas Jaekel 	printf("    ZNODE link              : %lu\n", zs.zev_cnt_znode_link);
962bb8e5e2SAndreas Jaekel 	printf("    ZNODE symlink           : %lu\n", zs.zev_cnt_znode_symlink);
972bb8e5e2SAndreas Jaekel 	printf("    ZNODE rename            : %lu\n", zs.zev_cnt_znode_rename);
982bb8e5e2SAndreas Jaekel 	printf("    ZNODE write             : %lu\n", zs.zev_cnt_znode_write);
992bb8e5e2SAndreas Jaekel 	printf("    ZNODE truncate          : %lu\n",
1002bb8e5e2SAndreas Jaekel 	    zs.zev_cnt_znode_truncate);
1012bb8e5e2SAndreas Jaekel 	printf("    ZNODE setattr           : %lu\n", zs.zev_cnt_znode_setattr);
1022bb8e5e2SAndreas Jaekel 	printf("    ZNODE acl               : %lu\n", zs.zev_cnt_znode_acl);
103e9a5e479SAndreas Jaekel 	return EXIT_SUCCESS;
1042bb8e5e2SAndreas Jaekel }
1052bb8e5e2SAndreas Jaekel 
1062bb8e5e2SAndreas Jaekel static void
107*d65b2fffSAndreas Jaekel zev_print_inode_info(char *name, zev_inode_info_t *info)
108*d65b2fffSAndreas Jaekel {
109*d65b2fffSAndreas Jaekel 	zpf("  %s.inode: %llu", name, info->ino);
110*d65b2fffSAndreas Jaekel 	zpf("  %s.gen: %llu", name, info->gen);
111*d65b2fffSAndreas Jaekel 	zpf("  %s.mtime: %llu", name, info->mtime);
112*d65b2fffSAndreas Jaekel 	zpf("  %s.ctime: %llu", name, info->ctime);
113*d65b2fffSAndreas Jaekel 	zpf("  %s.size: %llu", name, info->size);
114*d65b2fffSAndreas Jaekel 	zpf("  %s.mode: %llo", name, info->mode);
115*d65b2fffSAndreas Jaekel 	zpf("  %s.links: %llu", name, info->links);
116*d65b2fffSAndreas Jaekel 	zpf("  %s.type: %lu", name, info->type);
117*d65b2fffSAndreas Jaekel 	zpf("  %s.flags: %lu", name, info->flags);
118*d65b2fffSAndreas Jaekel }
119*d65b2fffSAndreas Jaekel 
120*d65b2fffSAndreas Jaekel static void
121*d65b2fffSAndreas Jaekel zev_print_mark_payload(zev_mark_t *rec)
122*d65b2fffSAndreas Jaekel {
123*d65b2fffSAndreas Jaekel 	int i;
124*d65b2fffSAndreas Jaekel 	int j;
125*d65b2fffSAndreas Jaekel 	uint8_t *p;
126*d65b2fffSAndreas Jaekel 	char c;
127*d65b2fffSAndreas Jaekel 
128*d65b2fffSAndreas Jaekel 	zpf("  payload:");
129*d65b2fffSAndreas Jaekel 	p = (uint8_t *)ZEV_PAYLOAD(rec);
130*d65b2fffSAndreas Jaekel 	for (i=0; i<rec->payload_len; i+=16) {
131*d65b2fffSAndreas Jaekel 		printf("  ");
132*d65b2fffSAndreas Jaekel 		for (j=i; j<rec->payload_len && j<i+16; j++) {
133*d65b2fffSAndreas Jaekel 			printf("%02x ", p[j]);
134*d65b2fffSAndreas Jaekel 			if (j == i + 7)
135*d65b2fffSAndreas Jaekel 				printf(" ");
136*d65b2fffSAndreas Jaekel 		}
137*d65b2fffSAndreas Jaekel 		if (grep_friendly)
138*d65b2fffSAndreas Jaekel 			continue;
139*d65b2fffSAndreas Jaekel 		for (; j<i+16; j++) {
140*d65b2fffSAndreas Jaekel 			printf("   ");
141*d65b2fffSAndreas Jaekel 			if (j == i + 7)
142*d65b2fffSAndreas Jaekel 				printf(" ");
143*d65b2fffSAndreas Jaekel 		}
144*d65b2fffSAndreas Jaekel 		printf("    ");
145*d65b2fffSAndreas Jaekel 		for (j=i; j<rec->payload_len && j<i+16; j++) {
146*d65b2fffSAndreas Jaekel 			c = '.';
147*d65b2fffSAndreas Jaekel 			if (p[j] >= ' ' && p[j] <= '~')
148*d65b2fffSAndreas Jaekel 				c = p[j];
149*d65b2fffSAndreas Jaekel 			printf("%c", c);
150*d65b2fffSAndreas Jaekel 			if (j == i + 7)
151*d65b2fffSAndreas Jaekel 				printf(" ");
152*d65b2fffSAndreas Jaekel 		}
153*d65b2fffSAndreas Jaekel 		printf("\n");
154*d65b2fffSAndreas Jaekel 	}
155*d65b2fffSAndreas Jaekel }
156*d65b2fffSAndreas Jaekel 
157*d65b2fffSAndreas Jaekel static void
15863aba447SAndreas Jaekel zev_print_error(char *buf)
15963aba447SAndreas Jaekel {
16063aba447SAndreas Jaekel 	zev_error_t *rec = (zev_error_t *)buf;
16163aba447SAndreas Jaekel 	time_t op_time = rec->op_time;
16263aba447SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
16363aba447SAndreas Jaekel 
164*d65b2fffSAndreas Jaekel 	if (verbose) {
165*d65b2fffSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
166*d65b2fffSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
167*d65b2fffSAndreas Jaekel 		zpf("  failed.op: %s",
168*d65b2fffSAndreas Jaekel 		    zev_op_name[rec->failed_op - ZEV_OP_MIN]);
169*d65b2fffSAndreas Jaekel 		zpf("  message: %s", ZEV_ERRSTR(rec));
170*d65b2fffSAndreas Jaekel 		znl();
171*d65b2fffSAndreas Jaekel 	} else {
17263aba447SAndreas Jaekel 		printf("%s %s: failed_op=%s msg=%s\n",
17363aba447SAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
174*d65b2fffSAndreas Jaekel 		       zev_op_name[rec->failed_op - ZEV_OP_MIN],
175*d65b2fffSAndreas Jaekel 		       ZEV_ERRSTR(rec));
176*d65b2fffSAndreas Jaekel 	}
17763aba447SAndreas Jaekel }
17863aba447SAndreas Jaekel 
17963aba447SAndreas Jaekel static void
18001c2c787SAndreas Jaekel zev_print_mark(char *buf)
18101c2c787SAndreas Jaekel {
18201c2c787SAndreas Jaekel 	zev_mark_t *rec = (zev_mark_t *)buf;
18301c2c787SAndreas Jaekel 	time_t op_time = rec->op_time;
18401c2c787SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
18501c2c787SAndreas Jaekel 
186*d65b2fffSAndreas Jaekel 	if (verbose) {
187*d65b2fffSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
188*d65b2fffSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
189*d65b2fffSAndreas Jaekel 		zpf("  mark.id: %llu", rec->mark_id);
190*d65b2fffSAndreas Jaekel 		zpf("  payload.len: %llu", rec->payload_len);
191*d65b2fffSAndreas Jaekel 		if (rec->payload_len)
192*d65b2fffSAndreas Jaekel 			zev_print_mark_payload(rec);
193*d65b2fffSAndreas Jaekel 		znl();
194*d65b2fffSAndreas Jaekel 	} else {
19501c2c787SAndreas Jaekel 		printf("%s %s: guid=%llu mark_id=%lld payload_len=%ld\n",
196*d65b2fffSAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN], rec->guid,
197*d65b2fffSAndreas Jaekel 		       rec->mark_id, rec->payload_len);
198*d65b2fffSAndreas Jaekel 	}
19901c2c787SAndreas Jaekel }
20001c2c787SAndreas Jaekel 
20101c2c787SAndreas Jaekel static void
20263aba447SAndreas Jaekel zev_print_zfs_mount(char *buf)
20363aba447SAndreas Jaekel {
20463aba447SAndreas Jaekel 	zev_zfs_mount_t *rec = (zev_zfs_mount_t *)buf;
20563aba447SAndreas Jaekel 	time_t op_time = rec->op_time;
20663aba447SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
20763aba447SAndreas Jaekel 
208*d65b2fffSAndreas Jaekel 	if (verbose) {
209*d65b2fffSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
210*d65b2fffSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
211*d65b2fffSAndreas Jaekel 		zpf("  dataset: %s", ZEV_DATASET(rec));
212*d65b2fffSAndreas Jaekel 		zpf("  mountpoint: %s", ZEV_MOUNTPOINT(rec));
213*d65b2fffSAndreas Jaekel 		zpf("  remount: %s", rec->remount ? "true" : "false");
214*d65b2fffSAndreas Jaekel 		zev_print_inode_info("root", &rec->root);
215*d65b2fffSAndreas Jaekel 		znl();
216*d65b2fffSAndreas Jaekel 	} else {
217*d65b2fffSAndreas Jaekel 		printf("%s %s: guid=%llu remount=%s dataset='%s' "
218*d65b2fffSAndreas Jaekel 		       "mountpoint='%s'\n",
21963aba447SAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
22063aba447SAndreas Jaekel 		       rec->guid,
22163aba447SAndreas Jaekel 		       rec->remount ? "true" : "false",
22263aba447SAndreas Jaekel 		       ZEV_DATASET(rec),
22363aba447SAndreas Jaekel 		       ZEV_MOUNTPOINT(rec));
22463aba447SAndreas Jaekel 	}
225*d65b2fffSAndreas Jaekel }
22663aba447SAndreas Jaekel 
22763aba447SAndreas Jaekel static void
22863aba447SAndreas Jaekel zev_print_zfs_umount(char *buf)
22963aba447SAndreas Jaekel {
23063aba447SAndreas Jaekel 	zev_zfs_umount_t *rec = (zev_zfs_umount_t *)buf;
23163aba447SAndreas Jaekel 	time_t op_time = rec->op_time;
23263aba447SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
23363aba447SAndreas Jaekel 
234*d65b2fffSAndreas Jaekel 	if (verbose) {
235*d65b2fffSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
236*d65b2fffSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
237*d65b2fffSAndreas Jaekel 		znl();
238*d65b2fffSAndreas Jaekel 	} else {
23963aba447SAndreas Jaekel 		printf("%s %s: guid=%llu\n",
24063aba447SAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
24163aba447SAndreas Jaekel 		       rec->guid);
24263aba447SAndreas Jaekel 	}
243*d65b2fffSAndreas Jaekel }
24463aba447SAndreas Jaekel 
24563aba447SAndreas Jaekel static void
24663aba447SAndreas Jaekel zev_print_zvol_truncate(char *buf)
24763aba447SAndreas Jaekel {
24863aba447SAndreas Jaekel 	zev_zvol_truncate_t *rec = (zev_zvol_truncate_t *)buf;
24963aba447SAndreas Jaekel 	time_t op_time = rec->op_time;
25063aba447SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
25163aba447SAndreas Jaekel 
252*d65b2fffSAndreas Jaekel 	if (verbose) {
253*d65b2fffSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
254*d65b2fffSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
255*d65b2fffSAndreas Jaekel 		zpf("  offset: %llu", rec->offset);
256*d65b2fffSAndreas Jaekel 		zpf("  length: %llu", rec->length);
257*d65b2fffSAndreas Jaekel 		znl();
258*d65b2fffSAndreas Jaekel 	} else {
25963aba447SAndreas Jaekel 		printf("%s %s: guid=%llu offset=%llu length=%llu\n",
26063aba447SAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
26163aba447SAndreas Jaekel 		       rec->guid,
26263aba447SAndreas Jaekel 		       rec->offset,
26363aba447SAndreas Jaekel 		       rec->length);
26463aba447SAndreas Jaekel 	}
265*d65b2fffSAndreas Jaekel }
26663aba447SAndreas Jaekel 
26763aba447SAndreas Jaekel static void
26863aba447SAndreas Jaekel zev_print_zvol_write(char *buf)
26963aba447SAndreas Jaekel {
27063aba447SAndreas Jaekel 	zev_print_zvol_truncate(buf);
27163aba447SAndreas Jaekel }
27263aba447SAndreas Jaekel 
27363aba447SAndreas Jaekel static void
27463aba447SAndreas Jaekel zev_print_znode_close_after_update(char *buf)
27563aba447SAndreas Jaekel {
27663aba447SAndreas Jaekel 	zev_znode_close_after_update_t *rec =
27763aba447SAndreas Jaekel 	    (zev_znode_close_after_update_t *)buf;
27863aba447SAndreas Jaekel 	time_t op_time = rec->op_time;
27963aba447SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
28063aba447SAndreas Jaekel 
281*d65b2fffSAndreas Jaekel 	if (verbose) {
282*d65b2fffSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
283*d65b2fffSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
284*d65b2fffSAndreas Jaekel 		zev_print_inode_info("file", &rec->file);
285*d65b2fffSAndreas Jaekel 		znl();
286*d65b2fffSAndreas Jaekel 	} else {
28763aba447SAndreas Jaekel 		printf("%s %s: guid=%llu file=%llu.%llu\n",
28863aba447SAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
28963aba447SAndreas Jaekel 		       rec->guid,
29063aba447SAndreas Jaekel 		       rec->file.ino, rec->file.gen);
29163aba447SAndreas Jaekel 	}
292*d65b2fffSAndreas Jaekel }
29363aba447SAndreas Jaekel 
29463aba447SAndreas Jaekel static void
29563aba447SAndreas Jaekel zev_print_znode_create(char *buf)
29663aba447SAndreas Jaekel {
29763aba447SAndreas Jaekel 	zev_znode_create_t *rec = (zev_znode_create_t *)buf;
29863aba447SAndreas Jaekel 	time_t op_time = rec->op_time;
29963aba447SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
30063aba447SAndreas Jaekel 
301*d65b2fffSAndreas Jaekel 	if (verbose) {
302*d65b2fffSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
303*d65b2fffSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
304*d65b2fffSAndreas Jaekel 		zpf("  name: '%s'", ZEV_NAME(rec));
305*d65b2fffSAndreas Jaekel 		zev_print_inode_info("parent", &rec->file);
306*d65b2fffSAndreas Jaekel 		zev_print_inode_info("file", &rec->file);
307*d65b2fffSAndreas Jaekel 		znl();
308*d65b2fffSAndreas Jaekel 	} else {
309c035b1e8SAndreas Jaekel 		printf("%s %s: guid=%llu parent=%llu.%llu file=%llu.%llu "
310c035b1e8SAndreas Jaekel 		       "file.mtime=%llu, parent.mtime=%llu, name='%s'\n",
31163aba447SAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
31263aba447SAndreas Jaekel 		       rec->guid,
31363aba447SAndreas Jaekel 		       rec->parent.ino, rec->parent.gen,
31463aba447SAndreas Jaekel 		       rec->file.ino, rec->file.gen,
315c035b1e8SAndreas Jaekel 		       rec->file.mtime, rec->parent.mtime,
31663aba447SAndreas Jaekel 		       ZEV_NAME(rec));
31763aba447SAndreas Jaekel 	}
318*d65b2fffSAndreas Jaekel }
31963aba447SAndreas Jaekel 
32063aba447SAndreas Jaekel static void
32163aba447SAndreas Jaekel zev_print_znode_mkdir(char *buf)
32263aba447SAndreas Jaekel {
32363aba447SAndreas Jaekel 	zev_print_znode_create(buf);
32463aba447SAndreas Jaekel }
32563aba447SAndreas Jaekel 
32663aba447SAndreas Jaekel static void
32763aba447SAndreas Jaekel zev_print_znode_make_xattr_dir(char *buf)
32863aba447SAndreas Jaekel {
32963aba447SAndreas Jaekel 	zev_print_znode_create(buf);
33063aba447SAndreas Jaekel }
33163aba447SAndreas Jaekel 
33263aba447SAndreas Jaekel static void
33363aba447SAndreas Jaekel zev_print_znode_remove(char *buf)
33463aba447SAndreas Jaekel {
33563aba447SAndreas Jaekel 	zev_znode_remove_t *rec = (zev_znode_remove_t *)buf;
33663aba447SAndreas Jaekel 	time_t op_time = rec->op_time;
33763aba447SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
33863aba447SAndreas Jaekel 
339*d65b2fffSAndreas Jaekel 	if (verbose) {
340*d65b2fffSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
341*d65b2fffSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
342*d65b2fffSAndreas Jaekel 		zpf("  file.name: '%s'", ZEV_NAME(rec));
343*d65b2fffSAndreas Jaekel 		zev_print_inode_info("file", &rec->file);
344*d65b2fffSAndreas Jaekel 		zev_print_inode_info("parent", &rec->file);
345*d65b2fffSAndreas Jaekel 		znl();
346*d65b2fffSAndreas Jaekel 	} else {
347*d65b2fffSAndreas Jaekel 		printf("%s %s: guid=%llu parent=%llu.%llu "
348*d65b2fffSAndreas Jaekel 		       "file.mtime=%llu name='%s'\n",
34963aba447SAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
35063aba447SAndreas Jaekel 		       rec->guid,
35163aba447SAndreas Jaekel 		       rec->parent.ino, rec->parent.gen,
3526db5d4ecSAndreas Jaekel 		       rec->file.mtime,
35363aba447SAndreas Jaekel 		       ZEV_NAME(rec));
35463aba447SAndreas Jaekel 	}
355*d65b2fffSAndreas Jaekel }
35663aba447SAndreas Jaekel 
35763aba447SAndreas Jaekel static void
35863aba447SAndreas Jaekel zev_print_znode_rmdir(char *buf)
35963aba447SAndreas Jaekel {
36063aba447SAndreas Jaekel 	zev_print_znode_remove(buf);
36163aba447SAndreas Jaekel }
36263aba447SAndreas Jaekel 
36363aba447SAndreas Jaekel static void
36463aba447SAndreas Jaekel zev_print_znode_link(char *buf)
36563aba447SAndreas Jaekel {
36663aba447SAndreas Jaekel 	zev_znode_link_t *rec = (zev_znode_link_t *)buf;
36763aba447SAndreas Jaekel 	time_t op_time = rec->op_time;
36863aba447SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
36963aba447SAndreas Jaekel 
370*d65b2fffSAndreas Jaekel 	if (verbose) {
371*d65b2fffSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
372*d65b2fffSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
373*d65b2fffSAndreas Jaekel 		zpf("  link.name: '%s'", ZEV_NAME(rec));
374*d65b2fffSAndreas Jaekel 		zev_print_inode_info("file", &rec->file);
375*d65b2fffSAndreas Jaekel 		zev_print_inode_info("parent", &rec->file);
376*d65b2fffSAndreas Jaekel 		znl();
377*d65b2fffSAndreas Jaekel 	} else {
37803101f54SAndreas Jaekel 		printf("%s %s: parent=%llu.%llu file=%llu.%llu "
37903101f54SAndreas Jaekel 		       "file.ctime=%llu parent.ctime=%llu name='%s'\n",
38063aba447SAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
38163aba447SAndreas Jaekel 		       rec->parent.ino, rec->parent.gen,
38263aba447SAndreas Jaekel 		       rec->file.ino, rec->file.gen,
38303101f54SAndreas Jaekel 		       rec->file.ctime, rec->parent.ctime,
38463aba447SAndreas Jaekel 		       ZEV_NAME(rec));
385*d65b2fffSAndreas Jaekel 	}
38663aba447SAndreas Jaekel }
38763aba447SAndreas Jaekel 
38863aba447SAndreas Jaekel static void
38963aba447SAndreas Jaekel zev_print_znode_symlink(char *buf)
39063aba447SAndreas Jaekel {
39163aba447SAndreas Jaekel 	zev_znode_symlink_t *rec = (zev_znode_symlink_t *)buf;
39263aba447SAndreas Jaekel 	time_t op_time = rec->op_time;
39363aba447SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
39463aba447SAndreas Jaekel 
395*d65b2fffSAndreas Jaekel 	if (verbose) {
396*d65b2fffSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
397*d65b2fffSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
398*d65b2fffSAndreas Jaekel 		zpf("  symlink.name: '%s'", ZEV_NAME(rec));
399*d65b2fffSAndreas Jaekel 		zpf("  symlink.link: '%s'", ZEV_LINK(rec));
400*d65b2fffSAndreas Jaekel 		zev_print_inode_info("file", &rec->file);
401*d65b2fffSAndreas Jaekel 		zev_print_inode_info("parent", &rec->file);
402*d65b2fffSAndreas Jaekel 		znl();
403*d65b2fffSAndreas Jaekel 	} else {
404*d65b2fffSAndreas Jaekel 		printf("%s %s: parent=%llu.%llu file=%llu.%llu "
405*d65b2fffSAndreas Jaekel 		       "name='%s' link='%s'\n",
40663aba447SAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
40763aba447SAndreas Jaekel 		       rec->parent.ino, rec->parent.gen,
40863aba447SAndreas Jaekel 		       rec->file.ino, rec->file.gen,
40963aba447SAndreas Jaekel 		       ZEV_NAME(rec),
41063aba447SAndreas Jaekel 		       ZEV_LINK(rec));
41163aba447SAndreas Jaekel 	}
412*d65b2fffSAndreas Jaekel }
41363aba447SAndreas Jaekel 
41463aba447SAndreas Jaekel static void
41563aba447SAndreas Jaekel zev_print_znode_rename(char *buf)
41663aba447SAndreas Jaekel {
41763aba447SAndreas Jaekel 	zev_znode_rename_t *rec = (zev_znode_rename_t *)buf;
41863aba447SAndreas Jaekel 	time_t op_time = rec->op_time;
41963aba447SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
42063aba447SAndreas Jaekel 
421*d65b2fffSAndreas Jaekel 	if (verbose) {
422*d65b2fffSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
423*d65b2fffSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
424*d65b2fffSAndreas Jaekel 		zpf("  file.srcname: '%s'", ZEV_SRCNAME(rec));
425*d65b2fffSAndreas Jaekel 		zpf("  file.dstname: '%s'", ZEV_DSTNAME(rec));
426*d65b2fffSAndreas Jaekel 		zev_print_inode_info("file", &rec->file);
427*d65b2fffSAndreas Jaekel 		zev_print_inode_info("srcdir", &rec->srcdir);
428*d65b2fffSAndreas Jaekel 		zev_print_inode_info("dstdir", &rec->dstdir);
429*d65b2fffSAndreas Jaekel 		znl();
430*d65b2fffSAndreas Jaekel 	} else {
431*d65b2fffSAndreas Jaekel 		printf("%s %s: srcdir=%llu.%llu dstdir=%llu.%llu "
432*d65b2fffSAndreas Jaekel 		       "file=%llu.%llu file.mtime=%llu, file.ctime=%llu, "
433*d65b2fffSAndreas Jaekel 		       "srcdir.mtime=%llu, srcdir.ctime=%llu, "
434*d65b2fffSAndreas Jaekel 		       "dstdir.mtime=%llu, dstdir.ctime=%llu, "
43563aba447SAndreas Jaekel 		       "srcname='%s' dstname='%s'\n",
43663aba447SAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
43763aba447SAndreas Jaekel 		       rec->srcdir.ino, rec->srcdir.gen,
43863aba447SAndreas Jaekel 		       rec->dstdir.ino, rec->dstdir.gen,
43963aba447SAndreas Jaekel 		       rec->file.ino, rec->file.gen,
440c035b1e8SAndreas Jaekel 		       rec->file.mtime, rec->file.ctime,
441c035b1e8SAndreas Jaekel 		       rec->srcdir.mtime, rec->srcdir.ctime,
442c035b1e8SAndreas Jaekel 		       rec->dstdir.mtime, rec->dstdir.ctime,
44363aba447SAndreas Jaekel 		       ZEV_SRCNAME(rec),
44463aba447SAndreas Jaekel 		       ZEV_DSTNAME(rec));
44563aba447SAndreas Jaekel 	}
446*d65b2fffSAndreas Jaekel }
44763aba447SAndreas Jaekel 
44863aba447SAndreas Jaekel static void
4495e286361SAndreas Jaekel sig2hex_direct(const uint8_t *sig, char *hex)
4505e286361SAndreas Jaekel {
4515e286361SAndreas Jaekel 	int     i;
4525e286361SAndreas Jaekel 
4535e286361SAndreas Jaekel 	for (i = 0; i < SHA1_DIGEST_LENGTH; ++i) {
4545e286361SAndreas Jaekel 		sprintf(hex + 2 * i, "%02x", sig[i]);
4555e286361SAndreas Jaekel 	}
4565e286361SAndreas Jaekel 	hex[SHA1_DIGEST_LENGTH * 2] = '\0';
4575e286361SAndreas Jaekel }
4585e286361SAndreas Jaekel 
4595e286361SAndreas Jaekel static void
46063aba447SAndreas Jaekel zev_print_znode_write(char *buf)
46163aba447SAndreas Jaekel {
46263aba447SAndreas Jaekel 	zev_znode_write_t *rec = (zev_znode_write_t *)buf;
46363aba447SAndreas Jaekel 	time_t op_time = rec->op_time;
46463aba447SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
4655e286361SAndreas Jaekel 	zev_sig_t *sig;
4665e286361SAndreas Jaekel 	char sigval[(SHA1_DIGEST_LENGTH * 2) + 1];
4675e286361SAndreas Jaekel 	int i;
46863aba447SAndreas Jaekel 
4695e286361SAndreas Jaekel 	if (verbose) {
470*d65b2fffSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
471*d65b2fffSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
472*d65b2fffSAndreas Jaekel 		zpf("  offset: %llu", rec->offset);
473*d65b2fffSAndreas Jaekel 		zpf("  length: %llu", rec->length);
474*d65b2fffSAndreas Jaekel 		zev_print_inode_info("file", &rec->file);
475*d65b2fffSAndreas Jaekel 		znl();
4765e286361SAndreas Jaekel 		for (i=0; i<rec->signature_cnt; i++) {
4775e286361SAndreas Jaekel 			sig = (zev_sig_t *)ZEV_SIGNATURES(rec);
4785e286361SAndreas Jaekel 			sig += i;
4795e286361SAndreas Jaekel 			sig2hex_direct(sig->value, sigval);
4805e286361SAndreas Jaekel 			printf("  sig: level %d, offset %llu, value %s\n",
4815e286361SAndreas Jaekel 			       sig->level, sig->block_offset, sigval);
4825e286361SAndreas Jaekel 		}
483*d65b2fffSAndreas Jaekel 	} else {
484*d65b2fffSAndreas Jaekel 		printf("%s %s: file=%llu.%llu offset=%llu length=%llu\n",
485*d65b2fffSAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
486*d65b2fffSAndreas Jaekel 		       rec->file.ino, rec->file.gen,
487*d65b2fffSAndreas Jaekel 		       rec->offset, rec->length);
4885e286361SAndreas Jaekel 	}
48963aba447SAndreas Jaekel }
49063aba447SAndreas Jaekel 
49163aba447SAndreas Jaekel static void
49263aba447SAndreas Jaekel zev_print_znode_truncate(char *buf)
49363aba447SAndreas Jaekel {
49463aba447SAndreas Jaekel 	zev_print_znode_write(buf);
49563aba447SAndreas Jaekel }
49663aba447SAndreas Jaekel 
49763aba447SAndreas Jaekel static void
49863aba447SAndreas Jaekel zev_print_znode_setattr(char *buf)
49963aba447SAndreas Jaekel {
50063aba447SAndreas Jaekel 	zev_znode_setattr_t *rec = (zev_znode_setattr_t *)buf;
50163aba447SAndreas Jaekel 	time_t op_time = rec->op_time;
50263aba447SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
50363aba447SAndreas Jaekel 
504*d65b2fffSAndreas Jaekel 	if (verbose) {
505*d65b2fffSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
506*d65b2fffSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
507*d65b2fffSAndreas Jaekel 		zev_print_inode_info("file", &rec->file);
508*d65b2fffSAndreas Jaekel 		znl();
509*d65b2fffSAndreas Jaekel 	} else {
510c035b1e8SAndreas Jaekel 		printf("%s %s: file=%llu.%llu mtime=%llu\n",
51163aba447SAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
512c035b1e8SAndreas Jaekel 		       rec->file.ino, rec->file.gen, rec->file.mtime);
51363aba447SAndreas Jaekel 	}
514*d65b2fffSAndreas Jaekel }
51563aba447SAndreas Jaekel 
51663aba447SAndreas Jaekel static void
51763aba447SAndreas Jaekel zev_print_znode_acl(char *buf)
51863aba447SAndreas Jaekel {
51963aba447SAndreas Jaekel 	zev_print_znode_setattr(buf);
52063aba447SAndreas Jaekel }
52163aba447SAndreas Jaekel 
52263aba447SAndreas Jaekel static void
5239193e9c2SAndreas Jaekel zev_print_event(char *buf, int len)
5249193e9c2SAndreas Jaekel {
52563aba447SAndreas Jaekel 	int record_len;
52663aba447SAndreas Jaekel 	int op;
5279193e9c2SAndreas Jaekel 
52863aba447SAndreas Jaekel 	record_len = *(uint32_t *)buf;
52963aba447SAndreas Jaekel 	if (record_len != len) {
53063aba447SAndreas Jaekel 		fprintf(stderr, "record length mismatch: got %d, expected %d\n",
53163aba447SAndreas Jaekel 		        record_len, len);
5329193e9c2SAndreas Jaekel 		exit(1);
5339193e9c2SAndreas Jaekel 	}
53463aba447SAndreas Jaekel 	op = *((uint32_t *)buf + 1);
5359193e9c2SAndreas Jaekel 	if (op < ZEV_OP_MIN || op > ZEV_OP_MAX) {
53663aba447SAndreas Jaekel 		fprintf(stderr, "unknown op code: %d\n", op);
5379193e9c2SAndreas Jaekel 		exit(1);
5389193e9c2SAndreas Jaekel 	}
53963aba447SAndreas Jaekel 	switch (op) {
54063aba447SAndreas Jaekel 	case ZEV_OP_ERROR:
54163aba447SAndreas Jaekel 		zev_print_error(buf);
5429193e9c2SAndreas Jaekel 		break;
54301c2c787SAndreas Jaekel 	case ZEV_OP_MARK:
54401c2c787SAndreas Jaekel 		zev_print_mark(buf);
54501c2c787SAndreas Jaekel 		break;
54663aba447SAndreas Jaekel 	case ZEV_OP_ZFS_MOUNT:
54763aba447SAndreas Jaekel 		zev_print_zfs_mount(buf);
5489193e9c2SAndreas Jaekel 		break;
54963aba447SAndreas Jaekel 	case ZEV_OP_ZFS_UMOUNT:
55063aba447SAndreas Jaekel 		zev_print_zfs_umount(buf);
5519193e9c2SAndreas Jaekel 		break;
55263aba447SAndreas Jaekel 	case ZEV_OP_ZVOL_TRUNCATE:
55363aba447SAndreas Jaekel 		zev_print_zvol_truncate(buf);
5549193e9c2SAndreas Jaekel 		break;
55563aba447SAndreas Jaekel 	case ZEV_OP_ZVOL_WRITE:
55663aba447SAndreas Jaekel 		zev_print_zvol_write(buf);
55763aba447SAndreas Jaekel 		break;
55863aba447SAndreas Jaekel 	case ZEV_OP_ZNODE_CLOSE_AFTER_UPDATE:
55963aba447SAndreas Jaekel 		zev_print_znode_close_after_update(buf);
56063aba447SAndreas Jaekel 		break;
56163aba447SAndreas Jaekel 	case ZEV_OP_ZNODE_CREATE:
56263aba447SAndreas Jaekel 		zev_print_znode_create(buf);
56363aba447SAndreas Jaekel 		break;
56463aba447SAndreas Jaekel 	case ZEV_OP_ZNODE_MKDIR:
56563aba447SAndreas Jaekel 		zev_print_znode_mkdir(buf);
56663aba447SAndreas Jaekel 		break;
56763aba447SAndreas Jaekel 	case ZEV_OP_ZNODE_MAKE_XATTR_DIR:
56863aba447SAndreas Jaekel 		zev_print_znode_make_xattr_dir(buf);
56963aba447SAndreas Jaekel 		break;
57063aba447SAndreas Jaekel 	case ZEV_OP_ZNODE_REMOVE:
57163aba447SAndreas Jaekel 		zev_print_znode_remove(buf);
57263aba447SAndreas Jaekel 		break;
57363aba447SAndreas Jaekel 	case ZEV_OP_ZNODE_RMDIR:
57463aba447SAndreas Jaekel 		zev_print_znode_rmdir(buf);
57563aba447SAndreas Jaekel 		break;
57663aba447SAndreas Jaekel 	case ZEV_OP_ZNODE_LINK:
57763aba447SAndreas Jaekel 		zev_print_znode_link(buf);
57863aba447SAndreas Jaekel 		break;
57963aba447SAndreas Jaekel 	case ZEV_OP_ZNODE_SYMLINK:
58063aba447SAndreas Jaekel 		zev_print_znode_symlink(buf);
58163aba447SAndreas Jaekel 		break;
58263aba447SAndreas Jaekel 	case ZEV_OP_ZNODE_RENAME:
58363aba447SAndreas Jaekel 		zev_print_znode_rename(buf);
58463aba447SAndreas Jaekel 		break;
58563aba447SAndreas Jaekel 	case ZEV_OP_ZNODE_WRITE:
58663aba447SAndreas Jaekel 		zev_print_znode_write(buf);
58763aba447SAndreas Jaekel 		break;
58863aba447SAndreas Jaekel 	case ZEV_OP_ZNODE_TRUNCATE:
58963aba447SAndreas Jaekel 		zev_print_znode_truncate(buf);
59063aba447SAndreas Jaekel 		break;
59163aba447SAndreas Jaekel 	case ZEV_OP_ZNODE_SETATTR:
59263aba447SAndreas Jaekel 		zev_print_znode_setattr(buf);
59363aba447SAndreas Jaekel 		break;
59463aba447SAndreas Jaekel 	case ZEV_OP_ZNODE_ACL:
59563aba447SAndreas Jaekel 		zev_print_znode_acl(buf);
5969193e9c2SAndreas Jaekel 		break;
5979193e9c2SAndreas Jaekel 	default:
59863aba447SAndreas Jaekel 		fprintf(stderr, "unhandled op code: %d\n", op);
5999193e9c2SAndreas Jaekel 		exit(1);
6009193e9c2SAndreas Jaekel 	}
6019193e9c2SAndreas Jaekel }
6029193e9c2SAndreas Jaekel 
603e9a5e479SAndreas Jaekel static int
6044ca7dd5eSAndreas Jaekel zev_poll_events(int fd, int create_tmp_queue)
6052bb8e5e2SAndreas Jaekel {
6062bb8e5e2SAndreas Jaekel 	struct pollfd pfd[1];
6072bb8e5e2SAndreas Jaekel 	int ret;
6089193e9c2SAndreas Jaekel 	char buf[4096];
60968a46c64SAndreas Jaekel 	zev_event_t *ev;
61068a46c64SAndreas Jaekel 	int off = 0;
611e9a5e479SAndreas Jaekel 	zev_ioctl_add_queue_t aq;
612e9a5e479SAndreas Jaekel 	int q_fd;
613e9a5e479SAndreas Jaekel 
6144ca7dd5eSAndreas Jaekel 	if (create_tmp_queue) {
615e9a5e479SAndreas Jaekel 		aq.zev_max_queue_len = 0;
616e9a5e479SAndreas Jaekel 		aq.zev_flags = ZEV_FL_BLOCK_WHILE_QUEUE_FULL;
617e9a5e479SAndreas Jaekel 		snprintf(aq.zev_name, ZEV_MAX_QUEUE_NAME_LEN,
618e9a5e479SAndreas Jaekel 			 "zevadm.%ld.%ld", time(NULL), getpid());
619e9a5e479SAndreas Jaekel 		aq.zev_namelen = strlen(aq.zev_name);
620e9a5e479SAndreas Jaekel 
621e9a5e479SAndreas Jaekel 		if (ioctl(fd, ZEV_IOC_ADD_QUEUE, &aq)) {
622e9a5e479SAndreas Jaekel 			perror("adding temporary queue failed");
623e9a5e479SAndreas Jaekel 			return (EXIT_FAILURE);
624e9a5e479SAndreas Jaekel 		}
625e9a5e479SAndreas Jaekel 
6264ca7dd5eSAndreas Jaekel 		snprintf(buf, sizeof(buf),
6274ca7dd5eSAndreas Jaekel 		         "/devices/pseudo/zev@0:%s", aq.zev_name);
628e9a5e479SAndreas Jaekel 		q_fd = open(buf, O_RDONLY);
629e9a5e479SAndreas Jaekel 		if (q_fd < 0) {
630e9a5e479SAndreas Jaekel 			perror("opening queue device failed");
631e9a5e479SAndreas Jaekel 			return (EXIT_FAILURE);
632e9a5e479SAndreas Jaekel 		}
6334ca7dd5eSAndreas Jaekel 	} else {
6344ca7dd5eSAndreas Jaekel 		q_fd = fd;
6354ca7dd5eSAndreas Jaekel 	}
636e9a5e479SAndreas Jaekel 
6372bb8e5e2SAndreas Jaekel 	while (1) {
638e9a5e479SAndreas Jaekel 		pfd[0].fd = q_fd;
6392bb8e5e2SAndreas Jaekel 		pfd[0].events = POLLIN;
6402bb8e5e2SAndreas Jaekel 		ret = poll(pfd, 1, 1000);
6412bb8e5e2SAndreas Jaekel 		if (ret < 0) {
6422bb8e5e2SAndreas Jaekel 			perror("poll failed");
6434ca7dd5eSAndreas Jaekel 			close(q_fd);
644e9a5e479SAndreas Jaekel 			return(EXIT_FAILURE);
6452bb8e5e2SAndreas Jaekel 		}
6462bb8e5e2SAndreas Jaekel 		if (!(pfd[0].revents & POLLIN))
6472bb8e5e2SAndreas Jaekel 			continue;
6482bb8e5e2SAndreas Jaekel 		/* data available */
649e9a5e479SAndreas Jaekel 		ret = read(q_fd, buf, sizeof(buf));
6502bb8e5e2SAndreas Jaekel 		if (ret < 0) {
6512bb8e5e2SAndreas Jaekel 			perror("read failed");
6524ca7dd5eSAndreas Jaekel 			close(q_fd);
653e9a5e479SAndreas Jaekel 			return(EXIT_FAILURE);
6542bb8e5e2SAndreas Jaekel 		}
6552bb8e5e2SAndreas Jaekel 		if (ret == 0)
6562bb8e5e2SAndreas Jaekel 			continue;
65768a46c64SAndreas Jaekel 		while (ret > off) {
65868a46c64SAndreas Jaekel 			ev = (zev_event_t *)(buf + off);
65968a46c64SAndreas Jaekel 			zev_print_event(buf + off, ev->header.record_len);
66068a46c64SAndreas Jaekel 			off += ev->header.record_len;
66168a46c64SAndreas Jaekel 		}
662108668daSAndreas Jaekel 		off = 0;
6632bb8e5e2SAndreas Jaekel 	}
6644ca7dd5eSAndreas Jaekel 	if (create_tmp_queue)
665e9a5e479SAndreas Jaekel 		close(q_fd);
666e9a5e479SAndreas Jaekel 	return EXIT_SUCCESS;
6672bb8e5e2SAndreas Jaekel }
6682bb8e5e2SAndreas Jaekel 
6692bb8e5e2SAndreas Jaekel static void
6702bb8e5e2SAndreas Jaekel usage(char *progname)
6712bb8e5e2SAndreas Jaekel {
672e9a5e479SAndreas Jaekel 	fprintf(stderr, "usage: %s [-d <dev>] [options]\n", progname);
673e9a5e479SAndreas Jaekel 	fprintf(stderr, "\n");
674e9a5e479SAndreas Jaekel 	fprintf(stderr, " Status information:\n");
6752bb8e5e2SAndreas Jaekel 	fprintf(stderr, "   -s                   show zev statistics\n");
6762bb8e5e2SAndreas Jaekel 	fprintf(stderr, "   -p                   poll for ZFS events\n");
677e9a5e479SAndreas Jaekel 	fprintf(stderr, "   -D                   print zev module debug "
678e9a5e479SAndreas Jaekel 	        "information\n");
679e9a5e479SAndreas Jaekel 	fprintf(stderr, "\n");
680e9a5e479SAndreas Jaekel 	fprintf(stderr, " Tune zev module settings:\n");
681e9a5e479SAndreas Jaekel 	fprintf(stderr, "   -Q <bytes>           set maximum event queue "
682e9a5e479SAndreas Jaekel 	        "length\n");
683e9a5e479SAndreas Jaekel 	fprintf(stderr, "   -m <pool>            mute pool, no events for "
684e9a5e479SAndreas Jaekel 	        "this pool\n");
6852bb8e5e2SAndreas Jaekel 	fprintf(stderr, "   -M <pool>            unmute pool\n");
686e9a5e479SAndreas Jaekel 	fprintf(stderr, "\n");
687e9a5e479SAndreas Jaekel 	fprintf(stderr, " Queue management:\n");
688e9a5e479SAndreas Jaekel 	fprintf(stderr, "   -l                   list queues\n");
6894ca7dd5eSAndreas Jaekel 	fprintf(stderr, "   -a <name>            add non-blocking queue\n");
6904ca7dd5eSAndreas Jaekel 	fprintf(stderr, "   -A <name>            add blocking queue\n");
691e9a5e479SAndreas Jaekel 	fprintf(stderr, "   -r <name>            remove queue\n");
692e9a5e479SAndreas Jaekel 	fprintf(stderr, "   -b <name>            make queue non-blocking "
693e9a5e479SAndreas Jaekel 	        "(default)\n");
694e9a5e479SAndreas Jaekel 	fprintf(stderr, "   -B <name>            make queue block when full\n");
695e9a5e479SAndreas Jaekel 	fprintf(stderr, "   -P <name>            display queue properties\n");
6964ca7dd5eSAndreas Jaekel 	fprintf(stderr, "   -L <name> <bytes>    set maximum event queue "
697e9a5e479SAndreas Jaekel 	        "length\n");
698e9a5e479SAndreas Jaekel 	fprintf(stderr, "   -t <name> <bytes>    set queue length poll "
699e9a5e479SAndreas Jaekel 	        "throttle\n");
700e9a5e479SAndreas Jaekel 	fprintf(stderr, "\n");
701e9a5e479SAndreas Jaekel 	fprintf(stderr, " Other options:\n");
702e9a5e479SAndreas Jaekel 	fprintf(stderr, "   -d <dev>             non-default device file. "
703e9a5e479SAndreas Jaekel 	        "('%s')\n", ZEV_DEVICE);
7044ca7dd5eSAndreas Jaekel 	fprintf(stderr, "   -q <name>            use device file for this "
7054ca7dd5eSAndreas Jaekel 		"queue name\n");
70601c2c787SAndreas Jaekel 	fprintf(stderr, "   -k <guid>:<payload>  queue mark event\n");
707b9710123SAndreas Jaekel 	fprintf(stderr, "   -c <filename>        list file's content "
708b9710123SAndreas Jaekel 		"checksums\n");
709*d65b2fffSAndreas Jaekel 	fprintf(stderr, "   -v                   verbose: additional output "
7105e286361SAndreas Jaekel 	        "for some operations\n");
711*d65b2fffSAndreas Jaekel 	fprintf(stderr, "   -g                   grep-friendly event output, "
712*d65b2fffSAndreas Jaekel 	        "one event per line\n");
7132bb8e5e2SAndreas Jaekel 	exit (EXIT_FAILURE);
7142bb8e5e2SAndreas Jaekel }
7152bb8e5e2SAndreas Jaekel 
7162bb8e5e2SAndreas Jaekel static int
7174ca7dd5eSAndreas Jaekel zev_add_queue(int fd, char *arg, int blocking)
7182bb8e5e2SAndreas Jaekel {
719e9a5e479SAndreas Jaekel 	zev_ioctl_add_queue_t aq;
720e9a5e479SAndreas Jaekel 	int namelen;
7212bb8e5e2SAndreas Jaekel 
722e9a5e479SAndreas Jaekel 	namelen = strlen(arg);
723e9a5e479SAndreas Jaekel 	if (namelen > ZEV_MAX_QUEUE_NAME_LEN) {
724e9a5e479SAndreas Jaekel 		fprintf(stderr, "queue name too long: %s\n", arg);
7252bb8e5e2SAndreas Jaekel 		return (EXIT_FAILURE);
7262bb8e5e2SAndreas Jaekel 	}
727e9a5e479SAndreas Jaekel 
728e9a5e479SAndreas Jaekel 	aq.zev_namelen = namelen;
729e9a5e479SAndreas Jaekel 	strcpy(aq.zev_name, arg);
7304ca7dd5eSAndreas Jaekel 	aq.zev_flags = ZEV_FL_PERSISTENT;
7314ca7dd5eSAndreas Jaekel 	if (blocking) {
7324ca7dd5eSAndreas Jaekel 		aq.zev_flags |= ZEV_FL_BLOCK_WHILE_QUEUE_FULL;
7334ca7dd5eSAndreas Jaekel 		aq.zev_max_queue_len = ZEV_MAX_QUEUE_LEN;
7344ca7dd5eSAndreas Jaekel 	} else {
735e9a5e479SAndreas Jaekel 		aq.zev_max_queue_len = (1024 * 1024);
7364ca7dd5eSAndreas Jaekel 	}
737e9a5e479SAndreas Jaekel 
738e9a5e479SAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_ADD_QUEUE, &aq)) {
739e9a5e479SAndreas Jaekel 		perror("adding queue failed");
7402bb8e5e2SAndreas Jaekel 		return (EXIT_FAILURE);
7412bb8e5e2SAndreas Jaekel 	}
7422bb8e5e2SAndreas Jaekel 	return (0);
7432bb8e5e2SAndreas Jaekel }
7442bb8e5e2SAndreas Jaekel 
7452bb8e5e2SAndreas Jaekel static int
746e9a5e479SAndreas Jaekel zev_remove_queue(int fd, char *arg)
747205a9bc9SAndreas Jaekel {
748e9a5e479SAndreas Jaekel 	zev_ioctl_remove_queue_t aq;
749e9a5e479SAndreas Jaekel 	int namelen;
750205a9bc9SAndreas Jaekel 
751e9a5e479SAndreas Jaekel 	namelen = strlen(arg);
752e9a5e479SAndreas Jaekel 	if (namelen > ZEV_MAX_QUEUE_NAME_LEN) {
753e9a5e479SAndreas Jaekel 		fprintf(stderr, "queue name too long: %s\n", arg);
754205a9bc9SAndreas Jaekel 		return (EXIT_FAILURE);
755205a9bc9SAndreas Jaekel 	}
756e9a5e479SAndreas Jaekel 
7574ca7dd5eSAndreas Jaekel 	aq.zev_queue_name.zev_namelen = namelen;
7584ca7dd5eSAndreas Jaekel 	strcpy(aq.zev_queue_name.zev_name, arg);
759e9a5e479SAndreas Jaekel 
760e9a5e479SAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_REMOVE_QUEUE, &aq)) {
761e9a5e479SAndreas Jaekel 		perror("removing queue failed");
762e9a5e479SAndreas Jaekel 		return (EXIT_FAILURE);
763e9a5e479SAndreas Jaekel 	}
764e9a5e479SAndreas Jaekel 	return (0);
765e9a5e479SAndreas Jaekel }
766e9a5e479SAndreas Jaekel 
767e9a5e479SAndreas Jaekel static int
768e9a5e479SAndreas Jaekel zev_set_global_max_queue_len(int fd, char *arg)
769e9a5e479SAndreas Jaekel {
770e9a5e479SAndreas Jaekel 	uint64_t maxqueuelen;
771e9a5e479SAndreas Jaekel 
772e9a5e479SAndreas Jaekel 	errno = 0;
773e9a5e479SAndreas Jaekel 	maxqueuelen = strtol(arg, (char **)NULL, 10);
774e9a5e479SAndreas Jaekel 	if (errno) {
775e9a5e479SAndreas Jaekel 		fprintf(stderr, "invalid queue length parameter: %s\n", arg);
776e9a5e479SAndreas Jaekel 		return (EXIT_FAILURE);
777e9a5e479SAndreas Jaekel 	}
778e9a5e479SAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_SET_MAX_QUEUE_LEN, &maxqueuelen)) {
779e9a5e479SAndreas Jaekel 		perror("setting max queue length failed");
780205a9bc9SAndreas Jaekel 		return (EXIT_FAILURE);
781205a9bc9SAndreas Jaekel 	}
782205a9bc9SAndreas Jaekel 	return (0);
783205a9bc9SAndreas Jaekel }
784205a9bc9SAndreas Jaekel 
785205a9bc9SAndreas Jaekel static int
7862bb8e5e2SAndreas Jaekel zev_mute_unmute_impl(int fd, char *poolname, int mute)
7872bb8e5e2SAndreas Jaekel {
7882bb8e5e2SAndreas Jaekel 	zev_ioctl_poolarg_t pa;
7892bb8e5e2SAndreas Jaekel 	int len;
7902bb8e5e2SAndreas Jaekel 	int op = mute ? ZEV_IOC_MUTE_POOL : ZEV_IOC_UNMUTE_POOL;
7912bb8e5e2SAndreas Jaekel 	len = strlen(poolname);
7922bb8e5e2SAndreas Jaekel 	if (len <= 0 || len >= sizeof(pa.zev_poolname)) {
7932bb8e5e2SAndreas Jaekel 		fprintf(stderr, "invalid poolname: %s\n", poolname);
7942bb8e5e2SAndreas Jaekel 		return (EXIT_FAILURE);
7952bb8e5e2SAndreas Jaekel 	}
7962bb8e5e2SAndreas Jaekel 	strcpy(pa.zev_poolname, poolname);
7972bb8e5e2SAndreas Jaekel 	pa.zev_poolname_len = len;
7982bb8e5e2SAndreas Jaekel 	if (ioctl(fd, op, &pa)) {
7992bb8e5e2SAndreas Jaekel 		perror("muting pool data failed");
8002bb8e5e2SAndreas Jaekel 		return (EXIT_FAILURE);
8012bb8e5e2SAndreas Jaekel 	}
8022bb8e5e2SAndreas Jaekel 	return (0);
8032bb8e5e2SAndreas Jaekel }
8042bb8e5e2SAndreas Jaekel 
8052bb8e5e2SAndreas Jaekel int
8062bb8e5e2SAndreas Jaekel zev_mute_pool(int fd, char *poolname)
8072bb8e5e2SAndreas Jaekel {
8082bb8e5e2SAndreas Jaekel 	return zev_mute_unmute_impl(fd, poolname, 1);
8092bb8e5e2SAndreas Jaekel }
8102bb8e5e2SAndreas Jaekel 
8112bb8e5e2SAndreas Jaekel int
8122bb8e5e2SAndreas Jaekel zev_unmute_pool(int fd, char *poolname)
8132bb8e5e2SAndreas Jaekel {
8142bb8e5e2SAndreas Jaekel 	return zev_mute_unmute_impl(fd, poolname, 0);
8152bb8e5e2SAndreas Jaekel }
8162bb8e5e2SAndreas Jaekel 
81701c2c787SAndreas Jaekel static int
818e9a5e479SAndreas Jaekel zev_debug_info(int fd)
819e9a5e479SAndreas Jaekel {
820e9a5e479SAndreas Jaekel 	zev_ioctl_debug_info_t di;
821e9a5e479SAndreas Jaekel 
822e9a5e479SAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_GET_DEBUG_INFO, &di)) {
823e9a5e479SAndreas Jaekel 		perror("getting zev debug info failed");
824e9a5e479SAndreas Jaekel 		return (EXIT_FAILURE);
825e9a5e479SAndreas Jaekel 	}
826e9a5e479SAndreas Jaekel 
827e9a5e479SAndreas Jaekel 	printf("memory allocated: %llu bytes\n", di.zev_memory_allocated);
8285e286361SAndreas Jaekel 	printf("checksum cache size: %llu\n", di.zev_chksum_cache_size);
8295e286361SAndreas Jaekel 	printf("checksum cache hits: %llu\n", di.zev_chksum_cache_hits);
8305e286361SAndreas Jaekel 	printf("checksum cache misses: %llu\n", di.zev_chksum_cache_misses);
831e9a5e479SAndreas Jaekel 	return 0;
832e9a5e479SAndreas Jaekel }
833e9a5e479SAndreas Jaekel 
834e9a5e479SAndreas Jaekel static int
83501c2c787SAndreas Jaekel zev_mark(int fd, char *arg)
83601c2c787SAndreas Jaekel {
83701c2c787SAndreas Jaekel 	zev_ioctl_mark_t *mark;
83801c2c787SAndreas Jaekel 	uint64_t guid;
83901c2c787SAndreas Jaekel 	int len;
84001c2c787SAndreas Jaekel 	char *p;
84101c2c787SAndreas Jaekel 
84201c2c787SAndreas Jaekel 	p = strchr(arg, ':');
84301c2c787SAndreas Jaekel 	if (!p) {
84401c2c787SAndreas Jaekel 		fprintf(stderr, "expected value is <guid>:<payload>, "
84501c2c787SAndreas Jaekel 		        "e.g. '123:hello'\n");
84601c2c787SAndreas Jaekel 		exit (EXIT_FAILURE);
84701c2c787SAndreas Jaekel 	}
84801c2c787SAndreas Jaekel 	*p = '\n';
84901c2c787SAndreas Jaekel 	p++;
85001c2c787SAndreas Jaekel 
85101c2c787SAndreas Jaekel 	errno = 0;
852e9a5e479SAndreas Jaekel 	guid = strtoll(arg, (char **)NULL, 10);
85301c2c787SAndreas Jaekel 	if (errno) {
85401c2c787SAndreas Jaekel 		fprintf(stderr, "guid must be a number.\n");
85501c2c787SAndreas Jaekel 		exit (EXIT_FAILURE);
85601c2c787SAndreas Jaekel 	}
85701c2c787SAndreas Jaekel 
85801c2c787SAndreas Jaekel 	len = strlen(p);
85901c2c787SAndreas Jaekel 
86001c2c787SAndreas Jaekel 	mark = malloc(sizeof(*mark) + len + 1);
86101c2c787SAndreas Jaekel 	if (!mark) {
86201c2c787SAndreas Jaekel 		fprintf(stderr, "can't allocate mark structure: %s\n",
86301c2c787SAndreas Jaekel 		        strerror(errno));
86401c2c787SAndreas Jaekel 		exit (EXIT_FAILURE);
86501c2c787SAndreas Jaekel 	}
86601c2c787SAndreas Jaekel 	mark->zev_guid = guid;
86701c2c787SAndreas Jaekel 	mark->zev_mark_id = 0;
86801c2c787SAndreas Jaekel 	mark->zev_payload_len = len;
86901c2c787SAndreas Jaekel 	strcpy(ZEV_PAYLOAD(mark), p);
87001c2c787SAndreas Jaekel 
87101c2c787SAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_MARK, mark)) {
87201c2c787SAndreas Jaekel 		perror("queueing mark failed");
87301c2c787SAndreas Jaekel 		return (EXIT_FAILURE);
87401c2c787SAndreas Jaekel 	}
87501c2c787SAndreas Jaekel 
87601c2c787SAndreas Jaekel 	printf("mark id: %lu\n", mark->zev_mark_id);
87701c2c787SAndreas Jaekel 	return (0);
87801c2c787SAndreas Jaekel }
87901c2c787SAndreas Jaekel 
880e9a5e479SAndreas Jaekel static int
881e9a5e479SAndreas Jaekel zev_queue_blocking(int fd, char *arg, int block)
882e9a5e479SAndreas Jaekel {
883e9a5e479SAndreas Jaekel 	zev_ioctl_get_queue_properties_t gqp;
884e9a5e479SAndreas Jaekel 
8854ca7dd5eSAndreas Jaekel 	gqp.zev_queue_name.zev_namelen = strlen(arg);
8864ca7dd5eSAndreas Jaekel 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
887e9a5e479SAndreas Jaekel 		fprintf(stderr, "queue name too long.\n");
888e9a5e479SAndreas Jaekel 		return EXIT_FAILURE;
889e9a5e479SAndreas Jaekel 	}
8904ca7dd5eSAndreas Jaekel 	strcpy(gqp.zev_queue_name.zev_name, arg);
891e9a5e479SAndreas Jaekel 
892e9a5e479SAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
893e9a5e479SAndreas Jaekel 		perror("getting queue properties failed");
894e9a5e479SAndreas Jaekel 		return (EXIT_FAILURE);
895e9a5e479SAndreas Jaekel 	}
896e9a5e479SAndreas Jaekel 	if (block) {
897e9a5e479SAndreas Jaekel 		gqp.zev_flags |= ZEV_FL_BLOCK_WHILE_QUEUE_FULL;
898e9a5e479SAndreas Jaekel 	} else {
899e9a5e479SAndreas Jaekel 		gqp.zev_flags &= ~ZEV_FL_BLOCK_WHILE_QUEUE_FULL;
900e9a5e479SAndreas Jaekel 	}
901e9a5e479SAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) {
902e9a5e479SAndreas Jaekel 		perror("setting queue properties failed");
903e9a5e479SAndreas Jaekel 		return (EXIT_FAILURE);
904e9a5e479SAndreas Jaekel 	}
905e9a5e479SAndreas Jaekel 	return (0);
906e9a5e479SAndreas Jaekel }
907e9a5e479SAndreas Jaekel 
908e9a5e479SAndreas Jaekel static int
909e9a5e479SAndreas Jaekel zev_set_max_queue_len(int fd, char *arg, char *len)
910e9a5e479SAndreas Jaekel {
911e9a5e479SAndreas Jaekel 	zev_ioctl_get_queue_properties_t gqp;
912e9a5e479SAndreas Jaekel 
913e9a5e479SAndreas Jaekel 	if (!len) {
914e9a5e479SAndreas Jaekel 		fprintf(stderr, "queue size parameter missing.\n");
915e9a5e479SAndreas Jaekel 		return EXIT_FAILURE;
916e9a5e479SAndreas Jaekel 	}
917e9a5e479SAndreas Jaekel 
9184ca7dd5eSAndreas Jaekel 	gqp.zev_queue_name.zev_namelen = strlen(arg);
9194ca7dd5eSAndreas Jaekel 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
920e9a5e479SAndreas Jaekel 		fprintf(stderr, "queue name too long.\n");
921e9a5e479SAndreas Jaekel 		return EXIT_FAILURE;
922e9a5e479SAndreas Jaekel 	}
9234ca7dd5eSAndreas Jaekel 	strcpy(gqp.zev_queue_name.zev_name, arg);
924e9a5e479SAndreas Jaekel 
925e9a5e479SAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
926e9a5e479SAndreas Jaekel 		perror("getting queue properties failed");
927e9a5e479SAndreas Jaekel 		return (EXIT_FAILURE);
928e9a5e479SAndreas Jaekel 	}
929e9a5e479SAndreas Jaekel 	gqp.zev_max_queue_len = atol(len);
930e9a5e479SAndreas Jaekel 	if (gqp.zev_max_queue_len == 0 && strcmp("0", len)) {
931e9a5e479SAndreas Jaekel 		fprintf(stderr, "queue size parameter garbled.\n");
932e9a5e479SAndreas Jaekel 		return (EXIT_FAILURE);
933e9a5e479SAndreas Jaekel 	}
934e9a5e479SAndreas Jaekel 	if (gqp.zev_max_queue_len > ZEV_MAX_QUEUE_LEN) {
935e9a5e479SAndreas Jaekel 		fprintf(stderr, "queue size parameter out of bounds.\n");
936e9a5e479SAndreas Jaekel 		return (EXIT_FAILURE);
937e9a5e479SAndreas Jaekel 	}
938e9a5e479SAndreas Jaekel 
939e9a5e479SAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) {
940e9a5e479SAndreas Jaekel 		perror("setting queue properties failed");
941e9a5e479SAndreas Jaekel 		return (EXIT_FAILURE);
942e9a5e479SAndreas Jaekel 	}
943e9a5e479SAndreas Jaekel 	return (0);
944e9a5e479SAndreas Jaekel }
945e9a5e479SAndreas Jaekel 
946e9a5e479SAndreas Jaekel static int
947e9a5e479SAndreas Jaekel zev_set_poll_wakeup_queue_len(int fd, char *arg, char *len)
948e9a5e479SAndreas Jaekel {
949e9a5e479SAndreas Jaekel 	zev_ioctl_get_queue_properties_t gqp;
950e9a5e479SAndreas Jaekel 
951e9a5e479SAndreas Jaekel 	if (!len) {
952e9a5e479SAndreas Jaekel 		fprintf(stderr, "poll throttle parameter missing.\n");
953e9a5e479SAndreas Jaekel 		return EXIT_FAILURE;
954e9a5e479SAndreas Jaekel 	}
955e9a5e479SAndreas Jaekel 
9564ca7dd5eSAndreas Jaekel 	gqp.zev_queue_name.zev_namelen = strlen(arg);
9574ca7dd5eSAndreas Jaekel 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
958e9a5e479SAndreas Jaekel 		fprintf(stderr, "queue name too long.\n");
959e9a5e479SAndreas Jaekel 		return EXIT_FAILURE;
960e9a5e479SAndreas Jaekel 	}
9614ca7dd5eSAndreas Jaekel 	strcpy(gqp.zev_queue_name.zev_name, arg);
962e9a5e479SAndreas Jaekel 
963e9a5e479SAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
964e9a5e479SAndreas Jaekel 		perror("getting queue properties failed");
965e9a5e479SAndreas Jaekel 		return (EXIT_FAILURE);
966e9a5e479SAndreas Jaekel 	}
967e9a5e479SAndreas Jaekel 	gqp.zev_poll_wakeup_threshold = atol(len);
968e9a5e479SAndreas Jaekel 	if (gqp.zev_poll_wakeup_threshold == 0 && strcmp("0", len)) {
969e9a5e479SAndreas Jaekel 		fprintf(stderr, "poll throttle parameter garbled.\n");
970e9a5e479SAndreas Jaekel 		return (EXIT_FAILURE);
971e9a5e479SAndreas Jaekel 	}
9724ca7dd5eSAndreas Jaekel 	if (gqp.zev_poll_wakeup_threshold > ZEV_MAX_POLL_WAKEUP_QUEUE_LEN) {
973e9a5e479SAndreas Jaekel 		fprintf(stderr, "poll throttle parameter out of bounds.\n");
974e9a5e479SAndreas Jaekel 		return (EXIT_FAILURE);
975e9a5e479SAndreas Jaekel 	}
976e9a5e479SAndreas Jaekel 
977e9a5e479SAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) {
978e9a5e479SAndreas Jaekel 		perror("setting queue properties failed");
979e9a5e479SAndreas Jaekel 		return (EXIT_FAILURE);
980e9a5e479SAndreas Jaekel 	}
981e9a5e479SAndreas Jaekel 	return (0);
982e9a5e479SAndreas Jaekel }
983e9a5e479SAndreas Jaekel 
984e9a5e479SAndreas Jaekel static int
985e9a5e479SAndreas Jaekel zev_queue_properties(int fd, char *arg)
986e9a5e479SAndreas Jaekel {
987e9a5e479SAndreas Jaekel 	zev_ioctl_get_queue_properties_t gqp;
988e9a5e479SAndreas Jaekel 
9894ca7dd5eSAndreas Jaekel 	gqp.zev_queue_name.zev_namelen = strlen(arg);
9904ca7dd5eSAndreas Jaekel 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
991e9a5e479SAndreas Jaekel 		fprintf(stderr, "queue name too long.\n");
992e9a5e479SAndreas Jaekel 		return EXIT_FAILURE;
993e9a5e479SAndreas Jaekel 	}
9944ca7dd5eSAndreas Jaekel 	strcpy(gqp.zev_queue_name.zev_name, arg);
995e9a5e479SAndreas Jaekel 
996e9a5e479SAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
997e9a5e479SAndreas Jaekel 		perror("getting queue properties failed");
998e9a5e479SAndreas Jaekel 		return (EXIT_FAILURE);
999e9a5e479SAndreas Jaekel 	}
1000e9a5e479SAndreas Jaekel 
1001e9a5e479SAndreas Jaekel 	printf("queue        : %s\n", arg);
1002e9a5e479SAndreas Jaekel 	printf("max size     : %" PRIu64 "\n", gqp.zev_max_queue_len);
1003e9a5e479SAndreas Jaekel 	printf("poll throttle: %" PRIu64 "\n", gqp.zev_poll_wakeup_threshold);
1004e9a5e479SAndreas Jaekel 	printf("persistent   : %s\n",
1005e9a5e479SAndreas Jaekel 		gqp.zev_flags & ZEV_FL_PERSISTENT ? "yes" : "no");
1006e9a5e479SAndreas Jaekel 	printf("blocking     : %s\n",
1007e9a5e479SAndreas Jaekel 		gqp.zev_flags & ZEV_FL_BLOCK_WHILE_QUEUE_FULL ? "yes" : "no");
1008e9a5e479SAndreas Jaekel 
1009e9a5e479SAndreas Jaekel 	return (0);
1010e9a5e479SAndreas Jaekel }
1011e9a5e479SAndreas Jaekel 
1012e9a5e479SAndreas Jaekel static int
1013e9a5e479SAndreas Jaekel zev_list_queues(int fd)
1014e9a5e479SAndreas Jaekel {
1015e9a5e479SAndreas Jaekel 	zev_ioctl_get_queue_properties_t gqp;
1016e9a5e479SAndreas Jaekel 	zev_ioctl_get_queue_list_t gql;
1017e9a5e479SAndreas Jaekel 	zev_ioctl_get_queue_statistics_t gs;
1018e9a5e479SAndreas Jaekel 	uint64_t	i;
1019e9a5e479SAndreas Jaekel 	char		name[ZEV_MAX_QUEUE_NAME_LEN+1];
1020e9a5e479SAndreas Jaekel 
1021e9a5e479SAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_LIST, &gql)) {
1022e9a5e479SAndreas Jaekel 		perror("getting queue list failed");
1023e9a5e479SAndreas Jaekel 		return (EXIT_FAILURE);
1024e9a5e479SAndreas Jaekel 	}
1025e9a5e479SAndreas Jaekel 
1026e9a5e479SAndreas Jaekel 	printf("Name                                     Size       "
1027e9a5e479SAndreas Jaekel 	       "Max Size   Wakeup Per Block\n");
1028e9a5e479SAndreas Jaekel 
1029e9a5e479SAndreas Jaekel 	for (i=0; i<gql.zev_n_queues; i++) {
1030e9a5e479SAndreas Jaekel 		strncpy(name, gql.zev_queue_name[i].zev_name,
1031e9a5e479SAndreas Jaekel 		        ZEV_MAX_QUEUE_NAME_LEN);
1032e9a5e479SAndreas Jaekel 		name[gql.zev_queue_name[i].zev_namelen] = '\0';
1033e9a5e479SAndreas Jaekel 
10344ca7dd5eSAndreas Jaekel 		memcpy(gqp.zev_queue_name.zev_name,
10354ca7dd5eSAndreas Jaekel 		    gql.zev_queue_name[i].zev_name, ZEV_MAX_QUEUE_NAME_LEN);
10364ca7dd5eSAndreas Jaekel 		gqp.zev_queue_name.zev_namelen =
10374ca7dd5eSAndreas Jaekel 		    gql.zev_queue_name[i].zev_namelen;
1038e9a5e479SAndreas Jaekel 
1039e9a5e479SAndreas Jaekel 		if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
1040e9a5e479SAndreas Jaekel 			if (errno == ENOENT)
1041e9a5e479SAndreas Jaekel 				continue;
1042e9a5e479SAndreas Jaekel 			perror("getting queue properties failed");
1043e9a5e479SAndreas Jaekel 			return (EXIT_FAILURE);
1044e9a5e479SAndreas Jaekel 		}
1045e9a5e479SAndreas Jaekel 
10464ca7dd5eSAndreas Jaekel 		memcpy(gs.zev_queue_name.zev_name,
10474ca7dd5eSAndreas Jaekel 		    gql.zev_queue_name[i].zev_name, ZEV_MAX_QUEUE_NAME_LEN);
10484ca7dd5eSAndreas Jaekel 		gs.zev_queue_name.zev_namelen =
10494ca7dd5eSAndreas Jaekel 		    gql.zev_queue_name[i].zev_namelen;
1050e9a5e479SAndreas Jaekel 
1051e9a5e479SAndreas Jaekel 		if (ioctl(fd, ZEV_IOC_GET_QUEUE_STATISTICS, &gs)) {
1052e9a5e479SAndreas Jaekel 			if (errno == ENOENT)
1053e9a5e479SAndreas Jaekel 				continue;
1054e9a5e479SAndreas Jaekel 			perror("getting statistics data failed");
1055e9a5e479SAndreas Jaekel 			return (EXIT_FAILURE);
1056e9a5e479SAndreas Jaekel 		}
1057e9a5e479SAndreas Jaekel 
1058e9a5e479SAndreas Jaekel 		printf("%-40s %-10" PRIu64 " %-10" PRIu64 " %-6" PRIu64
1059e9a5e479SAndreas Jaekel 		       " %-3s %-3s\n",
1060e9a5e479SAndreas Jaekel 			name,
1061e9a5e479SAndreas Jaekel 			gs.zev_statistics.zev_queue_len,
1062e9a5e479SAndreas Jaekel 			gqp.zev_max_queue_len,
1063e9a5e479SAndreas Jaekel 			gqp.zev_poll_wakeup_threshold,
1064e9a5e479SAndreas Jaekel 			gqp.zev_flags & ZEV_FL_PERSISTENT ? "yes" : "no",
1065e9a5e479SAndreas Jaekel 			gqp.zev_flags & ZEV_FL_BLOCK_WHILE_QUEUE_FULL ?
1066e9a5e479SAndreas Jaekel 				 "yes" : "no");
1067e9a5e479SAndreas Jaekel 	}
1068e9a5e479SAndreas Jaekel 
1069e9a5e479SAndreas Jaekel 	return (0);
1070e9a5e479SAndreas Jaekel }
1071e9a5e479SAndreas Jaekel 
1072b9710123SAndreas Jaekel static int
1073b9710123SAndreas Jaekel zev_checksum(int dev_fd, char *filename)
1074b9710123SAndreas Jaekel {
1075b9710123SAndreas Jaekel 	int fd;
1076b9710123SAndreas Jaekel 	offset_t off;
1077b9710123SAndreas Jaekel 	offset_t data;
1078b9710123SAndreas Jaekel 	zev_sig_t *sig;
1079b9710123SAndreas Jaekel 	char *buf;
1080b9710123SAndreas Jaekel 	zev_ioctl_get_signatures_t *gs;
1081b9710123SAndreas Jaekel 	int i;
1082b9710123SAndreas Jaekel 	char sigval[(SHA1_DIGEST_LENGTH * 2) + 1];
1083b9710123SAndreas Jaekel 	int buf_size;
1084b9710123SAndreas Jaekel 
1085b9710123SAndreas Jaekel 	/* control struct, one lv1 signature and up to 256 lv0 signatures */
1086b9710123SAndreas Jaekel 	buf_size = (1 + 256) * sizeof(zev_sig_t);
1087b9710123SAndreas Jaekel 	buf = malloc(sizeof(zev_ioctl_get_signatures_t) + buf_size);
1088b9710123SAndreas Jaekel 	if (!buf) {
1089b9710123SAndreas Jaekel 		perror("can't allocate checksum buffer");
1090b9710123SAndreas Jaekel 		return (EXIT_FAILURE);
1091b9710123SAndreas Jaekel 	}
1092b9710123SAndreas Jaekel 
1093b9710123SAndreas Jaekel 	fd = open(filename, O_RDONLY);
1094b9710123SAndreas Jaekel 	if (fd < 0) {
1095b9710123SAndreas Jaekel 		perror("can't open file");
1096b9710123SAndreas Jaekel 		return (EXIT_FAILURE);
1097b9710123SAndreas Jaekel 	}
1098b9710123SAndreas Jaekel 
1099b9710123SAndreas Jaekel 	gs = (zev_ioctl_get_signatures_t *)buf;
1100b9710123SAndreas Jaekel 	gs->zev_fd = fd;
1101b9710123SAndreas Jaekel 	gs->zev_bufsize = buf_size;
1102b9710123SAndreas Jaekel 
1103b9710123SAndreas Jaekel 	off = 0;
1104b9710123SAndreas Jaekel 	data = 0;
1105b9710123SAndreas Jaekel 	while (1) {
1106b9710123SAndreas Jaekel 		errno = 0;
1107b9710123SAndreas Jaekel 		data = llseek(fd, off, SEEK_DATA);
1108b9710123SAndreas Jaekel 		if (data < 0) {
1109b9710123SAndreas Jaekel 			if (errno == ENXIO)	/* no more data */
1110b9710123SAndreas Jaekel 				break;
1111b9710123SAndreas Jaekel 			perror("llseek failed");
1112b9710123SAndreas Jaekel 			goto err;
1113b9710123SAndreas Jaekel 		}
1114b9710123SAndreas Jaekel 		data = P2ALIGN(data, ZEV_L1_SIZE);
1115b9710123SAndreas Jaekel 		off = data + ZEV_L1_SIZE;
1116b9710123SAndreas Jaekel 
1117b9710123SAndreas Jaekel 		gs->zev_offset = data;
1118b9710123SAndreas Jaekel 		gs->zev_len = ZEV_L1_SIZE;
1119b9710123SAndreas Jaekel 
1120b9710123SAndreas Jaekel 		if (ioctl(dev_fd, ZEV_IOC_GET_FILE_SIGNATURES, gs)) {
1121b9710123SAndreas Jaekel 			perror("ioctl to get signatures failed");
1122b9710123SAndreas Jaekel 			goto err;
1123b9710123SAndreas Jaekel 		}
1124b9710123SAndreas Jaekel 
1125b9710123SAndreas Jaekel 		for (i=0; i<gs->zev_signature_cnt; i++) {
1126b9710123SAndreas Jaekel 			sig = (zev_sig_t *)ZEV_SIGNATURES(gs);
1127b9710123SAndreas Jaekel 			sig += i;
1128b9710123SAndreas Jaekel 			sig2hex_direct(sig->value, sigval);
1129b9710123SAndreas Jaekel 			printf("level %d, offset %llu, value %s\n",
1130b9710123SAndreas Jaekel 			       sig->level, sig->block_offset, sigval);
1131b9710123SAndreas Jaekel 		}
1132b9710123SAndreas Jaekel 	}
1133b9710123SAndreas Jaekel 
1134b9710123SAndreas Jaekel 	free(buf);
1135b9710123SAndreas Jaekel 	close(fd);
1136b9710123SAndreas Jaekel 	return 0;
1137b9710123SAndreas Jaekel err:
1138b9710123SAndreas Jaekel 	free(buf);
1139b9710123SAndreas Jaekel 	close(fd);
1140b9710123SAndreas Jaekel 	return (EXIT_FAILURE);
1141b9710123SAndreas Jaekel }
1142b9710123SAndreas Jaekel 
11432bb8e5e2SAndreas Jaekel int
11442bb8e5e2SAndreas Jaekel main(int argc, char **argv)
11452bb8e5e2SAndreas Jaekel {
11462bb8e5e2SAndreas Jaekel 	int fd;
11472bb8e5e2SAndreas Jaekel 	int c;
11482bb8e5e2SAndreas Jaekel 	extern char *optarg;
11494ca7dd5eSAndreas Jaekel 	int create_tmp_queue = 1;
11504ca7dd5eSAndreas Jaekel 	char buf[MAXPATHLEN];
11512bb8e5e2SAndreas Jaekel 
11522bb8e5e2SAndreas Jaekel 	/* open device */
11532bb8e5e2SAndreas Jaekel 	fd = open(zev_device, O_RDONLY);
11542bb8e5e2SAndreas Jaekel 	if (fd < 0) {
11552bb8e5e2SAndreas Jaekel 		perror("opening zev device failed");
11562bb8e5e2SAndreas Jaekel 		return EXIT_FAILURE;
11572bb8e5e2SAndreas Jaekel 	}
11584ca7dd5eSAndreas Jaekel 	while ((c = getopt(argc, argv,
1159*d65b2fffSAndreas Jaekel 	                   "gvspc:d:Dlk:L:q:Qt:m:M:a:A:r:P:b:B:h?")) != -1){
11602bb8e5e2SAndreas Jaekel 		switch(c) {
1161*d65b2fffSAndreas Jaekel 		case 'g':
1162*d65b2fffSAndreas Jaekel 			grep_friendly++;
1163*d65b2fffSAndreas Jaekel 			verbose++;
1164*d65b2fffSAndreas Jaekel 			break;
11655e286361SAndreas Jaekel 		case 'v':
11665e286361SAndreas Jaekel 			verbose++;
11675e286361SAndreas Jaekel 			break;
11682bb8e5e2SAndreas Jaekel 		case 's':
1169e9a5e479SAndreas Jaekel 			return zev_statistics(fd);
11702bb8e5e2SAndreas Jaekel 		case 'p':
11714ca7dd5eSAndreas Jaekel 			return zev_poll_events(fd, create_tmp_queue);
1172b9710123SAndreas Jaekel 		case 'c':
1173b9710123SAndreas Jaekel 			return zev_checksum(fd, optarg);
1174e9a5e479SAndreas Jaekel 		case 'D':
1175e9a5e479SAndreas Jaekel 			return zev_debug_info(fd);
11762bb8e5e2SAndreas Jaekel 		case 'd':
1177e9a5e479SAndreas Jaekel 			close(fd);
11782bb8e5e2SAndreas Jaekel 			zev_device = optarg;
1179e9a5e479SAndreas Jaekel 			fd = open(zev_device, O_RDONLY);
1180e9a5e479SAndreas Jaekel 			if (fd < 0) {
1181e9a5e479SAndreas Jaekel 				perror("opening zev device failed");
1182e9a5e479SAndreas Jaekel 				return EXIT_FAILURE;
1183e9a5e479SAndreas Jaekel 			}
11844ca7dd5eSAndreas Jaekel 			create_tmp_queue = 0;
11854ca7dd5eSAndreas Jaekel 			break;
11864ca7dd5eSAndreas Jaekel 		case 'q':
11874ca7dd5eSAndreas Jaekel 			snprintf(buf, sizeof(buf),
11884ca7dd5eSAndreas Jaekel 				 "/devices/pseudo/zev@0:%s", optarg);
11894ca7dd5eSAndreas Jaekel 			close(fd);
11904ca7dd5eSAndreas Jaekel 			zev_device = buf;
11914ca7dd5eSAndreas Jaekel 			fd = open(zev_device, O_RDONLY);
11924ca7dd5eSAndreas Jaekel 			if (fd < 0) {
11934ca7dd5eSAndreas Jaekel 				perror("opening zev device failed");
11944ca7dd5eSAndreas Jaekel 				return EXIT_FAILURE;
11954ca7dd5eSAndreas Jaekel 			}
11964ca7dd5eSAndreas Jaekel 			create_tmp_queue = 0;
11972bb8e5e2SAndreas Jaekel 			break;
1198e9a5e479SAndreas Jaekel 		case 'l':
1199e9a5e479SAndreas Jaekel 			return zev_list_queues(fd);
1200e9a5e479SAndreas Jaekel 		case 'Q':
1201e9a5e479SAndreas Jaekel 			return zev_set_global_max_queue_len(fd, optarg);
12024ca7dd5eSAndreas Jaekel 		case 'L':
1203e9a5e479SAndreas Jaekel 			return zev_set_max_queue_len(fd, optarg, argv[optind]);
1204205a9bc9SAndreas Jaekel 		case 't':
1205e9a5e479SAndreas Jaekel 			return zev_set_poll_wakeup_queue_len(fd, optarg,
1206e9a5e479SAndreas Jaekel 			                                     argv[optind]);
12072bb8e5e2SAndreas Jaekel 		case 'm':
12082bb8e5e2SAndreas Jaekel 			return zev_mute_pool(fd, optarg);
12092bb8e5e2SAndreas Jaekel 		case 'M':
12102bb8e5e2SAndreas Jaekel 			return zev_unmute_pool(fd, optarg);
121101c2c787SAndreas Jaekel 		case 'k':
121201c2c787SAndreas Jaekel 			return zev_mark(fd, optarg);
1213e9a5e479SAndreas Jaekel 		case 'a':
12144ca7dd5eSAndreas Jaekel 			return zev_add_queue(fd, optarg, 0);
12154ca7dd5eSAndreas Jaekel 		case 'A':
12164ca7dd5eSAndreas Jaekel 			return zev_add_queue(fd, optarg, 1);
1217e9a5e479SAndreas Jaekel 		case 'r':
1218e9a5e479SAndreas Jaekel 			return zev_remove_queue(fd, optarg);
1219e9a5e479SAndreas Jaekel 		case 'b':
1220e9a5e479SAndreas Jaekel 			return zev_queue_blocking(fd, optarg, 0);
1221e9a5e479SAndreas Jaekel 		case 'B':
1222e9a5e479SAndreas Jaekel 			return zev_queue_blocking(fd, optarg, 1);
1223e9a5e479SAndreas Jaekel 		case 'P':
1224e9a5e479SAndreas Jaekel 			return zev_queue_properties(fd, optarg);
12252bb8e5e2SAndreas Jaekel 		case 'h':
12262bb8e5e2SAndreas Jaekel 		case '?':
12272bb8e5e2SAndreas Jaekel 		default:
12282bb8e5e2SAndreas Jaekel 			usage(argv[0]);
12292bb8e5e2SAndreas Jaekel 		}
12302bb8e5e2SAndreas Jaekel 	}
12312bb8e5e2SAndreas Jaekel 	usage(argv[0]);
12322bb8e5e2SAndreas Jaekel 	close(fd);
1233e9a5e479SAndreas Jaekel 	return EXIT_FAILURE;
12342bb8e5e2SAndreas Jaekel }
12352bb8e5e2SAndreas Jaekel 
1236