]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/udev/udevadm-info.c
Fix some format strings for enums, they are signed
[thirdparty/systemd.git] / src / udev / udevadm-info.c
CommitLineData
be9b51f6 1/*
1298001e 2 * Copyright (C) 2004-2009 Kay Sievers <kay@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"
44433ebd 33#include "udev-util.h"
d6170d27 34#include "udevadm-util.h"
be9b51f6 35
9ec6e95b 36static bool skip_attribute(const char *name) {
46512cd9 37 static const char* const skip[] = {
912541b0
KS
38 "uevent",
39 "dev",
40 "modalias",
41 "resource",
42 "driver",
43 "subsystem",
44 "module",
45 };
46 unsigned int i;
47
8fef0ff2 48 for (i = 0; i < ELEMENTSOF(skip); i++)
090be865 49 if (streq(name, skip[i]))
912541b0
KS
50 return true;
51 return false;
20bee04c
KS
52}
53
9ec6e95b 54static void print_all_attributes(struct udev_device *device, const char *key) {
912541b0
KS
55 struct udev_list_entry *sysattr;
56
57 udev_list_entry_foreach(sysattr, udev_device_get_sysattr_list_entry(device)) {
58 const char *name;
59 const char *value;
60 size_t len;
61
62 name = udev_list_entry_get_name(sysattr);
63 if (skip_attribute(name))
64 continue;
65
66 value = udev_device_get_sysattr_value(device, name);
67 if (value == NULL)
68 continue;
912541b0
KS
69
70 /* skip any values that look like a path */
71 if (value[0] == '/')
72 continue;
73
74 /* skip nonprintable attributes */
75 len = strlen(value);
76 while (len > 0 && isprint(value[len-1]))
77 len--;
baa30fbc 78 if (len > 0)
912541b0 79 continue;
912541b0
KS
80
81 printf(" %s{%s}==\"%s\"\n", key, name, value);
82 }
83 printf("\n");
be9b51f6
KS
84}
85
9ec6e95b 86static int print_device_chain(struct udev_device *device) {
912541b0
KS
87 struct udev_device *device_parent;
88 const char *str;
89
90 printf("\n"
91 "Udevadm info starts with the device specified by the devpath and then\n"
92 "walks up the chain of parent devices. It prints for every device\n"
93 "found, all possible attributes in the udev rules key format.\n"
94 "A rule to match, can be composed by the attributes of the device\n"
95 "and the attributes from one single parent device.\n"
96 "\n");
97
98 printf(" looking at device '%s':\n", udev_device_get_devpath(device));
99 printf(" KERNEL==\"%s\"\n", udev_device_get_sysname(device));
100 str = udev_device_get_subsystem(device);
101 if (str == NULL)
102 str = "";
103 printf(" SUBSYSTEM==\"%s\"\n", str);
104 str = udev_device_get_driver(device);
105 if (str == NULL)
106 str = "";
107 printf(" DRIVER==\"%s\"\n", str);
108 print_all_attributes(device, "ATTR");
109
110 device_parent = device;
111 do {
112 device_parent = udev_device_get_parent(device_parent);
113 if (device_parent == NULL)
114 break;
115 printf(" looking at parent device '%s':\n", udev_device_get_devpath(device_parent));
116 printf(" KERNELS==\"%s\"\n", udev_device_get_sysname(device_parent));
117 str = udev_device_get_subsystem(device_parent);
118 if (str == NULL)
119 str = "";
120 printf(" SUBSYSTEMS==\"%s\"\n", str);
121 str = udev_device_get_driver(device_parent);
122 if (str == NULL)
123 str = "";
124 printf(" DRIVERS==\"%s\"\n", str);
125 print_all_attributes(device_parent, "ATTRS");
126 } while (device_parent != NULL);
127
128 return 0;
1aa1e248
KS
129}
130
9ec6e95b 131static void print_record(struct udev_device *device) {
912541b0
KS
132 const char *str;
133 int i;
134 struct udev_list_entry *list_entry;
135
136 printf("P: %s\n", udev_device_get_devpath(device));
137
912541b0
KS
138 str = udev_device_get_devnode(device);
139 if (str != NULL)
6ada823a 140 printf("N: %s\n", str + strlen("/dev/"));
912541b0
KS
141
142 i = udev_device_get_devlink_priority(device);
143 if (i != 0)
144 printf("L: %i\n", i);
145
6ada823a
KS
146 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device))
147 printf("S: %s\n", udev_list_entry_get_name(list_entry) + strlen("/dev/"));
912541b0
KS
148
149 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device))
150 printf("E: %s=%s\n",
151 udev_list_entry_get_name(list_entry),
152 udev_list_entry_get_value(list_entry));
153 printf("\n");
31de3a2b
KS
154}
155
9ec6e95b 156static int stat_device(const char *name, bool export, const char *prefix) {
912541b0
KS
157 struct stat statbuf;
158
159 if (stat(name, &statbuf) != 0)
160 return -1;
161
162 if (export) {
163 if (prefix == NULL)
164 prefix = "INFO_";
165 printf("%sMAJOR=%d\n"
166 "%sMINOR=%d\n",
167 prefix, major(statbuf.st_dev),
168 prefix, minor(statbuf.st_dev));
169 } else
170 printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
171 return 0;
f338bac8
KS
172}
173
9ec6e95b 174static int export_devices(struct udev *udev) {
912541b0
KS
175 struct udev_enumerate *udev_enumerate;
176 struct udev_list_entry *list_entry;
177
178 udev_enumerate = udev_enumerate_new(udev);
179 if (udev_enumerate == NULL)
180 return -1;
181 udev_enumerate_scan_devices(udev_enumerate);
182 udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
183 struct udev_device *device;
184
185 device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
186 if (device != NULL) {
187 print_record(device);
188 udev_device_unref(device);
189 }
190 }
191 udev_enumerate_unref(udev_enumerate);
192 return 0;
bf7ad0ea
KS
193}
194
9ec6e95b 195static void cleanup_dir(DIR *dir, mode_t mask, int depth) {
912541b0
KS
196 struct dirent *dent;
197
198 if (depth <= 0)
199 return;
200
201 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
202 struct stat stats;
203
204 if (dent->d_name[0] == '.')
205 continue;
206 if (fstatat(dirfd(dir), dent->d_name, &stats, AT_SYMLINK_NOFOLLOW) != 0)
207 continue;
208 if ((stats.st_mode & mask) != 0)
209 continue;
210 if (S_ISDIR(stats.st_mode)) {
211 DIR *dir2;
212
213 dir2 = fdopendir(openat(dirfd(dir), dent->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC));
214 if (dir2 != NULL) {
215 cleanup_dir(dir2, mask, depth-1);
216 closedir(dir2);
217 }
218 unlinkat(dirfd(dir), dent->d_name, AT_REMOVEDIR);
219 } else {
220 unlinkat(dirfd(dir), dent->d_name, 0);
221 }
222 }
9ead6627
KS
223}
224
9ec6e95b 225static void cleanup_db(struct udev *udev) {
912541b0
KS
226 DIR *dir;
227
6ada823a 228 unlink("/run/udev/queue.bin");
912541b0 229
6ada823a 230 dir = opendir("/run/udev/data");
912541b0
KS
231 if (dir != NULL) {
232 cleanup_dir(dir, S_ISVTX, 1);
233 closedir(dir);
234 }
235
6ada823a 236 dir = opendir("/run/udev/links");
912541b0
KS
237 if (dir != NULL) {
238 cleanup_dir(dir, 0, 2);
239 closedir(dir);
240 }
241
6ada823a 242 dir = opendir("/run/udev/tags");
912541b0
KS
243 if (dir != NULL) {
244 cleanup_dir(dir, 0, 2);
245 closedir(dir);
246 }
247
84b6ad70
TG
248 dir = opendir("/run/udev/static_node-tags");
249 if (dir != NULL) {
250 cleanup_dir(dir, 0, 2);
251 closedir(dir);
252 }
253
6ada823a 254 dir = opendir("/run/udev/watch");
912541b0
KS
255 if (dir != NULL) {
256 cleanup_dir(dir, 0, 1);
257 closedir(dir);
258 }
9ead6627
KS
259}
260
5ac0162c
LP
261static void help(void) {
262
263 printf("%s info [OPTIONS] [DEVPATH|FILE]\n\n"
264 "Query sysfs or the udev database.\n\n"
265 " -h --help Print this message\n"
266 " --version Print version of the program\n"
267 " -q --query=TYPE Query device information:\n"
268 " name Name of device node\n"
269 " symlink Pointing to node\n"
270 " path sysfs device path\n"
271 " property The device properties\n"
272 " all All values\n"
273 " -p --path=SYSPATH sysfs device path used for query or attribute walk\n"
274 " -n --name=NAME Node or symlink name used for query or attribute walk\n"
275 " -r --root Prepend dev directory to path names\n"
276 " -a --attribute-walk Print all key matches walking along the chain\n"
277 " of parent devices\n"
278 " -d --device-id-of-file=FILE Print major:minor of device containing this file\n"
279 " -x --export Export key/value pairs\n"
280 " -P --export-prefix Export the key name with a prefix\n"
281 " -e --export-db Export the content of the udev database\n"
282 " -c --cleanup-db Clean up the udev database\n"
283 , program_invocation_short_name);
284}
285
9ec6e95b 286static int uinfo(struct udev *udev, int argc, char *argv[]) {
44433ebd 287 _cleanup_udev_device_unref_ struct udev_device *device = NULL;
912541b0
KS
288 bool root = 0;
289 bool export = 0;
290 const char *export_prefix = NULL;
912541b0
KS
291 char name[UTIL_PATH_SIZE];
292 struct udev_list_entry *list_entry;
44433ebd 293 int c;
912541b0
KS
294
295 static const struct option options[] = {
7643ac9a
ZJS
296 { "name", required_argument, NULL, 'n' },
297 { "path", required_argument, NULL, 'p' },
298 { "query", required_argument, NULL, 'q' },
299 { "attribute-walk", no_argument, NULL, 'a' },
300 { "cleanup-db", no_argument, NULL, 'c' },
301 { "export-db", no_argument, NULL, 'e' },
302 { "root", no_argument, NULL, 'r' },
912541b0 303 { "device-id-of-file", required_argument, NULL, 'd' },
7643ac9a
ZJS
304 { "export", no_argument, NULL, 'x' },
305 { "export-prefix", required_argument, NULL, 'P' },
306 { "version", no_argument, NULL, 'V' },
307 { "help", no_argument, NULL, 'h' },
912541b0
KS
308 {}
309 };
310
311 enum action_type {
912541b0
KS
312 ACTION_QUERY,
313 ACTION_ATTRIBUTE_WALK,
912541b0 314 ACTION_DEVICE_ID_FILE,
4f5d327a 315 } action = ACTION_QUERY;
912541b0
KS
316
317 enum query_type {
912541b0
KS
318 QUERY_NAME,
319 QUERY_PATH,
320 QUERY_SYMLINK,
321 QUERY_PROPERTY,
322 QUERY_ALL,
4f5d327a 323 } query = QUERY_ALL;
912541b0 324
7643ac9a
ZJS
325 while ((c = getopt_long(argc, argv, "aced:n:p:q:rxP:RVh", options, NULL)) >= 0)
326 switch (c) {
4f5d327a 327 case 'n': {
912541b0
KS
328 if (device != NULL) {
329 fprintf(stderr, "device already specified\n");
44433ebd 330 return 2;
912541b0 331 }
4f5d327a
KS
332
333 device = find_device(udev, optarg, "/dev/");
334 if (device == NULL) {
912541b0 335 fprintf(stderr, "device node not found\n");
44433ebd 336 return 2;
912541b0
KS
337 }
338 break;
4f5d327a 339 }
912541b0
KS
340 case 'p':
341 if (device != NULL) {
342 fprintf(stderr, "device already specified\n");
44433ebd 343 return 2;
912541b0 344 }
4f5d327a
KS
345
346 device = find_device(udev, optarg, "/sys");
912541b0 347 if (device == NULL) {
4f5d327a 348 fprintf(stderr, "syspath not found\n");
44433ebd 349 return 2;
912541b0
KS
350 }
351 break;
352 case 'q':
353 action = ACTION_QUERY;
44433ebd 354 if (streq(optarg, "property") || streq(optarg, "env"))
912541b0 355 query = QUERY_PROPERTY;
44433ebd 356 else if (streq(optarg, "name"))
912541b0 357 query = QUERY_NAME;
44433ebd 358 else if (streq(optarg, "symlink"))
912541b0 359 query = QUERY_SYMLINK;
44433ebd 360 else if (streq(optarg, "path"))
912541b0 361 query = QUERY_PATH;
44433ebd 362 else if (streq(optarg, "all"))
912541b0 363 query = QUERY_ALL;
44433ebd 364 else {
912541b0 365 fprintf(stderr, "unknown query type\n");
44433ebd 366 return 3;
912541b0
KS
367 }
368 break;
369 case 'r':
912541b0
KS
370 root = true;
371 break;
912541b0
KS
372 case 'd':
373 action = ACTION_DEVICE_ID_FILE;
d5a89d7d 374 strscpy(name, sizeof(name), optarg);
912541b0
KS
375 break;
376 case 'a':
377 action = ACTION_ATTRIBUTE_WALK;
378 break;
379 case 'e':
380 export_devices(udev);
44433ebd 381 return 0;
912541b0
KS
382 case 'c':
383 cleanup_db(udev);
44433ebd 384 return 0;
912541b0
KS
385 case 'x':
386 export = true;
387 break;
388 case 'P':
389 export_prefix = optarg;
390 break;
391 case 'V':
392 printf("%s\n", VERSION);
44433ebd 393 return 0;
912541b0 394 case 'h':
5ac0162c 395 help();
44433ebd 396 return 0;
912541b0 397 default:
44433ebd 398 return 1;
912541b0 399 }
912541b0
KS
400
401 switch (action) {
402 case ACTION_QUERY:
4f5d327a
KS
403 if (!device) {
404 if (!argv[optind]) {
5ac0162c 405 help();
44433ebd 406 return 2;
4f5d327a
KS
407 }
408 device = find_device(udev, argv[optind], NULL);
409 if (!device) {
410 fprintf(stderr, "Unknown device, --name=, --path=, or absolute path in /dev/ or /sys expected.\n");
44433ebd 411 return 4;
4f5d327a 412 }
912541b0
KS
413 }
414
415 switch(query) {
416 case QUERY_NAME: {
417 const char *node = udev_device_get_devnode(device);
418
419 if (node == NULL) {
420 fprintf(stderr, "no device node found\n");
44433ebd 421 return 5;
912541b0
KS
422 }
423
6ada823a 424 if (root)
912541b0 425 printf("%s\n", udev_device_get_devnode(device));
6ada823a
KS
426 else
427 printf("%s\n", udev_device_get_devnode(device) + strlen("/dev/"));
912541b0
KS
428 break;
429 }
430 case QUERY_SYMLINK:
431 list_entry = udev_device_get_devlinks_list_entry(device);
432 while (list_entry != NULL) {
6ada823a 433 if (root)
912541b0 434 printf("%s", udev_list_entry_get_name(list_entry));
6ada823a
KS
435 else
436 printf("%s", udev_list_entry_get_name(list_entry) + strlen("/dev/"));
912541b0
KS
437 list_entry = udev_list_entry_get_next(list_entry);
438 if (list_entry != NULL)
439 printf(" ");
440 }
441 printf("\n");
442 break;
443 case QUERY_PATH:
444 printf("%s\n", udev_device_get_devpath(device));
44433ebd 445 return 0;
912541b0
KS
446 case QUERY_PROPERTY:
447 list_entry = udev_device_get_properties_list_entry(device);
448 while (list_entry != NULL) {
449 if (export) {
450 const char *prefix = export_prefix;
451
452 if (prefix == NULL)
453 prefix = "";
454 printf("%s%s='%s'\n", prefix,
455 udev_list_entry_get_name(list_entry),
456 udev_list_entry_get_value(list_entry));
457 } else {
458 printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
459 }
460 list_entry = udev_list_entry_get_next(list_entry);
461 }
462 break;
463 case QUERY_ALL:
464 print_record(device);
465 break;
466 default:
bdd13f6b 467 assert_not_reached("unknown query type");
912541b0
KS
468 }
469 break;
470 case ACTION_ATTRIBUTE_WALK:
4f5d327a
KS
471 if (!device && argv[optind]) {
472 device = find_device(udev, argv[optind], NULL);
473 if (!device) {
474 fprintf(stderr, "Unknown device, absolute path in /dev/ or /sys expected.\n");
44433ebd 475 return 4;
4f5d327a
KS
476 }
477 }
478 if (!device) {
479 fprintf(stderr, "Unknown device, --name=, --path=, or absolute path in /dev/ or /sys expected.\n");
44433ebd 480 return 4;
912541b0
KS
481 }
482 print_device_chain(device);
483 break;
484 case ACTION_DEVICE_ID_FILE:
485 if (stat_device(name, export, export_prefix) != 0)
44433ebd 486 return 1;
912541b0 487 break;
912541b0 488 }
87171e46 489
44433ebd 490 return 0;
87171e46 491}
1985c76e
KS
492
493const struct udevadm_cmd udevadm_info = {
912541b0
KS
494 .name = "info",
495 .cmd = uinfo,
5ac0162c 496 .help = "Query sysfs or the udev database",
1985c76e 497};