xref: /titanic_44/usr/src/cmd/zevadm/zevadm.c (revision 35526fb3e8e137ac6bbd22b69dab04aeb6da3d84)
1a18c35b9SAndreas Jaekel #include <stdio.h>
2a18c35b9SAndreas Jaekel #include <unistd.h>
3a18c35b9SAndreas Jaekel #include <stdlib.h>
4a18c35b9SAndreas Jaekel #include <fcntl.h>
5a18c35b9SAndreas Jaekel #include <stropts.h>
6a18c35b9SAndreas Jaekel #include <poll.h>
7a18c35b9SAndreas Jaekel #include <string.h>
8a18c35b9SAndreas Jaekel #include <sys/fs/zev.h>
9a18c35b9SAndreas Jaekel #include <errno.h>
1042110aacSAndreas Jaekel #include <sys/sysmacros.h>
1116ff6b2fSAndreas Jaekel #include <stdarg.h>
12b690436dSAndreas Jaekel #include <sys/avl.h>
13f432e238SAndreas Jaekel #include <sys/stat.h>
14a18c35b9SAndreas Jaekel 
15add9520fSAndreas Jaekel #define ZEV_DEVICE "/devices/pseudo/zev@0:ctrl"
16a18c35b9SAndreas Jaekel 
17b690436dSAndreas Jaekel #if !defined(offsetof)
18b690436dSAndreas Jaekel #define	offsetof(s, m)	((size_t)(&(((s *)0)->m)))
19b690436dSAndreas Jaekel #endif
20b690436dSAndreas Jaekel 
21a18c35b9SAndreas Jaekel static char *zev_device = ZEV_DEVICE;
22a18c35b9SAndreas Jaekel 
23aafc540fSAndreas Jaekel static char *zev_op_name[] = {
2416ff6b2fSAndreas Jaekel 	"ERROR",
2516ff6b2fSAndreas Jaekel 	"MARK",
2616ff6b2fSAndreas Jaekel 	"ZFS_MOUNT",
2716ff6b2fSAndreas Jaekel 	"ZFS_UMOUNT",
2816ff6b2fSAndreas Jaekel 	"ZVOL_WRITE",
2916ff6b2fSAndreas Jaekel 	"ZVOL_TRUNCATE",
3016ff6b2fSAndreas Jaekel 	"ZNODE_CLOSE_AFTER_UPDATE",
3116ff6b2fSAndreas Jaekel 	"ZNODE_CREATE",
3216ff6b2fSAndreas Jaekel 	"ZNODE_MKDIR",
3316ff6b2fSAndreas Jaekel 	"ZNODE_MAKE_XATTR_DIR",
3416ff6b2fSAndreas Jaekel 	"ZNODE_REMOVE",
3516ff6b2fSAndreas Jaekel 	"ZNODE_RMDIR",
3616ff6b2fSAndreas Jaekel 	"ZNODE_LINK",
3716ff6b2fSAndreas Jaekel 	"ZNODE_SYMLINK",
3816ff6b2fSAndreas Jaekel 	"ZNODE_RENAME",
3916ff6b2fSAndreas Jaekel 	"ZNODE_WRITE",
4016ff6b2fSAndreas Jaekel 	"ZNODE_TRUNCATE",
4116ff6b2fSAndreas Jaekel 	"ZNODE_SETATTR",
4216ff6b2fSAndreas Jaekel 	"ZNODE_ACL",
43aafc540fSAndreas Jaekel 	NULL
44aafc540fSAndreas Jaekel };
45aafc540fSAndreas Jaekel 
46a5090b97SAndreas Jaekel #define MD_STATISTICS			1
47a5090b97SAndreas Jaekel #define MD_POLL_EVENTS			2
48a5090b97SAndreas Jaekel #define MD_CHECKSUMS			3
49a5090b97SAndreas Jaekel #define MD_DEBUG_INFO			4
50a5090b97SAndreas Jaekel #define MD_LIST_QUEUES			5
51a5090b97SAndreas Jaekel #define MD_SET_GLOBAL_MAX_QUEUE_LEN	6
52a5090b97SAndreas Jaekel #define MD_SET_MAX_QUEUE_LEN		7
53a5090b97SAndreas Jaekel #define MD_SET_POLL_WAKEUP_QUEUE_LEN	8
54a5090b97SAndreas Jaekel #define MD_MUTE_POOL			9
55a5090b97SAndreas Jaekel #define MD_UNMUTE_POOL			10
56a5090b97SAndreas Jaekel #define MD_MARK				11
57a5090b97SAndreas Jaekel #define MD_ADD_QUEUE			12
58a5090b97SAndreas Jaekel #define MD_ADD_BLOCKING_QUEUE		13
59a5090b97SAndreas Jaekel #define MD_REMOVE_QUEUE			14
60a5090b97SAndreas Jaekel #define MD_QUEUE_BLOCKING		15
61a5090b97SAndreas Jaekel #define MD_QUEUE_NONBLOCKING		16
62a5090b97SAndreas Jaekel #define MD_QUEUE_PROPERTIES		17
63b690436dSAndreas Jaekel #define MD_ZEVSTAT			18
64f432e238SAndreas Jaekel #define MD_ZEV_REPORT			19
65*35526fb3SArne Jansen #define MD_DUMP_SPOOL			20
66a5090b97SAndreas Jaekel 
67205ed6bfSAndreas Jaekel static int verbose = 0;
6816ff6b2fSAndreas Jaekel static int grep_friendly = 0;
6916ff6b2fSAndreas Jaekel 
7016ff6b2fSAndreas Jaekel static void
7116ff6b2fSAndreas Jaekel zpf(char *fmt, ...)
7216ff6b2fSAndreas Jaekel {
7316ff6b2fSAndreas Jaekel 	va_list	ap;
7416ff6b2fSAndreas Jaekel 
7516ff6b2fSAndreas Jaekel 	va_start(ap, fmt);
7616ff6b2fSAndreas Jaekel 	vprintf(fmt, ap);
7716ff6b2fSAndreas Jaekel 	va_end(ap);
7816ff6b2fSAndreas Jaekel 	if (grep_friendly) {
7916ff6b2fSAndreas Jaekel 		printf(" ");
8016ff6b2fSAndreas Jaekel 	} else {
8116ff6b2fSAndreas Jaekel 		printf("\n");
8216ff6b2fSAndreas Jaekel 	}
8316ff6b2fSAndreas Jaekel }
8416ff6b2fSAndreas Jaekel 
8516ff6b2fSAndreas Jaekel static void
8616ff6b2fSAndreas Jaekel znl(void)
8716ff6b2fSAndreas Jaekel {
8816ff6b2fSAndreas Jaekel 	if (grep_friendly)
8916ff6b2fSAndreas Jaekel 		printf("\n");
9016ff6b2fSAndreas Jaekel }
91205ed6bfSAndreas Jaekel 
922eabeab5SAndreas Jaekel static void
932eabeab5SAndreas Jaekel sig2hex_direct(const uint8_t *sig, char *hex)
942eabeab5SAndreas Jaekel {
952eabeab5SAndreas Jaekel 	int     i;
962eabeab5SAndreas Jaekel 
972eabeab5SAndreas Jaekel 	for (i = 0; i < SHA1_DIGEST_LENGTH; ++i) {
982eabeab5SAndreas Jaekel 		sprintf(hex + 2 * i, "%02x", sig[i]);
992eabeab5SAndreas Jaekel 	}
1002eabeab5SAndreas Jaekel 	hex[SHA1_DIGEST_LENGTH * 2] = '\0';
1012eabeab5SAndreas Jaekel }
1022eabeab5SAndreas Jaekel 
103add9520fSAndreas Jaekel static int
104a18c35b9SAndreas Jaekel zev_statistics(int fd)
105a18c35b9SAndreas Jaekel {
106a18c35b9SAndreas Jaekel 	zev_statistics_t zs;
107add9520fSAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_GET_GLOBAL_STATISTICS, &zs)) {
108a18c35b9SAndreas Jaekel 		perror("getting statistics data failed");
109add9520fSAndreas Jaekel 		return (EXIT_FAILURE);
110a18c35b9SAndreas Jaekel 	}
111a18c35b9SAndreas Jaekel 	printf("ZEV module state:\n");
112a18c35b9SAndreas Jaekel 
113a18c35b9SAndreas Jaekel 	printf("    queue length in bytes   : %lu\n", zs.zev_queue_len);
114a18c35b9SAndreas Jaekel 	printf("    queue length limit      : %lu\n", zs.zev_max_queue_len);
115a18c35b9SAndreas Jaekel 	printf("    bytes read from device  : %lu\n", zs.zev_bytes_read);
116a18c35b9SAndreas Jaekel 	printf("    module internal errors  : %lu\n\n", zs.zev_cnt_errors);
117a18c35b9SAndreas Jaekel 
118add9520fSAndreas Jaekel 	printf("    discarded events        : %lu\n",
119add9520fSAndreas Jaekel 	    zs.zev_cnt_discarded_events);
120add9520fSAndreas Jaekel 	printf("    discarded bytes         : %lu\n\n", zs.zev_bytes_discarded);
121add9520fSAndreas Jaekel 
122a18c35b9SAndreas Jaekel 	printf("ZFS event statistics:\n");
123a18c35b9SAndreas Jaekel 
124a18c35b9SAndreas Jaekel 	printf("    total ZFS events        : %lu\n", zs.zev_cnt_total_events);
125a18c35b9SAndreas Jaekel 	printf("    ZFS mount               : %lu\n", zs.zev_cnt_zfs_mount);
126a18c35b9SAndreas Jaekel 	printf("    ZFS umount              : %lu\n", zs.zev_cnt_zfs_umount);
127a18c35b9SAndreas Jaekel 	printf("    ZVOL write              : %lu\n", zs.zev_cnt_zvol_write);
128a18c35b9SAndreas Jaekel 	printf("    ZVOL truncate           : %lu\n", zs.zev_cnt_zvol_truncate);
129a18c35b9SAndreas Jaekel 	printf("    ZNODE close after update: %lu\n",
130a18c35b9SAndreas Jaekel 	    zs.zev_cnt_znode_close_after_update);
131a18c35b9SAndreas Jaekel 	printf("    ZNODE create            : %lu\n", zs.zev_cnt_znode_create);
132a18c35b9SAndreas Jaekel 	printf("    ZNODE remove            : %lu\n", zs.zev_cnt_znode_remove);
133a18c35b9SAndreas Jaekel 	printf("    ZNODE link              : %lu\n", zs.zev_cnt_znode_link);
134a18c35b9SAndreas Jaekel 	printf("    ZNODE symlink           : %lu\n", zs.zev_cnt_znode_symlink);
135a18c35b9SAndreas Jaekel 	printf("    ZNODE rename            : %lu\n", zs.zev_cnt_znode_rename);
136a18c35b9SAndreas Jaekel 	printf("    ZNODE write             : %lu\n", zs.zev_cnt_znode_write);
137a18c35b9SAndreas Jaekel 	printf("    ZNODE truncate          : %lu\n",
138a18c35b9SAndreas Jaekel 	    zs.zev_cnt_znode_truncate);
139a18c35b9SAndreas Jaekel 	printf("    ZNODE setattr           : %lu\n", zs.zev_cnt_znode_setattr);
140a18c35b9SAndreas Jaekel 	printf("    ZNODE acl               : %lu\n", zs.zev_cnt_znode_acl);
141add9520fSAndreas Jaekel 	return EXIT_SUCCESS;
142a18c35b9SAndreas Jaekel }
143a18c35b9SAndreas Jaekel 
144a18c35b9SAndreas Jaekel static void
14516ff6b2fSAndreas Jaekel zev_print_inode_info(char *name, zev_inode_info_t *info)
14616ff6b2fSAndreas Jaekel {
14716ff6b2fSAndreas Jaekel 	zpf("  %s.inode: %llu", name, info->ino);
14816ff6b2fSAndreas Jaekel 	zpf("  %s.gen: %llu", name, info->gen);
14916ff6b2fSAndreas Jaekel 	zpf("  %s.mtime: %llu", name, info->mtime);
15016ff6b2fSAndreas Jaekel 	zpf("  %s.ctime: %llu", name, info->ctime);
15116ff6b2fSAndreas Jaekel 	zpf("  %s.size: %llu", name, info->size);
15216ff6b2fSAndreas Jaekel 	zpf("  %s.mode: %llo", name, info->mode);
15316ff6b2fSAndreas Jaekel 	zpf("  %s.links: %llu", name, info->links);
15416ff6b2fSAndreas Jaekel 	zpf("  %s.type: %lu", name, info->type);
15516ff6b2fSAndreas Jaekel 	zpf("  %s.flags: %lu", name, info->flags);
15616ff6b2fSAndreas Jaekel }
15716ff6b2fSAndreas Jaekel 
15816ff6b2fSAndreas Jaekel static void
15916ff6b2fSAndreas Jaekel zev_print_mark_payload(zev_mark_t *rec)
16016ff6b2fSAndreas Jaekel {
16116ff6b2fSAndreas Jaekel 	int i;
16216ff6b2fSAndreas Jaekel 	int j;
16316ff6b2fSAndreas Jaekel 	uint8_t *p;
16416ff6b2fSAndreas Jaekel 	char c;
16516ff6b2fSAndreas Jaekel 
16616ff6b2fSAndreas Jaekel 	zpf("  payload:");
16716ff6b2fSAndreas Jaekel 	p = (uint8_t *)ZEV_PAYLOAD(rec);
16816ff6b2fSAndreas Jaekel 	for (i=0; i<rec->payload_len; i+=16) {
16916ff6b2fSAndreas Jaekel 		printf("  ");
17016ff6b2fSAndreas Jaekel 		for (j=i; j<rec->payload_len && j<i+16; j++) {
17116ff6b2fSAndreas Jaekel 			printf("%02x ", p[j]);
17216ff6b2fSAndreas Jaekel 			if (j == i + 7)
17316ff6b2fSAndreas Jaekel 				printf(" ");
17416ff6b2fSAndreas Jaekel 		}
17516ff6b2fSAndreas Jaekel 		if (grep_friendly)
17616ff6b2fSAndreas Jaekel 			continue;
17716ff6b2fSAndreas Jaekel 		for (; j<i+16; j++) {
17816ff6b2fSAndreas Jaekel 			printf("   ");
17916ff6b2fSAndreas Jaekel 			if (j == i + 7)
18016ff6b2fSAndreas Jaekel 				printf(" ");
18116ff6b2fSAndreas Jaekel 		}
18216ff6b2fSAndreas Jaekel 		printf("    ");
18316ff6b2fSAndreas Jaekel 		for (j=i; j<rec->payload_len && j<i+16; j++) {
18416ff6b2fSAndreas Jaekel 			c = '.';
18516ff6b2fSAndreas Jaekel 			if (p[j] >= ' ' && p[j] <= '~')
18616ff6b2fSAndreas Jaekel 				c = p[j];
18716ff6b2fSAndreas Jaekel 			printf("%c", c);
18816ff6b2fSAndreas Jaekel 			if (j == i + 7)
18916ff6b2fSAndreas Jaekel 				printf(" ");
19016ff6b2fSAndreas Jaekel 		}
19116ff6b2fSAndreas Jaekel 		printf("\n");
19216ff6b2fSAndreas Jaekel 	}
19316ff6b2fSAndreas Jaekel }
19416ff6b2fSAndreas Jaekel 
19516ff6b2fSAndreas Jaekel static void
196f2dd45e5SAndreas Jaekel zev_print_error(char *buf)
197f2dd45e5SAndreas Jaekel {
198f2dd45e5SAndreas Jaekel 	zev_error_t *rec = (zev_error_t *)buf;
199f2dd45e5SAndreas Jaekel 	time_t op_time = rec->op_time;
200f2dd45e5SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
201f2dd45e5SAndreas Jaekel 
20216ff6b2fSAndreas Jaekel 	if (verbose) {
20316ff6b2fSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
20416ff6b2fSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
20516ff6b2fSAndreas Jaekel 		zpf("  failed.op: %s",
20616ff6b2fSAndreas Jaekel 		    zev_op_name[rec->failed_op - ZEV_OP_MIN]);
20716ff6b2fSAndreas Jaekel 		zpf("  message: %s", ZEV_ERRSTR(rec));
20816ff6b2fSAndreas Jaekel 		znl();
20916ff6b2fSAndreas Jaekel 	} else {
210f2dd45e5SAndreas Jaekel 		printf("%s %s: failed_op=%s msg=%s\n",
211f2dd45e5SAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
21216ff6b2fSAndreas Jaekel 		       zev_op_name[rec->failed_op - ZEV_OP_MIN],
21316ff6b2fSAndreas Jaekel 		       ZEV_ERRSTR(rec));
21416ff6b2fSAndreas Jaekel 	}
215f2dd45e5SAndreas Jaekel }
216f2dd45e5SAndreas Jaekel 
217f2dd45e5SAndreas Jaekel static void
218888fea18SAndreas Jaekel zev_print_mark(char *buf)
219888fea18SAndreas Jaekel {
220888fea18SAndreas Jaekel 	zev_mark_t *rec = (zev_mark_t *)buf;
221888fea18SAndreas Jaekel 	time_t op_time = rec->op_time;
222888fea18SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
223888fea18SAndreas Jaekel 
22416ff6b2fSAndreas Jaekel 	if (verbose) {
22516ff6b2fSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
22616ff6b2fSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
22716ff6b2fSAndreas Jaekel 		zpf("  mark.id: %llu", rec->mark_id);
22816ff6b2fSAndreas Jaekel 		zpf("  payload.len: %llu", rec->payload_len);
22916ff6b2fSAndreas Jaekel 		if (rec->payload_len)
23016ff6b2fSAndreas Jaekel 			zev_print_mark_payload(rec);
23116ff6b2fSAndreas Jaekel 		znl();
23216ff6b2fSAndreas Jaekel 	} else {
233647b4f9eSJan Schlien 		printf("%s %s: guid=%llu mark_id=%lld payload_len=%ld "
234647b4f9eSJan Schlien 		       "payload=\"%.*s\"\n",
23516ff6b2fSAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN], rec->guid,
236647b4f9eSJan Schlien 		       rec->mark_id, rec->payload_len,
237647b4f9eSJan Schlien 		       rec->payload_len, (char *)(rec + 1));
23816ff6b2fSAndreas Jaekel 	}
239888fea18SAndreas Jaekel }
240888fea18SAndreas Jaekel 
241888fea18SAndreas Jaekel static void
242f2dd45e5SAndreas Jaekel zev_print_zfs_mount(char *buf)
243f2dd45e5SAndreas Jaekel {
244f2dd45e5SAndreas Jaekel 	zev_zfs_mount_t *rec = (zev_zfs_mount_t *)buf;
245f2dd45e5SAndreas Jaekel 	time_t op_time = rec->op_time;
246f2dd45e5SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
247f2dd45e5SAndreas Jaekel 
24816ff6b2fSAndreas Jaekel 	if (verbose) {
24916ff6b2fSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
25016ff6b2fSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
25116ff6b2fSAndreas Jaekel 		zpf("  dataset: %s", ZEV_DATASET(rec));
25216ff6b2fSAndreas Jaekel 		zpf("  mountpoint: %s", ZEV_MOUNTPOINT(rec));
25316ff6b2fSAndreas Jaekel 		zpf("  remount: %s", rec->remount ? "true" : "false");
25416ff6b2fSAndreas Jaekel 		zev_print_inode_info("root", &rec->root);
25516ff6b2fSAndreas Jaekel 		znl();
25616ff6b2fSAndreas Jaekel 	} else {
25716ff6b2fSAndreas Jaekel 		printf("%s %s: guid=%llu remount=%s dataset='%s' "
25816ff6b2fSAndreas Jaekel 		       "mountpoint='%s'\n",
259f2dd45e5SAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
260f2dd45e5SAndreas Jaekel 		       rec->guid,
261f2dd45e5SAndreas Jaekel 		       rec->remount ? "true" : "false",
262f2dd45e5SAndreas Jaekel 		       ZEV_DATASET(rec),
263f2dd45e5SAndreas Jaekel 		       ZEV_MOUNTPOINT(rec));
264f2dd45e5SAndreas Jaekel 	}
26516ff6b2fSAndreas Jaekel }
266f2dd45e5SAndreas Jaekel 
267f2dd45e5SAndreas Jaekel static void
268f2dd45e5SAndreas Jaekel zev_print_zfs_umount(char *buf)
269f2dd45e5SAndreas Jaekel {
270f2dd45e5SAndreas Jaekel 	zev_zfs_umount_t *rec = (zev_zfs_umount_t *)buf;
271f2dd45e5SAndreas Jaekel 	time_t op_time = rec->op_time;
272f2dd45e5SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
273f2dd45e5SAndreas Jaekel 
27416ff6b2fSAndreas Jaekel 	if (verbose) {
27516ff6b2fSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
27616ff6b2fSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
27794875cb8SAndreas Jaekel 		zev_print_inode_info("covered", &rec->covered);
27816ff6b2fSAndreas Jaekel 		znl();
27916ff6b2fSAndreas Jaekel 	} else {
280f2dd45e5SAndreas Jaekel 		printf("%s %s: guid=%llu\n",
281f2dd45e5SAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
282f2dd45e5SAndreas Jaekel 		       rec->guid);
283f2dd45e5SAndreas Jaekel 	}
28416ff6b2fSAndreas Jaekel }
285f2dd45e5SAndreas Jaekel 
286f2dd45e5SAndreas Jaekel static void
287f2dd45e5SAndreas Jaekel zev_print_zvol_truncate(char *buf)
288f2dd45e5SAndreas Jaekel {
289f2dd45e5SAndreas Jaekel 	zev_zvol_truncate_t *rec = (zev_zvol_truncate_t *)buf;
290f2dd45e5SAndreas Jaekel 	time_t op_time = rec->op_time;
291f2dd45e5SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
292f2dd45e5SAndreas Jaekel 
29316ff6b2fSAndreas Jaekel 	if (verbose) {
29416ff6b2fSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
29516ff6b2fSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
29612119a7eSAndreas Jaekel 		zpf("  txg: %llu", rec->txg);
29716ff6b2fSAndreas Jaekel 		zpf("  offset: %llu", rec->offset);
29816ff6b2fSAndreas Jaekel 		zpf("  length: %llu", rec->length);
29916ff6b2fSAndreas Jaekel 		znl();
30016ff6b2fSAndreas Jaekel 	} else {
301f2dd45e5SAndreas Jaekel 		printf("%s %s: guid=%llu offset=%llu length=%llu\n",
302f2dd45e5SAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
303f2dd45e5SAndreas Jaekel 		       rec->guid,
304f2dd45e5SAndreas Jaekel 		       rec->offset,
305f2dd45e5SAndreas Jaekel 		       rec->length);
306f2dd45e5SAndreas Jaekel 	}
30716ff6b2fSAndreas Jaekel }
308f2dd45e5SAndreas Jaekel 
309f2dd45e5SAndreas Jaekel static void
310f2dd45e5SAndreas Jaekel zev_print_zvol_write(char *buf)
311f2dd45e5SAndreas Jaekel {
312f2dd45e5SAndreas Jaekel 	zev_print_zvol_truncate(buf);
313f2dd45e5SAndreas Jaekel }
314f2dd45e5SAndreas Jaekel 
315f2dd45e5SAndreas Jaekel static void
316f2dd45e5SAndreas Jaekel zev_print_znode_close_after_update(char *buf)
317f2dd45e5SAndreas Jaekel {
318f2dd45e5SAndreas Jaekel 	zev_znode_close_after_update_t *rec =
319f2dd45e5SAndreas Jaekel 	    (zev_znode_close_after_update_t *)buf;
320f2dd45e5SAndreas Jaekel 	time_t op_time = rec->op_time;
321f2dd45e5SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
322f2dd45e5SAndreas Jaekel 
32316ff6b2fSAndreas Jaekel 	if (verbose) {
32416ff6b2fSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
32516ff6b2fSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
32616ff6b2fSAndreas Jaekel 		zev_print_inode_info("file", &rec->file);
32716ff6b2fSAndreas Jaekel 		znl();
32816ff6b2fSAndreas Jaekel 	} else {
329f2dd45e5SAndreas Jaekel 		printf("%s %s: guid=%llu file=%llu.%llu\n",
330f2dd45e5SAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
331f2dd45e5SAndreas Jaekel 		       rec->guid,
332f2dd45e5SAndreas Jaekel 		       rec->file.ino, rec->file.gen);
333f2dd45e5SAndreas Jaekel 	}
33416ff6b2fSAndreas Jaekel }
335f2dd45e5SAndreas Jaekel 
336f2dd45e5SAndreas Jaekel static void
337f2dd45e5SAndreas Jaekel zev_print_znode_create(char *buf)
338f2dd45e5SAndreas Jaekel {
339f2dd45e5SAndreas Jaekel 	zev_znode_create_t *rec = (zev_znode_create_t *)buf;
340f2dd45e5SAndreas Jaekel 	time_t op_time = rec->op_time;
341f2dd45e5SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
3422eabeab5SAndreas Jaekel 	zev_sig_t *sig;
3432eabeab5SAndreas Jaekel 	char sigval[(SHA1_DIGEST_LENGTH * 2) + 1];
344f2dd45e5SAndreas Jaekel 
34516ff6b2fSAndreas Jaekel 	if (verbose) {
34616ff6b2fSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
34716ff6b2fSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
34812119a7eSAndreas Jaekel 		zpf("  txg: %llu", rec->txg);
34916ff6b2fSAndreas Jaekel 		zpf("  name: '%s'", ZEV_NAME(rec));
3502eabeab5SAndreas Jaekel 		sig = &rec->signature;
3512eabeab5SAndreas Jaekel 		sig2hex_direct(sig->value, sigval);
3522eabeab5SAndreas Jaekel 		zpf("  sig: level %d, offset %llu, value %s",
3532eabeab5SAndreas Jaekel 		    sig->level, sig->block_offset, sigval);
35416ff6b2fSAndreas Jaekel 		zev_print_inode_info("file", &rec->file);
35512119a7eSAndreas Jaekel 		zev_print_inode_info("parent", &rec->parent);
35616ff6b2fSAndreas Jaekel 		znl();
35716ff6b2fSAndreas Jaekel 	} else {
35835d4e8ddSAndreas Jaekel 		printf("%s %s: guid=%llu parent=%llu.%llu file=%llu.%llu "
35935d4e8ddSAndreas Jaekel 		       "file.mtime=%llu, parent.mtime=%llu, name='%s'\n",
360f2dd45e5SAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
361f2dd45e5SAndreas Jaekel 		       rec->guid,
362f2dd45e5SAndreas Jaekel 		       rec->parent.ino, rec->parent.gen,
363f2dd45e5SAndreas Jaekel 		       rec->file.ino, rec->file.gen,
36435d4e8ddSAndreas Jaekel 		       rec->file.mtime, rec->parent.mtime,
365f2dd45e5SAndreas Jaekel 		       ZEV_NAME(rec));
366f2dd45e5SAndreas Jaekel 	}
36716ff6b2fSAndreas Jaekel }
368f2dd45e5SAndreas Jaekel 
369f2dd45e5SAndreas Jaekel static void
370f2dd45e5SAndreas Jaekel zev_print_znode_mkdir(char *buf)
371f2dd45e5SAndreas Jaekel {
372f2dd45e5SAndreas Jaekel 	zev_print_znode_create(buf);
373f2dd45e5SAndreas Jaekel }
374f2dd45e5SAndreas Jaekel 
375f2dd45e5SAndreas Jaekel static void
376f2dd45e5SAndreas Jaekel zev_print_znode_make_xattr_dir(char *buf)
377f2dd45e5SAndreas Jaekel {
378f2dd45e5SAndreas Jaekel 	zev_print_znode_create(buf);
379f2dd45e5SAndreas Jaekel }
380f2dd45e5SAndreas Jaekel 
381f2dd45e5SAndreas Jaekel static void
382f2dd45e5SAndreas Jaekel zev_print_znode_remove(char *buf)
383f2dd45e5SAndreas Jaekel {
384f2dd45e5SAndreas Jaekel 	zev_znode_remove_t *rec = (zev_znode_remove_t *)buf;
385f2dd45e5SAndreas Jaekel 	time_t op_time = rec->op_time;
386f2dd45e5SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
387f2dd45e5SAndreas Jaekel 
38816ff6b2fSAndreas Jaekel 	if (verbose) {
38916ff6b2fSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
39016ff6b2fSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
39112119a7eSAndreas Jaekel 		zpf("  txg: %llu", rec->txg);
39216ff6b2fSAndreas Jaekel 		zpf("  file.name: '%s'", ZEV_NAME(rec));
39316ff6b2fSAndreas Jaekel 		zev_print_inode_info("file", &rec->file);
39412119a7eSAndreas Jaekel 		zev_print_inode_info("parent", &rec->parent);
39516ff6b2fSAndreas Jaekel 		znl();
39616ff6b2fSAndreas Jaekel 	} else {
39716ff6b2fSAndreas Jaekel 		printf("%s %s: guid=%llu parent=%llu.%llu "
39816ff6b2fSAndreas Jaekel 		       "file.mtime=%llu name='%s'\n",
399f2dd45e5SAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
400f2dd45e5SAndreas Jaekel 		       rec->guid,
401f2dd45e5SAndreas Jaekel 		       rec->parent.ino, rec->parent.gen,
40297dcf88dSAndreas Jaekel 		       rec->file.mtime,
403f2dd45e5SAndreas Jaekel 		       ZEV_NAME(rec));
404f2dd45e5SAndreas Jaekel 	}
40516ff6b2fSAndreas Jaekel }
406f2dd45e5SAndreas Jaekel 
407f2dd45e5SAndreas Jaekel static void
408f2dd45e5SAndreas Jaekel zev_print_znode_rmdir(char *buf)
409f2dd45e5SAndreas Jaekel {
410f2dd45e5SAndreas Jaekel 	zev_print_znode_remove(buf);
411f2dd45e5SAndreas Jaekel }
412f2dd45e5SAndreas Jaekel 
413f2dd45e5SAndreas Jaekel static void
414f2dd45e5SAndreas Jaekel zev_print_znode_link(char *buf)
415f2dd45e5SAndreas Jaekel {
416f2dd45e5SAndreas Jaekel 	zev_znode_link_t *rec = (zev_znode_link_t *)buf;
417f2dd45e5SAndreas Jaekel 	time_t op_time = rec->op_time;
418f2dd45e5SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
419f2dd45e5SAndreas Jaekel 
42016ff6b2fSAndreas Jaekel 	if (verbose) {
42116ff6b2fSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
42216ff6b2fSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
42312119a7eSAndreas Jaekel 		zpf("  txg: %llu", rec->txg);
42416ff6b2fSAndreas Jaekel 		zpf("  link.name: '%s'", ZEV_NAME(rec));
42516ff6b2fSAndreas Jaekel 		zev_print_inode_info("file", &rec->file);
42612119a7eSAndreas Jaekel 		zev_print_inode_info("parent", &rec->parent);
42716ff6b2fSAndreas Jaekel 		znl();
42816ff6b2fSAndreas Jaekel 	} else {
429a01b300aSAndreas Jaekel 		printf("%s %s: parent=%llu.%llu file=%llu.%llu "
430a01b300aSAndreas Jaekel 		       "file.ctime=%llu parent.ctime=%llu name='%s'\n",
431f2dd45e5SAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
432f2dd45e5SAndreas Jaekel 		       rec->parent.ino, rec->parent.gen,
433f2dd45e5SAndreas Jaekel 		       rec->file.ino, rec->file.gen,
434a01b300aSAndreas Jaekel 		       rec->file.ctime, rec->parent.ctime,
435f2dd45e5SAndreas Jaekel 		       ZEV_NAME(rec));
43616ff6b2fSAndreas Jaekel 	}
437f2dd45e5SAndreas Jaekel }
438f2dd45e5SAndreas Jaekel 
439f2dd45e5SAndreas Jaekel static void
440f2dd45e5SAndreas Jaekel zev_print_znode_symlink(char *buf)
441f2dd45e5SAndreas Jaekel {
442f2dd45e5SAndreas Jaekel 	zev_znode_symlink_t *rec = (zev_znode_symlink_t *)buf;
443f2dd45e5SAndreas Jaekel 	time_t op_time = rec->op_time;
444f2dd45e5SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
4452eabeab5SAndreas Jaekel 	zev_sig_t *sig;
4462eabeab5SAndreas Jaekel 	char sigval[(SHA1_DIGEST_LENGTH * 2) + 1];
447f2dd45e5SAndreas Jaekel 
44816ff6b2fSAndreas Jaekel 	if (verbose) {
44916ff6b2fSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
45016ff6b2fSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
45112119a7eSAndreas Jaekel 		zpf("  txg: %llu", rec->txg);
45216ff6b2fSAndreas Jaekel 		zpf("  symlink.name: '%s'", ZEV_NAME(rec));
45316ff6b2fSAndreas Jaekel 		zpf("  symlink.link: '%s'", ZEV_LINK(rec));
4542eabeab5SAndreas Jaekel 		sig = &rec->signature;
4552eabeab5SAndreas Jaekel 		sig2hex_direct(sig->value, sigval);
4562eabeab5SAndreas Jaekel 		zpf("  sig: level %d, offset %llu, value %s",
4572eabeab5SAndreas Jaekel 		    sig->level, sig->block_offset, sigval);
45816ff6b2fSAndreas Jaekel 		zev_print_inode_info("file", &rec->file);
45912119a7eSAndreas Jaekel 		zev_print_inode_info("parent", &rec->parent);
46016ff6b2fSAndreas Jaekel 		znl();
46116ff6b2fSAndreas Jaekel 	} else {
46216ff6b2fSAndreas Jaekel 		printf("%s %s: parent=%llu.%llu file=%llu.%llu "
46316ff6b2fSAndreas Jaekel 		       "name='%s' link='%s'\n",
464f2dd45e5SAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
465f2dd45e5SAndreas Jaekel 		       rec->parent.ino, rec->parent.gen,
466f2dd45e5SAndreas Jaekel 		       rec->file.ino, rec->file.gen,
467f2dd45e5SAndreas Jaekel 		       ZEV_NAME(rec),
468f2dd45e5SAndreas Jaekel 		       ZEV_LINK(rec));
469f2dd45e5SAndreas Jaekel 	}
47016ff6b2fSAndreas Jaekel }
471f2dd45e5SAndreas Jaekel 
472f2dd45e5SAndreas Jaekel static void
473f2dd45e5SAndreas Jaekel zev_print_znode_rename(char *buf)
474f2dd45e5SAndreas Jaekel {
475f2dd45e5SAndreas Jaekel 	zev_znode_rename_t *rec = (zev_znode_rename_t *)buf;
476f2dd45e5SAndreas Jaekel 	time_t op_time = rec->op_time;
477f2dd45e5SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
478f2dd45e5SAndreas Jaekel 
47916ff6b2fSAndreas Jaekel 	if (verbose) {
48016ff6b2fSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
48116ff6b2fSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
48212119a7eSAndreas Jaekel 		zpf("  txg: %llu", rec->txg);
48316ff6b2fSAndreas Jaekel 		zpf("  file.srcname: '%s'", ZEV_SRCNAME(rec));
48416ff6b2fSAndreas Jaekel 		zpf("  file.dstname: '%s'", ZEV_DSTNAME(rec));
48516ff6b2fSAndreas Jaekel 		zev_print_inode_info("file", &rec->file);
4868aa47a6bSAndreas Jaekel 		if (rec->clobbered_file.ino)
4878aa47a6bSAndreas Jaekel 			zev_print_inode_info("clobbered_file",
4888aa47a6bSAndreas Jaekel 			                     &rec->clobbered_file);
48916ff6b2fSAndreas Jaekel 		zev_print_inode_info("srcdir", &rec->srcdir);
49016ff6b2fSAndreas Jaekel 		zev_print_inode_info("dstdir", &rec->dstdir);
49116ff6b2fSAndreas Jaekel 		znl();
49216ff6b2fSAndreas Jaekel 	} else {
49316ff6b2fSAndreas Jaekel 		printf("%s %s: srcdir=%llu.%llu dstdir=%llu.%llu "
49416ff6b2fSAndreas Jaekel 		       "file=%llu.%llu file.mtime=%llu, file.ctime=%llu, "
49516ff6b2fSAndreas Jaekel 		       "srcdir.mtime=%llu, srcdir.ctime=%llu, "
49616ff6b2fSAndreas Jaekel 		       "dstdir.mtime=%llu, dstdir.ctime=%llu, "
497f2dd45e5SAndreas Jaekel 		       "srcname='%s' dstname='%s'\n",
498f2dd45e5SAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
499f2dd45e5SAndreas Jaekel 		       rec->srcdir.ino, rec->srcdir.gen,
500f2dd45e5SAndreas Jaekel 		       rec->dstdir.ino, rec->dstdir.gen,
501f2dd45e5SAndreas Jaekel 		       rec->file.ino, rec->file.gen,
50235d4e8ddSAndreas Jaekel 		       rec->file.mtime, rec->file.ctime,
50335d4e8ddSAndreas Jaekel 		       rec->srcdir.mtime, rec->srcdir.ctime,
50435d4e8ddSAndreas Jaekel 		       rec->dstdir.mtime, rec->dstdir.ctime,
505f2dd45e5SAndreas Jaekel 		       ZEV_SRCNAME(rec),
506f2dd45e5SAndreas Jaekel 		       ZEV_DSTNAME(rec));
507f2dd45e5SAndreas Jaekel 	}
50816ff6b2fSAndreas Jaekel }
509f2dd45e5SAndreas Jaekel 
510f2dd45e5SAndreas Jaekel static void
511f2dd45e5SAndreas Jaekel zev_print_znode_write(char *buf)
512f2dd45e5SAndreas Jaekel {
513f2dd45e5SAndreas Jaekel 	zev_znode_write_t *rec = (zev_znode_write_t *)buf;
514f2dd45e5SAndreas Jaekel 	time_t op_time = rec->op_time;
515f2dd45e5SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
516205ed6bfSAndreas Jaekel 	zev_sig_t *sig;
517205ed6bfSAndreas Jaekel 	char sigval[(SHA1_DIGEST_LENGTH * 2) + 1];
518205ed6bfSAndreas Jaekel 	int i;
519f2dd45e5SAndreas Jaekel 
520205ed6bfSAndreas Jaekel 	if (verbose) {
52116ff6b2fSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
52216ff6b2fSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
52312119a7eSAndreas Jaekel 		zpf("  txg: %llu", rec->txg);
52416ff6b2fSAndreas Jaekel 		zpf("  offset: %llu", rec->offset);
52516ff6b2fSAndreas Jaekel 		zpf("  length: %llu", rec->length);
52616ff6b2fSAndreas Jaekel 		zev_print_inode_info("file", &rec->file);
52716ff6b2fSAndreas Jaekel 		znl();
528205ed6bfSAndreas Jaekel 		for (i=0; i<rec->signature_cnt; i++) {
529205ed6bfSAndreas Jaekel 			sig = (zev_sig_t *)ZEV_SIGNATURES(rec);
530205ed6bfSAndreas Jaekel 			sig += i;
531205ed6bfSAndreas Jaekel 			sig2hex_direct(sig->value, sigval);
5322eabeab5SAndreas Jaekel 			zpf("  sig: level %d, offset %llu, value %s",
533205ed6bfSAndreas Jaekel 			    sig->level, sig->block_offset, sigval);
534205ed6bfSAndreas Jaekel 		}
53516ff6b2fSAndreas Jaekel 	} else {
53616ff6b2fSAndreas Jaekel 		printf("%s %s: file=%llu.%llu offset=%llu length=%llu\n",
53716ff6b2fSAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
53816ff6b2fSAndreas Jaekel 		       rec->file.ino, rec->file.gen,
53916ff6b2fSAndreas Jaekel 		       rec->offset, rec->length);
540205ed6bfSAndreas Jaekel 	}
541f2dd45e5SAndreas Jaekel }
542f2dd45e5SAndreas Jaekel 
543f2dd45e5SAndreas Jaekel static void
544f2dd45e5SAndreas Jaekel zev_print_znode_truncate(char *buf)
545f2dd45e5SAndreas Jaekel {
546f2dd45e5SAndreas Jaekel 	zev_print_znode_write(buf);
547f2dd45e5SAndreas Jaekel }
548f2dd45e5SAndreas Jaekel 
549f2dd45e5SAndreas Jaekel static void
550f2dd45e5SAndreas Jaekel zev_print_znode_setattr(char *buf)
551f2dd45e5SAndreas Jaekel {
552f2dd45e5SAndreas Jaekel 	zev_znode_setattr_t *rec = (zev_znode_setattr_t *)buf;
553f2dd45e5SAndreas Jaekel 	time_t op_time = rec->op_time;
554f2dd45e5SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
555f2dd45e5SAndreas Jaekel 
55616ff6b2fSAndreas Jaekel 	if (verbose) {
55716ff6b2fSAndreas Jaekel 		zpf("%s %s", ct, zev_op_name[rec->op - ZEV_OP_MIN]);
55816ff6b2fSAndreas Jaekel 		zpf("  guid: %llu", rec->guid);
55912119a7eSAndreas Jaekel 		zpf("  txg: %llu", rec->txg);
56016ff6b2fSAndreas Jaekel 		zev_print_inode_info("file", &rec->file);
56116ff6b2fSAndreas Jaekel 		znl();
56216ff6b2fSAndreas Jaekel 	} else {
56335d4e8ddSAndreas Jaekel 		printf("%s %s: file=%llu.%llu mtime=%llu\n",
564f2dd45e5SAndreas Jaekel 		       ct, zev_op_name[rec->op - ZEV_OP_MIN],
56535d4e8ddSAndreas Jaekel 		       rec->file.ino, rec->file.gen, rec->file.mtime);
566f2dd45e5SAndreas Jaekel 	}
56716ff6b2fSAndreas Jaekel }
568f2dd45e5SAndreas Jaekel 
569f2dd45e5SAndreas Jaekel static void
570f2dd45e5SAndreas Jaekel zev_print_znode_acl(char *buf)
571f2dd45e5SAndreas Jaekel {
572f2dd45e5SAndreas Jaekel 	zev_print_znode_setattr(buf);
573f2dd45e5SAndreas Jaekel }
574f2dd45e5SAndreas Jaekel 
575f2dd45e5SAndreas Jaekel static void
576aafc540fSAndreas Jaekel zev_print_event(char *buf, int len)
577aafc540fSAndreas Jaekel {
578f2dd45e5SAndreas Jaekel 	int record_len;
579f2dd45e5SAndreas Jaekel 	int op;
580aafc540fSAndreas Jaekel 
581f2dd45e5SAndreas Jaekel 	record_len = *(uint32_t *)buf;
582f2dd45e5SAndreas Jaekel 	if (record_len != len) {
583f2dd45e5SAndreas Jaekel 		fprintf(stderr, "record length mismatch: got %d, expected %d\n",
584f2dd45e5SAndreas Jaekel 		        record_len, len);
585aafc540fSAndreas Jaekel 		exit(1);
586aafc540fSAndreas Jaekel 	}
587f2dd45e5SAndreas Jaekel 	op = *((uint32_t *)buf + 1);
588aafc540fSAndreas Jaekel 	if (op < ZEV_OP_MIN || op > ZEV_OP_MAX) {
589f2dd45e5SAndreas Jaekel 		fprintf(stderr, "unknown op code: %d\n", op);
590aafc540fSAndreas Jaekel 		exit(1);
591aafc540fSAndreas Jaekel 	}
592f2dd45e5SAndreas Jaekel 	switch (op) {
593f2dd45e5SAndreas Jaekel 	case ZEV_OP_ERROR:
594f2dd45e5SAndreas Jaekel 		zev_print_error(buf);
595aafc540fSAndreas Jaekel 		break;
596888fea18SAndreas Jaekel 	case ZEV_OP_MARK:
597888fea18SAndreas Jaekel 		zev_print_mark(buf);
598888fea18SAndreas Jaekel 		break;
599f2dd45e5SAndreas Jaekel 	case ZEV_OP_ZFS_MOUNT:
600f2dd45e5SAndreas Jaekel 		zev_print_zfs_mount(buf);
601aafc540fSAndreas Jaekel 		break;
602f2dd45e5SAndreas Jaekel 	case ZEV_OP_ZFS_UMOUNT:
603f2dd45e5SAndreas Jaekel 		zev_print_zfs_umount(buf);
604aafc540fSAndreas Jaekel 		break;
605f2dd45e5SAndreas Jaekel 	case ZEV_OP_ZVOL_TRUNCATE:
606f2dd45e5SAndreas Jaekel 		zev_print_zvol_truncate(buf);
607aafc540fSAndreas Jaekel 		break;
608f2dd45e5SAndreas Jaekel 	case ZEV_OP_ZVOL_WRITE:
609f2dd45e5SAndreas Jaekel 		zev_print_zvol_write(buf);
610f2dd45e5SAndreas Jaekel 		break;
611f2dd45e5SAndreas Jaekel 	case ZEV_OP_ZNODE_CLOSE_AFTER_UPDATE:
612f2dd45e5SAndreas Jaekel 		zev_print_znode_close_after_update(buf);
613f2dd45e5SAndreas Jaekel 		break;
614f2dd45e5SAndreas Jaekel 	case ZEV_OP_ZNODE_CREATE:
615f2dd45e5SAndreas Jaekel 		zev_print_znode_create(buf);
616f2dd45e5SAndreas Jaekel 		break;
617f2dd45e5SAndreas Jaekel 	case ZEV_OP_ZNODE_MKDIR:
618f2dd45e5SAndreas Jaekel 		zev_print_znode_mkdir(buf);
619f2dd45e5SAndreas Jaekel 		break;
620f2dd45e5SAndreas Jaekel 	case ZEV_OP_ZNODE_MAKE_XATTR_DIR:
621f2dd45e5SAndreas Jaekel 		zev_print_znode_make_xattr_dir(buf);
622f2dd45e5SAndreas Jaekel 		break;
623f2dd45e5SAndreas Jaekel 	case ZEV_OP_ZNODE_REMOVE:
624f2dd45e5SAndreas Jaekel 		zev_print_znode_remove(buf);
625f2dd45e5SAndreas Jaekel 		break;
626f2dd45e5SAndreas Jaekel 	case ZEV_OP_ZNODE_RMDIR:
627f2dd45e5SAndreas Jaekel 		zev_print_znode_rmdir(buf);
628f2dd45e5SAndreas Jaekel 		break;
629f2dd45e5SAndreas Jaekel 	case ZEV_OP_ZNODE_LINK:
630f2dd45e5SAndreas Jaekel 		zev_print_znode_link(buf);
631f2dd45e5SAndreas Jaekel 		break;
632f2dd45e5SAndreas Jaekel 	case ZEV_OP_ZNODE_SYMLINK:
633f2dd45e5SAndreas Jaekel 		zev_print_znode_symlink(buf);
634f2dd45e5SAndreas Jaekel 		break;
635f2dd45e5SAndreas Jaekel 	case ZEV_OP_ZNODE_RENAME:
636f2dd45e5SAndreas Jaekel 		zev_print_znode_rename(buf);
637f2dd45e5SAndreas Jaekel 		break;
638f2dd45e5SAndreas Jaekel 	case ZEV_OP_ZNODE_WRITE:
639f2dd45e5SAndreas Jaekel 		zev_print_znode_write(buf);
640f2dd45e5SAndreas Jaekel 		break;
641f2dd45e5SAndreas Jaekel 	case ZEV_OP_ZNODE_TRUNCATE:
642f2dd45e5SAndreas Jaekel 		zev_print_znode_truncate(buf);
643f2dd45e5SAndreas Jaekel 		break;
644f2dd45e5SAndreas Jaekel 	case ZEV_OP_ZNODE_SETATTR:
645f2dd45e5SAndreas Jaekel 		zev_print_znode_setattr(buf);
646f2dd45e5SAndreas Jaekel 		break;
647f2dd45e5SAndreas Jaekel 	case ZEV_OP_ZNODE_ACL:
648f2dd45e5SAndreas Jaekel 		zev_print_znode_acl(buf);
649aafc540fSAndreas Jaekel 		break;
650aafc540fSAndreas Jaekel 	default:
651f2dd45e5SAndreas Jaekel 		fprintf(stderr, "unhandled op code: %d\n", op);
652aafc540fSAndreas Jaekel 		exit(1);
653aafc540fSAndreas Jaekel 	}
654aafc540fSAndreas Jaekel }
655aafc540fSAndreas Jaekel 
656add9520fSAndreas Jaekel static int
6576a6a51eeSAndreas Jaekel zev_poll_events(int fd, int create_tmp_queue)
658a18c35b9SAndreas Jaekel {
659a18c35b9SAndreas Jaekel 	struct pollfd pfd[1];
660a18c35b9SAndreas Jaekel 	int ret;
661aafc540fSAndreas Jaekel 	char buf[4096];
662d979f56cSAndreas Jaekel 	zev_event_t *ev;
663d979f56cSAndreas Jaekel 	int off = 0;
664add9520fSAndreas Jaekel 	zev_ioctl_add_queue_t aq;
665add9520fSAndreas Jaekel 	int q_fd;
666add9520fSAndreas Jaekel 
6676a6a51eeSAndreas Jaekel 	if (create_tmp_queue) {
668add9520fSAndreas Jaekel 		aq.zev_max_queue_len = 0;
669113f4c19SJan Schlien 		aq.zev_flags = ZEV_FL_INITIALLY_EMPTY;
670add9520fSAndreas Jaekel 		snprintf(aq.zev_name, ZEV_MAX_QUEUE_NAME_LEN,
671add9520fSAndreas Jaekel 			 "zevadm.%ld.%ld", time(NULL), getpid());
672add9520fSAndreas Jaekel 		aq.zev_namelen = strlen(aq.zev_name);
673add9520fSAndreas Jaekel 
674add9520fSAndreas Jaekel 		if (ioctl(fd, ZEV_IOC_ADD_QUEUE, &aq)) {
675add9520fSAndreas Jaekel 			perror("adding temporary queue failed");
676add9520fSAndreas Jaekel 			return (EXIT_FAILURE);
677add9520fSAndreas Jaekel 		}
678add9520fSAndreas Jaekel 
6796a6a51eeSAndreas Jaekel 		snprintf(buf, sizeof(buf),
6806a6a51eeSAndreas Jaekel 		         "/devices/pseudo/zev@0:%s", aq.zev_name);
681add9520fSAndreas Jaekel 		q_fd = open(buf, O_RDONLY);
682add9520fSAndreas Jaekel 		if (q_fd < 0) {
683add9520fSAndreas Jaekel 			perror("opening queue device failed");
684add9520fSAndreas Jaekel 			return (EXIT_FAILURE);
685add9520fSAndreas Jaekel 		}
6866a6a51eeSAndreas Jaekel 	} else {
6876a6a51eeSAndreas Jaekel 		q_fd = fd;
6886a6a51eeSAndreas Jaekel 	}
689add9520fSAndreas Jaekel 
690a18c35b9SAndreas Jaekel 	while (1) {
691add9520fSAndreas Jaekel 		pfd[0].fd = q_fd;
692a18c35b9SAndreas Jaekel 		pfd[0].events = POLLIN;
693a18c35b9SAndreas Jaekel 		ret = poll(pfd, 1, 1000);
694a18c35b9SAndreas Jaekel 		if (ret < 0) {
695a18c35b9SAndreas Jaekel 			perror("poll failed");
6966a6a51eeSAndreas Jaekel 			close(q_fd);
697add9520fSAndreas Jaekel 			return(EXIT_FAILURE);
698a18c35b9SAndreas Jaekel 		}
699a18c35b9SAndreas Jaekel 		if (!(pfd[0].revents & POLLIN))
700a18c35b9SAndreas Jaekel 			continue;
701a18c35b9SAndreas Jaekel 		/* data available */
702add9520fSAndreas Jaekel 		ret = read(q_fd, buf, sizeof(buf));
703a18c35b9SAndreas Jaekel 		if (ret < 0) {
704a18c35b9SAndreas Jaekel 			perror("read failed");
7056a6a51eeSAndreas Jaekel 			close(q_fd);
706add9520fSAndreas Jaekel 			return(EXIT_FAILURE);
707a18c35b9SAndreas Jaekel 		}
708a18c35b9SAndreas Jaekel 		if (ret == 0)
709a18c35b9SAndreas Jaekel 			continue;
710d979f56cSAndreas Jaekel 		while (ret > off) {
711d979f56cSAndreas Jaekel 			ev = (zev_event_t *)(buf + off);
712d979f56cSAndreas Jaekel 			zev_print_event(buf + off, ev->header.record_len);
713d979f56cSAndreas Jaekel 			off += ev->header.record_len;
714d979f56cSAndreas Jaekel 		}
715149d0affSAndreas Jaekel 		off = 0;
716a18c35b9SAndreas Jaekel 	}
7176a6a51eeSAndreas Jaekel 	if (create_tmp_queue)
718add9520fSAndreas Jaekel 		close(q_fd);
719add9520fSAndreas Jaekel 	return EXIT_SUCCESS;
720a18c35b9SAndreas Jaekel }
721a18c35b9SAndreas Jaekel 
722*35526fb3SArne Jansen static int
723*35526fb3SArne Jansen zev_dump_spool(int fd)
724*35526fb3SArne Jansen {
725*35526fb3SArne Jansen 	int len;
726*35526fb3SArne Jansen 	char buf[4096];
727*35526fb3SArne Jansen 	int off = 0;
728*35526fb3SArne Jansen 
729*35526fb3SArne Jansen 	while (1) {
730*35526fb3SArne Jansen 		len = read(fd, buf + off, sizeof(buf) - off);
731*35526fb3SArne Jansen 		if (len == -1) {
732*35526fb3SArne Jansen 			fprintf(stderr, "reading from spool failed: %s\n",
733*35526fb3SArne Jansen 				strerror(errno));
734*35526fb3SArne Jansen 			return EXIT_FAILURE;
735*35526fb3SArne Jansen 		}
736*35526fb3SArne Jansen 		if (len == 0)
737*35526fb3SArne Jansen 			break;
738*35526fb3SArne Jansen 
739*35526fb3SArne Jansen 		len += off;
740*35526fb3SArne Jansen 		off = 0;
741*35526fb3SArne Jansen 		while (len > off + sizeof(uint32_t)) {
742*35526fb3SArne Jansen 			uint32_t evlen;
743*35526fb3SArne Jansen 			char *mp;
744*35526fb3SArne Jansen 			zev_event_t *ev;
745*35526fb3SArne Jansen 
746*35526fb3SArne Jansen 			ev = (zev_event_t *)(buf + off);
747*35526fb3SArne Jansen 			evlen = ev->header.record_len;
748*35526fb3SArne Jansen 			if (len < off + evlen + 1)
749*35526fb3SArne Jansen 				break;
750*35526fb3SArne Jansen 			mp = buf + off + evlen;
751*35526fb3SArne Jansen 			if (!memchr(mp, 0, len - off - evlen))
752*35526fb3SArne Jansen 				break;
753*35526fb3SArne Jansen 			zev_print_event(buf + off, ev->header.record_len);
754*35526fb3SArne Jansen 			off += ev->header.record_len + strlen(mp) + 1;
755*35526fb3SArne Jansen 		}
756*35526fb3SArne Jansen 
757*35526fb3SArne Jansen 		memmove(buf, buf + off, len - off);
758*35526fb3SArne Jansen 		off = len - off;
759*35526fb3SArne Jansen 	}
760*35526fb3SArne Jansen 
761*35526fb3SArne Jansen 	return EXIT_SUCCESS;
762*35526fb3SArne Jansen }
763*35526fb3SArne Jansen 
764a18c35b9SAndreas Jaekel static void
765a18c35b9SAndreas Jaekel usage(char *progname)
766a18c35b9SAndreas Jaekel {
767add9520fSAndreas Jaekel 	fprintf(stderr, "usage: %s [-d <dev>] [options]\n", progname);
768add9520fSAndreas Jaekel 	fprintf(stderr, "\n");
769add9520fSAndreas Jaekel 	fprintf(stderr, " Status information:\n");
770a18c35b9SAndreas Jaekel 	fprintf(stderr, "   -s                   show zev statistics\n");
771a18c35b9SAndreas Jaekel 	fprintf(stderr, "   -p                   poll for ZFS events\n");
772*35526fb3SArne Jansen 	fprintf(stderr, "   -f <name>            dump events from spool\n");
773add9520fSAndreas Jaekel 	fprintf(stderr, "   -D                   print zev module debug "
774add9520fSAndreas Jaekel 	        "information\n");
775b690436dSAndreas Jaekel 	fprintf(stderr, "   -T <interval> <cnt>  zevstat mode\n");
776f432e238SAndreas Jaekel 	fprintf(stderr, "   -R <base filename>   zevreport mode\n");
777add9520fSAndreas Jaekel 	fprintf(stderr, "\n");
778add9520fSAndreas Jaekel 	fprintf(stderr, " Tune zev module settings:\n");
779add9520fSAndreas Jaekel 	fprintf(stderr, "   -Q <bytes>           set maximum event queue "
780add9520fSAndreas Jaekel 	        "length\n");
781add9520fSAndreas Jaekel 	fprintf(stderr, "   -m <pool>            mute pool, no events for "
782add9520fSAndreas Jaekel 	        "this pool\n");
783a18c35b9SAndreas Jaekel 	fprintf(stderr, "   -M <pool>            unmute pool\n");
784add9520fSAndreas Jaekel 	fprintf(stderr, "\n");
785add9520fSAndreas Jaekel 	fprintf(stderr, " Queue management:\n");
786add9520fSAndreas Jaekel 	fprintf(stderr, "   -l                   list queues\n");
7876a6a51eeSAndreas Jaekel 	fprintf(stderr, "   -a <name>            add non-blocking queue\n");
7886a6a51eeSAndreas Jaekel 	fprintf(stderr, "   -A <name>            add blocking queue\n");
789add9520fSAndreas Jaekel 	fprintf(stderr, "   -r <name>            remove queue\n");
790add9520fSAndreas Jaekel 	fprintf(stderr, "   -b <name>            make queue non-blocking "
791add9520fSAndreas Jaekel 	        "(default)\n");
792add9520fSAndreas Jaekel 	fprintf(stderr, "   -B <name>            make queue block when full\n");
793add9520fSAndreas Jaekel 	fprintf(stderr, "   -P <name>            display queue properties\n");
7946a6a51eeSAndreas Jaekel 	fprintf(stderr, "   -L <name> <bytes>    set maximum event queue "
795add9520fSAndreas Jaekel 	        "length\n");
796add9520fSAndreas Jaekel 	fprintf(stderr, "   -t <name> <bytes>    set queue length poll "
797add9520fSAndreas Jaekel 	        "throttle\n");
798add9520fSAndreas Jaekel 	fprintf(stderr, "\n");
799add9520fSAndreas Jaekel 	fprintf(stderr, " Other options:\n");
800add9520fSAndreas Jaekel 	fprintf(stderr, "   -d <dev>             non-default device file. "
801add9520fSAndreas Jaekel 	        "('%s')\n", ZEV_DEVICE);
8026a6a51eeSAndreas Jaekel 	fprintf(stderr, "   -q <name>            use device file for this "
8036a6a51eeSAndreas Jaekel 		"queue name\n");
804888fea18SAndreas Jaekel 	fprintf(stderr, "   -k <guid>:<payload>  queue mark event\n");
80542110aacSAndreas Jaekel 	fprintf(stderr, "   -c <filename>        list file's content "
80642110aacSAndreas Jaekel 		"checksums\n");
80716ff6b2fSAndreas Jaekel 	fprintf(stderr, "   -v                   verbose: additional output "
808205ed6bfSAndreas Jaekel 	        "for some operations\n");
80916ff6b2fSAndreas Jaekel 	fprintf(stderr, "   -g                   grep-friendly event output, "
81016ff6b2fSAndreas Jaekel 	        "one event per line\n");
811a18c35b9SAndreas Jaekel 	exit (EXIT_FAILURE);
812a18c35b9SAndreas Jaekel }
813a18c35b9SAndreas Jaekel 
81450da9edeSAndreas Jaekel static void
81550da9edeSAndreas Jaekel zevstat_usage(char *progname)
81650da9edeSAndreas Jaekel {
81750da9edeSAndreas Jaekel 	fprintf(stderr, "usage: %s [-v] <interval> [count]\n", progname);
81850da9edeSAndreas Jaekel 	fprintf(stderr, "   -v   verbose, show counters for all event types\n");
81950da9edeSAndreas Jaekel 	exit (EXIT_FAILURE);
82050da9edeSAndreas Jaekel }
82150da9edeSAndreas Jaekel 
822f432e238SAndreas Jaekel static void
823f432e238SAndreas Jaekel zevreport_usage(char *progname)
824f432e238SAndreas Jaekel {
825f432e238SAndreas Jaekel 	fprintf(stderr, "usage: %s <output base filename>\n", progname);
826f432e238SAndreas Jaekel 	exit (EXIT_FAILURE);
827f432e238SAndreas Jaekel }
828f432e238SAndreas Jaekel 
829a18c35b9SAndreas Jaekel static int
8306a6a51eeSAndreas Jaekel zev_add_queue(int fd, char *arg, int blocking)
831a18c35b9SAndreas Jaekel {
832add9520fSAndreas Jaekel 	zev_ioctl_add_queue_t aq;
833add9520fSAndreas Jaekel 	int namelen;
834a18c35b9SAndreas Jaekel 
835add9520fSAndreas Jaekel 	namelen = strlen(arg);
836add9520fSAndreas Jaekel 	if (namelen > ZEV_MAX_QUEUE_NAME_LEN) {
837add9520fSAndreas Jaekel 		fprintf(stderr, "queue name too long: %s\n", arg);
838a18c35b9SAndreas Jaekel 		return (EXIT_FAILURE);
839a18c35b9SAndreas Jaekel 	}
840add9520fSAndreas Jaekel 
841add9520fSAndreas Jaekel 	aq.zev_namelen = namelen;
842add9520fSAndreas Jaekel 	strcpy(aq.zev_name, arg);
843c99a1a25SAndreas Jaekel 	aq.zev_flags = ZEV_FL_PERSISTENT | ZEV_FL_INITIALLY_EMPTY;
8446a6a51eeSAndreas Jaekel 	if (blocking) {
8456a6a51eeSAndreas Jaekel 		aq.zev_flags |= ZEV_FL_BLOCK_WHILE_QUEUE_FULL;
8466a6a51eeSAndreas Jaekel 		aq.zev_max_queue_len = ZEV_MAX_QUEUE_LEN;
8476a6a51eeSAndreas Jaekel 	} else {
848add9520fSAndreas Jaekel 		aq.zev_max_queue_len = (1024 * 1024);
8496a6a51eeSAndreas Jaekel 	}
850add9520fSAndreas Jaekel 
851add9520fSAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_ADD_QUEUE, &aq)) {
852add9520fSAndreas Jaekel 		perror("adding queue failed");
853a18c35b9SAndreas Jaekel 		return (EXIT_FAILURE);
854a18c35b9SAndreas Jaekel 	}
855a18c35b9SAndreas Jaekel 	return (0);
856a18c35b9SAndreas Jaekel }
857a18c35b9SAndreas Jaekel 
858a18c35b9SAndreas Jaekel static int
859add9520fSAndreas Jaekel zev_remove_queue(int fd, char *arg)
860fec460f8SAndreas Jaekel {
861add9520fSAndreas Jaekel 	zev_ioctl_remove_queue_t aq;
862add9520fSAndreas Jaekel 	int namelen;
863fec460f8SAndreas Jaekel 
864add9520fSAndreas Jaekel 	namelen = strlen(arg);
865add9520fSAndreas Jaekel 	if (namelen > ZEV_MAX_QUEUE_NAME_LEN) {
866add9520fSAndreas Jaekel 		fprintf(stderr, "queue name too long: %s\n", arg);
867fec460f8SAndreas Jaekel 		return (EXIT_FAILURE);
868fec460f8SAndreas Jaekel 	}
869add9520fSAndreas Jaekel 
8706a6a51eeSAndreas Jaekel 	aq.zev_queue_name.zev_namelen = namelen;
8716a6a51eeSAndreas Jaekel 	strcpy(aq.zev_queue_name.zev_name, arg);
872add9520fSAndreas Jaekel 
873add9520fSAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_REMOVE_QUEUE, &aq)) {
874add9520fSAndreas Jaekel 		perror("removing queue failed");
875add9520fSAndreas Jaekel 		return (EXIT_FAILURE);
876add9520fSAndreas Jaekel 	}
877add9520fSAndreas Jaekel 	return (0);
878add9520fSAndreas Jaekel }
879add9520fSAndreas Jaekel 
880add9520fSAndreas Jaekel static int
881add9520fSAndreas Jaekel zev_set_global_max_queue_len(int fd, char *arg)
882add9520fSAndreas Jaekel {
883add9520fSAndreas Jaekel 	uint64_t maxqueuelen;
884add9520fSAndreas Jaekel 
885174dc952SAndreas Jaekel 	if (!arg) {
886174dc952SAndreas Jaekel 		fprintf(stderr, "missing queue length parameter\n");
887174dc952SAndreas Jaekel 		return (EXIT_FAILURE);
888174dc952SAndreas Jaekel 	}
889174dc952SAndreas Jaekel 
890add9520fSAndreas Jaekel 	errno = 0;
891add9520fSAndreas Jaekel 	maxqueuelen = strtol(arg, (char **)NULL, 10);
892add9520fSAndreas Jaekel 	if (errno) {
893add9520fSAndreas Jaekel 		fprintf(stderr, "invalid queue length parameter: %s\n", arg);
894add9520fSAndreas Jaekel 		return (EXIT_FAILURE);
895add9520fSAndreas Jaekel 	}
896add9520fSAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_SET_MAX_QUEUE_LEN, &maxqueuelen)) {
897add9520fSAndreas Jaekel 		perror("setting max queue length failed");
898fec460f8SAndreas Jaekel 		return (EXIT_FAILURE);
899fec460f8SAndreas Jaekel 	}
900fec460f8SAndreas Jaekel 	return (0);
901fec460f8SAndreas Jaekel }
902fec460f8SAndreas Jaekel 
903fec460f8SAndreas Jaekel static int
904a18c35b9SAndreas Jaekel zev_mute_unmute_impl(int fd, char *poolname, int mute)
905a18c35b9SAndreas Jaekel {
906a18c35b9SAndreas Jaekel 	zev_ioctl_poolarg_t pa;
907a18c35b9SAndreas Jaekel 	int len;
908a18c35b9SAndreas Jaekel 	int op = mute ? ZEV_IOC_MUTE_POOL : ZEV_IOC_UNMUTE_POOL;
909a18c35b9SAndreas Jaekel 	len = strlen(poolname);
910a18c35b9SAndreas Jaekel 	if (len <= 0 || len >= sizeof(pa.zev_poolname)) {
911a18c35b9SAndreas Jaekel 		fprintf(stderr, "invalid poolname: %s\n", poolname);
912a18c35b9SAndreas Jaekel 		return (EXIT_FAILURE);
913a18c35b9SAndreas Jaekel 	}
914a18c35b9SAndreas Jaekel 	strcpy(pa.zev_poolname, poolname);
915a18c35b9SAndreas Jaekel 	pa.zev_poolname_len = len;
916a18c35b9SAndreas Jaekel 	if (ioctl(fd, op, &pa)) {
917a18c35b9SAndreas Jaekel 		perror("muting pool data failed");
918a18c35b9SAndreas Jaekel 		return (EXIT_FAILURE);
919a18c35b9SAndreas Jaekel 	}
920a18c35b9SAndreas Jaekel 	return (0);
921a18c35b9SAndreas Jaekel }
922a18c35b9SAndreas Jaekel 
923a18c35b9SAndreas Jaekel int
924a18c35b9SAndreas Jaekel zev_mute_pool(int fd, char *poolname)
925a18c35b9SAndreas Jaekel {
926a18c35b9SAndreas Jaekel 	return zev_mute_unmute_impl(fd, poolname, 1);
927a18c35b9SAndreas Jaekel }
928a18c35b9SAndreas Jaekel 
929a18c35b9SAndreas Jaekel int
930a18c35b9SAndreas Jaekel zev_unmute_pool(int fd, char *poolname)
931a18c35b9SAndreas Jaekel {
932a18c35b9SAndreas Jaekel 	return zev_mute_unmute_impl(fd, poolname, 0);
933a18c35b9SAndreas Jaekel }
934a18c35b9SAndreas Jaekel 
935888fea18SAndreas Jaekel static int
936add9520fSAndreas Jaekel zev_debug_info(int fd)
937add9520fSAndreas Jaekel {
938add9520fSAndreas Jaekel 	zev_ioctl_debug_info_t di;
939add9520fSAndreas Jaekel 
940add9520fSAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_GET_DEBUG_INFO, &di)) {
941add9520fSAndreas Jaekel 		perror("getting zev debug info failed");
942add9520fSAndreas Jaekel 		return (EXIT_FAILURE);
943add9520fSAndreas Jaekel 	}
944add9520fSAndreas Jaekel 
945add9520fSAndreas Jaekel 	printf("memory allocated: %llu bytes\n", di.zev_memory_allocated);
946205ed6bfSAndreas Jaekel 	printf("checksum cache size: %llu\n", di.zev_chksum_cache_size);
947205ed6bfSAndreas Jaekel 	printf("checksum cache hits: %llu\n", di.zev_chksum_cache_hits);
948205ed6bfSAndreas Jaekel 	printf("checksum cache misses: %llu\n", di.zev_chksum_cache_misses);
949add9520fSAndreas Jaekel 	return 0;
950add9520fSAndreas Jaekel }
951add9520fSAndreas Jaekel 
952add9520fSAndreas Jaekel static int
953888fea18SAndreas Jaekel zev_mark(int fd, char *arg)
954888fea18SAndreas Jaekel {
955888fea18SAndreas Jaekel 	zev_ioctl_mark_t *mark;
956888fea18SAndreas Jaekel 	uint64_t guid;
957888fea18SAndreas Jaekel 	int len;
958888fea18SAndreas Jaekel 	char *p;
959888fea18SAndreas Jaekel 
960888fea18SAndreas Jaekel 	p = strchr(arg, ':');
961888fea18SAndreas Jaekel 	if (!p) {
962888fea18SAndreas Jaekel 		fprintf(stderr, "expected value is <guid>:<payload>, "
963888fea18SAndreas Jaekel 		        "e.g. '123:hello'\n");
964888fea18SAndreas Jaekel 		exit (EXIT_FAILURE);
965888fea18SAndreas Jaekel 	}
966888fea18SAndreas Jaekel 	*p = '\n';
967888fea18SAndreas Jaekel 	p++;
968888fea18SAndreas Jaekel 
969888fea18SAndreas Jaekel 	errno = 0;
970add9520fSAndreas Jaekel 	guid = strtoll(arg, (char **)NULL, 10);
971888fea18SAndreas Jaekel 	if (errno) {
972888fea18SAndreas Jaekel 		fprintf(stderr, "guid must be a number.\n");
973888fea18SAndreas Jaekel 		exit (EXIT_FAILURE);
974888fea18SAndreas Jaekel 	}
975888fea18SAndreas Jaekel 
976888fea18SAndreas Jaekel 	len = strlen(p);
977888fea18SAndreas Jaekel 
978888fea18SAndreas Jaekel 	mark = malloc(sizeof(*mark) + len + 1);
979888fea18SAndreas Jaekel 	if (!mark) {
980888fea18SAndreas Jaekel 		fprintf(stderr, "can't allocate mark structure: %s\n",
981888fea18SAndreas Jaekel 		        strerror(errno));
982888fea18SAndreas Jaekel 		exit (EXIT_FAILURE);
983888fea18SAndreas Jaekel 	}
984888fea18SAndreas Jaekel 	mark->zev_guid = guid;
985888fea18SAndreas Jaekel 	mark->zev_mark_id = 0;
986888fea18SAndreas Jaekel 	mark->zev_payload_len = len;
987888fea18SAndreas Jaekel 	strcpy(ZEV_PAYLOAD(mark), p);
988888fea18SAndreas Jaekel 
989888fea18SAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_MARK, mark)) {
990888fea18SAndreas Jaekel 		perror("queueing mark failed");
991888fea18SAndreas Jaekel 		return (EXIT_FAILURE);
992888fea18SAndreas Jaekel 	}
993888fea18SAndreas Jaekel 
994888fea18SAndreas Jaekel 	printf("mark id: %lu\n", mark->zev_mark_id);
995888fea18SAndreas Jaekel 	return (0);
996888fea18SAndreas Jaekel }
997888fea18SAndreas Jaekel 
998add9520fSAndreas Jaekel static int
999add9520fSAndreas Jaekel zev_queue_blocking(int fd, char *arg, int block)
1000add9520fSAndreas Jaekel {
1001add9520fSAndreas Jaekel 	zev_ioctl_get_queue_properties_t gqp;
1002add9520fSAndreas Jaekel 
10036a6a51eeSAndreas Jaekel 	gqp.zev_queue_name.zev_namelen = strlen(arg);
10046a6a51eeSAndreas Jaekel 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
1005add9520fSAndreas Jaekel 		fprintf(stderr, "queue name too long.\n");
1006add9520fSAndreas Jaekel 		return EXIT_FAILURE;
1007add9520fSAndreas Jaekel 	}
10086a6a51eeSAndreas Jaekel 	strcpy(gqp.zev_queue_name.zev_name, arg);
1009add9520fSAndreas Jaekel 
1010add9520fSAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
1011add9520fSAndreas Jaekel 		perror("getting queue properties failed");
1012add9520fSAndreas Jaekel 		return (EXIT_FAILURE);
1013add9520fSAndreas Jaekel 	}
1014add9520fSAndreas Jaekel 	if (block) {
1015add9520fSAndreas Jaekel 		gqp.zev_flags |= ZEV_FL_BLOCK_WHILE_QUEUE_FULL;
1016add9520fSAndreas Jaekel 	} else {
1017add9520fSAndreas Jaekel 		gqp.zev_flags &= ~ZEV_FL_BLOCK_WHILE_QUEUE_FULL;
1018add9520fSAndreas Jaekel 	}
1019add9520fSAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) {
1020add9520fSAndreas Jaekel 		perror("setting queue properties failed");
1021add9520fSAndreas Jaekel 		return (EXIT_FAILURE);
1022add9520fSAndreas Jaekel 	}
1023add9520fSAndreas Jaekel 	return (0);
1024add9520fSAndreas Jaekel }
1025add9520fSAndreas Jaekel 
1026add9520fSAndreas Jaekel static int
1027add9520fSAndreas Jaekel zev_set_max_queue_len(int fd, char *arg, char *len)
1028add9520fSAndreas Jaekel {
1029add9520fSAndreas Jaekel 	zev_ioctl_get_queue_properties_t gqp;
1030add9520fSAndreas Jaekel 
1031add9520fSAndreas Jaekel 	if (!len) {
1032add9520fSAndreas Jaekel 		fprintf(stderr, "queue size parameter missing.\n");
1033add9520fSAndreas Jaekel 		return EXIT_FAILURE;
1034add9520fSAndreas Jaekel 	}
1035add9520fSAndreas Jaekel 
10366a6a51eeSAndreas Jaekel 	gqp.zev_queue_name.zev_namelen = strlen(arg);
10376a6a51eeSAndreas Jaekel 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
1038add9520fSAndreas Jaekel 		fprintf(stderr, "queue name too long.\n");
1039add9520fSAndreas Jaekel 		return EXIT_FAILURE;
1040add9520fSAndreas Jaekel 	}
10416a6a51eeSAndreas Jaekel 	strcpy(gqp.zev_queue_name.zev_name, arg);
1042add9520fSAndreas Jaekel 
1043add9520fSAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
1044add9520fSAndreas Jaekel 		perror("getting queue properties failed");
1045add9520fSAndreas Jaekel 		return (EXIT_FAILURE);
1046add9520fSAndreas Jaekel 	}
1047add9520fSAndreas Jaekel 	gqp.zev_max_queue_len = atol(len);
1048add9520fSAndreas Jaekel 	if (gqp.zev_max_queue_len == 0 && strcmp("0", len)) {
1049add9520fSAndreas Jaekel 		fprintf(stderr, "queue size parameter garbled.\n");
1050add9520fSAndreas Jaekel 		return (EXIT_FAILURE);
1051add9520fSAndreas Jaekel 	}
1052add9520fSAndreas Jaekel 	if (gqp.zev_max_queue_len > ZEV_MAX_QUEUE_LEN) {
1053add9520fSAndreas Jaekel 		fprintf(stderr, "queue size parameter out of bounds.\n");
1054add9520fSAndreas Jaekel 		return (EXIT_FAILURE);
1055add9520fSAndreas Jaekel 	}
1056add9520fSAndreas Jaekel 
1057add9520fSAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) {
1058add9520fSAndreas Jaekel 		perror("setting queue properties failed");
1059add9520fSAndreas Jaekel 		return (EXIT_FAILURE);
1060add9520fSAndreas Jaekel 	}
1061add9520fSAndreas Jaekel 	return (0);
1062add9520fSAndreas Jaekel }
1063add9520fSAndreas Jaekel 
1064add9520fSAndreas Jaekel static int
1065add9520fSAndreas Jaekel zev_set_poll_wakeup_queue_len(int fd, char *arg, char *len)
1066add9520fSAndreas Jaekel {
1067add9520fSAndreas Jaekel 	zev_ioctl_get_queue_properties_t gqp;
1068add9520fSAndreas Jaekel 
1069add9520fSAndreas Jaekel 	if (!len) {
1070add9520fSAndreas Jaekel 		fprintf(stderr, "poll throttle parameter missing.\n");
1071add9520fSAndreas Jaekel 		return EXIT_FAILURE;
1072add9520fSAndreas Jaekel 	}
1073add9520fSAndreas Jaekel 
10746a6a51eeSAndreas Jaekel 	gqp.zev_queue_name.zev_namelen = strlen(arg);
10756a6a51eeSAndreas Jaekel 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
1076add9520fSAndreas Jaekel 		fprintf(stderr, "queue name too long.\n");
1077add9520fSAndreas Jaekel 		return EXIT_FAILURE;
1078add9520fSAndreas Jaekel 	}
10796a6a51eeSAndreas Jaekel 	strcpy(gqp.zev_queue_name.zev_name, arg);
1080add9520fSAndreas Jaekel 
1081add9520fSAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
1082add9520fSAndreas Jaekel 		perror("getting queue properties failed");
1083add9520fSAndreas Jaekel 		return (EXIT_FAILURE);
1084add9520fSAndreas Jaekel 	}
1085add9520fSAndreas Jaekel 	gqp.zev_poll_wakeup_threshold = atol(len);
1086add9520fSAndreas Jaekel 	if (gqp.zev_poll_wakeup_threshold == 0 && strcmp("0", len)) {
1087add9520fSAndreas Jaekel 		fprintf(stderr, "poll throttle parameter garbled.\n");
1088add9520fSAndreas Jaekel 		return (EXIT_FAILURE);
1089add9520fSAndreas Jaekel 	}
10906a6a51eeSAndreas Jaekel 	if (gqp.zev_poll_wakeup_threshold > ZEV_MAX_POLL_WAKEUP_QUEUE_LEN) {
1091add9520fSAndreas Jaekel 		fprintf(stderr, "poll throttle parameter out of bounds.\n");
1092add9520fSAndreas Jaekel 		return (EXIT_FAILURE);
1093add9520fSAndreas Jaekel 	}
1094add9520fSAndreas Jaekel 
1095add9520fSAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) {
1096add9520fSAndreas Jaekel 		perror("setting queue properties failed");
1097add9520fSAndreas Jaekel 		return (EXIT_FAILURE);
1098add9520fSAndreas Jaekel 	}
1099add9520fSAndreas Jaekel 	return (0);
1100add9520fSAndreas Jaekel }
1101add9520fSAndreas Jaekel 
1102add9520fSAndreas Jaekel static int
1103add9520fSAndreas Jaekel zev_queue_properties(int fd, char *arg)
1104add9520fSAndreas Jaekel {
1105add9520fSAndreas Jaekel 	zev_ioctl_get_queue_properties_t gqp;
1106add9520fSAndreas Jaekel 
11076a6a51eeSAndreas Jaekel 	gqp.zev_queue_name.zev_namelen = strlen(arg);
11086a6a51eeSAndreas Jaekel 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
1109add9520fSAndreas Jaekel 		fprintf(stderr, "queue name too long.\n");
1110add9520fSAndreas Jaekel 		return EXIT_FAILURE;
1111add9520fSAndreas Jaekel 	}
11126a6a51eeSAndreas Jaekel 	strcpy(gqp.zev_queue_name.zev_name, arg);
1113add9520fSAndreas Jaekel 
1114add9520fSAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
1115add9520fSAndreas Jaekel 		perror("getting queue properties failed");
1116add9520fSAndreas Jaekel 		return (EXIT_FAILURE);
1117add9520fSAndreas Jaekel 	}
1118add9520fSAndreas Jaekel 
1119add9520fSAndreas Jaekel 	printf("queue        : %s\n", arg);
1120add9520fSAndreas Jaekel 	printf("max size     : %" PRIu64 "\n", gqp.zev_max_queue_len);
1121add9520fSAndreas Jaekel 	printf("poll throttle: %" PRIu64 "\n", gqp.zev_poll_wakeup_threshold);
1122add9520fSAndreas Jaekel 	printf("persistent   : %s\n",
1123add9520fSAndreas Jaekel 		gqp.zev_flags & ZEV_FL_PERSISTENT ? "yes" : "no");
1124add9520fSAndreas Jaekel 	printf("blocking     : %s\n",
1125add9520fSAndreas Jaekel 		gqp.zev_flags & ZEV_FL_BLOCK_WHILE_QUEUE_FULL ? "yes" : "no");
1126add9520fSAndreas Jaekel 
1127add9520fSAndreas Jaekel 	return (0);
1128add9520fSAndreas Jaekel }
1129add9520fSAndreas Jaekel 
1130add9520fSAndreas Jaekel static int
1131add9520fSAndreas Jaekel zev_list_queues(int fd)
1132add9520fSAndreas Jaekel {
1133add9520fSAndreas Jaekel 	zev_ioctl_get_queue_properties_t gqp;
1134add9520fSAndreas Jaekel 	zev_ioctl_get_queue_list_t gql;
1135add9520fSAndreas Jaekel 	zev_ioctl_get_queue_statistics_t gs;
1136add9520fSAndreas Jaekel 	uint64_t	i;
1137add9520fSAndreas Jaekel 	char		name[ZEV_MAX_QUEUE_NAME_LEN+1];
1138add9520fSAndreas Jaekel 
1139add9520fSAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_LIST, &gql)) {
1140add9520fSAndreas Jaekel 		perror("getting queue list failed");
1141add9520fSAndreas Jaekel 		return (EXIT_FAILURE);
1142add9520fSAndreas Jaekel 	}
1143add9520fSAndreas Jaekel 
1144add9520fSAndreas Jaekel 	printf("Name                                     Size       "
1145add9520fSAndreas Jaekel 	       "Max Size   Wakeup Per Block\n");
1146add9520fSAndreas Jaekel 
1147add9520fSAndreas Jaekel 	for (i=0; i<gql.zev_n_queues; i++) {
1148add9520fSAndreas Jaekel 		strncpy(name, gql.zev_queue_name[i].zev_name,
1149add9520fSAndreas Jaekel 		        ZEV_MAX_QUEUE_NAME_LEN);
1150add9520fSAndreas Jaekel 		name[gql.zev_queue_name[i].zev_namelen] = '\0';
1151add9520fSAndreas Jaekel 
11526a6a51eeSAndreas Jaekel 		memcpy(gqp.zev_queue_name.zev_name,
11536a6a51eeSAndreas Jaekel 		    gql.zev_queue_name[i].zev_name, ZEV_MAX_QUEUE_NAME_LEN);
11546a6a51eeSAndreas Jaekel 		gqp.zev_queue_name.zev_namelen =
11556a6a51eeSAndreas Jaekel 		    gql.zev_queue_name[i].zev_namelen;
1156add9520fSAndreas Jaekel 
1157add9520fSAndreas Jaekel 		if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
1158add9520fSAndreas Jaekel 			if (errno == ENOENT)
1159add9520fSAndreas Jaekel 				continue;
1160add9520fSAndreas Jaekel 			perror("getting queue properties failed");
1161add9520fSAndreas Jaekel 			return (EXIT_FAILURE);
1162add9520fSAndreas Jaekel 		}
1163add9520fSAndreas Jaekel 
11646a6a51eeSAndreas Jaekel 		memcpy(gs.zev_queue_name.zev_name,
11656a6a51eeSAndreas Jaekel 		    gql.zev_queue_name[i].zev_name, ZEV_MAX_QUEUE_NAME_LEN);
11666a6a51eeSAndreas Jaekel 		gs.zev_queue_name.zev_namelen =
11676a6a51eeSAndreas Jaekel 		    gql.zev_queue_name[i].zev_namelen;
1168add9520fSAndreas Jaekel 
1169add9520fSAndreas Jaekel 		if (ioctl(fd, ZEV_IOC_GET_QUEUE_STATISTICS, &gs)) {
1170add9520fSAndreas Jaekel 			if (errno == ENOENT)
1171add9520fSAndreas Jaekel 				continue;
1172add9520fSAndreas Jaekel 			perror("getting statistics data failed");
1173add9520fSAndreas Jaekel 			return (EXIT_FAILURE);
1174add9520fSAndreas Jaekel 		}
1175add9520fSAndreas Jaekel 
1176add9520fSAndreas Jaekel 		printf("%-40s %-10" PRIu64 " %-10" PRIu64 " %-6" PRIu64
1177add9520fSAndreas Jaekel 		       " %-3s %-3s\n",
1178add9520fSAndreas Jaekel 			name,
1179add9520fSAndreas Jaekel 			gs.zev_statistics.zev_queue_len,
1180add9520fSAndreas Jaekel 			gqp.zev_max_queue_len,
1181add9520fSAndreas Jaekel 			gqp.zev_poll_wakeup_threshold,
1182add9520fSAndreas Jaekel 			gqp.zev_flags & ZEV_FL_PERSISTENT ? "yes" : "no",
1183add9520fSAndreas Jaekel 			gqp.zev_flags & ZEV_FL_BLOCK_WHILE_QUEUE_FULL ?
1184add9520fSAndreas Jaekel 				 "yes" : "no");
1185add9520fSAndreas Jaekel 	}
1186add9520fSAndreas Jaekel 
1187add9520fSAndreas Jaekel 	return (0);
1188add9520fSAndreas Jaekel }
1189add9520fSAndreas Jaekel 
119042110aacSAndreas Jaekel static int
119142110aacSAndreas Jaekel zev_checksum(int dev_fd, char *filename)
119242110aacSAndreas Jaekel {
119342110aacSAndreas Jaekel 	int fd;
119442110aacSAndreas Jaekel 	offset_t off;
119542110aacSAndreas Jaekel 	offset_t data;
119642110aacSAndreas Jaekel 	zev_sig_t *sig;
119742110aacSAndreas Jaekel 	char *buf;
119842110aacSAndreas Jaekel 	zev_ioctl_get_signatures_t *gs;
119942110aacSAndreas Jaekel 	int i;
120042110aacSAndreas Jaekel 	char sigval[(SHA1_DIGEST_LENGTH * 2) + 1];
120142110aacSAndreas Jaekel 	int buf_size;
120242110aacSAndreas Jaekel 
120342110aacSAndreas Jaekel 	/* control struct, one lv1 signature and up to 256 lv0 signatures */
120442110aacSAndreas Jaekel 	buf_size = (1 + 256) * sizeof(zev_sig_t);
120542110aacSAndreas Jaekel 	buf = malloc(sizeof(zev_ioctl_get_signatures_t) + buf_size);
120642110aacSAndreas Jaekel 	if (!buf) {
120742110aacSAndreas Jaekel 		perror("can't allocate checksum buffer");
120842110aacSAndreas Jaekel 		return (EXIT_FAILURE);
120942110aacSAndreas Jaekel 	}
121042110aacSAndreas Jaekel 
121142110aacSAndreas Jaekel 	fd = open(filename, O_RDONLY);
121242110aacSAndreas Jaekel 	if (fd < 0) {
121342110aacSAndreas Jaekel 		perror("can't open file");
121442110aacSAndreas Jaekel 		return (EXIT_FAILURE);
121542110aacSAndreas Jaekel 	}
121642110aacSAndreas Jaekel 
121742110aacSAndreas Jaekel 	gs = (zev_ioctl_get_signatures_t *)buf;
121842110aacSAndreas Jaekel 	gs->zev_fd = fd;
121942110aacSAndreas Jaekel 	gs->zev_bufsize = buf_size;
122042110aacSAndreas Jaekel 
122142110aacSAndreas Jaekel 	off = 0;
122242110aacSAndreas Jaekel 	data = 0;
122342110aacSAndreas Jaekel 	while (1) {
122442110aacSAndreas Jaekel 		errno = 0;
122542110aacSAndreas Jaekel 		data = llseek(fd, off, SEEK_DATA);
122642110aacSAndreas Jaekel 		if (data < 0) {
122742110aacSAndreas Jaekel 			if (errno == ENXIO)	/* no more data */
122842110aacSAndreas Jaekel 				break;
122942110aacSAndreas Jaekel 			perror("llseek failed");
123042110aacSAndreas Jaekel 			goto err;
123142110aacSAndreas Jaekel 		}
123242110aacSAndreas Jaekel 		data = P2ALIGN(data, ZEV_L1_SIZE);
123342110aacSAndreas Jaekel 		off = data + ZEV_L1_SIZE;
123442110aacSAndreas Jaekel 
123542110aacSAndreas Jaekel 		gs->zev_offset = data;
123642110aacSAndreas Jaekel 		gs->zev_len = ZEV_L1_SIZE;
123742110aacSAndreas Jaekel 
123842110aacSAndreas Jaekel 		if (ioctl(dev_fd, ZEV_IOC_GET_FILE_SIGNATURES, gs)) {
123942110aacSAndreas Jaekel 			perror("ioctl to get signatures failed");
124042110aacSAndreas Jaekel 			goto err;
124142110aacSAndreas Jaekel 		}
124242110aacSAndreas Jaekel 
124342110aacSAndreas Jaekel 		for (i=0; i<gs->zev_signature_cnt; i++) {
124442110aacSAndreas Jaekel 			sig = (zev_sig_t *)ZEV_SIGNATURES(gs);
124542110aacSAndreas Jaekel 			sig += i;
124642110aacSAndreas Jaekel 			sig2hex_direct(sig->value, sigval);
124742110aacSAndreas Jaekel 			printf("level %d, offset %llu, value %s\n",
124842110aacSAndreas Jaekel 			       sig->level, sig->block_offset, sigval);
124942110aacSAndreas Jaekel 		}
125042110aacSAndreas Jaekel 	}
125142110aacSAndreas Jaekel 
125242110aacSAndreas Jaekel 	free(buf);
125342110aacSAndreas Jaekel 	close(fd);
125442110aacSAndreas Jaekel 	return 0;
125542110aacSAndreas Jaekel err:
125642110aacSAndreas Jaekel 	free(buf);
125742110aacSAndreas Jaekel 	close(fd);
125842110aacSAndreas Jaekel 	return (EXIT_FAILURE);
125942110aacSAndreas Jaekel }
126042110aacSAndreas Jaekel 
1261b690436dSAndreas Jaekel typedef struct zevstat {
1262b690436dSAndreas Jaekel 	uint64_t	ns_start;
1263b690436dSAndreas Jaekel 	uint64_t	events[ZEV_OP_MIN + ZEV_OP_MAX];
1264b690436dSAndreas Jaekel 	uint64_t	guids;
1265b690436dSAndreas Jaekel 	uint64_t	total_events;
1266b690436dSAndreas Jaekel 	uint64_t	total_guids;
1267b690436dSAndreas Jaekel 	avl_tree_t	guids_interval;
1268b690436dSAndreas Jaekel 	avl_tree_t	guids_runtime;
1269b690436dSAndreas Jaekel } zevstat_t;
1270b690436dSAndreas Jaekel 
1271b690436dSAndreas Jaekel typedef struct zev_guidtrack_t {
1272b690436dSAndreas Jaekel 	uint64_t	guid;
1273b690436dSAndreas Jaekel 	avl_node_t	avl_interval;
1274b690436dSAndreas Jaekel 	avl_node_t	avl_runtime;
1275b690436dSAndreas Jaekel } zev_guidtrack_t;
1276b690436dSAndreas Jaekel 
1277b690436dSAndreas Jaekel zevstat_t zevstat;
1278b690436dSAndreas Jaekel 
1279b690436dSAndreas Jaekel static void
1280b690436dSAndreas Jaekel zev_eventstat(char *buf, int len)
1281b690436dSAndreas Jaekel {
1282b690436dSAndreas Jaekel 	zev_header_t *rec = (zev_header_t *)buf;
1283b690436dSAndreas Jaekel 	zev_guidtrack_t *gt;
1284b690436dSAndreas Jaekel 	zev_guidtrack_t *gt_int;
1285b690436dSAndreas Jaekel 	zev_guidtrack_t to_find;
1286b690436dSAndreas Jaekel 	avl_index_t where;
1287b690436dSAndreas Jaekel 
1288b690436dSAndreas Jaekel 	zevstat.total_events++;
1289b690436dSAndreas Jaekel 	zevstat.events[rec->op]++;
1290b690436dSAndreas Jaekel 
1291b690436dSAndreas Jaekel 	to_find.guid = rec->guid;
1292b690436dSAndreas Jaekel 	gt = avl_find(&zevstat.guids_runtime, &to_find, &where);
1293b690436dSAndreas Jaekel 	if (!gt) {
1294b690436dSAndreas Jaekel 		gt = malloc(sizeof(*gt));
1295b690436dSAndreas Jaekel 		if (!gt) {
1296b690436dSAndreas Jaekel 			perror("can't get guid tracking record");
1297b690436dSAndreas Jaekel 			exit (EXIT_FAILURE);
1298b690436dSAndreas Jaekel 		}
1299b690436dSAndreas Jaekel 		gt->guid = rec->guid;
1300b690436dSAndreas Jaekel 		avl_insert(&zevstat.guids_runtime, gt, where);
1301b690436dSAndreas Jaekel 	}
1302b690436dSAndreas Jaekel 	gt_int = avl_find(&zevstat.guids_interval, &to_find, &where);
1303b690436dSAndreas Jaekel 	if (!gt_int)
1304b690436dSAndreas Jaekel 		avl_insert(&zevstat.guids_interval, gt, where);
1305b690436dSAndreas Jaekel }
1306b690436dSAndreas Jaekel 
1307b690436dSAndreas Jaekel static void
1308f432e238SAndreas Jaekel zev_eventstat_interval(FILE *out)
1309b690436dSAndreas Jaekel {
1310b690436dSAndreas Jaekel 	uint64_t events;
1311b690436dSAndreas Jaekel 	int i;
1312b690436dSAndreas Jaekel 	zev_guidtrack_t *gt;
1313b690436dSAndreas Jaekel 
1314b690436dSAndreas Jaekel 	events = 0;
1315b690436dSAndreas Jaekel 	for (i = ZEV_OP_MIN; i <= ZEV_OP_MAX; i++) {
1316b690436dSAndreas Jaekel 		events += zevstat.events[i];
1317b690436dSAndreas Jaekel 	}
1318b690436dSAndreas Jaekel 
1319b690436dSAndreas Jaekel 	if (verbose) {
1320f432e238SAndreas Jaekel 		fprintf(out, "%u  %6llu  %6llu %6llu %6llu  ",
1321b690436dSAndreas Jaekel 		        time(NULL),
1322b690436dSAndreas Jaekel 		        events,
1323b690436dSAndreas Jaekel 		        zevstat.total_events,
1324b690436dSAndreas Jaekel 		        avl_numnodes(&zevstat.guids_interval),
1325b690436dSAndreas Jaekel 		        avl_numnodes(&zevstat.guids_runtime));
1326b690436dSAndreas Jaekel 		for (i = ZEV_OP_MIN; i <= ZEV_OP_MAX; i++)
1327f432e238SAndreas Jaekel 			fprintf(out, "%6llu ", zevstat.events[i]);
1328f432e238SAndreas Jaekel 		fprintf(out, "\n");
1329b690436dSAndreas Jaekel 	} else {
1330f432e238SAndreas Jaekel 		fprintf(out, "%u  %6llu  %6llu %6llu %6llu\n",
1331b690436dSAndreas Jaekel 		        time(NULL),
1332b690436dSAndreas Jaekel 		        events,
1333b690436dSAndreas Jaekel 		        zevstat.total_events,
1334b690436dSAndreas Jaekel 		        avl_numnodes(&zevstat.guids_interval),
1335b690436dSAndreas Jaekel 		        avl_numnodes(&zevstat.guids_runtime));
1336b690436dSAndreas Jaekel 	}
1337b690436dSAndreas Jaekel 	memset(&zevstat.events, 0, sizeof(zevstat.events));
1338b690436dSAndreas Jaekel 	zevstat.guids = 0;
1339b690436dSAndreas Jaekel 	while (gt = avl_first(&zevstat.guids_interval))
1340b690436dSAndreas Jaekel 		avl_remove(&zevstat.guids_interval, gt);
1341f432e238SAndreas Jaekel 	fflush(out);
1342b690436dSAndreas Jaekel }
1343b690436dSAndreas Jaekel 
1344b690436dSAndreas Jaekel static int
1345b690436dSAndreas Jaekel zev_evcompar(const void *a, const void *b)
1346b690436dSAndreas Jaekel {
1347b690436dSAndreas Jaekel 	const zev_guidtrack_t *ga = a;
1348b690436dSAndreas Jaekel 	const zev_guidtrack_t *gb = b;
1349b690436dSAndreas Jaekel 
1350b690436dSAndreas Jaekel 	if (ga->guid > gb->guid)
1351b690436dSAndreas Jaekel 		return 1;
1352b690436dSAndreas Jaekel 	if (ga->guid < gb->guid)
1353b690436dSAndreas Jaekel 		return -1;
1354b690436dSAndreas Jaekel 	return 0;
1355b690436dSAndreas Jaekel }
1356b690436dSAndreas Jaekel 
1357b690436dSAndreas Jaekel static int
1358f432e238SAndreas Jaekel zev_zevstat(int fd, char *s_interval, char *s_count, char *outfile)
1359b690436dSAndreas Jaekel {
1360b690436dSAndreas Jaekel 	uint64_t interval = 1000;
1361b690436dSAndreas Jaekel 	uint64_t ms;
1362b690436dSAndreas Jaekel 	uint64_t t_until;
1363b690436dSAndreas Jaekel 	uint64_t t_now;
1364b690436dSAndreas Jaekel 	int cnt = -1;
1365b690436dSAndreas Jaekel 	struct pollfd pfd[1];
1366b690436dSAndreas Jaekel 	int ret;
1367b690436dSAndreas Jaekel 	char buf[4096];
1368b690436dSAndreas Jaekel 	zev_event_t *ev;
1369b690436dSAndreas Jaekel 	int off = 0;
1370b690436dSAndreas Jaekel 	zev_ioctl_add_queue_t aq;
1371b690436dSAndreas Jaekel 	int q_fd;
1372b690436dSAndreas Jaekel 	zev_guidtrack_t *gt;
1373f432e238SAndreas Jaekel 	FILE *out = stdout;
1374f432e238SAndreas Jaekel 	struct stat st;
1375f432e238SAndreas Jaekel 	char filename[MAXPATHLEN];
1376f432e238SAndreas Jaekel 	int retry;
1377f432e238SAndreas Jaekel 
1378f432e238SAndreas Jaekel 	if (outfile) {
1379f432e238SAndreas Jaekel 		retry = 0;
1380f432e238SAndreas Jaekel 		strncpy(filename, outfile, sizeof(filename));
1381f432e238SAndreas Jaekel 		while (stat(filename, &st) == 0) {
1382f432e238SAndreas Jaekel 			/* file exists */
1383f432e238SAndreas Jaekel 			snprintf(filename, sizeof(filename),
1384f432e238SAndreas Jaekel 			         "%s.%d", outfile, retry);
1385f432e238SAndreas Jaekel 			retry++;
1386f432e238SAndreas Jaekel 		}
1387f432e238SAndreas Jaekel 		out = fopen(filename, "wb+");
1388f432e238SAndreas Jaekel 		if (!out) {
1389f432e238SAndreas Jaekel 			perror("opening output file failed");
1390f432e238SAndreas Jaekel 			return (EXIT_FAILURE);
1391f432e238SAndreas Jaekel 		}
1392f432e238SAndreas Jaekel 	}
1393b690436dSAndreas Jaekel 
1394b690436dSAndreas Jaekel 	memset(&zevstat, 0, sizeof(zevstat));
1395b690436dSAndreas Jaekel 	avl_create(&zevstat.guids_runtime, zev_evcompar,
1396b690436dSAndreas Jaekel 	           sizeof(zev_guidtrack_t),
1397b690436dSAndreas Jaekel 	           offsetof(zev_guidtrack_t, avl_runtime));
1398b690436dSAndreas Jaekel 	avl_create(&zevstat.guids_interval, zev_evcompar,
1399b690436dSAndreas Jaekel 	           sizeof(zev_guidtrack_t),
1400b690436dSAndreas Jaekel 	           offsetof(zev_guidtrack_t, avl_interval));
1401b690436dSAndreas Jaekel 
140219695134SAndreas Jaekel 	if (s_interval) {
1403b690436dSAndreas Jaekel 		interval = atol(s_interval);
1404b690436dSAndreas Jaekel 		if (interval == 0) {
1405b690436dSAndreas Jaekel 			fprintf(stderr, "invalid interval.\n");
1406b690436dSAndreas Jaekel 			return (EXIT_FAILURE);
1407b690436dSAndreas Jaekel 		}
1408b690436dSAndreas Jaekel 		interval *= 1000;
140919695134SAndreas Jaekel 	}
1410b690436dSAndreas Jaekel 	if (s_count) {
1411b690436dSAndreas Jaekel 		cnt = atol(s_count);
1412b690436dSAndreas Jaekel 		if (interval == 0) {
1413b690436dSAndreas Jaekel 			fprintf(stderr, "invalid count.\n");
1414b690436dSAndreas Jaekel 			return (EXIT_FAILURE);
1415b690436dSAndreas Jaekel 		}
1416b690436dSAndreas Jaekel 	}
1417b690436dSAndreas Jaekel 
1418b690436dSAndreas Jaekel 	aq.zev_max_queue_len = 1024 * 1024;
1419c99a1a25SAndreas Jaekel 	aq.zev_flags = ZEV_FL_INITIALLY_EMPTY;
1420b690436dSAndreas Jaekel 	snprintf(aq.zev_name, ZEV_MAX_QUEUE_NAME_LEN,
1421b690436dSAndreas Jaekel 		 "zevstat.%ld.%ld", time(NULL), getpid());
1422b690436dSAndreas Jaekel 	aq.zev_namelen = strlen(aq.zev_name);
1423b690436dSAndreas Jaekel 
1424b690436dSAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_ADD_QUEUE, &aq)) {
1425b690436dSAndreas Jaekel 		perror("adding temporary queue failed");
1426b690436dSAndreas Jaekel 		return (EXIT_FAILURE);
1427b690436dSAndreas Jaekel 	}
1428b690436dSAndreas Jaekel 
1429b690436dSAndreas Jaekel 	snprintf(buf, sizeof(buf),
1430b690436dSAndreas Jaekel 		 "/devices/pseudo/zev@0:%s", aq.zev_name);
1431b690436dSAndreas Jaekel 	q_fd = open(buf, O_RDONLY);
1432b690436dSAndreas Jaekel 	if (q_fd < 0) {
1433b690436dSAndreas Jaekel 		perror("opening queue device failed");
1434b690436dSAndreas Jaekel 		return (EXIT_FAILURE);
1435b690436dSAndreas Jaekel 	}
1436b690436dSAndreas Jaekel 
1437b690436dSAndreas Jaekel 	pfd[0].fd = q_fd;
1438b690436dSAndreas Jaekel 	pfd[0].events = POLLIN;
1439b690436dSAndreas Jaekel 
1440b690436dSAndreas Jaekel 	/* drain queue */
144119695134SAndreas Jaekel 	while ((ret = poll(pfd, 1, 0)) > 0) {
1442b690436dSAndreas Jaekel 		if (read(q_fd, buf, sizeof(buf)) < 0) {
1443b690436dSAndreas Jaekel 			perror("read failed");
1444b690436dSAndreas Jaekel 			close(q_fd);
1445b690436dSAndreas Jaekel 			return(EXIT_FAILURE);
1446b690436dSAndreas Jaekel 		}
1447b690436dSAndreas Jaekel 	}
1448b690436dSAndreas Jaekel 	if (ret < 0) {
1449b690436dSAndreas Jaekel 		perror("poll failed");
1450b690436dSAndreas Jaekel 		close(q_fd);
1451b690436dSAndreas Jaekel 		return(EXIT_FAILURE);
1452b690436dSAndreas Jaekel 	}
1453b690436dSAndreas Jaekel 
1454f432e238SAndreas Jaekel 	fprintf(out, "timestamp   events tevents  guids tguids");
1455b690436dSAndreas Jaekel 	if (verbose) {
1456f432e238SAndreas Jaekel 		fprintf(out, "   error   mark  mount umount zvol_w ");
1457f432e238SAndreas Jaekel 		fprintf(out, "zvol_t  close create  mkdir mxattr ");
1458f432e238SAndreas Jaekel 		fprintf(out, "remove  rmdir   link symlnk rename  ");
1459f432e238SAndreas Jaekel 		fprintf(out, "write  trunc setatt    acl");
1460b690436dSAndreas Jaekel 	}
1461f432e238SAndreas Jaekel 	fprintf(out, "\n");
1462b690436dSAndreas Jaekel 	while (cnt) {
1463b690436dSAndreas Jaekel 		t_until = gethrtime() + (interval * 1000000);
1464b690436dSAndreas Jaekel 		ms = interval;
1465b690436dSAndreas Jaekel 		do {
1466b690436dSAndreas Jaekel 			ret = poll(pfd, 1, ms);
1467b690436dSAndreas Jaekel 			t_now = gethrtime();
1468b690436dSAndreas Jaekel 			if (t_now < t_until) {
1469b690436dSAndreas Jaekel 				ms = t_until - t_now;
1470b690436dSAndreas Jaekel 				ms /= 1000000ull;
1471b690436dSAndreas Jaekel 			}
1472b690436dSAndreas Jaekel 			if (ret < 0) {
1473b690436dSAndreas Jaekel 				perror("poll failed");
1474b690436dSAndreas Jaekel 				close(q_fd);
1475b690436dSAndreas Jaekel 				return(EXIT_FAILURE);
1476b690436dSAndreas Jaekel 			}
1477b690436dSAndreas Jaekel 			if (!(pfd[0].revents & POLLIN))
1478b690436dSAndreas Jaekel 				continue;
1479b690436dSAndreas Jaekel 			/* data available */
1480b690436dSAndreas Jaekel 			ret = read(q_fd, buf, sizeof(buf));
1481b690436dSAndreas Jaekel 			if (ret < 0) {
1482b690436dSAndreas Jaekel 				perror("read failed");
1483b690436dSAndreas Jaekel 				close(q_fd);
1484b690436dSAndreas Jaekel 				return(EXIT_FAILURE);
1485b690436dSAndreas Jaekel 			}
1486b690436dSAndreas Jaekel 			if (ret == 0)
1487b690436dSAndreas Jaekel 				continue;
1488b690436dSAndreas Jaekel 			while (ret > off) {
1489b690436dSAndreas Jaekel 				ev = (zev_event_t *)(buf + off);
1490b690436dSAndreas Jaekel 				zev_eventstat(buf + off, ev->header.record_len);
1491b690436dSAndreas Jaekel 				off += ev->header.record_len;
1492b690436dSAndreas Jaekel 			}
1493b690436dSAndreas Jaekel 			off = 0;
1494b690436dSAndreas Jaekel 		} while ((t_now) < t_until && (ms > 0));
1495f432e238SAndreas Jaekel 		zev_eventstat_interval(out);
1496b690436dSAndreas Jaekel 		if (cnt > 0)
1497b690436dSAndreas Jaekel 			cnt--;
1498b690436dSAndreas Jaekel 	}
1499b690436dSAndreas Jaekel 	close(q_fd);
1500f432e238SAndreas Jaekel 	if (outfile)
1501f432e238SAndreas Jaekel 		fclose(out);
1502b690436dSAndreas Jaekel 	while (gt = avl_first(&zevstat.guids_interval))
1503b690436dSAndreas Jaekel 		avl_remove(&zevstat.guids_interval, gt);
1504b690436dSAndreas Jaekel 	while (gt = avl_first(&zevstat.guids_runtime)) {
1505b690436dSAndreas Jaekel 		avl_remove(&zevstat.guids_runtime, gt);
1506b690436dSAndreas Jaekel 		free(gt);
1507b690436dSAndreas Jaekel 	}
1508b690436dSAndreas Jaekel 	return EXIT_SUCCESS;
1509b690436dSAndreas Jaekel }
1510b690436dSAndreas Jaekel 
1511f432e238SAndreas Jaekel static int
1512f432e238SAndreas Jaekel zev_report(int fd, char *basename)
1513f432e238SAndreas Jaekel {
1514f432e238SAndreas Jaekel 	char filename[MAXPATHLEN];
1515f432e238SAndreas Jaekel 	char count[10];
1516f432e238SAndreas Jaekel 	time_t now;
1517f432e238SAndreas Jaekel 	time_t midnight;
1518f432e238SAndreas Jaekel 	struct tm tm;
1519f432e238SAndreas Jaekel 	int minutes;
1520f432e238SAndreas Jaekel 	int ret;
1521f432e238SAndreas Jaekel 
1522f432e238SAndreas Jaekel 	verbose++;
1523f432e238SAndreas Jaekel 	while (1) {
1524f432e238SAndreas Jaekel 		now = time(NULL);
1525f432e238SAndreas Jaekel 		localtime_r(&now, &tm);
1526f432e238SAndreas Jaekel 		snprintf(filename, sizeof(filename), "%s.%04d-%02d-%02d",
1527f432e238SAndreas Jaekel 		         basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
1528f432e238SAndreas Jaekel 		tm.tm_sec = 0;
1529f432e238SAndreas Jaekel 		tm.tm_min = 0;
1530f432e238SAndreas Jaekel 		tm.tm_hour = 0;
1531f432e238SAndreas Jaekel 		tm.tm_mday++;  /* works for Jan 32nd, Feb 30th, etc. */
1532f432e238SAndreas Jaekel 		midnight = mktime(&tm);
1533f432e238SAndreas Jaekel 		if (now % 60)
1534f432e238SAndreas Jaekel 			sleep(60 - (now % 60));
1535f432e238SAndreas Jaekel 		minutes = (midnight - time(NULL)) / 60;
1536f432e238SAndreas Jaekel 		snprintf(count, sizeof(count), "%d", minutes);
1537f432e238SAndreas Jaekel 		ret = zev_zevstat(fd, "60", count, filename);
1538f432e238SAndreas Jaekel 		if (ret)
1539f432e238SAndreas Jaekel 			return EXIT_FAILURE;
1540f432e238SAndreas Jaekel 	}
1541f432e238SAndreas Jaekel 	return EXIT_SUCCESS; /* never reached */
1542f432e238SAndreas Jaekel }
1543f432e238SAndreas Jaekel 
1544a0d677d8SAndreas Jaekel static void
1545a0d677d8SAndreas Jaekel zev_sigint(int sig)
1546a0d677d8SAndreas Jaekel {
1547a0d677d8SAndreas Jaekel 	fflush(stdout);
1548a0d677d8SAndreas Jaekel }
1549a0d677d8SAndreas Jaekel 
1550a18c35b9SAndreas Jaekel int
1551a18c35b9SAndreas Jaekel main(int argc, char **argv)
1552a18c35b9SAndreas Jaekel {
1553a18c35b9SAndreas Jaekel 	int fd;
1554a18c35b9SAndreas Jaekel 	int c;
1555a18c35b9SAndreas Jaekel 	extern char *optarg;
15566a6a51eeSAndreas Jaekel 	int create_tmp_queue = 1;
15576a6a51eeSAndreas Jaekel 	char buf[MAXPATHLEN];
1558a5090b97SAndreas Jaekel 	int mode = 0;
1559a5090b97SAndreas Jaekel 	char *arg = NULL;
1560a5090b97SAndreas Jaekel 	char *arg2 = NULL;
1561b690436dSAndreas Jaekel 	char *p;
1562b690436dSAndreas Jaekel 
1563a0d677d8SAndreas Jaekel 	sigset(SIGINT, zev_sigint);
1564a0d677d8SAndreas Jaekel 
156550da9edeSAndreas Jaekel 	/* open device */
156650da9edeSAndreas Jaekel 	fd = open(zev_device, O_RDONLY);
156750da9edeSAndreas Jaekel 	if (fd < 0) {
156850da9edeSAndreas Jaekel 		perror("opening zev device failed");
156950da9edeSAndreas Jaekel 		return EXIT_FAILURE;
157050da9edeSAndreas Jaekel 	}
157150da9edeSAndreas Jaekel 
1572b690436dSAndreas Jaekel 	p = strrchr(argv[0], '/');
1573b690436dSAndreas Jaekel 	if (!p) {
1574b690436dSAndreas Jaekel 		p = argv[0];
1575b690436dSAndreas Jaekel 	} else {
1576b690436dSAndreas Jaekel 		p++;
1577b690436dSAndreas Jaekel 	}
1578b690436dSAndreas Jaekel 	if (!strcmp(p, "zevstat")) {
1579b690436dSAndreas Jaekel 		mode = MD_ZEVSTAT;
158050da9edeSAndreas Jaekel 		if (argc < 2)
158150da9edeSAndreas Jaekel 			zevstat_usage(argv[0]);
158250da9edeSAndreas Jaekel 		if (!strcmp(argv[1], "-v")) {
158350da9edeSAndreas Jaekel 			if (argc < 3)
158450da9edeSAndreas Jaekel 				zevstat_usage(argv[0]);
158550da9edeSAndreas Jaekel 			verbose++;
158650da9edeSAndreas Jaekel 			arg = argv[2];
158750da9edeSAndreas Jaekel 			arg2 = argv[3];
158850da9edeSAndreas Jaekel 		} else {
158950da9edeSAndreas Jaekel 			arg = argv[1];
159050da9edeSAndreas Jaekel 			arg2 = argv[2];
159150da9edeSAndreas Jaekel 		}
1592f432e238SAndreas Jaekel 		return zev_zevstat(fd, arg, arg2, NULL);
1593f432e238SAndreas Jaekel 	} else if(!strcmp(p, "zevreport")) {
1594f432e238SAndreas Jaekel 		mode = MD_ZEV_REPORT;
1595f432e238SAndreas Jaekel 		if (argc != 2)
1596f432e238SAndreas Jaekel 			zevreport_usage(argv[0]);
1597f432e238SAndreas Jaekel 		return zev_report(fd, argv[1]);
1598b690436dSAndreas Jaekel 	}
1599a18c35b9SAndreas Jaekel 
16006a6a51eeSAndreas Jaekel 	while ((c = getopt(argc, argv,
1601*35526fb3SArne Jansen 	   "gvspc:d:Dlk:L:q:Q:t:m:M:a:A:r:P:b:B:T:R:f:h?")) != -1) {
1602a18c35b9SAndreas Jaekel 		switch(c) {
160316ff6b2fSAndreas Jaekel 		case 'g':
160416ff6b2fSAndreas Jaekel 			grep_friendly++;
160516ff6b2fSAndreas Jaekel 			verbose++;
160616ff6b2fSAndreas Jaekel 			break;
1607205ed6bfSAndreas Jaekel 		case 'v':
1608205ed6bfSAndreas Jaekel 			verbose++;
1609205ed6bfSAndreas Jaekel 			break;
1610a18c35b9SAndreas Jaekel 		case 's':
1611a5090b97SAndreas Jaekel 			mode = MD_STATISTICS;
1612a5090b97SAndreas Jaekel 			break;
1613a18c35b9SAndreas Jaekel 		case 'p':
1614a5090b97SAndreas Jaekel 			mode = MD_POLL_EVENTS;
1615a5090b97SAndreas Jaekel 			break;
161642110aacSAndreas Jaekel 		case 'c':
1617a5090b97SAndreas Jaekel 			mode = MD_CHECKSUMS;
1618a5090b97SAndreas Jaekel 			arg = optarg;
1619a5090b97SAndreas Jaekel 			break;
1620add9520fSAndreas Jaekel 		case 'D':
1621a5090b97SAndreas Jaekel 			mode = MD_DEBUG_INFO;
1622a5090b97SAndreas Jaekel 			break;
1623a18c35b9SAndreas Jaekel 		case 'd':
1624add9520fSAndreas Jaekel 			close(fd);
1625a18c35b9SAndreas Jaekel 			zev_device = optarg;
1626add9520fSAndreas Jaekel 			fd = open(zev_device, O_RDONLY);
1627add9520fSAndreas Jaekel 			if (fd < 0) {
1628add9520fSAndreas Jaekel 				perror("opening zev device failed");
1629add9520fSAndreas Jaekel 				return EXIT_FAILURE;
1630add9520fSAndreas Jaekel 			}
16316a6a51eeSAndreas Jaekel 			create_tmp_queue = 0;
16326a6a51eeSAndreas Jaekel 			break;
16336a6a51eeSAndreas Jaekel 		case 'q':
16346a6a51eeSAndreas Jaekel 			snprintf(buf, sizeof(buf),
16356a6a51eeSAndreas Jaekel 				 "/devices/pseudo/zev@0:%s", optarg);
16366a6a51eeSAndreas Jaekel 			close(fd);
16376a6a51eeSAndreas Jaekel 			zev_device = buf;
16386a6a51eeSAndreas Jaekel 			fd = open(zev_device, O_RDONLY);
16396a6a51eeSAndreas Jaekel 			if (fd < 0) {
16406a6a51eeSAndreas Jaekel 				perror("opening zev device failed");
16416a6a51eeSAndreas Jaekel 				return EXIT_FAILURE;
16426a6a51eeSAndreas Jaekel 			}
16436a6a51eeSAndreas Jaekel 			create_tmp_queue = 0;
1644a18c35b9SAndreas Jaekel 			break;
1645*35526fb3SArne Jansen 		case 'f':
1646*35526fb3SArne Jansen 			fd = open(optarg, O_RDONLY);
1647*35526fb3SArne Jansen 			if (fd < 0) {
1648*35526fb3SArne Jansen 				perror("opening spool file failed");
1649*35526fb3SArne Jansen 				return EXIT_FAILURE;
1650*35526fb3SArne Jansen 			}
1651*35526fb3SArne Jansen 			mode = MD_DUMP_SPOOL;
1652*35526fb3SArne Jansen 			break;
1653add9520fSAndreas Jaekel 		case 'l':
1654a5090b97SAndreas Jaekel 			mode = MD_LIST_QUEUES;
1655a5090b97SAndreas Jaekel 			break;
1656add9520fSAndreas Jaekel 		case 'Q':
1657a5090b97SAndreas Jaekel 			mode = MD_SET_GLOBAL_MAX_QUEUE_LEN;
1658a5090b97SAndreas Jaekel 			arg = optarg;
1659a5090b97SAndreas Jaekel 			break;
16606a6a51eeSAndreas Jaekel 		case 'L':
1661a5090b97SAndreas Jaekel 			mode = MD_SET_MAX_QUEUE_LEN;
1662a5090b97SAndreas Jaekel 			arg = optarg;
1663a5090b97SAndreas Jaekel 			arg2 = argv[optind];
1664a5090b97SAndreas Jaekel 			break;
1665b690436dSAndreas Jaekel 		case 'T':
1666b690436dSAndreas Jaekel 			mode = MD_ZEVSTAT;
1667b690436dSAndreas Jaekel 			arg = optarg;
1668b690436dSAndreas Jaekel 			arg2 = argv[optind];
1669b690436dSAndreas Jaekel 			break;
1670f432e238SAndreas Jaekel 		case 'R':
1671f432e238SAndreas Jaekel 			mode = MD_ZEV_REPORT;
1672f432e238SAndreas Jaekel 			arg = optarg;
1673f432e238SAndreas Jaekel 			break;
1674fec460f8SAndreas Jaekel 		case 't':
1675a5090b97SAndreas Jaekel 			mode = MD_SET_POLL_WAKEUP_QUEUE_LEN;
1676a5090b97SAndreas Jaekel 			arg = optarg;
1677a5090b97SAndreas Jaekel 			arg2 = argv[optind];
1678a5090b97SAndreas Jaekel 			break;
1679a18c35b9SAndreas Jaekel 		case 'm':
1680a5090b97SAndreas Jaekel 			mode = MD_MUTE_POOL;
1681a5090b97SAndreas Jaekel 			arg = optarg;
1682a5090b97SAndreas Jaekel 			break;
1683a18c35b9SAndreas Jaekel 		case 'M':
1684a5090b97SAndreas Jaekel 			mode = MD_UNMUTE_POOL;
1685a5090b97SAndreas Jaekel 			arg = optarg;
1686a5090b97SAndreas Jaekel 			break;
1687888fea18SAndreas Jaekel 		case 'k':
1688a5090b97SAndreas Jaekel 			mode = MD_MARK;
1689a5090b97SAndreas Jaekel 			arg = optarg;
1690a5090b97SAndreas Jaekel 			break;
1691add9520fSAndreas Jaekel 		case 'a':
1692a5090b97SAndreas Jaekel 			mode = MD_ADD_QUEUE;
1693a5090b97SAndreas Jaekel 			arg = optarg;
1694a5090b97SAndreas Jaekel 			break;
16956a6a51eeSAndreas Jaekel 		case 'A':
1696a5090b97SAndreas Jaekel 			mode = MD_ADD_BLOCKING_QUEUE;
1697a5090b97SAndreas Jaekel 			arg = optarg;
1698a5090b97SAndreas Jaekel 			break;
1699add9520fSAndreas Jaekel 		case 'r':
1700a5090b97SAndreas Jaekel 			mode = MD_REMOVE_QUEUE;
1701a5090b97SAndreas Jaekel 			arg = optarg;
1702a5090b97SAndreas Jaekel 			break;
1703add9520fSAndreas Jaekel 		case 'b':
1704a5090b97SAndreas Jaekel 			mode = MD_QUEUE_BLOCKING;
1705a5090b97SAndreas Jaekel 			arg = optarg;
1706a5090b97SAndreas Jaekel 			break;
1707add9520fSAndreas Jaekel 		case 'B':
1708a5090b97SAndreas Jaekel 			mode = MD_QUEUE_NONBLOCKING;
1709a5090b97SAndreas Jaekel 			arg = optarg;
1710a5090b97SAndreas Jaekel 			break;
1711add9520fSAndreas Jaekel 		case 'P':
1712a5090b97SAndreas Jaekel 			mode = MD_QUEUE_PROPERTIES;
1713a5090b97SAndreas Jaekel 			arg = optarg;
1714a5090b97SAndreas Jaekel 			break;
1715a18c35b9SAndreas Jaekel 		case 'h':
1716a18c35b9SAndreas Jaekel 		case '?':
1717a18c35b9SAndreas Jaekel 		default:
1718a18c35b9SAndreas Jaekel 			usage(argv[0]);
1719a18c35b9SAndreas Jaekel 		}
1720a18c35b9SAndreas Jaekel 	}
1721a5090b97SAndreas Jaekel 
1722a5090b97SAndreas Jaekel 	switch (mode) {
1723a5090b97SAndreas Jaekel 	case MD_STATISTICS:
1724a5090b97SAndreas Jaekel 		return zev_statistics(fd);
1725a5090b97SAndreas Jaekel 	case MD_POLL_EVENTS:
1726a5090b97SAndreas Jaekel 		return zev_poll_events(fd, create_tmp_queue);
1727*35526fb3SArne Jansen 	case MD_DUMP_SPOOL:
1728*35526fb3SArne Jansen 		return zev_dump_spool(fd);
1729a5090b97SAndreas Jaekel 	case MD_CHECKSUMS:
1730a5090b97SAndreas Jaekel 		return zev_checksum(fd, arg);
1731a5090b97SAndreas Jaekel 	case MD_DEBUG_INFO:
1732a5090b97SAndreas Jaekel 		return zev_debug_info(fd);
1733a5090b97SAndreas Jaekel 	case MD_LIST_QUEUES:
1734a5090b97SAndreas Jaekel 		return zev_list_queues(fd);
1735a5090b97SAndreas Jaekel 	case MD_SET_GLOBAL_MAX_QUEUE_LEN:
1736a5090b97SAndreas Jaekel 		return zev_set_global_max_queue_len(fd, arg);
1737a5090b97SAndreas Jaekel 	case MD_SET_MAX_QUEUE_LEN:
1738a5090b97SAndreas Jaekel 		return zev_set_max_queue_len(fd, arg, arg2);
1739a5090b97SAndreas Jaekel 	case MD_SET_POLL_WAKEUP_QUEUE_LEN:
1740a5090b97SAndreas Jaekel 		return zev_set_poll_wakeup_queue_len(fd, arg, arg2);
1741b690436dSAndreas Jaekel 	case MD_ZEVSTAT:
1742f432e238SAndreas Jaekel 		return zev_zevstat(fd, arg, arg2, NULL);
1743f432e238SAndreas Jaekel 	case MD_ZEV_REPORT:
1744f432e238SAndreas Jaekel 		return zev_report(fd, arg);
1745a5090b97SAndreas Jaekel 	case MD_MUTE_POOL:
1746a5090b97SAndreas Jaekel 		return zev_mute_pool(fd, arg);
1747a5090b97SAndreas Jaekel 	case MD_UNMUTE_POOL:
1748a5090b97SAndreas Jaekel 		return zev_unmute_pool(fd, arg);
1749a5090b97SAndreas Jaekel 	case MD_MARK:
1750a5090b97SAndreas Jaekel 		return zev_mark(fd, arg);
1751a5090b97SAndreas Jaekel 	case MD_ADD_QUEUE:
1752a5090b97SAndreas Jaekel 		return zev_add_queue(fd, arg, 0);
1753a5090b97SAndreas Jaekel 	case MD_ADD_BLOCKING_QUEUE:
1754a5090b97SAndreas Jaekel 		return zev_add_queue(fd, arg, 1);
1755a5090b97SAndreas Jaekel 	case MD_REMOVE_QUEUE:
1756a5090b97SAndreas Jaekel 		return zev_remove_queue(fd, arg);
1757a5090b97SAndreas Jaekel 	case MD_QUEUE_BLOCKING:
1758a5090b97SAndreas Jaekel 		return zev_queue_blocking(fd, arg, 0);
1759a5090b97SAndreas Jaekel 	case MD_QUEUE_NONBLOCKING:
1760a5090b97SAndreas Jaekel 		return zev_queue_blocking(fd, arg, 1);
1761a5090b97SAndreas Jaekel 	case MD_QUEUE_PROPERTIES:
1762a5090b97SAndreas Jaekel 		return zev_queue_properties(fd, arg);
1763a5090b97SAndreas Jaekel 	default:
1764a18c35b9SAndreas Jaekel 		close(fd);
1765a5090b97SAndreas Jaekel 		usage(argv[0]);
1766add9520fSAndreas Jaekel 		return EXIT_FAILURE;
1767a5090b97SAndreas Jaekel 	};
1768a18c35b9SAndreas Jaekel }
1769a18c35b9SAndreas Jaekel 
1770