13a3826b3SAlex Hornung /*
23a3826b3SAlex Hornung * Copyright (c) 2010 The DragonFly Project. All rights reserved.
33a3826b3SAlex Hornung *
43a3826b3SAlex Hornung * This code is derived from software contributed to The DragonFly Project
53a3826b3SAlex Hornung * by Alex Hornung <ahornung@gmail.com>
63a3826b3SAlex Hornung *
73a3826b3SAlex Hornung * Redistribution and use in source and binary forms, with or without
83a3826b3SAlex Hornung * modification, are permitted provided that the following conditions
93a3826b3SAlex Hornung * are met:
103a3826b3SAlex Hornung *
113a3826b3SAlex Hornung * 1. Redistributions of source code must retain the above copyright
123a3826b3SAlex Hornung * notice, this list of conditions and the following disclaimer.
133a3826b3SAlex Hornung * 2. Redistributions in binary form must reproduce the above copyright
143a3826b3SAlex Hornung * notice, this list of conditions and the following disclaimer in
153a3826b3SAlex Hornung * the documentation and/or other materials provided with the
163a3826b3SAlex Hornung * distribution.
173a3826b3SAlex Hornung * 3. Neither the name of The DragonFly Project nor the names of its
183a3826b3SAlex Hornung * contributors may be used to endorse or promote products derived
193a3826b3SAlex Hornung * from this software without specific, prior written permission.
203a3826b3SAlex Hornung *
213a3826b3SAlex Hornung * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
223a3826b3SAlex Hornung * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
233a3826b3SAlex Hornung * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
243a3826b3SAlex Hornung * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
253a3826b3SAlex Hornung * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
263a3826b3SAlex Hornung * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
273a3826b3SAlex Hornung * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
283a3826b3SAlex Hornung * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
293a3826b3SAlex Hornung * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
303a3826b3SAlex Hornung * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
313a3826b3SAlex Hornung * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
323a3826b3SAlex Hornung * SUCH DAMAGE.
333a3826b3SAlex Hornung */
343a3826b3SAlex Hornung #include <sys/types.h>
353a3826b3SAlex Hornung #include <sys/device.h>
363a3826b3SAlex Hornung #include <sys/wait.h>
373a3826b3SAlex Hornung #include <sys/socket.h>
383a3826b3SAlex Hornung #include <sys/ioctl.h>
393a3826b3SAlex Hornung #include <sys/poll.h>
403a3826b3SAlex Hornung #include <sys/queue.h>
413a3826b3SAlex Hornung #include <sys/un.h>
423a3826b3SAlex Hornung
433a3826b3SAlex Hornung #include <err.h>
443a3826b3SAlex Hornung #include <errno.h>
453a3826b3SAlex Hornung #include <fcntl.h>
463a3826b3SAlex Hornung #include <libgen.h>
473a3826b3SAlex Hornung #include <regex.h>
483a3826b3SAlex Hornung #include <signal.h>
493a3826b3SAlex Hornung #include <stdarg.h>
503a3826b3SAlex Hornung #include <stdio.h>
513a3826b3SAlex Hornung #include <stdlib.h>
523a3826b3SAlex Hornung #include <string.h>
533a3826b3SAlex Hornung #include <syslog.h>
543a3826b3SAlex Hornung #include <unistd.h>
553a3826b3SAlex Hornung
563a3826b3SAlex Hornung #include <libprop/proplib.h>
573a3826b3SAlex Hornung #include <sys/udev.h>
58*3bbbc629SAlex Hornung #define LIBDEVATTR_INTERNAL
593a3826b3SAlex Hornung #include "devattr.h"
603a3826b3SAlex Hornung
613a3826b3SAlex Hornung struct udev_enumerate {
623a3826b3SAlex Hornung struct udev *udev_ctx;
633a3826b3SAlex Hornung prop_array_t ev_filt;
643a3826b3SAlex Hornung prop_array_t pa;
653a3826b3SAlex Hornung int refs;
663a3826b3SAlex Hornung TAILQ_HEAD(, udev_list_entry) list_entries;
673a3826b3SAlex Hornung };
683a3826b3SAlex Hornung
693a3826b3SAlex Hornung struct udev_list_entry {
703a3826b3SAlex Hornung struct udev *udev_ctx;
713a3826b3SAlex Hornung prop_dictionary_t dict;
723a3826b3SAlex Hornung TAILQ_ENTRY(udev_list_entry) link;
733a3826b3SAlex Hornung };
743a3826b3SAlex Hornung
753a3826b3SAlex Hornung struct udev_enumerate *
udev_enumerate_new(struct udev * udev_ctx)763a3826b3SAlex Hornung udev_enumerate_new(struct udev *udev_ctx)
773a3826b3SAlex Hornung {
783a3826b3SAlex Hornung struct udev_enumerate *udev_enum;
793a3826b3SAlex Hornung
803a3826b3SAlex Hornung udev_enum = malloc(sizeof(struct udev_enumerate));
813a3826b3SAlex Hornung
823a3826b3SAlex Hornung udev_enum->refs = 1;
833a3826b3SAlex Hornung udev_enum->ev_filt = NULL;
843a3826b3SAlex Hornung udev_enum->pa = NULL;
853a3826b3SAlex Hornung TAILQ_INIT(&udev_enum->list_entries);
863a3826b3SAlex Hornung udev_enum->udev_ctx = udev_ref(udev_ctx);
873a3826b3SAlex Hornung
883a3826b3SAlex Hornung return udev_enum;
893a3826b3SAlex Hornung }
903a3826b3SAlex Hornung
913a3826b3SAlex Hornung struct udev_enumerate *
udev_enumerate_ref(struct udev_enumerate * udev_enum)923a3826b3SAlex Hornung udev_enumerate_ref(struct udev_enumerate *udev_enum)
933a3826b3SAlex Hornung {
943a3826b3SAlex Hornung atomic_add_int(&udev_enum->refs, 1);
953a3826b3SAlex Hornung
963a3826b3SAlex Hornung return udev_enum;
973a3826b3SAlex Hornung }
983a3826b3SAlex Hornung
993a3826b3SAlex Hornung void
udev_enumerate_unref(struct udev_enumerate * udev_enum)1003a3826b3SAlex Hornung udev_enumerate_unref(struct udev_enumerate *udev_enum)
1013a3826b3SAlex Hornung {
1023a3826b3SAlex Hornung struct udev_list_entry *le;
1033a3826b3SAlex Hornung int refcount;
1043a3826b3SAlex Hornung
1053a3826b3SAlex Hornung refcount = atomic_fetchadd_int(&udev_enum->refs, -1);
1063a3826b3SAlex Hornung
1073a3826b3SAlex Hornung if (refcount == 1) {
1083a3826b3SAlex Hornung atomic_subtract_int(&udev_enum->refs, 0x400); /* in destruction */
1093a3826b3SAlex Hornung if (udev_enum->pa != NULL)
1103a3826b3SAlex Hornung prop_object_release(udev_enum->pa);
1113a3826b3SAlex Hornung if (udev_enum->ev_filt != NULL)
1123a3826b3SAlex Hornung prop_object_release(udev_enum->ev_filt);
1133a3826b3SAlex Hornung
1143a3826b3SAlex Hornung while (!TAILQ_EMPTY(&udev_enum->list_entries)) {
1153a3826b3SAlex Hornung le = TAILQ_FIRST(&udev_enum->list_entries);
1163a3826b3SAlex Hornung TAILQ_REMOVE(&udev_enum->list_entries, le, link);
1173a3826b3SAlex Hornung prop_object_release(le->dict);
1183a3826b3SAlex Hornung free(le);
1193a3826b3SAlex Hornung }
1203a3826b3SAlex Hornung udev_unref(udev_enum->udev_ctx);
1213a3826b3SAlex Hornung free(udev_enum);
1223a3826b3SAlex Hornung }
1233a3826b3SAlex Hornung }
1243a3826b3SAlex Hornung
1253a3826b3SAlex Hornung struct udev *
udev_enumerate_get_udev(struct udev_enumerate * udev_enum)1263a3826b3SAlex Hornung udev_enumerate_get_udev(struct udev_enumerate *udev_enum)
1273a3826b3SAlex Hornung {
1283a3826b3SAlex Hornung return udev_enum->udev_ctx;
1293a3826b3SAlex Hornung }
1303a3826b3SAlex Hornung
1313a3826b3SAlex Hornung int
udev_enumerate_scan_devices(struct udev_enumerate * udev_enum)1323a3826b3SAlex Hornung udev_enumerate_scan_devices(struct udev_enumerate *udev_enum)
1333a3826b3SAlex Hornung {
1343a3826b3SAlex Hornung prop_array_t pa;
1353a3826b3SAlex Hornung
1363a3826b3SAlex Hornung if (udev_get_fd(udev_enum->udev_ctx) == -1)
1373a3826b3SAlex Hornung return -1;
1383a3826b3SAlex Hornung
1393a3826b3SAlex Hornung pa = udevd_request_devs(udev_get_fd(udev_enum->udev_ctx), udev_enum->ev_filt);
1403a3826b3SAlex Hornung if (pa == NULL)
1413a3826b3SAlex Hornung return -1;
1423a3826b3SAlex Hornung
1433a3826b3SAlex Hornung prop_object_retain(pa);
1443a3826b3SAlex Hornung
1453a3826b3SAlex Hornung if (udev_enum->pa != NULL)
1463a3826b3SAlex Hornung prop_object_release(udev_enum->pa);
1473a3826b3SAlex Hornung
1483a3826b3SAlex Hornung udev_enum->pa = pa;
1493a3826b3SAlex Hornung
1503a3826b3SAlex Hornung return 0;
1513a3826b3SAlex Hornung }
1523a3826b3SAlex Hornung
1533a3826b3SAlex Hornung struct udev_list_entry *
udev_enumerate_get_list_entry(struct udev_enumerate * udev_enum)1543a3826b3SAlex Hornung udev_enumerate_get_list_entry(struct udev_enumerate *udev_enum)
1553a3826b3SAlex Hornung {
1563a3826b3SAlex Hornung struct udev_list_entry *le;
1573a3826b3SAlex Hornung prop_object_iterator_t iter;
1583a3826b3SAlex Hornung prop_dictionary_t dict;
1593a3826b3SAlex Hornung
1603a3826b3SAlex Hornung /* If the list is not empty, assume it was populated in an earlier call */
1613a3826b3SAlex Hornung if (!TAILQ_EMPTY(&udev_enum->list_entries))
1623a3826b3SAlex Hornung return TAILQ_FIRST(&udev_enum->list_entries);
1633a3826b3SAlex Hornung
1643a3826b3SAlex Hornung iter = prop_array_iterator(udev_enum->pa);
1653a3826b3SAlex Hornung if (iter == NULL)
1663a3826b3SAlex Hornung return NULL;
1673a3826b3SAlex Hornung
1683a3826b3SAlex Hornung while ((dict = prop_object_iterator_next(iter)) != NULL) {
1693a3826b3SAlex Hornung le = malloc(sizeof(struct udev_list_entry));
1703a3826b3SAlex Hornung if (le == NULL)
1713a3826b3SAlex Hornung goto out;
1723a3826b3SAlex Hornung
1733a3826b3SAlex Hornung prop_object_retain(dict);
1743a3826b3SAlex Hornung le->dict = dict;
1753a3826b3SAlex Hornung le->udev_ctx = udev_enum->udev_ctx;
1763a3826b3SAlex Hornung TAILQ_INSERT_TAIL(&udev_enum->list_entries, le, link);
1773a3826b3SAlex Hornung }
1783a3826b3SAlex Hornung
1793a3826b3SAlex Hornung le = TAILQ_FIRST(&udev_enum->list_entries);
1803a3826b3SAlex Hornung
1813a3826b3SAlex Hornung out:
1823a3826b3SAlex Hornung prop_object_iterator_release(iter);
1833a3826b3SAlex Hornung return le;
1843a3826b3SAlex Hornung }
1853a3826b3SAlex Hornung
1863a3826b3SAlex Hornung prop_array_t
udev_enumerate_get_array(struct udev_enumerate * udev_enum)1873a3826b3SAlex Hornung udev_enumerate_get_array(struct udev_enumerate *udev_enum)
1883a3826b3SAlex Hornung {
1893a3826b3SAlex Hornung return udev_enum->pa;
1903a3826b3SAlex Hornung }
1913a3826b3SAlex Hornung
1923a3826b3SAlex Hornung struct udev_list_entry *
udev_list_entry_get_next(struct udev_list_entry * list_entry)1933a3826b3SAlex Hornung udev_list_entry_get_next(struct udev_list_entry *list_entry)
1943a3826b3SAlex Hornung {
1953a3826b3SAlex Hornung return TAILQ_NEXT(list_entry, link);
1963a3826b3SAlex Hornung }
1973a3826b3SAlex Hornung
1983a3826b3SAlex Hornung prop_dictionary_t
udev_list_entry_get_dictionary(struct udev_list_entry * list_entry)1993a3826b3SAlex Hornung udev_list_entry_get_dictionary(struct udev_list_entry *list_entry)
2003a3826b3SAlex Hornung {
2013a3826b3SAlex Hornung return list_entry->dict;
2023a3826b3SAlex Hornung }
2033a3826b3SAlex Hornung
2043a3826b3SAlex Hornung struct udev_device *
udev_list_entry_get_device(struct udev_list_entry * list_entry)2053a3826b3SAlex Hornung udev_list_entry_get_device(struct udev_list_entry *list_entry)
2063a3826b3SAlex Hornung {
2073a3826b3SAlex Hornung struct udev_device *udev_dev;
2083a3826b3SAlex Hornung
2093a3826b3SAlex Hornung udev_dev = udev_device_new_from_dictionary(list_entry->udev_ctx,
2103a3826b3SAlex Hornung list_entry->dict);
2113a3826b3SAlex Hornung
2123a3826b3SAlex Hornung return udev_dev;
2133a3826b3SAlex Hornung }
2143a3826b3SAlex Hornung
2153a3826b3SAlex Hornung int
udev_enumerate_add_match_subsystem(struct udev_enumerate * udev_enum,const char * subsystem)2163a3826b3SAlex Hornung udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enum,
2173a3826b3SAlex Hornung const char *subsystem)
2183a3826b3SAlex Hornung {
2193a3826b3SAlex Hornung int ret;
2203a3826b3SAlex Hornung
2213a3826b3SAlex Hornung ret = _udev_enumerate_filter_add_match_gen(udev_enum,
2223a3826b3SAlex Hornung EVENT_FILTER_TYPE_WILDCARD,
2233a3826b3SAlex Hornung 0,
2243a3826b3SAlex Hornung "subsystem",
2253a3826b3SAlex Hornung __DECONST(char *, subsystem));
2263a3826b3SAlex Hornung
2273a3826b3SAlex Hornung return ret;
2283a3826b3SAlex Hornung }
2293a3826b3SAlex Hornung
2303a3826b3SAlex Hornung int
udev_enumerate_add_nomatch_subsystem(struct udev_enumerate * udev_enum,const char * subsystem)2313a3826b3SAlex Hornung udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enum,
2323a3826b3SAlex Hornung const char *subsystem)
2333a3826b3SAlex Hornung {
2343a3826b3SAlex Hornung int ret;
2353a3826b3SAlex Hornung
2363a3826b3SAlex Hornung ret = _udev_enumerate_filter_add_match_gen(udev_enum,
2373a3826b3SAlex Hornung EVENT_FILTER_TYPE_WILDCARD,
2383a3826b3SAlex Hornung 1,
2393a3826b3SAlex Hornung "subsystem",
2403a3826b3SAlex Hornung __DECONST(char *, subsystem));
2413a3826b3SAlex Hornung
2423a3826b3SAlex Hornung return ret;
2433a3826b3SAlex Hornung }
2443a3826b3SAlex Hornung
2453a3826b3SAlex Hornung int
udev_enumerate_add_match_expr(struct udev_enumerate * udev_enum,const char * key,char * expr)2463a3826b3SAlex Hornung udev_enumerate_add_match_expr(struct udev_enumerate *udev_enum,
2473a3826b3SAlex Hornung const char *key,
2483a3826b3SAlex Hornung char *expr)
2493a3826b3SAlex Hornung {
2503a3826b3SAlex Hornung int ret;
2513a3826b3SAlex Hornung
2523a3826b3SAlex Hornung ret = _udev_enumerate_filter_add_match_gen(udev_enum,
2533a3826b3SAlex Hornung EVENT_FILTER_TYPE_WILDCARD,
2543a3826b3SAlex Hornung 0,
2553a3826b3SAlex Hornung key,
2563a3826b3SAlex Hornung expr);
2573a3826b3SAlex Hornung
2583a3826b3SAlex Hornung return ret;
2593a3826b3SAlex Hornung }
2603a3826b3SAlex Hornung
2613a3826b3SAlex Hornung int
udev_enumerate_add_nomatch_expr(struct udev_enumerate * udev_enum,const char * key,char * expr)2623a3826b3SAlex Hornung udev_enumerate_add_nomatch_expr(struct udev_enumerate *udev_enum,
2633a3826b3SAlex Hornung const char *key,
2643a3826b3SAlex Hornung char *expr)
2653a3826b3SAlex Hornung {
2663a3826b3SAlex Hornung int ret;
2673a3826b3SAlex Hornung
2683a3826b3SAlex Hornung ret = _udev_enumerate_filter_add_match_gen(udev_enum,
2693a3826b3SAlex Hornung EVENT_FILTER_TYPE_WILDCARD,
2703a3826b3SAlex Hornung 1,
2713a3826b3SAlex Hornung key,
2723a3826b3SAlex Hornung expr);
2733a3826b3SAlex Hornung
2743a3826b3SAlex Hornung return ret;
2753a3826b3SAlex Hornung }
2763a3826b3SAlex Hornung
2773a3826b3SAlex Hornung int
udev_enumerate_add_match_regex(struct udev_enumerate * udev_enum,const char * key,char * expr)2783a3826b3SAlex Hornung udev_enumerate_add_match_regex(struct udev_enumerate *udev_enum,
2793a3826b3SAlex Hornung const char *key,
2803a3826b3SAlex Hornung char *expr)
2813a3826b3SAlex Hornung {
2823a3826b3SAlex Hornung int ret;
2833a3826b3SAlex Hornung
2843a3826b3SAlex Hornung ret = _udev_enumerate_filter_add_match_gen(udev_enum,
2853a3826b3SAlex Hornung EVENT_FILTER_TYPE_REGEX,
2863a3826b3SAlex Hornung 0,
2873a3826b3SAlex Hornung key,
2883a3826b3SAlex Hornung expr);
2893a3826b3SAlex Hornung
2903a3826b3SAlex Hornung return ret;
2913a3826b3SAlex Hornung }
2923a3826b3SAlex Hornung
2933a3826b3SAlex Hornung int
udev_enumerate_add_nomatch_regex(struct udev_enumerate * udev_enum,const char * key,char * expr)2943a3826b3SAlex Hornung udev_enumerate_add_nomatch_regex(struct udev_enumerate *udev_enum,
2953a3826b3SAlex Hornung const char *key,
2963a3826b3SAlex Hornung char *expr)
2973a3826b3SAlex Hornung {
2983a3826b3SAlex Hornung int ret;
2993a3826b3SAlex Hornung
3003a3826b3SAlex Hornung ret = _udev_enumerate_filter_add_match_gen(udev_enum,
3013a3826b3SAlex Hornung EVENT_FILTER_TYPE_REGEX,
3023a3826b3SAlex Hornung 1,
3033a3826b3SAlex Hornung key,
3043a3826b3SAlex Hornung expr);
3053a3826b3SAlex Hornung
3063a3826b3SAlex Hornung return ret;
3073a3826b3SAlex Hornung }
3083a3826b3SAlex Hornung
3093a3826b3SAlex Hornung int
_udev_enumerate_filter_add_match_gen(struct udev_enumerate * udev_enum,int type,int neg,const char * key,char * expr)3103a3826b3SAlex Hornung _udev_enumerate_filter_add_match_gen(struct udev_enumerate *udev_enum,
3113a3826b3SAlex Hornung int type,
3123a3826b3SAlex Hornung int neg,
3133a3826b3SAlex Hornung const char *key,
3143a3826b3SAlex Hornung char *expr)
3153a3826b3SAlex Hornung {
3163a3826b3SAlex Hornung prop_array_t pa;
3173a3826b3SAlex Hornung int error;
3183a3826b3SAlex Hornung
3193a3826b3SAlex Hornung if (udev_enum->ev_filt == NULL) {
3203a3826b3SAlex Hornung pa = prop_array_create_with_capacity(5);
3213a3826b3SAlex Hornung if (pa == NULL)
3223a3826b3SAlex Hornung return -1;
3233a3826b3SAlex Hornung
3243a3826b3SAlex Hornung udev_enum->ev_filt = pa;
3253a3826b3SAlex Hornung }
3263a3826b3SAlex Hornung
3273a3826b3SAlex Hornung error = _udev_filter_add_match_gen(udev_enum->ev_filt, type, neg, key, expr);
3283a3826b3SAlex Hornung
3293a3826b3SAlex Hornung return error;
3303a3826b3SAlex Hornung }
331