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