File Index
Files and directories
Sign in
FILE

watch_test.c

File preview with syntax highlighting.

linux-6.19.14/samples/watch_queue/watch_test.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/* Use watch_queue API to watch for notifications.
  3 *
  4 * Copyright (C) 2020 Red Hat, Inc. All Rights Reserved.
  5 * Written by David Howells (dhowells@redhat.com)
  6 */
  7
  8#define _GNU_SOURCE
  9#include <stdbool.h>
 10#include <stdarg.h>
 11#include <stdio.h>
 12#include <stdlib.h>
 13#include <string.h>
 14#include <signal.h>
 15#include <unistd.h>
 16#include <errno.h>
 17#include <sys/ioctl.h>
 18#include <limits.h>
 19
 20// Work around glibc header silliness
 21#undef AT_RENAME_NOREPLACE
 22#undef AT_RENAME_EXCHANGE
 23#undef AT_RENAME_WHITEOUT
 24
 25#include <linux/watch_queue.h>
 26#include <linux/unistd.h>
 27#include <linux/keyctl.h>
 28
 29#ifndef KEYCTL_WATCH_KEY
 30#define KEYCTL_WATCH_KEY -1
 31#endif
 32#ifndef __NR_keyctl
 33#define __NR_keyctl -1
 34#endif
 35
 36#define BUF_SIZE 256
 37
 38static long keyctl_watch_key(int key, int watch_fd, int watch_id)
 39{
 40	return syscall(__NR_keyctl, KEYCTL_WATCH_KEY, key, watch_fd, watch_id);
 41}
 42
 43static const char *key_subtypes[256] = {
 44	[NOTIFY_KEY_INSTANTIATED]	= "instantiated",
 45	[NOTIFY_KEY_UPDATED]		= "updated",
 46	[NOTIFY_KEY_LINKED]		= "linked",
 47	[NOTIFY_KEY_UNLINKED]		= "unlinked",
 48	[NOTIFY_KEY_CLEARED]		= "cleared",
 49	[NOTIFY_KEY_REVOKED]		= "revoked",
 50	[NOTIFY_KEY_INVALIDATED]	= "invalidated",
 51	[NOTIFY_KEY_SETATTR]		= "setattr",
 52};
 53
 54static void saw_key_change(struct watch_notification *n, size_t len)
 55{
 56	struct key_notification *k = (struct key_notification *)n;
 57
 58	if (len != sizeof(struct key_notification)) {
 59		fprintf(stderr, "Incorrect key message length\n");
 60		return;
 61	}
 62
 63	printf("KEY %08x change=%u[%s] aux=%u\n",
 64	       k->key_id, n->subtype, key_subtypes[n->subtype], k->aux);
 65}
 66
 67/*
 68 * Consume and display events.
 69 */
 70static void consumer(int fd)
 71{
 72	unsigned char buffer[433], *p, *end;
 73	union {
 74		struct watch_notification n;
 75		unsigned char buf1[128];
 76	} n;
 77	ssize_t buf_len;
 78
 79	for (;;) {
 80		buf_len = read(fd, buffer, sizeof(buffer));
 81		if (buf_len == -1) {
 82			perror("read");
 83			exit(1);
 84		}
 85
 86		if (buf_len == 0) {
 87			printf("-- END --\n");
 88			return;
 89		}
 90
 91		if (buf_len > sizeof(buffer)) {
 92			fprintf(stderr, "Read buffer overrun: %zd\n", buf_len);
 93			return;
 94		}
 95
 96		printf("read() = %zd\n", buf_len);
 97
 98		p = buffer;
 99		end = buffer + buf_len;
100		while (p < end) {
101			size_t largest, len;
102
103			largest = end - p;
104			if (largest > 128)
105				largest = 128;
106			if (largest < sizeof(struct watch_notification)) {
107				fprintf(stderr, "Short message header: %zu\n", largest);
108				return;
109			}
110			memcpy(&n, p, largest);
111
112			printf("NOTIFY[%03zx]: ty=%06x sy=%02x i=%08x\n",
113			       p - buffer, n.n.type, n.n.subtype, n.n.info);
114
115			len = n.n.info & WATCH_INFO_LENGTH;
116			if (len < sizeof(n.n) || len > largest) {
117				fprintf(stderr, "Bad message length: %zu/%zu\n", len, largest);
118				exit(1);
119			}
120
121			switch (n.n.type) {
122			case WATCH_TYPE_META:
123				switch (n.n.subtype) {
124				case WATCH_META_REMOVAL_NOTIFICATION:
125					printf("REMOVAL of watchpoint %08x\n",
126					       (n.n.info & WATCH_INFO_ID) >>
127					       WATCH_INFO_ID__SHIFT);
128					break;
129				case WATCH_META_LOSS_NOTIFICATION:
130					printf("-- LOSS --\n");
131					break;
132				default:
133					printf("other meta record\n");
134					break;
135				}
136				break;
137			case WATCH_TYPE_KEY_NOTIFY:
138				saw_key_change(&n.n, len);
139				break;
140			default:
141				printf("other type\n");
142				break;
143			}
144
145			p += len;
146		}
147	}
148}
149
150static struct watch_notification_filter filter = {
151	.nr_filters	= 1,
152	.filters = {
153		[0]	= {
154			.type			= WATCH_TYPE_KEY_NOTIFY,
155			.subtype_filter[0]	= UINT_MAX,
156		},
157	},
158};
159
160int main(int argc, char **argv)
161{
162	int pipefd[2], fd;
163
164	if (pipe2(pipefd, O_NOTIFICATION_PIPE) == -1) {
165		perror("pipe2");
166		exit(1);
167	}
168	fd = pipefd[0];
169
170	if (ioctl(fd, IOC_WATCH_QUEUE_SET_SIZE, BUF_SIZE) == -1) {
171		perror("watch_queue(size)");
172		exit(1);
173	}
174
175	if (ioctl(fd, IOC_WATCH_QUEUE_SET_FILTER, &filter) == -1) {
176		perror("watch_queue(filter)");
177		exit(1);
178	}
179
180	if (keyctl_watch_key(KEY_SPEC_SESSION_KEYRING, fd, 0x01) == -1) {
181		perror("keyctl");
182		exit(1);
183	}
184
185	if (keyctl_watch_key(KEY_SPEC_USER_KEYRING, fd, 0x02) == -1) {
186		perror("keyctl");
187		exit(1);
188	}
189
190	consumer(fd);
191	exit(0);
192}
~/ Read-only file preview.