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