1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ 2/*** 3 This file is part of systemd. 4 5 Copyright 2008-2012 Kay Sievers <kay@vrfy.org> 6 7 systemd is free software; you can redistribute it and/or modify it 8 under the terms of the GNU Lesser General Public License as published by 9 the Free Software Foundation; either version 2.1 of the License, or 10 (at your option) any later version. 11 12 systemd is distributed in the hope that it will be useful, but 13 WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 Lesser General Public License for more details. 16 17 You should have received a copy of the GNU Lesser General Public License 18 along with systemd; If not, see <http://www.gnu.org/licenses/>. 19***/ 20 21#include <stdio.h> 22#include <stdarg.h> 23#include <stdlib.h> 24#include <unistd.h> 25#include <errno.h> 26#include <string.h> 27#include <getopt.h> 28#include <fcntl.h> 29#include <sys/epoll.h> 30#include <sys/sysmacros.h> 31 32#include "libudev.h" 33#include "udev-util.h" 34#include "util.h" 35 36#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 37 38static void print_device(struct udev_device *device) { 39 const char *str; 40 dev_t devnum; 41 int count; 42 struct udev_list_entry *list_entry; 43 44 printf("*** device: %p ***\n", device); 45 str = udev_device_get_action(device); 46 if (str != NULL) 47 printf("action: '%s'\n", str); 48 49 str = udev_device_get_syspath(device); 50 printf("syspath: '%s'\n", str); 51 52 str = udev_device_get_sysname(device); 53 printf("sysname: '%s'\n", str); 54 55 str = udev_device_get_sysnum(device); 56 if (str != NULL) 57 printf("sysnum: '%s'\n", str); 58 59 str = udev_device_get_devpath(device); 60 printf("devpath: '%s'\n", str); 61 62 str = udev_device_get_subsystem(device); 63 if (str != NULL) 64 printf("subsystem: '%s'\n", str); 65 66 str = udev_device_get_devtype(device); 67 if (str != NULL) 68 printf("devtype: '%s'\n", str); 69 70 str = udev_device_get_driver(device); 71 if (str != NULL) 72 printf("driver: '%s'\n", str); 73 74 str = udev_device_get_devnode(device); 75 if (str != NULL) 76 printf("devname: '%s'\n", str); 77 78 devnum = udev_device_get_devnum(device); 79 if (major(devnum) > 0) 80 printf("devnum: %u:%u\n", major(devnum), minor(devnum)); 81 82 count = 0; 83 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) { 84 printf("link: '%s'\n", udev_list_entry_get_name(list_entry)); 85 count++; 86 } 87 if (count > 0) 88 printf("found %i links\n", count); 89 90 count = 0; 91 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device)) { 92 printf("property: '%s=%s'\n", 93 udev_list_entry_get_name(list_entry), 94 udev_list_entry_get_value(list_entry)); 95 count++; 96 } 97 if (count > 0) 98 printf("found %i properties\n", count); 99 100 str = udev_device_get_property_value(device, "MAJOR"); 101 if (str != NULL) 102 printf("MAJOR: '%s'\n", str); 103 104 str = udev_device_get_sysattr_value(device, "dev"); 105 if (str != NULL) 106 printf("attr{dev}: '%s'\n", str); 107 108 printf("\n"); 109} 110 111static int test_device(struct udev *udev, const char *syspath) { 112 _cleanup_udev_device_unref_ struct udev_device *device; 113 114 printf("looking at device: %s\n", syspath); 115 device = udev_device_new_from_syspath(udev, syspath); 116 if (device == NULL) { 117 printf("no device found\n"); 118 return -1; 119 } 120 print_device(device); 121 122 return 0; 123} 124 125static int test_device_parents(struct udev *udev, const char *syspath) { 126 _cleanup_udev_device_unref_ struct udev_device *device; 127 struct udev_device *device_parent; 128 129 printf("looking at device: %s\n", syspath); 130 device = udev_device_new_from_syspath(udev, syspath); 131 if (device == NULL) 132 return -1; 133 134 printf("looking at parents\n"); 135 device_parent = device; 136 do { 137 print_device(device_parent); 138 device_parent = udev_device_get_parent(device_parent); 139 } while (device_parent != NULL); 140 141 printf("looking at parents again\n"); 142 device_parent = device; 143 do { 144 print_device(device_parent); 145 device_parent = udev_device_get_parent(device_parent); 146 } while (device_parent != NULL); 147 148 return 0; 149} 150 151static int test_device_devnum(struct udev *udev) { 152 dev_t devnum = makedev(1, 3); 153 struct udev_device *device; 154 155 printf("looking up device: %u:%u\n", major(devnum), minor(devnum)); 156 device = udev_device_new_from_devnum(udev, 'c', devnum); 157 if (device == NULL) 158 return -1; 159 print_device(device); 160 udev_device_unref(device); 161 return 0; 162} 163 164static int test_device_subsys_name(struct udev *udev) { 165 struct udev_device *device; 166 167 printf("looking up device: 'block':'sda'\n"); 168 device = udev_device_new_from_subsystem_sysname(udev, "block", "sda"); 169 if (device == NULL) 170 return -1; 171 print_device(device); 172 udev_device_unref(device); 173 174 printf("looking up device: 'subsystem':'pci'\n"); 175 device = udev_device_new_from_subsystem_sysname(udev, "subsystem", "pci"); 176 if (device == NULL) 177 return -1; 178 print_device(device); 179 udev_device_unref(device); 180 181 printf("looking up device: 'drivers':'scsi:sd'\n"); 182 device = udev_device_new_from_subsystem_sysname(udev, "drivers", "scsi:sd"); 183 if (device == NULL) 184 return -1; 185 print_device(device); 186 udev_device_unref(device); 187 188 printf("looking up device: 'module':'printk'\n"); 189 device = udev_device_new_from_subsystem_sysname(udev, "module", "printk"); 190 if (device == NULL) 191 return -1; 192 print_device(device); 193 udev_device_unref(device); 194 return 0; 195} 196 197static int test_enumerate_print_list(struct udev_enumerate *enumerate) { 198 struct udev_list_entry *list_entry; 199 int count = 0; 200 201 udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(enumerate)) { 202 struct udev_device *device; 203 204 device = udev_device_new_from_syspath(udev_enumerate_get_udev(enumerate), 205 udev_list_entry_get_name(list_entry)); 206 if (device != NULL) { 207 printf("device: '%s' (%s)\n", 208 udev_device_get_syspath(device), 209 udev_device_get_subsystem(device)); 210 udev_device_unref(device); 211 count++; 212 } 213 } 214 printf("found %i devices\n\n", count); 215 return count; 216} 217 218static int test_monitor(struct udev *udev) { 219 struct udev_monitor *udev_monitor = NULL; 220 int fd_ep; 221 int fd_udev = -1; 222 struct epoll_event ep_udev, ep_stdin; 223 224 fd_ep = epoll_create1(EPOLL_CLOEXEC); 225 if (fd_ep < 0) { 226 printf("error creating epoll fd: %m\n"); 227 goto out; 228 } 229 230 udev_monitor = udev_monitor_new_from_netlink(udev, "udev"); 231 if (udev_monitor == NULL) { 232 printf("no socket\n"); 233 goto out; 234 } 235 fd_udev = udev_monitor_get_fd(udev_monitor); 236 237 if (udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "block", NULL) < 0 || 238 udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "tty", NULL) < 0 || 239 udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb", "usb_device") < 0) { 240 printf("filter failed\n"); 241 goto out; 242 } 243 244 if (udev_monitor_enable_receiving(udev_monitor) < 0) { 245 printf("bind failed\n"); 246 goto out; 247 } 248 249 memzero(&ep_udev, sizeof(struct epoll_event)); 250 ep_udev.events = EPOLLIN; 251 ep_udev.data.fd = fd_udev; 252 if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_udev, &ep_udev) < 0) { 253 printf("fail to add fd to epoll: %m\n"); 254 goto out; 255 } 256 257 memzero(&ep_stdin, sizeof(struct epoll_event)); 258 ep_stdin.events = EPOLLIN; 259 ep_stdin.data.fd = STDIN_FILENO; 260 if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, STDIN_FILENO, &ep_stdin) < 0) { 261 printf("fail to add fd to epoll: %m\n"); 262 goto out; 263 } 264 265 for (;;) { 266 int fdcount; 267 struct epoll_event ev[4]; 268 struct udev_device *device; 269 int i; 270 271 printf("waiting for events from udev, press ENTER to exit\n"); 272 fdcount = epoll_wait(fd_ep, ev, ARRAY_SIZE(ev), -1); 273 printf("epoll fd count: %i\n", fdcount); 274 275 for (i = 0; i < fdcount; i++) { 276 if (ev[i].data.fd == fd_udev && ev[i].events & EPOLLIN) { 277 device = udev_monitor_receive_device(udev_monitor); 278 if (device == NULL) { 279 printf("no device from socket\n"); 280 continue; 281 } 282 print_device(device); 283 udev_device_unref(device); 284 } else if (ev[i].data.fd == STDIN_FILENO && ev[i].events & EPOLLIN) { 285 printf("exiting loop\n"); 286 goto out; 287 } 288 } 289 } 290out: 291 if (fd_ep >= 0) 292 close(fd_ep); 293 udev_monitor_unref(udev_monitor); 294 return 0; 295} 296 297static int test_queue(struct udev *udev) { 298 struct udev_queue *udev_queue; 299 300 udev_queue = udev_queue_new(udev); 301 if (udev_queue == NULL) 302 return -1; 303 304 if (udev_queue_get_queue_is_empty(udev_queue)) 305 printf("queue is empty\n"); 306 307 udev_queue_unref(udev_queue); 308 return 0; 309} 310 311static int test_enumerate(struct udev *udev, const char *subsystem) { 312 struct udev_enumerate *udev_enumerate; 313 314 printf("enumerate '%s'\n", subsystem == NULL ? "<all>" : subsystem); 315 udev_enumerate = udev_enumerate_new(udev); 316 if (udev_enumerate == NULL) 317 return -1; 318 udev_enumerate_add_match_subsystem(udev_enumerate, subsystem); 319 udev_enumerate_scan_devices(udev_enumerate); 320 test_enumerate_print_list(udev_enumerate); 321 udev_enumerate_unref(udev_enumerate); 322 323 printf("enumerate 'net' + duplicated scan + null + zero\n"); 324 udev_enumerate = udev_enumerate_new(udev); 325 if (udev_enumerate == NULL) 326 return -1; 327 udev_enumerate_add_match_subsystem(udev_enumerate, "net"); 328 udev_enumerate_scan_devices(udev_enumerate); 329 udev_enumerate_scan_devices(udev_enumerate); 330 udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero"); 331 udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/null"); 332 udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero"); 333 udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/null"); 334 udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero"); 335 udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/null"); 336 udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/null"); 337 udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero"); 338 udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero"); 339 udev_enumerate_scan_devices(udev_enumerate); 340 test_enumerate_print_list(udev_enumerate); 341 udev_enumerate_unref(udev_enumerate); 342 343 printf("enumerate 'block'\n"); 344 udev_enumerate = udev_enumerate_new(udev); 345 if (udev_enumerate == NULL) 346 return -1; 347 udev_enumerate_add_match_subsystem(udev_enumerate,"block"); 348 udev_enumerate_add_match_is_initialized(udev_enumerate); 349 udev_enumerate_scan_devices(udev_enumerate); 350 test_enumerate_print_list(udev_enumerate); 351 udev_enumerate_unref(udev_enumerate); 352 353 printf("enumerate 'not block'\n"); 354 udev_enumerate = udev_enumerate_new(udev); 355 if (udev_enumerate == NULL) 356 return -1; 357 udev_enumerate_add_nomatch_subsystem(udev_enumerate, "block"); 358 udev_enumerate_scan_devices(udev_enumerate); 359 test_enumerate_print_list(udev_enumerate); 360 udev_enumerate_unref(udev_enumerate); 361 362 printf("enumerate 'pci, mem, vc'\n"); 363 udev_enumerate = udev_enumerate_new(udev); 364 if (udev_enumerate == NULL) 365 return -1; 366 udev_enumerate_add_match_subsystem(udev_enumerate, "pci"); 367 udev_enumerate_add_match_subsystem(udev_enumerate, "mem"); 368 udev_enumerate_add_match_subsystem(udev_enumerate, "vc"); 369 udev_enumerate_scan_devices(udev_enumerate); 370 test_enumerate_print_list(udev_enumerate); 371 udev_enumerate_unref(udev_enumerate); 372 373 printf("enumerate 'subsystem'\n"); 374 udev_enumerate = udev_enumerate_new(udev); 375 if (udev_enumerate == NULL) 376 return -1; 377 udev_enumerate_scan_subsystems(udev_enumerate); 378 test_enumerate_print_list(udev_enumerate); 379 udev_enumerate_unref(udev_enumerate); 380 381 printf("enumerate 'property IF_FS_*=filesystem'\n"); 382 udev_enumerate = udev_enumerate_new(udev); 383 if (udev_enumerate == NULL) 384 return -1; 385 udev_enumerate_add_match_property(udev_enumerate, "ID_FS*", "filesystem"); 386 udev_enumerate_scan_devices(udev_enumerate); 387 test_enumerate_print_list(udev_enumerate); 388 udev_enumerate_unref(udev_enumerate); 389 return 0; 390} 391 392static void test_hwdb(struct udev *udev, const char *modalias) { 393 struct udev_hwdb *hwdb; 394 struct udev_list_entry *entry; 395 396 hwdb = udev_hwdb_new(udev); 397 398 udev_list_entry_foreach(entry, udev_hwdb_get_properties_list_entry(hwdb, modalias, 0)) 399 printf("'%s'='%s'\n", udev_list_entry_get_name(entry), udev_list_entry_get_value(entry)); 400 printf("\n"); 401 402 hwdb = udev_hwdb_unref(hwdb); 403 assert(hwdb == NULL); 404} 405 406int main(int argc, char *argv[]) { 407 struct udev *udev = NULL; 408 static const struct option options[] = { 409 { "syspath", required_argument, NULL, 'p' }, 410 { "subsystem", required_argument, NULL, 's' }, 411 { "debug", no_argument, NULL, 'd' }, 412 { "help", no_argument, NULL, 'h' }, 413 { "version", no_argument, NULL, 'V' }, 414 {} 415 }; 416 const char *syspath = "/devices/virtual/mem/null"; 417 const char *subsystem = NULL; 418 char path[1024]; 419 int c; 420 421 udev = udev_new(); 422 printf("context: %p\n", udev); 423 if (udev == NULL) { 424 printf("no context\n"); 425 return 1; 426 } 427 428 while ((c = getopt_long(argc, argv, "p:s:dhV", options, NULL)) >= 0) 429 switch (c) { 430 431 case 'p': 432 syspath = optarg; 433 break; 434 435 case 's': 436 subsystem = optarg; 437 break; 438 439 case 'd': 440 if (log_get_max_level() < LOG_INFO) 441 log_set_max_level(LOG_INFO); 442 break; 443 444 case 'h': 445 printf("--debug --syspath= --subsystem= --help\n"); 446 goto out; 447 448 case 'V': 449 printf("%s\n", VERSION); 450 goto out; 451 452 case '?': 453 goto out; 454 455 default: 456 assert_not_reached("Unhandled option code."); 457 } 458 459 460 /* add sys path if needed */ 461 if (!startswith(syspath, "/sys")) { 462 snprintf(path, sizeof(path), "/sys/%s", syspath); 463 syspath = path; 464 } 465 466 test_device(udev, syspath); 467 test_device_devnum(udev); 468 test_device_subsys_name(udev); 469 test_device_parents(udev, syspath); 470 471 test_enumerate(udev, subsystem); 472 473 test_queue(udev); 474 475 test_hwdb(udev, "usb:v0D50p0011*"); 476 477 test_monitor(udev); 478out: 479 udev_unref(udev); 480 return 0; 481} 482