xref: /dflybsd-src/lib/libdevattr/devattr.c (revision 0c8103dd622e5016512e2eedb2ceb865982089a5)
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