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_enumerate { 62 struct udev *udev_ctx; 63 prop_array_t ev_filt; 64 prop_array_t pa; 65 int refs; 66 TAILQ_HEAD(, udev_list_entry) list_entries; 67 }; 68 69 struct udev_list_entry { 70 struct udev *udev_ctx; 71 prop_dictionary_t dict; 72 TAILQ_ENTRY(udev_list_entry) link; 73 }; 74 75 struct udev_enumerate * 76 udev_enumerate_new(struct udev *udev_ctx) 77 { 78 struct udev_enumerate *udev_enum; 79 80 udev_enum = malloc(sizeof(struct udev_enumerate)); 81 82 udev_enum->refs = 1; 83 udev_enum->ev_filt = NULL; 84 udev_enum->pa = NULL; 85 TAILQ_INIT(&udev_enum->list_entries); 86 udev_enum->udev_ctx = udev_ref(udev_ctx); 87 88 return udev_enum; 89 } 90 91 struct udev_enumerate * 92 udev_enumerate_ref(struct udev_enumerate *udev_enum) 93 { 94 atomic_add_int(&udev_enum->refs, 1); 95 96 return udev_enum; 97 } 98 99 void 100 udev_enumerate_unref(struct udev_enumerate *udev_enum) 101 { 102 struct udev_list_entry *le; 103 int refcount; 104 105 refcount = atomic_fetchadd_int(&udev_enum->refs, -1); 106 107 if (refcount == 1) { 108 atomic_subtract_int(&udev_enum->refs, 0x400); /* in destruction */ 109 if (udev_enum->pa != NULL) 110 prop_object_release(udev_enum->pa); 111 if (udev_enum->ev_filt != NULL) 112 prop_object_release(udev_enum->ev_filt); 113 114 while (!TAILQ_EMPTY(&udev_enum->list_entries)) { 115 le = TAILQ_FIRST(&udev_enum->list_entries); 116 TAILQ_REMOVE(&udev_enum->list_entries, le, link); 117 prop_object_release(le->dict); 118 free(le); 119 } 120 udev_unref(udev_enum->udev_ctx); 121 free(udev_enum); 122 } 123 } 124 125 struct udev * 126 udev_enumerate_get_udev(struct udev_enumerate *udev_enum) 127 { 128 return udev_enum->udev_ctx; 129 } 130 131 int 132 udev_enumerate_scan_devices(struct udev_enumerate *udev_enum) 133 { 134 prop_array_t pa; 135 136 if (udev_get_fd(udev_enum->udev_ctx) == -1) 137 return -1; 138 139 pa = udevd_request_devs(udev_get_fd(udev_enum->udev_ctx), udev_enum->ev_filt); 140 if (pa == NULL) 141 return -1; 142 143 prop_object_retain(pa); 144 145 if (udev_enum->pa != NULL) 146 prop_object_release(udev_enum->pa); 147 148 udev_enum->pa = pa; 149 150 return 0; 151 } 152 153 struct udev_list_entry * 154 udev_enumerate_get_list_entry(struct udev_enumerate *udev_enum) 155 { 156 struct udev_list_entry *le; 157 prop_object_iterator_t iter; 158 prop_dictionary_t dict; 159 160 /* If the list is not empty, assume it was populated in an earlier call */ 161 if (!TAILQ_EMPTY(&udev_enum->list_entries)) 162 return TAILQ_FIRST(&udev_enum->list_entries); 163 164 iter = prop_array_iterator(udev_enum->pa); 165 if (iter == NULL) 166 return NULL; 167 168 while ((dict = prop_object_iterator_next(iter)) != NULL) { 169 le = malloc(sizeof(struct udev_list_entry)); 170 if (le == NULL) 171 goto out; 172 173 prop_object_retain(dict); 174 le->dict = dict; 175 le->udev_ctx = udev_enum->udev_ctx; 176 TAILQ_INSERT_TAIL(&udev_enum->list_entries, le, link); 177 } 178 179 le = TAILQ_FIRST(&udev_enum->list_entries); 180 181 out: 182 prop_object_iterator_release(iter); 183 return le; 184 } 185 186 prop_array_t 187 udev_enumerate_get_array(struct udev_enumerate *udev_enum) 188 { 189 return udev_enum->pa; 190 } 191 192 struct udev_list_entry * 193 udev_list_entry_get_next(struct udev_list_entry *list_entry) 194 { 195 return TAILQ_NEXT(list_entry, link); 196 } 197 198 prop_dictionary_t 199 udev_list_entry_get_dictionary(struct udev_list_entry *list_entry) 200 { 201 return list_entry->dict; 202 } 203 204 struct udev_device * 205 udev_list_entry_get_device(struct udev_list_entry *list_entry) 206 { 207 struct udev_device *udev_dev; 208 209 udev_dev = udev_device_new_from_dictionary(list_entry->udev_ctx, 210 list_entry->dict); 211 212 return udev_dev; 213 } 214 215 int 216 udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enum, 217 const char *subsystem) 218 { 219 int ret; 220 221 ret = _udev_enumerate_filter_add_match_gen(udev_enum, 222 EVENT_FILTER_TYPE_WILDCARD, 223 0, 224 "subsystem", 225 __DECONST(char *, subsystem)); 226 227 return ret; 228 } 229 230 int 231 udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enum, 232 const char *subsystem) 233 { 234 int ret; 235 236 ret = _udev_enumerate_filter_add_match_gen(udev_enum, 237 EVENT_FILTER_TYPE_WILDCARD, 238 1, 239 "subsystem", 240 __DECONST(char *, subsystem)); 241 242 return ret; 243 } 244 245 int 246 udev_enumerate_add_match_expr(struct udev_enumerate *udev_enum, 247 const char *key, 248 char *expr) 249 { 250 int ret; 251 252 ret = _udev_enumerate_filter_add_match_gen(udev_enum, 253 EVENT_FILTER_TYPE_WILDCARD, 254 0, 255 key, 256 expr); 257 258 return ret; 259 } 260 261 int 262 udev_enumerate_add_nomatch_expr(struct udev_enumerate *udev_enum, 263 const char *key, 264 char *expr) 265 { 266 int ret; 267 268 ret = _udev_enumerate_filter_add_match_gen(udev_enum, 269 EVENT_FILTER_TYPE_WILDCARD, 270 1, 271 key, 272 expr); 273 274 return ret; 275 } 276 277 int 278 udev_enumerate_add_match_regex(struct udev_enumerate *udev_enum, 279 const char *key, 280 char *expr) 281 { 282 int ret; 283 284 ret = _udev_enumerate_filter_add_match_gen(udev_enum, 285 EVENT_FILTER_TYPE_REGEX, 286 0, 287 key, 288 expr); 289 290 return ret; 291 } 292 293 int 294 udev_enumerate_add_nomatch_regex(struct udev_enumerate *udev_enum, 295 const char *key, 296 char *expr) 297 { 298 int ret; 299 300 ret = _udev_enumerate_filter_add_match_gen(udev_enum, 301 EVENT_FILTER_TYPE_REGEX, 302 1, 303 key, 304 expr); 305 306 return ret; 307 } 308 309 int 310 _udev_enumerate_filter_add_match_gen(struct udev_enumerate *udev_enum, 311 int type, 312 int neg, 313 const char *key, 314 char *expr) 315 { 316 prop_array_t pa; 317 int error; 318 319 if (udev_enum->ev_filt == NULL) { 320 pa = prop_array_create_with_capacity(5); 321 if (pa == NULL) 322 return -1; 323 324 udev_enum->ev_filt = pa; 325 } 326 327 error = _udev_filter_add_match_gen(udev_enum->ev_filt, type, neg, key, expr); 328 329 return error; 330 } 331