1 // SPDX-License-Identifier: GPL-2.0
2 /* Use watch_queue API to watch for notifications.
4 * Copyright (C) 2020 Red Hat, Inc. All Rights Reserved.
5 * Written by David Howells (dhowells@redhat.com)
17 #include <sys/ioctl.h>
19 #include <linux/watch_queue.h>
20 #include <linux/unistd.h>
21 #include <linux/keyctl.h>
23 #ifndef KEYCTL_WATCH_KEY
24 #define KEYCTL_WATCH_KEY -1
27 #define __NR_keyctl -1
32 static long keyctl_watch_key(int key
, int watch_fd
, int watch_id
)
34 return syscall(__NR_keyctl
, KEYCTL_WATCH_KEY
, key
, watch_fd
, watch_id
);
37 static const char *key_subtypes
[256] = {
38 [NOTIFY_KEY_INSTANTIATED
] = "instantiated",
39 [NOTIFY_KEY_UPDATED
] = "updated",
40 [NOTIFY_KEY_LINKED
] = "linked",
41 [NOTIFY_KEY_UNLINKED
] = "unlinked",
42 [NOTIFY_KEY_CLEARED
] = "cleared",
43 [NOTIFY_KEY_REVOKED
] = "revoked",
44 [NOTIFY_KEY_INVALIDATED
] = "invalidated",
45 [NOTIFY_KEY_SETATTR
] = "setattr",
48 static void saw_key_change(struct watch_notification
*n
, size_t len
)
50 struct key_notification
*k
= (struct key_notification
*)n
;
52 if (len
!= sizeof(struct key_notification
)) {
53 fprintf(stderr
, "Incorrect key message length\n");
57 printf("KEY %08x change=%u[%s] aux=%u\n",
58 k
->key_id
, n
->subtype
, key_subtypes
[n
->subtype
], k
->aux
);
62 * Consume and display events.
64 static void consumer(int fd
)
66 unsigned char buffer
[433], *p
, *end
;
68 struct watch_notification n
;
69 unsigned char buf1
[128];
74 buf_len
= read(fd
, buffer
, sizeof(buffer
));
81 printf("-- END --\n");
85 if (buf_len
> sizeof(buffer
)) {
86 fprintf(stderr
, "Read buffer overrun: %zd\n", buf_len
);
90 printf("read() = %zd\n", buf_len
);
93 end
= buffer
+ buf_len
;
100 if (largest
< sizeof(struct watch_notification
)) {
101 fprintf(stderr
, "Short message header: %zu\n", largest
);
104 memcpy(&n
, p
, largest
);
106 printf("NOTIFY[%03zx]: ty=%06x sy=%02x i=%08x\n",
107 p
- buffer
, n
.n
.type
, n
.n
.subtype
, n
.n
.info
);
109 len
= n
.n
.info
& WATCH_INFO_LENGTH
;
110 if (len
< sizeof(n
.n
) || len
> largest
) {
111 fprintf(stderr
, "Bad message length: %zu/%zu\n", len
, largest
);
116 case WATCH_TYPE_META
:
117 switch (n
.n
.subtype
) {
118 case WATCH_META_REMOVAL_NOTIFICATION
:
119 printf("REMOVAL of watchpoint %08x\n",
120 (n
.n
.info
& WATCH_INFO_ID
) >>
121 WATCH_INFO_ID__SHIFT
);
123 case WATCH_META_LOSS_NOTIFICATION
:
124 printf("-- LOSS --\n");
127 printf("other meta record\n");
131 case WATCH_TYPE_KEY_NOTIFY
:
132 saw_key_change(&n
.n
, len
);
135 printf("other type\n");
144 static struct watch_notification_filter filter
= {
148 .type
= WATCH_TYPE_KEY_NOTIFY
,
149 .subtype_filter
[0] = UINT_MAX
,
154 int main(int argc
, char **argv
)
158 if (pipe2(pipefd
, O_NOTIFICATION_PIPE
) == -1) {
164 if (ioctl(fd
, IOC_WATCH_QUEUE_SET_SIZE
, BUF_SIZE
) == -1) {
165 perror("watch_queue(size)");
169 if (ioctl(fd
, IOC_WATCH_QUEUE_SET_FILTER
, &filter
) == -1) {
170 perror("watch_queue(filter)");
174 if (keyctl_watch_key(KEY_SPEC_SESSION_KEYRING
, fd
, 0x01) == -1) {
179 if (keyctl_watch_key(KEY_SPEC_USER_KEYRING
, fd
, 0x02) == -1) {