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