13a3826b3SAlex Hornung /*
23a3826b3SAlex Hornung * Copyright (c) 2010 The DragonFly Project. All rights reserved.
33a3826b3SAlex Hornung *
43a3826b3SAlex Hornung * This code is derived from software contributed to The DragonFly Project
53a3826b3SAlex Hornung * by Alex Hornung <ahornung@gmail.com>
63a3826b3SAlex Hornung *
73a3826b3SAlex Hornung * Redistribution and use in source and binary forms, with or without
83a3826b3SAlex Hornung * modification, are permitted provided that the following conditions
93a3826b3SAlex Hornung * are met:
103a3826b3SAlex Hornung *
113a3826b3SAlex Hornung * 1. Redistributions of source code must retain the above copyright
123a3826b3SAlex Hornung * notice, this list of conditions and the following disclaimer.
133a3826b3SAlex Hornung * 2. Redistributions in binary form must reproduce the above copyright
143a3826b3SAlex Hornung * notice, this list of conditions and the following disclaimer in
153a3826b3SAlex Hornung * the documentation and/or other materials provided with the
163a3826b3SAlex Hornung * distribution.
173a3826b3SAlex Hornung * 3. Neither the name of The DragonFly Project nor the names of its
183a3826b3SAlex Hornung * contributors may be used to endorse or promote products derived
193a3826b3SAlex Hornung * from this software without specific, prior written permission.
203a3826b3SAlex Hornung *
213a3826b3SAlex Hornung * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
223a3826b3SAlex Hornung * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
233a3826b3SAlex Hornung * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
243a3826b3SAlex Hornung * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
253a3826b3SAlex Hornung * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
263a3826b3SAlex Hornung * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
273a3826b3SAlex Hornung * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
283a3826b3SAlex Hornung * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
293a3826b3SAlex Hornung * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
303a3826b3SAlex Hornung * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
313a3826b3SAlex Hornung * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
323a3826b3SAlex Hornung * SUCH DAMAGE.
333a3826b3SAlex Hornung */
343a3826b3SAlex Hornung #include <sys/types.h>
353a3826b3SAlex Hornung #include <sys/wait.h>
363a3826b3SAlex Hornung #include <sys/socket.h>
373a3826b3SAlex Hornung #include <sys/ioctl.h>
383a3826b3SAlex Hornung #include <sys/poll.h>
393a3826b3SAlex Hornung #include <sys/queue.h>
403a3826b3SAlex Hornung #include <sys/un.h>
413a3826b3SAlex Hornung
423a3826b3SAlex Hornung #include <err.h>
433a3826b3SAlex Hornung #include <errno.h>
443a3826b3SAlex Hornung #include <fcntl.h>
453a3826b3SAlex Hornung #include <libgen.h>
463a3826b3SAlex Hornung #include <regex.h>
473a3826b3SAlex Hornung #include <signal.h>
483a3826b3SAlex Hornung #include <stdarg.h>
493a3826b3SAlex Hornung #include <stdio.h>
503a3826b3SAlex Hornung #include <stdlib.h>
513a3826b3SAlex Hornung #include <string.h>
523a3826b3SAlex Hornung #include <syslog.h>
533a3826b3SAlex Hornung #include <unistd.h>
543a3826b3SAlex Hornung
553a3826b3SAlex Hornung #include <libprop/proplib.h>
563a3826b3SAlex Hornung #include <sys/udev.h>
57*3bbbc629SAlex Hornung #define LIBDEVATTR_INTERNAL
583a3826b3SAlex Hornung #include "devattr.h"
593a3826b3SAlex Hornung
603a3826b3SAlex Hornung struct udev {
613a3826b3SAlex Hornung int gp_fd;
623a3826b3SAlex Hornung int monitor_fd;
633a3826b3SAlex Hornung int refs;
643a3826b3SAlex Hornung
653a3826b3SAlex Hornung void *userdata;
663a3826b3SAlex Hornung };
673a3826b3SAlex Hornung
683a3826b3SAlex Hornung struct udev *
udev_ref(struct udev * udev_ctx)693a3826b3SAlex Hornung udev_ref(struct udev *udev_ctx)
703a3826b3SAlex Hornung {
713a3826b3SAlex Hornung atomic_add_int(&udev_ctx->refs, 1);
723a3826b3SAlex Hornung
733a3826b3SAlex Hornung return udev_ctx;
743a3826b3SAlex Hornung }
753a3826b3SAlex Hornung
763a3826b3SAlex Hornung void
udev_unref(struct udev * udev_ctx)773a3826b3SAlex Hornung udev_unref(struct udev *udev_ctx)
783a3826b3SAlex Hornung {
793a3826b3SAlex Hornung int refcount;
803a3826b3SAlex Hornung
813a3826b3SAlex Hornung refcount = atomic_fetchadd_int(&udev_ctx->refs, -1);
823a3826b3SAlex Hornung
833a3826b3SAlex Hornung if (refcount == 1) {
843a3826b3SAlex Hornung atomic_subtract_int(&udev_ctx->refs, 0x400); /* in destruction */
853a3826b3SAlex Hornung if (udev_ctx->gp_fd != -1)
863a3826b3SAlex Hornung close (udev_ctx->gp_fd);
873a3826b3SAlex Hornung if (udev_ctx->monitor_fd != -1)
883a3826b3SAlex Hornung close (udev_ctx->monitor_fd);
893a3826b3SAlex Hornung
903a3826b3SAlex Hornung free(udev_ctx);
913a3826b3SAlex Hornung }
923a3826b3SAlex Hornung }
933a3826b3SAlex Hornung
943a3826b3SAlex Hornung struct udev *
udev_new(void)953a3826b3SAlex Hornung udev_new(void)
963a3826b3SAlex Hornung {
973a3826b3SAlex Hornung struct udev *udev_ctx;
983a3826b3SAlex Hornung int ret, s;
993a3826b3SAlex Hornung
1003a3826b3SAlex Hornung ret = conn_local_server(LISTEN_SOCKET_FILE, SOCK_STREAM, 0, &s);
1013a3826b3SAlex Hornung if (ret < 0)
1023a3826b3SAlex Hornung return NULL;
1033a3826b3SAlex Hornung
1043a3826b3SAlex Hornung udev_ctx = malloc(sizeof(struct udev));
1053a3826b3SAlex Hornung
1063a3826b3SAlex Hornung udev_ctx->refs = 1;
1073a3826b3SAlex Hornung udev_ctx->gp_fd = s;
1083a3826b3SAlex Hornung udev_ctx->monitor_fd = -1;
1093a3826b3SAlex Hornung udev_ctx->userdata = NULL;
1103a3826b3SAlex Hornung
1113a3826b3SAlex Hornung return udev_ctx;
1123a3826b3SAlex Hornung }
1133a3826b3SAlex Hornung
udev_get_dev_path(struct udev * udev_ctx __unused)1143a3826b3SAlex Hornung const char *udev_get_dev_path(struct udev *udev_ctx __unused)
1153a3826b3SAlex Hornung {
1163a3826b3SAlex Hornung return "/dev";
1173a3826b3SAlex Hornung }
1183a3826b3SAlex Hornung
1193a3826b3SAlex Hornung void *
udev_get_userdata(struct udev * udev_ctx)1203a3826b3SAlex Hornung udev_get_userdata(struct udev *udev_ctx)
1213a3826b3SAlex Hornung {
1223a3826b3SAlex Hornung return udev_ctx->userdata;
1233a3826b3SAlex Hornung }
1243a3826b3SAlex Hornung
1253a3826b3SAlex Hornung void
udev_set_userdata(struct udev * udev_ctx,void * userdata)1263a3826b3SAlex Hornung udev_set_userdata(struct udev *udev_ctx, void *userdata)
1273a3826b3SAlex Hornung {
1283a3826b3SAlex Hornung udev_ctx->userdata = userdata;
1293a3826b3SAlex Hornung }
1303a3826b3SAlex Hornung
1313a3826b3SAlex Hornung int
udev_get_fd(struct udev * udev_ctx)1323a3826b3SAlex Hornung udev_get_fd(struct udev *udev_ctx)
1333a3826b3SAlex Hornung {
1343a3826b3SAlex Hornung return udev_ctx->gp_fd;
1353a3826b3SAlex Hornung }
1363a3826b3SAlex Hornung
1373a3826b3SAlex Hornung int
send_xml(int s,char * xml)1383a3826b3SAlex Hornung send_xml(int s, char *xml)
1393a3826b3SAlex Hornung {
1403a3826b3SAlex Hornung ssize_t r,n;
1413a3826b3SAlex Hornung size_t sz;
1423a3826b3SAlex Hornung
1433a3826b3SAlex Hornung sz = strlen(xml) + 1;
1443a3826b3SAlex Hornung
1453a3826b3SAlex Hornung r = send(s, &sz, sizeof(sz), 0);
1463a3826b3SAlex Hornung if (r <= 0)
1473a3826b3SAlex Hornung return r;
1483a3826b3SAlex Hornung
1493a3826b3SAlex Hornung r = 0;
1503a3826b3SAlex Hornung while (r < (ssize_t)sz) {
1513a3826b3SAlex Hornung n = send(s, xml+r, sz-r, 0);
1523a3826b3SAlex Hornung if (n <= 0)
1533a3826b3SAlex Hornung return n;
1543a3826b3SAlex Hornung r += n;
1553a3826b3SAlex Hornung }
1563a3826b3SAlex Hornung
1573a3826b3SAlex Hornung return r;
1583a3826b3SAlex Hornung }
1593a3826b3SAlex Hornung
1603a3826b3SAlex Hornung int
read_xml(int s,char ** buf)161*3bbbc629SAlex Hornung read_xml(int s, char **buf)
1623a3826b3SAlex Hornung {
163*3bbbc629SAlex Hornung char *xml;
1643a3826b3SAlex Hornung size_t sz;
1653a3826b3SAlex Hornung int n, r;
1663a3826b3SAlex Hornung
167*3bbbc629SAlex Hornung *buf = NULL;
168*3bbbc629SAlex Hornung
1693a3826b3SAlex Hornung n = recv(s, &sz, sizeof(sz), MSG_WAITALL);
170*3bbbc629SAlex Hornung if ((n <= 0) || (sz > 12*1024*1024)) /* Arbitrary limit */
1713a3826b3SAlex Hornung return n;
1723a3826b3SAlex Hornung
173*3bbbc629SAlex Hornung xml = malloc(sz+2);
1743a3826b3SAlex Hornung r = 0;
175*3bbbc629SAlex Hornung while (r < (ssize_t)sz) {
176*3bbbc629SAlex Hornung n = recv(s, xml+r, sz-r, MSG_WAITALL);
177*3bbbc629SAlex Hornung if (n <= 0) {
178*3bbbc629SAlex Hornung free(xml);
1793a3826b3SAlex Hornung return n;
180*3bbbc629SAlex Hornung }
1813a3826b3SAlex Hornung r += n;
1823a3826b3SAlex Hornung }
1833a3826b3SAlex Hornung
184*3bbbc629SAlex Hornung *buf = xml;
1853a3826b3SAlex Hornung return r;
1863a3826b3SAlex Hornung }
1873a3826b3SAlex Hornung
1883a3826b3SAlex Hornung int
_udev_dict_set_cstr(prop_dictionary_t dict,const char * key,char * str)1893a3826b3SAlex Hornung _udev_dict_set_cstr(prop_dictionary_t dict, const char *key, char *str)
1903a3826b3SAlex Hornung {
1913a3826b3SAlex Hornung prop_string_t ps;
1923a3826b3SAlex Hornung
1933a3826b3SAlex Hornung ps = prop_string_create_cstring(str);
1943a3826b3SAlex Hornung if (ps == NULL)
1953a3826b3SAlex Hornung return ENOMEM;
1963a3826b3SAlex Hornung
1973a3826b3SAlex Hornung if (prop_dictionary_set(dict, key, ps) == false) {
1983a3826b3SAlex Hornung prop_object_release(ps);
1993a3826b3SAlex Hornung return ENOMEM;
2003a3826b3SAlex Hornung }
2013a3826b3SAlex Hornung
2023a3826b3SAlex Hornung prop_object_release(ps);
2033a3826b3SAlex Hornung return 0;
2043a3826b3SAlex Hornung }
2053a3826b3SAlex Hornung
2063a3826b3SAlex Hornung int
_udev_dict_set_int(prop_dictionary_t dict,const char * key,int64_t val)2073a3826b3SAlex Hornung _udev_dict_set_int(prop_dictionary_t dict, const char *key, int64_t val)
2083a3826b3SAlex Hornung {
2093a3826b3SAlex Hornung prop_number_t pn;
2103a3826b3SAlex Hornung
2113a3826b3SAlex Hornung pn = prop_number_create_integer(val);
2123a3826b3SAlex Hornung if (pn == NULL)
2133a3826b3SAlex Hornung return ENOMEM;
2143a3826b3SAlex Hornung
2153a3826b3SAlex Hornung if (prop_dictionary_set(dict, key, pn) == false) {
2163a3826b3SAlex Hornung prop_object_release(pn);
2173a3826b3SAlex Hornung return ENOMEM;
2183a3826b3SAlex Hornung }
2193a3826b3SAlex Hornung
2203a3826b3SAlex Hornung prop_object_release(pn);
2213a3826b3SAlex Hornung return 0;
2223a3826b3SAlex Hornung }
2233a3826b3SAlex Hornung
2243a3826b3SAlex Hornung int
_udev_dict_set_uint(prop_dictionary_t dict,const char * key,uint64_t val)2253a3826b3SAlex Hornung _udev_dict_set_uint(prop_dictionary_t dict, const char *key, uint64_t val)
2263a3826b3SAlex Hornung {
2273a3826b3SAlex Hornung prop_number_t pn;
2283a3826b3SAlex Hornung
2293a3826b3SAlex Hornung pn = prop_number_create_unsigned_integer(val);
2303a3826b3SAlex Hornung if (pn == NULL)
2313a3826b3SAlex Hornung return ENOMEM;
2323a3826b3SAlex Hornung
2333a3826b3SAlex Hornung if (prop_dictionary_set(dict, key, pn) == false) {
2343a3826b3SAlex Hornung prop_object_release(pn);
2353a3826b3SAlex Hornung return ENOMEM;
2363a3826b3SAlex Hornung }
2373a3826b3SAlex Hornung
2383a3826b3SAlex Hornung prop_object_release(pn);
2393a3826b3SAlex Hornung return 0;
2403a3826b3SAlex Hornung }
2413a3826b3SAlex Hornung
2423a3826b3SAlex Hornung int
conn_local_server(const char * sockfile,int socktype,int nonblock __unused,int * retsock)2433a3826b3SAlex Hornung conn_local_server(const char *sockfile, int socktype, int nonblock __unused,
2443a3826b3SAlex Hornung int *retsock)
2453a3826b3SAlex Hornung {
2463a3826b3SAlex Hornung int s;
2473a3826b3SAlex Hornung struct sockaddr_un serv_addr;
2483a3826b3SAlex Hornung
2493a3826b3SAlex Hornung *retsock = -1;
2503a3826b3SAlex Hornung if ((s = socket(AF_UNIX, socktype, 0)) < 0)
2513a3826b3SAlex Hornung return -1;
2523a3826b3SAlex Hornung
2533a3826b3SAlex Hornung memset(&serv_addr, 0, sizeof(serv_addr));
2543a3826b3SAlex Hornung serv_addr.sun_family = AF_UNIX;
2553a3826b3SAlex Hornung strncpy(serv_addr.sun_path, sockfile, SOCKFILE_NAMELEN);
2563a3826b3SAlex Hornung serv_addr.sun_path[SOCKFILE_NAMELEN - 1] = '\0';
2573a3826b3SAlex Hornung
2583a3826b3SAlex Hornung *retsock = s;
2593a3826b3SAlex Hornung return connect(s, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
2603a3826b3SAlex Hornung }
2613a3826b3SAlex Hornung
2623a3826b3SAlex Hornung prop_dictionary_t
udevd_get_command_dict(char * command)2633a3826b3SAlex Hornung udevd_get_command_dict(char *command)
2643a3826b3SAlex Hornung {
2653a3826b3SAlex Hornung prop_dictionary_t dict;
2663a3826b3SAlex Hornung int error;
2673a3826b3SAlex Hornung
2683a3826b3SAlex Hornung dict = prop_dictionary_create();
2693a3826b3SAlex Hornung if (dict == NULL)
2703a3826b3SAlex Hornung return NULL;
2713a3826b3SAlex Hornung
2723a3826b3SAlex Hornung if ((error = _udev_dict_set_cstr(dict, "command", command)))
2733a3826b3SAlex Hornung goto error_out;
2743a3826b3SAlex Hornung
2753a3826b3SAlex Hornung return dict;
2763a3826b3SAlex Hornung
2773a3826b3SAlex Hornung error_out:
2783a3826b3SAlex Hornung prop_object_release(dict);
2793a3826b3SAlex Hornung return NULL;
2803a3826b3SAlex Hornung }
2813a3826b3SAlex Hornung
2823a3826b3SAlex Hornung prop_array_t
udevd_request_devs(int s,prop_array_t filters)2833a3826b3SAlex Hornung udevd_request_devs(int s, prop_array_t filters)
2843a3826b3SAlex Hornung {
2853a3826b3SAlex Hornung prop_array_t pa;
2863a3826b3SAlex Hornung prop_dictionary_t dict;
2873a3826b3SAlex Hornung char *xml;
2883a3826b3SAlex Hornung
2893a3826b3SAlex Hornung int n;
2903a3826b3SAlex Hornung
2913a3826b3SAlex Hornung dict = udevd_get_command_dict(__DECONST(char *, "getdevs"));
2923a3826b3SAlex Hornung if (dict == NULL)
2933a3826b3SAlex Hornung return NULL;
2943a3826b3SAlex Hornung
2953a3826b3SAlex Hornung /* Add filters to message, if available */
2963a3826b3SAlex Hornung if (filters != NULL) {
2973a3826b3SAlex Hornung if (prop_dictionary_set(dict, "filters", filters) == false) {
2983a3826b3SAlex Hornung prop_object_release(dict);
2993a3826b3SAlex Hornung return NULL;
3003a3826b3SAlex Hornung }
3013a3826b3SAlex Hornung }
3023a3826b3SAlex Hornung
3033a3826b3SAlex Hornung xml = prop_dictionary_externalize(dict);
3043a3826b3SAlex Hornung prop_object_release(dict);
3053a3826b3SAlex Hornung if (xml == NULL)
3063a3826b3SAlex Hornung return NULL;
3073a3826b3SAlex Hornung
3083a3826b3SAlex Hornung n = send_xml(s, xml);
3093a3826b3SAlex Hornung free(xml);
3103a3826b3SAlex Hornung
3113a3826b3SAlex Hornung if (n <= 0)
3123a3826b3SAlex Hornung return NULL;
3133a3826b3SAlex Hornung
314*3bbbc629SAlex Hornung if ((n = read_xml(s, &xml)) <= 0)
3153a3826b3SAlex Hornung return NULL;
3163a3826b3SAlex Hornung
3173a3826b3SAlex Hornung xml[n+1] = '\0';
3183a3826b3SAlex Hornung pa = prop_array_internalize(xml);
3193a3826b3SAlex Hornung free(xml);
3203a3826b3SAlex Hornung return (pa);
3213a3826b3SAlex Hornung }
322