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 
57 #include <libprop/proplib.h>
58 #include <sys/udev.h>
59 #define LIBDEVATTR_INTERNAL
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 	if ((n = read_xml(udev_monitor->socket, &xml)) <= 0)
146 		return NULL;
147 
148 	xml[n+1] = '\0';
149 	dict = prop_dictionary_internalize(xml);
150 	free(xml);
151 	if (dict == NULL)
152 		return NULL;
153 
154 	pn = prop_dictionary_get(dict, "evtype");
155 	if (pn == NULL) {
156 		prop_object_release(dict);
157 		return NULL;
158 	}
159 
160 	evdict = prop_dictionary_get(dict, "evdict");
161 	if (evdict == NULL) {
162 		prop_object_release(dict);
163 		return NULL;
164 	}
165 
166 	udev_dev = udev_device_new_from_dictionary(udev_monitor->udev_ctx, evdict);
167 	if (udev_dev == NULL) {
168 		prop_object_release(dict);
169 		return NULL;
170 	}
171 
172 	udev_device_set_action(udev_dev, prop_number_integer_value(pn));
173 
174 	prop_object_release(dict);
175 	return udev_dev;
176 }
177 
178 int
179 udev_monitor_enable_receiving(struct udev_monitor *udev_monitor)
180 {
181 	prop_dictionary_t	dict;
182 	char *xml;
183 	int n;
184 	/* ->socket, ->user_socket, ->ev_filt */
185 
186 	dict = udevd_get_command_dict(__DECONST(char *, "monitor"));
187 	if (dict == NULL)
188 		return -1;
189 
190 	/* Add event filters to message, if available */
191 	if (udev_monitor->ev_filt != NULL) {
192 		if (prop_dictionary_set(dict, "filters",
193 		    udev_monitor->ev_filt) == false) {
194 			prop_object_release(dict);
195 			return -1;
196 		}
197 	}
198 
199 	xml = prop_dictionary_externalize(dict);
200 	prop_object_release(dict);
201 	if (xml == NULL)
202 		return -1;
203 
204 	n = send_xml(udev_monitor->socket, xml);
205 	free(xml);
206 	if (n <= 0)
207 		return -1;
208 
209 	return 0;
210 }
211 
212 int
213 udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor,
214 						const char *subsystem,
215 						const char *devtype __unused)
216 {
217 	int ret;
218 
219 	ret = _udev_monitor_filter_add_match_gen(udev_monitor,
220 						 EVENT_FILTER_TYPE_WILDCARD,
221 						 0,
222 						 "subsystem",
223 						 __DECONST(char *, subsystem));
224 
225 	return ret;
226 }
227 
228 int
229 udev_monitor_filter_add_match_expr(struct udev_monitor *udev_monitor,
230 			      	   const char *key,
231 			      	   char *expr)
232 {
233 	int ret;
234 
235 	ret = _udev_monitor_filter_add_match_gen(udev_monitor,
236 						 EVENT_FILTER_TYPE_WILDCARD,
237 						 0,
238 						 key,
239 						 expr);
240 
241 	return ret;
242 }
243 
244 int
245 udev_monitor_filter_add_nomatch_expr(struct udev_monitor *udev_monitor,
246 			      	     const char *key,
247 			      	     char *expr)
248 {
249 	int ret;
250 
251 	ret = _udev_monitor_filter_add_match_gen(udev_monitor,
252 						 EVENT_FILTER_TYPE_WILDCARD,
253 						 1,
254 						 key,
255 						 expr);
256 
257 	return ret;
258 }
259 
260 int
261 udev_monitor_filter_add_match_regex(struct udev_monitor *udev_monitor,
262 			      	   const char *key,
263 			      	   char *expr)
264 {
265 	int ret;
266 
267 	ret = _udev_monitor_filter_add_match_gen(udev_monitor,
268 						 EVENT_FILTER_TYPE_REGEX,
269 						 0,
270 						 key,
271 						 expr);
272 
273 	return ret;
274 }
275 
276 int
277 udev_monitor_filter_add_nomatch_regex(struct udev_monitor *udev_monitor,
278 			      	     const char *key,
279 			      	     char *expr)
280 {
281 	int ret;
282 
283 	ret = _udev_monitor_filter_add_match_gen(udev_monitor,
284 						 EVENT_FILTER_TYPE_REGEX,
285 						 1,
286 						 key,
287 						 expr);
288 
289 	return ret;
290 }
291 
292 int
293 _udev_filter_add_match_gen(prop_array_t filters,
294 				   int type,
295 				   int neg,
296 				   const char *key,
297 				   char *expr)
298 {
299 	prop_dictionary_t	dict;
300 	int error;
301 
302 	if (key == NULL)
303 		return -1;
304 	if (expr == NULL)
305 		return -1;
306 
307 	dict = prop_dictionary_create();
308 	if (dict == NULL)
309 		return -1;
310 
311 	error = _udev_dict_set_cstr(dict, "key", __DECONST(char *, key));
312 	if (error != 0)
313 		goto error_out;
314 	error = _udev_dict_set_int(dict, "type", type);
315 	if (error != 0)
316 		goto error_out;
317 	error = _udev_dict_set_cstr(dict, "expr", expr);
318 	if (error != 0)
319 		goto error_out;
320 
321 	if (neg) {
322 		error = _udev_dict_set_int(dict, "negative", 1);
323 		if (error != 0)
324 			goto error_out;
325 	}
326 
327 	if (prop_array_add(filters, dict) == false)
328 		goto error_out;
329 
330 	return 0;
331 
332 error_out:
333 	prop_object_release(dict);
334 	return -1;
335 }
336 
337 int
338 _udev_monitor_filter_add_match_gen(struct udev_monitor *udev_monitor,
339 				   int type,
340 				   int neg,
341 				   const char *key,
342 				   char *expr)
343 {
344 	prop_array_t		pa;
345 	int error;
346 
347 	if (udev_monitor->ev_filt == NULL) {
348 		pa = prop_array_create_with_capacity(5);
349 		if (pa == NULL)
350 			return -1;
351 
352 		udev_monitor->ev_filt = pa;
353 	}
354 
355 	error = _udev_filter_add_match_gen(udev_monitor->ev_filt, type, neg, key, expr);
356 
357 	return error;
358 }
359 
360