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