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