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 int MonitorOpt; 55 56 static void 57 usage(const char *name) 58 { 59 fprintf(stderr, 60 "usage: %s [-Ah] [-p property] [-d device] [-m key:value] [-r key:value]\n" 61 "Valid options are:\n" 62 " -A\n" 63 " Don't display aliases.\n" 64 " -h\n" 65 " Print this help message.\n\n" 66 " -M\n" 67 " Continue monitoring after initial scan.\n\n" 68 "Valid options with their arguments are:\n" 69 " -p <property>\n" 70 " Only display property; can be specified multiple times and\n" 71 " combined with all other options.\n" 72 " -d <device>\n" 73 " Only display devices with name `device'. When used with\n" 74 " -p, only properties `-p' of device `-d' are listed. Can be\n" 75 " specified multiple times. Allows wildcards.\n" 76 " -m <key:value>\n" 77 " Only display devices whose property `key' matches with wildcards\n" 78 " value `value' unless the key-value pair starts with ~, in which\n" 79 " case the match is inverted. Stacks with -p, -d, and -m.\n" 80 " Can be specified multiple times.\n" 81 " -r <key:value>\n" 82 " Behaves similarly to `-m', but matches with regex.\n", 83 name); 84 exit(EX_USAGE); 85 } 86 87 static void 88 parse_args(int argc, char *argv[], struct udev_enumerate *enumerate) 89 { 90 int ch, invert; 91 char *colon; 92 93 SLIST_INIT(&props); 94 95 /* A = no aliases */ 96 /* p = properties to list (defaults to all) */ 97 /* d = devices to list (defaults to all) */ 98 /* m = display only devices in d that match these prop values */ 99 /* r = display only devices in d that match these prop values (regex) */ 100 while ((ch = getopt(argc, argv, "AMp:d:m:r:h")) != -1) { 101 invert = false; 102 103 switch (ch) { 104 case 'A': 105 udev_enumerate_add_match_property(enumerate, "alias", 106 "0"); 107 break; 108 case 'p': 109 ent = malloc(sizeof(struct sl_entry)); 110 ent->val = optarg; 111 SLIST_INSERT_HEAD(&props, ent, entries); 112 break; 113 case 'M': 114 MonitorOpt = 1; 115 break; 116 case 'd': 117 udev_enumerate_add_match_expr(enumerate, "name", 118 optarg); 119 break; 120 case 'm': 121 case 'r': 122 /* Check for exclusion. */ 123 invert = *optarg == '~'; 124 125 /* Split into key/value. */ 126 colon = strchr(optarg, ':'); 127 if (colon == NULL) { 128 fprintf(stderr, 129 "Invalid property key/value pair `%s'.\n", 130 optarg); 131 return; 132 } 133 134 *colon = '\0'; 135 if (invert) { 136 if (ch == 'r') 137 udev_enumerate_add_nomatch_regex(enumerate, 138 optarg + 1, colon + 1); 139 else 140 udev_enumerate_add_nomatch_expr(enumerate, 141 optarg + 1, colon + 1); 142 } else { 143 if (ch == 'r') 144 udev_enumerate_add_match_regex(enumerate, 145 optarg, colon + 1); 146 else 147 udev_enumerate_add_match_expr(enumerate, 148 optarg, colon + 1); 149 } 150 break; 151 case 'h': 152 default: 153 usage(argv[0]); 154 } 155 } 156 return; 157 } 158 159 static void 160 print_prop(const char* key, prop_object_t value) 161 { 162 char *val_str; 163 164 printf("\t%s = ", key); 165 166 prop_type_t val_type = prop_object_type(value); 167 switch (val_type) { 168 case PROP_TYPE_BOOL: 169 printf("%s\n", prop_bool_true((prop_bool_t)value) ? 170 "true" : "false"); 171 break; 172 case PROP_TYPE_NUMBER: 173 if (prop_number_unsigned((prop_number_t)value)) 174 printf("%1$"PRIu64" (0x%1$"PRIx64")\n", 175 prop_number_unsigned_integer_value((prop_number_t)value)); 176 else 177 printf("%"PRId64"\n", 178 prop_number_integer_value((prop_number_t)value)); 179 break; 180 case PROP_TYPE_STRING: 181 val_str = prop_string_cstring(value); 182 printf("%s\n", val_str); 183 free(val_str); 184 break; 185 default: 186 break; 187 } 188 } 189 190 int 191 main(int argc, char* argv[]) 192 { 193 struct udev *ctx; 194 struct udev_enumerate *enumerate; 195 struct udev_monitor *mon; 196 struct udev_list_entry *current; 197 struct udev_device *dev; 198 prop_object_t key_val; 199 prop_dictionary_t dict; 200 prop_dictionary_keysym_t cur_key; 201 prop_object_iterator_t iter; 202 const char *key_str; 203 char *dev_name; 204 int ret; 205 206 ctx = udev_new(); 207 if (ctx == NULL) { 208 fprintf(stderr, "Make sure udevd is running\n"); 209 err(EX_UNAVAILABLE, "udev_new"); 210 } 211 212 enumerate = udev_enumerate_new(ctx); 213 if (enumerate == NULL) 214 err(EX_UNAVAILABLE, "udev_enumerate_new"); 215 216 parse_args(argc, argv, enumerate); 217 218 /* 219 * Don't lose any races, start monitor before scanning devices. 220 */ 221 if (MonitorOpt) { 222 mon = udev_monitor_new(ctx); 223 udev_monitor_enable_receiving(mon); 224 } else { 225 mon = NULL; 226 } 227 228 ret = udev_enumerate_scan_devices(enumerate); 229 if (ret != 0) 230 err(EX_UNAVAILABLE, "udev_enumerate_scan_devices ret = %d", 231 ret); 232 233 current = udev_enumerate_get_list_entry(enumerate); 234 if (current == NULL) { 235 printf("No devices found.\n"); 236 } else { 237 udev_list_entry_foreach(current, current) { 238 dev = udev_list_entry_get_device(current); 239 if (dev == NULL) 240 continue; 241 dict = udev_device_get_dictionary(dev); 242 if (dict == NULL) 243 continue; 244 iter = prop_dictionary_iterator(dict); 245 cur_key = NULL; 246 247 dev_name = prop_string_cstring(prop_dictionary_get(dict, "name")); 248 printf("Device %s:\n", dev_name); 249 free(dev_name); 250 251 if (!SLIST_EMPTY(&props)) { 252 SLIST_FOREACH(ent, &props, entries) { 253 key_val = prop_dictionary_get(dict, 254 ent->val); 255 if (key_val != NULL) 256 print_prop(ent->val, key_val); 257 } 258 } else { 259 while ((cur_key = (prop_dictionary_keysym_t)prop_object_iterator_next(iter)) != NULL) { 260 key_str = prop_dictionary_keysym_cstring_nocopy(cur_key); 261 key_val = prop_dictionary_get_keysym(dict, 262 cur_key); 263 print_prop(key_str, key_val); 264 } 265 } 266 267 printf("\n"); 268 } 269 } 270 271 udev_enumerate_unref(enumerate); 272 273 if (mon) { 274 while ((dev = udev_monitor_receive_device(mon)) != NULL) { 275 dict = udev_device_get_dictionary(dev); 276 if (dict == NULL) 277 continue; 278 iter = prop_dictionary_iterator(dict); 279 cur_key =NULL; 280 281 dev_name = prop_string_cstring(prop_dictionary_get(dict, "name")); 282 printf("Device %s:\n", dev_name); 283 free(dev_name); 284 285 if (!SLIST_EMPTY(&props)) { 286 SLIST_FOREACH(ent, &props, entries) { 287 key_val = prop_dictionary_get(dict, 288 ent->val); 289 if (key_val != NULL) 290 print_prop(ent->val, key_val); 291 } 292 } else { 293 while ((cur_key = (prop_dictionary_keysym_t)prop_object_iterator_next(iter)) != NULL) { 294 key_str = prop_dictionary_keysym_cstring_nocopy(cur_key); 295 key_val = prop_dictionary_get_keysym(dict, 296 cur_key); 297 print_prop(key_str, key_val); 298 } 299 } 300 301 printf("\n"); 302 } 303 udev_monitor_unref(mon); 304 } 305 306 udev_unref(ctx); 307 308 return (0); 309 } 310