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