]> git.ipfire.org Git - thirdparty/systemd.git/blame - udev/udevadm-info.c
libudev: add userdata pointer
[thirdparty/systemd.git] / udev / udevadm-info.c
CommitLineData
be9b51f6 1/*
55e9959b 2 * Copyright (C) 2004-2008 Kay Sievers <kay.sievers@vrfy.org>
be9b51f6 3 *
55e9959b
KS
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
be9b51f6 8 *
55e9959b
KS
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
be9b51f6
KS
16 */
17
18#include <stdlib.h>
19#include <string.h>
20#include <stdio.h>
1aa1e248 21#include <stddef.h>
034f35d7 22#include <ctype.h>
87171e46
KS
23#include <stdarg.h>
24#include <unistd.h>
1aa1e248 25#include <dirent.h>
87171e46 26#include <errno.h>
11f1bb5a 27#include <getopt.h>
492e76c9
KS
28#include <sys/stat.h>
29#include <sys/types.h>
be9b51f6 30
869fc2f1 31#include "udev.h"
be9b51f6 32
93b0f384 33static void print_all_attributes(struct udev_device *device, const char *key)
be9b51f6 34{
1aa1e248
KS
35 DIR *dir;
36 struct dirent *dent;
37
93b0f384 38 dir = opendir(udev_device_get_syspath(device));
1aa1e248
KS
39 if (dir != NULL) {
40 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
492e76c9 41 struct stat statbuf;
17fcfb59 42 char filename[UTIL_PATH_SIZE];
93b0f384 43 const char *value;
1aa1e248
KS
44 size_t len;
45
492e76c9
KS
46 if (dent->d_name[0] == '.')
47 continue;
48
e9b64770
KS
49 if (strcmp(dent->d_name, "uevent") == 0)
50 continue;
4c46d72a
KS
51 if (strcmp(dent->d_name, "dev") == 0)
52 continue;
e9b64770 53
93b0f384 54 util_strlcpy(filename, udev_device_get_syspath(device), sizeof(filename));
31c1f537
KS
55 util_strlcat(filename, "/", sizeof(filename));
56 util_strlcat(filename, dent->d_name, sizeof(filename));
492e76c9
KS
57 if (lstat(filename, &statbuf) != 0)
58 continue;
59 if (S_ISLNK(statbuf.st_mode))
60 continue;
61
93b0f384
KS
62 value = udev_device_get_attr_value(device, dent->d_name);
63 if (value == NULL)
1aa1e248 64 continue;
7d563a17 65 dbg(udev, "attr '%s'='%s'(%zi)\n", dent->d_name, value, len);
1aa1e248 66
1aa1e248 67 /* skip nonprintable attributes */
93b0f384
KS
68 len = strlen(value);
69 while (len > 0 && isprint(value[len-1]))
1aa1e248 70 len--;
93b0f384
KS
71 if (len > 0) {
72 dbg(info, "attribute value of '%s' non-printable, skip\n", dent->d_name);
1aa1e248
KS
73 continue;
74 }
6276fdd2 75
95776dc6 76 printf(" %s{%s}==\"%s\"\n", key, dent->d_name, value);
6276fdd2 77 }
4ad3a37f 78 closedir(dir);
be9b51f6
KS
79 }
80 printf("\n");
be9b51f6
KS
81}
82
93b0f384 83static int print_device_chain(struct udev_device *device)
87171e46 84{
b2d9e4f2 85 struct udev_device *device_parent;
4ad3a37f 86 const char *str;
e48fc108 87
1aa1e248 88 printf("\n"
6cf19e52
KS
89 "Udevinfo starts with the device specified by the devpath and then\n"
90 "walks up the chain of parent devices. It prints for every device\n"
91 "found, all possible attributes in the udev rules key format.\n"
92 "A rule to match, can be composed by the attributes of the device\n"
93 "and the attributes from one single parent device.\n"
dba8c18b 94 "\n");
f61d732a 95
4ad3a37f
KS
96 printf(" looking at device '%s':\n", udev_device_get_devpath(device));
97 printf(" KERNEL==\"%s\"\n", udev_device_get_sysname(device));
98 str = udev_device_get_subsystem(device);
99 if (str == NULL)
100 str = "";
101 printf(" SUBSYSTEM==\"%s\"\n", str);
102 str = udev_device_get_driver(device);
103 if (str == NULL)
104 str = "";
105 printf(" DRIVER==\"%s\"\n", str);
93b0f384 106 print_all_attributes(device, "ATTR");
4ad3a37f 107
b2d9e4f2
KS
108 device_parent = device;
109 do {
110 device_parent = udev_device_get_parent(device_parent);
4ad3a37f 111 if (device_parent == NULL)
034f35d7 112 break;
b2d9e4f2
KS
113 printf(" looking at parent device '%s':\n", udev_device_get_devpath(device_parent));
114 printf(" KERNELS==\"%s\"\n", udev_device_get_sysname(device_parent));
115 str = udev_device_get_subsystem(device_parent);
4ad3a37f
KS
116 if (str == NULL)
117 str = "";
118 printf(" SUBSYSTEMS==\"%s\"\n", str);
b2d9e4f2 119 str = udev_device_get_driver(device_parent);
4ad3a37f
KS
120 if (str == NULL)
121 str = "";
122 printf(" DRIVERS==\"%s\"\n", str);
93b0f384 123 print_all_attributes(device_parent, "ATTRS");
b2d9e4f2 124 } while (device_parent != NULL);
be9b51f6 125
1aa1e248
KS
126 return 0;
127}
128
93b0f384 129static int print_record_devlinks_cb(struct udev_device *device, const char *value, void *data)
1aa1e248 130{
93b0f384
KS
131 size_t len;
132
133 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
134 printf("S: %s\n", &value[len+1]);
135 return 0;
be9b51f6 136}
87171e46 137
93b0f384 138static int print_record_properties_cb(struct udev_device *device, const char *key, const char *value, void *data)
7d563a17 139{
93b0f384
KS
140 printf("E: %s=%s\n", key, value);
141 return 0;
9fe1a96d
KS
142}
143
93b0f384 144static void print_record(struct udev_device *device)
31de3a2b 145{
93b0f384
KS
146 size_t len;
147 int i;
148
149 printf("P: %s\n", udev_device_get_devpath(device));
150 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
fb762bb9 151 printf("N: %s\n", &udev_device_get_devnode(device)[len+1]);
93b0f384
KS
152 i = device_get_devlink_priority(device);
153 if (i != 0)
154 printf("L: %i\n", i);
155 i = device_get_num_fake_partitions(device);
156 if (i != 0)
157 printf("A:%u\n", i);
158 i = device_get_ignore_remove(device);
159 if (i != 0)
160 printf("R:%u\n", i);
161 udev_device_get_devlinks(device, print_record_devlinks_cb, NULL);
162 udev_device_get_properties(device, print_record_properties_cb, NULL);
163 printf("\n");
164}
165
a076080b 166static int export_all_cb(struct udev_device *device, void *data)
93b0f384 167{
fb762bb9 168 if (udev_device_get_devnode(device) != NULL)
93b0f384 169 print_record(device);
93b0f384
KS
170 return 0;
171}
172
173static struct udev_device *lookup_device_by_name(struct udev *udev, const char *name)
174{
9a8047fa 175 struct udev_device *udev_device = NULL;
31de3a2b 176 LIST_HEAD(name_list);
be8594ab 177 int count;
31de3a2b 178 struct name_entry *device;
31de3a2b 179
7d563a17 180 count = udev_db_get_devices_by_name(udev, name, &name_list);
be8594ab 181 if (count <= 0)
31de3a2b
KS
182 goto out;
183
7d563a17 184 info(udev, "found %i devices for '%s'\n", count, name);
be8594ab 185
9a8047fa 186 /* select the device that matches */
31de3a2b 187 list_for_each_entry(device, &name_list, node) {
7d563a17 188 struct udevice *udevice_loop;
17fcfb59 189 char filename[UTIL_PATH_SIZE];
31de3a2b
KS
190 struct stat statbuf;
191
7d563a17
KS
192 udevice_loop = udev_device_init(udev);
193 if (udevice_loop == NULL)
44aff4cd 194 break;
7d563a17 195 if (udev_db_get_device(udevice_loop, device->name) != 0)
44aff4cd 196 goto next;
7d563a17 197 info(udev, "found db entry '%s'\n", device->name);
44aff4cd 198 /* make sure, we don't get a link of a different device */
31c1f537
KS
199 util_strlcpy(filename, udev_get_dev_path(udev), sizeof(filename));
200 util_strlcat(filename, "/", sizeof(filename));
201 util_strlcat(filename, name, sizeof(filename));
31de3a2b 202 if (stat(filename, &statbuf) != 0)
44aff4cd 203 goto next;
7d563a17
KS
204 if (major(udevice_loop->devt) > 0 && udevice_loop->devt != statbuf.st_rdev) {
205 info(udev, "skip '%s', dev_t doesn't match\n", udevice_loop->name);
44aff4cd 206 goto next;
31de3a2b 207 }
8753fadf
KS
208 util_strlcpy(filename, udev_get_sys_path(udev), sizeof(filename));
209 util_strlcat(filename, udevice_loop->dev->devpath, sizeof(filename));
210 udev_device = udev_device_new_from_syspath(udev, filename);
9a8047fa 211 udev_device_cleanup(udevice_loop);
be8594ab 212 break;
44aff4cd 213next:
7d563a17 214 udev_device_cleanup(udevice_loop);
31de3a2b
KS
215 }
216out:
7d563a17 217 name_list_cleanup(udev, &name_list);
9a8047fa 218 return udev_device;
93b0f384
KS
219}
220
221static int add_devlink_cb(struct udev_device *device, const char *value, void *data)
222{
223 char **links = data;
224
225 if (*links == NULL) {
226 *links = strdup(value);
227 } else {
228 char *str;
229
230 asprintf(&str, "%s %s", *links, value);
231 free(*links);
232 *links = str;
233 }
234 return 0;
235}
236
237static int add_devlink_noroot_cb(struct udev_device *device, const char *value, void *data)
238{
239 size_t len;
240
241 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
242 value = &value[len+1];
243 return add_devlink_cb(device, value, data);
244}
245
246static int print_property_cb(struct udev_device *device, const char *key, const char *value, void *data)
247{
248 printf("%s=%s\n", key, value);
249 return 0;
31de3a2b
KS
250}
251
d1acfc3e 252static int stat_device(const char *name, int export, const char *prefix)
f338bac8
KS
253{
254 struct stat statbuf;
255
256 if (stat(name, &statbuf) != 0)
257 return -1;
258
d1acfc3e
KS
259 if (export) {
260 if (prefix == NULL)
261 prefix = "INFO_";
262 printf("%sMAJOR=%d\n"
263 "%sMINOR=%d\n",
264 prefix, major(statbuf.st_dev),
265 prefix, minor(statbuf.st_dev));
266 } else
cce9d773 267 printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
f338bac8
KS
268 return 0;
269}
270
7d563a17 271int udevadm_info(struct udev *udev, int argc, char *argv[])
87171e46 272{
93b0f384 273 struct udev_device *device = NULL;
87171e46 274 int root = 0;
d1acfc3e
KS
275 int export = 0;
276 const char *export_prefix = NULL;
93b0f384
KS
277 char path[UTIL_PATH_SIZE];
278 char name[UTIL_PATH_SIZE];
279 char *links;
280 int rc = 0;
24ca5c33 281
e97717ba 282 static const struct option options[] = {
11f1bb5a
KS
283 { "name", 1, NULL, 'n' },
284 { "path", 1, NULL, 'p' },
285 { "query", 1, NULL, 'q' },
286 { "attribute-walk", 0, NULL, 'a' },
287 { "export-db", 0, NULL, 'e' },
288 { "root", 0, NULL, 'r' },
f338bac8 289 { "device-id-of-file", 1, NULL, 'd' },
d1acfc3e
KS
290 { "export", 0, NULL, 'x' },
291 { "export-prefix", 1, NULL, 'P' },
88caa9da 292 { "version", 0, NULL, 1 }, /* -V outputs braindead format */
11f1bb5a
KS
293 { "help", 0, NULL, 'h' },
294 {}
295 };
296
24ca5c33
KS
297 enum action_type {
298 ACTION_NONE,
299 ACTION_QUERY,
300 ACTION_ATTRIBUTE_WALK,
301 ACTION_ROOT,
f338bac8 302 ACTION_DEVICE_ID_FILE,
24ca5c33
KS
303 } action = ACTION_NONE;
304
b8476286
KS
305 enum query_type {
306 QUERY_NONE,
307 QUERY_NAME,
308 QUERY_PATH,
309 QUERY_SYMLINK,
310 QUERY_ENV,
311 QUERY_ALL,
312 } query = QUERY_NONE;
24ca5c33 313
87171e46 314 while (1) {
7d563a17
KS
315 int option;
316
d1acfc3e 317 option = getopt_long(argc, argv, "aed:n:p:q:rxPVh", options, NULL);
87171e46
KS
318 if (option == -1)
319 break;
320
7d563a17 321 dbg(udev, "option '%c'\n", option);
87171e46
KS
322 switch (option) {
323 case 'n':
93b0f384
KS
324 if (device != NULL) {
325 fprintf(stderr, "device already specified\n");
326 rc = 2;
327 goto exit;
328 }
2362eea6 329 /* remove /dev if given */
7d563a17 330 if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) == 0)
31c1f537 331 util_strlcpy(name, &optarg[strlen(udev_get_dev_path(udev))+1], sizeof(name));
2362eea6 332 else
31c1f537 333 util_strlcpy(name, optarg, sizeof(name));
ecc9ec57 334 util_remove_trailing_chars(name, '/');
93b0f384 335 device = lookup_device_by_name(udev, name);
87171e46 336 break;
87171e46 337 case 'p':
93b0f384
KS
338 if (device != NULL) {
339 fprintf(stderr, "device already specified\n");
340 rc = 2;
341 goto exit;
342 }
8753fadf
KS
343 /* add /sys if needed */
344 if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0) {
345 util_strlcpy(path, udev_get_sys_path(udev), sizeof(path));
346 util_strlcat(path, optarg, sizeof(path));
347 } else {
31c1f537 348 util_strlcpy(path, optarg, sizeof(path));
8753fadf 349 }
ecc9ec57 350 util_remove_trailing_chars(path, '/');
8753fadf 351 device = udev_device_new_from_syspath(udev, path);
87171e46 352 break;
87171e46 353 case 'q':
24ca5c33 354 action = ACTION_QUERY;
87171e46 355 if (strcmp(optarg, "name") == 0) {
b8476286 356 query = QUERY_NAME;
87171e46
KS
357 break;
358 }
87171e46 359 if (strcmp(optarg, "symlink") == 0) {
b8476286 360 query = QUERY_SYMLINK;
87171e46
KS
361 break;
362 }
87171e46 363 if (strcmp(optarg, "path") == 0) {
b8476286
KS
364 query = QUERY_PATH;
365 break;
366 }
b8476286
KS
367 if (strcmp(optarg, "env") == 0) {
368 query = QUERY_ENV;
87171e46
KS
369 break;
370 }
8ea84a8a 371 if (strcmp(optarg, "all") == 0) {
b8476286 372 query = QUERY_ALL;
8ea84a8a
KS
373 break;
374 }
61b1b706 375 fprintf(stderr, "unknown query type\n");
1aa1e248 376 rc = 2;
e48fc108 377 goto exit;
87171e46 378 case 'r':
24ca5c33
KS
379 if (action == ACTION_NONE)
380 action = ACTION_ROOT;
87171e46
KS
381 root = 1;
382 break;
f338bac8
KS
383 case 'd':
384 action = ACTION_DEVICE_ID_FILE;
31c1f537 385 util_strlcpy(name, optarg, sizeof(name));
f338bac8 386 break;
87171e46 387 case 'a':
24ca5c33 388 action = ACTION_ATTRIBUTE_WALK;
87171e46 389 break;
24ca5c33 390 case 'e':
93b0f384 391 udev_enumerate_devices(udev, NULL, export_all_cb, NULL);
e48fc108 392 goto exit;
d1acfc3e
KS
393 case 'x':
394 export = 1;
395 break;
396 case 'P':
397 export_prefix = optarg;
398 break;
88caa9da 399 case 1:
01618658 400 printf("%s\n", VERSION);
88caa9da 401 goto exit;
87171e46 402 case 'V':
01618658 403 printf("udevinfo, version %s\n", VERSION);
e48fc108 404 goto exit;
87171e46 405 case 'h':
225cb03b 406 printf("Usage: udevadm info OPTIONS\n"
f338bac8
KS
407 " --query=<type> query database for the specified value:\n"
408 " name name of device node\n"
409 " symlink pointing to node\n"
410 " path sysfs device path\n"
411 " env the device related imported environment\n"
412 " all all values\n"
413 " --path=<devpath> sysfs device path used for query or chain\n"
414 " --name=<name> node or symlink name used for query\n"
415 " --root prepend to query result or print udev_root\n"
416 " --attribute-walk print all key matches while walking along chain\n"
417 " of parent devices\n"
418 " --device-id-of-file=<file> print major/minor of underlying device\n"
419 " --export-db export the content of the udev database\n"
420 " --help print this text\n"
e3396a2d
KS
421 "\n");
422 goto exit;
87171e46 423 default:
24ca5c33 424 goto exit;
87171e46
KS
425 }
426 }
427
24ca5c33
KS
428 switch (action) {
429 case ACTION_QUERY:
93b0f384 430 if (device == NULL) {
9a8047fa 431 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
1aa1e248 432 rc = 4;
24ca5c33 433 goto exit;
87171e46
KS
434 }
435
87171e46 436 switch(query) {
b8476286 437 case QUERY_NAME:
93b0f384 438 if (root) {
fb762bb9 439 printf("%s\n", udev_device_get_devnode(device));
93b0f384
KS
440 } else {
441 size_t len;
18770246 442
93b0f384 443 len = strlen(udev_get_dev_path(udev));
fb762bb9 444 printf("%s\n", &udev_device_get_devnode(device)[len+1]);
18770246 445 }
24ca5c33 446 break;
93b0f384
KS
447 case QUERY_SYMLINK:
448 links = NULL;
449 if (root)
450 udev_device_get_devlinks(device, add_devlink_cb, &links);
451 else
452 udev_device_get_devlinks(device, add_devlink_noroot_cb, &links);
453 printf("%s\n", links);
454 free(links);
455 break;
b8476286 456 case QUERY_PATH:
93b0f384 457 printf("%s\n", udev_device_get_devpath(device));
e48fc108 458 goto exit;
b8476286 459 case QUERY_ENV:
93b0f384 460 udev_device_get_properties(device, print_property_cb, NULL);
24ca5c33 461 break;
b8476286 462 case QUERY_ALL:
93b0f384 463 print_record(device);
24ca5c33 464 break;
87171e46 465 default:
e3396a2d 466 fprintf(stderr, "unknown query type\n");
24ca5c33 467 break;
87171e46 468 }
24ca5c33
KS
469 break;
470 case ACTION_ATTRIBUTE_WALK:
93b0f384 471 if (device == NULL) {
9a8047fa 472 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
1aa0c52b
KS
473 rc = 5;
474 goto exit;
475 }
93b0f384 476 print_device_chain(device);
24ca5c33 477 break;
f338bac8 478 case ACTION_DEVICE_ID_FILE:
d1acfc3e 479 if (stat_device(name, export, export_prefix) != 0)
f338bac8
KS
480 rc = 6;
481 break;
24ca5c33 482 case ACTION_ROOT:
7d563a17 483 printf("%s\n", udev_get_dev_path(udev));
24ca5c33
KS
484 break;
485 default:
e3396a2d 486 fprintf(stderr, "missing option\n");
1aa1e248 487 rc = 1;
24ca5c33 488 break;
87171e46
KS
489 }
490
e48fc108 491exit:
93b0f384 492 udev_device_unref(device);
1aa1e248 493 return rc;
87171e46 494}