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