xref: /dflybsd-src/lib/libdevattr/devattr_monitor.c (revision 5844bad4362a5003b37475c888ad60161aad744d)
1 /*
2  * Copyright (c) 2010 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Alex Hornung <ahornung@gmail.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 #include <sys/types.h>
35 #include <sys/device.h>
36 #include <sys/wait.h>
37 #include <sys/socket.h>
38 #include <sys/ioctl.h>
39 #include <sys/poll.h>
40 #include <sys/queue.h>
41 #include <sys/un.h>
42 #include <cpu/inttypes.h>
43 
44 #include <err.h>
45 #include <errno.h>
46 #include <fcntl.h>
47 #include <libgen.h>
48 #include <regex.h>
49 #include <signal.h>
50 #include <stdarg.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <syslog.h>
55 #include <unistd.h>
56 #include <pthread.h>
57 
58 #include <libprop/proplib.h>
59 #include <sys/udev.h>
60 #include "devattr.h"
61 
62 struct udev_monitor {
63 	struct udev	*udev_ctx;
64 	prop_array_t	ev_filt;
65 	int	socket;
66 	int	user_socket; /* maybe... one day... */
67 	int	refs;
68 };
69 
70 struct udev_monitor *
71 udev_monitor_new(struct udev *udev_ctx)
72 {
73 	struct udev_monitor *udev_monitor;
74 	int ret, s;
75 
76 	ret = conn_local_server(LISTEN_SOCKET_FILE, SOCK_STREAM, 0, &s);
77 	if (ret < 0)
78 		return NULL;
79 
80 	udev_monitor = malloc(sizeof(struct udev_monitor));
81 	if (udev_monitor == NULL)
82 		return NULL;
83 
84 	udev_monitor->refs = 1;
85 	udev_monitor->ev_filt = NULL;
86 	udev_monitor->socket = s;
87 	udev_monitor->user_socket = 1;
88 	udev_monitor->udev_ctx = udev_ref(udev_ctx);
89 
90 	return udev_monitor;
91 }
92 
93 
94 struct udev_monitor *
95 udev_monitor_ref(struct udev_monitor *udev_monitor)
96 {
97 	atomic_add_int(&udev_monitor->refs, 1);
98 
99 	return udev_monitor;
100 }
101 
102 void
103 udev_monitor_unref(struct udev_monitor *udev_monitor)
104 {
105 	int refcount;
106 
107 	refcount = atomic_fetchadd_int(&udev_monitor->refs, -1);
108 
109 	if (refcount == 1) {
110 		atomic_subtract_int(&udev_monitor->refs, 0x400); /* in destruction */
111 		if (udev_monitor->ev_filt != NULL)
112 			prop_object_release(udev_monitor->ev_filt);
113 
114 		if (udev_monitor->socket != -1)
115 			close(udev_monitor->socket);
116 		if (udev_monitor->user_socket != -1)
117 			close(udev_monitor->user_socket);
118 
119 		udev_unref(udev_monitor->udev_ctx);
120 		free(udev_monitor);
121 	}
122 }
123 
124 struct udev *
125 udev_monitor_get_udev(struct udev_monitor *udev_monitor)
126 {
127 	return udev_monitor->udev_ctx;
128 }
129 
130 int
131 udev_monitor_get_fd(struct udev_monitor *udev_monitor)
132 {
133 	return udev_monitor->socket;
134 }
135 
136 struct udev_device *
137 udev_monitor_receive_device(struct udev_monitor *udev_monitor)
138 {
139 	struct udev_device *udev_dev;
140 	prop_dictionary_t dict, evdict;
141 	prop_number_t	pn;
142 	char *xml;
143 	int n;
144 
145 	xml = malloc(12*1024*1024);
146 	if (xml == NULL)
147 		return NULL;
148 
149 	if ((n = read_xml(udev_monitor->socket, xml, 12*1024*1024)) <= 0) {
150 		free(xml);
151 		return NULL;
152 	}
153 
154 	xml[n+1] = '\0';
155 	dict = prop_dictionary_internalize(xml);
156 	free(xml);
157 	if (dict == NULL)
158 		return NULL;
159 
160 	pn = prop_dictionary_get(dict, "evtype");
161 	if (pn == NULL) {
162 		prop_object_release(dict);
163 		return NULL;
164 	}
165 
166 	evdict = prop_dictionary_get(dict, "evdict");
167 	if (evdict == NULL) {
168 		prop_object_release(dict);
169 		return NULL;
170 	}
171 
172 	udev_dev = udev_device_new_from_dictionary(udev_monitor->udev_ctx, evdict);
173 	if (udev_dev == NULL) {
174 		prop_object_release(dict);
175 		return NULL;
176 	}
177 
178 	udev_device_set_action(udev_dev, prop_number_integer_value(pn));
179 
180 	prop_object_release(dict);
181 	return udev_dev;
182 }
183 
184 int
185 udev_monitor_enable_receiving(struct udev_monitor *udev_monitor)
186 {
187 	prop_dictionary_t	dict;
188 	char *xml;
189 	int n;
190 	/* ->socket, ->user_socket, ->ev_filt */
191 
192 	dict = udevd_get_command_dict(__DECONST(char *, "monitor"));
193 	if (dict == NULL)
194 		return -1;
195 
196 	/* Add event filters to message, if available */
197 	if (udev_monitor->ev_filt != NULL) {
198 		if (prop_dictionary_set(dict, "filters",
199 		    udev_monitor->ev_filt) == false) {
200 			prop_object_release(dict);
201 			return -1;
202 		}
203 	}
204 
205 	xml = prop_dictionary_externalize(dict);
206 	prop_object_release(dict);
207 	if (xml == NULL)
208 		return -1;
209 
210 	n = send_xml(udev_monitor->socket, xml);
211 	free(xml);
212 	if (n <= 0)
213 		return -1;
214 
215 	return 0;
216 }
217 
218 int
219 udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor,
220 						const char *subsystem,
221 						const char *devtype __unused)
222 {
223 	int ret;
224 
225 	ret = _udev_monitor_filter_add_match_gen(udev_monitor,
226 						 EVENT_FILTER_TYPE_WILDCARD,
227 						 0,
228 						 "subsystem",
229 						 __DECONST(char *, subsystem));
230 
231 	return ret;
232 }
233 
234 int
235 udev_monitor_filter_add_match_expr(struct udev_monitor *udev_monitor,
236 			      	   const char *key,
237 			      	   char *expr)
238 {
239 	int ret;
240 
241 	ret = _udev_monitor_filter_add_match_gen(udev_monitor,
242 						 EVENT_FILTER_TYPE_WILDCARD,
243 						 0,
244 						 key,
245 						 expr);
246 
247 	return ret;
248 }
249 
250 int
251 udev_monitor_filter_add_nomatch_expr(struct udev_monitor *udev_monitor,
252 			      	     const char *key,
253 			      	     char *expr)
254 {
255 	int ret;
256 
257 	ret = _udev_monitor_filter_add_match_gen(udev_monitor,
258 						 EVENT_FILTER_TYPE_WILDCARD,
259 						 1,
260 						 key,
261 						 expr);
262 
263 	return ret;
264 }
265 
266 int
267 udev_monitor_filter_add_match_regex(struct udev_monitor *udev_monitor,
268 			      	   const char *key,
269 			      	   char *expr)
270 {
271 	int ret;
272 
273 	ret = _udev_monitor_filter_add_match_gen(udev_monitor,
274 						 EVENT_FILTER_TYPE_REGEX,
275 						 0,
276 						 key,
277 						 expr);
278 
279 	return ret;
280 }
281 
282 int
283 udev_monitor_filter_add_nomatch_regex(struct udev_monitor *udev_monitor,
284 			      	     const char *key,
285 			      	     char *expr)
286 {
287 	int ret;
288 
289 	ret = _udev_monitor_filter_add_match_gen(udev_monitor,
290 						 EVENT_FILTER_TYPE_REGEX,
291 						 1,
292 						 key,
293 						 expr);
294 
295 	return ret;
296 }
297 
298 int
299 _udev_filter_add_match_gen(prop_array_t filters,
300 				   int type,
301 				   int neg,
302 				   const char *key,
303 				   char *expr)
304 {
305 	prop_dictionary_t	dict;
306 	int error;
307 
308 	if (key == NULL)
309 		return -1;
310 	if (expr == NULL)
311 		return -1;
312 
313 	dict = prop_dictionary_create();
314 	if (dict == NULL)
315 		return -1;
316 
317 	error = _udev_dict_set_cstr(dict, "key", __DECONST(char *, key));
318 	if (error != 0)
319 		goto error_out;
320 	error = _udev_dict_set_int(dict, "type", type);
321 	if (error != 0)
322 		goto error_out;
323 	error = _udev_dict_set_cstr(dict, "expr", expr);
324 	if (error != 0)
325 		goto error_out;
326 
327 	if (neg) {
328 		error = _udev_dict_set_int(dict, "negative", 1);
329 		if (error != 0)
330 			goto error_out;
331 	}
332 
333 	if (prop_array_add(filters, dict) == false)
334 		goto error_out;
335 
336 	return 0;
337 
338 error_out:
339 	prop_object_release(dict);
340 	return -1;
341 }
342 
343 int
344 _udev_monitor_filter_add_match_gen(struct udev_monitor *udev_monitor,
345 				   int type,
346 				   int neg,
347 				   const char *key,
348 				   char *expr)
349 {
350 	prop_array_t		pa;
351 	int error;
352 
353 	if (udev_monitor->ev_filt == NULL) {
354 		pa = prop_array_create_with_capacity(5);
355 		if (pa == NULL)
356 			return -1;
357 
358 		udev_monitor->ev_filt = pa;
359 	}
360 
361 	error = _udev_filter_add_match_gen(udev_monitor->ev_filt, type, neg, key, expr);
362 
363 	return error;
364 }
365 
366