]> git.ipfire.org Git - thirdparty/systemd.git/blame - udev/udevadm-info.c
test-libudev: add short options
[thirdparty/systemd.git] / udev / udevadm-info.c
CommitLineData
be9b51f6 1/*
fc206fbe 2 * Copyright (C) 2004-2009 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>
e6c1a2bd 28#include <fcntl.h>
492e76c9
KS
29#include <sys/stat.h>
30#include <sys/types.h>
be9b51f6 31
869fc2f1 32#include "udev.h"
be9b51f6 33
93b0f384 34static void print_all_attributes(struct udev_device *device, const char *key)
be9b51f6 35{
95ce1875 36 struct udev_list_entry *sysattr;
1aa1e248 37
95ce1875
TE
38 udev_list_entry_foreach(sysattr, udev_device_get_sysattr_list_entry(device)) {
39 const char *name;
40 const char *value;
41 size_t len;
1aa1e248 42
95ce1875
TE
43 /* skip symlinks */
44 if (0 == strcmp("s", udev_list_entry_get_value(sysattr)))
45 continue;
492e76c9 46
95ce1875
TE
47 name = udev_list_entry_get_name(sysattr);
48 if (strcmp(name, "uevent") == 0)
49 continue;
50 if (strcmp(name, "dev") == 0)
51 continue;
e9b64770 52
95ce1875
TE
53 value = udev_device_get_sysattr_value(device, name);
54 if (value == NULL)
55 continue;
56 dbg(udev_device_get_udev(device), "attr '%s'='%s'\n", name, value);
492e76c9 57
95ce1875
TE
58 /* skip nonprintable attributes */
59 len = strlen(value);
60 while (len > 0 && isprint(value[len-1]))
61 len--;
62 if (len > 0) {
63 dbg(udev_device_get_udev(device),
64 "attribute value of '%s' non-printable, skip\n", name);
65 continue;
6276fdd2 66 }
95ce1875
TE
67
68 printf(" %s{%s}==\"%s\"\n", key, name, value);
be9b51f6
KS
69 }
70 printf("\n");
be9b51f6
KS
71}
72
93b0f384 73static int print_device_chain(struct udev_device *device)
87171e46 74{
b2d9e4f2 75 struct udev_device *device_parent;
4ad3a37f 76 const char *str;
e48fc108 77
1aa1e248 78 printf("\n"
b620292b 79 "Udevadm info starts with the device specified by the devpath and then\n"
6cf19e52
KS
80 "walks up the chain of parent devices. It prints for every device\n"
81 "found, all possible attributes in the udev rules key format.\n"
82 "A rule to match, can be composed by the attributes of the device\n"
83 "and the attributes from one single parent device.\n"
dba8c18b 84 "\n");
f61d732a 85
4ad3a37f
KS
86 printf(" looking at device '%s':\n", udev_device_get_devpath(device));
87 printf(" KERNEL==\"%s\"\n", udev_device_get_sysname(device));
88 str = udev_device_get_subsystem(device);
89 if (str == NULL)
90 str = "";
91 printf(" SUBSYSTEM==\"%s\"\n", str);
92 str = udev_device_get_driver(device);
93 if (str == NULL)
94 str = "";
95 printf(" DRIVER==\"%s\"\n", str);
93b0f384 96 print_all_attributes(device, "ATTR");
4ad3a37f 97
b2d9e4f2
KS
98 device_parent = device;
99 do {
100 device_parent = udev_device_get_parent(device_parent);
4ad3a37f 101 if (device_parent == NULL)
034f35d7 102 break;
b2d9e4f2
KS
103 printf(" looking at parent device '%s':\n", udev_device_get_devpath(device_parent));
104 printf(" KERNELS==\"%s\"\n", udev_device_get_sysname(device_parent));
105 str = udev_device_get_subsystem(device_parent);
4ad3a37f
KS
106 if (str == NULL)
107 str = "";
108 printf(" SUBSYSTEMS==\"%s\"\n", str);
b2d9e4f2 109 str = udev_device_get_driver(device_parent);
4ad3a37f
KS
110 if (str == NULL)
111 str = "";
112 printf(" DRIVERS==\"%s\"\n", str);
93b0f384 113 print_all_attributes(device_parent, "ATTRS");
b2d9e4f2 114 } while (device_parent != NULL);
be9b51f6 115
1aa1e248
KS
116 return 0;
117}
118
93b0f384 119static void print_record(struct udev_device *device)
31de3a2b 120{
93b0f384 121 size_t len;
ee137da3 122 const char *str;
93b0f384 123 int i;
0de33a61 124 struct udev_list_entry *list_entry;
93b0f384
KS
125
126 printf("P: %s\n", udev_device_get_devpath(device));
bf7ad0ea 127
93b0f384 128 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
ee137da3
KS
129 str = udev_device_get_devnode(device);
130 if (str != NULL)
131 printf("N: %s\n", &str[len+1]);
bf7ad0ea 132
aa8734ff 133 i = udev_device_get_devlink_priority(device);
93b0f384
KS
134 if (i != 0)
135 printf("L: %i\n", i);
bf7ad0ea 136
0de33a61 137 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) {
bf7ad0ea 138 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
0de33a61 139 printf("S: %s\n", &udev_list_entry_get_name(list_entry)[len+1]);
31de3a2b 140 }
93b0f384 141
0de33a61
KS
142 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device))
143 printf("E: %s=%s\n",
144 udev_list_entry_get_name(list_entry),
145 udev_list_entry_get_value(list_entry));
bf7ad0ea 146 printf("\n");
31de3a2b
KS
147}
148
88163971 149static int stat_device(const char *name, bool export, const char *prefix)
f338bac8
KS
150{
151 struct stat statbuf;
152
153 if (stat(name, &statbuf) != 0)
154 return -1;
155
d1acfc3e
KS
156 if (export) {
157 if (prefix == NULL)
158 prefix = "INFO_";
159 printf("%sMAJOR=%d\n"
160 "%sMINOR=%d\n",
161 prefix, major(statbuf.st_dev),
162 prefix, minor(statbuf.st_dev));
163 } else
cce9d773 164 printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
f338bac8
KS
165 return 0;
166}
167
bf7ad0ea
KS
168static int export_devices(struct udev *udev)
169{
438d4c3c 170 struct udev_enumerate *udev_enumerate;
0de33a61 171 struct udev_list_entry *list_entry;
bf7ad0ea 172
438d4c3c
KS
173 udev_enumerate = udev_enumerate_new(udev);
174 if (udev_enumerate == NULL)
bf7ad0ea 175 return -1;
c97f839e 176 udev_enumerate_scan_devices(udev_enumerate);
438d4c3c 177 udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
bf7ad0ea
KS
178 struct udev_device *device;
179
0de33a61 180 device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
bf7ad0ea 181 if (device != NULL) {
b38a5801 182 print_record(device);
bf7ad0ea
KS
183 udev_device_unref(device);
184 }
bf7ad0ea 185 }
438d4c3c 186 udev_enumerate_unref(udev_enumerate);
bf7ad0ea
KS
187 return 0;
188}
189
4281da1f
KS
190static int convert_db(struct udev *udev)
191{
192 struct udev_enumerate *udev_enumerate;
193 struct udev_list_entry *list_entry;
194
195 udev_enumerate = udev_enumerate_new(udev);
196 if (udev_enumerate == NULL)
197 return -1;
198 udev_enumerate_scan_devices(udev_enumerate);
199 udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
200 struct udev_device *device;
201
202 device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
203 if (device != NULL) {
204 const char *id;
24d10766 205 struct stat stats;
4281da1f
KS
206 char to[UTIL_PATH_SIZE];
207 char devpath[UTIL_PATH_SIZE];
208 char from[UTIL_PATH_SIZE];
209
210 id = udev_device_get_id_filename(device);
24d10766
KS
211 if (id == NULL) {
212 udev_device_unref(device);
213 continue;
214 }
4281da1f
KS
215 util_strscpyl(to, sizeof(to), udev_get_dev_path(udev), "/.udev/db/", id, NULL);
216
4281da1f
KS
217 /* find old database with $subsys:$sysname */
218 util_strscpyl(from, sizeof(from), udev_get_dev_path(udev),
219 "/.udev/db/", udev_device_get_subsystem(device), ":",
220 udev_device_get_sysname(device), NULL);
24d10766
KS
221 if (lstat(from, &stats) == 0) {
222 if (lstat(to, &stats) == 0)
223 unlink(from);
224 else
225 rename(from, to);
4281da1f
KS
226 }
227
228 /* find old database with the encoded devpath */
229 util_path_encode(udev_device_get_devpath(device), devpath, sizeof(devpath));
230 util_strscpyl(from, sizeof(from), udev_get_dev_path(udev),
231 "/.udev/db/", devpath, NULL);
24d10766
KS
232 if (lstat(from, &stats) == 0) {
233 if (lstat(to, &stats) == 0)
234 unlink(from);
235 else
236 rename(from, to);
4281da1f 237 }
24d10766
KS
238
239 /* read the old database, and write out a new one */
240 udev_device_read_db(device);
241 udev_device_update_db(device);
242
4281da1f
KS
243 udev_device_unref(device);
244 }
245 }
246 udev_enumerate_unref(udev_enumerate);
247 return 0;
248}
249
7d563a17 250int udevadm_info(struct udev *udev, int argc, char *argv[])
87171e46 251{
93b0f384 252 struct udev_device *device = NULL;
88163971
KS
253 bool root = 0;
254 bool export = 0;
d1acfc3e 255 const char *export_prefix = NULL;
93b0f384
KS
256 char path[UTIL_PATH_SIZE];
257 char name[UTIL_PATH_SIZE];
0de33a61 258 struct udev_list_entry *list_entry;
93b0f384 259 int rc = 0;
24ca5c33 260
e97717ba 261 static const struct option options[] = {
033e9f8c
KS
262 { "name", required_argument, NULL, 'n' },
263 { "path", required_argument, NULL, 'p' },
ff5d99e0 264 { "query", required_argument, NULL, 'q' },
033e9f8c
KS
265 { "attribute-walk", no_argument, NULL, 'a' },
266 { "export-db", no_argument, NULL, 'e' },
4281da1f 267 { "convert-db", no_argument, NULL, 'C' },
033e9f8c
KS
268 { "root", no_argument, NULL, 'r' },
269 { "device-id-of-file", required_argument, NULL, 'd' },
270 { "export", no_argument, NULL, 'x' },
271 { "export-prefix", required_argument, NULL, 'P' },
50025605 272 { "version", no_argument, NULL, 'V' },
033e9f8c 273 { "help", no_argument, NULL, 'h' },
11f1bb5a
KS
274 {}
275 };
276
24ca5c33
KS
277 enum action_type {
278 ACTION_NONE,
279 ACTION_QUERY,
280 ACTION_ATTRIBUTE_WALK,
281 ACTION_ROOT,
f338bac8 282 ACTION_DEVICE_ID_FILE,
24ca5c33
KS
283 } action = ACTION_NONE;
284
b8476286
KS
285 enum query_type {
286 QUERY_NONE,
287 QUERY_NAME,
288 QUERY_PATH,
289 QUERY_SYMLINK,
0254b211 290 QUERY_PROPERTY,
b8476286
KS
291 QUERY_ALL,
292 } query = QUERY_NONE;
24ca5c33 293
88cbfb09 294 for (;;) {
7d563a17 295 int option;
bf7ad0ea 296 struct stat statbuf;
7d563a17 297
163c0365 298 option = getopt_long(argc, argv, "aed:n:p:q:rxP:Vh", options, NULL);
87171e46
KS
299 if (option == -1)
300 break;
301
7d563a17 302 dbg(udev, "option '%c'\n", option);
87171e46
KS
303 switch (option) {
304 case 'n':
93b0f384
KS
305 if (device != NULL) {
306 fprintf(stderr, "device already specified\n");
307 rc = 2;
308 goto exit;
309 }
2362eea6 310 /* remove /dev if given */
065db052
KS
311 if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) != 0)
312 util_strscpyl(name, sizeof(name), udev_get_dev_path(udev), "/", optarg, NULL);
313 else
314 util_strscpy(name, sizeof(name), optarg);
ecc9ec57 315 util_remove_trailing_chars(name, '/');
bf7ad0ea
KS
316 if (stat(name, &statbuf) < 0) {
317 fprintf(stderr, "device node not found\n");
318 rc = 2;
319 goto exit;
320 } else {
321 char type;
322
323 if (S_ISBLK(statbuf.st_mode)) {
324 type = 'b';
325 } else if (S_ISCHR(statbuf.st_mode)) {
326 type = 'c';
327 } else {
328 fprintf(stderr, "device node has wrong file type\n");
329 rc = 2;
330 goto exit;
331 }
332 device = udev_device_new_from_devnum(udev, type, statbuf.st_rdev);
333 if (device == NULL) {
334 fprintf(stderr, "device node not found\n");
335 rc = 2;
336 goto exit;
337 }
338 }
87171e46 339 break;
87171e46 340 case 'p':
93b0f384
KS
341 if (device != NULL) {
342 fprintf(stderr, "device already specified\n");
343 rc = 2;
344 goto exit;
345 }
bc8184ed 346 /* add sys dir if needed */
065db052
KS
347 if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0)
348 util_strscpyl(path, sizeof(path), udev_get_sys_path(udev), optarg, NULL);
349 else
350 util_strscpy(path, sizeof(path), optarg);
ecc9ec57 351 util_remove_trailing_chars(path, '/');
8753fadf 352 device = udev_device_new_from_syspath(udev, path);
bf7ad0ea
KS
353 if (device == NULL) {
354 fprintf(stderr, "device path not found\n");
355 rc = 2;
356 goto exit;
357 }
87171e46 358 break;
87171e46 359 case 'q':
24ca5c33 360 action = ACTION_QUERY;
ff5d99e0 361 if (strcmp(optarg, "property") == 0 || strcmp(optarg, "env") == 0) {
0254b211
KS
362 query = QUERY_PROPERTY;
363 } else if (strcmp(optarg, "name") == 0) {
b8476286 364 query = QUERY_NAME;
0254b211 365 } else if (strcmp(optarg, "symlink") == 0) {
b8476286 366 query = QUERY_SYMLINK;
0254b211 367 } else if (strcmp(optarg, "path") == 0) {
b8476286 368 query = QUERY_PATH;
0254b211 369 } else if (strcmp(optarg, "all") == 0) {
b8476286 370 query = QUERY_ALL;
0254b211
KS
371 } else {
372 fprintf(stderr, "unknown query type\n");
373 rc = 3;
374 goto exit;
8ea84a8a 375 }
0254b211 376 break;
87171e46 377 case 'r':
24ca5c33
KS
378 if (action == ACTION_NONE)
379 action = ACTION_ROOT;
88163971 380 root = true;
87171e46 381 break;
f338bac8
KS
382 case 'd':
383 action = ACTION_DEVICE_ID_FILE;
065db052 384 util_strscpy(name, sizeof(name), optarg);
f338bac8 385 break;
87171e46 386 case 'a':
24ca5c33 387 action = ACTION_ATTRIBUTE_WALK;
87171e46 388 break;
24ca5c33 389 case 'e':
bf7ad0ea 390 export_devices(udev);
e48fc108 391 goto exit;
4281da1f
KS
392 case 'C':
393 convert_db(udev);
394 goto exit;
d1acfc3e 395 case 'x':
88163971 396 export = true;
d1acfc3e
KS
397 break;
398 case 'P':
399 export_prefix = optarg;
400 break;
87171e46 401 case 'V':
50025605 402 printf("%s\n", VERSION);
e48fc108 403 goto exit;
87171e46 404 case 'h':
225cb03b 405 printf("Usage: udevadm info OPTIONS\n"
cd42b50d 406 " --query=<type> query device information:\n"
f338bac8
KS
407 " name name of device node\n"
408 " symlink pointing to node\n"
cd42b50d 409 " path sys device path\n"
0254b211 410 " property the device properties\n"
f338bac8 411 " all all values\n"
cd42b50d
KS
412 " --path=<syspath> sys device path used for query or attribute walk\n"
413 " --name=<name> node or symlink name used for query or attribute walk\n"
414 " --root prepend dev directory to path names\n"
415 " --attribute-walk print all key matches while walking along the chain\n"
f338bac8 416 " of parent devices\n"
cd42b50d 417 " --device-id-of-file=<file> print major:minor of device containing this file\n"
4281da1f
KS
418 " --export export key/value pairs\n"
419 " --export-prefix export the key name with a prefix\n"
f338bac8 420 " --export-db export the content of the udev database\n"
4281da1f 421 " --convert-db convert older version of database without a reboot\n"
f1e7e360 422 " --help\n\n");
e3396a2d 423 goto exit;
87171e46 424 default:
24ca5c33 425 goto exit;
87171e46
KS
426 }
427 }
428
24ca5c33
KS
429 switch (action) {
430 case ACTION_QUERY:
93b0f384 431 if (device == NULL) {
9a8047fa 432 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
1aa1e248 433 rc = 4;
24ca5c33 434 goto exit;
87171e46
KS
435 }
436
87171e46 437 switch(query) {
299650f1
KS
438 case QUERY_NAME: {
439 const char *node = udev_device_get_devnode(device);
440
441 if (node == NULL) {
442 fprintf(stderr, "no device node found\n");
443 rc = 5;
444 goto exit;
445 }
446
93b0f384 447 if (root) {
fb762bb9 448 printf("%s\n", udev_device_get_devnode(device));
93b0f384 449 } else {
299650f1
KS
450 size_t len = strlen(udev_get_dev_path(udev));
451
452 printf("%s\n", &udev_device_get_devnode(device)[len+1]);
18770246 453 }
24ca5c33 454 break;
299650f1 455 }
93b0f384 456 case QUERY_SYMLINK:
0de33a61
KS
457 list_entry = udev_device_get_devlinks_list_entry(device);
458 while (list_entry != NULL) {
bf7ad0ea 459 if (root) {
0de33a61 460 printf("%s", udev_list_entry_get_name(list_entry));
bf7ad0ea
KS
461 } else {
462 size_t len;
463
464 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
0de33a61 465 printf("%s", &udev_list_entry_get_name(list_entry)[len+1]);
bf7ad0ea 466 }
0de33a61
KS
467 list_entry = udev_list_entry_get_next(list_entry);
468 if (list_entry != NULL)
bf7ad0ea
KS
469 printf(" ");
470 }
471 printf("\n");
93b0f384 472 break;
b8476286 473 case QUERY_PATH:
93b0f384 474 printf("%s\n", udev_device_get_devpath(device));
e48fc108 475 goto exit;
0254b211 476 case QUERY_PROPERTY:
0de33a61
KS
477 list_entry = udev_device_get_properties_list_entry(device);
478 while (list_entry != NULL) {
88163971
KS
479 if (export) {
480 const char *prefix = export_prefix;
481
482 if (prefix == NULL)
483 prefix = "";
484 printf("%s%s='%s'\n", prefix,
485 udev_list_entry_get_name(list_entry),
486 udev_list_entry_get_value(list_entry));
487 } else {
488 printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
489 }
0de33a61 490 list_entry = udev_list_entry_get_next(list_entry);
bf7ad0ea 491 }
24ca5c33 492 break;
b8476286 493 case QUERY_ALL:
93b0f384 494 print_record(device);
24ca5c33 495 break;
87171e46 496 default:
e3396a2d 497 fprintf(stderr, "unknown query type\n");
24ca5c33 498 break;
87171e46 499 }
24ca5c33
KS
500 break;
501 case ACTION_ATTRIBUTE_WALK:
93b0f384 502 if (device == NULL) {
9a8047fa 503 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
62b9dfb6 504 rc = 4;
1aa0c52b
KS
505 goto exit;
506 }
93b0f384 507 print_device_chain(device);
24ca5c33 508 break;
f338bac8 509 case ACTION_DEVICE_ID_FILE:
d1acfc3e 510 if (stat_device(name, export, export_prefix) != 0)
62b9dfb6 511 rc = 1;
f338bac8 512 break;
24ca5c33 513 case ACTION_ROOT:
7d563a17 514 printf("%s\n", udev_get_dev_path(udev));
24ca5c33
KS
515 break;
516 default:
e3396a2d 517 fprintf(stderr, "missing option\n");
1aa1e248 518 rc = 1;
24ca5c33 519 break;
87171e46
KS
520 }
521
e48fc108 522exit:
93b0f384 523 udev_device_unref(device);
1aa1e248 524 return rc;
87171e46 525}