xref: /dflybsd-src/sbin/devattr/devattr.c (revision 14861de460d75c515ce6357d281a5a8e74ac6be4)
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 
5432fe4284SNolan Lum static void
55*14861de4SSascha Wildner usage(const char *name)
56*14861de4SSascha Wildner {
57*14861de4SSascha Wildner 	fprintf(stderr,
58*14861de4SSascha Wildner 	    "usage: %s [-Ah] [-p property] [-d device] [-m key:value] [-r key:value]\n"
5932fe4284SNolan Lum 	    "Valid options are:\n"
6032fe4284SNolan Lum 	    " -A\n"
6132fe4284SNolan Lum 	    "	Don't display aliases.\n"
6232fe4284SNolan Lum 	    " -h\n"
6332fe4284SNolan Lum 	    "	Print this help message.\n\n"
6432fe4284SNolan Lum 	    "Valid options with their arguments are:\n"
6532fe4284SNolan Lum 	    " -p <property>\n"
6632fe4284SNolan Lum 	    "	Only display property; can be specified multiple times and\n"
6732fe4284SNolan Lum 	    "	combined with all other options.\n"
6832fe4284SNolan Lum 	    " -d <device>\n"
6932fe4284SNolan Lum 	    "	Only display devices with name `device'. When used with\n"
7032fe4284SNolan Lum 	    "	-p, only properties `-p' of device `-d' are listed. Can be\n"
7132fe4284SNolan Lum 	    "	specified multiple times. Allows wildcards.\n"
7232fe4284SNolan Lum 	    " -m <key:value>\n"
7332fe4284SNolan Lum 	    "	Only display devices whose property `key' matches with wildcards\n"
7432fe4284SNolan Lum 	    "	value `value' unless the key-value pair starts with ~, in which\n"
7532fe4284SNolan Lum 	    "	case the match is inverted. Stacks with -p, -d, and -m.\n"
7632fe4284SNolan Lum 	    "	Can be specified multiple times.\n"
7732fe4284SNolan Lum 	    " -r <key:value>\n"
78*14861de4SSascha Wildner 	    "	Behaves similarly to `-m', but matches with regex.\n",
79*14861de4SSascha Wildner 	    name);
80*14861de4SSascha Wildner 	exit(EX_USAGE);
8132fe4284SNolan Lum }
8232fe4284SNolan Lum 
83*14861de4SSascha Wildner static void
84*14861de4SSascha Wildner parse_args(int argc, char *argv[], struct udev_enumerate *enumerate)
85*14861de4SSascha Wildner {
8632fe4284SNolan Lum 	int ch, invert;
8732fe4284SNolan Lum 	char *colon;
8832fe4284SNolan Lum 
8932fe4284SNolan Lum 	SLIST_INIT(&props);
9032fe4284SNolan Lum 
9132fe4284SNolan Lum 	/* A = no aliases */
9232fe4284SNolan Lum 	/* p = properties to list (defaults to all) */
9332fe4284SNolan Lum 	/* d = devices to list (defaults to all) */
9432fe4284SNolan Lum 	/* m = display only devices in d that match these prop values */
9532fe4284SNolan Lum 	/* r = display only devices in d that match these prop values (regex) */
9632fe4284SNolan Lum 	while ((ch = getopt(argc, argv, "Ap:d:m:r:h")) != -1) {
9732fe4284SNolan Lum 		invert = false;
9832fe4284SNolan Lum 
9932fe4284SNolan Lum 		switch (ch) {
10032fe4284SNolan Lum 		case 'A':
101*14861de4SSascha Wildner 			udev_enumerate_add_match_property(enumerate, "alias",
102*14861de4SSascha Wildner 			    "0");
10332fe4284SNolan Lum 			break;
10432fe4284SNolan Lum 		case 'p':
10532fe4284SNolan Lum 			ent = malloc(sizeof(struct sl_entry));
10632fe4284SNolan Lum 			ent->val = optarg;
10732fe4284SNolan Lum 			SLIST_INSERT_HEAD(&props, ent, entries);
10832fe4284SNolan Lum 			break;
10932fe4284SNolan Lum 		case 'd':
110*14861de4SSascha Wildner 			udev_enumerate_add_match_expr(enumerate, "name",
111*14861de4SSascha Wildner 			    optarg);
11232fe4284SNolan Lum 			break;
11332fe4284SNolan Lum 		case 'm':
11432fe4284SNolan Lum 		case 'r':
11532fe4284SNolan Lum 			/* Check for exclusion. */
11632fe4284SNolan Lum 			invert = *optarg == '~';
11732fe4284SNolan Lum 
11832fe4284SNolan Lum 			/* Split into key/value. */
11932fe4284SNolan Lum 			colon = strchr(optarg, ':');
12032fe4284SNolan Lum 			if (colon == NULL) {
12132fe4284SNolan Lum 				fprintf(stderr,
12232fe4284SNolan Lum 				    "Invalid property key/value pair `%s'.\n",
12332fe4284SNolan Lum 				    optarg);
124*14861de4SSascha Wildner 				return;
12532fe4284SNolan Lum 			}
12632fe4284SNolan Lum 
12732fe4284SNolan Lum 			*colon = '\0';
12832fe4284SNolan Lum 			if (invert) {
12932fe4284SNolan Lum 				if (ch == 'r')
13032fe4284SNolan Lum 					udev_enumerate_add_nomatch_regex(enumerate,
13132fe4284SNolan Lum 					    optarg + 1, colon + 1);
13232fe4284SNolan Lum 				else
13332fe4284SNolan Lum 					udev_enumerate_add_nomatch_expr(enumerate,
13432fe4284SNolan Lum 					    optarg + 1, colon + 1);
13532fe4284SNolan Lum 			} else {
13632fe4284SNolan Lum 				if (ch == 'r')
13732fe4284SNolan Lum 					udev_enumerate_add_match_regex(enumerate,
13832fe4284SNolan Lum 					    optarg, colon + 1);
13932fe4284SNolan Lum 				else
14032fe4284SNolan Lum 					udev_enumerate_add_match_expr(enumerate,
14132fe4284SNolan Lum 					    optarg, colon + 1);
14232fe4284SNolan Lum 			}
14332fe4284SNolan Lum 			break;
14432fe4284SNolan Lum 		case 'h':
145*14861de4SSascha Wildner 		default:
14632fe4284SNolan Lum 			usage(argv[0]);
14732fe4284SNolan Lum 		}
14832fe4284SNolan Lum 	}
149*14861de4SSascha Wildner 	return;
15032fe4284SNolan Lum }
15132fe4284SNolan Lum 
15232fe4284SNolan Lum static void
153*14861de4SSascha Wildner print_prop(const char* key, prop_object_t value)
154*14861de4SSascha Wildner {
15532fe4284SNolan Lum 	char *val_str;
15632fe4284SNolan Lum 
15732fe4284SNolan Lum 	printf("\t%s = ", key);
15832fe4284SNolan Lum 
15932fe4284SNolan Lum 	prop_type_t val_type = prop_object_type(value);
16032fe4284SNolan Lum 	switch (val_type) {
16132fe4284SNolan Lum 	case PROP_TYPE_BOOL:
162*14861de4SSascha Wildner 		printf("%s\n", prop_bool_true((prop_bool_t)value) ?
163*14861de4SSascha Wildner 		    "true" : "false");
16432fe4284SNolan Lum 		break;
16532fe4284SNolan Lum 	case PROP_TYPE_NUMBER:
16632fe4284SNolan Lum 		if (prop_number_unsigned((prop_number_t)value))
16732fe4284SNolan Lum 			printf("%1$"PRIu64" (0x%1$"PRIx64")\n",
16832fe4284SNolan Lum 			    prop_number_unsigned_integer_value((prop_number_t)value));
16932fe4284SNolan Lum 		else
17032fe4284SNolan Lum 			printf("%"PRId64"\n",
17132fe4284SNolan Lum 			    prop_number_integer_value((prop_number_t)value));
17232fe4284SNolan Lum 		break;
17332fe4284SNolan Lum 	case PROP_TYPE_STRING:
17432fe4284SNolan Lum 		val_str = prop_string_cstring(value);
17532fe4284SNolan Lum 		printf("%s\n", val_str);
17632fe4284SNolan Lum 		free(val_str);
17732fe4284SNolan Lum 		break;
17832fe4284SNolan Lum 	default:
17932fe4284SNolan Lum 		break;
18032fe4284SNolan Lum 	}
18132fe4284SNolan Lum }
18232fe4284SNolan Lum 
18332fe4284SNolan Lum int
184*14861de4SSascha Wildner main(int argc, char* argv[])
185*14861de4SSascha Wildner {
18632fe4284SNolan Lum 	struct udev *ctx;
18732fe4284SNolan Lum 	struct udev_enumerate *enumerate;
18832fe4284SNolan Lum 	struct udev_list_entry *current;
18932fe4284SNolan Lum 	struct udev_device *dev;
19032fe4284SNolan Lum 	prop_object_t key_val;
19132fe4284SNolan Lum 	prop_dictionary_t dict;
19232fe4284SNolan Lum 	prop_dictionary_keysym_t cur_key;
19332fe4284SNolan Lum 	prop_object_iterator_t iter;
19432fe4284SNolan Lum 	const char *key_str;
19532fe4284SNolan Lum 	char *dev_name;
19632fe4284SNolan Lum 	int ret;
19732fe4284SNolan Lum 
19832fe4284SNolan Lum 	ctx = udev_new();
19932fe4284SNolan Lum 	if (ctx == NULL)
20032fe4284SNolan Lum 		err(EX_UNAVAILABLE, "udev_new");
20132fe4284SNolan Lum 
20232fe4284SNolan Lum 	enumerate = udev_enumerate_new(ctx);
20332fe4284SNolan Lum 	if (enumerate == NULL)
20432fe4284SNolan Lum 		err(EX_UNAVAILABLE, "udev_enumerate_new");
20532fe4284SNolan Lum 
206*14861de4SSascha Wildner 	parse_args(argc, argv, enumerate);
20732fe4284SNolan Lum 
20832fe4284SNolan Lum 	ret = udev_enumerate_scan_devices(enumerate);
20932fe4284SNolan Lum 	if (ret != 0)
210*14861de4SSascha Wildner 		err(EX_UNAVAILABLE, "udev_enumerate_scan_devices ret = %d",
211*14861de4SSascha Wildner 		    ret);
21232fe4284SNolan Lum 
21332fe4284SNolan Lum 	current = udev_enumerate_get_list_entry(enumerate);
21432fe4284SNolan Lum 	if (current == NULL) {
21532fe4284SNolan Lum 		printf("No devices found.\n");
21632fe4284SNolan Lum 	} else {
21732fe4284SNolan Lum 		udev_list_entry_foreach(current, current) {
21832fe4284SNolan Lum 			dev = udev_list_entry_get_device(current);
21932fe4284SNolan Lum 			if (dev == NULL)
22032fe4284SNolan Lum 				continue;
22132fe4284SNolan Lum 			dict = udev_device_get_dictionary(dev);
22232fe4284SNolan Lum 			if (dict == NULL)
22332fe4284SNolan Lum 				continue;
22432fe4284SNolan Lum 			iter = prop_dictionary_iterator(dict);
22532fe4284SNolan Lum 			cur_key = NULL;
22632fe4284SNolan Lum 
22732fe4284SNolan Lum 			dev_name = prop_string_cstring(prop_dictionary_get(dict, "name"));
22832fe4284SNolan Lum 			printf("Device %s:\n", dev_name);
22932fe4284SNolan Lum 			free(dev_name);
23032fe4284SNolan Lum 
23132fe4284SNolan Lum 			if (!SLIST_EMPTY(&props)) {
23232fe4284SNolan Lum 				SLIST_FOREACH(ent, &props, entries) {
233*14861de4SSascha Wildner 					key_val = prop_dictionary_get(dict,
234*14861de4SSascha Wildner 					    ent->val);
23532fe4284SNolan Lum 					if (key_val != NULL)
23632fe4284SNolan Lum 						print_prop(ent->val, key_val);
23732fe4284SNolan Lum 				}
23832fe4284SNolan Lum 			} else {
23932fe4284SNolan Lum 				while ((cur_key = (prop_dictionary_keysym_t)prop_object_iterator_next(iter)) != NULL) {
24032fe4284SNolan Lum 					key_str = prop_dictionary_keysym_cstring_nocopy(cur_key);
241*14861de4SSascha Wildner 					key_val = prop_dictionary_get_keysym(dict,
242*14861de4SSascha Wildner 					    cur_key);
24332fe4284SNolan Lum 					print_prop(key_str, key_val);
24432fe4284SNolan Lum 				}
24532fe4284SNolan Lum 			}
24632fe4284SNolan Lum 
24732fe4284SNolan Lum 			printf("\n");
24832fe4284SNolan Lum 		}
24932fe4284SNolan Lum 	}
25032fe4284SNolan Lum 
25132fe4284SNolan Lum 	udev_enumerate_unref(enumerate);
25232fe4284SNolan Lum 	udev_unref(ctx);
25332fe4284SNolan Lum 
25432fe4284SNolan Lum 	return (0);
25532fe4284SNolan Lum }
256