xref: /dragonfly/lib/libdevattr/devattr_monitor.c (revision 0c8103dd622e5016512e2eedb2ceb865982089a5)
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 
43 #include <err.h>
44 #include <errno.h>
45 #include <fcntl.h>
46 #include <libgen.h>
47 #include <regex.h>
48 #include <signal.h>
49 #include <stdarg.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <syslog.h>
54 #include <unistd.h>
55 
56 #include <libprop/proplib.h>
57 #include <sys/udev.h>
58 #define LIBDEVATTR_INTERNAL
59 #include "devattr.h"
60 
61 struct udev_monitor {
62           struct udev         *udev_ctx;
63           prop_array_t        ev_filt;
64           int       socket;
65           int       user_socket; /* maybe... one day... */
66           int       refs;
67 };
68 
69 struct udev_monitor *
udev_monitor_new(struct udev * udev_ctx)70 udev_monitor_new(struct udev *udev_ctx)
71 {
72           struct udev_monitor *udev_monitor;
73           int ret, s;
74 
75           ret = conn_local_server(LISTEN_SOCKET_FILE, SOCK_STREAM, 0, &s);
76           if (ret < 0)
77                     return NULL;
78 
79           udev_monitor = malloc(sizeof(struct udev_monitor));
80           if (udev_monitor == NULL)
81                     return NULL;
82 
83           udev_monitor->refs = 1;
84           udev_monitor->ev_filt = NULL;
85           udev_monitor->socket = s;
86           udev_monitor->user_socket = 1;
87           udev_monitor->udev_ctx = udev_ref(udev_ctx);
88 
89           return udev_monitor;
90 }
91 
92 
93 struct udev_monitor *
udev_monitor_ref(struct udev_monitor * udev_monitor)94 udev_monitor_ref(struct udev_monitor *udev_monitor)
95 {
96           atomic_add_int(&udev_monitor->refs, 1);
97 
98           return udev_monitor;
99 }
100 
101 void
udev_monitor_unref(struct udev_monitor * udev_monitor)102 udev_monitor_unref(struct udev_monitor *udev_monitor)
103 {
104           int refcount;
105 
106           refcount = atomic_fetchadd_int(&udev_monitor->refs, -1);
107 
108           if (refcount == 1) {
109                     atomic_subtract_int(&udev_monitor->refs, 0x400); /* in destruction */
110                     if (udev_monitor->ev_filt != NULL)
111                               prop_object_release(udev_monitor->ev_filt);
112 
113                     if (udev_monitor->socket != -1)
114                               close(udev_monitor->socket);
115                     if (udev_monitor->user_socket != -1)
116                               close(udev_monitor->user_socket);
117 
118                     udev_unref(udev_monitor->udev_ctx);
119                     free(udev_monitor);
120           }
121 }
122 
123 struct udev *
udev_monitor_get_udev(struct udev_monitor * udev_monitor)124 udev_monitor_get_udev(struct udev_monitor *udev_monitor)
125 {
126           return udev_monitor->udev_ctx;
127 }
128 
129 int
udev_monitor_get_fd(struct udev_monitor * udev_monitor)130 udev_monitor_get_fd(struct udev_monitor *udev_monitor)
131 {
132           return udev_monitor->socket;
133 }
134 
135 struct udev_device *
udev_monitor_receive_device(struct udev_monitor * udev_monitor)136 udev_monitor_receive_device(struct udev_monitor *udev_monitor)
137 {
138           struct udev_device *udev_dev;
139           prop_dictionary_t dict, evdict;
140           prop_number_t       pn;
141           char *xml;
142           int n;
143 
144           if ((n = read_xml(udev_monitor->socket, &xml)) <= 0)
145                     return NULL;
146 
147           xml[n+1] = '\0';
148           dict = prop_dictionary_internalize(xml);
149           free(xml);
150           if (dict == NULL)
151                     return NULL;
152 
153           pn = prop_dictionary_get(dict, "evtype");
154           if (pn == NULL) {
155                     prop_object_release(dict);
156                     return NULL;
157           }
158 
159           evdict = prop_dictionary_get(dict, "evdict");
160           if (evdict == NULL) {
161                     prop_object_release(dict);
162                     return NULL;
163           }
164 
165           udev_dev = udev_device_new_from_dictionary(udev_monitor->udev_ctx, evdict);
166           if (udev_dev == NULL) {
167                     prop_object_release(dict);
168                     return NULL;
169           }
170 
171           udev_device_set_action(udev_dev, prop_number_integer_value(pn));
172 
173           prop_object_release(dict);
174           return udev_dev;
175 }
176 
177 int
udev_monitor_enable_receiving(struct udev_monitor * udev_monitor)178 udev_monitor_enable_receiving(struct udev_monitor *udev_monitor)
179 {
180           prop_dictionary_t   dict;
181           char *xml;
182           int n;
183           /* ->socket, ->user_socket, ->ev_filt */
184 
185           dict = udevd_get_command_dict(__DECONST(char *, "monitor"));
186           if (dict == NULL)
187                     return -1;
188 
189           /* Add event filters to message, if available */
190           if (udev_monitor->ev_filt != NULL) {
191                     if (prop_dictionary_set(dict, "filters",
192                         udev_monitor->ev_filt) == false) {
193                               prop_object_release(dict);
194                               return -1;
195                     }
196           }
197 
198           xml = prop_dictionary_externalize(dict);
199           prop_object_release(dict);
200           if (xml == NULL)
201                     return -1;
202 
203           n = send_xml(udev_monitor->socket, xml);
204           free(xml);
205           if (n <= 0)
206                     return -1;
207 
208           return 0;
209 }
210 
211 int
udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor * udev_monitor,const char * subsystem,const char * devtype __unused)212 udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor,
213                                                             const char *subsystem,
214                                                             const char *devtype __unused)
215 {
216           int ret;
217 
218           ret = _udev_monitor_filter_add_match_gen(udev_monitor,
219                                                              EVENT_FILTER_TYPE_WILDCARD,
220                                                              0,
221                                                              "subsystem",
222                                                              __DECONST(char *, subsystem));
223 
224           return ret;
225 }
226 
227 int
udev_monitor_filter_add_match_expr(struct udev_monitor * udev_monitor,const char * key,char * expr)228 udev_monitor_filter_add_match_expr(struct udev_monitor *udev_monitor,
229                                            const char *key,
230                                            char *expr)
231 {
232           int ret;
233 
234           ret = _udev_monitor_filter_add_match_gen(udev_monitor,
235                                                              EVENT_FILTER_TYPE_WILDCARD,
236                                                              0,
237                                                              key,
238                                                              expr);
239 
240           return ret;
241 }
242 
243 int
udev_monitor_filter_add_nomatch_expr(struct udev_monitor * udev_monitor,const char * key,char * expr)244 udev_monitor_filter_add_nomatch_expr(struct udev_monitor *udev_monitor,
245                                              const char *key,
246                                              char *expr)
247 {
248           int ret;
249 
250           ret = _udev_monitor_filter_add_match_gen(udev_monitor,
251                                                              EVENT_FILTER_TYPE_WILDCARD,
252                                                              1,
253                                                              key,
254                                                              expr);
255 
256           return ret;
257 }
258 
259 int
udev_monitor_filter_add_match_regex(struct udev_monitor * udev_monitor,const char * key,char * expr)260 udev_monitor_filter_add_match_regex(struct udev_monitor *udev_monitor,
261                                            const char *key,
262                                            char *expr)
263 {
264           int ret;
265 
266           ret = _udev_monitor_filter_add_match_gen(udev_monitor,
267                                                              EVENT_FILTER_TYPE_REGEX,
268                                                              0,
269                                                              key,
270                                                              expr);
271 
272           return ret;
273 }
274 
275 int
udev_monitor_filter_add_nomatch_regex(struct udev_monitor * udev_monitor,const char * key,char * expr)276 udev_monitor_filter_add_nomatch_regex(struct udev_monitor *udev_monitor,
277                                              const char *key,
278                                              char *expr)
279 {
280           int ret;
281 
282           ret = _udev_monitor_filter_add_match_gen(udev_monitor,
283                                                              EVENT_FILTER_TYPE_REGEX,
284                                                              1,
285                                                              key,
286                                                              expr);
287 
288           return ret;
289 }
290 
291 int
_udev_filter_add_match_gen(prop_array_t filters,int type,int neg,const char * key,char * expr)292 _udev_filter_add_match_gen(prop_array_t filters,
293                                            int type,
294                                            int neg,
295                                            const char *key,
296                                            char *expr)
297 {
298           prop_dictionary_t   dict;
299           int error;
300 
301           if (key == NULL)
302                     return -1;
303           if (expr == NULL)
304                     return -1;
305 
306           dict = prop_dictionary_create();
307           if (dict == NULL)
308                     return -1;
309 
310           error = _udev_dict_set_cstr(dict, "key", __DECONST(char *, key));
311           if (error != 0)
312                     goto error_out;
313           error = _udev_dict_set_int(dict, "type", type);
314           if (error != 0)
315                     goto error_out;
316           error = _udev_dict_set_cstr(dict, "expr", expr);
317           if (error != 0)
318                     goto error_out;
319 
320           if (neg) {
321                     error = _udev_dict_set_int(dict, "negative", 1);
322                     if (error != 0)
323                               goto error_out;
324           }
325 
326           if (prop_array_add(filters, dict) == false)
327                     goto error_out;
328 
329           return 0;
330 
331 error_out:
332           prop_object_release(dict);
333           return -1;
334 }
335 
336 int
_udev_monitor_filter_add_match_gen(struct udev_monitor * udev_monitor,int type,int neg,const char * key,char * expr)337 _udev_monitor_filter_add_match_gen(struct udev_monitor *udev_monitor,
338                                            int type,
339                                            int neg,
340                                            const char *key,
341                                            char *expr)
342 {
343           prop_array_t                  pa;
344           int error;
345 
346           if (udev_monitor->ev_filt == NULL) {
347                     pa = prop_array_create_with_capacity(5);
348                     if (pa == NULL)
349                               return -1;
350 
351                     udev_monitor->ev_filt = pa;
352           }
353 
354           error = _udev_filter_add_match_gen(udev_monitor->ev_filt, type, neg, key, expr);
355 
356           return error;
357 }
358 
359