xref: /titanic_44/usr/src/cmd/zevadm/zevadm.c (revision 6a6a51ee340e14dff36736402d6e3b06fdde00f5)
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>
10a18c35b9SAndreas Jaekel 
11a18c35b9SAndreas Jaekel #define OP_STATISTICS		(1 << 0)
12a18c35b9SAndreas Jaekel #define OP_POLL_EVENTS		(1 << 1)
13a18c35b9SAndreas Jaekel #define OP_MUTE_POOL		(1 << 2)
14a18c35b9SAndreas Jaekel #define OP_UNMUTE_POOL		(1 << 3)
15a18c35b9SAndreas Jaekel #define OP_SET_MAX_QUEUE_LEN	(1 << 4)
16add9520fSAndreas Jaekel #define OP_DEBUG_INFO		(1 << 5)
17a18c35b9SAndreas Jaekel 
18add9520fSAndreas Jaekel #define ZEV_DEVICE "/devices/pseudo/zev@0:ctrl"
19a18c35b9SAndreas Jaekel 
20a18c35b9SAndreas Jaekel static char *zev_device = ZEV_DEVICE;
21a18c35b9SAndreas Jaekel 
22aafc540fSAndreas Jaekel static char *zev_op_name[] = {
23aafc540fSAndreas Jaekel 	"ZEV_OP_ERROR",
24888fea18SAndreas Jaekel 	"ZEV_OP_MARK",
25aafc540fSAndreas Jaekel 	"ZEV_OP_ZFS_MOUNT",
26aafc540fSAndreas Jaekel 	"ZEV_OP_ZFS_UMOUNT",
27aafc540fSAndreas Jaekel 	"ZEV_OP_ZVOL_WRITE",
28aafc540fSAndreas Jaekel 	"ZEV_OP_ZVOL_TRUNCATE",
29aafc540fSAndreas Jaekel 	"ZEV_OP_ZNODE_CLOSE_AFTER_UPDATE",
30aafc540fSAndreas Jaekel 	"ZEV_OP_ZNODE_CREATE",
31aafc540fSAndreas Jaekel 	"ZEV_OP_ZNODE_MKDIR",
32aafc540fSAndreas Jaekel 	"ZEV_OP_ZNODE_MAKE_XATTR_DIR",
33aafc540fSAndreas Jaekel 	"ZEV_OP_ZNODE_REMOVE",
34aafc540fSAndreas Jaekel 	"ZEV_OP_ZNODE_RMDIR",
35aafc540fSAndreas Jaekel 	"ZEV_OP_ZNODE_LINK",
36aafc540fSAndreas Jaekel 	"ZEV_OP_ZNODE_SYMLINK",
37aafc540fSAndreas Jaekel 	"ZEV_OP_ZNODE_RENAME",
38aafc540fSAndreas Jaekel 	"ZEV_OP_ZNODE_WRITE",
39aafc540fSAndreas Jaekel 	"ZEV_OP_ZNODE_TRUNCATE",
40aafc540fSAndreas Jaekel 	"ZEV_OP_ZNODE_SETATTR",
41aafc540fSAndreas Jaekel 	"ZEV_OP_ZNODE_ACL",
42aafc540fSAndreas Jaekel 	NULL
43aafc540fSAndreas Jaekel };
44aafc540fSAndreas Jaekel 
45add9520fSAndreas Jaekel static int
46a18c35b9SAndreas Jaekel zev_statistics(int fd)
47a18c35b9SAndreas Jaekel {
48a18c35b9SAndreas Jaekel 	zev_statistics_t zs;
49add9520fSAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_GET_GLOBAL_STATISTICS, &zs)) {
50a18c35b9SAndreas Jaekel 		perror("getting statistics data failed");
51add9520fSAndreas Jaekel 		return (EXIT_FAILURE);
52a18c35b9SAndreas Jaekel 	}
53a18c35b9SAndreas Jaekel 	printf("ZEV module state:\n");
54a18c35b9SAndreas Jaekel 
55a18c35b9SAndreas Jaekel 	printf("    queue length in bytes   : %lu\n", zs.zev_queue_len);
56a18c35b9SAndreas Jaekel 	printf("    queue length limit      : %lu\n", zs.zev_max_queue_len);
57a18c35b9SAndreas Jaekel 	printf("    bytes read from device  : %lu\n", zs.zev_bytes_read);
58a18c35b9SAndreas Jaekel 	printf("    module internal errors  : %lu\n\n", zs.zev_cnt_errors);
59a18c35b9SAndreas Jaekel 
60add9520fSAndreas Jaekel 	printf("    discarded events        : %lu\n",
61add9520fSAndreas Jaekel 	    zs.zev_cnt_discarded_events);
62add9520fSAndreas Jaekel 	printf("    discarded bytes         : %lu\n\n", zs.zev_bytes_discarded);
63add9520fSAndreas Jaekel 
64a18c35b9SAndreas Jaekel 	printf("ZFS event statistics:\n");
65a18c35b9SAndreas Jaekel 
66a18c35b9SAndreas Jaekel 	printf("    total ZFS events        : %lu\n", zs.zev_cnt_total_events);
67a18c35b9SAndreas Jaekel 	printf("    ZFS mount               : %lu\n", zs.zev_cnt_zfs_mount);
68a18c35b9SAndreas Jaekel 	printf("    ZFS umount              : %lu\n", zs.zev_cnt_zfs_umount);
69a18c35b9SAndreas Jaekel 	printf("    ZVOL write              : %lu\n", zs.zev_cnt_zvol_write);
70a18c35b9SAndreas Jaekel 	printf("    ZVOL truncate           : %lu\n", zs.zev_cnt_zvol_truncate);
71a18c35b9SAndreas Jaekel 	printf("    ZNODE close after update: %lu\n",
72a18c35b9SAndreas Jaekel 	    zs.zev_cnt_znode_close_after_update);
73a18c35b9SAndreas Jaekel 	printf("    ZNODE create            : %lu\n", zs.zev_cnt_znode_create);
74a18c35b9SAndreas Jaekel 	printf("    ZNODE remove            : %lu\n", zs.zev_cnt_znode_remove);
75a18c35b9SAndreas Jaekel 	printf("    ZNODE link              : %lu\n", zs.zev_cnt_znode_link);
76a18c35b9SAndreas Jaekel 	printf("    ZNODE symlink           : %lu\n", zs.zev_cnt_znode_symlink);
77a18c35b9SAndreas Jaekel 	printf("    ZNODE rename            : %lu\n", zs.zev_cnt_znode_rename);
78a18c35b9SAndreas Jaekel 	printf("    ZNODE write             : %lu\n", zs.zev_cnt_znode_write);
79a18c35b9SAndreas Jaekel 	printf("    ZNODE truncate          : %lu\n",
80a18c35b9SAndreas Jaekel 	    zs.zev_cnt_znode_truncate);
81a18c35b9SAndreas Jaekel 	printf("    ZNODE setattr           : %lu\n", zs.zev_cnt_znode_setattr);
82a18c35b9SAndreas Jaekel 	printf("    ZNODE acl               : %lu\n", zs.zev_cnt_znode_acl);
83add9520fSAndreas Jaekel 	return EXIT_SUCCESS;
84a18c35b9SAndreas Jaekel }
85a18c35b9SAndreas Jaekel 
86a18c35b9SAndreas Jaekel static void
87f2dd45e5SAndreas Jaekel zev_print_error(char *buf)
88f2dd45e5SAndreas Jaekel {
89f2dd45e5SAndreas Jaekel 	zev_error_t *rec = (zev_error_t *)buf;
90f2dd45e5SAndreas Jaekel 	time_t op_time = rec->op_time;
91f2dd45e5SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
92f2dd45e5SAndreas Jaekel 
93f2dd45e5SAndreas Jaekel 	printf("%s %s: failed_op=%s msg=%s\n",
94f2dd45e5SAndreas Jaekel 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
95f2dd45e5SAndreas Jaekel 	       zev_op_name[rec->failed_op - ZEV_OP_MIN], ZEV_ERRSTR(rec));
96f2dd45e5SAndreas Jaekel }
97f2dd45e5SAndreas Jaekel 
98f2dd45e5SAndreas Jaekel static void
99888fea18SAndreas Jaekel zev_print_mark(char *buf)
100888fea18SAndreas Jaekel {
101888fea18SAndreas Jaekel 	zev_mark_t *rec = (zev_mark_t *)buf;
102888fea18SAndreas Jaekel 	time_t op_time = rec->op_time;
103888fea18SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
104888fea18SAndreas Jaekel 
105888fea18SAndreas Jaekel 	printf("%s %s: guid=%llu mark_id=%lld payload_len=%ld\n",
106888fea18SAndreas Jaekel 	       ct, zev_op_name[rec->op - ZEV_OP_MIN], rec->guid, rec->mark_id,
107888fea18SAndreas Jaekel 	       rec->payload_len);
108888fea18SAndreas Jaekel }
109888fea18SAndreas Jaekel 
110888fea18SAndreas Jaekel static void
111f2dd45e5SAndreas Jaekel zev_print_zfs_mount(char *buf)
112f2dd45e5SAndreas Jaekel {
113f2dd45e5SAndreas Jaekel 	zev_zfs_mount_t *rec = (zev_zfs_mount_t *)buf;
114f2dd45e5SAndreas Jaekel 	time_t op_time = rec->op_time;
115f2dd45e5SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
116f2dd45e5SAndreas Jaekel 
117f2dd45e5SAndreas Jaekel 	printf("%s %s: guid=%llu remount=%s dataset='%s' mountpoint='%s'\n",
118f2dd45e5SAndreas Jaekel 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
119f2dd45e5SAndreas Jaekel 	       rec->guid,
120f2dd45e5SAndreas Jaekel 	       rec->remount ? "true" : "false",
121f2dd45e5SAndreas Jaekel 	       ZEV_DATASET(rec),
122f2dd45e5SAndreas Jaekel 	       ZEV_MOUNTPOINT(rec));
123f2dd45e5SAndreas Jaekel }
124f2dd45e5SAndreas Jaekel 
125f2dd45e5SAndreas Jaekel static void
126f2dd45e5SAndreas Jaekel zev_print_zfs_umount(char *buf)
127f2dd45e5SAndreas Jaekel {
128f2dd45e5SAndreas Jaekel 	zev_zfs_umount_t *rec = (zev_zfs_umount_t *)buf;
129f2dd45e5SAndreas Jaekel 	time_t op_time = rec->op_time;
130f2dd45e5SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
131f2dd45e5SAndreas Jaekel 
132f2dd45e5SAndreas Jaekel 	printf("%s %s: guid=%llu\n",
133f2dd45e5SAndreas Jaekel 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
134f2dd45e5SAndreas Jaekel 	       rec->guid);
135f2dd45e5SAndreas Jaekel }
136f2dd45e5SAndreas Jaekel 
137f2dd45e5SAndreas Jaekel static void
138f2dd45e5SAndreas Jaekel zev_print_zvol_truncate(char *buf)
139f2dd45e5SAndreas Jaekel {
140f2dd45e5SAndreas Jaekel 	zev_zvol_truncate_t *rec = (zev_zvol_truncate_t *)buf;
141f2dd45e5SAndreas Jaekel 	time_t op_time = rec->op_time;
142f2dd45e5SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
143f2dd45e5SAndreas Jaekel 
144f2dd45e5SAndreas Jaekel 	printf("%s %s: guid=%llu offset=%llu length=%llu\n",
145f2dd45e5SAndreas Jaekel 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
146f2dd45e5SAndreas Jaekel 	       rec->guid,
147f2dd45e5SAndreas Jaekel 	       rec->offset,
148f2dd45e5SAndreas Jaekel 	       rec->length);
149f2dd45e5SAndreas Jaekel }
150f2dd45e5SAndreas Jaekel 
151f2dd45e5SAndreas Jaekel static void
152f2dd45e5SAndreas Jaekel zev_print_zvol_write(char *buf)
153f2dd45e5SAndreas Jaekel {
154f2dd45e5SAndreas Jaekel 	zev_print_zvol_truncate(buf);
155f2dd45e5SAndreas Jaekel }
156f2dd45e5SAndreas Jaekel 
157f2dd45e5SAndreas Jaekel static void
158f2dd45e5SAndreas Jaekel zev_print_znode_close_after_update(char *buf)
159f2dd45e5SAndreas Jaekel {
160f2dd45e5SAndreas Jaekel 	zev_znode_close_after_update_t *rec =
161f2dd45e5SAndreas Jaekel 	    (zev_znode_close_after_update_t *)buf;
162f2dd45e5SAndreas Jaekel 	time_t op_time = rec->op_time;
163f2dd45e5SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
164f2dd45e5SAndreas Jaekel 
165f2dd45e5SAndreas Jaekel 	printf("%s %s: guid=%llu file=%llu.%llu\n",
166f2dd45e5SAndreas Jaekel 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
167f2dd45e5SAndreas Jaekel 	       rec->guid,
168f2dd45e5SAndreas Jaekel 	       rec->file.ino, rec->file.gen);
169f2dd45e5SAndreas Jaekel }
170f2dd45e5SAndreas Jaekel 
171f2dd45e5SAndreas Jaekel static void
172f2dd45e5SAndreas Jaekel zev_print_znode_create(char *buf)
173f2dd45e5SAndreas Jaekel {
174f2dd45e5SAndreas Jaekel 	zev_znode_create_t *rec = (zev_znode_create_t *)buf;
175f2dd45e5SAndreas Jaekel 	time_t op_time = rec->op_time;
176f2dd45e5SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
177f2dd45e5SAndreas Jaekel 
17835d4e8ddSAndreas Jaekel 	printf("%s %s: guid=%llu parent=%llu.%llu file=%llu.%llu "
17935d4e8ddSAndreas Jaekel 	       "file.mtime=%llu, parent.mtime=%llu, name='%s'\n",
180f2dd45e5SAndreas Jaekel 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
181f2dd45e5SAndreas Jaekel 	       rec->guid,
182f2dd45e5SAndreas Jaekel 	       rec->parent.ino, rec->parent.gen,
183f2dd45e5SAndreas Jaekel 	       rec->file.ino, rec->file.gen,
18435d4e8ddSAndreas Jaekel 	       rec->file.mtime, rec->parent.mtime,
185f2dd45e5SAndreas Jaekel 	       ZEV_NAME(rec));
186f2dd45e5SAndreas Jaekel }
187f2dd45e5SAndreas Jaekel 
188f2dd45e5SAndreas Jaekel static void
189f2dd45e5SAndreas Jaekel zev_print_znode_mkdir(char *buf)
190f2dd45e5SAndreas Jaekel {
191f2dd45e5SAndreas Jaekel 	zev_print_znode_create(buf);
192f2dd45e5SAndreas Jaekel }
193f2dd45e5SAndreas Jaekel 
194f2dd45e5SAndreas Jaekel static void
195f2dd45e5SAndreas Jaekel zev_print_znode_make_xattr_dir(char *buf)
196f2dd45e5SAndreas Jaekel {
197f2dd45e5SAndreas Jaekel 	zev_print_znode_create(buf);
198f2dd45e5SAndreas Jaekel }
199f2dd45e5SAndreas Jaekel 
200f2dd45e5SAndreas Jaekel static void
201f2dd45e5SAndreas Jaekel zev_print_znode_remove(char *buf)
202f2dd45e5SAndreas Jaekel {
203f2dd45e5SAndreas Jaekel 	zev_znode_remove_t *rec = (zev_znode_remove_t *)buf;
204f2dd45e5SAndreas Jaekel 	time_t op_time = rec->op_time;
205f2dd45e5SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
206f2dd45e5SAndreas Jaekel 
20797dcf88dSAndreas Jaekel 	printf("%s %s: guid=%llu parent=%llu.%llu file.mtime=%llu name='%s'\n",
208f2dd45e5SAndreas Jaekel 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
209f2dd45e5SAndreas Jaekel 	       rec->guid,
210f2dd45e5SAndreas Jaekel 	       rec->parent.ino, rec->parent.gen,
21197dcf88dSAndreas Jaekel 	       rec->file.mtime,
212f2dd45e5SAndreas Jaekel 	       ZEV_NAME(rec));
213f2dd45e5SAndreas Jaekel }
214f2dd45e5SAndreas Jaekel 
215f2dd45e5SAndreas Jaekel static void
216f2dd45e5SAndreas Jaekel zev_print_znode_rmdir(char *buf)
217f2dd45e5SAndreas Jaekel {
218f2dd45e5SAndreas Jaekel 	zev_print_znode_remove(buf);
219f2dd45e5SAndreas Jaekel }
220f2dd45e5SAndreas Jaekel 
221f2dd45e5SAndreas Jaekel static void
222f2dd45e5SAndreas Jaekel zev_print_znode_link(char *buf)
223f2dd45e5SAndreas Jaekel {
224f2dd45e5SAndreas Jaekel 	zev_znode_link_t *rec = (zev_znode_link_t *)buf;
225f2dd45e5SAndreas Jaekel 	time_t op_time = rec->op_time;
226f2dd45e5SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
227f2dd45e5SAndreas Jaekel 
228a01b300aSAndreas Jaekel 	printf("%s %s: parent=%llu.%llu file=%llu.%llu "
229a01b300aSAndreas Jaekel 	       "file.ctime=%llu parent.ctime=%llu name='%s'\n",
230f2dd45e5SAndreas Jaekel 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
231f2dd45e5SAndreas Jaekel 	       rec->parent.ino, rec->parent.gen,
232f2dd45e5SAndreas Jaekel 	       rec->file.ino, rec->file.gen,
233a01b300aSAndreas Jaekel 	       rec->file.ctime, rec->parent.ctime,
234f2dd45e5SAndreas Jaekel 	       ZEV_NAME(rec));
235f2dd45e5SAndreas Jaekel 	printf("links: %d\n", rec->file.links);
236f2dd45e5SAndreas Jaekel }
237f2dd45e5SAndreas Jaekel 
238f2dd45e5SAndreas Jaekel static void
239f2dd45e5SAndreas Jaekel zev_print_znode_symlink(char *buf)
240f2dd45e5SAndreas Jaekel {
241f2dd45e5SAndreas Jaekel 	zev_znode_symlink_t *rec = (zev_znode_symlink_t *)buf;
242f2dd45e5SAndreas Jaekel 	time_t op_time = rec->op_time;
243f2dd45e5SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
244f2dd45e5SAndreas Jaekel 
245f2dd45e5SAndreas Jaekel 	printf("%s %s: parent=%llu.%llu file=%llu.%llu name='%s' link='%s'\n",
246f2dd45e5SAndreas Jaekel 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
247f2dd45e5SAndreas Jaekel 	       rec->parent.ino, rec->parent.gen,
248f2dd45e5SAndreas Jaekel 	       rec->file.ino, rec->file.gen,
249f2dd45e5SAndreas Jaekel 	       ZEV_NAME(rec),
250f2dd45e5SAndreas Jaekel 	       ZEV_LINK(rec));
251f2dd45e5SAndreas Jaekel }
252f2dd45e5SAndreas Jaekel 
253f2dd45e5SAndreas Jaekel static void
254f2dd45e5SAndreas Jaekel zev_print_znode_rename(char *buf)
255f2dd45e5SAndreas Jaekel {
256f2dd45e5SAndreas Jaekel 	zev_znode_rename_t *rec = (zev_znode_rename_t *)buf;
257f2dd45e5SAndreas Jaekel 	time_t op_time = rec->op_time;
258f2dd45e5SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
259f2dd45e5SAndreas Jaekel 
260f2dd45e5SAndreas Jaekel 	printf("%s %s: srcdir=%llu.%llu dstdir=%llu.%llu file=%llu.%llu "
26135d4e8ddSAndreas Jaekel 	       "file.mtime=%llu, file.ctime=%llu, srcdir.mtime=%llu, "
26235d4e8ddSAndreas Jaekel 	       "srcdir.ctime=%llu, dstdir.mtime=%llu, dstdir.ctime=%llu, "
263f2dd45e5SAndreas Jaekel 	       "srcname='%s' dstname='%s'\n",
264f2dd45e5SAndreas Jaekel 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
265f2dd45e5SAndreas Jaekel 	       rec->srcdir.ino, rec->srcdir.gen,
266f2dd45e5SAndreas Jaekel 	       rec->dstdir.ino, rec->dstdir.gen,
267f2dd45e5SAndreas Jaekel 	       rec->file.ino, rec->file.gen,
26835d4e8ddSAndreas Jaekel 	       rec->file.mtime, rec->file.ctime,
26935d4e8ddSAndreas Jaekel 	       rec->srcdir.mtime, rec->srcdir.ctime,
27035d4e8ddSAndreas Jaekel 	       rec->dstdir.mtime, rec->dstdir.ctime,
271f2dd45e5SAndreas Jaekel 	       ZEV_SRCNAME(rec),
272f2dd45e5SAndreas Jaekel 	       ZEV_DSTNAME(rec));
273f2dd45e5SAndreas Jaekel }
274f2dd45e5SAndreas Jaekel 
275f2dd45e5SAndreas Jaekel static void
276f2dd45e5SAndreas Jaekel zev_print_znode_write(char *buf)
277f2dd45e5SAndreas Jaekel {
278f2dd45e5SAndreas Jaekel 	zev_znode_write_t *rec = (zev_znode_write_t *)buf;
279f2dd45e5SAndreas Jaekel 	time_t op_time = rec->op_time;
280f2dd45e5SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
281f2dd45e5SAndreas Jaekel 
282f2dd45e5SAndreas Jaekel 	printf("%s %s: file=%llu.%llu offset=%llu length=%llu\n",
283f2dd45e5SAndreas Jaekel 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
284f2dd45e5SAndreas Jaekel 	       rec->file.ino, rec->file.gen,
285f2dd45e5SAndreas Jaekel 	       rec->offset, rec->length);
286f2dd45e5SAndreas Jaekel }
287f2dd45e5SAndreas Jaekel 
288f2dd45e5SAndreas Jaekel static void
289f2dd45e5SAndreas Jaekel zev_print_znode_truncate(char *buf)
290f2dd45e5SAndreas Jaekel {
291f2dd45e5SAndreas Jaekel 	zev_print_znode_write(buf);
292f2dd45e5SAndreas Jaekel }
293f2dd45e5SAndreas Jaekel 
294f2dd45e5SAndreas Jaekel static void
295f2dd45e5SAndreas Jaekel zev_print_znode_setattr(char *buf)
296f2dd45e5SAndreas Jaekel {
297f2dd45e5SAndreas Jaekel 	zev_znode_setattr_t *rec = (zev_znode_setattr_t *)buf;
298f2dd45e5SAndreas Jaekel 	time_t op_time = rec->op_time;
299f2dd45e5SAndreas Jaekel 	char *ct = ctime(&op_time); ct[24] = '\0';
300f2dd45e5SAndreas Jaekel 
30135d4e8ddSAndreas Jaekel 	printf("%s %s: file=%llu.%llu mtime=%llu\n",
302f2dd45e5SAndreas Jaekel 	       ct, zev_op_name[rec->op - ZEV_OP_MIN],
30335d4e8ddSAndreas Jaekel 	       rec->file.ino, rec->file.gen, rec->file.mtime);
304f2dd45e5SAndreas Jaekel }
305f2dd45e5SAndreas Jaekel 
306f2dd45e5SAndreas Jaekel static void
307f2dd45e5SAndreas Jaekel zev_print_znode_acl(char *buf)
308f2dd45e5SAndreas Jaekel {
309f2dd45e5SAndreas Jaekel 	zev_print_znode_setattr(buf);
310f2dd45e5SAndreas Jaekel }
311f2dd45e5SAndreas Jaekel 
312f2dd45e5SAndreas Jaekel static void
313aafc540fSAndreas Jaekel zev_print_event(char *buf, int len)
314aafc540fSAndreas Jaekel {
315f2dd45e5SAndreas Jaekel 	int record_len;
316f2dd45e5SAndreas Jaekel 	int op;
317aafc540fSAndreas Jaekel 
318f2dd45e5SAndreas Jaekel 	record_len = *(uint32_t *)buf;
319f2dd45e5SAndreas Jaekel 	if (record_len != len) {
320f2dd45e5SAndreas Jaekel 		fprintf(stderr, "record length mismatch: got %d, expected %d\n",
321f2dd45e5SAndreas Jaekel 		        record_len, len);
322aafc540fSAndreas Jaekel 		exit(1);
323aafc540fSAndreas Jaekel 	}
324f2dd45e5SAndreas Jaekel 	op = *((uint32_t *)buf + 1);
325aafc540fSAndreas Jaekel 	if (op < ZEV_OP_MIN || op > ZEV_OP_MAX) {
326f2dd45e5SAndreas Jaekel 		fprintf(stderr, "unknown op code: %d\n", op);
327aafc540fSAndreas Jaekel 		exit(1);
328aafc540fSAndreas Jaekel 	}
329f2dd45e5SAndreas Jaekel 	switch (op) {
330f2dd45e5SAndreas Jaekel 	case ZEV_OP_ERROR:
331f2dd45e5SAndreas Jaekel 		zev_print_error(buf);
332aafc540fSAndreas Jaekel 		break;
333888fea18SAndreas Jaekel 	case ZEV_OP_MARK:
334888fea18SAndreas Jaekel 		zev_print_mark(buf);
335888fea18SAndreas Jaekel 		break;
336f2dd45e5SAndreas Jaekel 	case ZEV_OP_ZFS_MOUNT:
337f2dd45e5SAndreas Jaekel 		zev_print_zfs_mount(buf);
338aafc540fSAndreas Jaekel 		break;
339f2dd45e5SAndreas Jaekel 	case ZEV_OP_ZFS_UMOUNT:
340f2dd45e5SAndreas Jaekel 		zev_print_zfs_umount(buf);
341aafc540fSAndreas Jaekel 		break;
342f2dd45e5SAndreas Jaekel 	case ZEV_OP_ZVOL_TRUNCATE:
343f2dd45e5SAndreas Jaekel 		zev_print_zvol_truncate(buf);
344aafc540fSAndreas Jaekel 		break;
345f2dd45e5SAndreas Jaekel 	case ZEV_OP_ZVOL_WRITE:
346f2dd45e5SAndreas Jaekel 		zev_print_zvol_write(buf);
347f2dd45e5SAndreas Jaekel 		break;
348f2dd45e5SAndreas Jaekel 	case ZEV_OP_ZNODE_CLOSE_AFTER_UPDATE:
349f2dd45e5SAndreas Jaekel 		zev_print_znode_close_after_update(buf);
350f2dd45e5SAndreas Jaekel 		break;
351f2dd45e5SAndreas Jaekel 	case ZEV_OP_ZNODE_CREATE:
352f2dd45e5SAndreas Jaekel 		zev_print_znode_create(buf);
353f2dd45e5SAndreas Jaekel 		break;
354f2dd45e5SAndreas Jaekel 	case ZEV_OP_ZNODE_MKDIR:
355f2dd45e5SAndreas Jaekel 		zev_print_znode_mkdir(buf);
356f2dd45e5SAndreas Jaekel 		break;
357f2dd45e5SAndreas Jaekel 	case ZEV_OP_ZNODE_MAKE_XATTR_DIR:
358f2dd45e5SAndreas Jaekel 		zev_print_znode_make_xattr_dir(buf);
359f2dd45e5SAndreas Jaekel 		break;
360f2dd45e5SAndreas Jaekel 	case ZEV_OP_ZNODE_REMOVE:
361f2dd45e5SAndreas Jaekel 		zev_print_znode_remove(buf);
362f2dd45e5SAndreas Jaekel 		break;
363f2dd45e5SAndreas Jaekel 	case ZEV_OP_ZNODE_RMDIR:
364f2dd45e5SAndreas Jaekel 		zev_print_znode_rmdir(buf);
365f2dd45e5SAndreas Jaekel 		break;
366f2dd45e5SAndreas Jaekel 	case ZEV_OP_ZNODE_LINK:
367f2dd45e5SAndreas Jaekel 		zev_print_znode_link(buf);
368f2dd45e5SAndreas Jaekel 		break;
369f2dd45e5SAndreas Jaekel 	case ZEV_OP_ZNODE_SYMLINK:
370f2dd45e5SAndreas Jaekel 		zev_print_znode_symlink(buf);
371f2dd45e5SAndreas Jaekel 		break;
372f2dd45e5SAndreas Jaekel 	case ZEV_OP_ZNODE_RENAME:
373f2dd45e5SAndreas Jaekel 		zev_print_znode_rename(buf);
374f2dd45e5SAndreas Jaekel 		break;
375f2dd45e5SAndreas Jaekel 	case ZEV_OP_ZNODE_WRITE:
376f2dd45e5SAndreas Jaekel 		zev_print_znode_write(buf);
377f2dd45e5SAndreas Jaekel 		break;
378f2dd45e5SAndreas Jaekel 	case ZEV_OP_ZNODE_TRUNCATE:
379f2dd45e5SAndreas Jaekel 		zev_print_znode_truncate(buf);
380f2dd45e5SAndreas Jaekel 		break;
381f2dd45e5SAndreas Jaekel 	case ZEV_OP_ZNODE_SETATTR:
382f2dd45e5SAndreas Jaekel 		zev_print_znode_setattr(buf);
383f2dd45e5SAndreas Jaekel 		break;
384f2dd45e5SAndreas Jaekel 	case ZEV_OP_ZNODE_ACL:
385f2dd45e5SAndreas Jaekel 		zev_print_znode_acl(buf);
386aafc540fSAndreas Jaekel 		break;
387aafc540fSAndreas Jaekel 	default:
388f2dd45e5SAndreas Jaekel 		fprintf(stderr, "unhandled op code: %d\n", op);
389aafc540fSAndreas Jaekel 		exit(1);
390aafc540fSAndreas Jaekel 	}
391aafc540fSAndreas Jaekel }
392aafc540fSAndreas Jaekel 
393add9520fSAndreas Jaekel static int
394*6a6a51eeSAndreas Jaekel zev_poll_events(int fd, int create_tmp_queue)
395a18c35b9SAndreas Jaekel {
396a18c35b9SAndreas Jaekel 	struct pollfd pfd[1];
397a18c35b9SAndreas Jaekel 	int ret;
398aafc540fSAndreas Jaekel 	char buf[4096];
399d979f56cSAndreas Jaekel 	zev_event_t *ev;
400d979f56cSAndreas Jaekel 	int off = 0;
401add9520fSAndreas Jaekel 	zev_ioctl_add_queue_t aq;
402add9520fSAndreas Jaekel 	int q_fd;
403add9520fSAndreas Jaekel 
404*6a6a51eeSAndreas Jaekel 	if (create_tmp_queue) {
405add9520fSAndreas Jaekel 		aq.zev_max_queue_len = 0;
406add9520fSAndreas Jaekel 		aq.zev_flags = ZEV_FL_BLOCK_WHILE_QUEUE_FULL;
407add9520fSAndreas Jaekel 		snprintf(aq.zev_name, ZEV_MAX_QUEUE_NAME_LEN,
408add9520fSAndreas Jaekel 			 "zevadm.%ld.%ld", time(NULL), getpid());
409add9520fSAndreas Jaekel 		aq.zev_namelen = strlen(aq.zev_name);
410add9520fSAndreas Jaekel 
411add9520fSAndreas Jaekel 		if (ioctl(fd, ZEV_IOC_ADD_QUEUE, &aq)) {
412add9520fSAndreas Jaekel 			perror("adding temporary queue failed");
413add9520fSAndreas Jaekel 			return (EXIT_FAILURE);
414add9520fSAndreas Jaekel 		}
415add9520fSAndreas Jaekel 
416*6a6a51eeSAndreas Jaekel 		snprintf(buf, sizeof(buf),
417*6a6a51eeSAndreas Jaekel 		         "/devices/pseudo/zev@0:%s", aq.zev_name);
418add9520fSAndreas Jaekel 		q_fd = open(buf, O_RDONLY);
419add9520fSAndreas Jaekel 		if (q_fd < 0) {
420add9520fSAndreas Jaekel 			perror("opening queue device failed");
421add9520fSAndreas Jaekel 			return (EXIT_FAILURE);
422add9520fSAndreas Jaekel 		}
423*6a6a51eeSAndreas Jaekel 	} else {
424*6a6a51eeSAndreas Jaekel 		q_fd = fd;
425*6a6a51eeSAndreas Jaekel 	}
426add9520fSAndreas Jaekel 
427a18c35b9SAndreas Jaekel 	while (1) {
428add9520fSAndreas Jaekel 		pfd[0].fd = q_fd;
429a18c35b9SAndreas Jaekel 		pfd[0].events = POLLIN;
430a18c35b9SAndreas Jaekel 		ret = poll(pfd, 1, 1000);
431a18c35b9SAndreas Jaekel 		if (ret < 0) {
432a18c35b9SAndreas Jaekel 			perror("poll failed");
433*6a6a51eeSAndreas Jaekel 			close(q_fd);
434add9520fSAndreas Jaekel 			return(EXIT_FAILURE);
435a18c35b9SAndreas Jaekel 		}
436a18c35b9SAndreas Jaekel 		if (!(pfd[0].revents & POLLIN))
437a18c35b9SAndreas Jaekel 			continue;
438a18c35b9SAndreas Jaekel 		/* data available */
439add9520fSAndreas Jaekel 		ret = read(q_fd, buf, sizeof(buf));
440a18c35b9SAndreas Jaekel 		if (ret < 0) {
441a18c35b9SAndreas Jaekel 			perror("read failed");
442*6a6a51eeSAndreas Jaekel 			close(q_fd);
443add9520fSAndreas Jaekel 			return(EXIT_FAILURE);
444a18c35b9SAndreas Jaekel 		}
445a18c35b9SAndreas Jaekel 		if (ret == 0)
446a18c35b9SAndreas Jaekel 			continue;
447d979f56cSAndreas Jaekel 		while (ret > off) {
448d979f56cSAndreas Jaekel 			ev = (zev_event_t *)(buf + off);
449d979f56cSAndreas Jaekel 			zev_print_event(buf + off, ev->header.record_len);
450d979f56cSAndreas Jaekel 			off += ev->header.record_len;
451d979f56cSAndreas Jaekel 		}
452149d0affSAndreas Jaekel 		off = 0;
453a18c35b9SAndreas Jaekel 	}
454*6a6a51eeSAndreas Jaekel 	if (create_tmp_queue)
455add9520fSAndreas Jaekel 		close(q_fd);
456add9520fSAndreas Jaekel 	return EXIT_SUCCESS;
457a18c35b9SAndreas Jaekel }
458a18c35b9SAndreas Jaekel 
459a18c35b9SAndreas Jaekel static void
460a18c35b9SAndreas Jaekel usage(char *progname)
461a18c35b9SAndreas Jaekel {
462add9520fSAndreas Jaekel 	fprintf(stderr, "usage: %s [-d <dev>] [options]\n", progname);
463add9520fSAndreas Jaekel 	fprintf(stderr, "\n");
464add9520fSAndreas Jaekel 	fprintf(stderr, " Status information:\n");
465a18c35b9SAndreas Jaekel 	fprintf(stderr, "   -s                   show zev statistics\n");
466a18c35b9SAndreas Jaekel 	fprintf(stderr, "   -p                   poll for ZFS events\n");
467add9520fSAndreas Jaekel 	fprintf(stderr, "   -D                   print zev module debug "
468add9520fSAndreas Jaekel 	        "information\n");
469add9520fSAndreas Jaekel 	fprintf(stderr, "\n");
470add9520fSAndreas Jaekel 	fprintf(stderr, " Tune zev module settings:\n");
471add9520fSAndreas Jaekel 	fprintf(stderr, "   -Q <bytes>           set maximum event queue "
472add9520fSAndreas Jaekel 	        "length\n");
473add9520fSAndreas Jaekel 	fprintf(stderr, "   -m <pool>            mute pool, no events for "
474add9520fSAndreas Jaekel 	        "this pool\n");
475a18c35b9SAndreas Jaekel 	fprintf(stderr, "   -M <pool>            unmute pool\n");
476add9520fSAndreas Jaekel 	fprintf(stderr, "\n");
477add9520fSAndreas Jaekel 	fprintf(stderr, " Queue management:\n");
478add9520fSAndreas Jaekel 	fprintf(stderr, "   -l                   list queues\n");
479*6a6a51eeSAndreas Jaekel 	fprintf(stderr, "   -a <name>            add non-blocking queue\n");
480*6a6a51eeSAndreas Jaekel 	fprintf(stderr, "   -A <name>            add blocking queue\n");
481add9520fSAndreas Jaekel 	fprintf(stderr, "   -r <name>            remove queue\n");
482add9520fSAndreas Jaekel 	fprintf(stderr, "   -b <name>            make queue non-blocking "
483add9520fSAndreas Jaekel 	        "(default)\n");
484add9520fSAndreas Jaekel 	fprintf(stderr, "   -B <name>            make queue block when full\n");
485add9520fSAndreas Jaekel 	fprintf(stderr, "   -P <name>            display queue properties\n");
486*6a6a51eeSAndreas Jaekel 	fprintf(stderr, "   -L <name> <bytes>    set maximum event queue "
487add9520fSAndreas Jaekel 	        "length\n");
488add9520fSAndreas Jaekel 	fprintf(stderr, "   -t <name> <bytes>    set queue length poll "
489add9520fSAndreas Jaekel 	        "throttle\n");
490add9520fSAndreas Jaekel 	fprintf(stderr, "\n");
491add9520fSAndreas Jaekel 	fprintf(stderr, " Other options:\n");
492add9520fSAndreas Jaekel 	fprintf(stderr, "   -d <dev>             non-default device file. "
493add9520fSAndreas Jaekel 	        "('%s')\n", ZEV_DEVICE);
494*6a6a51eeSAndreas Jaekel 	fprintf(stderr, "   -q <name>            use device file for this "
495*6a6a51eeSAndreas Jaekel 		"queue name\n");
496888fea18SAndreas Jaekel 	fprintf(stderr, "   -k <guid>:<payload>  queue mark event\n");
497a18c35b9SAndreas Jaekel 	exit (EXIT_FAILURE);
498a18c35b9SAndreas Jaekel }
499a18c35b9SAndreas Jaekel 
500a18c35b9SAndreas Jaekel static int
501*6a6a51eeSAndreas Jaekel zev_add_queue(int fd, char *arg, int blocking)
502a18c35b9SAndreas Jaekel {
503add9520fSAndreas Jaekel 	zev_ioctl_add_queue_t aq;
504add9520fSAndreas Jaekel 	int namelen;
505a18c35b9SAndreas Jaekel 
506add9520fSAndreas Jaekel 	namelen = strlen(arg);
507add9520fSAndreas Jaekel 	if (namelen > ZEV_MAX_QUEUE_NAME_LEN) {
508add9520fSAndreas Jaekel 		fprintf(stderr, "queue name too long: %s\n", arg);
509a18c35b9SAndreas Jaekel 		return (EXIT_FAILURE);
510a18c35b9SAndreas Jaekel 	}
511add9520fSAndreas Jaekel 
512add9520fSAndreas Jaekel 	aq.zev_namelen = namelen;
513add9520fSAndreas Jaekel 	strcpy(aq.zev_name, arg);
514*6a6a51eeSAndreas Jaekel 	aq.zev_flags = ZEV_FL_PERSISTENT;
515*6a6a51eeSAndreas Jaekel 	if (blocking) {
516*6a6a51eeSAndreas Jaekel 		aq.zev_flags |= ZEV_FL_BLOCK_WHILE_QUEUE_FULL;
517*6a6a51eeSAndreas Jaekel 		aq.zev_max_queue_len = ZEV_MAX_QUEUE_LEN;
518*6a6a51eeSAndreas Jaekel 	} else {
519add9520fSAndreas Jaekel 		aq.zev_max_queue_len = (1024 * 1024);
520*6a6a51eeSAndreas Jaekel 	}
521add9520fSAndreas Jaekel 
522add9520fSAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_ADD_QUEUE, &aq)) {
523add9520fSAndreas Jaekel 		perror("adding queue failed");
524a18c35b9SAndreas Jaekel 		return (EXIT_FAILURE);
525a18c35b9SAndreas Jaekel 	}
526a18c35b9SAndreas Jaekel 	return (0);
527a18c35b9SAndreas Jaekel }
528a18c35b9SAndreas Jaekel 
529a18c35b9SAndreas Jaekel static int
530add9520fSAndreas Jaekel zev_remove_queue(int fd, char *arg)
531fec460f8SAndreas Jaekel {
532add9520fSAndreas Jaekel 	zev_ioctl_remove_queue_t aq;
533add9520fSAndreas Jaekel 	int namelen;
534fec460f8SAndreas Jaekel 
535add9520fSAndreas Jaekel 	namelen = strlen(arg);
536add9520fSAndreas Jaekel 	if (namelen > ZEV_MAX_QUEUE_NAME_LEN) {
537add9520fSAndreas Jaekel 		fprintf(stderr, "queue name too long: %s\n", arg);
538fec460f8SAndreas Jaekel 		return (EXIT_FAILURE);
539fec460f8SAndreas Jaekel 	}
540add9520fSAndreas Jaekel 
541*6a6a51eeSAndreas Jaekel 	aq.zev_queue_name.zev_namelen = namelen;
542*6a6a51eeSAndreas Jaekel 	strcpy(aq.zev_queue_name.zev_name, arg);
543add9520fSAndreas Jaekel 
544add9520fSAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_REMOVE_QUEUE, &aq)) {
545add9520fSAndreas Jaekel 		perror("removing queue failed");
546add9520fSAndreas Jaekel 		return (EXIT_FAILURE);
547add9520fSAndreas Jaekel 	}
548add9520fSAndreas Jaekel 	return (0);
549add9520fSAndreas Jaekel }
550add9520fSAndreas Jaekel 
551add9520fSAndreas Jaekel static int
552add9520fSAndreas Jaekel zev_set_global_max_queue_len(int fd, char *arg)
553add9520fSAndreas Jaekel {
554add9520fSAndreas Jaekel 	uint64_t maxqueuelen;
555add9520fSAndreas Jaekel 
556add9520fSAndreas Jaekel 	errno = 0;
557add9520fSAndreas Jaekel 	maxqueuelen = strtol(arg, (char **)NULL, 10);
558add9520fSAndreas Jaekel 	if (errno) {
559add9520fSAndreas Jaekel 		fprintf(stderr, "invalid queue length parameter: %s\n", arg);
560add9520fSAndreas Jaekel 		return (EXIT_FAILURE);
561add9520fSAndreas Jaekel 	}
562add9520fSAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_SET_MAX_QUEUE_LEN, &maxqueuelen)) {
563add9520fSAndreas Jaekel 		perror("setting max queue length failed");
564fec460f8SAndreas Jaekel 		return (EXIT_FAILURE);
565fec460f8SAndreas Jaekel 	}
566fec460f8SAndreas Jaekel 	return (0);
567fec460f8SAndreas Jaekel }
568fec460f8SAndreas Jaekel 
569fec460f8SAndreas Jaekel static int
570a18c35b9SAndreas Jaekel zev_mute_unmute_impl(int fd, char *poolname, int mute)
571a18c35b9SAndreas Jaekel {
572a18c35b9SAndreas Jaekel 	zev_ioctl_poolarg_t pa;
573a18c35b9SAndreas Jaekel 	int len;
574a18c35b9SAndreas Jaekel 	int op = mute ? ZEV_IOC_MUTE_POOL : ZEV_IOC_UNMUTE_POOL;
575a18c35b9SAndreas Jaekel 	len = strlen(poolname);
576a18c35b9SAndreas Jaekel 	if (len <= 0 || len >= sizeof(pa.zev_poolname)) {
577a18c35b9SAndreas Jaekel 		fprintf(stderr, "invalid poolname: %s\n", poolname);
578a18c35b9SAndreas Jaekel 		return (EXIT_FAILURE);
579a18c35b9SAndreas Jaekel 	}
580a18c35b9SAndreas Jaekel 	strcpy(pa.zev_poolname, poolname);
581a18c35b9SAndreas Jaekel 	pa.zev_poolname_len = len;
582a18c35b9SAndreas Jaekel 	if (ioctl(fd, op, &pa)) {
583a18c35b9SAndreas Jaekel 		perror("muting pool data failed");
584a18c35b9SAndreas Jaekel 		return (EXIT_FAILURE);
585a18c35b9SAndreas Jaekel 	}
586a18c35b9SAndreas Jaekel 	return (0);
587a18c35b9SAndreas Jaekel }
588a18c35b9SAndreas Jaekel 
589a18c35b9SAndreas Jaekel int
590a18c35b9SAndreas Jaekel zev_mute_pool(int fd, char *poolname)
591a18c35b9SAndreas Jaekel {
592a18c35b9SAndreas Jaekel 	return zev_mute_unmute_impl(fd, poolname, 1);
593a18c35b9SAndreas Jaekel }
594a18c35b9SAndreas Jaekel 
595a18c35b9SAndreas Jaekel int
596a18c35b9SAndreas Jaekel zev_unmute_pool(int fd, char *poolname)
597a18c35b9SAndreas Jaekel {
598a18c35b9SAndreas Jaekel 	return zev_mute_unmute_impl(fd, poolname, 0);
599a18c35b9SAndreas Jaekel }
600a18c35b9SAndreas Jaekel 
601888fea18SAndreas Jaekel static int
602add9520fSAndreas Jaekel zev_debug_info(int fd)
603add9520fSAndreas Jaekel {
604add9520fSAndreas Jaekel 	zev_ioctl_debug_info_t di;
605add9520fSAndreas Jaekel 
606add9520fSAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_GET_DEBUG_INFO, &di)) {
607add9520fSAndreas Jaekel 		perror("getting zev debug info failed");
608add9520fSAndreas Jaekel 		return (EXIT_FAILURE);
609add9520fSAndreas Jaekel 	}
610add9520fSAndreas Jaekel 
611add9520fSAndreas Jaekel 	printf("memory allocated: %llu bytes\n", di.zev_memory_allocated);
612add9520fSAndreas Jaekel 	return 0;
613add9520fSAndreas Jaekel }
614add9520fSAndreas Jaekel 
615add9520fSAndreas Jaekel static int
616888fea18SAndreas Jaekel zev_mark(int fd, char *arg)
617888fea18SAndreas Jaekel {
618888fea18SAndreas Jaekel 	zev_ioctl_mark_t *mark;
619888fea18SAndreas Jaekel 	uint64_t guid;
620888fea18SAndreas Jaekel 	int len;
621888fea18SAndreas Jaekel 	char *p;
622888fea18SAndreas Jaekel 
623888fea18SAndreas Jaekel 	p = strchr(arg, ':');
624888fea18SAndreas Jaekel 	if (!p) {
625888fea18SAndreas Jaekel 		fprintf(stderr, "expected value is <guid>:<payload>, "
626888fea18SAndreas Jaekel 		        "e.g. '123:hello'\n");
627888fea18SAndreas Jaekel 		exit (EXIT_FAILURE);
628888fea18SAndreas Jaekel 	}
629888fea18SAndreas Jaekel 	*p = '\n';
630888fea18SAndreas Jaekel 	p++;
631888fea18SAndreas Jaekel 
632888fea18SAndreas Jaekel 	errno = 0;
633add9520fSAndreas Jaekel 	guid = strtoll(arg, (char **)NULL, 10);
634888fea18SAndreas Jaekel 	if (errno) {
635888fea18SAndreas Jaekel 		fprintf(stderr, "guid must be a number.\n");
636888fea18SAndreas Jaekel 		exit (EXIT_FAILURE);
637888fea18SAndreas Jaekel 	}
638888fea18SAndreas Jaekel 
639888fea18SAndreas Jaekel 	len = strlen(p);
640888fea18SAndreas Jaekel 
641888fea18SAndreas Jaekel 	mark = malloc(sizeof(*mark) + len + 1);
642888fea18SAndreas Jaekel 	if (!mark) {
643888fea18SAndreas Jaekel 		fprintf(stderr, "can't allocate mark structure: %s\n",
644888fea18SAndreas Jaekel 		        strerror(errno));
645888fea18SAndreas Jaekel 		exit (EXIT_FAILURE);
646888fea18SAndreas Jaekel 	}
647888fea18SAndreas Jaekel 	mark->zev_guid = guid;
648888fea18SAndreas Jaekel 	mark->zev_mark_id = 0;
649888fea18SAndreas Jaekel 	mark->zev_payload_len = len;
650888fea18SAndreas Jaekel 	strcpy(ZEV_PAYLOAD(mark), p);
651888fea18SAndreas Jaekel 
652888fea18SAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_MARK, mark)) {
653888fea18SAndreas Jaekel 		perror("queueing mark failed");
654888fea18SAndreas Jaekel 		return (EXIT_FAILURE);
655888fea18SAndreas Jaekel 	}
656888fea18SAndreas Jaekel 
657888fea18SAndreas Jaekel 	printf("mark id: %lu\n", mark->zev_mark_id);
658888fea18SAndreas Jaekel 	return (0);
659888fea18SAndreas Jaekel }
660888fea18SAndreas Jaekel 
661add9520fSAndreas Jaekel static int
662add9520fSAndreas Jaekel zev_queue_blocking(int fd, char *arg, int block)
663add9520fSAndreas Jaekel {
664add9520fSAndreas Jaekel 	zev_ioctl_get_queue_properties_t gqp;
665add9520fSAndreas Jaekel 
666*6a6a51eeSAndreas Jaekel 	gqp.zev_queue_name.zev_namelen = strlen(arg);
667*6a6a51eeSAndreas Jaekel 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
668add9520fSAndreas Jaekel 		fprintf(stderr, "queue name too long.\n");
669add9520fSAndreas Jaekel 		return EXIT_FAILURE;
670add9520fSAndreas Jaekel 	}
671*6a6a51eeSAndreas Jaekel 	strcpy(gqp.zev_queue_name.zev_name, arg);
672add9520fSAndreas Jaekel 
673add9520fSAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
674add9520fSAndreas Jaekel 		perror("getting queue properties failed");
675add9520fSAndreas Jaekel 		return (EXIT_FAILURE);
676add9520fSAndreas Jaekel 	}
677add9520fSAndreas Jaekel 	if (block) {
678add9520fSAndreas Jaekel 		gqp.zev_flags |= ZEV_FL_BLOCK_WHILE_QUEUE_FULL;
679add9520fSAndreas Jaekel 	} else {
680add9520fSAndreas Jaekel 		gqp.zev_flags &= ~ZEV_FL_BLOCK_WHILE_QUEUE_FULL;
681add9520fSAndreas Jaekel 	}
682add9520fSAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) {
683add9520fSAndreas Jaekel 		perror("setting queue properties failed");
684add9520fSAndreas Jaekel 		return (EXIT_FAILURE);
685add9520fSAndreas Jaekel 	}
686add9520fSAndreas Jaekel 	return (0);
687add9520fSAndreas Jaekel }
688add9520fSAndreas Jaekel 
689add9520fSAndreas Jaekel static int
690add9520fSAndreas Jaekel zev_set_max_queue_len(int fd, char *arg, char *len)
691add9520fSAndreas Jaekel {
692add9520fSAndreas Jaekel 	zev_ioctl_get_queue_properties_t gqp;
693add9520fSAndreas Jaekel 
694add9520fSAndreas Jaekel 	if (!len) {
695add9520fSAndreas Jaekel 		fprintf(stderr, "queue size parameter missing.\n");
696add9520fSAndreas Jaekel 		return EXIT_FAILURE;
697add9520fSAndreas Jaekel 	}
698add9520fSAndreas Jaekel 
699*6a6a51eeSAndreas Jaekel 	gqp.zev_queue_name.zev_namelen = strlen(arg);
700*6a6a51eeSAndreas Jaekel 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
701add9520fSAndreas Jaekel 		fprintf(stderr, "queue name too long.\n");
702add9520fSAndreas Jaekel 		return EXIT_FAILURE;
703add9520fSAndreas Jaekel 	}
704*6a6a51eeSAndreas Jaekel 	strcpy(gqp.zev_queue_name.zev_name, arg);
705add9520fSAndreas Jaekel 
706add9520fSAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
707add9520fSAndreas Jaekel 		perror("getting queue properties failed");
708add9520fSAndreas Jaekel 		return (EXIT_FAILURE);
709add9520fSAndreas Jaekel 	}
710add9520fSAndreas Jaekel 	gqp.zev_max_queue_len = atol(len);
711add9520fSAndreas Jaekel 	if (gqp.zev_max_queue_len == 0 && strcmp("0", len)) {
712add9520fSAndreas Jaekel 		fprintf(stderr, "queue size parameter garbled.\n");
713add9520fSAndreas Jaekel 		return (EXIT_FAILURE);
714add9520fSAndreas Jaekel 	}
715add9520fSAndreas Jaekel 	if (gqp.zev_max_queue_len > ZEV_MAX_QUEUE_LEN) {
716add9520fSAndreas Jaekel 		fprintf(stderr, "queue size parameter out of bounds.\n");
717add9520fSAndreas Jaekel 		return (EXIT_FAILURE);
718add9520fSAndreas Jaekel 	}
719add9520fSAndreas Jaekel 
720add9520fSAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) {
721add9520fSAndreas Jaekel 		perror("setting queue properties failed");
722add9520fSAndreas Jaekel 		return (EXIT_FAILURE);
723add9520fSAndreas Jaekel 	}
724add9520fSAndreas Jaekel 	return (0);
725add9520fSAndreas Jaekel }
726add9520fSAndreas Jaekel 
727add9520fSAndreas Jaekel static int
728add9520fSAndreas Jaekel zev_set_poll_wakeup_queue_len(int fd, char *arg, char *len)
729add9520fSAndreas Jaekel {
730add9520fSAndreas Jaekel 	zev_ioctl_get_queue_properties_t gqp;
731add9520fSAndreas Jaekel 
732add9520fSAndreas Jaekel 	if (!len) {
733add9520fSAndreas Jaekel 		fprintf(stderr, "poll throttle parameter missing.\n");
734add9520fSAndreas Jaekel 		return EXIT_FAILURE;
735add9520fSAndreas Jaekel 	}
736add9520fSAndreas Jaekel 
737*6a6a51eeSAndreas Jaekel 	gqp.zev_queue_name.zev_namelen = strlen(arg);
738*6a6a51eeSAndreas Jaekel 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
739add9520fSAndreas Jaekel 		fprintf(stderr, "queue name too long.\n");
740add9520fSAndreas Jaekel 		return EXIT_FAILURE;
741add9520fSAndreas Jaekel 	}
742*6a6a51eeSAndreas Jaekel 	strcpy(gqp.zev_queue_name.zev_name, arg);
743add9520fSAndreas Jaekel 
744add9520fSAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
745add9520fSAndreas Jaekel 		perror("getting queue properties failed");
746add9520fSAndreas Jaekel 		return (EXIT_FAILURE);
747add9520fSAndreas Jaekel 	}
748add9520fSAndreas Jaekel 	gqp.zev_poll_wakeup_threshold = atol(len);
749add9520fSAndreas Jaekel 	if (gqp.zev_poll_wakeup_threshold == 0 && strcmp("0", len)) {
750add9520fSAndreas Jaekel 		fprintf(stderr, "poll throttle parameter garbled.\n");
751add9520fSAndreas Jaekel 		return (EXIT_FAILURE);
752add9520fSAndreas Jaekel 	}
753*6a6a51eeSAndreas Jaekel 	if (gqp.zev_poll_wakeup_threshold > ZEV_MAX_POLL_WAKEUP_QUEUE_LEN) {
754add9520fSAndreas Jaekel 		fprintf(stderr, "poll throttle parameter out of bounds.\n");
755add9520fSAndreas Jaekel 		return (EXIT_FAILURE);
756add9520fSAndreas Jaekel 	}
757add9520fSAndreas Jaekel 
758add9520fSAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_SET_QUEUE_PROPERTIES, &gqp)) {
759add9520fSAndreas Jaekel 		perror("setting queue properties failed");
760add9520fSAndreas Jaekel 		return (EXIT_FAILURE);
761add9520fSAndreas Jaekel 	}
762add9520fSAndreas Jaekel 	return (0);
763add9520fSAndreas Jaekel }
764add9520fSAndreas Jaekel 
765add9520fSAndreas Jaekel static int
766add9520fSAndreas Jaekel zev_queue_properties(int fd, char *arg)
767add9520fSAndreas Jaekel {
768add9520fSAndreas Jaekel 	zev_ioctl_get_queue_properties_t gqp;
769add9520fSAndreas Jaekel 
770*6a6a51eeSAndreas Jaekel 	gqp.zev_queue_name.zev_namelen = strlen(arg);
771*6a6a51eeSAndreas Jaekel 	if (gqp.zev_queue_name.zev_namelen > ZEV_MAX_QUEUE_NAME_LEN) {
772add9520fSAndreas Jaekel 		fprintf(stderr, "queue name too long.\n");
773add9520fSAndreas Jaekel 		return EXIT_FAILURE;
774add9520fSAndreas Jaekel 	}
775*6a6a51eeSAndreas Jaekel 	strcpy(gqp.zev_queue_name.zev_name, arg);
776add9520fSAndreas Jaekel 
777add9520fSAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
778add9520fSAndreas Jaekel 		perror("getting queue properties failed");
779add9520fSAndreas Jaekel 		return (EXIT_FAILURE);
780add9520fSAndreas Jaekel 	}
781add9520fSAndreas Jaekel 
782add9520fSAndreas Jaekel 	printf("queue        : %s\n", arg);
783add9520fSAndreas Jaekel 	printf("max size     : %" PRIu64 "\n", gqp.zev_max_queue_len);
784add9520fSAndreas Jaekel 	printf("poll throttle: %" PRIu64 "\n", gqp.zev_poll_wakeup_threshold);
785add9520fSAndreas Jaekel 	printf("persistent   : %s\n",
786add9520fSAndreas Jaekel 		gqp.zev_flags & ZEV_FL_PERSISTENT ? "yes" : "no");
787add9520fSAndreas Jaekel 	printf("blocking     : %s\n",
788add9520fSAndreas Jaekel 		gqp.zev_flags & ZEV_FL_BLOCK_WHILE_QUEUE_FULL ? "yes" : "no");
789add9520fSAndreas Jaekel 
790add9520fSAndreas Jaekel 	return (0);
791add9520fSAndreas Jaekel }
792add9520fSAndreas Jaekel 
793add9520fSAndreas Jaekel static int
794add9520fSAndreas Jaekel zev_list_queues(int fd)
795add9520fSAndreas Jaekel {
796add9520fSAndreas Jaekel 	zev_ioctl_get_queue_properties_t gqp;
797add9520fSAndreas Jaekel 	zev_ioctl_get_queue_list_t gql;
798add9520fSAndreas Jaekel 	zev_ioctl_get_queue_statistics_t gs;
799add9520fSAndreas Jaekel 	uint64_t	i;
800add9520fSAndreas Jaekel 	char		name[ZEV_MAX_QUEUE_NAME_LEN+1];
801add9520fSAndreas Jaekel 
802add9520fSAndreas Jaekel 	if (ioctl(fd, ZEV_IOC_GET_QUEUE_LIST, &gql)) {
803add9520fSAndreas Jaekel 		perror("getting queue list failed");
804add9520fSAndreas Jaekel 		return (EXIT_FAILURE);
805add9520fSAndreas Jaekel 	}
806add9520fSAndreas Jaekel 
807add9520fSAndreas Jaekel 	printf("Name                                     Size       "
808add9520fSAndreas Jaekel 	       "Max Size   Wakeup Per Block\n");
809add9520fSAndreas Jaekel 
810add9520fSAndreas Jaekel 	for (i=0; i<gql.zev_n_queues; i++) {
811add9520fSAndreas Jaekel 		strncpy(name, gql.zev_queue_name[i].zev_name,
812add9520fSAndreas Jaekel 		        ZEV_MAX_QUEUE_NAME_LEN);
813add9520fSAndreas Jaekel 		name[gql.zev_queue_name[i].zev_namelen] = '\0';
814add9520fSAndreas Jaekel 
815*6a6a51eeSAndreas Jaekel 		memcpy(gqp.zev_queue_name.zev_name,
816*6a6a51eeSAndreas Jaekel 		    gql.zev_queue_name[i].zev_name, ZEV_MAX_QUEUE_NAME_LEN);
817*6a6a51eeSAndreas Jaekel 		gqp.zev_queue_name.zev_namelen =
818*6a6a51eeSAndreas Jaekel 		    gql.zev_queue_name[i].zev_namelen;
819add9520fSAndreas Jaekel 
820add9520fSAndreas Jaekel 		if (ioctl(fd, ZEV_IOC_GET_QUEUE_PROPERTIES, &gqp)) {
821add9520fSAndreas Jaekel 			if (errno == ENOENT)
822add9520fSAndreas Jaekel 				continue;
823add9520fSAndreas Jaekel 			perror("getting queue properties failed");
824add9520fSAndreas Jaekel 			return (EXIT_FAILURE);
825add9520fSAndreas Jaekel 		}
826add9520fSAndreas Jaekel 
827*6a6a51eeSAndreas Jaekel 		memcpy(gs.zev_queue_name.zev_name,
828*6a6a51eeSAndreas Jaekel 		    gql.zev_queue_name[i].zev_name, ZEV_MAX_QUEUE_NAME_LEN);
829*6a6a51eeSAndreas Jaekel 		gs.zev_queue_name.zev_namelen =
830*6a6a51eeSAndreas Jaekel 		    gql.zev_queue_name[i].zev_namelen;
831add9520fSAndreas Jaekel 
832add9520fSAndreas Jaekel 		if (ioctl(fd, ZEV_IOC_GET_QUEUE_STATISTICS, &gs)) {
833add9520fSAndreas Jaekel 			if (errno == ENOENT)
834add9520fSAndreas Jaekel 				continue;
835add9520fSAndreas Jaekel 			perror("getting statistics data failed");
836add9520fSAndreas Jaekel 			return (EXIT_FAILURE);
837add9520fSAndreas Jaekel 		}
838add9520fSAndreas Jaekel 
839add9520fSAndreas Jaekel 		printf("%-40s %-10" PRIu64 " %-10" PRIu64 " %-6" PRIu64
840add9520fSAndreas Jaekel 		       " %-3s %-3s\n",
841add9520fSAndreas Jaekel 			name,
842add9520fSAndreas Jaekel 			gs.zev_statistics.zev_queue_len,
843add9520fSAndreas Jaekel 			gqp.zev_max_queue_len,
844add9520fSAndreas Jaekel 			gqp.zev_poll_wakeup_threshold,
845add9520fSAndreas Jaekel 			gqp.zev_flags & ZEV_FL_PERSISTENT ? "yes" : "no",
846add9520fSAndreas Jaekel 			gqp.zev_flags & ZEV_FL_BLOCK_WHILE_QUEUE_FULL ?
847add9520fSAndreas Jaekel 				 "yes" : "no");
848add9520fSAndreas Jaekel 	}
849add9520fSAndreas Jaekel 
850add9520fSAndreas Jaekel 	return (0);
851add9520fSAndreas Jaekel }
852add9520fSAndreas Jaekel 
853a18c35b9SAndreas Jaekel int
854a18c35b9SAndreas Jaekel main(int argc, char **argv)
855a18c35b9SAndreas Jaekel {
856a18c35b9SAndreas Jaekel 	int fd;
857a18c35b9SAndreas Jaekel 	int c;
858a18c35b9SAndreas Jaekel 	extern char *optarg;
859*6a6a51eeSAndreas Jaekel 	int create_tmp_queue = 1;
860*6a6a51eeSAndreas Jaekel 	char buf[MAXPATHLEN];
861a18c35b9SAndreas Jaekel 
862a18c35b9SAndreas Jaekel 	/* open device */
863a18c35b9SAndreas Jaekel 	fd = open(zev_device, O_RDONLY);
864a18c35b9SAndreas Jaekel 	if (fd < 0) {
865a18c35b9SAndreas Jaekel 		perror("opening zev device failed");
866a18c35b9SAndreas Jaekel 		return EXIT_FAILURE;
867a18c35b9SAndreas Jaekel 	}
868*6a6a51eeSAndreas Jaekel 	while ((c = getopt(argc, argv,
869*6a6a51eeSAndreas Jaekel 	                   "spd:Dlk:L:q:Qt:m:M:a:A:r:P:b:B:h?")) != -1){
870a18c35b9SAndreas Jaekel 		switch(c) {
871a18c35b9SAndreas Jaekel 		case 's':
872add9520fSAndreas Jaekel 			return zev_statistics(fd);
873a18c35b9SAndreas Jaekel 		case 'p':
874*6a6a51eeSAndreas Jaekel 			return zev_poll_events(fd, create_tmp_queue);
875add9520fSAndreas Jaekel 		case 'D':
876add9520fSAndreas Jaekel 			return zev_debug_info(fd);
877a18c35b9SAndreas Jaekel 		case 'd':
878add9520fSAndreas Jaekel 			close(fd);
879a18c35b9SAndreas Jaekel 			zev_device = optarg;
880add9520fSAndreas Jaekel 			fd = open(zev_device, O_RDONLY);
881add9520fSAndreas Jaekel 			if (fd < 0) {
882add9520fSAndreas Jaekel 				perror("opening zev device failed");
883add9520fSAndreas Jaekel 				return EXIT_FAILURE;
884add9520fSAndreas Jaekel 			}
885*6a6a51eeSAndreas Jaekel 			create_tmp_queue = 0;
886*6a6a51eeSAndreas Jaekel 			break;
887*6a6a51eeSAndreas Jaekel 		case 'q':
888*6a6a51eeSAndreas Jaekel 			snprintf(buf, sizeof(buf),
889*6a6a51eeSAndreas Jaekel 				 "/devices/pseudo/zev@0:%s", optarg);
890*6a6a51eeSAndreas Jaekel 			close(fd);
891*6a6a51eeSAndreas Jaekel 			zev_device = buf;
892*6a6a51eeSAndreas Jaekel 			fd = open(zev_device, O_RDONLY);
893*6a6a51eeSAndreas Jaekel 			if (fd < 0) {
894*6a6a51eeSAndreas Jaekel 				perror("opening zev device failed");
895*6a6a51eeSAndreas Jaekel 				return EXIT_FAILURE;
896*6a6a51eeSAndreas Jaekel 			}
897*6a6a51eeSAndreas Jaekel 			create_tmp_queue = 0;
898a18c35b9SAndreas Jaekel 			break;
899add9520fSAndreas Jaekel 		case 'l':
900add9520fSAndreas Jaekel 			return zev_list_queues(fd);
901add9520fSAndreas Jaekel 		case 'Q':
902add9520fSAndreas Jaekel 			return zev_set_global_max_queue_len(fd, optarg);
903*6a6a51eeSAndreas Jaekel 		case 'L':
904add9520fSAndreas Jaekel 			return zev_set_max_queue_len(fd, optarg, argv[optind]);
905fec460f8SAndreas Jaekel 		case 't':
906add9520fSAndreas Jaekel 			return zev_set_poll_wakeup_queue_len(fd, optarg,
907add9520fSAndreas Jaekel 			                                     argv[optind]);
908a18c35b9SAndreas Jaekel 		case 'm':
909a18c35b9SAndreas Jaekel 			return zev_mute_pool(fd, optarg);
910a18c35b9SAndreas Jaekel 		case 'M':
911a18c35b9SAndreas Jaekel 			return zev_unmute_pool(fd, optarg);
912888fea18SAndreas Jaekel 		case 'k':
913888fea18SAndreas Jaekel 			return zev_mark(fd, optarg);
914add9520fSAndreas Jaekel 		case 'a':
915*6a6a51eeSAndreas Jaekel 			return zev_add_queue(fd, optarg, 0);
916*6a6a51eeSAndreas Jaekel 		case 'A':
917*6a6a51eeSAndreas Jaekel 			return zev_add_queue(fd, optarg, 1);
918add9520fSAndreas Jaekel 		case 'r':
919add9520fSAndreas Jaekel 			return zev_remove_queue(fd, optarg);
920add9520fSAndreas Jaekel 		case 'b':
921add9520fSAndreas Jaekel 			return zev_queue_blocking(fd, optarg, 0);
922add9520fSAndreas Jaekel 		case 'B':
923add9520fSAndreas Jaekel 			return zev_queue_blocking(fd, optarg, 1);
924add9520fSAndreas Jaekel 		case 'P':
925add9520fSAndreas Jaekel 			return zev_queue_properties(fd, optarg);
926a18c35b9SAndreas Jaekel 		case 'h':
927a18c35b9SAndreas Jaekel 		case '?':
928a18c35b9SAndreas Jaekel 		default:
929a18c35b9SAndreas Jaekel 			usage(argv[0]);
930a18c35b9SAndreas Jaekel 		}
931a18c35b9SAndreas Jaekel 	}
932a18c35b9SAndreas Jaekel 	usage(argv[0]);
933a18c35b9SAndreas Jaekel 	close(fd);
934add9520fSAndreas Jaekel 	return EXIT_FAILURE;
935a18c35b9SAndreas Jaekel }
936a18c35b9SAndreas Jaekel 
937