From 2e7bf158f373428dba2c765c927f14d9e94f00a4 Mon Sep 17 00:00:00 2001 From: Alex Hornung Date: Sat, 10 Jul 2010 09:41:40 +0100 Subject: [PATCH] udevd - bring into sbin, add rc script * Bring udevd into sbin so it can be used very early on, for example in the initrd environment. * Add an rc script for udevd. * Remove debugging flags from libdevattr Makefile --- etc/rc.d/Makefile | 2 +- etc/rc.d/udevd | 12 + lib/libdevattr/Makefile | 1 - sbin/Makefile | 1 + sbin/udevd/Makefile | 7 + sbin/udevd/mktest | 7 + sbin/udevd/test_udevd.c | 770 ++++++++++++++++++++++++++++++++++++++++ sbin/udevd/udevd.c | 365 +++++++++++++++++++ sbin/udevd/udevd.h | 119 ++++++ sbin/udevd/udevd_client.c | 231 ++++++++++++ sbin/udevd/udevd_monitor.c | 485 +++++++++++++++++++++++++ sbin/udevd/udevd_pdev.c | 138 +++++++ sbin/udevd/udevd_socket.c | 157 ++++++++ usr.sbin/Makefile | 1 - usr.sbin/udevd/Makefile | 8 - usr.sbin/udevd/mktest | 7 - usr.sbin/udevd/test_udevd.c | 770 ---------------------------------------- usr.sbin/udevd/udevd.c | 365 ------------------- usr.sbin/udevd/udevd.h | 119 ------ usr.sbin/udevd/udevd_client.c | 231 ------------ usr.sbin/udevd/udevd_monitor.c | 485 ------------------------- usr.sbin/udevd/udevd_pdev.c | 138 ------- usr.sbin/udevd/udevd_socket.c | 157 -------- 23 files changed, 2293 insertions(+), 2283 deletions(-) create mode 100644 etc/rc.d/udevd create mode 100644 sbin/udevd/Makefile create mode 100644 sbin/udevd/mktest create mode 100644 sbin/udevd/test_udevd.c create mode 100644 sbin/udevd/udevd.c create mode 100644 sbin/udevd/udevd.h create mode 100644 sbin/udevd/udevd_client.c create mode 100644 sbin/udevd/udevd_monitor.c create mode 100644 sbin/udevd/udevd_pdev.c create mode 100644 sbin/udevd/udevd_socket.c delete mode 100644 usr.sbin/udevd/Makefile delete mode 100644 usr.sbin/udevd/mktest delete mode 100644 usr.sbin/udevd/test_udevd.c delete mode 100644 usr.sbin/udevd/udevd.c delete mode 100644 usr.sbin/udevd/udevd.h delete mode 100644 usr.sbin/udevd/udevd_client.c delete mode 100644 usr.sbin/udevd/udevd_monitor.c delete mode 100644 usr.sbin/udevd/udevd_pdev.c delete mode 100644 usr.sbin/udevd/udevd_socket.c diff --git a/etc/rc.d/Makefile b/etc/rc.d/Makefile index b85004b..1a58987 100644 --- a/etc/rc.d/Makefile +++ b/etc/rc.d/Makefile @@ -22,7 +22,7 @@ FILES= DAEMON LOGIN NETWORKING SERVERS abi accounting addswap adjkerntz \ quota random rarpd rcconf resident rndcontrol root route6d routed \ routing rpcbind rtadvd rtsold rwho sysdb savecore sdpd securelevel \ sendmail sensorsd serial sppp sshd statd swap1 syscons sysctl syslogd \ - timed ttys usbd varsym vinum vkernel virecover \ + timed ttys udevd usbd varsym vinum vkernel virecover \ watchdogd wpa_supplicant \ ypbind yppasswdd ypserv ypset ypupdated ypxfrd diff --git a/etc/rc.d/udevd b/etc/rc.d/udevd new file mode 100644 index 0000000..7fbef5d --- /dev/null +++ b/etc/rc.d/udevd @@ -0,0 +1,12 @@ +#!/bin/sh +# PROVIDE: udevd +# REQUIRE: syslogd + +. /etc/rc.subr + +name="udevd" +rcvar=`set_rcvar` +command="/sbin/${name}" + +load_rc_config $name +run_rc_command "$1" diff --git a/lib/libdevattr/Makefile b/lib/libdevattr/Makefile index 340eaa8..7e7f120 100644 --- a/lib/libdevattr/Makefile +++ b/lib/libdevattr/Makefile @@ -2,7 +2,6 @@ LIB= devattr SRCS= devattr.c devattr_device.c devattr_enumerate.c devattr_monitor.c WARNS?= 6 -DEBUG_FLAGS=-g LDADD+= -lprop DPADD+= ${LIBPROP} diff --git a/sbin/Makefile b/sbin/Makefile index 36bb84b..4655bc6 100644 --- a/sbin/Makefile +++ b/sbin/Makefile @@ -91,6 +91,7 @@ SUBDIR= adjkerntz \ swapon \ sysctl \ tunefs \ + udevd \ umount \ vinum diff --git a/sbin/udevd/Makefile b/sbin/udevd/Makefile new file mode 100644 index 0000000..371a89b --- /dev/null +++ b/sbin/udevd/Makefile @@ -0,0 +1,7 @@ +PROG= udevd +SRCS= udevd.c udevd_client.c udevd_monitor.c udevd_pdev.c +SRCS+= udevd_socket.c +LDADD= -lprop -lpthread +NOMAN= + +.include diff --git a/sbin/udevd/mktest b/sbin/udevd/mktest new file mode 100644 index 0000000..9a39224 --- /dev/null +++ b/sbin/udevd/mktest @@ -0,0 +1,7 @@ +DEBUG_FLAGS=-g +PROG= test_udevd +SRCS= test_udevd.c +LDADD= -lprop +NOMAN= + +.include diff --git a/sbin/udevd/test_udevd.c b/sbin/udevd/test_udevd.c new file mode 100644 index 0000000..6564dfc --- /dev/null +++ b/sbin/udevd/test_udevd.c @@ -0,0 +1,770 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define LISTEN_SOCKET_FILE "/tmp/udevd.socket" +#define SOCKFILE_NAMELEN strlen(LISTEN_SOCKET_FILE)+1 + +int conn_local_server(const char *sockfile, int socktype, int nonblock, + int *retsock); +prop_dictionary_t udevd_get_command_dict(char *command); +void udevd_request_devs(int s); + +struct udev { + int gp_fd; + int monitor_fd; + int refs; + + void *userdata; +}; + +struct udev_enumerate { + struct udev *udev_ctx; + prop_array_t pa; + int refs; + TAILQ_HEAD(, udev_list_entry) list_entries; +}; + +struct udev_list_entry { + prop_dictionary_t dict; + TAILQ_ENTRY(udev_list_entry) link; +}; + +struct udev_monitor { + struct udev *udev_ctx; + prop_array_t ev_filt; + int socket; + int user_socket; /* maybe... one day... */ + int refs; +}; + +struct udev_device { + struct udev *udev_ctx; + prop_dictionary_t dict; + int ev_type; + int refs; +}; + +struct udev * +udev_ref(struct udev *udev_ctx) +{ + atomic_add_int(&udev_ctx->refs, 1); + + return udev_ctx; +} + +void +udev_unref(struct udev *udev_ctx) +{ + int refcount; + + refcount = atomic_fetchadd_int(&udev_ctx->refs, -1); + + if (refcount == 1) { + atomic_subtract_int(&udev_ctx->refs, 0x400); /* in destruction */ + if (udev_ctx->gp_fd != -1) + close (udev_ctx->gp_fd); + if (udev_ctx->monitor_fd != -1) + close (udev_ctx->monitor_fd); + + free(udev_ctx); + } +} + +struct udev * +udev_new() +{ + struct udev *udev_ctx; + + udev_ctx = malloc(sizeof(struct udev)); + + udev_ctx->refs = 1; + udev_ctx->gp_fd = -1; + udev_ctx->monitor_fd = -1; + udev_ctx->userdata = NULL; + + return udev_ctx; +} + +const char *udev_get_dev_path(struct udev *udev_ctx __unused) +{ + return "/dev"; +} + +void * +udev_get_userdata(struct udev *udev_ctx) +{ + return udev_ctx->userdata; +} + +void +udev_set_userdata(struct udev *udev_ctx, void *userdata) +{ + udev_ctx->userdata = userdata; +} + +struct udev_enumerate * +udev_enumerate_new(struct udev *udev_ctx) +{ + struct udev_enumerate *udev_enum; + + udev_enum = malloc(sizeof(struct udev_enumerate)); + + udev_enum->refs = 1; + udev_enum->pa = NULL; + TAILQ_INIT(&udev_enum->list_entries); + udev_enum->udev_ctx = udev_ref(udev_ctx); +} + +struct udev_enumerate * +udev_enumerate_ref(struct udev_enumerate *udev_enum) +{ + atomic_add_int(&udev_enum->refs, 1); + + return udev_enum; +} + +void +udev_enumerate_unref(struct udev_enumerate *udev_enum) +{ + struct udev_list_entry *le; + int refcount; + + refcount = atomic_fetchadd_int(&udev_enum->refs, -1); + + if (refcount == 1) { + atomic_subtract_int(&udev_enum->refs, 0x400); /* in destruction */ + if (udev_enum->pa != NULL) + prop_object_release(udev_enum->pa); + + while (!TAILQ_EMPTY(&udev_enum->list_entries)) { + le = TAILQ_FIRST(&udev_enum->list_entries); + TAILQ_REMOVE(&udev_enum->list_entries, le, link); + prop_object_release(le->dict); + free(le); + } + udev_unref(udev_enum->udev_ctx); + free(udev_enum); + } +} + +struct udev * +udev_enumerate_get_udev(struct udev_enumerate *udev_enum) +{ + return udev_enum->udev_ctx; +} + +int +udev_enumerate_scan_devices(struct udev_enumerate *udev_enum) +{ + prop_array_t pa; + + if (udev_enum->udev_ctx->gp_fd == -1) + return -1; + + pa = udevd_request_devs(udev_enum->udev_ctx->gp_fd); + if (pa == NULL) + return -1; + + prop_object_retain(pa); + + if (udev_enum->pa != NULL) + prop_object_release(udev_enum->pa); + + udev_enum->iter = NULL; + udev_enum->pa = pa; + + return 0; +} + +struct udev_list_entry * +udev_enumerate_get_list_entry(struct udev_enumerate *udev_enum) +{ + struct udev_list_entry *le; + prop_object_iterator_t iter; + + /* If the list is not empty, assume it was populated in an earlier call */ + if (!TAILQ_EMPTY(&udev_enum->list_entries)) + return TAILQ_FIRST(&udev_enum->list_entries); + + iter = prop_array_iterator(udev_enum->pa); + if (iter == NULL) + return NULL; + + while ((dict = prop_object_iterator_next(iter)) != NULL) { + le = malloc(sizeof(struct udev_list_entry)); + if (le == NULL) + goto out; + + prop_object_retain(dict); + le->dict = dict; + TAILQ_INSERT_TAIL(&udev_enum->list_entries, le, link); + } + + le = TAILQ_FIRST(&udev_enum->list_entries); + +out: + prop_object_iterator_release(iter); + return le; +} + +prop_array_t +udev_enumerate_get_array(struct udev_enumerate *udev_enum) +{ + return udev_enum->pa; +} + +struct udev_list_entry * +udev_list_entry_get_next(struct udev_list_entry *list_entry) +{ + return TAILQ_NEXT(list_entry, link); +} + +prop_dictionary_t +udev_list_entry_get_dictionary(struct udev_list_entry *list_entry) +{ + return list_entry->dict; +} + +#define udev_list_entry_foreach(list_entry, first_entry) \ + for(list_entry = first_entry; \ + list_entry != NULL; \ + list_entry = udev_list_entry_get_next(list_entry)) + + + + + + +struct udev_monitor * +udev_monitor_new(struct udev *udev_ctx) +{ + struct udev_monitor *udev_monitor; + int ret, s; + + ret = conn_local_server(LISTEN_SOCKET_FILE, SOCK_STREAM, 0, &s); + if (ret < 0) + return NULL; + + udev_monitor = malloc(sizeof(struct udev_monitor)); + if (udev_monitor == NULL) + return NULL; + + udev_monitor->refs = 1; + udev_monitor->ev_filt = NULL; + udev_monitor->socket = s; + udev_monitor->user_socket = 1; + udev_monitor->udev_ctx = udev_ref(udev_ctx); + + return udev_monitor; +} + + +struct udev_monitor * +udev_monitor_ref(struct udev_monitor *udev_monitor) +{ + atomic_add_int(&udev_monitor->refs, 1); + + return udev_monitor; +} + +void +udev_monitor_unref(struct udev_monitor *udev_monitor) +{ + int refcount; + + refcount = atomic_fetchadd_int(&udev_monitor->refs, -1); + + if (refcount == 1) { + atomic_subtract_int(&udev_monitor->refs, 0x400); /* in destruction */ + if (udev_monitor->ev_filt != NULL) + prop_object_release(udev_monitor->ev_filt); + + if (udev_monitor->socket != -1) + close(udev_monitor->socket); + if (udev_monitor->user_socket != -1) + close(udev_monitor->user_socket); + + udev_unref(udev_monitor->udev_ctx); + free(udev_monitor); + } +} + +struct udev * +udev_monitor_get_udev(struct udev_monitor *udev_monitor) +{ + return udev_monitor->udev_ctx; +} + +int +udev_monitor_get_fd(struct udev_monitor *udev_monitor) +{ + return udev_monitor->socket; +} + +struct udev_device * +udev_monitor_receive_device(struct udev_monitor *udev_monitor) +{ + struct udev_device *udev_dev; + prop_dictionary_t dict; + prop_number_t pn; + char *xml; + int n, evtype; + + xml = malloc(12*1024*1024); + if (xml == NULL) + return NULL; + + if ((n = read_xml(udev_monitor->socket, xml, 12*1024*1024)) <= 0) { + free(xml); + return NULL; + } + + xml[n+1] = '\0'; + dict = prop_dictionary_internalize(xml); + free(xml); + if (dict == NULL) + return NULL; + + pn = prop_dictionary_get(dict, "evtype"); + if (pn == NULL) { + prop_object_release(dict); + return NULL; + } + + udev_dev = malloc(sizeof(struct udev_dev)); + if (udev_dev == NULL) { + prop_object_release(dict); + return NULL; + } + + udev_dev->refs = 1; + udev_dev->ev_type = prop_number_integer_value(pn); + udev_dev->dict = prop_dictionary_get(dict, "evdict"); + if (udev_dev->dict == NULL) { + free(udev_dev); + return NULL; + } + udev_dev->udev_ctx = udev_ref(udev_monitor->udev_ctx); + +out: + return udev_dev; +} + +int +udev_monitor_enable_receiving(struct udev_monitor *udev_monitor) +{ + prop_dictionary_t dict; + char *xml; + /* ->socket, ->user_socket, ->ev_filt */ + + dict = udevd_get_command_dict(__DECONST(char *, "monitor")); + if (dict == NULL) + return -1; + + /* Add event filters to message, if available */ + if (udev_monitor->ev_filt != NULL) { + if (prop_dictionary_set(dict, "filters", + udev_monitor->ev_filt) == false) { + prop_object_release(dict); + return -1; + } + } + + xml = prop_dictionary_externalize(dict); + prop_object_release(dict); + if (xml == NULL) + return -1; + + n = send_xml(udev_monitor->socket, xml); + free(xml); + if (n <= 0) + return NULL; + + return 0; +} + +int +udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, + const char *subsystem, + const char *devtype __unused) +{ + int ret; + + ret = _udev_monitor_filter_add_match_gen(udev_monitor, + EVENT_FILTER_TYPE_WILDCARD, + 0, + "subsystem", + subsystem); + + return ret; +} + +int +udev_monitor_filter_add_match_expr(struct udev_monitor *udev_monitor, + const char *key, + char *expr) +{ + int ret; + + ret = _udev_monitor_filter_add_match_gen(udev_monitor, + EVENT_FILTER_TYPE_WILDCARD, + 0, + key, + expr); + + return ret; +} + +int +udev_monitor_filter_add_nomatch_expr(struct udev_monitor *udev_monitor, + const char *key, + char *expr) +{ + int ret; + + ret = _udev_monitor_filter_add_match_gen(udev_monitor, + EVENT_FILTER_TYPE_WILDCARD, + 1, + key, + expr); + + return ret; +} + +int +udev_monitor_filter_add_match_regex(struct udev_monitor *udev_monitor, + const char *key, + char *expr) +{ + int ret; + + ret = _udev_monitor_filter_add_match_gen(udev_monitor, + EVENT_FILTER_TYPE_REGEX, + 0, + key, + expr); + + return ret; +} + +int +udev_monitor_filter_add_nomatch_regex(struct udev_monitor *udev_monitor, + const char *key, + char *expr) +{ + int ret; + + ret = _udev_monitor_filter_add_match_gen(udev_monitor, + EVENT_FILTER_TYPE_REGEX, + 1, + key, + expr); + + return ret; +} + +int +_udev_monitor_filter_add_match_gen(struct udev_monitor *udev_monitor, + int type, + int neg, + const char *key, + char *expr) +{ + prop_array_t pa; + prop_dictionary_t dict; + int error; + + if (subsystem == NULL) + return NULL; + + dict = prop_dictionary_create(); + if (dict == NULL) + return -1; + + error = _udev_dict_set_cstr(dict, "key", key); + if (error != 0) + goto error_out; + error = _udev_dict_set_int(dict, "type", type); + if (error != 0) + goto error_out; + error = _udev_dict_set_int(dict, "expr", expr); + if (error != 0) + goto error_out; + + if (neg) { + error = _udev_dict_set_int(dict, "negative", 1); + if (error != 0) + goto error_out; + } + + if (udev_monitor->ev_filt == NULL) { + pa = prop_array_create(); + if (pa == NULL) + goto error_out; + + udev_monitor->ev_filt = pa; + } + + if (prop_array_add(udev_monitor->ev_filt, dict) == false) + goto error_out; + + return 0; + +error_out: + prop_object_release(dict); + return -1; +} + +struct udev_device * +udev_device_ref(struct udev_device *udev_device) +{ + atomic_add_int(&udev_device->refs, 1); + + return udev_device; +} + +void +udev_device_unref(struct udev_device *udev_device) +{ + int refcount; + + refcount = atomic_fetchadd_int(&udev_device->refs, -1); + + if (refcount == 1) { + atomic_subtract_int(&udev_device->refs, 0x400); /* in destruction */ + if (udev_device->dict != NULL) + prop_object_release(udev_device->dict); + + udev_unref(udev_device->udev_ctx); + free(udev_device); + } +} + +prop_dictionary_t +udev_device_get_dictionary(struct udev_device *udev_device) +{ + return udev_device->dict; +} + +struct udev * +udev_device_get_udev(struct udev_device *udev_device) +{ + return udev_device->udev_ctx; +} + +int +send_xml(int s, char *xml) +{ + ssize_t r,n; + size_t sz; + + sz = strlen(xml) + 1; + + r = send(s, &sz, sizeof(sz), 0); + if (r <= 0) + return r; + + r = 0; + while (r < (ssize_t)sz) { + n = send(s, xml+r, sz-r, 0); + if (n <= 0) + return n; + r += n; + } + + return r; +} + +int +read_xml(int s, char *buf, size_t buf_sz) +{ + size_t sz; + int n, r; + + n = recv(s, &sz, sizeof(sz), MSG_WAITALL); + if (n <= 0) + return n; + + r = 0; + while ((r < (ssize_t)sz) && (r < (ssize_t)buf_sz)) { + n = recv(s, buf+r, sz-r, MSG_WAITALL); + if (n <= 0) + return n; + r += n; + } + + return r; +} + + + +static int +_udev_dict_set_cstr(prop_dictionary_t dict, const char *key, char *str) +{ + prop_string_t ps; + + ps = prop_string_create_cstring(str); + if (ps == NULL) + return ENOMEM; + + if (prop_dictionary_set(dict, key, ps) == false) { + prop_object_release(ps); + return ENOMEM; + } + + prop_object_release(ps); + return 0; +} + +static int +_udev_dict_set_int(prop_dictionary_t dict, const char *key, int64_t val) +{ + prop_number_t pn; + + pn = prop_number_create_integer(val); + if (pn == NULL) + return ENOMEM; + + if (prop_dictionary_set(dict, key, pn) == false) { + prop_object_release(pn); + return ENOMEM; + } + + prop_object_release(pn); + return 0; +} + +static int +_udev_dict_set_uint(prop_dictionary_t dict, const char *key, uint64_t val) +{ + prop_number_t pn; + + pn = prop_number_create_unsigned_integer(val); + if (pn == NULL) + return ENOMEM; + + if (prop_dictionary_set(dict, key, pn) == false) { + prop_object_release(pn); + return ENOMEM; + } + + prop_object_release(pn); + return 0; +} + +int +conn_local_server(const char *sockfile, int socktype, int nonblock, + int *retsock) +{ + int s; + struct sockaddr_un serv_addr; + + *retsock = -1; + if ((s = socket(AF_UNIX, socktype, 0)) < 0) + return -1; + + memset(&serv_addr, 0, sizeof(serv_addr)); + serv_addr.sun_family = AF_UNIX; + strncpy(serv_addr.sun_path, sockfile, SOCKFILE_NAMELEN); + serv_addr.sun_path[SOCKFILE_NAMELEN - 1] = '\0'; + + if (nonblock && unblock_descriptor(s) < 0) { + close(s); + return -1; + } + + *retsock = s; + return connect(s, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); +} + +prop_dictionary_t +udevd_get_command_dict(char *command) +{ + prop_dictionary_t dict; + int error; + + dict = prop_dictionary_create(); + if (dict == NULL) + return NULL; + + if ((error = _udev_dict_set_cstr(dict, "command", command))) + goto error_out; + + return dict; + +error_out: + prop_object_release(dict); + return NULL; +} + +prop_array_t +udevd_request_devs(int s) +{ + prop_array_t pa; + prop_dictionary_t dict; + char *xml; + + int n, t; + + dict = udevd_get_command_dict(__DECONST(char *, "getdevs")); + if (dict == NULL) + return NULL; + + xml = prop_dictionary_externalize(dict); + prop_object_release(dict); + if (xml == NULL) + return NULL; + + n = send_xml(s, xml); + free(xml); + + if (n <= 0) + return NULL; + + xml = malloc(12*1024*1024); /* generous 12 MB */ + if ((n = read_xml(s, xml, 12*1024*1024)) <= 0) { + free(xml); + return NULL; + } + + xml[n+1] = '\0'; + pa = prop_array_internalize(xml); + free(xml); + return (pa); +} + + + +int +main(void) +{ + int ret, s; + + ret = conn_local_server(LISTEN_SOCKET_FILE, SOCK_STREAM, 0, &s); + if (ret < 0) + err(1, "conn_local_server"); + + udevd_request_devs(s); + + return 0; +} diff --git a/sbin/udevd/udevd.c b/sbin/udevd/udevd.c new file mode 100644 index 0000000..015998e --- /dev/null +++ b/sbin/udevd/udevd.c @@ -0,0 +1,365 @@ +/* + * Copyright (c) 2010 The DragonFly Project. All rights reserved. + * + * This code is derived from software contributed to The DragonFly Project + * by Alex Hornung + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of The DragonFly Project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific, prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "udevd.h" + +static int udevfd; + +extern pthread_mutex_t monitor_lock; +extern TAILQ_HEAD(udev_monitor_list_head, udev_monitor) udev_monitor_list; +extern TAILQ_HEAD(pdev_array_list_head, pdev_array_entry) pdev_array_list; + +int match_dev_dict(prop_dictionary_t, prop_dictionary_t); +prop_dictionary_t find_dev_dict(int64_t, prop_dictionary_t, int *); + +void udev_read_event(int); +prop_array_t udev_getdevs(int); + +int +match_dev_dict(prop_dictionary_t dict, prop_dictionary_t match_dict) +{ + prop_number_t pn, pn2; + prop_string_t ps, ps2; + + if (dict == NULL) + return 0; + + if ((ps = prop_dictionary_get(dict, "name")) == NULL) + return 0; + if ((ps2 = prop_dictionary_get(match_dict, "name")) == NULL) + return 0; + if (!prop_string_equals(ps, ps2)) + return 0; + + if ((pn = prop_dictionary_get(dict, "devnum")) == NULL) + return 0; + if ((pn2 = prop_dictionary_get(match_dict, "devnum")) == NULL) + return 0; + if (!prop_number_equals(pn, pn2)) + return 0; + + if ((pn = prop_dictionary_get(dict, "kptr")) == NULL) + return 0; + if ((pn2 = prop_dictionary_get(match_dict, "kptr")) == NULL) + return 0; + if (!prop_number_equals(pn, pn2)) + return 0; + + return 1; +} + +prop_dictionary_t +find_dev_dict(int64_t generation, prop_dictionary_t match_dict, int *idx) +{ + struct pdev_array_entry *pae; + prop_array_t pa; + prop_object_iterator_t iter; + prop_dictionary_t dict; + int i = 0; + + if (generation == -1) + pae = pdev_array_entry_get_last(); + else + pae = pdev_array_entry_get(generation); + + if (pae == NULL) + return NULL; + + pa = pae->pdev_array; + + iter = prop_array_iterator(pa); + if (iter == NULL) { + pdev_array_entry_unref(pae); + return NULL; + } + + while ((dict = prop_object_iterator_next(iter)) != NULL) { + if (match_dev_dict(dict, match_dict)) + break; + ++i; + } + + prop_object_iterator_release(iter); + + if (idx != NULL) + *idx = i; + + pdev_array_entry_unref(pae); + return dict; +} + +void +udev_read_event(int fd) +{ + struct pdev_array_entry *pae; + prop_dictionary_t dict, evdict, devdict; + prop_number_t pn; + prop_string_t ps; + prop_object_t po; + prop_array_t pa; + char *xml; + int n, idx, evtype; + size_t sz; + + sz = 4096 * 1024; + + xml = malloc(sz); /* 4 MB */ +again: + if ((n = read(fd, xml, sz)) <= 0) { + if (errno == ENOMEM) { + sz <<= 2; + realloc(xml, sz); + goto again; + } + free(xml); + return; + } + + dict = prop_dictionary_internalize(xml); + free(xml); + if (dict == NULL) { + syslog(LOG_ERR, "internalization of xml failed"); + return; + } + + pn = prop_dictionary_get(dict, "evtype"); + if (pn == NULL) { + syslog(LOG_ERR, "read_event: no key evtype"); + goto out; + } + + evtype = prop_number_integer_value(pn); + + evdict = prop_dictionary_get(dict, "evdict"); + if (evdict == NULL) { + syslog(LOG_ERR, "read_event: no key evdict"); + goto out; + } + + switch (evtype) { + case UDEV_EVENT_ATTACH: + monitor_queue_event(dict); + pae = pdev_array_entry_get_last(); + pa = prop_array_copy(pae->pdev_array); + pdev_array_entry_unref(pae); + if (pa == NULL) + goto out; + prop_array_add(pa, evdict); + pdev_array_entry_insert(pa); + break; + + case UDEV_EVENT_DETACH: + monitor_queue_event(dict); + if ((devdict = find_dev_dict(-1, evdict, &idx)) == NULL) + goto out; + pae = pdev_array_entry_get_last(); + pa = prop_array_copy(pae->pdev_array); + pdev_array_entry_unref(pae); + if (pa == NULL) + goto out; + prop_array_remove(pa, idx); + //pdev_array_entry_insert(pa); + break; + + case UDEV_EV_KEY_UPDATE: + if ((devdict = find_dev_dict(-1, evdict, NULL)) == NULL) + goto out; + if ((ps = prop_dictionary_get(evdict, "key")) == NULL) + goto out; + if ((po = prop_dictionary_get(evdict, "value")) == NULL) + goto out; + /* prop_object_retain(po); */ /* not necessary afaik */ + prop_dictionary_set(devdict, prop_string_cstring_nocopy(ps), po); + break; + + case UDEV_EV_KEY_REMOVE: + if ((devdict = find_dev_dict(-1, evdict, NULL)) == NULL) + goto out; + if ((ps = prop_dictionary_get(evdict, "key")) == NULL) + goto out; + prop_dictionary_remove(devdict, prop_string_cstring_nocopy(ps)); + break; + + default: + syslog(LOG_ERR, "read_event: unknown evtype %d", evtype); + } + +out: + prop_object_release(dict); + return; +} + +prop_array_t +udev_getdevs(int devfd) +{ + prop_dictionary_t pd, rpd; + prop_string_t ps; + prop_array_t pa; + + pd = prop_dictionary_create(); + if (pd == NULL) { + err(1, "prop_dictionary_create()"); + } + + ps = prop_string_create_cstring("getdevs"); + if (ps == NULL) { + prop_object_release(pd); + err(1, "prop_string_create_cstring()"); + } + + if (prop_dictionary_set(pd, "command", ps) == false) { + prop_object_release(ps); + prop_object_release(pd); + err(1, "prop_dictionary_set()"); + } + + prop_object_release(ps); + + /* Send dictionary to kernel space */ + if (prop_dictionary_sendrecv_ioctl(pd, devfd, UDEVPROP, &rpd) != 0) + err(1, "prop_array_recv_ioctl()"); + + prop_object_release(pd); + + pa = prop_dictionary_get(rpd, "array"); + if (pa == NULL) + goto out; + prop_object_retain(pa); + +out: + prop_object_release(rpd); + return pa; +} + +int +ignore_signal(int signum) +{ + struct sigaction act; + int ret; + + act.sa_handler = SIG_IGN; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + + ret = sigaction(signum, &act, NULL); + return ret; +} + +int main(int argc __unused, char *argv[] __unused) +{ + int error __unused, i, r, s; + struct pollfd fds[NFDS]; + + TAILQ_INIT(&pdev_array_list); + TAILQ_INIT(&udev_monitor_list); + + r = ignore_signal(SIGPIPE); + if (r != 0) + err(1, "could not ignore_signal SIGPIPE"); + + r = pthread_mutex_init(&(monitor_lock), NULL); + if (r != 0) + err(1, "could not allocate a pthread_mutex"); + + if ((udevfd = open(UDEV_DEVICE_PATH, O_RDWR | O_NONBLOCK)) == -1) + err(1, "%s", UDEV_DEVICE_PATH); + unblock_descriptor(udevfd); + + s = init_local_server(LISTEN_SOCKET_FILE, SOCK_STREAM, 0); + if (s < 0) + err(1, "init_local_server"); + + if (daemon(0, 0) == -1) + err(1, "daemon"); + + syslog(LOG_ERR, "udevd started"); + + pdev_array_entry_insert(udev_getdevs(udevfd)); + + memset(fds, 0 , sizeof(fds)); + fds[UDEV_DEVICE_FD_IDX].fd = udevfd; + fds[UDEV_DEVICE_FD_IDX].events = POLLIN; + fds[UDEV_SOCKET_FD_IDX].fd = s; + fds[UDEV_SOCKET_FD_IDX].events = POLLIN | POLLPRI; + + for (;;) { + r = poll(fds, NFDS, -1); + if (r < 0) + err(1, "polling..."); + + for (i = 0; (i < NFDS) && (r > 0); i++) { + if (fds[i].revents == 0) + continue; + + --r; + switch (i) { + case UDEV_DEVICE_FD_IDX: + udev_read_event(udevfd); + break; + case UDEV_SOCKET_FD_IDX: + handle_new_connection(s); + break; + default: + break; + } + } + } + + return 0; +} diff --git a/sbin/udevd/udevd.h b/sbin/udevd/udevd.h new file mode 100644 index 0000000..cc19122 --- /dev/null +++ b/sbin/udevd/udevd.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2010 The DragonFly Project. All rights reserved. + * + * This code is derived from software contributed to The DragonFly Project + * by Alex Hornung + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of The DragonFly Project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific, prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#define UDEV_DEVICE_PATH "/dev/udev" +#define LOCAL_BACKLOG 5 + +#define UDEV_DEVICE_FD_IDX 0 +#define UDEV_SOCKET_FD_IDX 1 +#define NFDS 2 + + +struct pdev_array_entry { + int32_t refs; + int64_t generation; + prop_array_t pdev_array; + TAILQ_ENTRY(pdev_array_entry) link; +}; + +struct event_filter { + int id; + int neg; + int type; + char *key; + char *wildcard_match; + regex_t regex_match; + + TAILQ_ENTRY(event_filter) link; +}; + +struct udev_monitor; + +struct client_info { + pthread_t tid; + int fd; + struct udev_monitor *udm; + struct event_filter ev_filt; +}; + +struct udev_monitor_event { + prop_dictionary_t ev_dict; + TAILQ_ENTRY(udev_monitor_event) link; +}; + +struct udev_monitor { + pthread_mutex_t q_lock; + pthread_cond_t cond; + struct client_info *cli; + TAILQ_HEAD(, event_filter) ev_filt; + TAILQ_HEAD(, udev_monitor_event) ev_queue; + TAILQ_ENTRY(udev_monitor) link; +}; + +struct cmd_function { + const char *cmd; + int (*fn)(struct client_info *, prop_dictionary_t); +}; + +/* From udevd_socket.c */ +int init_local_server(const char *sockfile, int socktype, int nonblock); +int block_descriptor(int s); +int unblock_descriptor(int s); +int read_xml(int s, char *buf, size_t buf_sz); +int send_xml(int s, char *xml); + +/* From udevd_pdev.c */ +void pdev_array_entry_ref(struct pdev_array_entry *pae); +void pdev_array_entry_unref(struct pdev_array_entry *pae); +void pdev_array_entry_insert(prop_array_t pa); +struct pdev_array_entry *pdev_array_entry_get(int64_t generation); +struct pdev_array_entry *pdev_array_entry_get_last(void); + +/* From udevd_client.c */ +void handle_new_connection(int s); +int client_cmd_getdevs(struct client_info *cli, prop_dictionary_t dict); + + +/* From udevd_monitor.c */ +void monitor_queue_event(prop_dictionary_t ev_dict); +int client_cmd_monitor(struct client_info *cli, prop_dictionary_t dict); +int match_event_filter(struct udev_monitor *udm, prop_dictionary_t ev_dict); +struct udev_monitor *udev_monitor_init(struct client_info *cli, prop_array_t filters); +void udev_monitor_free(struct udev_monitor *udm); + +/* From udevd.c */ +int ignore_signal(int signum); diff --git a/sbin/udevd/udevd_client.c b/sbin/udevd/udevd_client.c new file mode 100644 index 0000000..79f25f9 --- /dev/null +++ b/sbin/udevd/udevd_client.c @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2010 The DragonFly Project. All rights reserved. + * + * This code is derived from software contributed to The DragonFly Project + * by Alex Hornung + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of The DragonFly Project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific, prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "udevd.h" + +struct cmd_function cmd_fn[] = { + { .cmd = "getdevs", .fn = client_cmd_getdevs}, + { .cmd = "monitor", .fn = client_cmd_monitor}, + {NULL, NULL} +}; + +static void *client_thread(void *arg); + +void +handle_new_connection(int s) +{ + struct client_info *cli_info; + struct sockaddr_un addr; + int fd; + socklen_t saddr_len = sizeof(struct sockaddr_un); + + fd = accept(s, (struct sockaddr *)&addr, &saddr_len); + if (fd < 0) { + syslog(LOG_ERR, "uh, oh, accept failed with %d", errno); + return; + } + + block_descriptor(fd); + cli_info = malloc(sizeof(struct client_info)); + memset(cli_info, 0, sizeof(struct client_info)); + + cli_info->fd = fd; + pthread_create(&cli_info->tid, NULL, client_thread, (void *)cli_info); +} + + +static void * +client_thread(void *arg) +{ + prop_dictionary_t dict; + prop_string_t ps; + prop_object_t po; + struct client_info *cli; + char *xml; + int r, n, error; + + r = ignore_signal(SIGPIPE); + if (r != 0) + err(1, "could not ignore_signal SIGPIPE"); + + cli = (struct client_info *)arg; + xml = malloc(12*1024*1024); /* generous 12 MB */ + for (;;) { + n = read_xml(cli->fd, xml, 12*1024*1024); + if (n == 0) + goto cli_disconnect; + else if (n < 0) + goto error_out; + + xml[n+1] = '\0'; + + dict = prop_dictionary_internalize(xml); + if (dict == NULL) { + syslog(LOG_ERR, "internalization of received XML failed"); + goto error_out; + } + + po = prop_dictionary_get(dict, "command"); + if (po == NULL || prop_object_type(po) != PROP_TYPE_STRING) { + syslog(LOG_ERR, "received dictionary doesn't contain a key 'command'"); + prop_object_release(dict); + continue; + } + + ps = po; + + syslog(LOG_DEBUG, "Received command: %s (from fd = %d)\n", prop_string_cstring_nocopy(ps), cli->fd); + for(n = 0; cmd_fn[n].cmd != NULL; n++) { + if (prop_string_equals_cstring(ps, cmd_fn[n].cmd)) + break; + } + + if (cmd_fn[n].cmd != NULL) { + error = cmd_fn[n].fn(cli, dict); + if (error) { + prop_object_release(dict); + goto error_out; + } + } + prop_object_release(dict); + } + +error_out: + +cli_disconnect: + close(cli->fd); + free(xml); + cli->fd = -1; + free(cli); + return NULL; +} + +int +client_cmd_getdevs(struct client_info *cli, prop_dictionary_t cli_dict) +{ + struct pdev_array_entry *pae; + struct udev_monitor *udm; + prop_object_iterator_t iter; + prop_dictionary_t dict; + prop_object_t po; + prop_array_t pa; + char *xml; + ssize_t r; + int filters; + + + pa = NULL; + po = prop_dictionary_get(cli_dict, "filters"); + if ((po != NULL) && prop_object_type(po) == PROP_TYPE_ARRAY) { + pa = po; + filters = 1; + } else { + filters = 0; + } + + pae = pdev_array_entry_get_last(); + if (pae == NULL) + return 1; + + if (filters) { + udm = udev_monitor_init(cli, pa); + if (udm == NULL) { + pdev_array_entry_unref(pae); + return 1; + } + + pa = prop_array_create_with_capacity(10); + + iter = prop_array_iterator(pae->pdev_array); + if (iter == NULL) { + pdev_array_entry_unref(pae); + udev_monitor_free(udm); + return 1; + } + + while ((dict = prop_object_iterator_next(iter)) != NULL) { + if (match_event_filter(udm, dict)) { + prop_array_add(pa, dict); + } + } + + udev_monitor_free(udm); + } else { + pa = pae->pdev_array; + } + + xml = prop_array_externalize(pa); + if (filters) + prop_object_release(pa); + + pdev_array_entry_unref(pae); + + if (xml == NULL) + return 1; + + r = send_xml(cli->fd, xml); + if (r < 0) + syslog(LOG_DEBUG, "error while send_xml (cmd_getdevs)\n"); + if (r == 0) + syslog(LOG_DEBUG, "EOF while send_xml (cmd_getdevs)\n"); + + free(xml); + + return 0; +} diff --git a/sbin/udevd/udevd_monitor.c b/sbin/udevd/udevd_monitor.c new file mode 100644 index 0000000..4dfcd4e --- /dev/null +++ b/sbin/udevd/udevd_monitor.c @@ -0,0 +1,485 @@ +/* + * Copyright (c) 2010 The DragonFly Project. All rights reserved. + * + * This code is derived from software contributed to The DragonFly Project + * by Alex Hornung + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of The DragonFly Project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific, prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "udevd.h" + +#define MONITOR_LOCK() pthread_mutex_lock(&monitor_lock) +#define MONITOR_UNLOCK() pthread_mutex_unlock(&monitor_lock) + +static int _parse_filter_prop(struct udev_monitor *udm, prop_array_t pa); +static int match_filter(struct event_filter *evf, prop_dictionary_t dict); + +static int WildCaseCmp(const char *w, const char *s); +static int wildCaseCmp(const char **mary, int d, const char *w, const char *s); + +TAILQ_HEAD(udev_monitor_list_head, udev_monitor) udev_monitor_list; +pthread_mutex_t monitor_lock; + + +void +monitor_queue_event(prop_dictionary_t ev_dict) +{ + struct udev_monitor *udm; + struct udev_monitor_event *udm_ev; + + MONITOR_LOCK(); + + TAILQ_FOREACH(udm, &udev_monitor_list, link) { + udm_ev = malloc(sizeof(struct udev_monitor_event)); + if (udm_ev == NULL) + continue; + + prop_object_retain(ev_dict); + udm_ev->ev_dict = ev_dict; + + if (match_event_filter(udm, + prop_dictionary_get(udm_ev->ev_dict, "evdict")) == 0) { + prop_object_release(ev_dict); + free(udm_ev); + continue; + } + + pthread_mutex_lock(&udm->q_lock); + TAILQ_INSERT_TAIL(&udm->ev_queue, udm_ev, link); + pthread_cond_signal(&udm->cond); + pthread_mutex_unlock(&udm->q_lock); + } + + MONITOR_UNLOCK(); +} + +struct udev_monitor * +udev_monitor_init(struct client_info *cli, prop_array_t filters) +{ + struct udev_monitor *udm; + int error; + + udm = malloc(sizeof(struct udev_monitor)); + if (udm == NULL) + return NULL; + + TAILQ_INIT(&udm->ev_queue); + TAILQ_INIT(&udm->ev_filt); + + pthread_mutex_init(&udm->q_lock, NULL); + pthread_cond_init(&udm->cond, NULL); + udm->cli = cli; + + if (filters != NULL) { + error = _parse_filter_prop(udm, filters); + /* XXX: ignore error for now */ + } + + return udm; +} + +void +udev_monitor_free(struct udev_monitor *udm) +{ + struct event_filter *evf; + struct udev_monitor_event *udm_ev; + + pthread_mutex_lock(&udm->q_lock); + + while ((udm_ev = TAILQ_FIRST(&udm->ev_queue)) != NULL) { + prop_object_release(udm_ev->ev_dict); + udm_ev->ev_dict = NULL; + TAILQ_REMOVE(&udm->ev_queue, udm_ev, link); + free(udm_ev); + } + + while ((evf = TAILQ_FIRST(&udm->ev_filt)) != NULL) { + TAILQ_REMOVE(&udm->ev_filt, evf, link); + free(evf); + } + + pthread_mutex_unlock(&udm->q_lock); + free(udm); +} + +int +client_cmd_monitor(struct client_info *cli, prop_dictionary_t dict) +{ + prop_array_t pa; + prop_object_t po; + struct udev_monitor *udm; + struct udev_monitor_event *udm_ev; + char *xml; + ssize_t r; + int ok = 1; + + pa = NULL; + po = prop_dictionary_get(dict, "filters"); + if ((po != NULL) && prop_object_type(po) == PROP_TYPE_ARRAY) { + pa = po; + } + + udm = udev_monitor_init(cli, pa); + if (udm == NULL) + return 1; + + MONITOR_LOCK(); + TAILQ_INSERT_TAIL(&udev_monitor_list, udm, link); + MONITOR_UNLOCK(); + + pthread_mutex_lock(&udm->q_lock); + while (ok) { + pthread_cond_wait(&udm->cond, &udm->q_lock); + + udm_ev = TAILQ_FIRST(&udm->ev_queue); + if (udm_ev == NULL) + continue; + + assert(udm_ev->ev_dict != NULL); + xml = prop_dictionary_externalize(udm_ev->ev_dict); + if (xml == NULL) + continue; + + prop_object_release(udm_ev->ev_dict); + udm_ev->ev_dict = NULL; + TAILQ_REMOVE(&udm->ev_queue, udm_ev, link); + free(udm_ev); + + r = send_xml(cli->fd, xml); + if (r <= 0) + goto end; + + free(xml); + continue; +end: + pthread_mutex_unlock(&udm->q_lock); + close(cli->fd); + ok = 0; + free(xml); + } + + MONITOR_LOCK(); + TAILQ_REMOVE(&udev_monitor_list, udm, link); + MONITOR_UNLOCK(); + + udev_monitor_free(udm); + + return 1; +} + +static int +_parse_filter_prop(struct udev_monitor *udm, prop_array_t pa) +{ + prop_string_t ps; + prop_number_t pn; + prop_object_iterator_t iter; + prop_dictionary_t dict; + struct event_filter *evf; + int error; + + iter = prop_array_iterator(pa); + if (iter == NULL) + return -1; + + while ((dict = prop_object_iterator_next(iter)) != NULL) { + evf = malloc(sizeof(struct event_filter)); + if (evf == NULL) + goto error_alloc; + + ps = prop_dictionary_get(dict, "key"); + if (ps == NULL) + goto error_out; + evf->key = prop_string_cstring(ps); + if (evf->key == NULL) + goto error_out; + + pn = prop_dictionary_get(dict, "type"); + if (pn == NULL) + goto error_out_ps; + + ps = prop_dictionary_get(dict, "expr"); + if (ps == NULL) + goto error_out_ps; + + if (prop_dictionary_get(dict, "negative")) + evf->neg = 1; + else + evf->neg = 0; + + evf->type = prop_number_integer_value(pn); + switch (evf->type) { + case EVENT_FILTER_TYPE_WILDCARD: + evf->wildcard_match = prop_string_cstring(ps); + if (evf->wildcard_match == NULL) + goto error_out_ps; + break; + + case EVENT_FILTER_TYPE_REGEX: + error = regcomp(&evf->regex_match, prop_string_cstring_nocopy(ps), REG_ICASE | REG_NOSUB); + if (error) + goto error_out_ps; + break; + + default: + goto error_out_ps; + } + + pthread_mutex_lock(&udm->q_lock); + TAILQ_INSERT_TAIL(&udm->ev_filt, evf, link); + pthread_mutex_unlock(&udm->q_lock); + + } + + prop_object_iterator_release(iter); + return 0; + +error_out_ps: + free(evf->key); +error_out: + free(evf); +error_alloc: + prop_object_iterator_release(iter); + return -1; +} + +/* +Event filter format: + + +key +(e.g. kptr, devnum, ...) +type +(e.g. wildcard or regex) +expr +(regex) + +... repeat ... + +*/ + +static int +match_filter(struct event_filter *evf, prop_dictionary_t ev_dict) +{ + prop_object_t po; + prop_string_t ps; + prop_number_t pn; + char *str; + char buf[128]; + int ret; + + if (ev_dict == NULL) + return 0; + + prop_object_retain(ev_dict); + + assert(prop_dictionary_externalize(ev_dict) != NULL); + if ((po = prop_dictionary_get(ev_dict, evf->key)) == NULL) + goto no_match; + + if (prop_object_type(po) == PROP_TYPE_STRING) { + ps = po; + str = __DECONST(char *, prop_string_cstring_nocopy(ps)); + } else if (prop_object_type(po) == PROP_TYPE_NUMBER) { + pn = po; + if (prop_number_unsigned(pn)) { + snprintf(buf, sizeof(buf), "%" PRIu64, prop_number_unsigned_integer_value(pn)); + } else { + snprintf(buf, sizeof(buf), "%" PRIi64, prop_number_integer_value(pn)); + } + str = buf; + } else { + syslog(LOG_DEBUG, "Unexpected type in match_filter: %d\n", prop_object_type(po)); + /* Unexpected type */ + goto no_match; + } + + switch (evf->type) { + case EVENT_FILTER_TYPE_WILDCARD: + ret = WildCaseCmp(evf->wildcard_match, str); + + if (ret != 0) + goto no_match; + + break; + case EVENT_FILTER_TYPE_REGEX: + ret = regexec(&evf->regex_match, str, 0, NULL, 0); + + if (ret != 0) + goto no_match; + break; + default: + goto no_match; + } + + prop_object_release(ev_dict); + return 1; + +no_match: + prop_object_release(ev_dict); + return 0; +} + +int +match_event_filter(struct udev_monitor *udm, prop_dictionary_t ev_dict) +{ + struct event_filter *evf; + int all_negative = 1; + + pthread_mutex_lock(&udm->q_lock); + + if (TAILQ_EMPTY(&udm->ev_filt)) + return 1; + + TAILQ_FOREACH(evf, &udm->ev_filt, link) { + //printf("match_event_filter 3\n"); + if (evf->neg == 0) + all_negative = 0; + + if (match_filter(evf, ev_dict)) { + pthread_mutex_unlock(&udm->q_lock); + return (1 ^ evf->neg); /* return 1; or 0 for 'nomatch' hit */ + } + //printf("match_event_filter 5\n"); + } + + pthread_mutex_unlock(&udm->q_lock); + return (all_negative == 1)?1:0; +} + +static int +WildCaseCmp(const char *w, const char *s) +{ + int i; + int c; + int slen = strlen(s); + const char **mary; + + for (i = c = 0; w[i]; ++i) { + if (w[i] == '*') + ++c; + } + mary = malloc(sizeof(char *) * (c + 1)); + if (mary == NULL) + return -1; + + for (i = 0; i < c; ++i) + mary[i] = s + slen; + i = wildCaseCmp(mary, 0, w, s); + free(mary); + return(i); +} + +/* + * WildCaseCmp() - compare wild string to sane string, case insensitive + * + * Returns 0 on success, -1 on failure. + */ +static int +wildCaseCmp(const char **mary, int d, const char *w, const char *s) +{ + int i; + + /* + * skip fixed portion + */ + for (;;) { + switch(*w) { + case '*': + /* + * optimize terminator + */ + if (w[1] == 0) + return(0); + if (w[1] != '?' && w[1] != '*') { + /* + * optimize * followed by non-wild + */ + for (i = 0; s + i < mary[d]; ++i) { + if (s[i] == w[1] && wildCaseCmp(mary, d + 1, w + 1, s + i) == 0) + return(0); + } + } else { + /* + * less-optimal + */ + for (i = 0; s + i < mary[d]; ++i) { + if (wildCaseCmp(mary, d + 1, w + 1, s + i) == 0) + return(0); + } + } + mary[d] = s; + return(-1); + case '?': + if (*s == 0) + return(-1); + ++w; + ++s; + break; + default: + if (*w != *s) { + if (tolower(*w) != tolower(*s)) + return(-1); + } + if (*w == 0) /* terminator */ + return(0); + ++w; + ++s; + break; + } + } + /* not reached */ + return(-1); +} diff --git a/sbin/udevd/udevd_pdev.c b/sbin/udevd/udevd_pdev.c new file mode 100644 index 0000000..5992a13 --- /dev/null +++ b/sbin/udevd/udevd_pdev.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2010 The DragonFly Project. All rights reserved. + * + * This code is derived from software contributed to The DragonFly Project + * by Alex Hornung + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of The DragonFly Project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific, prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "udevd.h" + +static int64_t udev_generation; +TAILQ_HEAD(pdev_array_list_head, pdev_array_entry) pdev_array_list; + +void +pdev_array_entry_ref(struct pdev_array_entry *pae) +{ + ++pae->refs; +} + +void +pdev_array_entry_unref(struct pdev_array_entry *pae) +{ + if (--pae->refs == 0) { + TAILQ_REMOVE(&pdev_array_list, pae, link); + prop_object_release(pae->pdev_array); /* XXX */ + free(pae); + } +} + +void +pdev_array_entry_insert(prop_array_t pa) +{ + struct pdev_array_entry *pae, *opae = NULL; + + if (pa == NULL) + errx(1, "null prop_array in insert_pdev_array"); + pae = malloc(sizeof(struct pdev_array_entry)); + if (pae == NULL) + errx(1, "insert_pdev_array could not allocate mem"); + memset(pae, 0, sizeof(struct pdev_array_entry)); + pae->pdev_array = pa; + pae->generation = udev_generation++; + pae->refs = 1; /* One ref because it's the most recent one */ + + /* + * If the TAILQ is not empty, unref the last entry, + * as it isn't needed anymore. + */ + if (!TAILQ_EMPTY(&pdev_array_list)) + opae = TAILQ_LAST(&pdev_array_list, pdev_array_list_head); + + TAILQ_INSERT_TAIL(&pdev_array_list, pae, link); + + if (opae != NULL) + pdev_array_entry_unref(opae); +} + +struct pdev_array_entry * +pdev_array_entry_get(int64_t generation) +{ + struct pdev_array_entry *pae; + int found = 0; + + TAILQ_FOREACH(pae, &pdev_array_list, link) { + if (pae->generation == generation) { + found = 1; + break; + } + } + + if (!found) + return NULL; + + pdev_array_entry_ref(pae); + return pae; +} + +struct pdev_array_entry * +pdev_array_entry_get_last(void) +{ + struct pdev_array_entry *pae; + + pae = TAILQ_LAST(&pdev_array_list, pdev_array_list_head); + + pdev_array_entry_ref(pae); + return pae; +} diff --git a/sbin/udevd/udevd_socket.c b/sbin/udevd/udevd_socket.c new file mode 100644 index 0000000..f6a4bfd --- /dev/null +++ b/sbin/udevd/udevd_socket.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2010 The DragonFly Project. All rights reserved. + * + * This code is derived from software contributed to The DragonFly Project + * by Alex Hornung + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of The DragonFly Project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific, prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "udevd.h" + +int +send_xml(int s, char *xml) +{ + ssize_t r,n; + size_t sz; + + sz = strlen(xml) + 1; + + r = send(s, &sz, sizeof(sz), 0); + if (r <= 0) + return r; + + r = 0; + while (r < (ssize_t)sz) { + n = send(s, xml+r, sz-r, 0); + if (n <= 0) + return n; + r += n; + } + + return r; +} + +int +read_xml(int s, char *buf, size_t buf_sz) +{ + size_t sz; + int n, r; + + n = recv(s, &sz, sizeof(sz), MSG_WAITALL); + if (n <= 0) + return n; + + r = 0; + while ((r < (ssize_t)sz) && (r < (ssize_t)buf_sz)) { + n = recv(s, buf+r, sz-r, MSG_WAITALL); + if (n <= 0) + return n; + r += n; + } + + return r; +} + +int +unblock_descriptor(int s) +{ + int flags, ret; + + flags = fcntl(s, F_GETFL, 0); + ret = fcntl(s, F_SETFL, flags | O_NONBLOCK); + return ret; +} + +int +block_descriptor(int s) +{ + int flags, ret; + + flags = fcntl(s, F_GETFL, 0); + ret = fcntl(s, F_SETFL, flags & ~O_NONBLOCK); + return ret; +} + +int +init_local_server(const char *sockfile, int socktype, int nonblock) +{ + int s; + struct sockaddr_un un_addr; + + if ((s = socket(AF_UNIX, socktype, 0)) < 0) + return -1; + + memset(&un_addr, 0, sizeof(un_addr)); + un_addr.sun_family = AF_UNIX; + strncpy(un_addr.sun_path, sockfile, SOCKFILE_NAMELEN); + un_addr.sun_path[SOCKFILE_NAMELEN - 1] = '\0'; + + /* + * DO NOT change `un_addr.sun_path' to `sockfile' here, + * since `sockfile' may have been truncated by above strncpy(3). + */ + unlink(un_addr.sun_path); + + if (nonblock && unblock_descriptor(s) < 0) { + close(s); + return -1; + } + + if (bind(s, (struct sockaddr *)&un_addr, sizeof(un_addr)) < 0) { + close(s); + return -1; + } + + if (socktype == SOCK_STREAM && listen(s, LOCAL_BACKLOG) < 0) { + close(s); + return -1; + } + + return s; +} diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile index 93b02fd..a262c45 100644 --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -123,7 +123,6 @@ SUBDIR= 802_11 \ traceroute6 \ trpt \ tzsetup \ - udevd \ usbd \ usbdevs \ vidcontrol \ diff --git a/usr.sbin/udevd/Makefile b/usr.sbin/udevd/Makefile deleted file mode 100644 index 9e1c3f5..0000000 --- a/usr.sbin/udevd/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -DEBUG_FLAGS=-g -PROG= udevd -SRCS= udevd.c udevd_client.c udevd_monitor.c udevd_pdev.c -SRCS+= udevd_socket.c -LDADD= -lprop -lpthread -NOMAN= - -.include diff --git a/usr.sbin/udevd/mktest b/usr.sbin/udevd/mktest deleted file mode 100644 index 9a39224..0000000 --- a/usr.sbin/udevd/mktest +++ /dev/null @@ -1,7 +0,0 @@ -DEBUG_FLAGS=-g -PROG= test_udevd -SRCS= test_udevd.c -LDADD= -lprop -NOMAN= - -.include diff --git a/usr.sbin/udevd/test_udevd.c b/usr.sbin/udevd/test_udevd.c deleted file mode 100644 index 6564dfc..0000000 --- a/usr.sbin/udevd/test_udevd.c +++ /dev/null @@ -1,770 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define LISTEN_SOCKET_FILE "/tmp/udevd.socket" -#define SOCKFILE_NAMELEN strlen(LISTEN_SOCKET_FILE)+1 - -int conn_local_server(const char *sockfile, int socktype, int nonblock, - int *retsock); -prop_dictionary_t udevd_get_command_dict(char *command); -void udevd_request_devs(int s); - -struct udev { - int gp_fd; - int monitor_fd; - int refs; - - void *userdata; -}; - -struct udev_enumerate { - struct udev *udev_ctx; - prop_array_t pa; - int refs; - TAILQ_HEAD(, udev_list_entry) list_entries; -}; - -struct udev_list_entry { - prop_dictionary_t dict; - TAILQ_ENTRY(udev_list_entry) link; -}; - -struct udev_monitor { - struct udev *udev_ctx; - prop_array_t ev_filt; - int socket; - int user_socket; /* maybe... one day... */ - int refs; -}; - -struct udev_device { - struct udev *udev_ctx; - prop_dictionary_t dict; - int ev_type; - int refs; -}; - -struct udev * -udev_ref(struct udev *udev_ctx) -{ - atomic_add_int(&udev_ctx->refs, 1); - - return udev_ctx; -} - -void -udev_unref(struct udev *udev_ctx) -{ - int refcount; - - refcount = atomic_fetchadd_int(&udev_ctx->refs, -1); - - if (refcount == 1) { - atomic_subtract_int(&udev_ctx->refs, 0x400); /* in destruction */ - if (udev_ctx->gp_fd != -1) - close (udev_ctx->gp_fd); - if (udev_ctx->monitor_fd != -1) - close (udev_ctx->monitor_fd); - - free(udev_ctx); - } -} - -struct udev * -udev_new() -{ - struct udev *udev_ctx; - - udev_ctx = malloc(sizeof(struct udev)); - - udev_ctx->refs = 1; - udev_ctx->gp_fd = -1; - udev_ctx->monitor_fd = -1; - udev_ctx->userdata = NULL; - - return udev_ctx; -} - -const char *udev_get_dev_path(struct udev *udev_ctx __unused) -{ - return "/dev"; -} - -void * -udev_get_userdata(struct udev *udev_ctx) -{ - return udev_ctx->userdata; -} - -void -udev_set_userdata(struct udev *udev_ctx, void *userdata) -{ - udev_ctx->userdata = userdata; -} - -struct udev_enumerate * -udev_enumerate_new(struct udev *udev_ctx) -{ - struct udev_enumerate *udev_enum; - - udev_enum = malloc(sizeof(struct udev_enumerate)); - - udev_enum->refs = 1; - udev_enum->pa = NULL; - TAILQ_INIT(&udev_enum->list_entries); - udev_enum->udev_ctx = udev_ref(udev_ctx); -} - -struct udev_enumerate * -udev_enumerate_ref(struct udev_enumerate *udev_enum) -{ - atomic_add_int(&udev_enum->refs, 1); - - return udev_enum; -} - -void -udev_enumerate_unref(struct udev_enumerate *udev_enum) -{ - struct udev_list_entry *le; - int refcount; - - refcount = atomic_fetchadd_int(&udev_enum->refs, -1); - - if (refcount == 1) { - atomic_subtract_int(&udev_enum->refs, 0x400); /* in destruction */ - if (udev_enum->pa != NULL) - prop_object_release(udev_enum->pa); - - while (!TAILQ_EMPTY(&udev_enum->list_entries)) { - le = TAILQ_FIRST(&udev_enum->list_entries); - TAILQ_REMOVE(&udev_enum->list_entries, le, link); - prop_object_release(le->dict); - free(le); - } - udev_unref(udev_enum->udev_ctx); - free(udev_enum); - } -} - -struct udev * -udev_enumerate_get_udev(struct udev_enumerate *udev_enum) -{ - return udev_enum->udev_ctx; -} - -int -udev_enumerate_scan_devices(struct udev_enumerate *udev_enum) -{ - prop_array_t pa; - - if (udev_enum->udev_ctx->gp_fd == -1) - return -1; - - pa = udevd_request_devs(udev_enum->udev_ctx->gp_fd); - if (pa == NULL) - return -1; - - prop_object_retain(pa); - - if (udev_enum->pa != NULL) - prop_object_release(udev_enum->pa); - - udev_enum->iter = NULL; - udev_enum->pa = pa; - - return 0; -} - -struct udev_list_entry * -udev_enumerate_get_list_entry(struct udev_enumerate *udev_enum) -{ - struct udev_list_entry *le; - prop_object_iterator_t iter; - - /* If the list is not empty, assume it was populated in an earlier call */ - if (!TAILQ_EMPTY(&udev_enum->list_entries)) - return TAILQ_FIRST(&udev_enum->list_entries); - - iter = prop_array_iterator(udev_enum->pa); - if (iter == NULL) - return NULL; - - while ((dict = prop_object_iterator_next(iter)) != NULL) { - le = malloc(sizeof(struct udev_list_entry)); - if (le == NULL) - goto out; - - prop_object_retain(dict); - le->dict = dict; - TAILQ_INSERT_TAIL(&udev_enum->list_entries, le, link); - } - - le = TAILQ_FIRST(&udev_enum->list_entries); - -out: - prop_object_iterator_release(iter); - return le; -} - -prop_array_t -udev_enumerate_get_array(struct udev_enumerate *udev_enum) -{ - return udev_enum->pa; -} - -struct udev_list_entry * -udev_list_entry_get_next(struct udev_list_entry *list_entry) -{ - return TAILQ_NEXT(list_entry, link); -} - -prop_dictionary_t -udev_list_entry_get_dictionary(struct udev_list_entry *list_entry) -{ - return list_entry->dict; -} - -#define udev_list_entry_foreach(list_entry, first_entry) \ - for(list_entry = first_entry; \ - list_entry != NULL; \ - list_entry = udev_list_entry_get_next(list_entry)) - - - - - - -struct udev_monitor * -udev_monitor_new(struct udev *udev_ctx) -{ - struct udev_monitor *udev_monitor; - int ret, s; - - ret = conn_local_server(LISTEN_SOCKET_FILE, SOCK_STREAM, 0, &s); - if (ret < 0) - return NULL; - - udev_monitor = malloc(sizeof(struct udev_monitor)); - if (udev_monitor == NULL) - return NULL; - - udev_monitor->refs = 1; - udev_monitor->ev_filt = NULL; - udev_monitor->socket = s; - udev_monitor->user_socket = 1; - udev_monitor->udev_ctx = udev_ref(udev_ctx); - - return udev_monitor; -} - - -struct udev_monitor * -udev_monitor_ref(struct udev_monitor *udev_monitor) -{ - atomic_add_int(&udev_monitor->refs, 1); - - return udev_monitor; -} - -void -udev_monitor_unref(struct udev_monitor *udev_monitor) -{ - int refcount; - - refcount = atomic_fetchadd_int(&udev_monitor->refs, -1); - - if (refcount == 1) { - atomic_subtract_int(&udev_monitor->refs, 0x400); /* in destruction */ - if (udev_monitor->ev_filt != NULL) - prop_object_release(udev_monitor->ev_filt); - - if (udev_monitor->socket != -1) - close(udev_monitor->socket); - if (udev_monitor->user_socket != -1) - close(udev_monitor->user_socket); - - udev_unref(udev_monitor->udev_ctx); - free(udev_monitor); - } -} - -struct udev * -udev_monitor_get_udev(struct udev_monitor *udev_monitor) -{ - return udev_monitor->udev_ctx; -} - -int -udev_monitor_get_fd(struct udev_monitor *udev_monitor) -{ - return udev_monitor->socket; -} - -struct udev_device * -udev_monitor_receive_device(struct udev_monitor *udev_monitor) -{ - struct udev_device *udev_dev; - prop_dictionary_t dict; - prop_number_t pn; - char *xml; - int n, evtype; - - xml = malloc(12*1024*1024); - if (xml == NULL) - return NULL; - - if ((n = read_xml(udev_monitor->socket, xml, 12*1024*1024)) <= 0) { - free(xml); - return NULL; - } - - xml[n+1] = '\0'; - dict = prop_dictionary_internalize(xml); - free(xml); - if (dict == NULL) - return NULL; - - pn = prop_dictionary_get(dict, "evtype"); - if (pn == NULL) { - prop_object_release(dict); - return NULL; - } - - udev_dev = malloc(sizeof(struct udev_dev)); - if (udev_dev == NULL) { - prop_object_release(dict); - return NULL; - } - - udev_dev->refs = 1; - udev_dev->ev_type = prop_number_integer_value(pn); - udev_dev->dict = prop_dictionary_get(dict, "evdict"); - if (udev_dev->dict == NULL) { - free(udev_dev); - return NULL; - } - udev_dev->udev_ctx = udev_ref(udev_monitor->udev_ctx); - -out: - return udev_dev; -} - -int -udev_monitor_enable_receiving(struct udev_monitor *udev_monitor) -{ - prop_dictionary_t dict; - char *xml; - /* ->socket, ->user_socket, ->ev_filt */ - - dict = udevd_get_command_dict(__DECONST(char *, "monitor")); - if (dict == NULL) - return -1; - - /* Add event filters to message, if available */ - if (udev_monitor->ev_filt != NULL) { - if (prop_dictionary_set(dict, "filters", - udev_monitor->ev_filt) == false) { - prop_object_release(dict); - return -1; - } - } - - xml = prop_dictionary_externalize(dict); - prop_object_release(dict); - if (xml == NULL) - return -1; - - n = send_xml(udev_monitor->socket, xml); - free(xml); - if (n <= 0) - return NULL; - - return 0; -} - -int -udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, - const char *subsystem, - const char *devtype __unused) -{ - int ret; - - ret = _udev_monitor_filter_add_match_gen(udev_monitor, - EVENT_FILTER_TYPE_WILDCARD, - 0, - "subsystem", - subsystem); - - return ret; -} - -int -udev_monitor_filter_add_match_expr(struct udev_monitor *udev_monitor, - const char *key, - char *expr) -{ - int ret; - - ret = _udev_monitor_filter_add_match_gen(udev_monitor, - EVENT_FILTER_TYPE_WILDCARD, - 0, - key, - expr); - - return ret; -} - -int -udev_monitor_filter_add_nomatch_expr(struct udev_monitor *udev_monitor, - const char *key, - char *expr) -{ - int ret; - - ret = _udev_monitor_filter_add_match_gen(udev_monitor, - EVENT_FILTER_TYPE_WILDCARD, - 1, - key, - expr); - - return ret; -} - -int -udev_monitor_filter_add_match_regex(struct udev_monitor *udev_monitor, - const char *key, - char *expr) -{ - int ret; - - ret = _udev_monitor_filter_add_match_gen(udev_monitor, - EVENT_FILTER_TYPE_REGEX, - 0, - key, - expr); - - return ret; -} - -int -udev_monitor_filter_add_nomatch_regex(struct udev_monitor *udev_monitor, - const char *key, - char *expr) -{ - int ret; - - ret = _udev_monitor_filter_add_match_gen(udev_monitor, - EVENT_FILTER_TYPE_REGEX, - 1, - key, - expr); - - return ret; -} - -int -_udev_monitor_filter_add_match_gen(struct udev_monitor *udev_monitor, - int type, - int neg, - const char *key, - char *expr) -{ - prop_array_t pa; - prop_dictionary_t dict; - int error; - - if (subsystem == NULL) - return NULL; - - dict = prop_dictionary_create(); - if (dict == NULL) - return -1; - - error = _udev_dict_set_cstr(dict, "key", key); - if (error != 0) - goto error_out; - error = _udev_dict_set_int(dict, "type", type); - if (error != 0) - goto error_out; - error = _udev_dict_set_int(dict, "expr", expr); - if (error != 0) - goto error_out; - - if (neg) { - error = _udev_dict_set_int(dict, "negative", 1); - if (error != 0) - goto error_out; - } - - if (udev_monitor->ev_filt == NULL) { - pa = prop_array_create(); - if (pa == NULL) - goto error_out; - - udev_monitor->ev_filt = pa; - } - - if (prop_array_add(udev_monitor->ev_filt, dict) == false) - goto error_out; - - return 0; - -error_out: - prop_object_release(dict); - return -1; -} - -struct udev_device * -udev_device_ref(struct udev_device *udev_device) -{ - atomic_add_int(&udev_device->refs, 1); - - return udev_device; -} - -void -udev_device_unref(struct udev_device *udev_device) -{ - int refcount; - - refcount = atomic_fetchadd_int(&udev_device->refs, -1); - - if (refcount == 1) { - atomic_subtract_int(&udev_device->refs, 0x400); /* in destruction */ - if (udev_device->dict != NULL) - prop_object_release(udev_device->dict); - - udev_unref(udev_device->udev_ctx); - free(udev_device); - } -} - -prop_dictionary_t -udev_device_get_dictionary(struct udev_device *udev_device) -{ - return udev_device->dict; -} - -struct udev * -udev_device_get_udev(struct udev_device *udev_device) -{ - return udev_device->udev_ctx; -} - -int -send_xml(int s, char *xml) -{ - ssize_t r,n; - size_t sz; - - sz = strlen(xml) + 1; - - r = send(s, &sz, sizeof(sz), 0); - if (r <= 0) - return r; - - r = 0; - while (r < (ssize_t)sz) { - n = send(s, xml+r, sz-r, 0); - if (n <= 0) - return n; - r += n; - } - - return r; -} - -int -read_xml(int s, char *buf, size_t buf_sz) -{ - size_t sz; - int n, r; - - n = recv(s, &sz, sizeof(sz), MSG_WAITALL); - if (n <= 0) - return n; - - r = 0; - while ((r < (ssize_t)sz) && (r < (ssize_t)buf_sz)) { - n = recv(s, buf+r, sz-r, MSG_WAITALL); - if (n <= 0) - return n; - r += n; - } - - return r; -} - - - -static int -_udev_dict_set_cstr(prop_dictionary_t dict, const char *key, char *str) -{ - prop_string_t ps; - - ps = prop_string_create_cstring(str); - if (ps == NULL) - return ENOMEM; - - if (prop_dictionary_set(dict, key, ps) == false) { - prop_object_release(ps); - return ENOMEM; - } - - prop_object_release(ps); - return 0; -} - -static int -_udev_dict_set_int(prop_dictionary_t dict, const char *key, int64_t val) -{ - prop_number_t pn; - - pn = prop_number_create_integer(val); - if (pn == NULL) - return ENOMEM; - - if (prop_dictionary_set(dict, key, pn) == false) { - prop_object_release(pn); - return ENOMEM; - } - - prop_object_release(pn); - return 0; -} - -static int -_udev_dict_set_uint(prop_dictionary_t dict, const char *key, uint64_t val) -{ - prop_number_t pn; - - pn = prop_number_create_unsigned_integer(val); - if (pn == NULL) - return ENOMEM; - - if (prop_dictionary_set(dict, key, pn) == false) { - prop_object_release(pn); - return ENOMEM; - } - - prop_object_release(pn); - return 0; -} - -int -conn_local_server(const char *sockfile, int socktype, int nonblock, - int *retsock) -{ - int s; - struct sockaddr_un serv_addr; - - *retsock = -1; - if ((s = socket(AF_UNIX, socktype, 0)) < 0) - return -1; - - memset(&serv_addr, 0, sizeof(serv_addr)); - serv_addr.sun_family = AF_UNIX; - strncpy(serv_addr.sun_path, sockfile, SOCKFILE_NAMELEN); - serv_addr.sun_path[SOCKFILE_NAMELEN - 1] = '\0'; - - if (nonblock && unblock_descriptor(s) < 0) { - close(s); - return -1; - } - - *retsock = s; - return connect(s, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); -} - -prop_dictionary_t -udevd_get_command_dict(char *command) -{ - prop_dictionary_t dict; - int error; - - dict = prop_dictionary_create(); - if (dict == NULL) - return NULL; - - if ((error = _udev_dict_set_cstr(dict, "command", command))) - goto error_out; - - return dict; - -error_out: - prop_object_release(dict); - return NULL; -} - -prop_array_t -udevd_request_devs(int s) -{ - prop_array_t pa; - prop_dictionary_t dict; - char *xml; - - int n, t; - - dict = udevd_get_command_dict(__DECONST(char *, "getdevs")); - if (dict == NULL) - return NULL; - - xml = prop_dictionary_externalize(dict); - prop_object_release(dict); - if (xml == NULL) - return NULL; - - n = send_xml(s, xml); - free(xml); - - if (n <= 0) - return NULL; - - xml = malloc(12*1024*1024); /* generous 12 MB */ - if ((n = read_xml(s, xml, 12*1024*1024)) <= 0) { - free(xml); - return NULL; - } - - xml[n+1] = '\0'; - pa = prop_array_internalize(xml); - free(xml); - return (pa); -} - - - -int -main(void) -{ - int ret, s; - - ret = conn_local_server(LISTEN_SOCKET_FILE, SOCK_STREAM, 0, &s); - if (ret < 0) - err(1, "conn_local_server"); - - udevd_request_devs(s); - - return 0; -} diff --git a/usr.sbin/udevd/udevd.c b/usr.sbin/udevd/udevd.c deleted file mode 100644 index bed883c..0000000 --- a/usr.sbin/udevd/udevd.c +++ /dev/null @@ -1,365 +0,0 @@ -/* - * Copyright (c) 2010 The DragonFly Project. All rights reserved. - * - * This code is derived from software contributed to The DragonFly Project - * by Alex Hornung - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name of The DragonFly Project nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific, prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include "udevd.h" - -static int udevfd; - -extern pthread_mutex_t monitor_lock; -extern TAILQ_HEAD(udev_monitor_list_head, udev_monitor) udev_monitor_list; -extern TAILQ_HEAD(pdev_array_list_head, pdev_array_entry) pdev_array_list; - -int match_dev_dict(prop_dictionary_t, prop_dictionary_t); -prop_dictionary_t find_dev_dict(int64_t, prop_dictionary_t, int *); - -void udev_read_event(int); -prop_array_t udev_getdevs(int); - -int -match_dev_dict(prop_dictionary_t dict, prop_dictionary_t match_dict) -{ - prop_number_t pn, pn2; - prop_string_t ps, ps2; - - if (dict == NULL) - return 0; - - if ((ps = prop_dictionary_get(dict, "name")) == NULL) - return 0; - if ((ps2 = prop_dictionary_get(match_dict, "name")) == NULL) - return 0; - if (!prop_string_equals(ps, ps2)) - return 0; - - if ((pn = prop_dictionary_get(dict, "devnum")) == NULL) - return 0; - if ((pn2 = prop_dictionary_get(match_dict, "devnum")) == NULL) - return 0; - if (!prop_number_equals(pn, pn2)) - return 0; - - if ((pn = prop_dictionary_get(dict, "kptr")) == NULL) - return 0; - if ((pn2 = prop_dictionary_get(match_dict, "kptr")) == NULL) - return 0; - if (!prop_number_equals(pn, pn2)) - return 0; - - return 1; -} - -prop_dictionary_t -find_dev_dict(int64_t generation, prop_dictionary_t match_dict, int *idx) -{ - struct pdev_array_entry *pae; - prop_array_t pa; - prop_object_iterator_t iter; - prop_dictionary_t dict; - int i = 0; - - if (generation == -1) - pae = pdev_array_entry_get_last(); - else - pae = pdev_array_entry_get(generation); - - if (pae == NULL) - return NULL; - - pa = pae->pdev_array; - - iter = prop_array_iterator(pa); - if (iter == NULL) { - pdev_array_entry_unref(pae); - return NULL; - } - - while ((dict = prop_object_iterator_next(iter)) != NULL) { - if (match_dev_dict(dict, match_dict)) - break; - ++i; - } - - prop_object_iterator_release(iter); - - if (idx != NULL) - *idx = i; - - pdev_array_entry_unref(pae); - return dict; -} - -void -udev_read_event(int fd) -{ - struct pdev_array_entry *pae; - prop_dictionary_t dict, evdict, devdict; - prop_number_t pn; - prop_string_t ps; - prop_object_t po; - prop_array_t pa; - char *xml; - int n, idx, evtype; - size_t sz; - - sz = 4096 * 1024; - - xml = malloc(sz); /* 4 MB */ -again: - if ((n = read(fd, xml, sz)) <= 0) { - if (errno == ENOMEM) { - sz <<= 2; - realloc(xml, sz); - goto again; - } - free(xml); - return; - } - - dict = prop_dictionary_internalize(xml); - free(xml); - if (dict == NULL) { - syslog(LOG_ERR, "internalization of xml failed"); - return; - } - - pn = prop_dictionary_get(dict, "evtype"); - if (pn == NULL) { - syslog(LOG_ERR, "read_event: no key evtype"); - goto out; - } - - evtype = prop_number_integer_value(pn); - - evdict = prop_dictionary_get(dict, "evdict"); - if (evdict == NULL) { - syslog(LOG_ERR, "read_event: no key evdict"); - goto out; - } - - switch (evtype) { - case UDEV_EVENT_ATTACH: - monitor_queue_event(dict); - pae = pdev_array_entry_get_last(); - pa = prop_array_copy(pae->pdev_array); - pdev_array_entry_unref(pae); - if (pa == NULL) - goto out; - prop_array_add(pa, evdict); - pdev_array_entry_insert(pa); - break; - - case UDEV_EVENT_DETACH: - monitor_queue_event(dict); - if ((devdict = find_dev_dict(-1, evdict, &idx)) == NULL) - goto out; - pae = pdev_array_entry_get_last(); - pa = prop_array_copy(pae->pdev_array); - pdev_array_entry_unref(pae); - if (pa == NULL) - goto out; - prop_array_remove(pa, idx); - //pdev_array_entry_insert(pa); - break; - - case UDEV_EV_KEY_UPDATE: - if ((devdict = find_dev_dict(-1, evdict, NULL)) == NULL) - goto out; - if ((ps = prop_dictionary_get(evdict, "key")) == NULL) - goto out; - if ((po = prop_dictionary_get(evdict, "value")) == NULL) - goto out; - /* prop_object_retain(po); */ /* not necessary afaik */ - prop_dictionary_set(devdict, prop_string_cstring_nocopy(ps), po); - break; - - case UDEV_EV_KEY_REMOVE: - if ((devdict = find_dev_dict(-1, evdict, NULL)) == NULL) - goto out; - if ((ps = prop_dictionary_get(evdict, "key")) == NULL) - goto out; - prop_dictionary_remove(devdict, prop_string_cstring_nocopy(ps)); - break; - - default: - syslog(LOG_ERR, "read_event: unknown evtype %d", evtype); - } - -out: - prop_object_release(dict); - return; -} - -prop_array_t -udev_getdevs(int devfd) -{ - prop_dictionary_t pd, rpd; - prop_string_t ps; - prop_array_t pa; - - pd = prop_dictionary_create(); - if (pd == NULL) { - err(1, "prop_dictionary_create()"); - } - - ps = prop_string_create_cstring("getdevs"); - if (ps == NULL) { - prop_object_release(pd); - err(1, "prop_string_create_cstring()"); - } - - if (prop_dictionary_set(pd, "command", ps) == false) { - prop_object_release(ps); - prop_object_release(pd); - err(1, "prop_dictionary_set()"); - } - - prop_object_release(ps); - - /* Send dictionary to kernel space */ - if (prop_dictionary_sendrecv_ioctl(pd, devfd, UDEVPROP, &rpd) != 0) - err(1, "prop_array_recv_ioctl()"); - - prop_object_release(pd); - - pa = prop_dictionary_get(rpd, "array"); - if (pa == NULL) - goto out; - prop_object_retain(pa); - -out: - prop_object_release(rpd); - return pa; -} - -int -ignore_signal(int signum) -{ - struct sigaction act; - int ret; - - act.sa_handler = SIG_IGN; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; - - ret = sigaction(signum, &act, NULL); - return ret; -} - -int main(int argc __unused, char *argv[] __unused) -{ - int error __unused, i, r, s; - struct pollfd fds[NFDS]; - - TAILQ_INIT(&pdev_array_list); - TAILQ_INIT(&udev_monitor_list); - - r = ignore_signal(SIGPIPE); - if (r != 0) - err(1, "could not ignore_signal SIGPIPE"); - - r = pthread_mutex_init(&(monitor_lock), NULL); - if (r != 0) - err(1, "could not allocate a pthread_mutex"); - - if ((udevfd = open(UDEV_DEVICE_PATH, O_RDWR | O_NONBLOCK)) == -1) - err(1, "%s", UDEV_DEVICE_PATH); - unblock_descriptor(udevfd); - - //if (daemon(0, 0) == -1) - // err(1, "daemon"); - - syslog(LOG_ERR, "udevd started"); - - pdev_array_entry_insert(udev_getdevs(udevfd)); - - s = init_local_server(LISTEN_SOCKET_FILE, SOCK_STREAM, 0); - if (s < 0) - err(1, "init_local_server"); - - memset(fds, 0 , sizeof(fds)); - fds[UDEV_DEVICE_FD_IDX].fd = udevfd; - fds[UDEV_DEVICE_FD_IDX].events = POLLIN; - fds[UDEV_SOCKET_FD_IDX].fd = s; - fds[UDEV_SOCKET_FD_IDX].events = POLLIN | POLLPRI; - - for (;;) { - r = poll(fds, NFDS, -1); - if (r < 0) - err(1, "polling..."); - - for (i = 0; (i < NFDS) && (r > 0); i++) { - if (fds[i].revents == 0) - continue; - - --r; - switch (i) { - case UDEV_DEVICE_FD_IDX: - udev_read_event(udevfd); - break; - case UDEV_SOCKET_FD_IDX: - handle_new_connection(s); - break; - default: - break; - } - } - } - - return 0; -} diff --git a/usr.sbin/udevd/udevd.h b/usr.sbin/udevd/udevd.h deleted file mode 100644 index cc19122..0000000 --- a/usr.sbin/udevd/udevd.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (c) 2010 The DragonFly Project. All rights reserved. - * - * This code is derived from software contributed to The DragonFly Project - * by Alex Hornung - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name of The DragonFly Project nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific, prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -#include - -#define UDEV_DEVICE_PATH "/dev/udev" -#define LOCAL_BACKLOG 5 - -#define UDEV_DEVICE_FD_IDX 0 -#define UDEV_SOCKET_FD_IDX 1 -#define NFDS 2 - - -struct pdev_array_entry { - int32_t refs; - int64_t generation; - prop_array_t pdev_array; - TAILQ_ENTRY(pdev_array_entry) link; -}; - -struct event_filter { - int id; - int neg; - int type; - char *key; - char *wildcard_match; - regex_t regex_match; - - TAILQ_ENTRY(event_filter) link; -}; - -struct udev_monitor; - -struct client_info { - pthread_t tid; - int fd; - struct udev_monitor *udm; - struct event_filter ev_filt; -}; - -struct udev_monitor_event { - prop_dictionary_t ev_dict; - TAILQ_ENTRY(udev_monitor_event) link; -}; - -struct udev_monitor { - pthread_mutex_t q_lock; - pthread_cond_t cond; - struct client_info *cli; - TAILQ_HEAD(, event_filter) ev_filt; - TAILQ_HEAD(, udev_monitor_event) ev_queue; - TAILQ_ENTRY(udev_monitor) link; -}; - -struct cmd_function { - const char *cmd; - int (*fn)(struct client_info *, prop_dictionary_t); -}; - -/* From udevd_socket.c */ -int init_local_server(const char *sockfile, int socktype, int nonblock); -int block_descriptor(int s); -int unblock_descriptor(int s); -int read_xml(int s, char *buf, size_t buf_sz); -int send_xml(int s, char *xml); - -/* From udevd_pdev.c */ -void pdev_array_entry_ref(struct pdev_array_entry *pae); -void pdev_array_entry_unref(struct pdev_array_entry *pae); -void pdev_array_entry_insert(prop_array_t pa); -struct pdev_array_entry *pdev_array_entry_get(int64_t generation); -struct pdev_array_entry *pdev_array_entry_get_last(void); - -/* From udevd_client.c */ -void handle_new_connection(int s); -int client_cmd_getdevs(struct client_info *cli, prop_dictionary_t dict); - - -/* From udevd_monitor.c */ -void monitor_queue_event(prop_dictionary_t ev_dict); -int client_cmd_monitor(struct client_info *cli, prop_dictionary_t dict); -int match_event_filter(struct udev_monitor *udm, prop_dictionary_t ev_dict); -struct udev_monitor *udev_monitor_init(struct client_info *cli, prop_array_t filters); -void udev_monitor_free(struct udev_monitor *udm); - -/* From udevd.c */ -int ignore_signal(int signum); diff --git a/usr.sbin/udevd/udevd_client.c b/usr.sbin/udevd/udevd_client.c deleted file mode 100644 index 79f25f9..0000000 --- a/usr.sbin/udevd/udevd_client.c +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright (c) 2010 The DragonFly Project. All rights reserved. - * - * This code is derived from software contributed to The DragonFly Project - * by Alex Hornung - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name of The DragonFly Project nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific, prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include "udevd.h" - -struct cmd_function cmd_fn[] = { - { .cmd = "getdevs", .fn = client_cmd_getdevs}, - { .cmd = "monitor", .fn = client_cmd_monitor}, - {NULL, NULL} -}; - -static void *client_thread(void *arg); - -void -handle_new_connection(int s) -{ - struct client_info *cli_info; - struct sockaddr_un addr; - int fd; - socklen_t saddr_len = sizeof(struct sockaddr_un); - - fd = accept(s, (struct sockaddr *)&addr, &saddr_len); - if (fd < 0) { - syslog(LOG_ERR, "uh, oh, accept failed with %d", errno); - return; - } - - block_descriptor(fd); - cli_info = malloc(sizeof(struct client_info)); - memset(cli_info, 0, sizeof(struct client_info)); - - cli_info->fd = fd; - pthread_create(&cli_info->tid, NULL, client_thread, (void *)cli_info); -} - - -static void * -client_thread(void *arg) -{ - prop_dictionary_t dict; - prop_string_t ps; - prop_object_t po; - struct client_info *cli; - char *xml; - int r, n, error; - - r = ignore_signal(SIGPIPE); - if (r != 0) - err(1, "could not ignore_signal SIGPIPE"); - - cli = (struct client_info *)arg; - xml = malloc(12*1024*1024); /* generous 12 MB */ - for (;;) { - n = read_xml(cli->fd, xml, 12*1024*1024); - if (n == 0) - goto cli_disconnect; - else if (n < 0) - goto error_out; - - xml[n+1] = '\0'; - - dict = prop_dictionary_internalize(xml); - if (dict == NULL) { - syslog(LOG_ERR, "internalization of received XML failed"); - goto error_out; - } - - po = prop_dictionary_get(dict, "command"); - if (po == NULL || prop_object_type(po) != PROP_TYPE_STRING) { - syslog(LOG_ERR, "received dictionary doesn't contain a key 'command'"); - prop_object_release(dict); - continue; - } - - ps = po; - - syslog(LOG_DEBUG, "Received command: %s (from fd = %d)\n", prop_string_cstring_nocopy(ps), cli->fd); - for(n = 0; cmd_fn[n].cmd != NULL; n++) { - if (prop_string_equals_cstring(ps, cmd_fn[n].cmd)) - break; - } - - if (cmd_fn[n].cmd != NULL) { - error = cmd_fn[n].fn(cli, dict); - if (error) { - prop_object_release(dict); - goto error_out; - } - } - prop_object_release(dict); - } - -error_out: - -cli_disconnect: - close(cli->fd); - free(xml); - cli->fd = -1; - free(cli); - return NULL; -} - -int -client_cmd_getdevs(struct client_info *cli, prop_dictionary_t cli_dict) -{ - struct pdev_array_entry *pae; - struct udev_monitor *udm; - prop_object_iterator_t iter; - prop_dictionary_t dict; - prop_object_t po; - prop_array_t pa; - char *xml; - ssize_t r; - int filters; - - - pa = NULL; - po = prop_dictionary_get(cli_dict, "filters"); - if ((po != NULL) && prop_object_type(po) == PROP_TYPE_ARRAY) { - pa = po; - filters = 1; - } else { - filters = 0; - } - - pae = pdev_array_entry_get_last(); - if (pae == NULL) - return 1; - - if (filters) { - udm = udev_monitor_init(cli, pa); - if (udm == NULL) { - pdev_array_entry_unref(pae); - return 1; - } - - pa = prop_array_create_with_capacity(10); - - iter = prop_array_iterator(pae->pdev_array); - if (iter == NULL) { - pdev_array_entry_unref(pae); - udev_monitor_free(udm); - return 1; - } - - while ((dict = prop_object_iterator_next(iter)) != NULL) { - if (match_event_filter(udm, dict)) { - prop_array_add(pa, dict); - } - } - - udev_monitor_free(udm); - } else { - pa = pae->pdev_array; - } - - xml = prop_array_externalize(pa); - if (filters) - prop_object_release(pa); - - pdev_array_entry_unref(pae); - - if (xml == NULL) - return 1; - - r = send_xml(cli->fd, xml); - if (r < 0) - syslog(LOG_DEBUG, "error while send_xml (cmd_getdevs)\n"); - if (r == 0) - syslog(LOG_DEBUG, "EOF while send_xml (cmd_getdevs)\n"); - - free(xml); - - return 0; -} diff --git a/usr.sbin/udevd/udevd_monitor.c b/usr.sbin/udevd/udevd_monitor.c deleted file mode 100644 index 4dfcd4e..0000000 --- a/usr.sbin/udevd/udevd_monitor.c +++ /dev/null @@ -1,485 +0,0 @@ -/* - * Copyright (c) 2010 The DragonFly Project. All rights reserved. - * - * This code is derived from software contributed to The DragonFly Project - * by Alex Hornung - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name of The DragonFly Project nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific, prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include "udevd.h" - -#define MONITOR_LOCK() pthread_mutex_lock(&monitor_lock) -#define MONITOR_UNLOCK() pthread_mutex_unlock(&monitor_lock) - -static int _parse_filter_prop(struct udev_monitor *udm, prop_array_t pa); -static int match_filter(struct event_filter *evf, prop_dictionary_t dict); - -static int WildCaseCmp(const char *w, const char *s); -static int wildCaseCmp(const char **mary, int d, const char *w, const char *s); - -TAILQ_HEAD(udev_monitor_list_head, udev_monitor) udev_monitor_list; -pthread_mutex_t monitor_lock; - - -void -monitor_queue_event(prop_dictionary_t ev_dict) -{ - struct udev_monitor *udm; - struct udev_monitor_event *udm_ev; - - MONITOR_LOCK(); - - TAILQ_FOREACH(udm, &udev_monitor_list, link) { - udm_ev = malloc(sizeof(struct udev_monitor_event)); - if (udm_ev == NULL) - continue; - - prop_object_retain(ev_dict); - udm_ev->ev_dict = ev_dict; - - if (match_event_filter(udm, - prop_dictionary_get(udm_ev->ev_dict, "evdict")) == 0) { - prop_object_release(ev_dict); - free(udm_ev); - continue; - } - - pthread_mutex_lock(&udm->q_lock); - TAILQ_INSERT_TAIL(&udm->ev_queue, udm_ev, link); - pthread_cond_signal(&udm->cond); - pthread_mutex_unlock(&udm->q_lock); - } - - MONITOR_UNLOCK(); -} - -struct udev_monitor * -udev_monitor_init(struct client_info *cli, prop_array_t filters) -{ - struct udev_monitor *udm; - int error; - - udm = malloc(sizeof(struct udev_monitor)); - if (udm == NULL) - return NULL; - - TAILQ_INIT(&udm->ev_queue); - TAILQ_INIT(&udm->ev_filt); - - pthread_mutex_init(&udm->q_lock, NULL); - pthread_cond_init(&udm->cond, NULL); - udm->cli = cli; - - if (filters != NULL) { - error = _parse_filter_prop(udm, filters); - /* XXX: ignore error for now */ - } - - return udm; -} - -void -udev_monitor_free(struct udev_monitor *udm) -{ - struct event_filter *evf; - struct udev_monitor_event *udm_ev; - - pthread_mutex_lock(&udm->q_lock); - - while ((udm_ev = TAILQ_FIRST(&udm->ev_queue)) != NULL) { - prop_object_release(udm_ev->ev_dict); - udm_ev->ev_dict = NULL; - TAILQ_REMOVE(&udm->ev_queue, udm_ev, link); - free(udm_ev); - } - - while ((evf = TAILQ_FIRST(&udm->ev_filt)) != NULL) { - TAILQ_REMOVE(&udm->ev_filt, evf, link); - free(evf); - } - - pthread_mutex_unlock(&udm->q_lock); - free(udm); -} - -int -client_cmd_monitor(struct client_info *cli, prop_dictionary_t dict) -{ - prop_array_t pa; - prop_object_t po; - struct udev_monitor *udm; - struct udev_monitor_event *udm_ev; - char *xml; - ssize_t r; - int ok = 1; - - pa = NULL; - po = prop_dictionary_get(dict, "filters"); - if ((po != NULL) && prop_object_type(po) == PROP_TYPE_ARRAY) { - pa = po; - } - - udm = udev_monitor_init(cli, pa); - if (udm == NULL) - return 1; - - MONITOR_LOCK(); - TAILQ_INSERT_TAIL(&udev_monitor_list, udm, link); - MONITOR_UNLOCK(); - - pthread_mutex_lock(&udm->q_lock); - while (ok) { - pthread_cond_wait(&udm->cond, &udm->q_lock); - - udm_ev = TAILQ_FIRST(&udm->ev_queue); - if (udm_ev == NULL) - continue; - - assert(udm_ev->ev_dict != NULL); - xml = prop_dictionary_externalize(udm_ev->ev_dict); - if (xml == NULL) - continue; - - prop_object_release(udm_ev->ev_dict); - udm_ev->ev_dict = NULL; - TAILQ_REMOVE(&udm->ev_queue, udm_ev, link); - free(udm_ev); - - r = send_xml(cli->fd, xml); - if (r <= 0) - goto end; - - free(xml); - continue; -end: - pthread_mutex_unlock(&udm->q_lock); - close(cli->fd); - ok = 0; - free(xml); - } - - MONITOR_LOCK(); - TAILQ_REMOVE(&udev_monitor_list, udm, link); - MONITOR_UNLOCK(); - - udev_monitor_free(udm); - - return 1; -} - -static int -_parse_filter_prop(struct udev_monitor *udm, prop_array_t pa) -{ - prop_string_t ps; - prop_number_t pn; - prop_object_iterator_t iter; - prop_dictionary_t dict; - struct event_filter *evf; - int error; - - iter = prop_array_iterator(pa); - if (iter == NULL) - return -1; - - while ((dict = prop_object_iterator_next(iter)) != NULL) { - evf = malloc(sizeof(struct event_filter)); - if (evf == NULL) - goto error_alloc; - - ps = prop_dictionary_get(dict, "key"); - if (ps == NULL) - goto error_out; - evf->key = prop_string_cstring(ps); - if (evf->key == NULL) - goto error_out; - - pn = prop_dictionary_get(dict, "type"); - if (pn == NULL) - goto error_out_ps; - - ps = prop_dictionary_get(dict, "expr"); - if (ps == NULL) - goto error_out_ps; - - if (prop_dictionary_get(dict, "negative")) - evf->neg = 1; - else - evf->neg = 0; - - evf->type = prop_number_integer_value(pn); - switch (evf->type) { - case EVENT_FILTER_TYPE_WILDCARD: - evf->wildcard_match = prop_string_cstring(ps); - if (evf->wildcard_match == NULL) - goto error_out_ps; - break; - - case EVENT_FILTER_TYPE_REGEX: - error = regcomp(&evf->regex_match, prop_string_cstring_nocopy(ps), REG_ICASE | REG_NOSUB); - if (error) - goto error_out_ps; - break; - - default: - goto error_out_ps; - } - - pthread_mutex_lock(&udm->q_lock); - TAILQ_INSERT_TAIL(&udm->ev_filt, evf, link); - pthread_mutex_unlock(&udm->q_lock); - - } - - prop_object_iterator_release(iter); - return 0; - -error_out_ps: - free(evf->key); -error_out: - free(evf); -error_alloc: - prop_object_iterator_release(iter); - return -1; -} - -/* -Event filter format: - - -key -(e.g. kptr, devnum, ...) -type -(e.g. wildcard or regex) -expr -(regex) - -... repeat ... - -*/ - -static int -match_filter(struct event_filter *evf, prop_dictionary_t ev_dict) -{ - prop_object_t po; - prop_string_t ps; - prop_number_t pn; - char *str; - char buf[128]; - int ret; - - if (ev_dict == NULL) - return 0; - - prop_object_retain(ev_dict); - - assert(prop_dictionary_externalize(ev_dict) != NULL); - if ((po = prop_dictionary_get(ev_dict, evf->key)) == NULL) - goto no_match; - - if (prop_object_type(po) == PROP_TYPE_STRING) { - ps = po; - str = __DECONST(char *, prop_string_cstring_nocopy(ps)); - } else if (prop_object_type(po) == PROP_TYPE_NUMBER) { - pn = po; - if (prop_number_unsigned(pn)) { - snprintf(buf, sizeof(buf), "%" PRIu64, prop_number_unsigned_integer_value(pn)); - } else { - snprintf(buf, sizeof(buf), "%" PRIi64, prop_number_integer_value(pn)); - } - str = buf; - } else { - syslog(LOG_DEBUG, "Unexpected type in match_filter: %d\n", prop_object_type(po)); - /* Unexpected type */ - goto no_match; - } - - switch (evf->type) { - case EVENT_FILTER_TYPE_WILDCARD: - ret = WildCaseCmp(evf->wildcard_match, str); - - if (ret != 0) - goto no_match; - - break; - case EVENT_FILTER_TYPE_REGEX: - ret = regexec(&evf->regex_match, str, 0, NULL, 0); - - if (ret != 0) - goto no_match; - break; - default: - goto no_match; - } - - prop_object_release(ev_dict); - return 1; - -no_match: - prop_object_release(ev_dict); - return 0; -} - -int -match_event_filter(struct udev_monitor *udm, prop_dictionary_t ev_dict) -{ - struct event_filter *evf; - int all_negative = 1; - - pthread_mutex_lock(&udm->q_lock); - - if (TAILQ_EMPTY(&udm->ev_filt)) - return 1; - - TAILQ_FOREACH(evf, &udm->ev_filt, link) { - //printf("match_event_filter 3\n"); - if (evf->neg == 0) - all_negative = 0; - - if (match_filter(evf, ev_dict)) { - pthread_mutex_unlock(&udm->q_lock); - return (1 ^ evf->neg); /* return 1; or 0 for 'nomatch' hit */ - } - //printf("match_event_filter 5\n"); - } - - pthread_mutex_unlock(&udm->q_lock); - return (all_negative == 1)?1:0; -} - -static int -WildCaseCmp(const char *w, const char *s) -{ - int i; - int c; - int slen = strlen(s); - const char **mary; - - for (i = c = 0; w[i]; ++i) { - if (w[i] == '*') - ++c; - } - mary = malloc(sizeof(char *) * (c + 1)); - if (mary == NULL) - return -1; - - for (i = 0; i < c; ++i) - mary[i] = s + slen; - i = wildCaseCmp(mary, 0, w, s); - free(mary); - return(i); -} - -/* - * WildCaseCmp() - compare wild string to sane string, case insensitive - * - * Returns 0 on success, -1 on failure. - */ -static int -wildCaseCmp(const char **mary, int d, const char *w, const char *s) -{ - int i; - - /* - * skip fixed portion - */ - for (;;) { - switch(*w) { - case '*': - /* - * optimize terminator - */ - if (w[1] == 0) - return(0); - if (w[1] != '?' && w[1] != '*') { - /* - * optimize * followed by non-wild - */ - for (i = 0; s + i < mary[d]; ++i) { - if (s[i] == w[1] && wildCaseCmp(mary, d + 1, w + 1, s + i) == 0) - return(0); - } - } else { - /* - * less-optimal - */ - for (i = 0; s + i < mary[d]; ++i) { - if (wildCaseCmp(mary, d + 1, w + 1, s + i) == 0) - return(0); - } - } - mary[d] = s; - return(-1); - case '?': - if (*s == 0) - return(-1); - ++w; - ++s; - break; - default: - if (*w != *s) { - if (tolower(*w) != tolower(*s)) - return(-1); - } - if (*w == 0) /* terminator */ - return(0); - ++w; - ++s; - break; - } - } - /* not reached */ - return(-1); -} diff --git a/usr.sbin/udevd/udevd_pdev.c b/usr.sbin/udevd/udevd_pdev.c deleted file mode 100644 index 5992a13..0000000 --- a/usr.sbin/udevd/udevd_pdev.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (c) 2010 The DragonFly Project. All rights reserved. - * - * This code is derived from software contributed to The DragonFly Project - * by Alex Hornung - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name of The DragonFly Project nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific, prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include "udevd.h" - -static int64_t udev_generation; -TAILQ_HEAD(pdev_array_list_head, pdev_array_entry) pdev_array_list; - -void -pdev_array_entry_ref(struct pdev_array_entry *pae) -{ - ++pae->refs; -} - -void -pdev_array_entry_unref(struct pdev_array_entry *pae) -{ - if (--pae->refs == 0) { - TAILQ_REMOVE(&pdev_array_list, pae, link); - prop_object_release(pae->pdev_array); /* XXX */ - free(pae); - } -} - -void -pdev_array_entry_insert(prop_array_t pa) -{ - struct pdev_array_entry *pae, *opae = NULL; - - if (pa == NULL) - errx(1, "null prop_array in insert_pdev_array"); - pae = malloc(sizeof(struct pdev_array_entry)); - if (pae == NULL) - errx(1, "insert_pdev_array could not allocate mem"); - memset(pae, 0, sizeof(struct pdev_array_entry)); - pae->pdev_array = pa; - pae->generation = udev_generation++; - pae->refs = 1; /* One ref because it's the most recent one */ - - /* - * If the TAILQ is not empty, unref the last entry, - * as it isn't needed anymore. - */ - if (!TAILQ_EMPTY(&pdev_array_list)) - opae = TAILQ_LAST(&pdev_array_list, pdev_array_list_head); - - TAILQ_INSERT_TAIL(&pdev_array_list, pae, link); - - if (opae != NULL) - pdev_array_entry_unref(opae); -} - -struct pdev_array_entry * -pdev_array_entry_get(int64_t generation) -{ - struct pdev_array_entry *pae; - int found = 0; - - TAILQ_FOREACH(pae, &pdev_array_list, link) { - if (pae->generation == generation) { - found = 1; - break; - } - } - - if (!found) - return NULL; - - pdev_array_entry_ref(pae); - return pae; -} - -struct pdev_array_entry * -pdev_array_entry_get_last(void) -{ - struct pdev_array_entry *pae; - - pae = TAILQ_LAST(&pdev_array_list, pdev_array_list_head); - - pdev_array_entry_ref(pae); - return pae; -} diff --git a/usr.sbin/udevd/udevd_socket.c b/usr.sbin/udevd/udevd_socket.c deleted file mode 100644 index f6a4bfd..0000000 --- a/usr.sbin/udevd/udevd_socket.c +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (c) 2010 The DragonFly Project. All rights reserved. - * - * This code is derived from software contributed to The DragonFly Project - * by Alex Hornung - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name of The DragonFly Project nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific, prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include "udevd.h" - -int -send_xml(int s, char *xml) -{ - ssize_t r,n; - size_t sz; - - sz = strlen(xml) + 1; - - r = send(s, &sz, sizeof(sz), 0); - if (r <= 0) - return r; - - r = 0; - while (r < (ssize_t)sz) { - n = send(s, xml+r, sz-r, 0); - if (n <= 0) - return n; - r += n; - } - - return r; -} - -int -read_xml(int s, char *buf, size_t buf_sz) -{ - size_t sz; - int n, r; - - n = recv(s, &sz, sizeof(sz), MSG_WAITALL); - if (n <= 0) - return n; - - r = 0; - while ((r < (ssize_t)sz) && (r < (ssize_t)buf_sz)) { - n = recv(s, buf+r, sz-r, MSG_WAITALL); - if (n <= 0) - return n; - r += n; - } - - return r; -} - -int -unblock_descriptor(int s) -{ - int flags, ret; - - flags = fcntl(s, F_GETFL, 0); - ret = fcntl(s, F_SETFL, flags | O_NONBLOCK); - return ret; -} - -int -block_descriptor(int s) -{ - int flags, ret; - - flags = fcntl(s, F_GETFL, 0); - ret = fcntl(s, F_SETFL, flags & ~O_NONBLOCK); - return ret; -} - -int -init_local_server(const char *sockfile, int socktype, int nonblock) -{ - int s; - struct sockaddr_un un_addr; - - if ((s = socket(AF_UNIX, socktype, 0)) < 0) - return -1; - - memset(&un_addr, 0, sizeof(un_addr)); - un_addr.sun_family = AF_UNIX; - strncpy(un_addr.sun_path, sockfile, SOCKFILE_NAMELEN); - un_addr.sun_path[SOCKFILE_NAMELEN - 1] = '\0'; - - /* - * DO NOT change `un_addr.sun_path' to `sockfile' here, - * since `sockfile' may have been truncated by above strncpy(3). - */ - unlink(un_addr.sun_path); - - if (nonblock && unblock_descriptor(s) < 0) { - close(s); - return -1; - } - - if (bind(s, (struct sockaddr *)&un_addr, sizeof(un_addr)) < 0) { - close(s); - return -1; - } - - if (socktype == SOCK_STREAM && listen(s, LOCAL_BACKLOG) < 0) { - close(s); - return -1; - } - - return s; -} -- 1.7.7.2