]> git.ipfire.org Git - thirdparty/systemd.git/blame - udev/udevadm-info.c
libudev: get devnum from uevent file
[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 void print_record(struct udev_device *device)
31de3a2b 130{
93b0f384
KS
131 size_t len;
132 int i;
bf7ad0ea 133 struct udev_list *list;
93b0f384
KS
134
135 printf("P: %s\n", udev_device_get_devpath(device));
bf7ad0ea 136
93b0f384 137 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
fb762bb9 138 printf("N: %s\n", &udev_device_get_devnode(device)[len+1]);
bf7ad0ea 139
93b0f384
KS
140 i = device_get_devlink_priority(device);
141 if (i != 0)
142 printf("L: %i\n", i);
bf7ad0ea 143
93b0f384
KS
144 i = device_get_num_fake_partitions(device);
145 if (i != 0)
146 printf("A:%u\n", i);
bf7ad0ea 147
93b0f384
KS
148 i = device_get_ignore_remove(device);
149 if (i != 0)
150 printf("R:%u\n", i);
93b0f384 151
bf7ad0ea
KS
152 list = udev_device_get_devlinks_list(device);
153 while (list != NULL) {
154 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
155 printf("S: %s\n", &udev_list_get_name(list)[len+1]);
156 list = udev_list_get_next(list);
31de3a2b 157 }
93b0f384 158
bf7ad0ea
KS
159 list = udev_device_get_properties_list(device);
160 while (list != NULL) {
161 printf("E: %s=%s\n", udev_list_get_name(list), udev_list_get_value(list));
162 list = udev_list_get_next(list);
93b0f384 163 }
93b0f384 164
bf7ad0ea 165 printf("\n");
31de3a2b
KS
166}
167
d1acfc3e 168static int stat_device(const char *name, int export, const char *prefix)
f338bac8
KS
169{
170 struct stat statbuf;
171
172 if (stat(name, &statbuf) != 0)
173 return -1;
174
d1acfc3e
KS
175 if (export) {
176 if (prefix == NULL)
177 prefix = "INFO_";
178 printf("%sMAJOR=%d\n"
179 "%sMINOR=%d\n",
180 prefix, major(statbuf.st_dev),
181 prefix, minor(statbuf.st_dev));
182 } else
cce9d773 183 printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
f338bac8
KS
184 return 0;
185}
186
bf7ad0ea
KS
187static int export_devices(struct udev *udev)
188{
189 struct udev_enumerate *enumerate;
190 struct udev_list *list;
191
192 enumerate = udev_enumerate_new_from_subsystems(udev, NULL);
193 if (enumerate == NULL)
194 return -1;
195 list = udev_enumerate_get_devices_list(enumerate);
196 while (list != NULL) {
197 struct udev_device *device;
198
199 device = udev_device_new_from_syspath(udev, udev_list_get_name(list));
200 if (device != NULL) {
201 if (udev_device_get_devnode(device) != NULL)
202 print_record(device);
203 udev_device_unref(device);
204 }
205 list = udev_list_get_next(list);
206 }
207 udev_enumerate_unref(enumerate);
208 return 0;
209}
210
7d563a17 211int udevadm_info(struct udev *udev, int argc, char *argv[])
87171e46 212{
93b0f384 213 struct udev_device *device = NULL;
87171e46 214 int root = 0;
d1acfc3e
KS
215 int export = 0;
216 const char *export_prefix = NULL;
93b0f384
KS
217 char path[UTIL_PATH_SIZE];
218 char name[UTIL_PATH_SIZE];
bf7ad0ea 219 struct udev_list *list;
93b0f384 220 int rc = 0;
24ca5c33 221
e97717ba 222 static const struct option options[] = {
11f1bb5a
KS
223 { "name", 1, NULL, 'n' },
224 { "path", 1, NULL, 'p' },
225 { "query", 1, NULL, 'q' },
226 { "attribute-walk", 0, NULL, 'a' },
227 { "export-db", 0, NULL, 'e' },
228 { "root", 0, NULL, 'r' },
f338bac8 229 { "device-id-of-file", 1, NULL, 'd' },
d1acfc3e
KS
230 { "export", 0, NULL, 'x' },
231 { "export-prefix", 1, NULL, 'P' },
88caa9da 232 { "version", 0, NULL, 1 }, /* -V outputs braindead format */
11f1bb5a
KS
233 { "help", 0, NULL, 'h' },
234 {}
235 };
236
24ca5c33
KS
237 enum action_type {
238 ACTION_NONE,
239 ACTION_QUERY,
240 ACTION_ATTRIBUTE_WALK,
241 ACTION_ROOT,
f338bac8 242 ACTION_DEVICE_ID_FILE,
24ca5c33
KS
243 } action = ACTION_NONE;
244
b8476286
KS
245 enum query_type {
246 QUERY_NONE,
247 QUERY_NAME,
248 QUERY_PATH,
249 QUERY_SYMLINK,
250 QUERY_ENV,
251 QUERY_ALL,
252 } query = QUERY_NONE;
24ca5c33 253
87171e46 254 while (1) {
7d563a17 255 int option;
bf7ad0ea 256 struct stat statbuf;
7d563a17 257
d1acfc3e 258 option = getopt_long(argc, argv, "aed:n:p:q:rxPVh", options, NULL);
87171e46
KS
259 if (option == -1)
260 break;
261
7d563a17 262 dbg(udev, "option '%c'\n", option);
87171e46
KS
263 switch (option) {
264 case 'n':
93b0f384
KS
265 if (device != NULL) {
266 fprintf(stderr, "device already specified\n");
267 rc = 2;
268 goto exit;
269 }
2362eea6 270 /* remove /dev if given */
bf7ad0ea
KS
271 if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) != 0) {
272 util_strlcpy(name, udev_get_dev_path(udev), sizeof(name));
273 util_strlcat(name, "/", sizeof(name));
274 util_strlcat(name, optarg, sizeof(name));
275 } else {
31c1f537 276 util_strlcpy(name, optarg, sizeof(name));
bf7ad0ea 277 }
ecc9ec57 278 util_remove_trailing_chars(name, '/');
bf7ad0ea
KS
279 if (stat(name, &statbuf) < 0) {
280 fprintf(stderr, "device node not found\n");
281 rc = 2;
282 goto exit;
283 } else {
284 char type;
285
286 if (S_ISBLK(statbuf.st_mode)) {
287 type = 'b';
288 } else if (S_ISCHR(statbuf.st_mode)) {
289 type = 'c';
290 } else {
291 fprintf(stderr, "device node has wrong file type\n");
292 rc = 2;
293 goto exit;
294 }
295 device = udev_device_new_from_devnum(udev, type, statbuf.st_rdev);
296 if (device == NULL) {
297 fprintf(stderr, "device node not found\n");
298 rc = 2;
299 goto exit;
300 }
301 }
87171e46 302 break;
87171e46 303 case 'p':
93b0f384
KS
304 if (device != NULL) {
305 fprintf(stderr, "device already specified\n");
306 rc = 2;
307 goto exit;
308 }
8753fadf
KS
309 /* add /sys if needed */
310 if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0) {
311 util_strlcpy(path, udev_get_sys_path(udev), sizeof(path));
312 util_strlcat(path, optarg, sizeof(path));
313 } else {
31c1f537 314 util_strlcpy(path, optarg, sizeof(path));
8753fadf 315 }
ecc9ec57 316 util_remove_trailing_chars(path, '/');
8753fadf 317 device = udev_device_new_from_syspath(udev, path);
bf7ad0ea
KS
318 if (device == NULL) {
319 fprintf(stderr, "device path not found\n");
320 rc = 2;
321 goto exit;
322 }
87171e46 323 break;
87171e46 324 case 'q':
24ca5c33 325 action = ACTION_QUERY;
87171e46 326 if (strcmp(optarg, "name") == 0) {
b8476286 327 query = QUERY_NAME;
87171e46
KS
328 break;
329 }
87171e46 330 if (strcmp(optarg, "symlink") == 0) {
b8476286 331 query = QUERY_SYMLINK;
87171e46
KS
332 break;
333 }
87171e46 334 if (strcmp(optarg, "path") == 0) {
b8476286
KS
335 query = QUERY_PATH;
336 break;
337 }
b8476286
KS
338 if (strcmp(optarg, "env") == 0) {
339 query = QUERY_ENV;
87171e46
KS
340 break;
341 }
8ea84a8a 342 if (strcmp(optarg, "all") == 0) {
b8476286 343 query = QUERY_ALL;
8ea84a8a
KS
344 break;
345 }
61b1b706 346 fprintf(stderr, "unknown query type\n");
1aa1e248 347 rc = 2;
e48fc108 348 goto exit;
87171e46 349 case 'r':
24ca5c33
KS
350 if (action == ACTION_NONE)
351 action = ACTION_ROOT;
87171e46
KS
352 root = 1;
353 break;
f338bac8
KS
354 case 'd':
355 action = ACTION_DEVICE_ID_FILE;
31c1f537 356 util_strlcpy(name, optarg, sizeof(name));
f338bac8 357 break;
87171e46 358 case 'a':
24ca5c33 359 action = ACTION_ATTRIBUTE_WALK;
87171e46 360 break;
24ca5c33 361 case 'e':
bf7ad0ea 362 export_devices(udev);
e48fc108 363 goto exit;
d1acfc3e
KS
364 case 'x':
365 export = 1;
366 break;
367 case 'P':
368 export_prefix = optarg;
369 break;
88caa9da 370 case 1:
01618658 371 printf("%s\n", VERSION);
88caa9da 372 goto exit;
87171e46 373 case 'V':
01618658 374 printf("udevinfo, version %s\n", VERSION);
e48fc108 375 goto exit;
87171e46 376 case 'h':
225cb03b 377 printf("Usage: udevadm info OPTIONS\n"
f338bac8
KS
378 " --query=<type> query database for the specified value:\n"
379 " name name of device node\n"
380 " symlink pointing to node\n"
381 " path sysfs device path\n"
382 " env the device related imported environment\n"
383 " all all values\n"
384 " --path=<devpath> sysfs device path used for query or chain\n"
385 " --name=<name> node or symlink name used for query\n"
386 " --root prepend to query result or print udev_root\n"
387 " --attribute-walk print all key matches while walking along chain\n"
388 " of parent devices\n"
389 " --device-id-of-file=<file> print major/minor of underlying device\n"
390 " --export-db export the content of the udev database\n"
391 " --help print this text\n"
e3396a2d
KS
392 "\n");
393 goto exit;
87171e46 394 default:
24ca5c33 395 goto exit;
87171e46
KS
396 }
397 }
398
24ca5c33
KS
399 switch (action) {
400 case ACTION_QUERY:
93b0f384 401 if (device == NULL) {
9a8047fa 402 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
1aa1e248 403 rc = 4;
24ca5c33 404 goto exit;
87171e46
KS
405 }
406
87171e46 407 switch(query) {
b8476286 408 case QUERY_NAME:
93b0f384 409 if (root) {
fb762bb9 410 printf("%s\n", udev_device_get_devnode(device));
93b0f384
KS
411 } else {
412 size_t len;
18770246 413
93b0f384 414 len = strlen(udev_get_dev_path(udev));
fb762bb9 415 printf("%s\n", &udev_device_get_devnode(device)[len+1]);
18770246 416 }
24ca5c33 417 break;
93b0f384 418 case QUERY_SYMLINK:
bf7ad0ea
KS
419 list = udev_device_get_devlinks_list(device);
420 while (list != NULL) {
421 if (root) {
422 printf("%s", udev_list_get_name(list));
423 } else {
424 size_t len;
425
426 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
427 printf("%s", &udev_list_get_name(list)[len+1]);
428 }
429 list = udev_list_get_next(list);
430 if (list != NULL)
431 printf(" ");
432 }
433 printf("\n");
93b0f384 434 break;
b8476286 435 case QUERY_PATH:
93b0f384 436 printf("%s\n", udev_device_get_devpath(device));
e48fc108 437 goto exit;
b8476286 438 case QUERY_ENV:
bf7ad0ea
KS
439 list = udev_device_get_properties_list(device);
440 while (list != NULL) {
441 printf("%s=%s\n", udev_list_get_name(list), udev_list_get_value(list));
442 list = udev_list_get_next(list);
443 }
24ca5c33 444 break;
b8476286 445 case QUERY_ALL:
93b0f384 446 print_record(device);
24ca5c33 447 break;
87171e46 448 default:
e3396a2d 449 fprintf(stderr, "unknown query type\n");
24ca5c33 450 break;
87171e46 451 }
24ca5c33
KS
452 break;
453 case ACTION_ATTRIBUTE_WALK:
93b0f384 454 if (device == NULL) {
9a8047fa 455 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
1aa0c52b
KS
456 rc = 5;
457 goto exit;
458 }
93b0f384 459 print_device_chain(device);
24ca5c33 460 break;
f338bac8 461 case ACTION_DEVICE_ID_FILE:
d1acfc3e 462 if (stat_device(name, export, export_prefix) != 0)
f338bac8
KS
463 rc = 6;
464 break;
24ca5c33 465 case ACTION_ROOT:
7d563a17 466 printf("%s\n", udev_get_dev_path(udev));
24ca5c33
KS
467 break;
468 default:
e3396a2d 469 fprintf(stderr, "missing option\n");
1aa1e248 470 rc = 1;
24ca5c33 471 break;
87171e46
KS
472 }
473
e48fc108 474exit:
93b0f384 475 udev_device_unref(device);
1aa1e248 476 return rc;
87171e46 477}