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 "udevd.h" 61 62 static int udevfd; 63 64 extern pthread_mutex_t monitor_lock; 65 extern TAILQ_HEAD(udev_monitor_list_head, udev_monitor) udev_monitor_list; 66 extern TAILQ_HEAD(pdev_array_list_head, pdev_array_entry) pdev_array_list; 67 68 int match_dev_dict(prop_dictionary_t, prop_dictionary_t); 69 prop_dictionary_t find_dev_dict(int64_t, prop_dictionary_t, int *); 70 71 void udev_read_event(int); 72 prop_array_t udev_getdevs(int); 73 74 int 75 match_dev_dict(prop_dictionary_t dict, prop_dictionary_t match_dict) 76 { 77 prop_number_t pn, pn2; 78 prop_string_t ps, ps2; 79 80 if (dict == NULL) 81 return 0; 82 83 if ((ps = prop_dictionary_get(dict, "name")) == NULL) 84 return 0; 85 if ((ps2 = prop_dictionary_get(match_dict, "name")) == NULL) 86 return 0; 87 if (!prop_string_equals(ps, ps2)) 88 return 0; 89 90 if ((pn = prop_dictionary_get(dict, "devnum")) == NULL) 91 return 0; 92 if ((pn2 = prop_dictionary_get(match_dict, "devnum")) == NULL) 93 return 0; 94 if (!prop_number_equals(pn, pn2)) 95 return 0; 96 97 if ((pn = prop_dictionary_get(dict, "kptr")) == NULL) 98 return 0; 99 if ((pn2 = prop_dictionary_get(match_dict, "kptr")) == NULL) 100 return 0; 101 if (!prop_number_equals(pn, pn2)) 102 return 0; 103 104 return 1; 105 } 106 107 prop_dictionary_t 108 find_dev_dict(int64_t generation, prop_dictionary_t match_dict, int *idx) 109 { 110 struct pdev_array_entry *pae; 111 prop_array_t pa; 112 prop_object_iterator_t iter; 113 prop_dictionary_t dict; 114 int i = 0; 115 116 if (generation == -1) 117 pae = pdev_array_entry_get_last(); 118 else 119 pae = pdev_array_entry_get(generation); 120 121 if (pae == NULL) 122 return NULL; 123 124 pa = pae->pdev_array; 125 126 iter = prop_array_iterator(pa); 127 if (iter == NULL) { 128 pdev_array_entry_unref(pae); 129 return NULL; 130 } 131 132 while ((dict = prop_object_iterator_next(iter)) != NULL) { 133 if (match_dev_dict(dict, match_dict)) 134 break; 135 ++i; 136 } 137 138 prop_object_iterator_release(iter); 139 140 if (idx != NULL) 141 *idx = i; 142 143 pdev_array_entry_unref(pae); 144 return dict; 145 } 146 147 void 148 udev_read_event(int fd) 149 { 150 struct pdev_array_entry *pae; 151 prop_dictionary_t dict, evdict, devdict; 152 prop_number_t pn; 153 prop_string_t ps; 154 prop_object_t po; 155 prop_array_t pa; 156 char *xml; 157 int n, idx, evtype; 158 size_t sz; 159 160 sz = 4096 * 1024; 161 162 xml = malloc(sz); /* 4 MB */ 163 again: 164 if ((n = read(fd, xml, sz)) <= 0) { 165 if (errno == ENOMEM) { 166 sz <<= 2; 167 realloc(xml, sz); 168 goto again; 169 } 170 free(xml); 171 return; 172 } 173 174 dict = prop_dictionary_internalize(xml); 175 free(xml); 176 if (dict == NULL) { 177 syslog(LOG_ERR, "internalization of xml failed"); 178 return; 179 } 180 181 pn = prop_dictionary_get(dict, "evtype"); 182 if (pn == NULL) { 183 syslog(LOG_ERR, "read_event: no key evtype"); 184 goto out; 185 } 186 187 evtype = prop_number_integer_value(pn); 188 189 evdict = prop_dictionary_get(dict, "evdict"); 190 if (evdict == NULL) { 191 syslog(LOG_ERR, "read_event: no key evdict"); 192 goto out; 193 } 194 195 switch (evtype) { 196 case UDEV_EVENT_ATTACH: 197 monitor_queue_event(dict); 198 pae = pdev_array_entry_get_last(); 199 pa = prop_array_copy(pae->pdev_array); 200 pdev_array_entry_unref(pae); 201 if (pa == NULL) 202 goto out; 203 prop_array_add(pa, evdict); 204 pdev_array_entry_insert(pa); 205 break; 206 207 case UDEV_EVENT_DETACH: 208 monitor_queue_event(dict); 209 if ((devdict = find_dev_dict(-1, evdict, &idx)) == NULL) 210 goto out; 211 pae = pdev_array_entry_get_last(); 212 pa = prop_array_copy(pae->pdev_array); 213 pdev_array_entry_unref(pae); 214 if (pa == NULL) 215 goto out; 216 prop_array_remove(pa, idx); 217 pdev_array_entry_insert(pa); 218 break; 219 220 case UDEV_EV_KEY_UPDATE: 221 if ((devdict = find_dev_dict(-1, evdict, NULL)) == NULL) 222 goto out; 223 if ((ps = prop_dictionary_get(evdict, "key")) == NULL) 224 goto out; 225 if ((po = prop_dictionary_get(evdict, "value")) == NULL) 226 goto out; 227 /* prop_object_retain(po); */ /* not necessary afaik */ 228 prop_dictionary_set(devdict, prop_string_cstring_nocopy(ps), po); 229 break; 230 231 case UDEV_EV_KEY_REMOVE: 232 if ((devdict = find_dev_dict(-1, evdict, NULL)) == NULL) 233 goto out; 234 if ((ps = prop_dictionary_get(evdict, "key")) == NULL) 235 goto out; 236 prop_dictionary_remove(devdict, prop_string_cstring_nocopy(ps)); 237 break; 238 239 default: 240 syslog(LOG_ERR, "read_event: unknown evtype %d", evtype); 241 } 242 243 out: 244 prop_object_release(dict); 245 return; 246 } 247 248 prop_array_t 249 udev_getdevs(int devfd) 250 { 251 prop_dictionary_t pd, rpd; 252 prop_string_t ps; 253 prop_array_t pa; 254 255 pd = prop_dictionary_create(); 256 if (pd == NULL) { 257 err(1, "prop_dictionary_create()"); 258 } 259 260 ps = prop_string_create_cstring("getdevs"); 261 if (ps == NULL) { 262 prop_object_release(pd); 263 err(1, "prop_string_create_cstring()"); 264 } 265 266 if (prop_dictionary_set(pd, "command", ps) == false) { 267 prop_object_release(ps); 268 prop_object_release(pd); 269 err(1, "prop_dictionary_set()"); 270 } 271 272 prop_object_release(ps); 273 274 /* Send dictionary to kernel space */ 275 if (prop_dictionary_sendrecv_ioctl(pd, devfd, UDEVPROP, &rpd) != 0) 276 err(1, "prop_array_recv_ioctl()"); 277 278 prop_object_release(pd); 279 280 pa = prop_dictionary_get(rpd, "array"); 281 if (pa == NULL) 282 goto out; 283 prop_object_retain(pa); 284 285 out: 286 prop_object_release(rpd); 287 return pa; 288 } 289 290 static void 291 killed(int sig __unused) 292 { 293 syslog(LOG_ERR, "udevd stopped"); 294 unlink("/var/run/udevd.pid"); 295 pdev_array_clean(); 296 } 297 298 int 299 ignore_signal(int signum) 300 { 301 struct sigaction act; 302 int ret; 303 304 act.sa_handler = SIG_IGN; 305 sigemptyset(&act.sa_mask); 306 act.sa_flags = 0; 307 308 ret = sigaction(signum, &act, NULL); 309 return ret; 310 } 311 312 static int 313 set_killed_signal(void) 314 { 315 struct sigaction act; 316 int ret; 317 318 act.sa_handler = killed; 319 sigemptyset(&act.sa_mask); 320 act.sa_flags = 0; 321 322 ret = sigaction(SIGTERM, &act, NULL); 323 return ret; 324 } 325 326 int main(int argc __unused, char *argv[] __unused) 327 { 328 int error __unused, i, r, s; 329 struct pollfd fds[NFDS]; 330 FILE *pidf; 331 332 TAILQ_INIT(&pdev_array_list); 333 TAILQ_INIT(&udev_monitor_list); 334 335 r = ignore_signal(SIGPIPE); 336 if (r != 0) 337 err(1, "could not ignore_signal SIGPIPE"); 338 339 r = pthread_mutex_init(&(monitor_lock), NULL); 340 if (r != 0) 341 err(1, "could not allocate a pthread_mutex"); 342 343 if ((udevfd = open(UDEV_DEVICE_PATH, O_RDWR | O_NONBLOCK)) == -1) 344 err(1, "%s", UDEV_DEVICE_PATH); 345 unblock_descriptor(udevfd); 346 347 s = init_local_server(LISTEN_SOCKET_FILE, SOCK_STREAM, 0); 348 if (s < 0) 349 err(1, "init_local_server"); 350 351 pidf = fopen("/var/run/udevd.pid", "w"); 352 if (pidf == NULL) 353 err(1, "pidfile"); 354 355 set_killed_signal(); 356 357 if (daemon(0, 0) == -1) 358 err(1, "daemon"); 359 360 fprintf(pidf, "%ld\n", (long)getpid()); 361 fclose(pidf); 362 363 syslog(LOG_ERR, "udevd started"); 364 365 pdev_array_entry_insert(udev_getdevs(udevfd)); 366 367 memset(fds, 0 , sizeof(fds)); 368 fds[UDEV_DEVICE_FD_IDX].fd = udevfd; 369 fds[UDEV_DEVICE_FD_IDX].events = POLLIN; 370 fds[UDEV_SOCKET_FD_IDX].fd = s; 371 fds[UDEV_SOCKET_FD_IDX].events = POLLIN | POLLPRI; 372 373 for (;;) { 374 r = poll(fds, NFDS, -1); 375 if (r < 0) 376 err(1, "polling..."); 377 378 for (i = 0; (i < NFDS) && (r > 0); i++) { 379 if (fds[i].revents == 0) 380 continue; 381 382 --r; 383 switch (i) { 384 case UDEV_DEVICE_FD_IDX: 385 udev_read_event(udevfd); 386 break; 387 case UDEV_SOCKET_FD_IDX: 388 handle_new_connection(s); 389 break; 390 default: 391 break; 392 } 393 } 394 } 395 396 return 0; 397 } 398