xref: /titanic_50/usr/src/cmd/zevadm/zevadm.c (revision 1ca5a13b91f7b1ae27d6dd26a0fd511ef5492d35)
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>
11d65b2fffSAndreas 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[] = {
18d65b2fffSAndreas Jaekel 	"ERROR",
19d65b2fffSAndreas Jaekel 	"MARK",
20d65b2fffSAndreas Jaekel 	"ZFS_MOUNT",
21d65b2fffSAndreas Jaekel 	"ZFS_UMOUNT",
22d65b2fffSAndreas Jaekel 	"ZVOL_WRITE",
23d65b2fffSAndreas Jaekel 	"ZVOL_TRUNCATE",
24d65b2fffSAndreas Jaekel 	"ZNODE_CLOSE_AFTER_UPDATE",
25d65b2fffSAndreas Jaekel 	"ZNODE_CREATE",
26d65b2fffSAndreas Jaekel 	"ZNODE_MKDIR",
27d65b2fffSAndreas Jaekel 	"ZNODE_MAKE_XATTR_DIR",
28d65b2fffSAndreas Jaekel 	"ZNODE_REMOVE",
29d65b2fffSAndreas Jaekel 	"ZNODE_RMDIR",
30d65b2fffSAndreas Jaekel 	"ZNODE_LINK",
31d65b2fffSAndreas Jaekel 	"ZNODE_SYMLINK",
32d65b2fffSAndreas Jaekel 	"ZNODE_RENAME",
33d65b2fffSAndreas Jaekel 	"ZNODE_WRITE",
34d65b2fffSAndreas Jaekel 	"ZNODE_TRUNCATE",
35d65b2fffSAndreas Jaekel 	"ZNODE_SETATTR",
36d65b2fffSAndreas Jaekel 	"ZNODE_ACL",
379193e9c2SAndreas Jaekel 	NULL
389193e9c2SAndreas Jaekel };
399193e9c2SAndreas Jaekel 
405e286361SAndreas Jaekel static int verbose = 0;
41d65b2fffSAndreas Jaekel static int grep_friendly = 0;
42d65b2fffSAndreas Jaekel 
43d65b2fffSAndreas Jaekel static void
44d65b2fffSAndreas Jaekel zpf(char *fmt, ...)
45d65b2fffSAndreas Jaekel {
46d65b2fffSAndreas Jaekel 	va_list	ap;
47d65b2fffSAndreas Jaekel 
48d65b2fffSAndreas Jaekel 	va_start(ap, fmt);
49d65b2fffSAndreas Jaekel 	vprintf(fmt, ap);
50d65b2fffSAndreas Jaekel 	va_end(ap);
51d65b2fffSAndreas Jaekel 	if (grep_friendly) {
52d65b2fffSAndreas Jaekel 		printf(" ");
53d65b2fffSAndreas Jaekel 	} else {
54d65b2fffSAndreas Jaekel 		printf("\n");
55d65b2fffSAndreas Jaekel 	}
56d65b2fffSAndreas Jaekel }
57d65b2fffSAndreas Jaekel 
58d65b2fffSAndreas Jaekel static void
59d65b2fffSAndreas Jaekel znl(void)
60d65b2fffSAndreas Jaekel {
61d65b2fffSAndreas Jaekel 	if (grep_friendly)
62d65b2fffSAndreas Jaekel 		printf("\n");
63d65b2fffSAndreas Jaekel }
645e286361SAndreas Jaekel 
65*1ca5a13bSAndreas Jaekel static void
66*1ca5a13bSAndreas Jaekel sig2hex_direct(const uint8_t *sig, char *hex)
67*1ca5a13bSAndreas Jaekel {
68*1ca5a13bSAndreas Jaekel 	int     i;
69*1ca5a13bSAndreas Jaekel 
70*1ca5a13bSAndreas Jaekel 	for (i = 0; i < SHA1_DIGEST_LENGTH; ++i) {
71*1ca5a13bSAndreas Jaekel 		sprintf(hex + 2 * i, "%02x", sig[i]);
72*1ca5a13bSAndreas Jaekel 	}
73*1ca5a13bSAndreas Jaekel 	hex[SHA1_DIGEST_LENGTH * 2] = '\0';
74*1ca5a13bSAndreas Jaekel }
75*1ca5a13bSAndreas Jaekel 
76e9a5e479SAndreas Jaekel static int
772bb8e5e2SAndreas Jaekel zev_statistics(int fd)
782bb8e5e2SAndreas Jaekel {
792bb8e5e2SAndreas Jaekel 	zev_statistics_t zs;
80e9a5e479SAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_GET_GLOBAL_STATISTICS, &zs)) {
812bb8e5e2SAndreas Jaekel 		perror("getting statistics data failed");
82e9a5e479SAndreas Jaekel 		return (EXIT_FAILURE);
832bb8e5e2SAndreas Jaekel 	}
842bb8e5e2SAndreas Jaekel 	printf("ZEV module state:\n");
852bb8e5e2SAndreas Jaekel 
862bb8e5e2SAndreas Jaekel 	printf("    queue length in bytes   : %lu\n", zs.zev_queue_len);
872bb8e5e2SAndreas Jaekel 	printf("    queue length limit      : %lu\n", zs.zev_max_queue_len);
882bb8e5e2SAndreas Jaekel 	printf("    bytes read from device  : %lu\n", zs.zev_bytes_read);
892bb8e5e2SAndreas Jaekel 	printf("    module internal errors  : %lu\n\n", zs.zev_cnt_errors);
902bb8e5e2SAndreas Jaekel 
91e9a5e479SAndreas Jaekel 	printf("    discarded events        : %lu\n",
92e9a5e479SAndreas Jaekel 	    zs.zev_cnt_discarded_events);
93e9a5e479SAndreas Jaekel 	printf("    discarded bytes         : %lu\n\n", zs.zev_bytes_discarded);
94e9a5e479SAndreas Jaekel 
952bb8e5e2SAndreas Jaekel 	printf("ZFS event statistics:\n");
962bb8e5e2SAndreas Jaekel 
972bb8e5e2SAndreas Jaekel 	printf("    total ZFS events        : %lu\n", zs.zev_cnt_total_events);
982bb8e5e2SAndreas Jaekel 	printf("    ZFS mount               : %lu\n", zs.zev_cnt_zfs_mount);
992bb8e5e2SAndreas Jaekel 	printf("    ZFS umount              : %lu\n", zs.zev_cnt_zfs_umount);
1002bb8e5e2SAndreas Jaekel 	printf("    ZVOL write              : %lu\n", zs.zev_cnt_zvol_write);
1012bb8e5e2SAndreas Jaekel 	printf("    ZVOL truncate           : %lu\n", zs.zev_cnt_zvol_truncate);
1022bb8e5e2SAndreas Jaekel 	printf("    ZNODE close after update: %lu\n",
1032bb8e5e2SAndreas Jaekel 	    zs.zev_cnt_znode_close_after_update);
1042bb8e5e2SAndreas Jaekel 	printf("    ZNODE create            : %lu\n", zs.zev_cnt_znode_create);
1052bb8e5e2SAndreas Jaekel 	printf("    ZNODE remove            : %lu\n", zs.zev_cnt_znode_remove);
1062bb8e5e2SAndreas Jaekel 	printf("    ZNODE link              : %lu\n", zs.zev_cnt_znode_link);
1072bb8e5e2SAndreas Jaekel 	printf("    ZNODE symlink           : %lu\n", zs.zev_cnt_znode_symlink);
1082bb8e5e2SAndreas Jaekel 	printf("    ZNODE rename            : %lu\n", zs.zev_cnt_znode_rename);
1092bb8e5e2SAndreas Jaekel 	printf("    ZNODE write             : %lu\n", zs.zev_cnt_znode_write);
1102bb8e5e2SAndreas Jaekel 	printf("    ZNODE truncate          : %lu\n",
1112bb8e5e2SAndreas Jaekel 	    zs.zev_cnt_znode_truncate);
1122bb8e5e2SAndreas Jaekel 	printf("    ZNODE setattr           : %lu\n", zs.zev_cnt_znode_setattr);
1132bb8e5e2SAndreas Jaekel 	printf("    ZNODE acl               : %lu\n", zs.zev_cnt_znode_acl);
114e9a5e479SAndreas Jaekel 	return EXIT_SUCCESS;
1152bb8e5e2SAndreas Jaekel }
1162bb8e5e2SAndreas Jaekel 
1172bb8e5e2SAndreas Jaekel static void
118d65b2fffSAndreas Jaekel zev_print_inode_info(char *name, zev_inode_info_t *info)
119d65b2fffSAndreas Jaekel {
120d65b2fffSAndreas Jaekel 	zpf("  %s.inode: %llu", name, info->ino);
121d65b2fffSAndreas Jaekel 	zpf("  %s.gen: %llu", name, info->gen);
122d65b2fffSAndreas Jaekel 	zpf("  %s.mtime: %llu", name, info->mtime);
123d65b2fffSAndreas Jaekel 	zpf("  %s.ctime: %llu", name, info->ctime);
124d65b2fffSAndreas Jaekel 	zpf("  %s.size: %llu", name, info->size);
125d65b2fffSAndreas Jaekel 	zpf("  %s.mode: %llo", name, info->mode);
126d65b2fffSAndreas Jaekel 	zpf("  %s.links: %llu", name, info->links);
127d65b2fffSAndreas Jaekel 	zpf("  %s.type: %lu", name, info->type);
128d65b2fffSAndreas Jaekel 	zpf("  %s.flags: %lu", name, info->flags);
129d65b2fffSAndreas Jaekel }
130d65b2fffSAndreas Jaekel 
131d65b2fffSAndreas Jaekel static void
132d65b2fffSAndreas Jaekel zev_print_mark_payload(zev_mark_t *rec)
133d65b2fffSAndreas Jaekel {
134d65b2fffSAndreas Jaekel 	int i;
135d65b2fffSAndreas Jaekel 	int j;
136d65b2fffSAndreas Jaekel 	uint8_t *p;
137d65b2fffSAndreas Jaekel 	char c;
138d65b2fffSAndreas Jaekel 
139d65b2fffSAndreas Jaekel 	zpf("  payload:");
140d65b2fffSAndreas Jaekel 	p = (uint8_t *)ZEV_PAYLOAD(rec);
141d65b2fffSAndreas Jaekel 	for (i=0; i<rec->payload_len; i+=16) {
142d65b2fffSAndreas Jaekel 		printf("  ");
143d65b2fffSAndreas Jaekel 		for (j=i; j<rec->payload_len && j<i+16; j++) {
144d65b2fffSAndreas Jaekel 			printf("%02x ", p[j]);
145d65b2fffSAndreas Jaekel 			if (j == i + 7)
146d65b2fffSAndreas Jaekel 				printf(" ");
147d65b2fffSAndreas Jaekel 		}
148d65b2fffSAndreas Jaekel 		if (grep_friendly)
149d65b2fffSAndreas Jaekel 			continue;
150d65b2fffSAndreas Jaekel 		for (; j<i+16; j++) {
151d65b2fffSAndreas Jaekel 			printf("   ");
152d65b2fffSAndreas Jaekel 			if (j == i + 7)
153d65b2fffSAndreas Jaekel 				printf(" ");
154d65b2fffSAndreas Jaekel 		}
155d65b2fffSAndreas Jaekel 		printf("    ");
156d65b2fffSAndreas Jaekel 		for (j=i; j<rec->payload_len && j<i+16; j++) {
157d65b2fffSAndreas Jaekel 			c = '.';
158d65b2fffSAndreas Jaekel 			if (p[j] >= ' ' && p[j] <= '~')
159d65b2fffSAndreas Jaekel 				c = p[j];
160d65b2fffSAndreas Jaekel 			printf("%c", c);
161d65b2fffSAndreas Jaekel 			if (j == i + 7)
162d65b2fffSAndreas Jaekel 				printf(" ");
163d65b2fffSAndreas Jaekel 		}
164d65b2fffSAndreas Jaekel 		printf("\n");
165d65b2fffSAndreas Jaekel 	}
166d65b2fffSAndreas Jaekel }
167d65b2fffSAndreas Jaekel 
168d65b2fffSAndreas Jaekel static void
16963aba447SAndreas Jaekel zev_print_error(char *buf)
17063aba447SAndreas Jaekel {
17163aba447SAndreas Jaekel 	zev_error_t *rec = (zev_error_t *)buf;
17263aba447SAndreas Jaekel 	time_t op_time = rec->op_time;
17363aba447SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
17463aba447SAndreas Jaekel 
175d65b2fffSAndreas Jaekel 	if (verbose) {
176d65b2fffSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
177d65b2fffSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
178d65b2fffSAndreas Jaekel 		zpf("  failed.op: %s",
179d65b2fffSAndreas Jaekel 		    zev_op_name[rec->failed_op - ZEV_OP_MIN]);
180d65b2fffSAndreas Jaekel 		zpf("  message: %s", ZEV_ERRSTR(rec));
181d65b2fffSAndreas Jaekel 		znl();
182d65b2fffSAndreas Jaekel 	} else {
18363aba447SAndreas Jaekel 		printf("%s %s: failed_op=%s msg=%s\n",
18463aba447SAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
185d65b2fffSAndreas Jaekel 		       zev_op_name[rec->failed_op - ZEV_OP_MIN],
186d65b2fffSAndreas Jaekel 		       ZEV_ERRSTR(rec));
187d65b2fffSAndreas Jaekel 	}
18863aba447SAndreas Jaekel }
18963aba447SAndreas Jaekel 
19063aba447SAndreas Jaekel static void
19101c2c787SAndreas Jaekel zev_print_mark(char *buf)
19201c2c787SAndreas Jaekel {
19301c2c787SAndreas Jaekel 	zev_mark_t *rec = (zev_mark_t *)buf;
19401c2c787SAndreas Jaekel 	time_t op_time = rec->op_time;
19501c2c787SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
19601c2c787SAndreas Jaekel 
197d65b2fffSAndreas Jaekel 	if (verbose) {
198d65b2fffSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
199d65b2fffSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
200d65b2fffSAndreas Jaekel 		zpf("  mark.id: %llu", rec->mark_id);
201d65b2fffSAndreas Jaekel 		zpf("  payload.len: %llu", rec->payload_len);
202d65b2fffSAndreas Jaekel 		if (rec->payload_len)
203d65b2fffSAndreas Jaekel 			zev_print_mark_payload(rec);
204d65b2fffSAndreas Jaekel 		znl();
205d65b2fffSAndreas Jaekel 	} else {
20601c2c787SAndreas Jaekel 		printf("%s %s: guid=%llu mark_id=%lld payload_len=%ld\n",
207d65b2fffSAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN], rec->guid,
208d65b2fffSAndreas Jaekel 		       rec->mark_id, rec->payload_len);
209d65b2fffSAndreas Jaekel 	}
21001c2c787SAndreas Jaekel }
21101c2c787SAndreas Jaekel 
21201c2c787SAndreas Jaekel static void
21363aba447SAndreas Jaekel zev_print_zfs_mount(char *buf)
21463aba447SAndreas Jaekel {
21563aba447SAndreas Jaekel 	zev_zfs_mount_t *rec = (zev_zfs_mount_t *)buf;
21663aba447SAndreas Jaekel 	time_t op_time = rec->op_time;
21763aba447SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
21863aba447SAndreas Jaekel 
219d65b2fffSAndreas Jaekel 	if (verbose) {
220d65b2fffSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
221d65b2fffSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
222d65b2fffSAndreas Jaekel 		zpf("  dataset: %s", ZEV_DATASET(rec));
223d65b2fffSAndreas Jaekel 		zpf("  mountpoint: %s", ZEV_MOUNTPOINT(rec));
224d65b2fffSAndreas Jaekel 		zpf("  remount: %s", rec->remount ? "true" : "false");
225d65b2fffSAndreas Jaekel 		zev_print_inode_info("root", &rec->root);
226d65b2fffSAndreas Jaekel 		znl();
227d65b2fffSAndreas Jaekel 	} else {
228d65b2fffSAndreas Jaekel 		printf("%s %s: guid=%llu remount=%s dataset='%s' "
229d65b2fffSAndreas Jaekel 		       "mountpoint='%s'\n",
23063aba447SAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
23163aba447SAndreas Jaekel 		       rec->guid,
23263aba447SAndreas Jaekel 		       rec->remount ? "true" : "false",
23363aba447SAndreas Jaekel 		       ZEV_DATASET(rec),
23463aba447SAndreas Jaekel 		       ZEV_MOUNTPOINT(rec));
23563aba447SAndreas Jaekel 	}
236d65b2fffSAndreas Jaekel }
23763aba447SAndreas Jaekel 
23863aba447SAndreas Jaekel static void
23963aba447SAndreas Jaekel zev_print_zfs_umount(char *buf)
24063aba447SAndreas Jaekel {
24163aba447SAndreas Jaekel 	zev_zfs_umount_t *rec = (zev_zfs_umount_t *)buf;
24263aba447SAndreas Jaekel 	time_t op_time = rec->op_time;
24363aba447SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
24463aba447SAndreas Jaekel 
245d65b2fffSAndreas Jaekel 	if (verbose) {
246d65b2fffSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
247d65b2fffSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
248d65b2fffSAndreas Jaekel 		znl();
249d65b2fffSAndreas Jaekel 	} else {
25063aba447SAndreas Jaekel 		printf("%s %s: guid=%llu\n",
25163aba447SAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
25263aba447SAndreas Jaekel 		       rec->guid);
25363aba447SAndreas Jaekel 	}
254d65b2fffSAndreas Jaekel }
25563aba447SAndreas Jaekel 
25663aba447SAndreas Jaekel static void
25763aba447SAndreas Jaekel zev_print_zvol_truncate(char *buf)
25863aba447SAndreas Jaekel {
25963aba447SAndreas Jaekel 	zev_zvol_truncate_t *rec = (zev_zvol_truncate_t *)buf;
26063aba447SAndreas Jaekel 	time_t op_time = rec->op_time;
26163aba447SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
26263aba447SAndreas Jaekel 
263d65b2fffSAndreas Jaekel 	if (verbose) {
264d65b2fffSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
265d65b2fffSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
266e206ace3SAndreas Jaekel 		zpf("  txg: %llu", rec->txg);
267d65b2fffSAndreas Jaekel 		zpf("  offset: %llu", rec->offset);
268d65b2fffSAndreas Jaekel 		zpf("  length: %llu", rec->length);
269d65b2fffSAndreas Jaekel 		znl();
270d65b2fffSAndreas Jaekel 	} else {
27163aba447SAndreas Jaekel 		printf("%s %s: guid=%llu offset=%llu length=%llu\n",
27263aba447SAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
27363aba447SAndreas Jaekel 		       rec->guid,
27463aba447SAndreas Jaekel 		       rec->offset,
27563aba447SAndreas Jaekel 		       rec->length);
27663aba447SAndreas Jaekel 	}
277d65b2fffSAndreas Jaekel }
27863aba447SAndreas Jaekel 
27963aba447SAndreas Jaekel static void
28063aba447SAndreas Jaekel zev_print_zvol_write(char *buf)
28163aba447SAndreas Jaekel {
28263aba447SAndreas Jaekel 	zev_print_zvol_truncate(buf);
28363aba447SAndreas Jaekel }
28463aba447SAndreas Jaekel 
28563aba447SAndreas Jaekel static void
28663aba447SAndreas Jaekel zev_print_znode_close_after_update(char *buf)
28763aba447SAndreas Jaekel {
28863aba447SAndreas Jaekel 	zev_znode_close_after_update_t *rec =
28963aba447SAndreas Jaekel 	    (zev_znode_close_after_update_t *)buf;
29063aba447SAndreas Jaekel 	time_t op_time = rec->op_time;
29163aba447SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
29263aba447SAndreas Jaekel 
293d65b2fffSAndreas Jaekel 	if (verbose) {
294d65b2fffSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
295d65b2fffSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
296d65b2fffSAndreas Jaekel 		zev_print_inode_info("file", &rec->file);
297d65b2fffSAndreas Jaekel 		znl();
298d65b2fffSAndreas Jaekel 	} else {
29963aba447SAndreas Jaekel 		printf("%s %s: guid=%llu file=%llu.%llu\n",
30063aba447SAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
30163aba447SAndreas Jaekel 		       rec->guid,
30263aba447SAndreas Jaekel 		       rec->file.ino, rec->file.gen);
30363aba447SAndreas Jaekel 	}
304d65b2fffSAndreas Jaekel }
30563aba447SAndreas Jaekel 
30663aba447SAndreas Jaekel static void
30763aba447SAndreas Jaekel zev_print_znode_create(char *buf)
30863aba447SAndreas Jaekel {
30963aba447SAndreas Jaekel 	zev_znode_create_t *rec = (zev_znode_create_t *)buf;
31063aba447SAndreas Jaekel 	time_t op_time = rec->op_time;
31163aba447SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
312*1ca5a13bSAndreas Jaekel 	zev_sig_t *sig;
313*1ca5a13bSAndreas Jaekel 	char sigval[(SHA1_DIGEST_LENGTH * 2) + 1];
31463aba447SAndreas Jaekel 
315d65b2fffSAndreas Jaekel 	if (verbose) {
316d65b2fffSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
317d65b2fffSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
318e206ace3SAndreas Jaekel 		zpf("  txg: %llu", rec->txg);
319d65b2fffSAndreas Jaekel 		zpf("  name: '%s'", ZEV_NAME(rec));
320*1ca5a13bSAndreas Jaekel 		sig = &rec->signature;
321*1ca5a13bSAndreas Jaekel 		sig2hex_direct(sig->value, sigval);
322*1ca5a13bSAndreas Jaekel 		zpf("  sig: level %d, offset %llu, value %s",
323*1ca5a13bSAndreas Jaekel 		    sig->level, sig->block_offset, sigval);
324d65b2fffSAndreas Jaekel 		zev_print_inode_info("file", &rec->file);
325e206ace3SAndreas Jaekel 		zev_print_inode_info("parent", &rec->parent);
326d65b2fffSAndreas Jaekel 		znl();
327d65b2fffSAndreas Jaekel 	} else {
328c035b1e8SAndreas Jaekel 		printf("%s %s: guid=%llu parent=%llu.%llu file=%llu.%llu "
329c035b1e8SAndreas Jaekel 		       "file.mtime=%llu, parent.mtime=%llu, name='%s'\n",
33063aba447SAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
33163aba447SAndreas Jaekel 		       rec->guid,
33263aba447SAndreas Jaekel 		       rec->parent.ino, rec->parent.gen,
33363aba447SAndreas Jaekel 		       rec->file.ino, rec->file.gen,
334c035b1e8SAndreas Jaekel 		       rec->file.mtime, rec->parent.mtime,
33563aba447SAndreas Jaekel 		       ZEV_NAME(rec));
33663aba447SAndreas Jaekel 	}
337d65b2fffSAndreas Jaekel }
33863aba447SAndreas Jaekel 
33963aba447SAndreas Jaekel static void
34063aba447SAndreas Jaekel zev_print_znode_mkdir(char *buf)
34163aba447SAndreas Jaekel {
34263aba447SAndreas Jaekel 	zev_print_znode_create(buf);
34363aba447SAndreas Jaekel }
34463aba447SAndreas Jaekel 
34563aba447SAndreas Jaekel static void
34663aba447SAndreas Jaekel zev_print_znode_make_xattr_dir(char *buf)
34763aba447SAndreas Jaekel {
34863aba447SAndreas Jaekel 	zev_print_znode_create(buf);
34963aba447SAndreas Jaekel }
35063aba447SAndreas Jaekel 
35163aba447SAndreas Jaekel static void
35263aba447SAndreas Jaekel zev_print_znode_remove(char *buf)
35363aba447SAndreas Jaekel {
35463aba447SAndreas Jaekel 	zev_znode_remove_t *rec = (zev_znode_remove_t *)buf;
35563aba447SAndreas Jaekel 	time_t op_time = rec->op_time;
35663aba447SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
35763aba447SAndreas Jaekel 
358d65b2fffSAndreas Jaekel 	if (verbose) {
359d65b2fffSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
360d65b2fffSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
361e206ace3SAndreas Jaekel 		zpf("  txg: %llu", rec->txg);
362d65b2fffSAndreas Jaekel 		zpf("  file.name: '%s'", ZEV_NAME(rec));
363d65b2fffSAndreas Jaekel 		zev_print_inode_info("file", &rec->file);
364e206ace3SAndreas Jaekel 		zev_print_inode_info("parent", &rec->parent);
365d65b2fffSAndreas Jaekel 		znl();
366d65b2fffSAndreas Jaekel 	} else {
367d65b2fffSAndreas Jaekel 		printf("%s %s: guid=%llu parent=%llu.%llu "
368d65b2fffSAndreas Jaekel 		       "file.mtime=%llu name='%s'\n",
36963aba447SAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
37063aba447SAndreas Jaekel 		       rec->guid,
37163aba447SAndreas Jaekel 		       rec->parent.ino, rec->parent.gen,
3726db5d4ecSAndreas Jaekel 		       rec->file.mtime,
37363aba447SAndreas Jaekel 		       ZEV_NAME(rec));
37463aba447SAndreas Jaekel 	}
375d65b2fffSAndreas Jaekel }
37663aba447SAndreas Jaekel 
37763aba447SAndreas Jaekel static void
37863aba447SAndreas Jaekel zev_print_znode_rmdir(char *buf)
37963aba447SAndreas Jaekel {
38063aba447SAndreas Jaekel 	zev_print_znode_remove(buf);
38163aba447SAndreas Jaekel }
38263aba447SAndreas Jaekel 
38363aba447SAndreas Jaekel static void
38463aba447SAndreas Jaekel zev_print_znode_link(char *buf)
38563aba447SAndreas Jaekel {
38663aba447SAndreas Jaekel 	zev_znode_link_t *rec = (zev_znode_link_t *)buf;
38763aba447SAndreas Jaekel 	time_t op_time = rec->op_time;
38863aba447SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
38963aba447SAndreas Jaekel 
390d65b2fffSAndreas Jaekel 	if (verbose) {
391d65b2fffSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
392d65b2fffSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
393e206ace3SAndreas Jaekel 		zpf("  txg: %llu", rec->txg);
394d65b2fffSAndreas Jaekel 		zpf("  link.name: '%s'", ZEV_NAME(rec));
395d65b2fffSAndreas Jaekel 		zev_print_inode_info("file", &rec->file);
396e206ace3SAndreas Jaekel 		zev_print_inode_info("parent", &rec->parent);
397d65b2fffSAndreas Jaekel 		znl();
398d65b2fffSAndreas Jaekel 	} else {
39903101f54SAndreas Jaekel 		printf("%s %s: parent=%llu.%llu file=%llu.%llu "
40003101f54SAndreas Jaekel 		       "file.ctime=%llu parent.ctime=%llu name='%s'\n",
40163aba447SAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
40263aba447SAndreas Jaekel 		       rec->parent.ino, rec->parent.gen,
40363aba447SAndreas Jaekel 		       rec->file.ino, rec->file.gen,
40403101f54SAndreas Jaekel 		       rec->file.ctime, rec->parent.ctime,
40563aba447SAndreas Jaekel 		       ZEV_NAME(rec));
406d65b2fffSAndreas Jaekel 	}
40763aba447SAndreas Jaekel }
40863aba447SAndreas Jaekel 
40963aba447SAndreas Jaekel static void
41063aba447SAndreas Jaekel zev_print_znode_symlink(char *buf)
41163aba447SAndreas Jaekel {
41263aba447SAndreas Jaekel 	zev_znode_symlink_t *rec = (zev_znode_symlink_t *)buf;
41363aba447SAndreas Jaekel 	time_t op_time = rec->op_time;
41463aba447SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
415*1ca5a13bSAndreas Jaekel 	zev_sig_t *sig;
416*1ca5a13bSAndreas Jaekel 	char sigval[(SHA1_DIGEST_LENGTH * 2) + 1];
41763aba447SAndreas Jaekel 
418d65b2fffSAndreas Jaekel 	if (verbose) {
419d65b2fffSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
420d65b2fffSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
421e206ace3SAndreas Jaekel 		zpf("  txg: %llu", rec->txg);
422d65b2fffSAndreas Jaekel 		zpf("  symlink.name: '%s'", ZEV_NAME(rec));
423d65b2fffSAndreas Jaekel 		zpf("  symlink.link: '%s'", ZEV_LINK(rec));
424*1ca5a13bSAndreas Jaekel 		sig = &rec->signature;
425*1ca5a13bSAndreas Jaekel 		sig2hex_direct(sig->value, sigval);
426*1ca5a13bSAndreas Jaekel 		zpf("  sig: level %d, offset %llu, value %s",
427*1ca5a13bSAndreas Jaekel 		    sig->level, sig->block_offset, sigval);
428d65b2fffSAndreas Jaekel 		zev_print_inode_info("file", &rec->file);
429e206ace3SAndreas Jaekel 		zev_print_inode_info("parent", &rec->parent);
430d65b2fffSAndreas Jaekel 		znl();
431d65b2fffSAndreas Jaekel 	} else {
432d65b2fffSAndreas Jaekel 		printf("%s %s: parent=%llu.%llu file=%llu.%llu "
433d65b2fffSAndreas Jaekel 		       "name='%s' link='%s'\n",
43463aba447SAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
43563aba447SAndreas Jaekel 		       rec->parent.ino, rec->parent.gen,
43663aba447SAndreas Jaekel 		       rec->file.ino, rec->file.gen,
43763aba447SAndreas Jaekel 		       ZEV_NAME(rec),
43863aba447SAndreas Jaekel 		       ZEV_LINK(rec));
43963aba447SAndreas Jaekel 	}
440d65b2fffSAndreas Jaekel }
44163aba447SAndreas Jaekel 
44263aba447SAndreas Jaekel static void
44363aba447SAndreas Jaekel zev_print_znode_rename(char *buf)
44463aba447SAndreas Jaekel {
44563aba447SAndreas Jaekel 	zev_znode_rename_t *rec = (zev_znode_rename_t *)buf;
44663aba447SAndreas Jaekel 	time_t op_time = rec->op_time;
44763aba447SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
44863aba447SAndreas Jaekel 
449d65b2fffSAndreas Jaekel 	if (verbose) {
450d65b2fffSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
451d65b2fffSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
452e206ace3SAndreas Jaekel 		zpf("  txg: %llu", rec->txg);
453d65b2fffSAndreas Jaekel 		zpf("  file.srcname: '%s'", ZEV_SRCNAME(rec));
454d65b2fffSAndreas Jaekel 		zpf("  file.dstname: '%s'", ZEV_DSTNAME(rec));
455d65b2fffSAndreas Jaekel 		zev_print_inode_info("file", &rec->file);
456d65b2fffSAndreas Jaekel 		zev_print_inode_info("srcdir", &rec->srcdir);
457d65b2fffSAndreas Jaekel 		zev_print_inode_info("dstdir", &rec->dstdir);
458d65b2fffSAndreas Jaekel 		znl();
459d65b2fffSAndreas Jaekel 	} else {
460d65b2fffSAndreas Jaekel 		printf("%s %s: srcdir=%llu.%llu dstdir=%llu.%llu "
461d65b2fffSAndreas Jaekel 		       "file=%llu.%llu file.mtime=%llu, file.ctime=%llu, "
462d65b2fffSAndreas Jaekel 		       "srcdir.mtime=%llu, srcdir.ctime=%llu, "
463d65b2fffSAndreas Jaekel 		       "dstdir.mtime=%llu, dstdir.ctime=%llu, "
46463aba447SAndreas Jaekel 		       "srcname='%s' dstname='%s'\n",
46563aba447SAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
46663aba447SAndreas Jaekel 		       rec->srcdir.ino, rec->srcdir.gen,
46763aba447SAndreas Jaekel 		       rec->dstdir.ino, rec->dstdir.gen,
46863aba447SAndreas Jaekel 		       rec->file.ino, rec->file.gen,
469c035b1e8SAndreas Jaekel 		       rec->file.mtime, rec->file.ctime,
470c035b1e8SAndreas Jaekel 		       rec->srcdir.mtime, rec->srcdir.ctime,
471c035b1e8SAndreas Jaekel 		       rec->dstdir.mtime, rec->dstdir.ctime,
47263aba447SAndreas Jaekel 		       ZEV_SRCNAME(rec),
47363aba447SAndreas Jaekel 		       ZEV_DSTNAME(rec));
47463aba447SAndreas Jaekel 	}
475d65b2fffSAndreas Jaekel }
47663aba447SAndreas Jaekel 
47763aba447SAndreas Jaekel static void
47863aba447SAndreas Jaekel zev_print_znode_write(char *buf)
47963aba447SAndreas Jaekel {
48063aba447SAndreas Jaekel 	zev_znode_write_t *rec = (zev_znode_write_t *)buf;
48163aba447SAndreas Jaekel 	time_t op_time = rec->op_time;
48263aba447SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
4835e286361SAndreas Jaekel 	zev_sig_t *sig;
4845e286361SAndreas Jaekel 	char sigval[(SHA1_DIGEST_LENGTH * 2) + 1];
4855e286361SAndreas Jaekel 	int i;
48663aba447SAndreas Jaekel 
4875e286361SAndreas Jaekel 	if (verbose) {
488d65b2fffSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
489d65b2fffSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
490e206ace3SAndreas Jaekel 		zpf("  txg: %llu", rec->txg);
491d65b2fffSAndreas Jaekel 		zpf("  offset: %llu", rec->offset);
492d65b2fffSAndreas Jaekel 		zpf("  length: %llu", rec->length);
493d65b2fffSAndreas Jaekel 		zev_print_inode_info("file", &rec->file);
494d65b2fffSAndreas Jaekel 		znl();
4955e286361SAndreas Jaekel 		for (i=0; i<rec->signature_cnt; i++) {
4965e286361SAndreas Jaekel 			sig = (zev_sig_t *)ZEV_SIGNATURES(rec);
4975e286361SAndreas Jaekel 			sig += i;
4985e286361SAndreas Jaekel 			sig2hex_direct(sig->value, sigval);
499*1ca5a13bSAndreas Jaekel 			zpf("  sig: level %d, offset %llu, value %s",
5005e286361SAndreas Jaekel 			    sig->level, sig->block_offset, sigval);
5015e286361SAndreas Jaekel 		}
502d65b2fffSAndreas Jaekel 	} else {
503d65b2fffSAndreas Jaekel 		printf("%s %s: file=%llu.%llu offset=%llu length=%llu\n",
504d65b2fffSAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
505d65b2fffSAndreas Jaekel 		       rec->file.ino, rec->file.gen,
506d65b2fffSAndreas Jaekel 		       rec->offset, rec->length);
5075e286361SAndreas Jaekel 	}
50863aba447SAndreas Jaekel }
50963aba447SAndreas Jaekel 
51063aba447SAndreas Jaekel static void
51163aba447SAndreas Jaekel zev_print_znode_truncate(char *buf)
51263aba447SAndreas Jaekel {
51363aba447SAndreas Jaekel 	zev_print_znode_write(buf);
51463aba447SAndreas Jaekel }
51563aba447SAndreas Jaekel 
51663aba447SAndreas Jaekel static void
51763aba447SAndreas Jaekel zev_print_znode_setattr(char *buf)
51863aba447SAndreas Jaekel {
51963aba447SAndreas Jaekel 	zev_znode_setattr_t *rec = (zev_znode_setattr_t *)buf;
52063aba447SAndreas Jaekel 	time_t op_time = rec->op_time;
52163aba447SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
52263aba447SAndreas Jaekel 
523d65b2fffSAndreas Jaekel 	if (verbose) {
524d65b2fffSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
525d65b2fffSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
526e206ace3SAndreas Jaekel 		zpf("  txg: %llu", rec->txg);
527d65b2fffSAndreas Jaekel 		zev_print_inode_info("file", &rec->file);
528d65b2fffSAndreas Jaekel 		znl();
529d65b2fffSAndreas Jaekel 	} else {
530c035b1e8SAndreas Jaekel 		printf("%s %s: file=%llu.%llu mtime=%llu\n",
53163aba447SAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
532c035b1e8SAndreas Jaekel 		       rec->file.ino, rec->file.gen, rec->file.mtime);
53363aba447SAndreas Jaekel 	}
534d65b2fffSAndreas Jaekel }
53563aba447SAndreas Jaekel 
53663aba447SAndreas Jaekel static void
53763aba447SAndreas Jaekel zev_print_znode_acl(char *buf)
53863aba447SAndreas Jaekel {
53963aba447SAndreas Jaekel 	zev_print_znode_setattr(buf);
54063aba447SAndreas Jaekel }
54163aba447SAndreas Jaekel 
54263aba447SAndreas Jaekel static void
5439193e9c2SAndreas Jaekel zev_print_event(char *buf, int len)
5449193e9c2SAndreas Jaekel {
54563aba447SAndreas Jaekel 	int record_len;
54663aba447SAndreas Jaekel 	int op;
5479193e9c2SAndreas Jaekel 
54863aba447SAndreas Jaekel 	record_len = *(uint32_t *)buf;
54963aba447SAndreas Jaekel 	if (record_len != len) {
55063aba447SAndreas Jaekel 		fprintf(stderr, "record length mismatch: got %d, expected %d\n",
55163aba447SAndreas Jaekel 		        record_len, len);
5529193e9c2SAndreas Jaekel 		exit(1);
5539193e9c2SAndreas Jaekel 	}
55463aba447SAndreas Jaekel 	op = *((uint32_t *)buf + 1);
5559193e9c2SAndreas Jaekel 	if (op < ZEV_OP_MIN || op > ZEV_OP_MAX) {
55663aba447SAndreas Jaekel 		fprintf(stderr, "unknown op code: %d\n", op);
5579193e9c2SAndreas Jaekel 		exit(1);
5589193e9c2SAndreas Jaekel 	}
55963aba447SAndreas Jaekel 	switch (op) {
56063aba447SAndreas Jaekel 	case ZEV_OP_ERROR:
56163aba447SAndreas Jaekel 		zev_print_error(buf);
5629193e9c2SAndreas Jaekel 		break;
56301c2c787SAndreas Jaekel 	case ZEV_OP_MARK:
56401c2c787SAndreas Jaekel 		zev_print_mark(buf);
56501c2c787SAndreas Jaekel 		break;
56663aba447SAndreas Jaekel 	case ZEV_OP_ZFS_MOUNT:
56763aba447SAndreas Jaekel 		zev_print_zfs_mount(buf);
5689193e9c2SAndreas Jaekel 		break;
56963aba447SAndreas Jaekel 	case ZEV_OP_ZFS_UMOUNT:
57063aba447SAndreas Jaekel 		zev_print_zfs_umount(buf);
5719193e9c2SAndreas Jaekel 		break;
57263aba447SAndreas Jaekel 	case ZEV_OP_ZVOL_TRUNCATE:
57363aba447SAndreas Jaekel 		zev_print_zvol_truncate(buf);
5749193e9c2SAndreas Jaekel 		break;
57563aba447SAndreas Jaekel 	case ZEV_OP_ZVOL_WRITE:
57663aba447SAndreas Jaekel 		zev_print_zvol_write(buf);
57763aba447SAndreas Jaekel 		break;
57863aba447SAndreas Jaekel 	case ZEV_OP_ZNODE_CLOSE_AFTER_UPDATE:
57963aba447SAndreas Jaekel 		zev_print_znode_close_after_update(buf);
58063aba447SAndreas Jaekel 		break;
58163aba447SAndreas Jaekel 	case ZEV_OP_ZNODE_CREATE:
58263aba447SAndreas Jaekel 		zev_print_znode_create(buf);
58363aba447SAndreas Jaekel 		break;
58463aba447SAndreas Jaekel 	case ZEV_OP_ZNODE_MKDIR:
58563aba447SAndreas Jaekel 		zev_print_znode_mkdir(buf);
58663aba447SAndreas Jaekel 		break;
58763aba447SAndreas Jaekel 	case ZEV_OP_ZNODE_MAKE_XATTR_DIR:
58863aba447SAndreas Jaekel 		zev_print_znode_make_xattr_dir(buf);
58963aba447SAndreas Jaekel 		break;
59063aba447SAndreas Jaekel 	case ZEV_OP_ZNODE_REMOVE:
59163aba447SAndreas Jaekel 		zev_print_znode_remove(buf);
59263aba447SAndreas Jaekel 		break;
59363aba447SAndreas Jaekel 	case ZEV_OP_ZNODE_RMDIR:
59463aba447SAndreas Jaekel 		zev_print_znode_rmdir(buf);
59563aba447SAndreas Jaekel 		break;
59663aba447SAndreas Jaekel 	case ZEV_OP_ZNODE_LINK:
59763aba447SAndreas Jaekel 		zev_print_znode_link(buf);
59863aba447SAndreas Jaekel 		break;
59963aba447SAndreas Jaekel 	case ZEV_OP_ZNODE_SYMLINK:
60063aba447SAndreas Jaekel 		zev_print_znode_symlink(buf);
60163aba447SAndreas Jaekel 		break;
60263aba447SAndreas Jaekel 	case ZEV_OP_ZNODE_RENAME:
60363aba447SAndreas Jaekel 		zev_print_znode_rename(buf);
60463aba447SAndreas Jaekel 		break;
60563aba447SAndreas Jaekel 	case ZEV_OP_ZNODE_WRITE:
60663aba447SAndreas Jaekel 		zev_print_znode_write(buf);
60763aba447SAndreas Jaekel 		break;
60863aba447SAndreas Jaekel 	case ZEV_OP_ZNODE_TRUNCATE:
60963aba447SAndreas Jaekel 		zev_print_znode_truncate(buf);
61063aba447SAndreas Jaekel 		break;
61163aba447SAndreas Jaekel 	case ZEV_OP_ZNODE_SETATTR:
61263aba447SAndreas Jaekel 		zev_print_znode_setattr(buf);
61363aba447SAndreas Jaekel 		break;
61463aba447SAndreas Jaekel 	case ZEV_OP_ZNODE_ACL:
61563aba447SAndreas Jaekel 		zev_print_znode_acl(buf);
6169193e9c2SAndreas Jaekel 		break;
6179193e9c2SAndreas Jaekel 	default:
61863aba447SAndreas Jaekel 		fprintf(stderr, "unhandled op code: %d\n", op);
6199193e9c2SAndreas Jaekel 		exit(1);
6209193e9c2SAndreas Jaekel 	}
6219193e9c2SAndreas Jaekel }
6229193e9c2SAndreas Jaekel 
623e9a5e479SAndreas Jaekel static int
6244ca7dd5eSAndreas Jaekel zev_poll_events(int fd, int create_tmp_queue)
6252bb8e5e2SAndreas Jaekel {
6262bb8e5e2SAndreas Jaekel 	struct pollfd pfd[1];
6272bb8e5e2SAndreas Jaekel 	int ret;
6289193e9c2SAndreas Jaekel 	char buf[4096];
62968a46c64SAndreas Jaekel 	zev_event_t *ev;
63068a46c64SAndreas Jaekel 	int off = 0;
631e9a5e479SAndreas Jaekel 	zev_ioctl_add_queue_t aq;
632e9a5e479SAndreas Jaekel 	int q_fd;
633e9a5e479SAndreas Jaekel 
6344ca7dd5eSAndreas Jaekel 	if (create_tmp_queue) {
635e9a5e479SAndreas Jaekel 		aq.zev_max_queue_len = 0;
636e9a5e479SAndreas Jaekel 		aq.zev_flags = ZEV_FL_BLOCK_WHILE_QUEUE_FULL;
637e9a5e479SAndreas Jaekel 		snprintf(aq.zev_name, ZEV_MAX_QUEUE_NAME_LEN,
638e9a5e479SAndreas Jaekel 			 "zevadm.%ld.%ld", time(NULL), getpid());
639e9a5e479SAndreas Jaekel 		aq.zev_namelen = strlen(aq.zev_name);
640e9a5e479SAndreas Jaekel 
641e9a5e479SAndreas Jaekel 		if (ioctl(fd, ZEV_IOC_ADD_QUEUE, &aq)) {
642e9a5e479SAndreas Jaekel 			perror("adding temporary queue failed");
643e9a5e479SAndreas Jaekel 			return (EXIT_FAILURE);
644e9a5e479SAndreas Jaekel 		}
645e9a5e479SAndreas Jaekel 
6464ca7dd5eSAndreas Jaekel 		snprintf(buf, sizeof(buf),
6474ca7dd5eSAndreas Jaekel 		         "/devices/pseudo/zev@0:%s", aq.zev_name);
648e9a5e479SAndreas Jaekel 		q_fd = open(buf, O_RDONLY);
649e9a5e479SAndreas Jaekel 		if (q_fd < 0) {
650e9a5e479SAndreas Jaekel 			perror("opening queue device failed");
651e9a5e479SAndreas Jaekel 			return (EXIT_FAILURE);
652e9a5e479SAndreas Jaekel 		}
6534ca7dd5eSAndreas Jaekel 	} else {
6544ca7dd5eSAndreas Jaekel 		q_fd = fd;
6554ca7dd5eSAndreas Jaekel 	}
656e9a5e479SAndreas Jaekel 
6572bb8e5e2SAndreas Jaekel 	while (1) {
658e9a5e479SAndreas Jaekel 		pfd[0].fd = q_fd;
6592bb8e5e2SAndreas Jaekel 		pfd[0].events = POLLIN;
6602bb8e5e2SAndreas Jaekel 		ret = poll(pfd, 1, 1000);
6612bb8e5e2SAndreas Jaekel 		if (ret < 0) {
6622bb8e5e2SAndreas Jaekel 			perror("poll failed");
6634ca7dd5eSAndreas Jaekel 			close(q_fd);
664e9a5e479SAndreas Jaekel 			return(EXIT_FAILURE);
6652bb8e5e2SAndreas Jaekel 		}
6662bb8e5e2SAndreas Jaekel 		if (!(pfd[0].revents & POLLIN))
6672bb8e5e2SAndreas Jaekel 			continue;
6682bb8e5e2SAndreas Jaekel 		/* data available */
669e9a5e479SAndreas Jaekel 		ret = read(q_fd, buf, sizeof(buf));
6702bb8e5e2SAndreas Jaekel 		if (ret < 0) {
6712bb8e5e2SAndreas Jaekel 			perror("read failed");
6724ca7dd5eSAndreas Jaekel 			close(q_fd);
673e9a5e479SAndreas Jaekel 			return(EXIT_FAILURE);
6742bb8e5e2SAndreas Jaekel 		}
6752bb8e5e2SAndreas Jaekel 		if (ret == 0)
6762bb8e5e2SAndreas Jaekel 			continue;
67768a46c64SAndreas Jaekel 		while (ret > off) {
67868a46c64SAndreas Jaekel 			ev = (zev_event_t *)(buf + off);
67968a46c64SAndreas Jaekel 			zev_print_event(buf + off, ev->header.record_len);
68068a46c64SAndreas Jaekel 			off += ev->header.record_len;
68168a46c64SAndreas Jaekel 		}
682108668daSAndreas Jaekel 		off = 0;
6832bb8e5e2SAndreas Jaekel 	}
6844ca7dd5eSAndreas Jaekel 	if (create_tmp_queue)
685e9a5e479SAndreas Jaekel 		close(q_fd);
686e9a5e479SAndreas Jaekel 	return EXIT_SUCCESS;
6872bb8e5e2SAndreas Jaekel }
6882bb8e5e2SAndreas Jaekel 
6892bb8e5e2SAndreas Jaekel static void
6902bb8e5e2SAndreas Jaekel usage(char *progname)
6912bb8e5e2SAndreas Jaekel {
692e9a5e479SAndreas Jaekel 	fprintf(stderr, "usage: %s [-d <dev>] [options]\n", progname);
693e9a5e479SAndreas Jaekel 	fprintf(stderr, "\n");
694e9a5e479SAndreas Jaekel 	fprintf(stderr, " Status information:\n");
6952bb8e5e2SAndreas Jaekel 	fprintf(stderr, "   -s                   show zev statistics\n");
6962bb8e5e2SAndreas Jaekel 	fprintf(stderr, "   -p                   poll for ZFS events\n");
697e9a5e479SAndreas Jaekel 	fprintf(stderr, "   -D                   print zev module debug "
698e9a5e479SAndreas Jaekel 	        "information\n");
699e9a5e479SAndreas Jaekel 	fprintf(stderr, "\n");
700e9a5e479SAndreas Jaekel 	fprintf(stderr, " Tune zev module settings:\n");
701e9a5e479SAndreas Jaekel 	fprintf(stderr, "   -Q <bytes>           set maximum event queue "
702e9a5e479SAndreas Jaekel 	        "length\n");
703e9a5e479SAndreas Jaekel 	fprintf(stderr, "   -m <pool>            mute pool, no events for "
704e9a5e479SAndreas Jaekel 	        "this pool\n");
7052bb8e5e2SAndreas Jaekel 	fprintf(stderr, "   -M <pool>            unmute pool\n");
706e9a5e479SAndreas Jaekel 	fprintf(stderr, "\n");
707e9a5e479SAndreas Jaekel 	fprintf(stderr, " Queue management:\n");
708e9a5e479SAndreas Jaekel 	fprintf(stderr, "   -l                   list queues\n");
7094ca7dd5eSAndreas Jaekel 	fprintf(stderr, "   -a <name>            add non-blocking queue\n");
7104ca7dd5eSAndreas Jaekel 	fprintf(stderr, "   -A <name>            add blocking queue\n");
711e9a5e479SAndreas Jaekel 	fprintf(stderr, "   -r <name>            remove queue\n");
712e9a5e479SAndreas Jaekel 	fprintf(stderr, "   -b <name>            make queue non-blocking "
713e9a5e479SAndreas Jaekel 	        "(default)\n");
714e9a5e479SAndreas Jaekel 	fprintf(stderr, "   -B <name>            make queue block when full\n");
715e9a5e479SAndreas Jaekel 	fprintf(stderr, "   -P <name>            display queue properties\n");
7164ca7dd5eSAndreas Jaekel 	fprintf(stderr, "   -L <name> <bytes>    set maximum event queue "
717e9a5e479SAndreas Jaekel 	        "length\n");
718e9a5e479SAndreas Jaekel 	fprintf(stderr, "   -t <name> <bytes>    set queue length poll "
719e9a5e479SAndreas Jaekel 	        "throttle\n");
720e9a5e479SAndreas Jaekel 	fprintf(stderr, "\n");
721e9a5e479SAndreas Jaekel 	fprintf(stderr, " Other options:\n");
722e9a5e479SAndreas Jaekel 	fprintf(stderr, "   -d <dev>             non-default device file. "
723e9a5e479SAndreas Jaekel 	        "('%s')\n", ZEV_DEVICE);
7244ca7dd5eSAndreas Jaekel 	fprintf(stderr, "   -q <name>            use device file for this "
7254ca7dd5eSAndreas Jaekel 		"queue name\n");
72601c2c787SAndreas Jaekel 	fprintf(stderr, "   -k <guid>:<payload>  queue mark event\n");
727b9710123SAndreas Jaekel 	fprintf(stderr, "   -c <filename>        list file's content "
728b9710123SAndreas Jaekel 		"checksums\n");
729d65b2fffSAndreas Jaekel 	fprintf(stderr, "   -v                   verbose: additional output "
7305e286361SAndreas Jaekel 	        "for some operations\n");
731d65b2fffSAndreas Jaekel 	fprintf(stderr, "   -g                   grep-friendly event output, "
732d65b2fffSAndreas Jaekel 	        "one event per line\n");
7332bb8e5e2SAndreas Jaekel 	exit (EXIT_FAILURE);
7342bb8e5e2SAndreas Jaekel }
7352bb8e5e2SAndreas Jaekel 
7362bb8e5e2SAndreas Jaekel static int
7374ca7dd5eSAndreas Jaekel zev_add_queue(int fd, char *arg, int blocking)
7382bb8e5e2SAndreas Jaekel {
739e9a5e479SAndreas Jaekel 	zev_ioctl_add_queue_t aq;
740e9a5e479SAndreas Jaekel 	int namelen;
7412bb8e5e2SAndreas Jaekel 
742e9a5e479SAndreas Jaekel 	namelen = strlen(arg);
743e9a5e479SAndreas Jaekel 	if (namelen > ZEV_MAX_QUEUE_NAME_LEN) {
744e9a5e479SAndreas Jaekel 		fprintf(stderr, "queue name too long: %s\n", arg);
7452bb8e5e2SAndreas Jaekel 		return (EXIT_FAILURE);
7462bb8e5e2SAndreas Jaekel 	}
747e9a5e479SAndreas Jaekel 
748e9a5e479SAndreas Jaekel 	aq.zev_namelen = namelen;
749e9a5e479SAndreas Jaekel 	strcpy(aq.zev_name, arg);
7504ca7dd5eSAndreas Jaekel 	aq.zev_flags = ZEV_FL_PERSISTENT;
7514ca7dd5eSAndreas Jaekel 	if (blocking) {
7524ca7dd5eSAndreas Jaekel 		aq.zev_flags |= ZEV_FL_BLOCK_WHILE_QUEUE_FULL;
7534ca7dd5eSAndreas Jaekel 		aq.zev_max_queue_len = ZEV_MAX_QUEUE_LEN;
7544ca7dd5eSAndreas Jaekel 	} else {
755e9a5e479SAndreas Jaekel 		aq.zev_max_queue_len = (1024 * 1024);
7564ca7dd5eSAndreas Jaekel 	}
757e9a5e479SAndreas Jaekel 
758e9a5e479SAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_ADD_QUEUE, &aq)) {
759e9a5e479SAndreas Jaekel 		perror("adding queue failed");
7602bb8e5e2SAndreas Jaekel 		return (EXIT_FAILURE);
7612bb8e5e2SAndreas Jaekel 	}
7622bb8e5e2SAndreas Jaekel 	return (0);
7632bb8e5e2SAndreas Jaekel }
7642bb8e5e2SAndreas Jaekel 
7652bb8e5e2SAndreas Jaekel static int
766e9a5e479SAndreas Jaekel zev_remove_queue(int fd, char *arg)
767205a9bc9SAndreas Jaekel {
768e9a5e479SAndreas Jaekel 	zev_ioctl_remove_queue_t aq;
769e9a5e479SAndreas Jaekel 	int namelen;
770205a9bc9SAndreas Jaekel 
771e9a5e479SAndreas Jaekel 	namelen = strlen(arg);
772e9a5e479SAndreas Jaekel 	if (namelen > ZEV_MAX_QUEUE_NAME_LEN) {
773e9a5e479SAndreas Jaekel 		fprintf(stderr, "queue name too long: %s\n", arg);
774205a9bc9SAndreas Jaekel 		return (EXIT_FAILURE);
775205a9bc9SAndreas Jaekel 	}
776e9a5e479SAndreas Jaekel 
7774ca7dd5eSAndreas Jaekel 	aq.zev_queue_name.zev_namelen = namelen;
7784ca7dd5eSAndreas Jaekel 	strcpy(aq.zev_queue_name.zev_name, arg);
779e9a5e479SAndreas Jaekel 
780e9a5e479SAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_REMOVE_QUEUE, &aq)) {
781e9a5e479SAndreas Jaekel 		perror("removing queue failed");
782e9a5e479SAndreas Jaekel 		return (EXIT_FAILURE);
783e9a5e479SAndreas Jaekel 	}
784e9a5e479SAndreas Jaekel 	return (0);
785e9a5e479SAndreas Jaekel }
786e9a5e479SAndreas Jaekel 
787e9a5e479SAndreas Jaekel static int
788e9a5e479SAndreas Jaekel zev_set_global_max_queue_len(int fd, char *arg)
789e9a5e479SAndreas Jaekel {
790e9a5e479SAndreas Jaekel 	uint64_t maxqueuelen;
791e9a5e479SAndreas Jaekel 
792e9a5e479SAndreas Jaekel 	errno = 0;
793e9a5e479SAndreas Jaekel 	maxqueuelen = strtol(arg, (char **)NULL, 10);
794e9a5e479SAndreas Jaekel 	if (errno) {
795e9a5e479SAndreas Jaekel 		fprintf(stderr, "invalid queue length parameter: %s\n", arg);
796e9a5e479SAndreas Jaekel 		return (EXIT_FAILURE);
797e9a5e479SAndreas Jaekel 	}
798e9a5e479SAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_SET_MAX_QUEUE_LEN, &maxqueuelen)) {
799e9a5e479SAndreas Jaekel 		perror("setting max queue length failed");
800205a9bc9SAndreas Jaekel 		return (EXIT_FAILURE);
801205a9bc9SAndreas Jaekel 	}
802205a9bc9SAndreas Jaekel 	return (0);
803205a9bc9SAndreas Jaekel }
804205a9bc9SAndreas Jaekel 
805205a9bc9SAndreas Jaekel static int
8062bb8e5e2SAndreas Jaekel zev_mute_unmute_impl(int fd, char *poolname, int mute)
8072bb8e5e2SAndreas Jaekel {
8082bb8e5e2SAndreas Jaekel 	zev_ioctl_poolarg_t pa;
8092bb8e5e2SAndreas Jaekel 	int len;
8102bb8e5e2SAndreas Jaekel 	int op = mute ? ZEV_IOC_MUTE_POOL : ZEV_IOC_UNMUTE_POOL;
8112bb8e5e2SAndreas Jaekel 	len = strlen(poolname);
8122bb8e5e2SAndreas Jaekel 	if (len <= 0 || len >= sizeof(pa.zev_poolname)) {
8132bb8e5e2SAndreas Jaekel 		fprintf(stderr, "invalid poolname: %s\n", poolname);
8142bb8e5e2SAndreas Jaekel 		return (EXIT_FAILURE);
8152bb8e5e2SAndreas Jaekel 	}
8162bb8e5e2SAndreas Jaekel 	strcpy(pa.zev_poolname, poolname);
8172bb8e5e2SAndreas Jaekel 	pa.zev_poolname_len = len;
8182bb8e5e2SAndreas Jaekel 	if (ioctl(fd, op, &pa)) {
8192bb8e5e2SAndreas Jaekel 		perror("muting pool data failed");
8202bb8e5e2SAndreas Jaekel 		return (EXIT_FAILURE);
8212bb8e5e2SAndreas Jaekel 	}
8222bb8e5e2SAndreas Jaekel 	return (0);
8232bb8e5e2SAndreas Jaekel }
8242bb8e5e2SAndreas Jaekel 
8252bb8e5e2SAndreas Jaekel int
8262bb8e5e2SAndreas Jaekel zev_mute_pool(int fd, char *poolname)
8272bb8e5e2SAndreas Jaekel {
8282bb8e5e2SAndreas Jaekel 	return zev_mute_unmute_impl(fd, poolname, 1);
8292bb8e5e2SAndreas Jaekel }
8302bb8e5e2SAndreas Jaekel 
8312bb8e5e2SAndreas Jaekel int
8322bb8e5e2SAndreas Jaekel zev_unmute_pool(int fd, char *poolname)
8332bb8e5e2SAndreas Jaekel {
8342bb8e5e2SAndreas Jaekel 	return zev_mute_unmute_impl(fd, poolname, 0);
8352bb8e5e2SAndreas Jaekel }
8362bb8e5e2SAndreas Jaekel 
83701c2c787SAndreas Jaekel static int
838e9a5e479SAndreas Jaekel zev_debug_info(int fd)
839e9a5e479SAndreas Jaekel {
840e9a5e479SAndreas Jaekel 	zev_ioctl_debug_info_t di;
841e9a5e479SAndreas Jaekel 
842e9a5e479SAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_GET_DEBUG_INFO, &di)) {
843e9a5e479SAndreas Jaekel 		perror("getting zev debug info failed");
844e9a5e479SAndreas Jaekel 		return (EXIT_FAILURE);
845e9a5e479SAndreas Jaekel 	}
846e9a5e479SAndreas Jaekel 
847e9a5e479SAndreas Jaekel 	printf("memory allocated: %llu bytes\n", di.zev_memory_allocated);
8485e286361SAndreas Jaekel 	printf("checksum cache size: %llu\n", di.zev_chksum_cache_size);
8495e286361SAndreas Jaekel 	printf("checksum cache hits: %llu\n", di.zev_chksum_cache_hits);
8505e286361SAndreas Jaekel 	printf("checksum cache misses: %llu\n", di.zev_chksum_cache_misses);
851e9a5e479SAndreas Jaekel 	return 0;
852e9a5e479SAndreas Jaekel }
853e9a5e479SAndreas Jaekel 
854e9a5e479SAndreas Jaekel static int
85501c2c787SAndreas Jaekel zev_mark(int fd, char *arg)
85601c2c787SAndreas Jaekel {
85701c2c787SAndreas Jaekel 	zev_ioctl_mark_t *mark;
85801c2c787SAndreas Jaekel 	uint64_t guid;
85901c2c787SAndreas Jaekel 	int len;
86001c2c787SAndreas Jaekel 	char *p;
86101c2c787SAndreas Jaekel 
86201c2c787SAndreas Jaekel 	p = strchr(arg, ':');
86301c2c787SAndreas Jaekel 	if (!p) {
86401c2c787SAndreas Jaekel 		fprintf(stderr, "expected value is <guid>:<payload>, "
86501c2c787SAndreas Jaekel 		        "e.g. '123:hello'\n");
86601c2c787SAndreas Jaekel 		exit (EXIT_FAILURE);
86701c2c787SAndreas Jaekel 	}
86801c2c787SAndreas Jaekel 	*p = '\n';
86901c2c787SAndreas Jaekel 	p++;
87001c2c787SAndreas Jaekel 
87101c2c787SAndreas Jaekel 	errno = 0;
872e9a5e479SAndreas Jaekel 	guid = strtoll(arg, (char **)NULL, 10);
87301c2c787SAndreas Jaekel 	if (errno) {
87401c2c787SAndreas Jaekel 		fprintf(stderr, "guid must be a number.\n");
87501c2c787SAndreas Jaekel 		exit (EXIT_FAILURE);
87601c2c787SAndreas Jaekel 	}
87701c2c787SAndreas Jaekel 
87801c2c787SAndreas Jaekel 	len = strlen(p);
87901c2c787SAndreas Jaekel 
88001c2c787SAndreas Jaekel 	mark = malloc(sizeof(*mark) + len + 1);
88101c2c787SAndreas Jaekel 	if (!mark) {
88201c2c787SAndreas Jaekel 		fprintf(stderr, "can't allocate mark structure: %s\n",
88301c2c787SAndreas Jaekel 		        strerror(errno));
88401c2c787SAndreas Jaekel 		exit (EXIT_FAILURE);
88501c2c787SAndreas Jaekel 	}
88601c2c787SAndreas Jaekel 	mark->zev_guid = guid;
88701c2c787SAndreas Jaekel 	mark->zev_mark_id = 0;
88801c2c787SAndreas Jaekel 	mark->zev_payload_len = len;
88901c2c787SAndreas Jaekel 	strcpy(ZEV_PAYLOAD(mark), p);
89001c2c787SAndreas Jaekel 
89101c2c787SAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_MARK, mark)) {
89201c2c787SAndreas Jaekel 		perror("queueing mark failed");
89301c2c787SAndreas Jaekel 		return (EXIT_FAILURE);
89401c2c787SAndreas Jaekel 	}
89501c2c787SAndreas Jaekel 
89601c2c787SAndreas Jaekel 	printf("mark id: %lu\n", mark->zev_mark_id);
89701c2c787SAndreas Jaekel 	return (0);
89801c2c787SAndreas Jaekel }
89901c2c787SAndreas Jaekel 
900e9a5e479SAndreas Jaekel static int
901e9a5e479SAndreas Jaekel zev_queue_blocking(int fd, char *arg, int block)
902e9a5e479SAndreas Jaekel {
903e9a5e479SAndreas Jaekel 	zev_ioctl_get_queue_properties_t gqp;
904e9a5e479SAndreas Jaekel 
9054ca7dd5eSAndreas Jaekel 	gqp.zev_queue_name.zev_namelen = strlen(arg);
9064ca7dd5eSAndreas Jaekel 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
907e9a5e479SAndreas Jaekel 		fprintf(stderr, "queue name too long.\n");
908e9a5e479SAndreas Jaekel 		return EXIT_FAILURE;
909e9a5e479SAndreas Jaekel 	}
9104ca7dd5eSAndreas Jaekel 	strcpy(gqp.zev_queue_name.zev_name, arg);
911e9a5e479SAndreas Jaekel 
912e9a5e479SAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
913e9a5e479SAndreas Jaekel 		perror("getting queue properties failed");
914e9a5e479SAndreas Jaekel 		return (EXIT_FAILURE);
915e9a5e479SAndreas Jaekel 	}
916e9a5e479SAndreas Jaekel 	if (block) {
917e9a5e479SAndreas Jaekel 		gqp.zev_flags |= ZEV_FL_BLOCK_WHILE_QUEUE_FULL;
918e9a5e479SAndreas Jaekel 	} else {
919e9a5e479SAndreas Jaekel 		gqp.zev_flags &= ~ZEV_FL_BLOCK_WHILE_QUEUE_FULL;
920e9a5e479SAndreas Jaekel 	}
921e9a5e479SAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) {
922e9a5e479SAndreas Jaekel 		perror("setting queue properties failed");
923e9a5e479SAndreas Jaekel 		return (EXIT_FAILURE);
924e9a5e479SAndreas Jaekel 	}
925e9a5e479SAndreas Jaekel 	return (0);
926e9a5e479SAndreas Jaekel }
927e9a5e479SAndreas Jaekel 
928e9a5e479SAndreas Jaekel static int
929e9a5e479SAndreas Jaekel zev_set_max_queue_len(int fd, char *arg, char *len)
930e9a5e479SAndreas Jaekel {
931e9a5e479SAndreas Jaekel 	zev_ioctl_get_queue_properties_t gqp;
932e9a5e479SAndreas Jaekel 
933e9a5e479SAndreas Jaekel 	if (!len) {
934e9a5e479SAndreas Jaekel 		fprintf(stderr, "queue size parameter missing.\n");
935e9a5e479SAndreas Jaekel 		return EXIT_FAILURE;
936e9a5e479SAndreas Jaekel 	}
937e9a5e479SAndreas Jaekel 
9384ca7dd5eSAndreas Jaekel 	gqp.zev_queue_name.zev_namelen = strlen(arg);
9394ca7dd5eSAndreas Jaekel 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
940e9a5e479SAndreas Jaekel 		fprintf(stderr, "queue name too long.\n");
941e9a5e479SAndreas Jaekel 		return EXIT_FAILURE;
942e9a5e479SAndreas Jaekel 	}
9434ca7dd5eSAndreas Jaekel 	strcpy(gqp.zev_queue_name.zev_name, arg);
944e9a5e479SAndreas Jaekel 
945e9a5e479SAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
946e9a5e479SAndreas Jaekel 		perror("getting queue properties failed");
947e9a5e479SAndreas Jaekel 		return (EXIT_FAILURE);
948e9a5e479SAndreas Jaekel 	}
949e9a5e479SAndreas Jaekel 	gqp.zev_max_queue_len = atol(len);
950e9a5e479SAndreas Jaekel 	if (gqp.zev_max_queue_len == 0 && strcmp("0", len)) {
951e9a5e479SAndreas Jaekel 		fprintf(stderr, "queue size parameter garbled.\n");
952e9a5e479SAndreas Jaekel 		return (EXIT_FAILURE);
953e9a5e479SAndreas Jaekel 	}
954e9a5e479SAndreas Jaekel 	if (gqp.zev_max_queue_len > ZEV_MAX_QUEUE_LEN) {
955e9a5e479SAndreas Jaekel 		fprintf(stderr, "queue size parameter out of bounds.\n");
956e9a5e479SAndreas Jaekel 		return (EXIT_FAILURE);
957e9a5e479SAndreas Jaekel 	}
958e9a5e479SAndreas Jaekel 
959e9a5e479SAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) {
960e9a5e479SAndreas Jaekel 		perror("setting queue properties failed");
961e9a5e479SAndreas Jaekel 		return (EXIT_FAILURE);
962e9a5e479SAndreas Jaekel 	}
963e9a5e479SAndreas Jaekel 	return (0);
964e9a5e479SAndreas Jaekel }
965e9a5e479SAndreas Jaekel 
966e9a5e479SAndreas Jaekel static int
967e9a5e479SAndreas Jaekel zev_set_poll_wakeup_queue_len(int fd, char *arg, char *len)
968e9a5e479SAndreas Jaekel {
969e9a5e479SAndreas Jaekel 	zev_ioctl_get_queue_properties_t gqp;
970e9a5e479SAndreas Jaekel 
971e9a5e479SAndreas Jaekel 	if (!len) {
972e9a5e479SAndreas Jaekel 		fprintf(stderr, "poll throttle parameter missing.\n");
973e9a5e479SAndreas Jaekel 		return EXIT_FAILURE;
974e9a5e479SAndreas Jaekel 	}
975e9a5e479SAndreas Jaekel 
9764ca7dd5eSAndreas Jaekel 	gqp.zev_queue_name.zev_namelen = strlen(arg);
9774ca7dd5eSAndreas Jaekel 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
978e9a5e479SAndreas Jaekel 		fprintf(stderr, "queue name too long.\n");
979e9a5e479SAndreas Jaekel 		return EXIT_FAILURE;
980e9a5e479SAndreas Jaekel 	}
9814ca7dd5eSAndreas Jaekel 	strcpy(gqp.zev_queue_name.zev_name, arg);
982e9a5e479SAndreas Jaekel 
983e9a5e479SAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
984e9a5e479SAndreas Jaekel 		perror("getting queue properties failed");
985e9a5e479SAndreas Jaekel 		return (EXIT_FAILURE);
986e9a5e479SAndreas Jaekel 	}
987e9a5e479SAndreas Jaekel 	gqp.zev_poll_wakeup_threshold = atol(len);
988e9a5e479SAndreas Jaekel 	if (gqp.zev_poll_wakeup_threshold == 0 && strcmp("0", len)) {
989e9a5e479SAndreas Jaekel 		fprintf(stderr, "poll throttle parameter garbled.\n");
990e9a5e479SAndreas Jaekel 		return (EXIT_FAILURE);
991e9a5e479SAndreas Jaekel 	}
9924ca7dd5eSAndreas Jaekel 	if (gqp.zev_poll_wakeup_threshold > ZEV_MAX_POLL_WAKEUP_QUEUE_LEN) {
993e9a5e479SAndreas Jaekel 		fprintf(stderr, "poll throttle parameter out of bounds.\n");
994e9a5e479SAndreas Jaekel 		return (EXIT_FAILURE);
995e9a5e479SAndreas Jaekel 	}
996e9a5e479SAndreas Jaekel 
997e9a5e479SAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) {
998e9a5e479SAndreas Jaekel 		perror("setting queue properties failed");
999e9a5e479SAndreas Jaekel 		return (EXIT_FAILURE);
1000e9a5e479SAndreas Jaekel 	}
1001e9a5e479SAndreas Jaekel 	return (0);
1002e9a5e479SAndreas Jaekel }
1003e9a5e479SAndreas Jaekel 
1004e9a5e479SAndreas Jaekel static int
1005e9a5e479SAndreas Jaekel zev_queue_properties(int fd, char *arg)
1006e9a5e479SAndreas Jaekel {
1007e9a5e479SAndreas Jaekel 	zev_ioctl_get_queue_properties_t gqp;
1008e9a5e479SAndreas Jaekel 
10094ca7dd5eSAndreas Jaekel 	gqp.zev_queue_name.zev_namelen = strlen(arg);
10104ca7dd5eSAndreas Jaekel 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
1011e9a5e479SAndreas Jaekel 		fprintf(stderr, "queue name too long.\n");
1012e9a5e479SAndreas Jaekel 		return EXIT_FAILURE;
1013e9a5e479SAndreas Jaekel 	}
10144ca7dd5eSAndreas Jaekel 	strcpy(gqp.zev_queue_name.zev_name, arg);
1015e9a5e479SAndreas Jaekel 
1016e9a5e479SAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
1017e9a5e479SAndreas Jaekel 		perror("getting queue properties failed");
1018e9a5e479SAndreas Jaekel 		return (EXIT_FAILURE);
1019e9a5e479SAndreas Jaekel 	}
1020e9a5e479SAndreas Jaekel 
1021e9a5e479SAndreas Jaekel 	printf("queue        : %s\n", arg);
1022e9a5e479SAndreas Jaekel 	printf("max size     : %" PRIu64 "\n", gqp.zev_max_queue_len);
1023e9a5e479SAndreas Jaekel 	printf("poll throttle: %" PRIu64 "\n", gqp.zev_poll_wakeup_threshold);
1024e9a5e479SAndreas Jaekel 	printf("persistent   : %s\n",
1025e9a5e479SAndreas Jaekel 		gqp.zev_flags & ZEV_FL_PERSISTENT ? "yes" : "no");
1026e9a5e479SAndreas Jaekel 	printf("blocking     : %s\n",
1027e9a5e479SAndreas Jaekel 		gqp.zev_flags & ZEV_FL_BLOCK_WHILE_QUEUE_FULL ? "yes" : "no");
1028e9a5e479SAndreas Jaekel 
1029e9a5e479SAndreas Jaekel 	return (0);
1030e9a5e479SAndreas Jaekel }
1031e9a5e479SAndreas Jaekel 
1032e9a5e479SAndreas Jaekel static int
1033e9a5e479SAndreas Jaekel zev_list_queues(int fd)
1034e9a5e479SAndreas Jaekel {
1035e9a5e479SAndreas Jaekel 	zev_ioctl_get_queue_properties_t gqp;
1036e9a5e479SAndreas Jaekel 	zev_ioctl_get_queue_list_t gql;
1037e9a5e479SAndreas Jaekel 	zev_ioctl_get_queue_statistics_t gs;
1038e9a5e479SAndreas Jaekel 	uint64_t	i;
1039e9a5e479SAndreas Jaekel 	char		name[ZEV_MAX_QUEUE_NAME_LEN+1];
1040e9a5e479SAndreas Jaekel 
1041e9a5e479SAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_LIST, &gql)) {
1042e9a5e479SAndreas Jaekel 		perror("getting queue list failed");
1043e9a5e479SAndreas Jaekel 		return (EXIT_FAILURE);
1044e9a5e479SAndreas Jaekel 	}
1045e9a5e479SAndreas Jaekel 
1046e9a5e479SAndreas Jaekel 	printf("Name                                     Size       "
1047e9a5e479SAndreas Jaekel 	       "Max Size   Wakeup Per Block\n");
1048e9a5e479SAndreas Jaekel 
1049e9a5e479SAndreas Jaekel 	for (i=0; i<gql.zev_n_queues; i++) {
1050e9a5e479SAndreas Jaekel 		strncpy(name, gql.zev_queue_name[i].zev_name,
1051e9a5e479SAndreas Jaekel 		        ZEV_MAX_QUEUE_NAME_LEN);
1052e9a5e479SAndreas Jaekel 		name[gql.zev_queue_name[i].zev_namelen] = '\0';
1053e9a5e479SAndreas Jaekel 
10544ca7dd5eSAndreas Jaekel 		memcpy(gqp.zev_queue_name.zev_name,
10554ca7dd5eSAndreas Jaekel 		    gql.zev_queue_name[i].zev_name, ZEV_MAX_QUEUE_NAME_LEN);
10564ca7dd5eSAndreas Jaekel 		gqp.zev_queue_name.zev_namelen =
10574ca7dd5eSAndreas Jaekel 		    gql.zev_queue_name[i].zev_namelen;
1058e9a5e479SAndreas Jaekel 
1059e9a5e479SAndreas Jaekel 		if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
1060e9a5e479SAndreas Jaekel 			if (errno == ENOENT)
1061e9a5e479SAndreas Jaekel 				continue;
1062e9a5e479SAndreas Jaekel 			perror("getting queue properties failed");
1063e9a5e479SAndreas Jaekel 			return (EXIT_FAILURE);
1064e9a5e479SAndreas Jaekel 		}
1065e9a5e479SAndreas Jaekel 
10664ca7dd5eSAndreas Jaekel 		memcpy(gs.zev_queue_name.zev_name,
10674ca7dd5eSAndreas Jaekel 		    gql.zev_queue_name[i].zev_name, ZEV_MAX_QUEUE_NAME_LEN);
10684ca7dd5eSAndreas Jaekel 		gs.zev_queue_name.zev_namelen =
10694ca7dd5eSAndreas Jaekel 		    gql.zev_queue_name[i].zev_namelen;
1070e9a5e479SAndreas Jaekel 
1071e9a5e479SAndreas Jaekel 		if (ioctl(fd, ZEV_IOC_GET_QUEUE_STATISTICS, &gs)) {
1072e9a5e479SAndreas Jaekel 			if (errno == ENOENT)
1073e9a5e479SAndreas Jaekel 				continue;
1074e9a5e479SAndreas Jaekel 			perror("getting statistics data failed");
1075e9a5e479SAndreas Jaekel 			return (EXIT_FAILURE);
1076e9a5e479SAndreas Jaekel 		}
1077e9a5e479SAndreas Jaekel 
1078e9a5e479SAndreas Jaekel 		printf("%-40s %-10" PRIu64 " %-10" PRIu64 " %-6" PRIu64
1079e9a5e479SAndreas Jaekel 		       " %-3s %-3s\n",
1080e9a5e479SAndreas Jaekel 			name,
1081e9a5e479SAndreas Jaekel 			gs.zev_statistics.zev_queue_len,
1082e9a5e479SAndreas Jaekel 			gqp.zev_max_queue_len,
1083e9a5e479SAndreas Jaekel 			gqp.zev_poll_wakeup_threshold,
1084e9a5e479SAndreas Jaekel 			gqp.zev_flags & ZEV_FL_PERSISTENT ? "yes" : "no",
1085e9a5e479SAndreas Jaekel 			gqp.zev_flags & ZEV_FL_BLOCK_WHILE_QUEUE_FULL ?
1086e9a5e479SAndreas Jaekel 				 "yes" : "no");
1087e9a5e479SAndreas Jaekel 	}
1088e9a5e479SAndreas Jaekel 
1089e9a5e479SAndreas Jaekel 	return (0);
1090e9a5e479SAndreas Jaekel }
1091e9a5e479SAndreas Jaekel 
1092b9710123SAndreas Jaekel static int
1093b9710123SAndreas Jaekel zev_checksum(int dev_fd, char *filename)
1094b9710123SAndreas Jaekel {
1095b9710123SAndreas Jaekel 	int fd;
1096b9710123SAndreas Jaekel 	offset_t off;
1097b9710123SAndreas Jaekel 	offset_t data;
1098b9710123SAndreas Jaekel 	zev_sig_t *sig;
1099b9710123SAndreas Jaekel 	char *buf;
1100b9710123SAndreas Jaekel 	zev_ioctl_get_signatures_t *gs;
1101b9710123SAndreas Jaekel 	int i;
1102b9710123SAndreas Jaekel 	char sigval[(SHA1_DIGEST_LENGTH * 2) + 1];
1103b9710123SAndreas Jaekel 	int buf_size;
1104b9710123SAndreas Jaekel 
1105b9710123SAndreas Jaekel 	/* control struct, one lv1 signature and up to 256 lv0 signatures */
1106b9710123SAndreas Jaekel 	buf_size = (1 + 256) * sizeof(zev_sig_t);
1107b9710123SAndreas Jaekel 	buf = malloc(sizeof(zev_ioctl_get_signatures_t) + buf_size);
1108b9710123SAndreas Jaekel 	if (!buf) {
1109b9710123SAndreas Jaekel 		perror("can't allocate checksum buffer");
1110b9710123SAndreas Jaekel 		return (EXIT_FAILURE);
1111b9710123SAndreas Jaekel 	}
1112b9710123SAndreas Jaekel 
1113b9710123SAndreas Jaekel 	fd = open(filename, O_RDONLY);
1114b9710123SAndreas Jaekel 	if (fd < 0) {
1115b9710123SAndreas Jaekel 		perror("can't open file");
1116b9710123SAndreas Jaekel 		return (EXIT_FAILURE);
1117b9710123SAndreas Jaekel 	}
1118b9710123SAndreas Jaekel 
1119b9710123SAndreas Jaekel 	gs = (zev_ioctl_get_signatures_t *)buf;
1120b9710123SAndreas Jaekel 	gs->zev_fd = fd;
1121b9710123SAndreas Jaekel 	gs->zev_bufsize = buf_size;
1122b9710123SAndreas Jaekel 
1123b9710123SAndreas Jaekel 	off = 0;
1124b9710123SAndreas Jaekel 	data = 0;
1125b9710123SAndreas Jaekel 	while (1) {
1126b9710123SAndreas Jaekel 		errno = 0;
1127b9710123SAndreas Jaekel 		data = llseek(fd, off, SEEK_DATA);
1128b9710123SAndreas Jaekel 		if (data < 0) {
1129b9710123SAndreas Jaekel 			if (errno == ENXIO)	/* no more data */
1130b9710123SAndreas Jaekel 				break;
1131b9710123SAndreas Jaekel 			perror("llseek failed");
1132b9710123SAndreas Jaekel 			goto err;
1133b9710123SAndreas Jaekel 		}
1134b9710123SAndreas Jaekel 		data = P2ALIGN(data, ZEV_L1_SIZE);
1135b9710123SAndreas Jaekel 		off = data + ZEV_L1_SIZE;
1136b9710123SAndreas Jaekel 
1137b9710123SAndreas Jaekel 		gs->zev_offset = data;
1138b9710123SAndreas Jaekel 		gs->zev_len = ZEV_L1_SIZE;
1139b9710123SAndreas Jaekel 
1140b9710123SAndreas Jaekel 		if (ioctl(dev_fd, ZEV_IOC_GET_FILE_SIGNATURES, gs)) {
1141b9710123SAndreas Jaekel 			perror("ioctl to get signatures failed");
1142b9710123SAndreas Jaekel 			goto err;
1143b9710123SAndreas Jaekel 		}
1144b9710123SAndreas Jaekel 
1145b9710123SAndreas Jaekel 		for (i=0; i<gs->zev_signature_cnt; i++) {
1146b9710123SAndreas Jaekel 			sig = (zev_sig_t *)ZEV_SIGNATURES(gs);
1147b9710123SAndreas Jaekel 			sig += i;
1148b9710123SAndreas Jaekel 			sig2hex_direct(sig->value, sigval);
1149b9710123SAndreas Jaekel 			printf("level %d, offset %llu, value %s\n",
1150b9710123SAndreas Jaekel 			       sig->level, sig->block_offset, sigval);
1151b9710123SAndreas Jaekel 		}
1152b9710123SAndreas Jaekel 	}
1153b9710123SAndreas Jaekel 
1154b9710123SAndreas Jaekel 	free(buf);
1155b9710123SAndreas Jaekel 	close(fd);
1156b9710123SAndreas Jaekel 	return 0;
1157b9710123SAndreas Jaekel err:
1158b9710123SAndreas Jaekel 	free(buf);
1159b9710123SAndreas Jaekel 	close(fd);
1160b9710123SAndreas Jaekel 	return (EXIT_FAILURE);
1161b9710123SAndreas Jaekel }
1162b9710123SAndreas Jaekel 
11632bb8e5e2SAndreas Jaekel int
11642bb8e5e2SAndreas Jaekel main(int argc, char **argv)
11652bb8e5e2SAndreas Jaekel {
11662bb8e5e2SAndreas Jaekel 	int fd;
11672bb8e5e2SAndreas Jaekel 	int c;
11682bb8e5e2SAndreas Jaekel 	extern char *optarg;
11694ca7dd5eSAndreas Jaekel 	int create_tmp_queue = 1;
11704ca7dd5eSAndreas Jaekel 	char buf[MAXPATHLEN];
11712bb8e5e2SAndreas Jaekel 
11722bb8e5e2SAndreas Jaekel 	/* open device */
11732bb8e5e2SAndreas Jaekel 	fd = open(zev_device, O_RDONLY);
11742bb8e5e2SAndreas Jaekel 	if (fd < 0) {
11752bb8e5e2SAndreas Jaekel 		perror("opening zev device failed");
11762bb8e5e2SAndreas Jaekel 		return EXIT_FAILURE;
11772bb8e5e2SAndreas Jaekel 	}
11784ca7dd5eSAndreas Jaekel 	while ((c = getopt(argc, argv,
1179d65b2fffSAndreas Jaekel 	                   "gvspc:d:Dlk:L:q:Qt:m:M:a:A:r:P:b:B:h?")) != -1){
11802bb8e5e2SAndreas Jaekel 		switch(c) {
1181d65b2fffSAndreas Jaekel 		case 'g':
1182d65b2fffSAndreas Jaekel 			grep_friendly++;
1183d65b2fffSAndreas Jaekel 			verbose++;
1184d65b2fffSAndreas Jaekel 			break;
11855e286361SAndreas Jaekel 		case 'v':
11865e286361SAndreas Jaekel 			verbose++;
11875e286361SAndreas Jaekel 			break;
11882bb8e5e2SAndreas Jaekel 		case 's':
1189e9a5e479SAndreas Jaekel 			return zev_statistics(fd);
11902bb8e5e2SAndreas Jaekel 		case 'p':
11914ca7dd5eSAndreas Jaekel 			return zev_poll_events(fd, create_tmp_queue);
1192b9710123SAndreas Jaekel 		case 'c':
1193b9710123SAndreas Jaekel 			return zev_checksum(fd, optarg);
1194e9a5e479SAndreas Jaekel 		case 'D':
1195e9a5e479SAndreas Jaekel 			return zev_debug_info(fd);
11962bb8e5e2SAndreas Jaekel 		case 'd':
1197e9a5e479SAndreas Jaekel 			close(fd);
11982bb8e5e2SAndreas Jaekel 			zev_device = optarg;
1199e9a5e479SAndreas Jaekel 			fd = open(zev_device, O_RDONLY);
1200e9a5e479SAndreas Jaekel 			if (fd < 0) {
1201e9a5e479SAndreas Jaekel 				perror("opening zev device failed");
1202e9a5e479SAndreas Jaekel 				return EXIT_FAILURE;
1203e9a5e479SAndreas Jaekel 			}
12044ca7dd5eSAndreas Jaekel 			create_tmp_queue = 0;
12054ca7dd5eSAndreas Jaekel 			break;
12064ca7dd5eSAndreas Jaekel 		case 'q':
12074ca7dd5eSAndreas Jaekel 			snprintf(buf, sizeof(buf),
12084ca7dd5eSAndreas Jaekel 				 "/devices/pseudo/zev@0:%s", optarg);
12094ca7dd5eSAndreas Jaekel 			close(fd);
12104ca7dd5eSAndreas Jaekel 			zev_device = buf;
12114ca7dd5eSAndreas Jaekel 			fd = open(zev_device, O_RDONLY);
12124ca7dd5eSAndreas Jaekel 			if (fd < 0) {
12134ca7dd5eSAndreas Jaekel 				perror("opening zev device failed");
12144ca7dd5eSAndreas Jaekel 				return EXIT_FAILURE;
12154ca7dd5eSAndreas Jaekel 			}
12164ca7dd5eSAndreas Jaekel 			create_tmp_queue = 0;
12172bb8e5e2SAndreas Jaekel 			break;
1218e9a5e479SAndreas Jaekel 		case 'l':
1219e9a5e479SAndreas Jaekel 			return zev_list_queues(fd);
1220e9a5e479SAndreas Jaekel 		case 'Q':
1221e9a5e479SAndreas Jaekel 			return zev_set_global_max_queue_len(fd, optarg);
12224ca7dd5eSAndreas Jaekel 		case 'L':
1223e9a5e479SAndreas Jaekel 			return zev_set_max_queue_len(fd, optarg, argv[optind]);
1224205a9bc9SAndreas Jaekel 		case 't':
1225e9a5e479SAndreas Jaekel 			return zev_set_poll_wakeup_queue_len(fd, optarg,
1226e9a5e479SAndreas Jaekel 			                                     argv[optind]);
12272bb8e5e2SAndreas Jaekel 		case 'm':
12282bb8e5e2SAndreas Jaekel 			return zev_mute_pool(fd, optarg);
12292bb8e5e2SAndreas Jaekel 		case 'M':
12302bb8e5e2SAndreas Jaekel 			return zev_unmute_pool(fd, optarg);
123101c2c787SAndreas Jaekel 		case 'k':
123201c2c787SAndreas Jaekel 			return zev_mark(fd, optarg);
1233e9a5e479SAndreas Jaekel 		case 'a':
12344ca7dd5eSAndreas Jaekel 			return zev_add_queue(fd, optarg, 0);
12354ca7dd5eSAndreas Jaekel 		case 'A':
12364ca7dd5eSAndreas Jaekel 			return zev_add_queue(fd, optarg, 1);
1237e9a5e479SAndreas Jaekel 		case 'r':
1238e9a5e479SAndreas Jaekel 			return zev_remove_queue(fd, optarg);
1239e9a5e479SAndreas Jaekel 		case 'b':
1240e9a5e479SAndreas Jaekel 			return zev_queue_blocking(fd, optarg, 0);
1241e9a5e479SAndreas Jaekel 		case 'B':
1242e9a5e479SAndreas Jaekel 			return zev_queue_blocking(fd, optarg, 1);
1243e9a5e479SAndreas Jaekel 		case 'P':
1244e9a5e479SAndreas Jaekel 			return zev_queue_properties(fd, optarg);
12452bb8e5e2SAndreas Jaekel 		case 'h':
12462bb8e5e2SAndreas Jaekel 		case '?':
12472bb8e5e2SAndreas Jaekel 		default:
12482bb8e5e2SAndreas Jaekel 			usage(argv[0]);
12492bb8e5e2SAndreas Jaekel 		}
12502bb8e5e2SAndreas Jaekel 	}
12512bb8e5e2SAndreas Jaekel 	usage(argv[0]);
12522bb8e5e2SAndreas Jaekel 	close(fd);
1253e9a5e479SAndreas Jaekel 	return EXIT_FAILURE;
12542bb8e5e2SAndreas Jaekel }
12552bb8e5e2SAndreas Jaekel 
1256