2 * Copyright (c) 2010 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Alex Hornung <ahornung@gmail.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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
34 #include <sys/types.h>
35 #include <sys/device.h>
37 #include <sys/socket.h>
38 #include <sys/ioctl.h>
40 #include <sys/queue.h>
42 #include <cpu/inttypes.h>
60 #include <libprop/proplib.h>
64 #define MONITOR_LOCK() pthread_mutex_lock(&monitor_lock)
65 #define MONITOR_UNLOCK() pthread_mutex_unlock(&monitor_lock)
67 static int _parse_filter_prop(struct udev_monitor *udm, prop_array_t pa);
68 static int match_filter(struct event_filter *evf, prop_dictionary_t dict);
70 static int WildCaseCmp(const char *w, const char *s);
71 static int wildCaseCmp(const char **mary, int d, const char *w, const char *s);
73 TAILQ_HEAD(udev_monitor_list_head, udev_monitor) udev_monitor_list;
74 pthread_mutex_t monitor_lock;
78 monitor_queue_event(prop_dictionary_t ev_dict)
80 struct udev_monitor *udm;
81 struct udev_monitor_event *udm_ev;
85 TAILQ_FOREACH(udm, &udev_monitor_list, link) {
86 udm_ev = malloc(sizeof(struct udev_monitor_event));
90 prop_object_retain(ev_dict);
91 udm_ev->ev_dict = ev_dict;
93 if (match_event_filter(udm,
94 prop_dictionary_get(udm_ev->ev_dict, "evdict")) == 0) {
95 prop_object_release(ev_dict);
100 pthread_mutex_lock(&udm->q_lock);
101 TAILQ_INSERT_TAIL(&udm->ev_queue, udm_ev, link);
102 pthread_cond_signal(&udm->cond);
103 pthread_mutex_unlock(&udm->q_lock);
109 struct udev_monitor *
110 udev_monitor_init(struct client_info *cli, prop_array_t filters)
112 struct udev_monitor *udm;
115 udm = malloc(sizeof(struct udev_monitor));
119 TAILQ_INIT(&udm->ev_queue);
120 TAILQ_INIT(&udm->ev_filt);
122 pthread_mutex_init(&udm->q_lock, NULL);
123 pthread_cond_init(&udm->cond, NULL);
126 if (filters != NULL) {
127 error = _parse_filter_prop(udm, filters);
128 /* XXX: ignore error for now */
135 udev_monitor_free(struct udev_monitor *udm)
137 struct event_filter *evf;
138 struct udev_monitor_event *udm_ev;
140 pthread_mutex_lock(&udm->q_lock);
142 while ((udm_ev = TAILQ_FIRST(&udm->ev_queue)) != NULL) {
143 prop_object_release(udm_ev->ev_dict);
144 udm_ev->ev_dict = NULL;
145 TAILQ_REMOVE(&udm->ev_queue, udm_ev, link);
149 while ((evf = TAILQ_FIRST(&udm->ev_filt)) != NULL) {
150 TAILQ_REMOVE(&udm->ev_filt, evf, link);
152 if (evf->type == EVENT_FILTER_TYPE_WILDCARD)
153 free(evf->wildcard_match);
154 else if (evf->type == EVENT_FILTER_TYPE_REGEX)
155 regfree(&evf->regex_match);
159 pthread_mutex_unlock(&udm->q_lock);
164 client_cmd_monitor(struct client_info *cli, prop_dictionary_t dict)
168 struct udev_monitor *udm;
169 struct udev_monitor_event *udm_ev;
170 struct timespec abstime;
171 struct pollfd fds[1];
177 po = prop_dictionary_get(dict, "filters");
178 if ((po != NULL) && prop_object_type(po) == PROP_TYPE_ARRAY) {
182 udm = udev_monitor_init(cli, pa);
188 fds[0].events = POLLRDNORM;
191 TAILQ_INSERT_TAIL(&udev_monitor_list, udm, link);
194 pthread_mutex_lock(&udm->q_lock);
196 clock_gettime(CLOCK_REALTIME,&abstime);
198 ret = pthread_cond_timedwait(&udm->cond, &udm->q_lock, &abstime);
201 syslog(LOG_ERR, "pthread_cond_timedwait error: EINVAL");
205 if ((ret = poll(fds, 1, 0)) > 0) {
206 ret = recv(fds[0].fd, &dummy, sizeof(dummy), MSG_DONTWAIT);
207 if ((ret == 0) || ((ret < 0) && (errno != EAGAIN)))
211 udm_ev = TAILQ_FIRST(&udm->ev_queue);
215 assert(udm_ev->ev_dict != NULL);
216 xml = prop_dictionary_externalize(udm_ev->ev_dict);
220 prop_object_release(udm_ev->ev_dict);
221 udm_ev->ev_dict = NULL;
222 TAILQ_REMOVE(&udm->ev_queue, udm_ev, link);
225 r = send_xml(cli->fd, xml);
234 pthread_mutex_unlock(&udm->q_lock);
241 TAILQ_REMOVE(&udev_monitor_list, udm, link);
244 udev_monitor_free(udm);
250 _parse_filter_prop(struct udev_monitor *udm, prop_array_t pa)
254 prop_object_iterator_t iter;
255 prop_dictionary_t dict;
256 struct event_filter *evf;
259 iter = prop_array_iterator(pa);
263 while ((dict = prop_object_iterator_next(iter)) != NULL) {
264 evf = malloc(sizeof(struct event_filter));
265 bzero(evf, sizeof(struct event_filter));
269 ps = prop_dictionary_get(dict, "key");
272 evf->key = prop_string_cstring(ps);
273 if (evf->key == NULL)
276 pn = prop_dictionary_get(dict, "type");
280 ps = prop_dictionary_get(dict, "expr");
284 if (prop_dictionary_get(dict, "negative"))
289 evf->type = prop_number_integer_value(pn);
291 case EVENT_FILTER_TYPE_WILDCARD:
292 evf->wildcard_match = prop_string_cstring(ps);
293 if (evf->wildcard_match == NULL)
297 case EVENT_FILTER_TYPE_REGEX:
298 error = regcomp(&evf->regex_match, prop_string_cstring_nocopy(ps), REG_ICASE | REG_NOSUB);
307 pthread_mutex_lock(&udm->q_lock);
308 TAILQ_INSERT_TAIL(&udm->ev_filt, evf, link);
309 pthread_mutex_unlock(&udm->q_lock);
313 prop_object_iterator_release(iter);
321 prop_object_iterator_release(iter);
330 <value>(e.g. kptr, devnum, ...)</value>
332 <value>(e.g. wildcard or regex)</value>
334 <value>(regex)</value>
341 match_filter(struct event_filter *evf, prop_dictionary_t ev_dict)
353 prop_object_retain(ev_dict);
355 if ((po = prop_dictionary_get(ev_dict, evf->key)) == NULL)
358 if (prop_object_type(po) == PROP_TYPE_STRING) {
360 str = __DECONST(char *, prop_string_cstring_nocopy(ps));
361 } else if (prop_object_type(po) == PROP_TYPE_NUMBER) {
363 if (prop_number_unsigned(pn)) {
364 snprintf(buf, sizeof(buf), "%" PRIu64, prop_number_unsigned_integer_value(pn));
366 snprintf(buf, sizeof(buf), "%" PRIi64, prop_number_integer_value(pn));
370 syslog(LOG_DEBUG, "Unexpected type in match_filter: %d\n", prop_object_type(po));
371 /* Unexpected type */
376 case EVENT_FILTER_TYPE_WILDCARD:
377 ret = WildCaseCmp(evf->wildcard_match, str);
383 case EVENT_FILTER_TYPE_REGEX:
384 ret = regexec(&evf->regex_match, str, 0, NULL, 0);
393 prop_object_release(ev_dict);
397 prop_object_release(ev_dict);
402 match_event_filter(struct udev_monitor *udm, prop_dictionary_t ev_dict)
404 struct event_filter *evf;
405 int all_negative = 1;
407 pthread_mutex_lock(&udm->q_lock);
409 if (TAILQ_EMPTY(&udm->ev_filt))
412 TAILQ_FOREACH(evf, &udm->ev_filt, link) {
413 //printf("match_event_filter 3\n");
417 if (match_filter(evf, ev_dict)) {
418 pthread_mutex_unlock(&udm->q_lock);
419 return (1 ^ evf->neg); /* return 1; or 0 for 'nomatch' hit */
421 //printf("match_event_filter 5\n");
424 pthread_mutex_unlock(&udm->q_lock);
425 return (all_negative == 1)?1:0;
429 WildCaseCmp(const char *w, const char *s)
433 int slen = strlen(s);
436 for (i = c = 0; w[i]; ++i) {
440 mary = malloc(sizeof(char *) * (c + 1));
444 for (i = 0; i < c; ++i)
446 i = wildCaseCmp(mary, 0, w, s);
452 * WildCaseCmp() - compare wild string to sane string, case insensitive
454 * Returns 0 on success, -1 on failure.
457 wildCaseCmp(const char **mary, int d, const char *w, const char *s)
468 * optimize terminator
472 if (w[1] != '?' && w[1] != '*') {
474 * optimize * followed by non-wild
476 for (i = 0; s + i < mary[d]; ++i) {
477 if (s[i] == w[1] && wildCaseCmp(mary, d + 1, w + 1, s + i) == 0)
484 for (i = 0; s + i < mary[d]; ++i) {
485 if (wildCaseCmp(mary, d + 1, w + 1, s + i) == 0)
499 if (tolower(*w) != tolower(*s))
502 if (*w == 0) /* terminator */