xref: /dragonfly/sbin/udevd/udevd_client.c (revision 0c8103dd)
12e7bf158SAlex Hornung /*
22e7bf158SAlex Hornung  * Copyright (c) 2010 The DragonFly Project.  All rights reserved.
32e7bf158SAlex Hornung  *
42e7bf158SAlex Hornung  * This code is derived from software contributed to The DragonFly Project
52e7bf158SAlex Hornung  * by Alex Hornung <ahornung@gmail.com>
62e7bf158SAlex Hornung  *
72e7bf158SAlex Hornung  * Redistribution and use in source and binary forms, with or without
82e7bf158SAlex Hornung  * modification, are permitted provided that the following conditions
92e7bf158SAlex Hornung  * are met:
102e7bf158SAlex Hornung  *
112e7bf158SAlex Hornung  * 1. Redistributions of source code must retain the above copyright
122e7bf158SAlex Hornung  *    notice, this list of conditions and the following disclaimer.
132e7bf158SAlex Hornung  * 2. Redistributions in binary form must reproduce the above copyright
142e7bf158SAlex Hornung  *    notice, this list of conditions and the following disclaimer in
152e7bf158SAlex Hornung  *    the documentation and/or other materials provided with the
162e7bf158SAlex Hornung  *    distribution.
172e7bf158SAlex Hornung  * 3. Neither the name of The DragonFly Project nor the names of its
182e7bf158SAlex Hornung  *    contributors may be used to endorse or promote products derived
192e7bf158SAlex Hornung  *    from this software without specific, prior written permission.
202e7bf158SAlex Hornung  *
212e7bf158SAlex Hornung  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
222e7bf158SAlex Hornung  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
232e7bf158SAlex Hornung  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
242e7bf158SAlex Hornung  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
252e7bf158SAlex Hornung  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
262e7bf158SAlex Hornung  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
272e7bf158SAlex Hornung  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
282e7bf158SAlex Hornung  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
292e7bf158SAlex Hornung  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
302e7bf158SAlex Hornung  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
312e7bf158SAlex Hornung  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
322e7bf158SAlex Hornung  * SUCH DAMAGE.
332e7bf158SAlex Hornung  */
342e7bf158SAlex Hornung #include <sys/types.h>
352e7bf158SAlex Hornung #include <sys/device.h>
362e7bf158SAlex Hornung #include <sys/wait.h>
372e7bf158SAlex Hornung #include <sys/socket.h>
382e7bf158SAlex Hornung #include <sys/ioctl.h>
392e7bf158SAlex Hornung #include <sys/poll.h>
402e7bf158SAlex Hornung #include <sys/queue.h>
412e7bf158SAlex Hornung #include <sys/un.h>
422e7bf158SAlex Hornung 
432e7bf158SAlex Hornung #include <err.h>
442e7bf158SAlex Hornung #include <errno.h>
452e7bf158SAlex Hornung #include <fcntl.h>
462e7bf158SAlex Hornung #include <libgen.h>
472e7bf158SAlex Hornung #include <regex.h>
482e7bf158SAlex Hornung #include <signal.h>
492e7bf158SAlex Hornung #include <stdarg.h>
502e7bf158SAlex Hornung #include <stdio.h>
512e7bf158SAlex Hornung #include <stdlib.h>
522e7bf158SAlex Hornung #include <string.h>
532e7bf158SAlex Hornung #include <syslog.h>
542e7bf158SAlex Hornung #include <unistd.h>
552e7bf158SAlex Hornung #include <pthread.h>
56*9ff03f9eSAlex Hornung #include <assert.h>
572e7bf158SAlex Hornung 
582e7bf158SAlex Hornung #include <libprop/proplib.h>
592e7bf158SAlex Hornung #include <sys/udev.h>
602e7bf158SAlex Hornung #include "udevd.h"
612e7bf158SAlex Hornung 
622e7bf158SAlex Hornung struct cmd_function cmd_fn[] = {
632e7bf158SAlex Hornung 		{ .cmd = "getdevs", .fn = client_cmd_getdevs},
642e7bf158SAlex Hornung 		{ .cmd = "monitor", .fn = client_cmd_monitor},
652e7bf158SAlex Hornung 		{NULL, NULL}
662e7bf158SAlex Hornung };
672e7bf158SAlex Hornung 
682e7bf158SAlex Hornung static void *client_thread(void *arg);
692e7bf158SAlex Hornung 
702e7bf158SAlex Hornung void
handle_new_connection(int s)712e7bf158SAlex Hornung handle_new_connection(int s)
722e7bf158SAlex Hornung {
732e7bf158SAlex Hornung 	struct client_info *cli_info;
742e7bf158SAlex Hornung 	struct sockaddr_un addr;
752e7bf158SAlex Hornung 	int fd;
762e7bf158SAlex Hornung 	socklen_t saddr_len = sizeof(struct sockaddr_un);
772e7bf158SAlex Hornung 
782e7bf158SAlex Hornung 	fd = accept(s, (struct sockaddr *)&addr, &saddr_len);
792e7bf158SAlex Hornung 	if (fd < 0) {
802e7bf158SAlex Hornung 		syslog(LOG_ERR, "uh, oh, accept failed with %d", errno);
812e7bf158SAlex Hornung 		return;
822e7bf158SAlex Hornung 	}
832e7bf158SAlex Hornung 
842e7bf158SAlex Hornung 	block_descriptor(fd);
852e7bf158SAlex Hornung 	cli_info = malloc(sizeof(struct client_info));
862e7bf158SAlex Hornung 	memset(cli_info, 0, sizeof(struct client_info));
872e7bf158SAlex Hornung 
882e7bf158SAlex Hornung 	cli_info->fd = fd;
892e7bf158SAlex Hornung 	pthread_create(&cli_info->tid, NULL, client_thread, (void *)cli_info);
902e7bf158SAlex Hornung }
912e7bf158SAlex Hornung 
922e7bf158SAlex Hornung 
932e7bf158SAlex Hornung static void *
client_thread(void * arg)942e7bf158SAlex Hornung client_thread(void *arg)
952e7bf158SAlex Hornung {
962e7bf158SAlex Hornung 	prop_dictionary_t	dict;
972e7bf158SAlex Hornung 	prop_string_t		ps;
982e7bf158SAlex Hornung 	prop_object_t		po;
992e7bf158SAlex Hornung 	struct client_info	*cli;
1002e7bf158SAlex Hornung 	char	*xml;
1012e7bf158SAlex Hornung 	int	r, n, error;
1022e7bf158SAlex Hornung 
103*9ff03f9eSAlex Hornung 	r = pthread_detach(pthread_self());
104*9ff03f9eSAlex Hornung 	assert(r == 0);
105*9ff03f9eSAlex Hornung 
1062e7bf158SAlex Hornung 	r = ignore_signal(SIGPIPE);
1072e7bf158SAlex Hornung 	if (r != 0)
1082e7bf158SAlex Hornung 		err(1, "could not ignore_signal SIGPIPE");
1092e7bf158SAlex Hornung 
1102e7bf158SAlex Hornung 	cli = (struct client_info *)arg;
1112e7bf158SAlex Hornung 	for (;;) {
112*9ff03f9eSAlex Hornung 		n = read_xml(cli->fd, &xml);
1132e7bf158SAlex Hornung 		if (n == 0)
1142e7bf158SAlex Hornung 			goto cli_disconnect;
1152e7bf158SAlex Hornung 		else if (n < 0)
1162e7bf158SAlex Hornung 			goto error_out;
1172e7bf158SAlex Hornung 
1182e7bf158SAlex Hornung 		xml[n+1] = '\0';
1192e7bf158SAlex Hornung 
1202e7bf158SAlex Hornung 		dict = prop_dictionary_internalize(xml);
121*9ff03f9eSAlex Hornung 		free(xml);
122*9ff03f9eSAlex Hornung 
1232e7bf158SAlex Hornung 		if (dict == NULL) {
1242e7bf158SAlex Hornung 			syslog(LOG_ERR, "internalization of received XML failed");
1252e7bf158SAlex Hornung 			goto error_out;
1262e7bf158SAlex Hornung 		}
1272e7bf158SAlex Hornung 
1282e7bf158SAlex Hornung 		po = prop_dictionary_get(dict, "command");
1292e7bf158SAlex Hornung 		if (po == NULL || prop_object_type(po) != PROP_TYPE_STRING) {
1302e7bf158SAlex Hornung 			syslog(LOG_ERR, "received dictionary doesn't contain a key 'command'");
1312e7bf158SAlex Hornung 			prop_object_release(dict);
1322e7bf158SAlex Hornung 			continue;
1332e7bf158SAlex Hornung 		}
1342e7bf158SAlex Hornung 
1352e7bf158SAlex Hornung 		ps = po;
1362e7bf158SAlex Hornung 
1372e7bf158SAlex Hornung 		syslog(LOG_DEBUG, "Received command: %s (from fd = %d)\n", prop_string_cstring_nocopy(ps), cli->fd);
1382e7bf158SAlex Hornung 		for(n = 0; cmd_fn[n].cmd != NULL; n++) {
1392e7bf158SAlex Hornung 			if (prop_string_equals_cstring(ps, cmd_fn[n].cmd))
1402e7bf158SAlex Hornung 				break;
1412e7bf158SAlex Hornung 		}
1422e7bf158SAlex Hornung 
1432e7bf158SAlex Hornung 		if (cmd_fn[n].cmd != NULL) {
1442e7bf158SAlex Hornung 			error = cmd_fn[n].fn(cli, dict);
1452e7bf158SAlex Hornung 			if (error) {
1462e7bf158SAlex Hornung 				prop_object_release(dict);
1472e7bf158SAlex Hornung 				goto error_out;
1482e7bf158SAlex Hornung 			}
1492e7bf158SAlex Hornung 		}
1502e7bf158SAlex Hornung 		prop_object_release(dict);
1512e7bf158SAlex Hornung 	}
1522e7bf158SAlex Hornung 
1532e7bf158SAlex Hornung error_out:
1542e7bf158SAlex Hornung 
1552e7bf158SAlex Hornung cli_disconnect:
1562e7bf158SAlex Hornung 	close(cli->fd);
1572e7bf158SAlex Hornung 	cli->fd = -1;
1582e7bf158SAlex Hornung 	free(cli);
1592e7bf158SAlex Hornung 	return NULL;
1602e7bf158SAlex Hornung }
1612e7bf158SAlex Hornung 
1622e7bf158SAlex Hornung int
client_cmd_getdevs(struct client_info * cli,prop_dictionary_t cli_dict)1632e7bf158SAlex Hornung client_cmd_getdevs(struct client_info *cli, prop_dictionary_t cli_dict)
1642e7bf158SAlex Hornung {
1652e7bf158SAlex Hornung 	struct pdev_array_entry *pae;
1662e7bf158SAlex Hornung 	struct udev_monitor	*udm;
1672e7bf158SAlex Hornung 	prop_object_iterator_t	iter;
1682e7bf158SAlex Hornung 	prop_dictionary_t	dict;
1692e7bf158SAlex Hornung 	prop_object_t	po;
1702e7bf158SAlex Hornung 	prop_array_t	pa;
1712e7bf158SAlex Hornung 	char *xml;
1722e7bf158SAlex Hornung 	ssize_t r;
1732e7bf158SAlex Hornung 	int filters;
1742e7bf158SAlex Hornung 
1752e7bf158SAlex Hornung 
1762e7bf158SAlex Hornung 	pa = NULL;
1772e7bf158SAlex Hornung 	po = prop_dictionary_get(cli_dict, "filters");
1782e7bf158SAlex Hornung 	if ((po != NULL) && prop_object_type(po) == PROP_TYPE_ARRAY) {
1792e7bf158SAlex Hornung 		pa = po;
1802e7bf158SAlex Hornung 		filters = 1;
1812e7bf158SAlex Hornung 	} else {
1822e7bf158SAlex Hornung 		filters = 0;
1832e7bf158SAlex Hornung 	}
1842e7bf158SAlex Hornung 
1852e7bf158SAlex Hornung 	pae = pdev_array_entry_get_last();
1862e7bf158SAlex Hornung 	if (pae == NULL)
1872e7bf158SAlex Hornung 		return 1;
1882e7bf158SAlex Hornung 
1892e7bf158SAlex Hornung 	if (filters) {
1902e7bf158SAlex Hornung 		udm = udev_monitor_init(cli, pa);
1912e7bf158SAlex Hornung 		if (udm == NULL) {
1922e7bf158SAlex Hornung 			pdev_array_entry_unref(pae);
1932e7bf158SAlex Hornung 			return 1;
1942e7bf158SAlex Hornung 		}
1952e7bf158SAlex Hornung 
1962e7bf158SAlex Hornung 		pa = prop_array_create_with_capacity(10);
1972e7bf158SAlex Hornung 
1982e7bf158SAlex Hornung 		iter = prop_array_iterator(pae->pdev_array);
1992e7bf158SAlex Hornung 		if (iter == NULL) {
2002e7bf158SAlex Hornung 			pdev_array_entry_unref(pae);
2012e7bf158SAlex Hornung 			udev_monitor_free(udm);
2022e7bf158SAlex Hornung 			return 1;
2032e7bf158SAlex Hornung 		}
2042e7bf158SAlex Hornung 
2052e7bf158SAlex Hornung 		while ((dict = prop_object_iterator_next(iter)) != NULL) {
2062e7bf158SAlex Hornung 			if (match_event_filter(udm, dict)) {
2072e7bf158SAlex Hornung 				prop_array_add(pa, dict);
2082e7bf158SAlex Hornung 			}
2092e7bf158SAlex Hornung 		}
2102e7bf158SAlex Hornung 
211*9ff03f9eSAlex Hornung 		prop_object_iterator_release(iter);
2122e7bf158SAlex Hornung 		udev_monitor_free(udm);
2132e7bf158SAlex Hornung 	} else {
2142e7bf158SAlex Hornung 		pa = pae->pdev_array;
2152e7bf158SAlex Hornung 	}
2162e7bf158SAlex Hornung 
2172e7bf158SAlex Hornung 	xml = prop_array_externalize(pa);
2182e7bf158SAlex Hornung 	if (filters)
2192e7bf158SAlex Hornung 		prop_object_release(pa);
2202e7bf158SAlex Hornung 
2212e7bf158SAlex Hornung 	pdev_array_entry_unref(pae);
2222e7bf158SAlex Hornung 
2232e7bf158SAlex Hornung 	if (xml == NULL)
2242e7bf158SAlex Hornung 		return 1;
2252e7bf158SAlex Hornung 
2262e7bf158SAlex Hornung 	r = send_xml(cli->fd, xml);
2272e7bf158SAlex Hornung 	if (r < 0)
2282e7bf158SAlex Hornung 		syslog(LOG_DEBUG, "error while send_xml (cmd_getdevs)\n");
2292e7bf158SAlex Hornung 	if (r == 0)
2302e7bf158SAlex Hornung 		syslog(LOG_DEBUG, "EOF while send_xml (cmd_getdevs)\n");
2312e7bf158SAlex Hornung 
2322e7bf158SAlex Hornung 	free(xml);
2332e7bf158SAlex Hornung 
2342e7bf158SAlex Hornung 	return 0;
2352e7bf158SAlex Hornung }
236