Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  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#include <linux/watch_queue.h>
 20#include <linux/unistd.h>
 21#include <linux/keyctl.h>
 22
 23#ifndef KEYCTL_WATCH_KEY
 24#define KEYCTL_WATCH_KEY -1
 25#endif
 26#ifndef __NR_keyctl
 27#define __NR_keyctl -1
 28#endif
 29
 30#define BUF_SIZE 256
 31
 32static long keyctl_watch_key(int key, int watch_fd, int watch_id)
 33{
 34	return syscall(__NR_keyctl, KEYCTL_WATCH_KEY, key, watch_fd, watch_id);
 35}
 36
 37static 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",
 46};
 47
 48static void saw_key_change(struct watch_notification *n, size_t len)
 49{
 50	struct key_notification *k = (struct key_notification *)n;
 51
 52	if (len != sizeof(struct key_notification)) {
 53		fprintf(stderr, "Incorrect key message length\n");
 54		return;
 55	}
 56
 57	printf("KEY %08x change=%u[%s] aux=%u\n",
 58	       k->key_id, n->subtype, key_subtypes[n->subtype], k->aux);
 59}
 60
 61/*
 62 * Consume and display events.
 63 */
 64static void consumer(int fd)
 65{
 66	unsigned char buffer[433], *p, *end;
 67	union {
 68		struct watch_notification n;
 69		unsigned char buf1[128];
 70	} n;
 71	ssize_t buf_len;
 72
 73	for (;;) {
 74		buf_len = read(fd, buffer, sizeof(buffer));
 75		if (buf_len == -1) {
 76			perror("read");
 77			exit(1);
 78		}
 79
 80		if (buf_len == 0) {
 81			printf("-- END --\n");
 82			return;
 83		}
 84
 85		if (buf_len > sizeof(buffer)) {
 86			fprintf(stderr, "Read buffer overrun: %zd\n", buf_len);
 87			return;
 88		}
 89
 90		printf("read() = %zd\n", buf_len);
 91
 92		p = buffer;
 93		end = buffer + buf_len;
 94		while (p < end) {
 95			size_t largest, len;
 96
 97			largest = end - p;
 98			if (largest > 128)
 99				largest = 128;
100			if (largest < sizeof(struct watch_notification)) {
101				fprintf(stderr, "Short message header: %zu\n", largest);
102				return;
103			}
104			memcpy(&n, p, largest);
105
106			printf("NOTIFY[%03zx]: ty=%06x sy=%02x i=%08x\n",
107			       p - buffer, n.n.type, n.n.subtype, n.n.info);
108
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);
112				exit(1);
113			}
114
115			switch (n.n.type) {
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);
122					break;
123				case WATCH_META_LOSS_NOTIFICATION:
124					printf("-- LOSS --\n");
125					break;
126				default:
127					printf("other meta record\n");
128					break;
129				}
130				break;
131			case WATCH_TYPE_KEY_NOTIFY:
132				saw_key_change(&n.n, len);
133				break;
134			default:
135				printf("other type\n");
136				break;
137			}
138
139			p += len;
140		}
141	}
142}
143
144static struct watch_notification_filter filter = {
145	.nr_filters	= 1,
146	.filters = {
147		[0]	= {
148			.type			= WATCH_TYPE_KEY_NOTIFY,
149			.subtype_filter[0]	= UINT_MAX,
150		},
151	},
152};
153
154int main(int argc, char **argv)
155{
156	int pipefd[2], fd;
157
158	if (pipe2(pipefd, O_NOTIFICATION_PIPE) == -1) {
159		perror("pipe2");
160		exit(1);
161	}
162	fd = pipefd[0];
163
164	if (ioctl(fd, IOC_WATCH_QUEUE_SET_SIZE, BUF_SIZE) == -1) {
165		perror("watch_queue(size)");
166		exit(1);
167	}
168
169	if (ioctl(fd, IOC_WATCH_QUEUE_SET_FILTER, &filter) == -1) {
170		perror("watch_queue(filter)");
171		exit(1);
172	}
173
174	if (keyctl_watch_key(KEY_SPEC_SESSION_KEYRING, fd, 0x01) == -1) {
175		perror("keyctl");
176		exit(1);
177	}
178
179	if (keyctl_watch_key(KEY_SPEC_USER_KEYRING, fd, 0x02) == -1) {
180		perror("keyctl");
181		exit(1);
182	}
183
184	consumer(fd);
185	exit(0);
186}