xref: /dflybsd-src/sbin/devattr/devattr.c (revision 1de3960396be14736ccbdd7071801467c0ca1bee)
132fe4284SNolan Lum /*
232fe4284SNolan Lum  * Copyright (c) 2010
332fe4284SNolan Lum  *		The DragonFly Project.	All rights reserved.
432fe4284SNolan Lum  *
532fe4284SNolan Lum  * This code is derived from software contributed to The DragonFly Project
632fe4284SNolan Lum  * by Nolan Lum <nol888@gmail.com>
732fe4284SNolan Lum  *
832fe4284SNolan Lum  * Redistribution and use in source and binary forms, with or without
932fe4284SNolan Lum  * modification, are permitted provided that the following conditions
1032fe4284SNolan Lum  * are met:
1132fe4284SNolan Lum  *
1232fe4284SNolan Lum  * 1. Redistributions of source code must retain the above copyright
1332fe4284SNolan Lum  *	  notice, this list of conditions and the following disclaimer.
1432fe4284SNolan Lum  * 2. Redistributions in binary form must reproduce the above copyright
1532fe4284SNolan Lum  *	  notice, this list of conditions and the following disclaimer in
1632fe4284SNolan Lum  *	  the documentation and/or other materials provided with the
1732fe4284SNolan Lum  *	  distribution.
1832fe4284SNolan Lum  * 3. Neither the name of The DragonFly Project nor the names of its
1932fe4284SNolan Lum  *	  contributors may be used to endorse or promote products derived
2032fe4284SNolan Lum  *	  from this software without specific, prior written permission.
2132fe4284SNolan Lum  *
2232fe4284SNolan Lum  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2332fe4284SNolan Lum  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2432fe4284SNolan Lum  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2532fe4284SNolan Lum  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.	 IN NO EVENT SHALL THE
2632fe4284SNolan Lum  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2732fe4284SNolan Lum  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
2832fe4284SNolan Lum  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2932fe4284SNolan Lum  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
3032fe4284SNolan Lum  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
3132fe4284SNolan Lum  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
3232fe4284SNolan Lum  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3332fe4284SNolan Lum  * SUCH DAMAGE.
3432fe4284SNolan Lum  */
3532fe4284SNolan Lum 
3632fe4284SNolan Lum #include <sys/queue.h>
3732fe4284SNolan Lum 
3832fe4284SNolan Lum #include <ctype.h>
3932fe4284SNolan Lum #include <devattr.h>
4032fe4284SNolan Lum #include <err.h>
4132fe4284SNolan Lum #include <inttypes.h>
4232fe4284SNolan Lum #include <string.h>
4332fe4284SNolan Lum #include <stdlib.h>
4432fe4284SNolan Lum #include <stdio.h>
4532fe4284SNolan Lum #include <sysexits.h>
4632fe4284SNolan Lum #include <unistd.h>
4732fe4284SNolan Lum 
4832fe4284SNolan Lum static SLIST_HEAD(, sl_entry) props = SLIST_HEAD_INITIALIZER(props);
4932fe4284SNolan Lum struct sl_entry {
5032fe4284SNolan Lum 	char *val;
5132fe4284SNolan Lum 	SLIST_ENTRY(sl_entry) entries;
5232fe4284SNolan Lum } *ent;
5332fe4284SNolan Lum 
54*1de39603SMatthew Dillon static int MonitorOpt;
55*1de39603SMatthew Dillon 
5632fe4284SNolan Lum static void
usage(const char * name)5714861de4SSascha Wildner usage(const char *name)
5814861de4SSascha Wildner {
5914861de4SSascha Wildner 	fprintf(stderr,
6014861de4SSascha Wildner 	    "usage: %s [-Ah] [-p property] [-d device] [-m key:value] [-r key:value]\n"
6132fe4284SNolan Lum 	    "Valid options are:\n"
6232fe4284SNolan Lum 	    " -A\n"
6332fe4284SNolan Lum 	    "	Don't display aliases.\n"
6432fe4284SNolan Lum 	    " -h\n"
6532fe4284SNolan Lum 	    "	Print this help message.\n\n"
66*1de39603SMatthew Dillon 	    " -M\n"
67*1de39603SMatthew Dillon 	    "   Continue monitoring after initial scan.\n\n"
6832fe4284SNolan Lum 	    "Valid options with their arguments are:\n"
6932fe4284SNolan Lum 	    " -p <property>\n"
7032fe4284SNolan Lum 	    "	Only display property; can be specified multiple times and\n"
7132fe4284SNolan Lum 	    "	combined with all other options.\n"
7232fe4284SNolan Lum 	    " -d <device>\n"
7332fe4284SNolan Lum 	    "	Only display devices with name `device'. When used with\n"
7432fe4284SNolan Lum 	    "	-p, only properties `-p' of device `-d' are listed. Can be\n"
7532fe4284SNolan Lum 	    "	specified multiple times. Allows wildcards.\n"
7632fe4284SNolan Lum 	    " -m <key:value>\n"
7732fe4284SNolan Lum 	    "	Only display devices whose property `key' matches with wildcards\n"
7832fe4284SNolan Lum 	    "	value `value' unless the key-value pair starts with ~, in which\n"
7932fe4284SNolan Lum 	    "	case the match is inverted. Stacks with -p, -d, and -m.\n"
8032fe4284SNolan Lum 	    "	Can be specified multiple times.\n"
8132fe4284SNolan Lum 	    " -r <key:value>\n"
8214861de4SSascha Wildner 	    "	Behaves similarly to `-m', but matches with regex.\n",
8314861de4SSascha Wildner 	    name);
8414861de4SSascha Wildner 	exit(EX_USAGE);
8532fe4284SNolan Lum }
8632fe4284SNolan Lum 
8714861de4SSascha Wildner static void
parse_args(int argc,char * argv[],struct udev_enumerate * enumerate)8814861de4SSascha Wildner parse_args(int argc, char *argv[], struct udev_enumerate *enumerate)
8914861de4SSascha Wildner {
9032fe4284SNolan Lum 	int ch, invert;
9132fe4284SNolan Lum 	char *colon;
9232fe4284SNolan Lum 
9332fe4284SNolan Lum 	SLIST_INIT(&props);
9432fe4284SNolan Lum 
9532fe4284SNolan Lum 	/* A = no aliases */
9632fe4284SNolan Lum 	/* p = properties to list (defaults to all) */
9732fe4284SNolan Lum 	/* d = devices to list (defaults to all) */
9832fe4284SNolan Lum 	/* m = display only devices in d that match these prop values */
9932fe4284SNolan Lum 	/* r = display only devices in d that match these prop values (regex) */
100*1de39603SMatthew Dillon 	while ((ch = getopt(argc, argv, "AMp:d:m:r:h")) != -1) {
10132fe4284SNolan Lum 		invert = false;
10232fe4284SNolan Lum 
10332fe4284SNolan Lum 		switch (ch) {
10432fe4284SNolan Lum 		case 'A':
10514861de4SSascha Wildner 			udev_enumerate_add_match_property(enumerate, "alias",
10614861de4SSascha Wildner 			    "0");
10732fe4284SNolan Lum 			break;
10832fe4284SNolan Lum 		case 'p':
10932fe4284SNolan Lum 			ent = malloc(sizeof(struct sl_entry));
11032fe4284SNolan Lum 			ent->val = optarg;
11132fe4284SNolan Lum 			SLIST_INSERT_HEAD(&props, ent, entries);
11232fe4284SNolan Lum 			break;
113*1de39603SMatthew Dillon 		case 'M':
114*1de39603SMatthew Dillon 			MonitorOpt = 1;
115*1de39603SMatthew Dillon 			break;
11632fe4284SNolan Lum 		case 'd':
11714861de4SSascha Wildner 			udev_enumerate_add_match_expr(enumerate, "name",
11814861de4SSascha Wildner 			    optarg);
11932fe4284SNolan Lum 			break;
12032fe4284SNolan Lum 		case 'm':
12132fe4284SNolan Lum 		case 'r':
12232fe4284SNolan Lum 			/* Check for exclusion. */
12332fe4284SNolan Lum 			invert = *optarg == '~';
12432fe4284SNolan Lum 
12532fe4284SNolan Lum 			/* Split into key/value. */
12632fe4284SNolan Lum 			colon = strchr(optarg, ':');
12732fe4284SNolan Lum 			if (colon == NULL) {
12832fe4284SNolan Lum 				fprintf(stderr,
12932fe4284SNolan Lum 				    "Invalid property key/value pair `%s'.\n",
13032fe4284SNolan Lum 				    optarg);
13114861de4SSascha Wildner 				return;
13232fe4284SNolan Lum 			}
13332fe4284SNolan Lum 
13432fe4284SNolan Lum 			*colon = '\0';
13532fe4284SNolan Lum 			if (invert) {
13632fe4284SNolan Lum 				if (ch == 'r')
13732fe4284SNolan Lum 					udev_enumerate_add_nomatch_regex(enumerate,
13832fe4284SNolan Lum 					    optarg + 1, colon + 1);
13932fe4284SNolan Lum 				else
14032fe4284SNolan Lum 					udev_enumerate_add_nomatch_expr(enumerate,
14132fe4284SNolan Lum 					    optarg + 1, colon + 1);
14232fe4284SNolan Lum 			} else {
14332fe4284SNolan Lum 				if (ch == 'r')
14432fe4284SNolan Lum 					udev_enumerate_add_match_regex(enumerate,
14532fe4284SNolan Lum 					    optarg, colon + 1);
14632fe4284SNolan Lum 				else
14732fe4284SNolan Lum 					udev_enumerate_add_match_expr(enumerate,
14832fe4284SNolan Lum 					    optarg, colon + 1);
14932fe4284SNolan Lum 			}
15032fe4284SNolan Lum 			break;
15132fe4284SNolan Lum 		case 'h':
15214861de4SSascha Wildner 		default:
15332fe4284SNolan Lum 			usage(argv[0]);
15432fe4284SNolan Lum 		}
15532fe4284SNolan Lum 	}
15614861de4SSascha Wildner 	return;
15732fe4284SNolan Lum }
15832fe4284SNolan Lum 
15932fe4284SNolan Lum static void
print_prop(const char * key,prop_object_t value)16014861de4SSascha Wildner print_prop(const char* key, prop_object_t value)
16114861de4SSascha Wildner {
16232fe4284SNolan Lum 	char *val_str;
16332fe4284SNolan Lum 
16432fe4284SNolan Lum 	printf("\t%s = ", key);
16532fe4284SNolan Lum 
16632fe4284SNolan Lum 	prop_type_t val_type = prop_object_type(value);
16732fe4284SNolan Lum 	switch (val_type) {
16832fe4284SNolan Lum 	case PROP_TYPE_BOOL:
16914861de4SSascha Wildner 		printf("%s\n", prop_bool_true((prop_bool_t)value) ?
17014861de4SSascha Wildner 		    "true" : "false");
17132fe4284SNolan Lum 		break;
17232fe4284SNolan Lum 	case PROP_TYPE_NUMBER:
17332fe4284SNolan Lum 		if (prop_number_unsigned((prop_number_t)value))
17432fe4284SNolan Lum 			printf("%1$"PRIu64" (0x%1$"PRIx64")\n",
17532fe4284SNolan Lum 			    prop_number_unsigned_integer_value((prop_number_t)value));
17632fe4284SNolan Lum 		else
17732fe4284SNolan Lum 			printf("%"PRId64"\n",
17832fe4284SNolan Lum 			    prop_number_integer_value((prop_number_t)value));
17932fe4284SNolan Lum 		break;
18032fe4284SNolan Lum 	case PROP_TYPE_STRING:
18132fe4284SNolan Lum 		val_str = prop_string_cstring(value);
18232fe4284SNolan Lum 		printf("%s\n", val_str);
18332fe4284SNolan Lum 		free(val_str);
18432fe4284SNolan Lum 		break;
18532fe4284SNolan Lum 	default:
18632fe4284SNolan Lum 		break;
18732fe4284SNolan Lum 	}
18832fe4284SNolan Lum }
18932fe4284SNolan Lum 
19032fe4284SNolan Lum int
main(int argc,char * argv[])19114861de4SSascha Wildner main(int argc, char* argv[])
19214861de4SSascha Wildner {
19332fe4284SNolan Lum 	struct udev *ctx;
19432fe4284SNolan Lum 	struct udev_enumerate *enumerate;
195*1de39603SMatthew Dillon 	struct udev_monitor *mon;
19632fe4284SNolan Lum 	struct udev_list_entry *current;
19732fe4284SNolan Lum 	struct udev_device *dev;
19832fe4284SNolan Lum 	prop_object_t key_val;
19932fe4284SNolan Lum 	prop_dictionary_t dict;
20032fe4284SNolan Lum 	prop_dictionary_keysym_t cur_key;
20132fe4284SNolan Lum 	prop_object_iterator_t iter;
20232fe4284SNolan Lum 	const char *key_str;
20332fe4284SNolan Lum 	char *dev_name;
20432fe4284SNolan Lum 	int ret;
20532fe4284SNolan Lum 
20632fe4284SNolan Lum 	ctx = udev_new();
207636d9c9eSAlex Hornung 	if (ctx == NULL) {
208636d9c9eSAlex Hornung 		fprintf(stderr, "Make sure udevd is running\n");
20932fe4284SNolan Lum 		err(EX_UNAVAILABLE, "udev_new");
210636d9c9eSAlex Hornung 	}
21132fe4284SNolan Lum 
21232fe4284SNolan Lum 	enumerate = udev_enumerate_new(ctx);
21332fe4284SNolan Lum 	if (enumerate == NULL)
21432fe4284SNolan Lum 		err(EX_UNAVAILABLE, "udev_enumerate_new");
21532fe4284SNolan Lum 
21614861de4SSascha Wildner 	parse_args(argc, argv, enumerate);
21732fe4284SNolan Lum 
218*1de39603SMatthew Dillon 	/*
219*1de39603SMatthew Dillon 	 * Don't lose any races, start monitor before scanning devices.
220*1de39603SMatthew Dillon 	 */
221*1de39603SMatthew Dillon 	if (MonitorOpt) {
222*1de39603SMatthew Dillon 		mon = udev_monitor_new(ctx);
223*1de39603SMatthew Dillon 		udev_monitor_enable_receiving(mon);
224*1de39603SMatthew Dillon 	} else {
225*1de39603SMatthew Dillon 		mon = NULL;
226*1de39603SMatthew Dillon 	}
227*1de39603SMatthew Dillon 
22832fe4284SNolan Lum 	ret = udev_enumerate_scan_devices(enumerate);
22932fe4284SNolan Lum 	if (ret != 0)
23014861de4SSascha Wildner 		err(EX_UNAVAILABLE, "udev_enumerate_scan_devices ret = %d",
23114861de4SSascha Wildner 		    ret);
23232fe4284SNolan Lum 
23332fe4284SNolan Lum 	current = udev_enumerate_get_list_entry(enumerate);
23432fe4284SNolan Lum 	if (current == NULL) {
23532fe4284SNolan Lum 		printf("No devices found.\n");
23632fe4284SNolan Lum 	} else {
23732fe4284SNolan Lum 		udev_list_entry_foreach(current, current) {
23832fe4284SNolan Lum 			dev = udev_list_entry_get_device(current);
23932fe4284SNolan Lum 			if (dev == NULL)
24032fe4284SNolan Lum 				continue;
24132fe4284SNolan Lum 			dict = udev_device_get_dictionary(dev);
24232fe4284SNolan Lum 			if (dict == NULL)
24332fe4284SNolan Lum 				continue;
24432fe4284SNolan Lum 			iter = prop_dictionary_iterator(dict);
24532fe4284SNolan Lum 			cur_key = NULL;
24632fe4284SNolan Lum 
24732fe4284SNolan Lum 			dev_name = prop_string_cstring(prop_dictionary_get(dict, "name"));
24832fe4284SNolan Lum 			printf("Device %s:\n", dev_name);
24932fe4284SNolan Lum 			free(dev_name);
25032fe4284SNolan Lum 
25132fe4284SNolan Lum 			if (!SLIST_EMPTY(&props)) {
25232fe4284SNolan Lum 				SLIST_FOREACH(ent, &props, entries) {
25314861de4SSascha Wildner 					key_val = prop_dictionary_get(dict,
25414861de4SSascha Wildner 					    ent->val);
25532fe4284SNolan Lum 					if (key_val != NULL)
25632fe4284SNolan Lum 						print_prop(ent->val, key_val);
25732fe4284SNolan Lum 				}
25832fe4284SNolan Lum 			} else {
25932fe4284SNolan Lum 				while ((cur_key = (prop_dictionary_keysym_t)prop_object_iterator_next(iter)) != NULL) {
26032fe4284SNolan Lum 					key_str = prop_dictionary_keysym_cstring_nocopy(cur_key);
26114861de4SSascha Wildner 					key_val = prop_dictionary_get_keysym(dict,
26214861de4SSascha Wildner 					    cur_key);
26332fe4284SNolan Lum 					print_prop(key_str, key_val);
26432fe4284SNolan Lum 				}
26532fe4284SNolan Lum 			}
26632fe4284SNolan Lum 
26732fe4284SNolan Lum 			printf("\n");
26832fe4284SNolan Lum 		}
26932fe4284SNolan Lum 	}
27032fe4284SNolan Lum 
27132fe4284SNolan Lum 	udev_enumerate_unref(enumerate);
272*1de39603SMatthew Dillon 
273*1de39603SMatthew Dillon 	if (mon) {
274*1de39603SMatthew Dillon 		while ((dev = udev_monitor_receive_device(mon)) != NULL) {
275*1de39603SMatthew Dillon 			dict = udev_device_get_dictionary(dev);
276*1de39603SMatthew Dillon 			if (dict == NULL)
277*1de39603SMatthew Dillon 				continue;
278*1de39603SMatthew Dillon 			iter = prop_dictionary_iterator(dict);
279*1de39603SMatthew Dillon 			cur_key =NULL;
280*1de39603SMatthew Dillon 
281*1de39603SMatthew Dillon 			dev_name = prop_string_cstring(prop_dictionary_get(dict, "name"));
282*1de39603SMatthew Dillon 			printf("Device %s:\n", dev_name);
283*1de39603SMatthew Dillon 			free(dev_name);
284*1de39603SMatthew Dillon 
285*1de39603SMatthew Dillon 			if (!SLIST_EMPTY(&props)) {
286*1de39603SMatthew Dillon 				SLIST_FOREACH(ent, &props, entries) {
287*1de39603SMatthew Dillon 					key_val = prop_dictionary_get(dict,
288*1de39603SMatthew Dillon 					    ent->val);
289*1de39603SMatthew Dillon 					if (key_val != NULL)
290*1de39603SMatthew Dillon 						print_prop(ent->val, key_val);
291*1de39603SMatthew Dillon 				}
292*1de39603SMatthew Dillon 			} else {
293*1de39603SMatthew Dillon 				while ((cur_key = (prop_dictionary_keysym_t)prop_object_iterator_next(iter)) != NULL) {
294*1de39603SMatthew Dillon 					key_str = prop_dictionary_keysym_cstring_nocopy(cur_key);
295*1de39603SMatthew Dillon 					key_val = prop_dictionary_get_keysym(dict,
296*1de39603SMatthew Dillon 					    cur_key);
297*1de39603SMatthew Dillon 					print_prop(key_str, key_val);
298*1de39603SMatthew Dillon 				}
299*1de39603SMatthew Dillon 			}
300*1de39603SMatthew Dillon 
301*1de39603SMatthew Dillon 			printf("\n");
302*1de39603SMatthew Dillon 		}
303*1de39603SMatthew Dillon 		udev_monitor_unref(mon);
304*1de39603SMatthew Dillon 	}
305*1de39603SMatthew Dillon 
30632fe4284SNolan Lum 	udev_unref(ctx);
30732fe4284SNolan Lum 
30832fe4284SNolan Lum 	return (0);
30932fe4284SNolan Lum }
310