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