1 /* 2 * Copyright (c) 2010 3 * The DragonFly Project. All rights reserved. 4 * 5 * This code is derived from software contributed to The DragonFly Project 6 * by Nolan Lum <nol888@gmail.com> 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * 3. Neither the name of The DragonFly Project nor the names of its 19 * contributors may be used to endorse or promote products derived 20 * from this software without specific, prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/queue.h> 37 38 #include <ctype.h> 39 #include <devattr.h> 40 #include <err.h> 41 #include <inttypes.h> 42 #include <string.h> 43 #include <stdlib.h> 44 #include <stdio.h> 45 #include <sysexits.h> 46 #include <unistd.h> 47 48 static SLIST_HEAD(, sl_entry) props = SLIST_HEAD_INITIALIZER(props); 49 struct sl_entry { 50 char *val; 51 SLIST_ENTRY(sl_entry) entries; 52 } *ent; 53 54 static void 55 usage(const char *name) 56 { 57 fprintf(stderr, 58 "usage: %s [-Ah] [-p property] [-d device] [-m key:value] [-r key:value]\n" 59 "Valid options are:\n" 60 " -A\n" 61 " Don't display aliases.\n" 62 " -h\n" 63 " Print this help message.\n\n" 64 "Valid options with their arguments are:\n" 65 " -p <property>\n" 66 " Only display property; can be specified multiple times and\n" 67 " combined with all other options.\n" 68 " -d <device>\n" 69 " Only display devices with name `device'. When used with\n" 70 " -p, only properties `-p' of device `-d' are listed. Can be\n" 71 " specified multiple times. Allows wildcards.\n" 72 " -m <key:value>\n" 73 " Only display devices whose property `key' matches with wildcards\n" 74 " value `value' unless the key-value pair starts with ~, in which\n" 75 " case the match is inverted. Stacks with -p, -d, and -m.\n" 76 " Can be specified multiple times.\n" 77 " -r <key:value>\n" 78 " Behaves similarly to `-m', but matches with regex.\n", 79 name); 80 exit(EX_USAGE); 81 } 82 83 static void 84 parse_args(int argc, char *argv[], struct udev_enumerate *enumerate) 85 { 86 int ch, invert; 87 char *colon; 88 89 SLIST_INIT(&props); 90 91 /* A = no aliases */ 92 /* p = properties to list (defaults to all) */ 93 /* d = devices to list (defaults to all) */ 94 /* m = display only devices in d that match these prop values */ 95 /* r = display only devices in d that match these prop values (regex) */ 96 while ((ch = getopt(argc, argv, "Ap:d:m:r:h")) != -1) { 97 invert = false; 98 99 switch (ch) { 100 case 'A': 101 udev_enumerate_add_match_property(enumerate, "alias", 102 "0"); 103 break; 104 case 'p': 105 ent = malloc(sizeof(struct sl_entry)); 106 ent->val = optarg; 107 SLIST_INSERT_HEAD(&props, ent, entries); 108 break; 109 case 'd': 110 udev_enumerate_add_match_expr(enumerate, "name", 111 optarg); 112 break; 113 case 'm': 114 case 'r': 115 /* Check for exclusion. */ 116 invert = *optarg == '~'; 117 118 /* Split into key/value. */ 119 colon = strchr(optarg, ':'); 120 if (colon == NULL) { 121 fprintf(stderr, 122 "Invalid property key/value pair `%s'.\n", 123 optarg); 124 return; 125 } 126 127 *colon = '\0'; 128 if (invert) { 129 if (ch == 'r') 130 udev_enumerate_add_nomatch_regex(enumerate, 131 optarg + 1, colon + 1); 132 else 133 udev_enumerate_add_nomatch_expr(enumerate, 134 optarg + 1, colon + 1); 135 } else { 136 if (ch == 'r') 137 udev_enumerate_add_match_regex(enumerate, 138 optarg, colon + 1); 139 else 140 udev_enumerate_add_match_expr(enumerate, 141 optarg, colon + 1); 142 } 143 break; 144 case 'h': 145 default: 146 usage(argv[0]); 147 } 148 } 149 return; 150 } 151 152 static void 153 print_prop(const char* key, prop_object_t value) 154 { 155 char *val_str; 156 157 printf("\t%s = ", key); 158 159 prop_type_t val_type = prop_object_type(value); 160 switch (val_type) { 161 case PROP_TYPE_BOOL: 162 printf("%s\n", prop_bool_true((prop_bool_t)value) ? 163 "true" : "false"); 164 break; 165 case PROP_TYPE_NUMBER: 166 if (prop_number_unsigned((prop_number_t)value)) 167 printf("%1$"PRIu64" (0x%1$"PRIx64")\n", 168 prop_number_unsigned_integer_value((prop_number_t)value)); 169 else 170 printf("%"PRId64"\n", 171 prop_number_integer_value((prop_number_t)value)); 172 break; 173 case PROP_TYPE_STRING: 174 val_str = prop_string_cstring(value); 175 printf("%s\n", val_str); 176 free(val_str); 177 break; 178 default: 179 break; 180 } 181 } 182 183 int 184 main(int argc, char* argv[]) 185 { 186 struct udev *ctx; 187 struct udev_enumerate *enumerate; 188 struct udev_list_entry *current; 189 struct udev_device *dev; 190 prop_object_t key_val; 191 prop_dictionary_t dict; 192 prop_dictionary_keysym_t cur_key; 193 prop_object_iterator_t iter; 194 const char *key_str; 195 char *dev_name; 196 int ret; 197 198 ctx = udev_new(); 199 if (ctx == NULL) 200 err(EX_UNAVAILABLE, "udev_new"); 201 202 enumerate = udev_enumerate_new(ctx); 203 if (enumerate == NULL) 204 err(EX_UNAVAILABLE, "udev_enumerate_new"); 205 206 parse_args(argc, argv, enumerate); 207 208 ret = udev_enumerate_scan_devices(enumerate); 209 if (ret != 0) 210 err(EX_UNAVAILABLE, "udev_enumerate_scan_devices ret = %d", 211 ret); 212 213 current = udev_enumerate_get_list_entry(enumerate); 214 if (current == NULL) { 215 printf("No devices found.\n"); 216 } else { 217 udev_list_entry_foreach(current, current) { 218 dev = udev_list_entry_get_device(current); 219 if (dev == NULL) 220 continue; 221 dict = udev_device_get_dictionary(dev); 222 if (dict == NULL) 223 continue; 224 iter = prop_dictionary_iterator(dict); 225 cur_key = NULL; 226 227 dev_name = prop_string_cstring(prop_dictionary_get(dict, "name")); 228 printf("Device %s:\n", dev_name); 229 free(dev_name); 230 231 if (!SLIST_EMPTY(&props)) { 232 SLIST_FOREACH(ent, &props, entries) { 233 key_val = prop_dictionary_get(dict, 234 ent->val); 235 if (key_val != NULL) 236 print_prop(ent->val, key_val); 237 } 238 } else { 239 while ((cur_key = (prop_dictionary_keysym_t)prop_object_iterator_next(iter)) != NULL) { 240 key_str = prop_dictionary_keysym_cstring_nocopy(cur_key); 241 key_val = prop_dictionary_get_keysym(dict, 242 cur_key); 243 print_prop(key_str, key_val); 244 } 245 } 246 247 printf("\n"); 248 } 249 } 250 251 udev_enumerate_unref(enumerate); 252 udev_unref(ctx); 253 254 return (0); 255 } 256