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