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 #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 xml = malloc(12*1024*1024); 146 if (xml == NULL) 147 return NULL; 148 149 if ((n = read_xml(udev_monitor->socket, xml, 12*1024*1024)) <= 0) { 150 free(xml); 151 return NULL; 152 } 153 154 xml[n+1] = '\0'; 155 dict = prop_dictionary_internalize(xml); 156 free(xml); 157 if (dict == NULL) 158 return NULL; 159 160 pn = prop_dictionary_get(dict, "evtype"); 161 if (pn == NULL) { 162 prop_object_release(dict); 163 return NULL; 164 } 165 166 evdict = prop_dictionary_get(dict, "evdict"); 167 if (evdict == NULL) { 168 prop_object_release(dict); 169 return NULL; 170 } 171 172 udev_dev = udev_device_new_from_dictionary(udev_monitor->udev_ctx, evdict); 173 if (udev_dev == NULL) { 174 prop_object_release(dict); 175 return NULL; 176 } 177 178 udev_device_set_action(udev_dev, prop_number_integer_value(pn)); 179 180 prop_object_release(dict); 181 return udev_dev; 182 } 183 184 int 185 udev_monitor_enable_receiving(struct udev_monitor *udev_monitor) 186 { 187 prop_dictionary_t dict; 188 char *xml; 189 int n; 190 /* ->socket, ->user_socket, ->ev_filt */ 191 192 dict = udevd_get_command_dict(__DECONST(char *, "monitor")); 193 if (dict == NULL) 194 return -1; 195 196 /* Add event filters to message, if available */ 197 if (udev_monitor->ev_filt != NULL) { 198 if (prop_dictionary_set(dict, "filters", 199 udev_monitor->ev_filt) == false) { 200 prop_object_release(dict); 201 return -1; 202 } 203 } 204 205 xml = prop_dictionary_externalize(dict); 206 prop_object_release(dict); 207 if (xml == NULL) 208 return -1; 209 210 n = send_xml(udev_monitor->socket, xml); 211 free(xml); 212 if (n <= 0) 213 return -1; 214 215 return 0; 216 } 217 218 int 219 udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, 220 const char *subsystem, 221 const char *devtype __unused) 222 { 223 int ret; 224 225 ret = _udev_monitor_filter_add_match_gen(udev_monitor, 226 EVENT_FILTER_TYPE_WILDCARD, 227 0, 228 "subsystem", 229 __DECONST(char *, subsystem)); 230 231 return ret; 232 } 233 234 int 235 udev_monitor_filter_add_match_expr(struct udev_monitor *udev_monitor, 236 const char *key, 237 char *expr) 238 { 239 int ret; 240 241 ret = _udev_monitor_filter_add_match_gen(udev_monitor, 242 EVENT_FILTER_TYPE_WILDCARD, 243 0, 244 key, 245 expr); 246 247 return ret; 248 } 249 250 int 251 udev_monitor_filter_add_nomatch_expr(struct udev_monitor *udev_monitor, 252 const char *key, 253 char *expr) 254 { 255 int ret; 256 257 ret = _udev_monitor_filter_add_match_gen(udev_monitor, 258 EVENT_FILTER_TYPE_WILDCARD, 259 1, 260 key, 261 expr); 262 263 return ret; 264 } 265 266 int 267 udev_monitor_filter_add_match_regex(struct udev_monitor *udev_monitor, 268 const char *key, 269 char *expr) 270 { 271 int ret; 272 273 ret = _udev_monitor_filter_add_match_gen(udev_monitor, 274 EVENT_FILTER_TYPE_REGEX, 275 0, 276 key, 277 expr); 278 279 return ret; 280 } 281 282 int 283 udev_monitor_filter_add_nomatch_regex(struct udev_monitor *udev_monitor, 284 const char *key, 285 char *expr) 286 { 287 int ret; 288 289 ret = _udev_monitor_filter_add_match_gen(udev_monitor, 290 EVENT_FILTER_TYPE_REGEX, 291 1, 292 key, 293 expr); 294 295 return ret; 296 } 297 298 int 299 _udev_filter_add_match_gen(prop_array_t filters, 300 int type, 301 int neg, 302 const char *key, 303 char *expr) 304 { 305 prop_dictionary_t dict; 306 int error; 307 308 if (key == NULL) 309 return -1; 310 if (expr == NULL) 311 return -1; 312 313 dict = prop_dictionary_create(); 314 if (dict == NULL) 315 return -1; 316 317 error = _udev_dict_set_cstr(dict, "key", __DECONST(char *, key)); 318 if (error != 0) 319 goto error_out; 320 error = _udev_dict_set_int(dict, "type", type); 321 if (error != 0) 322 goto error_out; 323 error = _udev_dict_set_cstr(dict, "expr", expr); 324 if (error != 0) 325 goto error_out; 326 327 if (neg) { 328 error = _udev_dict_set_int(dict, "negative", 1); 329 if (error != 0) 330 goto error_out; 331 } 332 333 if (prop_array_add(filters, dict) == false) 334 goto error_out; 335 336 return 0; 337 338 error_out: 339 prop_object_release(dict); 340 return -1; 341 } 342 343 int 344 _udev_monitor_filter_add_match_gen(struct udev_monitor *udev_monitor, 345 int type, 346 int neg, 347 const char *key, 348 char *expr) 349 { 350 prop_array_t pa; 351 int error; 352 353 if (udev_monitor->ev_filt == NULL) { 354 pa = prop_array_create_with_capacity(5); 355 if (pa == NULL) 356 return -1; 357 358 udev_monitor->ev_filt = pa; 359 } 360 361 error = _udev_filter_add_match_gen(udev_monitor->ev_filt, type, neg, key, expr); 362 363 return error; 364 } 365 366