]> git.ipfire.org Git - thirdparty/systemd.git/blame - udev/udevadm-info.c
edd_id: use openat()
[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
065db052 55 util_strscpyl(filename, sizeof(filename), udev_device_get_syspath(device), "/", dent->d_name, NULL);
492e76c9
KS
56 if (lstat(filename, &statbuf) != 0)
57 continue;
58 if (S_ISLNK(statbuf.st_mode))
59 continue;
60
69239210 61 value = udev_device_get_sysattr_value(device, dent->d_name);
93b0f384 62 if (value == NULL)
1aa1e248 63 continue;
7d563a17 64 dbg(udev, "attr '%s'='%s'(%zi)\n", dent->d_name, value, len);
1aa1e248 65
1aa1e248 66 /* skip nonprintable attributes */
93b0f384
KS
67 len = strlen(value);
68 while (len > 0 && isprint(value[len-1]))
1aa1e248 69 len--;
93b0f384 70 if (len > 0) {
4aa0b15e 71 dbg(udev, "attribute value of '%s' non-printable, skip\n", dent->d_name);
1aa1e248
KS
72 continue;
73 }
6276fdd2 74
95776dc6 75 printf(" %s{%s}==\"%s\"\n", key, dent->d_name, value);
6276fdd2 76 }
4ad3a37f 77 closedir(dir);
be9b51f6
KS
78 }
79 printf("\n");
be9b51f6
KS
80}
81
93b0f384 82static int print_device_chain(struct udev_device *device)
87171e46 83{
b2d9e4f2 84 struct udev_device *device_parent;
4ad3a37f 85 const char *str;
e48fc108 86
1aa1e248 87 printf("\n"
b620292b 88 "Udevadm info starts with the device specified by the devpath and then\n"
6cf19e52
KS
89 "walks up the chain of parent devices. It prints for every device\n"
90 "found, all possible attributes in the udev rules key format.\n"
91 "A rule to match, can be composed by the attributes of the device\n"
92 "and the attributes from one single parent device.\n"
dba8c18b 93 "\n");
f61d732a 94
4ad3a37f
KS
95 printf(" looking at device '%s':\n", udev_device_get_devpath(device));
96 printf(" KERNEL==\"%s\"\n", udev_device_get_sysname(device));
97 str = udev_device_get_subsystem(device);
98 if (str == NULL)
99 str = "";
100 printf(" SUBSYSTEM==\"%s\"\n", str);
101 str = udev_device_get_driver(device);
102 if (str == NULL)
103 str = "";
104 printf(" DRIVER==\"%s\"\n", str);
93b0f384 105 print_all_attributes(device, "ATTR");
4ad3a37f 106
b2d9e4f2
KS
107 device_parent = device;
108 do {
109 device_parent = udev_device_get_parent(device_parent);
4ad3a37f 110 if (device_parent == NULL)
034f35d7 111 break;
b2d9e4f2
KS
112 printf(" looking at parent device '%s':\n", udev_device_get_devpath(device_parent));
113 printf(" KERNELS==\"%s\"\n", udev_device_get_sysname(device_parent));
114 str = udev_device_get_subsystem(device_parent);
4ad3a37f
KS
115 if (str == NULL)
116 str = "";
117 printf(" SUBSYSTEMS==\"%s\"\n", str);
b2d9e4f2 118 str = udev_device_get_driver(device_parent);
4ad3a37f
KS
119 if (str == NULL)
120 str = "";
121 printf(" DRIVERS==\"%s\"\n", str);
93b0f384 122 print_all_attributes(device_parent, "ATTRS");
b2d9e4f2 123 } while (device_parent != NULL);
be9b51f6 124
1aa1e248
KS
125 return 0;
126}
127
93b0f384 128static void print_record(struct udev_device *device)
31de3a2b 129{
93b0f384 130 size_t len;
ee137da3 131 const char *str;
93b0f384 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)));
ee137da3
KS
138 str = udev_device_get_devnode(device);
139 if (str != NULL)
140 printf("N: %s\n", &str[len+1]);
bf7ad0ea 141
aa8734ff 142 i = udev_device_get_devlink_priority(device);
93b0f384
KS
143 if (i != 0)
144 printf("L: %i\n", i);
bf7ad0ea 145
aa8734ff 146 i = udev_device_get_num_fake_partitions(device);
93b0f384
KS
147 if (i != 0)
148 printf("A:%u\n", i);
bf7ad0ea 149
aa8734ff 150 i = udev_device_get_ignore_remove(device);
93b0f384
KS
151 if (i != 0)
152 printf("R:%u\n", i);
93b0f384 153
c08337da
SJR
154 i = udev_device_get_watch_handle(device);
155 if (i >= 0)
156 printf("W:%u\n", i);
157
0de33a61 158 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) {
bf7ad0ea 159 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
0de33a61 160 printf("S: %s\n", &udev_list_entry_get_name(list_entry)[len+1]);
31de3a2b 161 }
93b0f384 162
0de33a61
KS
163 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device))
164 printf("E: %s=%s\n",
165 udev_list_entry_get_name(list_entry),
166 udev_list_entry_get_value(list_entry));
bf7ad0ea 167 printf("\n");
31de3a2b
KS
168}
169
d1acfc3e 170static int stat_device(const char *name, int export, const char *prefix)
f338bac8
KS
171{
172 struct stat statbuf;
173
174 if (stat(name, &statbuf) != 0)
175 return -1;
176
d1acfc3e
KS
177 if (export) {
178 if (prefix == NULL)
179 prefix = "INFO_";
180 printf("%sMAJOR=%d\n"
181 "%sMINOR=%d\n",
182 prefix, major(statbuf.st_dev),
183 prefix, minor(statbuf.st_dev));
184 } else
cce9d773 185 printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
f338bac8
KS
186 return 0;
187}
188
bf7ad0ea
KS
189static int export_devices(struct udev *udev)
190{
438d4c3c 191 struct udev_enumerate *udev_enumerate;
0de33a61 192 struct udev_list_entry *list_entry;
bf7ad0ea 193
438d4c3c
KS
194 udev_enumerate = udev_enumerate_new(udev);
195 if (udev_enumerate == NULL)
bf7ad0ea 196 return -1;
c97f839e 197 udev_enumerate_scan_devices(udev_enumerate);
438d4c3c 198 udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
bf7ad0ea
KS
199 struct udev_device *device;
200
0de33a61 201 device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
bf7ad0ea 202 if (device != NULL) {
b38a5801 203 print_record(device);
bf7ad0ea
KS
204 udev_device_unref(device);
205 }
bf7ad0ea 206 }
438d4c3c 207 udev_enumerate_unref(udev_enumerate);
bf7ad0ea
KS
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];
0de33a61 219 struct udev_list_entry *list_entry;
93b0f384 220 int rc = 0;
24ca5c33 221
e97717ba 222 static const struct option options[] = {
033e9f8c
KS
223 { "name", required_argument, NULL, 'n' },
224 { "path", required_argument, NULL, 'p' },
225 { "query", required_argument, NULL, 'q' },
226 { "attribute-walk", no_argument, NULL, 'a' },
227 { "export-db", no_argument, NULL, 'e' },
228 { "root", no_argument, NULL, 'r' },
229 { "device-id-of-file", required_argument, NULL, 'd' },
230 { "export", no_argument, NULL, 'x' },
231 { "export-prefix", required_argument, NULL, 'P' },
50025605 232 { "version", no_argument, NULL, 'V' },
033e9f8c 233 { "help", no_argument, NULL, 'h' },
11f1bb5a
KS
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 */
065db052
KS
271 if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) != 0)
272 util_strscpyl(name, sizeof(name), udev_get_dev_path(udev), "/", optarg, NULL);
273 else
274 util_strscpy(name, sizeof(name), optarg);
ecc9ec57 275 util_remove_trailing_chars(name, '/');
bf7ad0ea
KS
276 if (stat(name, &statbuf) < 0) {
277 fprintf(stderr, "device node not found\n");
278 rc = 2;
279 goto exit;
280 } else {
281 char type;
282
283 if (S_ISBLK(statbuf.st_mode)) {
284 type = 'b';
285 } else if (S_ISCHR(statbuf.st_mode)) {
286 type = 'c';
287 } else {
288 fprintf(stderr, "device node has wrong file type\n");
289 rc = 2;
290 goto exit;
291 }
292 device = udev_device_new_from_devnum(udev, type, statbuf.st_rdev);
293 if (device == NULL) {
294 fprintf(stderr, "device node not found\n");
295 rc = 2;
296 goto exit;
297 }
298 }
87171e46 299 break;
87171e46 300 case 'p':
93b0f384
KS
301 if (device != NULL) {
302 fprintf(stderr, "device already specified\n");
303 rc = 2;
304 goto exit;
305 }
bc8184ed 306 /* add sys dir if needed */
065db052
KS
307 if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0)
308 util_strscpyl(path, sizeof(path), udev_get_sys_path(udev), optarg, NULL);
309 else
310 util_strscpy(path, sizeof(path), optarg);
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");
62b9dfb6 342 rc = 3;
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;
065db052 351 util_strscpy(name, sizeof(name), optarg);
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;
87171e46 365 case 'V':
50025605 366 printf("%s\n", VERSION);
e48fc108 367 goto exit;
87171e46 368 case 'h':
225cb03b 369 printf("Usage: udevadm info OPTIONS\n"
cd42b50d 370 " --query=<type> query device information:\n"
f338bac8
KS
371 " name name of device node\n"
372 " symlink pointing to node\n"
cd42b50d 373 " path sys device path\n"
f338bac8
KS
374 " env the device related imported environment\n"
375 " all all values\n"
cd42b50d
KS
376 " --path=<syspath> sys device path used for query or attribute walk\n"
377 " --name=<name> node or symlink name used for query or attribute walk\n"
378 " --root prepend dev directory to path names\n"
379 " --attribute-walk print all key matches while walking along the chain\n"
f338bac8 380 " of parent devices\n"
cd42b50d 381 " --device-id-of-file=<file> print major:minor of device containing this file\n"
f338bac8 382 " --export-db export the content of the udev database\n"
f1e7e360 383 " --help\n\n");
e3396a2d 384 goto exit;
87171e46 385 default:
24ca5c33 386 goto exit;
87171e46
KS
387 }
388 }
389
24ca5c33
KS
390 switch (action) {
391 case ACTION_QUERY:
93b0f384 392 if (device == NULL) {
9a8047fa 393 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
1aa1e248 394 rc = 4;
24ca5c33 395 goto exit;
87171e46
KS
396 }
397
87171e46 398 switch(query) {
b8476286 399 case QUERY_NAME:
93b0f384 400 if (root) {
fb762bb9 401 printf("%s\n", udev_device_get_devnode(device));
93b0f384
KS
402 } else {
403 size_t len;
62b9dfb6 404 const char *node;
18770246 405
93b0f384 406 len = strlen(udev_get_dev_path(udev));
62b9dfb6
KS
407 node = udev_device_get_devnode(device);
408 if (node == NULL) {
409 fprintf(stderr, "no device node found\n");
410 rc = 5;
411 goto exit;
412 }
413 printf("%s\n", &udev_device_get_devnode(device)[len+1]);
18770246 414 }
24ca5c33 415 break;
93b0f384 416 case QUERY_SYMLINK:
0de33a61
KS
417 list_entry = udev_device_get_devlinks_list_entry(device);
418 while (list_entry != NULL) {
bf7ad0ea 419 if (root) {
0de33a61 420 printf("%s", udev_list_entry_get_name(list_entry));
bf7ad0ea
KS
421 } else {
422 size_t len;
423
424 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
0de33a61 425 printf("%s", &udev_list_entry_get_name(list_entry)[len+1]);
bf7ad0ea 426 }
0de33a61
KS
427 list_entry = udev_list_entry_get_next(list_entry);
428 if (list_entry != NULL)
bf7ad0ea
KS
429 printf(" ");
430 }
431 printf("\n");
93b0f384 432 break;
b8476286 433 case QUERY_PATH:
93b0f384 434 printf("%s\n", udev_device_get_devpath(device));
e48fc108 435 goto exit;
b8476286 436 case QUERY_ENV:
0de33a61
KS
437 list_entry = udev_device_get_properties_list_entry(device);
438 while (list_entry != NULL) {
439 printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
440 list_entry = udev_list_entry_get_next(list_entry);
bf7ad0ea 441 }
24ca5c33 442 break;
b8476286 443 case QUERY_ALL:
93b0f384 444 print_record(device);
24ca5c33 445 break;
87171e46 446 default:
e3396a2d 447 fprintf(stderr, "unknown query type\n");
24ca5c33 448 break;
87171e46 449 }
24ca5c33
KS
450 break;
451 case ACTION_ATTRIBUTE_WALK:
93b0f384 452 if (device == NULL) {
9a8047fa 453 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
62b9dfb6 454 rc = 4;
1aa0c52b
KS
455 goto exit;
456 }
93b0f384 457 print_device_chain(device);
24ca5c33 458 break;
f338bac8 459 case ACTION_DEVICE_ID_FILE:
d1acfc3e 460 if (stat_device(name, export, export_prefix) != 0)
62b9dfb6 461 rc = 1;
f338bac8 462 break;
24ca5c33 463 case ACTION_ROOT:
7d563a17 464 printf("%s\n", udev_get_dev_path(udev));
24ca5c33
KS
465 break;
466 default:
e3396a2d 467 fprintf(stderr, "missing option\n");
1aa1e248 468 rc = 1;
24ca5c33 469 break;
87171e46
KS
470 }
471
e48fc108 472exit:
93b0f384 473 udev_device_unref(device);
1aa1e248 474 return rc;
87171e46 475}